Sophie

Sophie

distrib > Mandriva > 2011.0 > i586 > media > main-updates-src > by-pkgid > 7390cb2e4511dda8a7fb6606b3d28b7b > files > 5

networkmanager-0.8.6.0-0.1.src.rpm

diff --git a/README.mdv b/README.mdv
new file mode 100644
index 0000000..989ca01
--- /dev/null
+++ b/README.mdv
@@ -0,0 +1,14 @@
+The ifcfg-mdv is a BETA plugin, which adds support for Mandriva-specific
+variables in /etc/sysconfig/network-scripts/ifcfg-* files to network
+manager.
+
+This is not a production-ready version, nor it is officially supported as of
+now. However, it works fine for me, so - at least in theory - it should work
+for some of you out there as well.
+
+To get the most up-to-date patch against mainstream NetworkManager code,
+just run:
+# git diff master mdv
+
+The 'patches' directory contains mostly up-to-date patches to be used with
+Mandriva's networkmanager package.
diff --git a/configure.ac b/configure.ac
index ebb2aa9..6f0deef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -575,6 +575,7 @@ system-settings/plugins/ifnet/tests/Makefile
 system-settings/plugins/ifcfg-rh/Makefile
 system-settings/plugins/ifcfg-rh/tests/Makefile
 system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile
+system-settings/plugins/ifcfg-mdv/Makefile
 system-settings/plugins/ifcfg-suse/Makefile
 system-settings/plugins/keyfile/Makefile
 system-settings/plugins/keyfile/tests/Makefile
diff --git a/initscript/Mandriva/networkmanager.in b/initscript/Mandriva/networkmanager.in
index dac14e7..3e7847e 100644
--- a/initscript/Mandriva/networkmanager.in
+++ b/initscript/Mandriva/networkmanager.in
@@ -11,8 +11,10 @@
 #
 ### BEGIN INIT INFO
 # Provides: networkmanager
-# Required-Start: $network
-# Required-Stop: $network
+# Required-Start: $network messagebus
+# Should-Start: $named $syslog resolvconf
+# Required-Stop: $network messagebus
+# Should-Stop: $syslog
 # Default-Start: 3 4 5
 # Short-Description: Daemon for automatically switching to best network connection.
 # Description: This is a daemon for automatically switching network
@@ -46,10 +48,6 @@ start()
 	echo $"Setting network parameters... "
 	sysctl -e -p /etc/sysctl.conf >/dev/null 2>&1
 
-	if [ ! -e /var/lock/subsys/named ]; then
-		service named start >/dev/null 2>&1
-	fi
-
 	echo -n $"Starting NetworkManager daemon: "
 	daemon --check $servicename $processname --pid-file=$pidfile
 	RETVAL=$?
diff --git a/man/NetworkManager.conf.5.in b/man/NetworkManager.conf.5.in
index acacb43..e372372 100644
--- a/man/NetworkManager.conf.5.in
+++ b/man/NetworkManager.conf.5.in
@@ -70,6 +70,13 @@ to read and write configuration from the standard /etc/sysconfig/network-scripts
 It currently supports reading wired, WiFi, and 802.1x connections, but does not yet support reading
 or writing mobile broadband, PPPoE, or VPN connections. To allow reading and writing of these
 add \fIkeyfile\fP plugin to your configuration as well.
+.TP 
+.I ifcfg\-mdv
+plugin is used on the Mandriva distribution
+to read and write configuration from the standard files under /etc/sysconfig/network-scripts. Additionally wireless security information is taken from /etc/wpa_supplicant.conf.
+It currently supports reading wired, WiFi, and possibly 802.1x connections, but does not yet support reading
+or writing mobile broadband, PPPoE, or VPN connections. To allow reading and writing of these
+add \fIkeyfile\fP plugin to your configuration as well.
 .TP
 .I ifupdown
 plugin is used on the Debian and Ubuntu distributions, and reads connections from
diff --git a/system-settings/plugins/Makefile.am b/system-settings/plugins/Makefile.am
index 5df57d5..36e30cc 100644
--- a/system-settings/plugins/Makefile.am
+++ b/system-settings/plugins/Makefile.am
@@ -9,6 +9,7 @@ SUBDIRS+=ifcfg-suse
 endif
 
 if TARGET_MANDRIVA
+SUBDIRS+=ifcfg-mdv
 SUBDIRS+=ifcfg-rh
 endif
 
diff --git a/system-settings/plugins/ifcfg-mdv/Makefile.am b/system-settings/plugins/ifcfg-mdv/Makefile.am
new file mode 100644
index 0000000..48319be
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/Makefile.am
@@ -0,0 +1,66 @@
+SUBDIRS=.
+
+pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-mdv.la
+
+noinst_LTLIBRARIES = libifcfg-mdv-io.la
+
+libifcfg_mdv_io_la_SOURCES = \
+	parse_wpa_supplicant_conf.c \
+	parse_wpa_supplicant_conf.h \
+	reader.c \
+	reader.h \
+	writer.c \
+	writer.h \
+	common.h \
+	utils-mdv.c \
+	utils-mdv.h \
+	../ifcfg-rh/shvar.c \
+	../ifcfg-rh/shvar.h \
+	../ifcfg-rh/errors.c \
+	../ifcfg-rh/utils.c \
+	../ifcfg-rh/utils.h
+
+INCLUDES = \
+	-I$(top_srcdir)/system-settings/plugins/ifcfg-rh \
+	-I$(top_srcdir)/src/system-settings \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/libnm-glib \
+	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/marshallers
+
+libifcfg_mdv_io_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	$(NSS_CFLAGS) \
+	-DG_DISABLE_DEPRECATED \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
+	-DSBINDIR=\"$(sbindir)\"
+
+libifcfg_mdv_io_la_LIBADD = \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(GLIB_LIBS) \
+	$(NSS_LIBS)
+
+libnm_settings_plugin_ifcfg_mdv_la_SOURCES = \
+	plugin.c \
+	plugin.h \
+	nm-ifcfg-connection.c \
+	nm-ifcfg-connection.h
+
+libnm_settings_plugin_ifcfg_mdv_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(GMODULE_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	-DG_DISABLE_DEPRECATED \
+	-DSYSCONFDIR=\"$(sysconfdir)\"
+
+libnm_settings_plugin_ifcfg_mdv_la_LDFLAGS = -module -avoid-version
+libnm_settings_plugin_ifcfg_mdv_la_LIBADD = \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(top_builddir)/libnm-glib/libnm-glib.la \
+	$(top_builddir)/marshallers/libmarshallers.la \
+	libifcfg-mdv-io.la \
+	$(GLIB_LIBS) \
+	$(GMODULE_LIBS) \
+	$(GIO_LIBS)
+
diff --git a/system-settings/plugins/ifcfg-mdv/common.h b/system-settings/plugins/ifcfg-mdv/common.h
new file mode 100644
index 0000000..667a39a
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/common.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * 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.
+ *
+ * (C) Copyright 2008 - 2009 Red Hat, Inc.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <glib.h>
+
+#define IFCFG_TAG "ifcfg-"
+#define KEYS_TAG "keys-"
+#define ROUTE_TAG "route-"
+#define ROUTE6_TAG "route6-"
+
+#define BAK_TAG ".bak"
+#define TILDE_TAG "~"
+#define ORIG_TAG ".orig"
+#define REJ_TAG ".rej"
+#define RPMNEW_TAG ".rpmnew"
+
+#define IFCFG_DIR SYSCONFDIR"/sysconfig/network-scripts"
+#define IFCFG_WIRELESS_D_DIR IFCFG_DIR"/wireless.d"
+
+#define IFCFG_PLUGIN_NAME "ifcfg-mdv"
+#define IFCFG_PLUGIN_INFO "(c) 2009 - 2010 Eugeni Dodonov <eugeni@mandriva.com>."
+
+#define TYPE_ETHERNET "Ethernet"
+#define TYPE_WIRELESS "Wireless"
+#define TYPE_BRIDGE   "Bridge"
+
+#define IFCFG_PLUGIN_ERROR (ifcfg_plugin_error_quark ())
+GQuark ifcfg_plugin_error_quark (void);
+
+
+#endif  /* __COMMON_H__ */
+
diff --git a/system-settings/plugins/ifcfg-mdv/nm-ifcfg-connection.c b/system-settings/plugins/ifcfg-mdv/nm-ifcfg-connection.c
new file mode 100644
index 0000000..466e72a
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/nm-ifcfg-connection.c
@@ -0,0 +1,414 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2008 - 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <net/ethernet.h>
+#include <netinet/ether.h>
+
+#include <glib/gstdio.h>
+
+#include <NetworkManager.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-gsm.h>
+#include <nm-setting-cdma.h>
+#include <nm-setting-pppoe.h>
+#include <nm-setting-wireless-security.h>
+#include <nm-setting-8021x.h>
+#include <nm-settings-connection-interface.h>
+
+#include "common.h"
+#include "nm-ifcfg-connection.h"
+#include "reader.h"
+#include "utils.h"
+#include "utils-mdv.h"
+#include "writer.h"
+#include "nm-inotify-helper.h"
+
+#include "parse_wpa_supplicant_conf.h"
+
+static NMSettingsConnectionInterface *parent_settings_connection_iface;
+
+static void settings_connection_interface_init (NMSettingsConnectionInterface *klass);
+
+G_DEFINE_TYPE_EXTENDED (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_SYSCONFIG_CONNECTION, 0,
+                        G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE,
+                                               settings_connection_interface_init))
+
+#define NM_IFCFG_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionPrivate))
+
+typedef struct {
+	gulong ih_event_id;
+
+	char *filename;
+	int file_wd;
+
+	char *keyfile;
+	int keyfile_wd;
+
+	char *routefile;
+	int routefile_wd;
+
+	char *route6file;
+	int route6file_wd;
+
+	char *udi;
+	char *unmanaged;
+} NMIfcfgConnectionPrivate;
+
+enum {
+	PROP_0,
+	PROP_FILENAME,
+	PROP_UNMANAGED,
+	PROP_UDI,
+
+	LAST_PROP
+};
+
+/* Signals */
+enum {
+	IFCFG_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+files_changed_cb (NMInotifyHelper *ih,
+                  struct inotify_event *evt,
+                  const char *path,
+                  gpointer user_data)
+{
+	NMIfcfgConnection *self = NM_IFCFG_CONNECTION (user_data);
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
+
+	if ((evt->wd != priv->file_wd) && (evt->wd != priv->keyfile_wd) && (evt->wd != priv->routefile_wd) && (evt->wd != priv->route6file_wd))
+		return;
+
+	/* push the event up to the plugin */
+	g_signal_emit (self, signals[IFCFG_CHANGED], 0);
+}
+
+NMIfcfgConnection *
+nm_ifcfg_connection_new (const char *filename,
+                         GError **error,
+                         gboolean *ignore_error)
+{
+	GObject *object;
+	NMIfcfgConnectionPrivate *priv;
+	NMConnection *tmp;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	NMInotifyHelper *ih;
+
+	g_return_val_if_fail (filename != NULL, NULL);
+
+	tmp = connection_from_file (filename, NULL, NULL, NULL, &unmanaged, &keyfile, &routefile, &route6file, error, ignore_error);
+	if (!tmp)
+		return NULL;
+
+	object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION,
+	                                   NM_IFCFG_CONNECTION_FILENAME, filename,
+	                                   NM_IFCFG_CONNECTION_UNMANAGED, unmanaged,
+	                                   NULL);
+	if (!object) {
+		g_object_unref (tmp);
+		return NULL;
+	}
+
+	/* Update our settings with what was read from the file */
+	nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (object), tmp, FALSE, NULL);
+	g_object_unref (tmp);
+
+	priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
+
+	ih = nm_inotify_helper_get ();
+	priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (files_changed_cb), object);
+
+	priv->file_wd = nm_inotify_helper_add_watch (ih, filename);
+
+	priv->keyfile = keyfile;
+	priv->keyfile_wd = nm_inotify_helper_add_watch (ih, keyfile);
+
+	priv->routefile = routefile;
+	priv->routefile_wd = nm_inotify_helper_add_watch (ih, routefile);
+
+	priv->route6file = route6file;
+	priv->route6file_wd = nm_inotify_helper_add_watch (ih, route6file);
+
+	return NM_IFCFG_CONNECTION (object);
+}
+
+const char *
+nm_ifcfg_connection_get_filename (NMIfcfgConnection *self)
+{
+	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
+
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->filename;
+}
+
+const char *
+nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self)
+{
+	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), FALSE);
+
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unmanaged;
+}
+
+static gboolean
+update (NMSettingsConnectionInterface *connection,
+	    NMSettingsConnectionInterfaceUpdateFunc callback,
+	    gpointer user_data)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection);
+	GError *error = NULL;
+	NMConnection *reread;
+	char *unmanaged = NULL, *keyfile = NULL, *routefile = NULL, *route6file = NULL;
+
+	/* To ensure we don't rewrite files that are only changed from other
+	 * processes on-disk, read the existing connection back in and only rewrite
+	 * it if it's really changed.
+	 */
+	reread = connection_from_file (priv->filename, NULL, NULL, NULL,
+	                               &unmanaged, &keyfile, &routefile, &route6file,
+	                               NULL, NULL);
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+
+	if (reread && nm_connection_compare (NM_CONNECTION (connection),
+	                                     reread,
+	                                     NM_SETTING_COMPARE_FLAG_EXACT))
+		goto out;
+
+	if (!writer_update_connection (NM_CONNECTION (connection),
+	                               IFCFG_DIR,
+	                               priv->filename,
+	                               priv->keyfile,
+	                               &error)) {
+		callback (connection, error, user_data);
+		g_error_free (error);
+		return FALSE;
+	}
+
+out:
+	if (reread)
+		g_object_unref (reread);
+	return parent_settings_connection_iface->update (connection, callback, user_data);
+}
+
+static gboolean 
+do_delete (NMSettingsConnectionInterface *connection,
+	       NMSettingsConnectionInterfaceDeleteFunc callback,
+	       gpointer user_data)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection);
+	NMSettingWireless *s_wireless;
+	WPANetwork *wpan;
+	const GByteArray *ssid = NULL;
+	MdvIfcfgType conntype = mdv_get_ifcfg_type(priv->filename);
+	GError *error = NULL;
+
+	/*
+	 * There is no obviouos way to create interface-specific configuration
+	 * on Mandriva. Current ifup/ifdown scripts do not handle spaces in
+	 * names and NM connections are not tied to specific interface so
+	 * do not offer means to enter interface name. So we do not create
+	 * them and do not allow to delete them. Users should use draknet.
+	 */
+	if (conntype != MdvIfcfgTypeSSID) {
+		g_set_error(&error, ifcfg_plugin_error_quark(), 0,
+			"Only roaming connection can be deleted");
+		callback(connection, error, user_data);
+		g_error_free(error);
+		return FALSE;
+	}
+
+	s_wireless = (NMSettingWireless *)nm_connection_get_setting(NM_CONNECTION(connection), NM_TYPE_SETTING_WIRELESS);
+	if (s_wireless)
+		ssid = nm_setting_wireless_get_ssid(s_wireless);
+
+	/* Delete network block from wpa_supplicant.conf */
+	if (ssid) {
+		wpan = ifcfg_mdv_wpa_network_new(NULL);
+		if (wpan) {
+			ifcfg_mdv_wpa_network_set_ssid(wpan, ssid);
+			ifcfg_mdv_wpa_network_set_val(wpan, "__DELETE__", "yes");
+			ifcfg_mdv_wpa_network_save(wpan, "/etc/wpa_supplicant.conf", NULL);
+			ifcfg_mdv_wpa_network_free(wpan);
+		}
+	}
+
+	g_unlink (priv->filename);
+	if (priv->keyfile)
+		g_unlink (priv->keyfile);
+	if (priv->routefile)
+		g_unlink (priv->routefile);
+
+	if (priv->route6file)
+		g_unlink (priv->route6file);
+
+	return parent_settings_connection_iface->delete (connection, callback, user_data);
+}
+
+/* GObject */
+
+static void
+settings_connection_interface_init (NMSettingsConnectionInterface *iface)
+{
+	parent_settings_connection_iface = g_type_interface_peek_parent (iface);
+	iface->update = update;
+	iface->delete = do_delete;
+}
+
+static void
+nm_ifcfg_connection_init (NMIfcfgConnection *connection)
+{
+}
+
+static void
+finalize (GObject *object)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
+	NMInotifyHelper *ih;
+
+	g_free (priv->udi);
+
+	nm_connection_clear_secrets (NM_CONNECTION (object));
+
+	ih = nm_inotify_helper_get ();
+
+	g_signal_handler_disconnect (ih, priv->ih_event_id);
+
+	g_free (priv->filename);
+	if (priv->file_wd >= 0)
+		nm_inotify_helper_remove_watch (ih, priv->file_wd);
+
+	g_free (priv->keyfile);
+	if (priv->keyfile_wd >= 0)
+		nm_inotify_helper_remove_watch (ih, priv->keyfile_wd);
+
+	g_free (priv->routefile);
+	if (priv->routefile_wd >= 0)
+		nm_inotify_helper_remove_watch (ih, priv->routefile_wd);
+
+	g_free (priv->route6file);
+	if (priv->route6file_wd >= 0)
+		nm_inotify_helper_remove_watch (ih, priv->route6file_wd);
+
+	G_OBJECT_CLASS (nm_ifcfg_connection_parent_class)->finalize (object);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+		    const GValue *value, GParamSpec *pspec)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_FILENAME:
+		/* Construct only */
+		priv->filename = g_value_dup_string (value);
+		break;
+	case PROP_UNMANAGED:
+		priv->unmanaged = g_value_dup_string (value);
+		break;
+	case PROP_UDI:
+		/* Construct only */
+		priv->udi = g_value_dup_string (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+		    GValue *value, GParamSpec *pspec)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_FILENAME:
+		g_value_set_string (value, priv->filename);
+		break;
+	case PROP_UNMANAGED:
+		g_value_set_string (value, priv->unmanaged);
+		break;
+	case PROP_UDI:
+		g_value_set_string (value, priv->udi);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (ifcfg_connection_class);
+
+	g_type_class_add_private (ifcfg_connection_class, sizeof (NMIfcfgConnectionPrivate));
+
+	/* Virtual methods */
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+	object_class->finalize     = finalize;
+
+	/* Properties */
+	g_object_class_install_property
+		(object_class, PROP_FILENAME,
+		 g_param_spec_string (NM_IFCFG_CONNECTION_FILENAME,
+						  "FileName",
+						  "File name",
+						  NULL,
+						  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_UNMANAGED,
+		 g_param_spec_string (NM_IFCFG_CONNECTION_UNMANAGED,
+						  "Unmanaged",
+						  "Unmanaged",
+						  NULL,
+						  G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_UDI,
+		 g_param_spec_string (NM_IFCFG_CONNECTION_UDI,
+						  "UDI",
+						  "UDI",
+						  NULL,
+						  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	signals[IFCFG_CHANGED] =
+		g_signal_new ("ifcfg-changed",
+		              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/system-settings/plugins/ifcfg-mdv/nm-ifcfg-connection.h b/system-settings/plugins/ifcfg-mdv/nm-ifcfg-connection.h
new file mode 100644
index 0000000..5cac5d9
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/nm-ifcfg-connection.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifndef NM_IFCFG_CONNECTION_H
+#define NM_IFCFG_CONNECTION_H
+
+G_BEGIN_DECLS
+
+#include <NetworkManager.h>
+#include <nm-sysconfig-connection.h>
+
+#define NM_TYPE_IFCFG_CONNECTION            (nm_ifcfg_connection_get_type ())
+#define NM_IFCFG_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnection))
+#define NM_IFCFG_CONNECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionClass))
+#define NM_IS_IFCFG_CONNECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IFCFG_CONNECTION))
+#define NM_IS_IFCFG_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_IFCFG_CONNECTION))
+#define NM_IFCFG_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionClass))
+
+#define NM_IFCFG_CONNECTION_FILENAME  "filename"
+#define NM_IFCFG_CONNECTION_UNMANAGED "unmanaged"
+#define NM_IFCFG_CONNECTION_UDI       "udi"
+
+typedef struct {
+	NMSysconfigConnection parent;
+} NMIfcfgConnection;
+
+typedef struct {
+	NMSysconfigConnectionClass parent;
+} NMIfcfgConnectionClass;
+
+GType nm_ifcfg_connection_get_type (void);
+
+NMIfcfgConnection *nm_ifcfg_connection_new (const char *filename,
+                                            GError **error,
+                                            gboolean *ignore_error);
+
+const char *nm_ifcfg_connection_get_filename (NMIfcfgConnection *self);
+
+const char *nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self);
+
+gboolean nm_ifcfg_connection_update (NMIfcfgConnection *self,
+                                     GHashTable *new_settings,
+                                     GError **error);
+
+G_END_DECLS
+
+#endif /* NM_IFCFG_CONNECTION_H */
diff --git a/system-settings/plugins/ifcfg-mdv/parse_wpa_supplicant_conf.c b/system-settings/plugins/ifcfg-mdv/parse_wpa_supplicant_conf.c
new file mode 100644
index 0000000..e879c26
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/parse_wpa_supplicant_conf.c
@@ -0,0 +1,536 @@
+#include <errno.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "utils.h"
+#include "common.h"
+
+#include "parse_wpa_supplicant_conf.h"
+
+struct _WPAConfig {
+	gchar		*file;	/* wpa_supplicant.conf file name */
+	GString		*line;	/* Input buffer */
+	GRegex		*skip;	/* Filter for comments */
+	GRegex		*network;	/* Start of network definition */
+	GRegex		*fini;		/* Closing curly bracket */
+	GRegex		*keyval;	/* (key, val) pair in network def */
+	GSList		*list;		/* list of networks */
+	GSList		*next;		/* list iterator */
+};
+
+struct _WPANetwork {
+	WPAConfig	*parent;	/* IO channel etc */
+	GHashTable	*keyvals;	/* content */
+};
+
+static gchar *
+parse_wpa_string(const gchar *value, gsize *len)
+{
+	gchar *str;
+	gsize l;
+
+	if (*value == '"') {
+		const gchar *pos;
+		value++;
+		pos = strrchr(value, '"');
+		if (pos == NULL || pos[1] != '\0')
+			return NULL;
+		l = pos - value;
+		str = g_malloc(l + 1);
+		if (str == NULL)
+			return NULL;
+		memcpy(str, value, l);
+		str[l] = '\0';
+	} else {
+		l = strlen(value);
+		str = utils_hexstr2bin(value, l);
+		if (str == NULL)
+			return NULL;
+	}
+
+	if (len)
+		*len = l;
+	return str;
+}
+
+
+WPAConfig *
+ifcfg_mdv_wpa_config_new(gchar *file)
+{
+	WPAConfig *wpac;
+
+	g_return_val_if_fail(file != NULL, NULL);
+
+	wpac = g_new(WPAConfig, 1);
+	if (!wpac)
+		return NULL;
+
+	wpac->file = g_strdup(file);
+	wpac->line = g_string_new("");
+
+	wpac->skip = g_regex_new("^\\s*(#.*)?$", 0, 0, NULL);
+	wpac->network = g_regex_new("^\\s*network\\s*=\\s*{\\s*$", 0, 0, NULL);
+	wpac->fini = g_regex_new("^\\s*}\\s*$", 0, 0, NULL);
+	wpac->keyval = g_regex_new("^\\s*([\\w\\d]+)\\s*=\\s*(\\S+.*\\S*)\\s*$", 0, 0, NULL);
+	wpac->list = NULL;
+	wpac->next = NULL;
+
+	if (!wpac->file || !wpac->line || !wpac->skip ||
+	    !wpac->network || !wpac->fini || !wpac->keyval) {
+		ifcfg_mdv_wpa_config_free(wpac);
+		return NULL;
+	}
+
+	return wpac;
+}
+
+void
+ifcfg_mdv_wpa_config_free(WPAConfig *wpac)
+{
+	GSList *l;
+
+	if (!wpac)
+		return;
+
+	for (l = wpac->list; l; l = g_slist_next(l))
+		ifcfg_mdv_wpa_network_free(l->data);
+
+	g_slist_free(wpac->list);
+
+	g_regex_unref(wpac->skip);
+	g_regex_unref(wpac->network);
+	g_regex_unref(wpac->fini);
+	g_regex_unref(wpac->keyval);
+
+	g_string_free(wpac->line, TRUE);
+	g_free(wpac->file);
+
+	g_free(wpac);
+}
+
+WPANetwork *
+ifcfg_mdv_wpa_network_new(WPAConfig *wpac)
+{
+	WPANetwork *wpan;
+
+	// g_return_val_if_fail(wpac != NULL, NULL);
+
+	wpan = g_new(WPANetwork, 1);
+	if (!wpan)
+		return NULL;
+
+	wpan->keyvals = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	if (!wpan->keyvals) {
+		g_free(wpan);
+		return NULL;
+	}
+	wpan->parent = wpac;
+
+	return wpan;
+}
+
+void
+ifcfg_mdv_wpa_network_free(WPANetwork *wpan)
+{
+	if (!wpan)
+		return;
+
+	g_hash_table_destroy(wpan->keyvals);
+	g_free(wpan);
+}
+
+static void
+free_list(GSList **list)
+{
+	GSList *n;
+
+	for (n = *list; n; n = g_slist_next(n))
+		g_free(n->data);
+	if (*list)
+		g_slist_free(*list);
+	*list = NULL;
+}
+
+gboolean
+ifcfg_mdv_wpa_config_parse(WPAConfig *wpac)
+{
+	WPANetwork *wpan = NULL;
+	GIOChannel *ioc;
+	GMatchInfo *mi;
+	GError *error = NULL;
+
+	g_return_val_if_fail(wpac != NULL, FALSE);
+
+	ioc = g_io_channel_new_file(wpac->file, "r", &error);
+	if (!ioc) {
+		if (error->code == G_FILE_ERROR_NOENT) {
+			g_error_free(error);
+			return TRUE;
+		}
+		return FALSE;
+	}
+
+	while (g_io_channel_read_line_string(ioc, wpac->line, NULL, NULL) == G_IO_STATUS_NORMAL) {
+
+		if (g_regex_match(wpac->skip, wpac->line->str, 0, NULL))
+			continue;
+
+		if (!wpan && g_regex_match(wpac->network, wpac->line->str, 0, NULL)) {
+			wpan = ifcfg_mdv_wpa_network_new(wpac);
+			if (!wpan)
+				return FALSE;
+			continue;
+		}
+
+		if (wpan && g_regex_match(wpac->keyval, wpac->line->str, 0, &mi)) {
+			gchar *key = g_match_info_fetch(mi, 1);
+			gchar *val = g_match_info_fetch(mi, 2);
+			ifcfg_mdv_wpa_network_set_val(wpan, key, val);
+			g_free(key);
+			g_free(val);
+			continue;
+		}
+
+		if (wpan && g_regex_match(wpac->fini, wpac->line->str, 0, NULL)) {
+			wpac->list = g_slist_prepend(wpac->list, wpan);
+			wpac->next = wpac->list;
+			wpan = NULL;
+		}
+	}
+
+	g_match_info_free(mi);
+	g_io_channel_unref(ioc);
+
+	return TRUE;
+}
+
+WPANetwork *
+ifcfg_mdv_wpa_config_next(WPAConfig *wpac)
+{
+	GSList *l = wpac->next;
+
+	if (l)
+		wpac->next = g_slist_next(l);
+	else
+		wpac->next = wpac->list;
+
+	return l == NULL ? NULL : l->data;
+}
+
+void
+ifcfg_mdv_wpa_config_rewind(WPAConfig *wpac)
+{
+		wpac->next = wpac->list;
+}
+
+gpointer
+ifcfg_mdv_wpa_network_get_val(WPANetwork *wpan, const gchar *key)
+{
+	g_return_val_if_fail(wpan != NULL, NULL);
+
+	return g_hash_table_lookup(wpan->keyvals, key);
+}
+
+void
+ifcfg_mdv_wpa_network_set_val(WPANetwork *wpan, const gchar *key, const gchar *val)
+{
+	gchar *k, *v;
+
+	g_return_if_fail(wpan != NULL);
+	g_return_if_fail(key != NULL);
+	g_return_if_fail(val != NULL);
+
+	k = g_strdup(key);
+	v = g_strdup(val);
+	g_hash_table_replace(wpan->keyvals, k, v);
+}
+
+gchar *
+ifcfg_mdv_wpa_network_get_str(WPANetwork *wpan, const gchar *key)
+{
+	gchar *value;
+
+	g_return_val_if_fail(wpan != NULL, NULL);
+	g_return_val_if_fail(key != NULL, NULL);
+
+	value = ifcfg_mdv_wpa_network_get_val(wpan, key);
+	if (!value)
+		return NULL;
+
+	return parse_wpa_string(value, NULL);
+}
+
+GByteArray *
+ifcfg_mdv_wpa_network_get_ssid(WPANetwork *wpan)
+{
+	gchar *value, *ssid;
+	gsize len;
+	GByteArray *a;
+
+	g_return_val_if_fail(wpan != NULL, NULL);
+
+	value = ifcfg_mdv_wpa_network_get_val(wpan, "ssid");
+	if (!value)
+		return NULL;
+
+	ssid = parse_wpa_string(value, &len);
+	if (!ssid)
+		return NULL;
+	if (len == 0 || len > 32)
+		goto error;
+
+	a = g_byte_array_sized_new (len);
+	if (!a)
+		goto error;
+
+	g_byte_array_append (a, (const guint8 *) ssid, len);
+	g_free(ssid);
+	return a;
+
+error:
+	g_free(ssid);
+	return NULL;
+}
+
+void
+ifcfg_mdv_wpa_network_set_ssid(WPANetwork *wpan, const GByteArray *val)
+{
+	gchar buf[33];
+
+	g_return_if_fail(wpan != NULL);
+	g_return_if_fail(wpan != NULL);
+
+	if (val->len == 0 || val->len > 32)
+		return;
+
+	memcpy(buf, val->data, val->len);
+	buf[val->len] = '\0';
+	ifcfg_mdv_wpa_network_set_str(wpan, "ssid", buf);
+}
+
+void
+ifcfg_mdv_wpa_network_set_str(WPANetwork *wpan, const gchar *key, const gchar *val)
+{
+	const gchar *p;
+	gchar *str;
+	gboolean need_hex = FALSE;
+
+	/* We may get NULL for non-existing values */
+	if (!val) {
+		ifcfg_mdv_wpa_network_unset(wpan, key);
+		return;
+	}
+
+	for (p = val; *p; p++)
+		if (!g_ascii_isprint(*p)) {
+			need_hex = TRUE;
+			break;
+		}
+
+	if (need_hex)
+		str = utils_bin2hexstr(val, strlen(val), -1);
+	else
+		str = g_strdup_printf("\"%s\"", val);
+
+	if (str)
+		ifcfg_mdv_wpa_network_set_val(wpan, key, str);
+#if 0
+	else
+		PLUGIN_WARN(IFCFG_PLUGIN_NAME, "    warning: could not set value for wpa key %s", key);
+#endif
+	g_free(str);
+}
+
+void
+ifcfg_mdv_wpa_network_unset(WPANetwork *wpan, const gchar *key)
+{
+	g_return_if_fail(wpan != NULL);
+	g_return_if_fail(key != NULL);
+
+	g_hash_table_remove(wpan->keyvals, key);
+}
+
+static gboolean
+add_line(GSList **list, gchar *s)
+{
+	gchar *n;
+
+	g_return_val_if_fail(list != NULL, FALSE);
+	g_return_val_if_fail(s != NULL, FALSE);
+
+	n = g_strdup(s);
+	if (!n)
+		return FALSE;
+
+	*list = g_slist_append(*list, n);
+	if (!*list)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+dump_network(GSList **list, WPANetwork *wpan, GError **error)
+{
+	GHashTableIter iter;
+	gpointer key, val;
+	gchar *s;
+
+	g_return_val_if_fail(list != NULL, FALSE);
+	g_return_val_if_fail(wpan != NULL, FALSE);
+
+	if (!add_line(list, "network={\n"))
+		return FALSE;
+
+	g_hash_table_iter_init(&iter, wpan->keyvals);
+	while (g_hash_table_iter_next(&iter, &key, &val)) {
+
+		s = g_strdup_printf("\t%s=%s\n", (gchar *)key, (gchar *)val);
+		if (!s) {
+			g_set_error(error, ifcfg_plugin_error_quark(), 0,
+				"Out of memory");
+			return FALSE;
+		}
+		*list = g_slist_append(*list, s);
+		if (!*list)
+			return FALSE;
+	}
+
+	if (!add_line(list, "}\n"))
+		return FALSE;
+
+	return TRUE;
+}
+
+gboolean
+ifcfg_mdv_wpa_network_save(WPANetwork *wpan, gchar *file, GError **error)
+{
+	WPAConfig *wpac = NULL;
+	WPANetwork *o_wpan = NULL;
+	GIOStatus ret;
+	GSList *network = NULL, *wpa_rest = NULL, *l;
+	GIOChannel *ioc = NULL;
+	gsize written;
+	gchar *ssid;
+	gboolean result = FALSE, found = FALSE, delete = FALSE;
+	GMatchInfo *mi = NULL;
+
+	g_return_val_if_fail(wpan != NULL, FALSE);
+	g_return_val_if_fail(file != NULL, FALSE);
+
+	ssid = ifcfg_mdv_wpa_network_get_val(wpan, "ssid");
+	if (!ssid || !*ssid) {
+		g_set_error(error, ifcfg_plugin_error_quark(), 0,
+				"SSID is missing, unable to store wpa_supplicant configuration");
+		goto error;
+	}
+
+	/* Looks like a hack but it probably is not worth extra function */
+	if (ifcfg_mdv_wpa_network_get_val(wpan, "__DELETE__"))
+			delete = TRUE;
+
+	ioc = g_io_channel_new_file(file, "r", error);
+	if (!ioc) {
+		if ((*error)->code == G_FILE_ERROR_NOENT) {
+			g_error_free(*error);
+			*error = NULL;
+			goto no_input;
+		}
+		goto error;
+	}
+
+	wpac = ifcfg_mdv_wpa_config_new("");
+	if (!wpac)
+		goto error;
+
+	/* Read original file skipping network in wpan */
+	while ((ret = g_io_channel_read_line_string(ioc, wpac->line, NULL, error)) == G_IO_STATUS_NORMAL) {
+
+		/* shortcut */
+		if (found) {
+			if (!add_line(&wpa_rest, wpac->line->str))
+				goto error;
+			continue;
+		}
+
+		if (!o_wpan && g_regex_match(wpac->network, wpac->line->str, 0, NULL)) {
+			if (!add_line(&network, wpac->line->str))
+				goto error;
+			o_wpan = ifcfg_mdv_wpa_network_new(wpac);
+			if (!o_wpan)
+				goto error;
+			continue;
+		}
+
+		if (o_wpan && g_regex_match(wpac->keyval, wpac->line->str, 0, &mi)) {
+			gchar *key = g_match_info_fetch(mi, 1);
+			gchar *val = g_match_info_fetch(mi, 2);
+			ifcfg_mdv_wpa_network_set_val(o_wpan, key, val);
+			g_free(key);
+			g_free(val);
+
+			if (!add_line(&network, wpac->line->str))
+				goto error;
+			continue;
+		}
+
+		if (o_wpan && g_regex_match(wpac->fini, wpac->line->str, 0, NULL)) {
+			gchar *o_ssid;
+
+			if (!add_line(&network, wpac->line->str))
+				goto error;
+			o_ssid = ifcfg_mdv_wpa_network_get_val(o_wpan, "ssid");
+			if (!o_ssid || g_strcmp0(ssid, o_ssid)) {
+				wpa_rest = g_slist_concat(wpa_rest, network);
+				ifcfg_mdv_wpa_network_free(o_wpan);
+				o_wpan = NULL;
+				network = NULL;
+			} else {
+				ifcfg_mdv_wpa_network_free(o_wpan);
+				o_wpan = NULL;
+				found = TRUE;
+			}
+			continue;
+		}
+
+		if (!add_line(&wpa_rest, wpac->line->str))
+			goto error;
+	}
+
+	if (ret != G_IO_STATUS_EOF)
+		goto error;
+
+	g_io_channel_unref(ioc);
+	ioc = NULL;
+
+no_input:
+	if (!delete && !dump_network(&wpa_rest, wpan, error))
+		goto error;
+
+
+	ioc = g_io_channel_new_file(file, "w", error);
+	if (!ioc)
+		goto error;
+	g_chmod(file, 0600);
+
+	for (l = wpa_rest; l; l = g_slist_next(l))
+		if (g_io_channel_write_chars(ioc, l->data, -1, &written, error) != G_IO_STATUS_NORMAL)
+			goto error;
+	if (g_io_channel_flush(ioc, error) != G_IO_STATUS_NORMAL)
+		goto error;
+
+	result = TRUE;
+
+error:
+	ifcfg_mdv_wpa_config_free(wpac);
+	ifcfg_mdv_wpa_network_free(o_wpan);
+	free_list(&wpa_rest);
+	free_list(&network);
+	if (ioc)
+		g_io_channel_unref(ioc);
+	if (mi)
+		g_match_info_free(mi);
+
+	return result;
+}
diff --git a/system-settings/plugins/ifcfg-mdv/parse_wpa_supplicant_conf.h b/system-settings/plugins/ifcfg-mdv/parse_wpa_supplicant_conf.h
new file mode 100644
index 0000000..3222f85
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/parse_wpa_supplicant_conf.h
@@ -0,0 +1,27 @@
+#ifndef PARSE_WPA_SUPPLICANT_CONF_H
+#define PARSE_WPA_SUPPLICANT_CONF_H
+
+typedef struct _WPAConfig WPAConfig;
+typedef struct _WPANetwork WPANetwork;
+
+gboolean ifcfg_mdv_wpa_config_parse(WPAConfig *);
+void ifcfg_mdv_wpa_config_free(WPAConfig *);
+WPAConfig *ifcfg_mdv_wpa_config_new(gchar *);
+
+WPANetwork *ifcfg_mdv_wpa_config_next(WPAConfig *);
+void ifcfg_mdv_wpa_config_rewind(WPAConfig *);
+
+WPANetwork *ifcfg_mdv_wpa_network_new(WPAConfig *);
+void ifcfg_mdv_wpa_network_free(WPANetwork *);
+
+gpointer ifcfg_mdv_wpa_network_get_val(WPANetwork *, const gchar *);
+void ifcfg_mdv_wpa_network_set_val(WPANetwork *, const gchar *, const gchar *);
+gchar *ifcfg_mdv_wpa_network_get_str(WPANetwork *, const gchar *);
+void ifcfg_mdv_wpa_network_set_str(WPANetwork *, const gchar *, const gchar *);
+GByteArray *ifcfg_mdv_wpa_network_get_ssid(WPANetwork *);
+void ifcfg_mdv_wpa_network_set_ssid(WPANetwork *, const GByteArray *);
+void ifcfg_mdv_wpa_network_unset(WPANetwork *, const gchar *);
+
+gboolean ifcfg_mdv_wpa_network_save(WPANetwork *, gchar *, GError **);
+
+#endif /* PARSE_WPA_SUPPLICANT_CONF_H */
diff --git a/system-settings/plugins/ifcfg-mdv/plugin.c b/system-settings/plugins/ifcfg-mdv/plugin.c
new file mode 100644
index 0000000..fcc7de0
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/plugin.c
@@ -0,0 +1,753 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * Dan Williams <dcbw@redhat.com>
+ * Søren Sandmann <sandmann@daimi.au.dk>
+ *
+ * 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) 2007 - 2008 Red Hat, Inc.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <net/ethernet.h>
+#include <netinet/ether.h>
+
+#include <gmodule.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <dbus/dbus-glib.h>
+
+#include <nm-setting-connection.h>
+
+#include "common.h"
+#include "nm-dbus-glib-types.h"
+#include "plugin.h"
+#include "nm-system-config-interface.h"
+#include "nm-ifcfg-connection.h"
+#include "nm-inotify-helper.h"
+#include "shvar.h"
+#include "writer.h"
+#include "utils.h"
+#include "utils-mdv.h"
+
+static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
+
+static void connection_changed_handler (SCPluginIfcfg *plugin,
+                                        const char *path,
+                                        NMIfcfgConnection *connection,
+                                        gboolean *do_remove,
+                                        gboolean *do_new);
+
+static void handle_connection_remove_or_new (SCPluginIfcfg *plugin,
+                                             const char *path,
+                                             NMIfcfgConnection *connection,
+                                             gboolean do_remove,
+                                             gboolean do_new);
+
+G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0,
+						G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE,
+											   system_config_interface_init))
+
+#define SC_PLUGIN_IFCFG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgPrivate))
+
+
+typedef struct {
+	GHashTable *connections;
+
+	gulong ih_event_id;
+	int sc_network_wd;
+	char *hostname;
+
+	GFileMonitor *ifcfg_monitor;
+	guint ifcfg_monitor_id;
+
+	GFileMonitor *wireless_d_monitor;
+	guint wireless_d_monitor_id;
+
+	GFileMonitor *wpa_supplicant_monitor;
+	guint wpa_supplicant_monitor_id;
+} SCPluginIfcfgPrivate;
+
+
+static void
+connection_unmanaged_changed (NMIfcfgConnection *connection,
+                              GParamSpec *pspec,
+                              gpointer user_data)
+{
+	g_signal_emit_by_name (SC_PLUGIN_IFCFG (user_data), NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
+}
+
+static void
+connection_ifcfg_changed (NMIfcfgConnection *connection, gpointer user_data)
+{
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
+	gboolean do_remove = FALSE, do_new = FALSE;
+	const char *path;
+
+	path = nm_ifcfg_connection_get_filename (connection);
+	g_return_if_fail (path != NULL);
+
+	connection_changed_handler (plugin, path, connection, &do_remove, &do_new);
+	handle_connection_remove_or_new (plugin, path, connection, do_remove, do_new);
+}
+
+static NMIfcfgConnection *
+read_one_connection (SCPluginIfcfg *plugin, const char *filename)
+{
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	NMIfcfgConnection *connection;
+	GError *error = NULL;
+	gboolean ignore_error = FALSE;
+
+	PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "parsing %s ... ", filename);
+
+	connection = nm_ifcfg_connection_new (filename, &error, &ignore_error);
+	if (connection) {
+		NMSettingConnection *s_con;
+		const char *cid;
+
+		s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION);
+		g_assert (s_con);
+
+		cid = nm_setting_connection_get_id (s_con);
+		g_assert (cid);
+
+		g_hash_table_insert (priv->connections,
+		                     (gpointer) nm_ifcfg_connection_get_filename (connection),
+		                     g_object_ref (connection));
+		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "    read connection '%s'", cid);
+
+		if (nm_ifcfg_connection_get_unmanaged_spec (connection)) {
+			PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its "
+			              "device due to NM_CONTROLLED/BRIDGE/VLAN.", cid);
+		} else {
+			/* Wait for the connection to become unmanaged once it knows the
+			 * UDI of it's device, if/when the device gets plugged in.
+			 */
+			g_signal_connect (G_OBJECT (connection), "notify::unmanaged",
+			                  G_CALLBACK (connection_unmanaged_changed), plugin);
+		}
+
+		/* watch changes of ifcfg hardlinks */
+		g_signal_connect (G_OBJECT (connection), "ifcfg-changed",
+		                  G_CALLBACK (connection_ifcfg_changed), plugin);
+	} else {
+		if (!ignore_error) {
+			PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "    error: %s",
+			              (error && error->message) ? error->message : "(unknown)");
+		}
+		g_clear_error (&error);
+	}
+
+	return connection;
+}
+
+static void
+read_connections (SCPluginIfcfg *plugin)
+{
+	static const gchar *dirs[] = { IFCFG_DIR, IFCFG_WIRELESS_D_DIR, NULL };
+	const gchar **current;
+
+	for (current = dirs; current && *current; current++) {
+		GError *err = NULL;
+		GDir *dir = g_dir_open (*current, 0, &err);
+
+		if (dir) {
+			const char *item;
+
+			while ((item = g_dir_read_name (dir))) {
+				char *full_path = g_build_filename (*current, item, NULL);
+
+				if (mdv_should_ignore_file (full_path)) {
+					g_free(full_path);
+					continue;
+				}
+
+				read_one_connection (plugin, full_path);
+				g_free (full_path);
+			}
+
+			g_dir_close (dir);
+		} else {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "Can not read directory '%s': %s", *current, err->message);
+			g_error_free (err);
+		}
+	}
+}
+
+/* Monitoring */
+
+static void
+connection_changed_handler (SCPluginIfcfg *plugin,
+                            const char *path,
+                            NMIfcfgConnection *connection,
+                            gboolean *do_remove,
+                            gboolean *do_new)
+{
+	NMIfcfgConnection *new;
+	GError *error = NULL;
+	gboolean ignore_error = FALSE;
+	const char *new_unmanaged = NULL, *old_unmanaged = NULL;
+
+	g_return_if_fail (plugin != NULL);
+	g_return_if_fail (path != NULL);
+	g_return_if_fail (connection != NULL);
+	g_return_if_fail (do_remove != NULL);
+	g_return_if_fail (do_new != NULL);
+
+	PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "updating %s", path);
+
+	new = (NMIfcfgConnection *) nm_ifcfg_connection_new (path, &error, &ignore_error);
+	if (!new) {
+		/* errors reading connection; remove it */
+		if (!ignore_error) {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    error: %s",
+			             (error && error->message) ? error->message : "(unknown)");
+		}
+		g_clear_error (&error);
+
+		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", path);
+		*do_remove = TRUE;
+		return;
+	}
+
+	/* Successfully read connection changes */
+
+	old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (connection));
+	new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (new));
+
+	if (new_unmanaged) {
+		if (!old_unmanaged) {
+			/* Unexport the connection by destroying it, then re-creating it as unmanaged */
+			*do_remove = *do_new = TRUE;
+		}
+	} else {
+		if (old_unmanaged) {  /* now managed */
+			NMSettingConnection *s_con;
+			const char *cid;
+
+			s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (new), NM_TYPE_SETTING_CONNECTION);
+			g_assert (s_con);
+
+			cid = nm_setting_connection_get_id (s_con);
+			g_assert (cid);
+
+			PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Managing connection '%s' and its "
+			              "device because NM_CONTROLLED was true.", cid);
+			g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection);
+		}
+
+		if (!nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (connection),
+		                                     NM_CONNECTION (new),
+		                                     TRUE,
+		                                     &error)) {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    error updating: %s",
+			             (error && error->message) ? error->message : "(unknown)");
+			g_clear_error (&error);
+		}
+
+		/* Update unmanaged status */
+		g_object_set (connection, "unmanaged", new_unmanaged, NULL);
+		g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
+	}
+	g_object_unref (new);
+}
+
+static void
+handle_connection_remove_or_new (SCPluginIfcfg *plugin,
+                                 const char *path,
+                                 NMIfcfgConnection *connection,
+                                 gboolean do_remove,
+                                 gboolean do_new)
+{
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+
+	g_return_if_fail (plugin != NULL);
+	g_return_if_fail (path != NULL);
+
+	if (do_remove) {
+		const char *unmanaged;
+
+		g_return_if_fail (connection != NULL);
+
+		unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection);
+		g_hash_table_remove (priv->connections, path);
+		g_signal_emit_by_name (connection, "removed");
+
+		/* Emit unmanaged changes _after_ removing the connection */
+		if (unmanaged)
+			g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
+	}
+
+	if (do_new) {
+		connection = read_one_connection (plugin, path);
+		if (connection) {
+			if (nm_ifcfg_connection_get_unmanaged_spec (connection))
+				g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
+			else
+				g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection);
+		}
+	}
+}
+static void
+dir_changed (GFileMonitor *monitor,
+		   GFile *file,
+		   GFile *other_file,
+		   GFileMonitorEvent event_type,
+		   gpointer user_data)
+{
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	char *path, *name;
+	NMIfcfgConnection *connection;
+	gboolean do_remove = FALSE, do_new = FALSE;
+
+	path = g_file_get_path (file);
+	if (mdv_should_ignore_file (path)) {
+		g_free (path);
+		return;
+	}
+
+	/* Given any ifcfg, keys, or routes file, get the ifcfg file path */
+	name = mdv_get_ifcfg_path (path);
+	g_free (path);
+
+	connection = g_hash_table_lookup (priv->connections, name);
+	switch (event_type) {
+	case G_FILE_MONITOR_EVENT_DELETED:
+		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", name);
+		if (connection)
+			handle_connection_remove_or_new (plugin, name, connection, TRUE, FALSE);
+		break;
+	case G_FILE_MONITOR_EVENT_CREATED:
+	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+		/* Update */
+		if (!connection)
+			do_new = TRUE;
+		else
+			connection_changed_handler (plugin, name, connection, &do_remove, &do_new);
+
+		handle_connection_remove_or_new (plugin, name, connection, do_remove, do_new);
+		break;
+	default:
+		break;
+	}
+
+	g_free (name);
+}
+
+static void
+update_wireless (gpointer data,
+		gpointer user_data)
+{
+	NMIfcfgConnection *connection = data;
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
+
+	connection_ifcfg_changed (connection, plugin);
+}
+
+static void
+add_wireless_d_connection (gpointer key,
+		gpointer value,
+		gpointer user_data)
+{
+	GSList **list = user_data;
+	char *ifcfg = key;
+	NMIfcfgConnection *connection = value;
+
+	if (mdv_get_ifcfg_type (ifcfg) == MdvIfcfgTypeSSID)
+		*list = g_slist_prepend (*list, g_object_ref (connection));
+}
+
+static void
+wpa_supplicant_changed (GFileMonitor *monitor,
+		   GFile *file,
+		   GFile *other_file,
+		   GFileMonitorEvent event_type,
+		   gpointer user_data)
+{
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	GSList *list = NULL;
+
+	switch (event_type) {
+	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+	case G_FILE_MONITOR_EVENT_CREATED:
+	case G_FILE_MONITOR_EVENT_DELETED:
+		g_hash_table_foreach (priv->connections, add_wireless_d_connection, &list);
+		break;
+	default:
+		return;
+		break;
+	}
+
+	g_slist_foreach (list, update_wireless, plugin);
+	g_slist_free_full (list, (GDestroyNotify) g_object_unref);
+}
+
+static void
+setup_ifcfg_monitoring (SCPluginIfcfg *plugin)
+{
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	GFile *file;
+	GFileMonitor *monitor;
+
+	priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+
+	file = g_file_new_for_path (IFCFG_DIR "/");
+	monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (file);
+
+	if (monitor) {
+		priv->ifcfg_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), plugin);
+		priv->ifcfg_monitor = monitor;
+	}
+
+	file = g_file_new_for_path (IFCFG_WIRELESS_D_DIR "/");
+	monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (file);
+
+	if (monitor) {
+		priv->wireless_d_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), plugin);
+		priv->wireless_d_monitor = monitor;
+	}
+
+	file = g_file_new_for_path ("/etc/wpa_supplicant.conf");
+	monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (file);
+
+	if (monitor) {
+		priv->wpa_supplicant_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (wpa_supplicant_changed), plugin);
+		priv->wpa_supplicant_monitor = monitor;
+	}
+}
+
+static GSList *
+get_connections (NMSystemConfigInterface *config)
+{
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	GSList *list = NULL;
+	GHashTableIter iter;
+	gpointer value;
+
+	if (!priv->connections) {
+		setup_ifcfg_monitoring (plugin);
+		read_connections (plugin);
+	}
+
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, &value)) {
+		NMIfcfgConnection *exported = NM_IFCFG_CONNECTION (value);
+
+		if (!nm_ifcfg_connection_get_unmanaged_spec (exported))
+			list = g_slist_prepend (list, value);
+	}
+
+	return list;
+}
+
+static void
+check_unmanaged (gpointer key, gpointer data, gpointer user_data)
+{
+	GSList **list = (GSList **) user_data;
+	NMIfcfgConnection *connection = NM_IFCFG_CONNECTION (data);
+	const char *unmanaged_spec;
+	GSList *iter;
+
+	unmanaged_spec = nm_ifcfg_connection_get_unmanaged_spec (connection);
+	if (!unmanaged_spec)
+		return;
+
+	/* Just return if the unmanaged spec is already in the list */
+	for (iter = *list; iter; iter = g_slist_next (iter)) {
+		if (!strcmp ((char *) iter->data, unmanaged_spec))
+			return;
+	}
+
+	*list = g_slist_prepend (*list, g_strdup (unmanaged_spec));
+}
+
+static GSList *
+get_unmanaged_specs (NMSystemConfigInterface *config)
+{
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);
+	GSList *list = NULL;
+
+	if (!priv->connections) {
+		setup_ifcfg_monitoring (plugin);
+		read_connections (plugin);
+	}
+
+	g_hash_table_foreach (priv->connections, check_unmanaged, &list);
+	return list;
+}
+
+static gboolean
+add_connection (NMSystemConfigInterface *config,
+                NMConnection *connection,
+                GError **error)
+{
+	return writer_new_connection (connection, IFCFG_DIR, NULL, error);
+}
+
+#define SC_NETWORK_FILE SYSCONFDIR"/sysconfig/network"
+
+static char *
+plugin_get_hostname (SCPluginIfcfg *plugin)
+{
+	shvarFile *network;
+	char *hostname;
+	gboolean ignore_localhost;
+
+	network = svNewFile (SC_NETWORK_FILE);
+	if (!network) {
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "Could not get hostname: failed to read " SC_NETWORK_FILE);
+		return FALSE;
+	}
+
+	hostname = svGetValue (network, "HOSTNAME", FALSE);
+	ignore_localhost = svTrueValue (network, "NM_IGNORE_HOSTNAME_LOCALHOST", FALSE);
+	if (ignore_localhost) {
+		/* Ignore a hostname of 'localhost' or 'localhost.localdomain' to preserve
+		 * 'network' service behavior.
+		 */
+		if (hostname && (!strcmp (hostname, "localhost") || !strcmp (hostname, "localhost.localdomain"))) {
+			g_free (hostname);
+			hostname = NULL;
+		}
+	}
+
+	svCloseFile (network);
+	return hostname;
+}
+
+static gboolean
+plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname)
+{
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	shvarFile *network;
+
+	network = svCreateFile (SC_NETWORK_FILE);
+	if (!network) {
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "Could not save hostname: failed to create/open " SC_NETWORK_FILE);
+		return FALSE;
+	}
+
+	svSetValue (network, "HOSTNAME", hostname, FALSE);
+	svWriteFile (network, 0644);
+	svCloseFile (network);
+
+	g_free (priv->hostname);
+	priv->hostname = hostname ? g_strdup (hostname) : NULL;
+	return TRUE;
+}
+
+static void
+sc_network_changed_cb (NMInotifyHelper *ih,
+                       struct inotify_event *evt,
+                       const char *path,
+                       gpointer user_data)
+{
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	char *new_hostname;
+
+	if (evt->wd != priv->sc_network_wd)
+		return;
+
+	new_hostname = plugin_get_hostname (plugin);
+	if (   (new_hostname && !priv->hostname)
+	    || (!new_hostname && priv->hostname)
+	    || (priv->hostname && new_hostname && strcmp (priv->hostname, new_hostname))) {
+		g_free (priv->hostname);
+		priv->hostname = new_hostname;
+		g_object_notify (G_OBJECT (plugin), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
+	} else
+		g_free (new_hostname);
+}
+
+static void
+init (NMSystemConfigInterface *config)
+{
+}
+
+static void
+sc_plugin_ifcfg_init (SCPluginIfcfg *plugin)
+{
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	NMInotifyHelper *ih;
+
+	ih = nm_inotify_helper_get ();
+	priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (sc_network_changed_cb), plugin);
+	priv->sc_network_wd = nm_inotify_helper_add_watch (ih, SC_NETWORK_FILE);
+
+	priv->hostname = plugin_get_hostname (plugin);
+}
+
+static void
+dispose (GObject *object)
+{
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (object);
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	NMInotifyHelper *ih;
+
+	ih = nm_inotify_helper_get ();
+
+	g_signal_handler_disconnect (ih, priv->ih_event_id);
+
+	if (priv->sc_network_wd >= 0)
+		nm_inotify_helper_remove_watch (ih, priv->sc_network_wd);
+
+	g_free (priv->hostname);
+
+	if (priv->connections)
+		g_hash_table_destroy (priv->connections);
+
+	if (priv->ifcfg_monitor) {
+		if (priv->ifcfg_monitor_id)
+			g_signal_handler_disconnect (priv->ifcfg_monitor, priv->ifcfg_monitor_id);
+
+		g_file_monitor_cancel (priv->ifcfg_monitor);
+		g_object_unref (priv->ifcfg_monitor);
+	}
+
+	if (priv->wireless_d_monitor) {
+		if (priv->wireless_d_monitor_id)
+			g_signal_handler_disconnect (priv->wireless_d_monitor, priv->wireless_d_monitor_id);
+
+		g_file_monitor_cancel (priv->wireless_d_monitor);
+		g_object_unref (priv->wireless_d_monitor);
+	}
+
+	if (priv->wpa_supplicant_monitor) {
+		if (priv->wpa_supplicant_monitor_id)
+			g_signal_handler_disconnect (priv->wpa_supplicant_monitor, priv->wpa_supplicant_monitor_id);
+
+		g_file_monitor_cancel (priv->wpa_supplicant_monitor);
+		g_object_unref (priv->wpa_supplicant_monitor);
+	}
+
+	G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+	G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->finalize (object);
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec)
+{
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
+		g_value_set_string (value, IFCFG_PLUGIN_NAME);
+		break;
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO:
+		g_value_set_string (value, IFCFG_PLUGIN_INFO);
+		break;
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
+		g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS | NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
+		break;
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
+		g_value_set_string (value, priv->hostname);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	const char *hostname;
+
+	switch (prop_id) {
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
+		hostname = g_value_get_string (value);
+		if (hostname && strlen (hostname) < 1)
+			hostname = NULL;
+		plugin_set_hostname (SC_PLUGIN_IFCFG (object), hostname);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+	g_type_class_add_private (req_class, sizeof (SCPluginIfcfgPrivate));
+
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+
+	g_object_class_override_property (object_class,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_NAME);
+
+	g_object_class_override_property (object_class,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_INFO);
+
+	g_object_class_override_property (object_class,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
+
+	g_object_class_override_property (object_class,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
+}
+
+static void
+system_config_interface_init (NMSystemConfigInterface *system_config_interface_class)
+{
+	/* interface implementation */
+	system_config_interface_class->get_connections = get_connections;
+	system_config_interface_class->add_connection = add_connection;
+	system_config_interface_class->get_unmanaged_specs = get_unmanaged_specs;
+	system_config_interface_class->init = init;
+}
+
+G_MODULE_EXPORT GObject *
+nm_system_config_factory (void)
+{
+	static SCPluginIfcfg *singleton = NULL;
+
+	if (!singleton)
+		singleton = SC_PLUGIN_IFCFG (g_object_new (SC_TYPE_PLUGIN_IFCFG, NULL));
+	else
+		g_object_ref (singleton);
+
+	return G_OBJECT (singleton);
+}
diff --git a/system-settings/plugins/ifcfg-mdv/plugin.h b/system-settings/plugins/ifcfg-mdv/plugin.h
new file mode 100644
index 0000000..d820a26
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/plugin.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * Dan Williams <dcbw@redhat.com>
+ * Søren Sandmann <sandmann@daimi.au.dk>
+ *
+ * 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) 2007 - 2008 Red Hat, Inc.
+ */
+
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+
+#include <glib-object.h>
+
+#define SC_TYPE_PLUGIN_IFCFG            (sc_plugin_ifcfg_get_type ())
+#define SC_PLUGIN_IFCFG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfg))
+#define SC_PLUGIN_IFCFG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass))
+#define SC_IS_PLUGIN_IFCFG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFCFG))
+#define SC_IS_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SC_TYPE_PLUGIN_IFCFG))
+#define SC_PLUGIN_IFCFG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass))
+
+typedef struct _SCPluginIfcfg SCPluginIfcfg;
+typedef struct _SCPluginIfcfgClass SCPluginIfcfgClass;
+
+struct _SCPluginIfcfg {
+	GObject parent;
+};
+
+struct _SCPluginIfcfgClass {
+	GObjectClass parent;
+};
+
+GType sc_plugin_ifcfg_get_type (void);
+
+#endif	/* _PLUGIN_H_ */
+
diff --git a/system-settings/plugins/ifcfg-mdv/reader.c b/system-settings/plugins/ifcfg-mdv/reader.c
new file mode 100644
index 0000000..3c80d9a
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/reader.c
@@ -0,0 +1,3777 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2008 - 2010 Red Hat, Inc.
+ * Mandriva-specific changes by Eugeni Dodonov <eugeni@mandriva.com>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sys/inotify.h>
+#include <errno.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <netinet/ether.h>
+#include <netinet/in.h>
+
+#ifndef __user
+#define __user
+#endif
+#include <linux/types.h>
+#include <wireless.h>
+#undef __user
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <nm-connection.h>
+#include <NetworkManager.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-ip4-config.h>
+#include <nm-setting-ip6-config.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-8021x.h>
+#include <nm-utils.h>
+
+#include "common.h"
+#include "shvar.h"
+#include "utils.h"
+#include "utils-mdv.h"
+
+#include "reader.h"
+#include "parse_wpa_supplicant_conf.h"
+
+#define PLUGIN_PRINT(pname, fmt, args...) \
+	{ g_message ("   " pname ": " fmt, ##args); }
+
+#define PLUGIN_WARN(pname, fmt, args...) \
+	{ g_warning ("   " pname ": " fmt, ##args); }
+
+static gboolean eap_simple_reader (const char *eap_method,
+				   WPANetwork *wpan,
+                                   shvarFile *ifcfg,
+                                   shvarFile *keys,
+                                   NMSetting8021x *s_8021x,
+                                   gboolean phase2,
+                                   GError **error);
+
+static gboolean eap_tls_reader (const char *eap_method,
+				WPANetwork *wpan,
+                                shvarFile *ifcfg,
+                                shvarFile *keys,
+                                NMSetting8021x *s_8021x,
+                                gboolean phase2,
+                                GError **error);
+
+static gboolean eap_peap_reader (const char *eap_method,
+				 WPANetwork *wpan,
+                                 shvarFile *ifcfg,
+                                 shvarFile *keys,
+                                 NMSetting8021x *s_8021x,
+                                 gboolean phase2,
+                                 GError **error);
+
+static gboolean eap_ttls_reader (const char *eap_method,
+				 WPANetwork *wpan,
+                                 shvarFile *ifcfg,
+                                 shvarFile *keys,
+                                 NMSetting8021x *s_8021x,
+                                 gboolean phase2,
+                                 GError **error);
+
+static gboolean
+get_int (const char *str, int *value)
+{
+	char *e;
+
+	errno = 0;
+	*value = strtol (str, &e, 0);
+	if (errno || *e != '\0')
+		return FALSE;
+
+	return TRUE;
+}
+
+static NMSetting *
+make_connection_setting (const char *file,
+                         shvarFile *ifcfg,
+                         const char *type,
+                         const char *suggested)
+{
+	NMSettingConnection *s_con;
+	char *ifcfg_name = NULL;
+	char *new_id = NULL, *uuid = NULL, *value;
+	char *ifcfg_id;
+	int onboot, nm_onboot;
+
+	ifcfg_name = mdv_get_ifcfg_name (file);
+	if (!ifcfg_name)
+		return NULL;
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+
+	/* Try the ifcfg file's internally defined name if available */
+	ifcfg_id = svGetValue (ifcfg, "NAME", FALSE);
+	if (ifcfg_id && strlen (ifcfg_id))
+		g_object_set (s_con, NM_SETTING_CONNECTION_ID, ifcfg_id, NULL);
+
+	if (!nm_setting_connection_get_id (s_con)) {
+		if (suggested) {
+			/* For cosmetic reasons, if the suggested name is the same as
+			 * the ifcfg files name, don't use it.  Mainly for wifi so that
+			 * the SSID is shown in the connection ID instead of just "wlan0".
+			 */
+			if (strcmp (ifcfg_name, suggested)) {
+				new_id = g_strdup_printf ("%s %s (%s)", reader_get_prefix (), suggested, ifcfg_name);
+				g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
+			}
+		}
+
+		/* Use the ifcfg file's name as a last resort */
+		if (!nm_setting_connection_get_id (s_con)) {
+			new_id = g_strdup_printf ("%s %s", reader_get_prefix (), ifcfg_name);
+			g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
+		}
+	}
+
+	g_free (new_id);
+	g_free (ifcfg_id);
+
+	/* Try for a UUID key before falling back to hashing the file name */
+	uuid = svGetValue (ifcfg, "UUID", FALSE);
+	if (!uuid || !strlen (uuid)) {
+		g_free (uuid);
+		uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName);
+	}
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_TYPE, type,
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NULL);
+	g_free (uuid);
+
+	/* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */
+	onboot = svTrueValue (ifcfg, "ONBOOT", TRUE);
+	/* make sure existing ifcfg still works after migration */
+	nm_onboot = svTrueValue (ifcfg, "_NM_ONBOOT", -1);
+	if (nm_onboot != -1)
+		onboot = nm_onboot;
+	g_object_set (s_con, NM_SETTING_CONNECTION_AUTOCONNECT,
+	              onboot,
+	              NULL);
+
+	value = svGetValue (ifcfg, "LAST_CONNECT", FALSE);
+	if (value) {
+		unsigned long int tmp;
+		guint64 timestamp;
+
+		errno = 0;
+		tmp = strtoul (value, NULL, 10);
+		if (errno == 0) {
+			timestamp = (guint64) tmp;
+			g_object_set (s_con, NM_SETTING_CONNECTION_TIMESTAMP, timestamp, NULL);
+		} else
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid LAST_CONNECT time");
+		g_free (value);
+	}
+
+	return NM_SETTING (s_con);
+}
+
+static gboolean
+discover_mac_address(char *device, GByteArray **array, GError **error)
+{
+	int fd, ret;
+	struct ifreq ifr;
+
+	g_return_val_if_fail (device != NULL, FALSE);
+	g_return_val_if_fail (array != NULL, FALSE);
+	g_return_val_if_fail (*array == NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		g_set_error(error, IFCFG_PLUGIN_ERROR, errno,
+				"Unable to discover MAC address: socket error");
+		return FALSE;
+	}
+
+	ifr.ifr_addr.sa_family = AF_INET;
+	strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
+
+	ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
+	if (ret < 0) {
+		g_set_error(error, IFCFG_PLUGIN_ERROR, errno,
+				"Unable to discover MAC address: ioctl error");
+		return FALSE;
+	}
+	close(fd);
+
+	*array = g_byte_array_sized_new (ETH_ALEN);
+	g_byte_array_append (*array, (guint8 *) ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+	return TRUE;
+}
+
+static gboolean
+read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError **error)
+{
+	char *value = NULL;
+	struct ether_addr *mac;
+
+	g_return_val_if_fail (ifcfg != NULL, FALSE);
+	g_return_val_if_fail (array != NULL, FALSE);
+	g_return_val_if_fail (*array == NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	value = svGetValue (ifcfg, key, FALSE);
+	if (!value || !strlen (value)) {
+		g_free (value);
+		return TRUE;
+	}
+
+	mac = ether_aton (value);
+	if (!mac) {
+		g_free (value);
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "%s: the MAC address '%s' was invalid.", key, value);
+		return FALSE;
+	}
+
+	g_free (value);
+	*array = g_byte_array_sized_new (ETH_ALEN);
+	g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN);
+	return TRUE;
+}
+
+/* Mandriva does not seem to ever hex-encode SSID in ifcfg. So do not bother
+ * as well - just get what we have. This highly simplifies the logic */
+/* FIXME this currently fails for '\0' which is not accepted as input either */
+GByteArray *
+ifcfg_mdv_parse_ssid(char *value, GError **error)
+{
+	gsize ssid_len;
+	gchar *ssid = NULL;
+	GByteArray *a;
+
+	ssid = g_strdup(value);
+	if (!ssid) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		     "Cannot duplicate SSID");
+		goto error;
+	}
+	svUnescape (ssid);
+	ssid_len = strlen (ssid);
+	if (ssid_len > 32 || ssid_len == 0) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
+			     value, ssid_len);
+		goto error;
+	}
+
+	a = g_byte_array_sized_new (ssid_len);
+	if (!a) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "Cannot allocate SSID");
+		goto error;
+	}
+
+	g_byte_array_append (a, (const guint8 *) ssid, ssid_len);
+	g_free(ssid);
+
+	return a;
+
+error:
+	g_free(ssid);
+	return NULL;
+}
+
+#if 0
+/* no iSCSI on Mandriva */
+static void
+iscsiadm_child_setup (gpointer user_data G_GNUC_UNUSED)
+{
+	/* We are in the child process here; set a different process group to
+	 * ensure signal isolation between child and parent.
+	 */
+	pid_t pid = getpid ();
+	setpgid (pid, pid);
+}
+
+static char *
+match_iscsiadm_tag (const char *line, const char *tag, gboolean *skip)
+{
+	char *p;
+
+	if (g_ascii_strncasecmp (line, tag, strlen (tag)))
+		return NULL;
+
+	p = strchr (line, '=');
+	if (!p) {
+		g_warning ("%s: malformed iscsiadm record: no = in '%s'.",
+		           __func__, line);
+		*skip = TRUE;
+		return NULL;
+	}
+
+	p++; /* advance past = */
+	return g_strstrip (p);
+}
+
+#define ISCSI_HWADDR_TAG    "iface.hwaddress"
+#define ISCSI_BOOTPROTO_TAG "iface.bootproto"
+#define ISCSI_IPADDR_TAG    "iface.ipaddress"
+#define ISCSI_SUBNET_TAG    "iface.subnet_mask"
+#define ISCSI_GATEWAY_TAG   "iface.gateway"
+#define ISCSI_DNS1_TAG      "iface.primary_dns"
+#define ISCSI_DNS2_TAG      "iface.secondary_dns"
+
+static gboolean
+fill_ip4_setting_from_ibft (shvarFile *ifcfg,
+                            NMSettingIP4Config *s_ip4,
+                            const char *iscsiadm_path,
+                            GError **error)
+{
+	const char *argv[4] = { iscsiadm_path, "-m", "fw", NULL };
+	const char *envp[1] = { NULL };
+	gboolean success = FALSE, in_record = FALSE, hwaddr_matched = FALSE, skip = FALSE;
+	char *out = NULL, *err = NULL;
+	gint status = 0;
+	GByteArray *ifcfg_mac = NULL;
+	char **lines = NULL, **iter;
+	const char *method = NULL;
+	struct in_addr ipaddr;
+	struct in_addr gateway;
+	struct in_addr dns1;
+	struct in_addr dns2;
+	guint32 prefix = 0;
+
+	g_return_val_if_fail (s_ip4 != NULL, FALSE);
+	g_return_val_if_fail (iscsiadm_path != NULL, FALSE);
+
+	if (!g_spawn_sync ("/", (char **) argv, (char **) envp, 0,
+	                   iscsiadm_child_setup, NULL, &out, &err, &status, error))
+		return FALSE;
+
+	if (!WIFEXITED (status)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "%s exited abnormally.", iscsiadm_path);
+		goto done;
+	}
+
+	if (WEXITSTATUS (status) != 0) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "%s exited with error %d.  Message: '%s'",
+		             iscsiadm_path, WEXITSTATUS (status), err ? err : "(none)");
+		goto done;
+	}
+
+	if (!read_mac_address (ifcfg, "HWADDR", &ifcfg_mac, error))
+		goto done;
+	/* Ensure we got a MAC */
+	if (!ifcfg_mac) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing device MAC address (no HWADDR tag present).");
+		goto done;
+	}
+
+	memset (&ipaddr, 0, sizeof (ipaddr));
+	memset (&gateway, 0, sizeof (gateway));
+	memset (&dns1, 0, sizeof (dns1));
+	memset (&dns2, 0, sizeof (dns2));
+
+	/* Success, lets parse the output */
+	lines = g_strsplit_set (out, "\n\r", -1);
+	for (iter = lines; iter && *iter; iter++) {
+		char *p;
+
+		if (!g_ascii_strcasecmp (*iter, "# BEGIN RECORD")) {
+			if (in_record) {
+				g_warning ("%s: malformed iscsiadm record: already parsing record.", __func__);
+				skip = TRUE;
+			}
+		} else if (!g_ascii_strcasecmp (*iter, "# END RECORD")) {
+			if (!skip && hwaddr_matched) {
+				/* Record is good; fill IP4 config with its info */
+				if (!method) {
+					g_warning ("%s: malformed iscsiadm record: missing BOOTPROTO.", __func__);
+					return FALSE;
+				}
+
+				g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, method, NULL);
+
+				if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
+					NMIP4Address *addr;
+
+				    if (!ipaddr.s_addr || !prefix) {
+						g_warning ("%s: malformed iscsiadm record: BOOTPROTO=static "
+						           "but missing IP address or prefix.", __func__);
+						return FALSE;
+					}
+
+					addr = nm_ip4_address_new ();
+					nm_ip4_address_set_address (addr, ipaddr.s_addr);
+					nm_ip4_address_set_prefix (addr, prefix);
+					nm_ip4_address_set_gateway (addr, gateway.s_addr);
+					nm_setting_ip4_config_add_address (s_ip4, addr);
+					nm_ip4_address_unref (addr);
+
+					if (dns1.s_addr)
+						nm_setting_ip4_config_add_dns (s_ip4, dns1.s_addr);
+					if (dns2.s_addr)
+						nm_setting_ip4_config_add_dns (s_ip4, dns2.s_addr);
+
+					// FIXME: DNS search domains?
+				}
+				return TRUE;
+			}
+			skip = FALSE;
+			hwaddr_matched = FALSE;
+			memset (&ipaddr, 0, sizeof (ipaddr));
+			memset (&gateway, 0, sizeof (gateway));
+			memset (&dns1, 0, sizeof (dns1));
+			memset (&dns2, 0, sizeof (dns2));
+			prefix = 0;
+			method = NULL;
+		}
+
+		if (skip)
+			continue;
+
+		/* HWADDR */
+		if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_HWADDR_TAG, &skip))) {
+			struct ether_addr *ibft_mac;
+
+			ibft_mac = ether_aton (p);
+			if (!ibft_mac) {
+				g_warning ("%s: malformed iscsiadm record: invalid hwaddress.", __func__);
+				skip = TRUE;
+				continue;
+			}
+
+			if (memcmp (ifcfg_mac->data, (guint8 *) ibft_mac->ether_addr_octet, ETH_ALEN)) {
+				/* This record isn't for the current device, ignore it */
+				skip = TRUE;
+				continue;
+			}
+
+			/* Success, this record is for this device */
+			hwaddr_matched = TRUE;
+		}
+
+		/* BOOTPROTO */
+		if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_BOOTPROTO_TAG, &skip))) {
+			if (!g_ascii_strcasecmp (p, "dhcp"))
+				method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+			else if (!g_ascii_strcasecmp (p, "static"))
+				method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
+			else {
+				g_warning ("%s: malformed iscsiadm record: unknown BOOTPROTO '%s'.",
+				           __func__, p);
+				skip = TRUE;
+				continue;
+			}
+		}
+
+		if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_IPADDR_TAG, &skip))) {
+			if (inet_pton (AF_INET, p, &ipaddr) < 1) {
+				g_warning ("%s: malformed iscsiadm record: invalid IP address '%s'.",
+				           __func__, p);
+				skip = TRUE;
+				continue;
+			}
+		}
+
+		if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_SUBNET_TAG, &skip))) {
+			struct in_addr mask;
+
+			if (inet_pton (AF_INET, p, &mask) < 1) {
+				g_warning ("%s: malformed iscsiadm record: invalid subnet mask '%s'.",
+				           __func__, p);
+				skip = TRUE;
+				continue;
+			}
+
+			prefix = nm_utils_ip4_netmask_to_prefix (mask.s_addr);
+		}
+
+		if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_GATEWAY_TAG, &skip))) {
+			if (inet_pton (AF_INET, p, &gateway) < 1) {
+				g_warning ("%s: malformed iscsiadm record: invalid IP gateway '%s'.",
+				           __func__, p);
+				skip = TRUE;
+				continue;
+			}
+		}
+
+		if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS1_TAG, &skip))) {
+			if (inet_pton (AF_INET, p, &dns1) < 1) {
+				g_warning ("%s: malformed iscsiadm record: invalid DNS1 address '%s'.",
+				           __func__, p);
+				skip = TRUE;
+				continue;
+			}
+		}
+
+		if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS2_TAG, &skip))) {
+			if (inet_pton (AF_INET, p, &dns2) < 1) {
+				g_warning ("%s: malformed iscsiadm record: invalid DNS2 address '%s'.",
+				           __func__, p);
+				skip = TRUE;
+				continue;
+			}
+		}
+	}
+
+	success = TRUE;
+
+done:
+	if (ifcfg_mac)
+		g_byte_array_free (ifcfg_mac, TRUE);
+	g_strfreev (lines);
+	g_free (out);
+	g_free (err);
+	return success;
+}
+#endif
+
+static gboolean
+read_ip4_address (shvarFile *ifcfg,
+                  const char *tag,
+                  guint32 *out_addr,
+                  GError **error)
+{
+	char *value = NULL;
+	struct in_addr ip4_addr;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (ifcfg != NULL, FALSE);
+	g_return_val_if_fail (tag != NULL, FALSE);
+	g_return_val_if_fail (out_addr != NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	*out_addr = 0;
+
+	value = svGetValue (ifcfg, tag, FALSE);
+	if (!value)
+		return TRUE;
+
+	if (inet_pton (AF_INET, value, &ip4_addr) > 0) {
+		*out_addr = ip4_addr.s_addr;
+		success = TRUE;
+	} else {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Invalid %s IP4 address '%s'", tag, value);
+	}
+	g_free (value);
+	return success;
+}
+
+#if 0
+No IPv6 on Mandriva
+static gboolean
+parse_ip6_address (const char *value,
+                  struct in6_addr *out_addr,
+                  GError **error)
+{
+	struct in6_addr ip6_addr;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (value != NULL, FALSE);
+	g_return_val_if_fail (out_addr != NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	*out_addr = in6addr_any;
+
+	if (inet_pton (AF_INET6, value, &ip6_addr) > 0) {
+		*out_addr = ip6_addr;
+		success = TRUE;
+	} else {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Invalid IP6 address '%s'", value);
+	}
+	return success;
+}
+#endif
+
+static NMIP4Address *
+read_full_ip4_address (shvarFile *ifcfg,
+                       const char *network_file,
+                       guint32 which,
+                       GError **error)
+{
+	NMIP4Address *addr;
+	char *ip_tag, *prefix_tag, *netmask_tag, *gw_tag;
+	guint32 tmp;
+	gboolean success = FALSE;
+	shvarFile *network_ifcfg;
+	char *value;
+
+	g_return_val_if_fail (which > 0, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+	g_return_val_if_fail (network_file != NULL, NULL);
+
+	/* Mandriva does not seem to use more than one address */
+	if (which != 1)
+		return NULL;
+
+	addr = nm_ip4_address_new ();
+	if (which == 1) {
+		ip_tag = g_strdup ("IPADDR");
+		prefix_tag = g_strdup ("PREFIX");
+		netmask_tag = g_strdup ("NETMASK");
+		gw_tag = g_strdup ("GATEWAY");
+	} else {
+		ip_tag = g_strdup_printf ("IPADDR%u", which);
+		prefix_tag = g_strdup_printf ("PREFIX%u", which);
+		netmask_tag = g_strdup_printf ("NETMASK%u", which);
+		gw_tag = g_strdup_printf ("GATEWAY%u", which);
+	}
+
+	/* IP address */
+	if (!read_ip4_address (ifcfg, ip_tag, &tmp, error))
+		goto error;
+	if (!tmp) {
+		nm_ip4_address_unref (addr);
+		addr = NULL;
+		success = TRUE;  /* done */
+		goto error;
+	}
+	nm_ip4_address_set_address (addr, tmp);
+
+	/* Gateway */
+	if (!read_ip4_address (ifcfg, gw_tag, &tmp, error))
+		goto error;
+	if (tmp)
+		nm_ip4_address_set_gateway (addr, tmp);
+	else {
+		gboolean read_success;
+
+		/* If no gateway in the ifcfg, try /etc/sysconfig/network instead */
+		network_ifcfg = svNewFile (network_file);
+		if (network_ifcfg) {
+			read_success = read_ip4_address (network_ifcfg, "GATEWAY", &tmp, error);
+			svCloseFile (network_ifcfg);
+			if (!read_success)
+				goto error;
+			nm_ip4_address_set_gateway (addr, tmp);
+		}
+	}
+
+	/* NETMASK */
+	if (!read_ip4_address (ifcfg, netmask_tag, &tmp, error))
+		goto error;
+	nm_ip4_address_set_prefix (addr, nm_utils_ip4_netmask_to_prefix (tmp));
+
+
+	/* Fall back to PERFIX if no NETMASK was specified */
+	if (!nm_ip4_address_get_prefix (addr)) {
+		value = svGetValue (ifcfg, prefix_tag, FALSE);
+		if (value) {
+			long int prefix;
+
+			errno = 0;
+			prefix = strtol (value, NULL, 10);
+			if (errno || prefix <= 0 || prefix > 32) {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					     "Invalid IP4 prefix '%s'", value);
+				g_free (value);
+				goto error;
+			}
+			nm_ip4_address_set_prefix (addr, (guint32) prefix);
+			g_free (value);
+		}
+	}
+
+	/* Try to autodetermine the prefix for the address' class */
+	if (!nm_ip4_address_get_prefix (addr)) {
+		guint32 prefix = 0;
+
+		prefix = nm_utils_ip4_get_default_prefix (nm_ip4_address_get_address (addr));
+		nm_ip4_address_set_prefix (addr, prefix);
+
+		value = svGetValue (ifcfg, ip_tag, FALSE);
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: missing %s, assuming %s/%u",
+		             prefix_tag, value, prefix);
+		g_free (value);
+	}
+
+	/* Validate the prefix */
+	if (nm_ip4_address_get_prefix (addr) > 32) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing or invalid IP4 prefix '%d'",
+		             nm_ip4_address_get_prefix (addr));
+		goto error;
+	}
+
+	success = TRUE;
+
+error:
+	if (!success) {
+		nm_ip4_address_unref (addr);
+		addr = NULL;
+	}
+
+	g_free (ip_tag);
+	g_free (prefix_tag);
+	g_free (netmask_tag);
+	g_free (gw_tag);
+	return addr;
+}
+
+#if 0
+/* No routes on Mandriva */
+static NMIP4Route *
+read_one_ip4_route (shvarFile *ifcfg,
+                    const char *network_file,
+                    guint32 which,
+                    GError **error)
+{
+	NMIP4Route *route;
+	char *ip_tag, *netmask_tag, *gw_tag, *metric_tag, *value;
+	guint32 tmp;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+	g_return_val_if_fail (network_file != NULL, NULL);
+	g_return_val_if_fail (which >= 0, NULL);
+
+	route = nm_ip4_route_new ();
+
+	ip_tag = g_strdup_printf ("ADDRESS%u", which);
+	netmask_tag = g_strdup_printf ("NETMASK%u", which);
+	gw_tag = g_strdup_printf ("GATEWAY%u", which);
+	metric_tag = g_strdup_printf ("METRIC%u", which);
+
+	/* Destination */
+	if (!read_ip4_address (ifcfg, ip_tag, &tmp, error))
+		goto out;
+	if (!tmp) {
+		/* Check whether IP is missing or 0.0.0.0 */
+		char *val;
+		val = svGetValue (ifcfg, ip_tag, FALSE);
+		if (!val) {
+			nm_ip4_route_unref (route);
+			route = NULL;
+			success = TRUE;  /* done */
+			goto out;
+		}
+		g_free (val);
+	}
+	nm_ip4_route_set_dest (route, tmp);
+
+	/* Next hop */
+	if (!read_ip4_address (ifcfg, gw_tag, &tmp, error))
+		goto out;
+	if (!tmp) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing or invalid IP4 gateway address '%d'",
+		             tmp);
+		goto out;
+	}
+	nm_ip4_route_set_next_hop (route, tmp);
+
+	/* Prefix */
+	if (!read_ip4_address (ifcfg, netmask_tag, &tmp, error))
+		goto out;
+	nm_ip4_route_set_prefix (route, nm_utils_ip4_netmask_to_prefix (tmp));
+
+	/* Validate the prefix */
+	if (  !nm_ip4_route_get_prefix (route)
+	    || nm_ip4_route_get_prefix (route) > 32) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing or invalid IP4 prefix '%d'",
+		             nm_ip4_route_get_prefix (route));
+		goto out;
+	}
+
+	/* Metric */
+	value = svGetValue (ifcfg, metric_tag, FALSE);
+	if (value) {
+		long int metric;
+
+		errno = 0;
+		metric = strtol (value, NULL, 10);
+		if (errno || metric < 0) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid IP4 route metric '%s'", value);
+			g_free (value);
+			goto out;
+		}
+		nm_ip4_route_set_metric (route, (guint32) metric);
+		g_free (value);
+	}
+
+	success = TRUE;
+
+out:
+	if (!success) {
+		nm_ip4_route_unref (route);
+		route = NULL;
+	}
+
+	g_free (ip_tag);
+	g_free (netmask_tag);
+	g_free (gw_tag);
+	g_free (metric_tag);
+	return route;
+}
+
+static gboolean
+read_route_file_legacy (const char *filename, NMSettingIP4Config *s_ip4, GError **error)
+{
+	char *contents = NULL;
+	gsize len = 0;
+	char **lines = NULL, **iter;
+	GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
+	GMatchInfo *match_info;
+	NMIP4Route *route;
+	struct in_addr ip4_addr;
+	char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
+	long int prefix_int, metric_int;
+	gboolean success = FALSE;
+
+	const char *pattern_empty = "^\\s*(\\#.*)?$";
+	const char *pattern_to1 = "^\\s*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)"  /* IP or 'default' keyword */
+	                          "(?:/(\\d{1,2}))?";                                         /* optional prefix */
+	const char *pattern_to2 = "to\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */
+	                          "(?:/(\\d{1,2}))?";                                         /* optional prefix */
+	const char *pattern_via = "via\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})";       /* IP of gateway */
+	const char *pattern_metric = "metric\\s+(\\d+)";                                      /* metric */
+
+	g_return_val_if_fail (filename != NULL, FALSE);
+	g_return_val_if_fail (s_ip4 != NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	/* Read the route file */
+	if (!g_file_get_contents (filename, &contents, &len, NULL))
+		return FALSE;
+
+	if (len == 0) {
+		g_free (contents);
+		return FALSE;
+	}
+
+	/* Create regexes for pieces to be matched */
+	regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
+	regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
+	regex_via = g_regex_new (pattern_via, 0, 0, NULL);
+	regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
+
+	/* New NMIP4Route structure */
+	route = nm_ip4_route_new ();
+
+	/* Iterate through file lines */
+	lines = g_strsplit_set (contents, "\n\r", -1);
+	for (iter = lines; iter && *iter; iter++) {
+
+		/* Skip empty lines */
+		if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
+			continue;
+
+		/* Destination */
+		g_regex_match (regex_to1, *iter, 0, &match_info);
+		if (!g_match_info_matches (match_info)) {
+			g_match_info_free (match_info);
+			g_regex_match (regex_to2, *iter, 0, &match_info);
+			if (!g_match_info_matches (match_info)) {
+				g_match_info_free (match_info);
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					     "Missing IP4 route destination address in record: '%s'", *iter);
+				goto error;
+			}
+		}
+		dest = g_match_info_fetch (match_info, 1);
+		g_match_info_free (match_info);
+		if (!strcmp (dest, "default"))
+			strcpy (dest, "0.0.0.0");
+		if (inet_pton (AF_INET, dest, &ip4_addr) != 1) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Invalid IP4 route destination address '%s'", dest);
+			g_free (dest);
+			goto error;
+		}
+		nm_ip4_route_set_dest (route, ip4_addr.s_addr);
+		g_free (dest);
+
+		/* Prefix - is optional; 32 if missing */
+		prefix = g_match_info_fetch (match_info, 2);
+		prefix_int = 32;
+		if (prefix) {
+			errno = 0;
+			prefix_int = strtol (prefix, NULL, 10);
+			if (errno || prefix_int < 0 || prefix_int > 32) {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					     "Invalid IP4 route destination prefix '%s'", prefix);
+				g_free (prefix);
+				goto error;
+			}
+		}
+
+		nm_ip4_route_set_prefix (route, (guint32) prefix_int);
+		g_free (prefix);
+
+		/* Next hop */
+		g_regex_match (regex_via, *iter, 0, &match_info);
+		if (!g_match_info_matches (match_info)) {
+			g_match_info_free (match_info);
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Missing IP4 route gateway address in record: '%s'", *iter);
+			goto error;
+		}
+		next_hop = g_match_info_fetch (match_info, 1);
+		g_match_info_free (match_info);
+		if (inet_pton (AF_INET, next_hop, &ip4_addr) != 1) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid IP4 route gateway address '%s'", next_hop);
+			g_free (next_hop);
+			goto error;
+		}
+		nm_ip4_route_set_next_hop (route, ip4_addr.s_addr);
+		g_free (next_hop);
+
+		/* Metric */
+		g_regex_match (regex_metric, *iter, 0, &match_info);
+		metric_int = 0;
+		if (g_match_info_matches (match_info)) {
+			metric = g_match_info_fetch (match_info, 1);
+			errno = 0;
+			metric_int = strtol (metric, NULL, 10);
+			if (errno || metric_int < 0) {
+				g_match_info_free (match_info);
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				             "Invalid IP4 route metric '%s'", metric);
+				g_free (metric);
+				goto error;
+			}
+			g_free (metric);
+		}
+
+		nm_ip4_route_set_metric (route, (guint32) metric_int);
+		g_match_info_free (match_info);
+
+		if (!nm_setting_ip4_config_add_route (s_ip4, route))
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP4 route");
+
+	}
+
+	success = TRUE;
+
+error:
+	g_free (contents);
+	g_strfreev (lines);
+	nm_ip4_route_unref (route);
+	g_regex_unref (regex_to1);
+	g_regex_unref (regex_to2);
+	g_regex_unref (regex_via);
+	g_regex_unref (regex_metric);
+
+	return success;
+}
+#endif
+
+#if 0
+No IPv6 on Mandriva
+static NMIP6Address *
+parse_full_ip6_address (const char *addr_str, GError **error)
+{
+	NMIP6Address *addr = NULL;
+	char **list;
+	char *ip_tag, *prefix_tag;
+	struct in6_addr tmp = IN6ADDR_ANY_INIT;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (addr_str != NULL, NULL);
+	g_return_val_if_fail (error != NULL, NULL);
+	g_return_val_if_fail (*error == NULL, NULL);
+
+	/* Split the adddress and prefix */
+	list = g_strsplit_set (addr_str, "/", 2);
+	if (g_strv_length (list) < 1) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Invalid IP6 address '%s'", addr_str);
+		goto error;
+	}
+
+	ip_tag = list[0];
+	prefix_tag = list[1];
+
+	addr = nm_ip6_address_new ();
+	/* IP address */
+	if (ip_tag) {
+		if (!parse_ip6_address (ip_tag, &tmp, error))
+			goto error;
+	}
+
+	nm_ip6_address_set_address (addr, &tmp);
+
+	/* Prefix */
+	if (prefix_tag) {
+		long int prefix;
+
+		errno = 0;
+		prefix = strtol (prefix_tag, NULL, 10);
+		if (errno || prefix <= 0 || prefix > 128) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid IP6 prefix '%s'", prefix_tag);
+			goto error;
+		}
+		nm_ip6_address_set_prefix (addr, (guint32) prefix);
+	} else {
+		/* Missing prefix is treated as prefix of 64 */
+		nm_ip6_address_set_prefix (addr, 64);
+	}
+
+	success = TRUE;
+
+error:
+	if (!success) {
+		nm_ip6_address_unref (addr);
+		addr = NULL;
+	}
+
+	g_strfreev (list);
+	return addr;
+}
+
+/* IPv6 address is very complex to describe completely by a regular expression,
+ * so don't try to, rather use looser syntax to comprise all possibilities
+ * NOTE: The regexes below don't describe all variants allowed by 'ip route add',
+ * namely destination IP without 'to' keyword is recognized just at line start.
+ */
+#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
+
+static gboolean
+read_route6_file (const char *filename, NMSettingIP6Config *s_ip6, GError **error)
+{
+	char *contents = NULL;
+	gsize len = 0;
+	char **lines = NULL, **iter;
+	GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
+	GMatchInfo *match_info;
+	NMIP6Route *route;
+	struct in6_addr ip6_addr;
+	char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
+	long int prefix_int, metric_int;
+	gboolean success = FALSE;
+
+	const char *pattern_empty = "^\\s*(\\#.*)?$";
+	const char *pattern_to1 = "^\\s*(" IPV6_ADDR_REGEX "|default)"  /* IPv6 or 'default' keyword */
+	                          "(?:/(\\d{1,2}))?";                   /* optional prefix */
+	const char *pattern_to2 = "to\\s+(" IPV6_ADDR_REGEX "|default)" /* IPv6 or 'default' keyword */
+	                          "(?:/(\\d{1,2}))?";                   /* optional prefix */
+	const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")";       /* IPv6 of gateway */
+	const char *pattern_metric = "metric\\s+(\\d+)";                /* metric */
+
+	g_return_val_if_fail (filename != NULL, FALSE);
+	g_return_val_if_fail (s_ip6 != NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	/* Read the route file */
+	if (!g_file_get_contents (filename, &contents, &len, NULL))
+		return FALSE;
+
+	if (len == 0) {
+		g_free (contents);
+		return FALSE;
+	}
+
+	/* Create regexes for pieces to be matched */
+	regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
+	regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
+	regex_via = g_regex_new (pattern_via, 0, 0, NULL);
+	regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
+
+	/* New NMIP6Route structure */
+	route = nm_ip6_route_new ();
+
+	/* Iterate through file lines */
+	lines = g_strsplit_set (contents, "\n\r", -1);
+	for (iter = lines; iter && *iter; iter++) {
+
+		/* Skip empty lines */
+		if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
+			continue;
+
+		/* Destination */
+		g_regex_match (regex_to1, *iter, 0, &match_info);
+		if (!g_match_info_matches (match_info)) {
+			g_match_info_free (match_info);
+			g_regex_match (regex_to2, *iter, 0, &match_info);
+			if (!g_match_info_matches (match_info)) {
+				g_match_info_free (match_info);
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					     "Missing IP6 route destination address in record: '%s'", *iter);
+				goto error;
+			}
+		}
+		dest = g_match_info_fetch (match_info, 1);
+		g_match_info_free (match_info);
+		if (!strcmp (dest, "default"))
+			strcpy (dest, "::");
+		if (inet_pton (AF_INET6, dest, &ip6_addr) != 1) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Invalid IP6 route destination address '%s'", dest);
+			g_free (dest);
+			goto error;
+		}
+		nm_ip6_route_set_dest (route, &ip6_addr);
+		g_free (dest);
+
+		/* Prefix - is optional; 128 if missing */
+		prefix = g_match_info_fetch (match_info, 2);
+		prefix_int = 128;
+		if (prefix) {
+			errno = 0;
+			prefix_int = strtol (prefix, NULL, 10);
+			if (errno || prefix_int < 0 || prefix_int > 128) {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					     "Invalid IP6 route destination prefix '%s'", prefix);
+				g_free (prefix);
+				goto error;
+			}
+		}
+
+		nm_ip6_route_set_prefix (route, (guint32) prefix_int);
+		g_free (prefix);
+
+		/* Next hop */
+		g_regex_match (regex_via, *iter, 0, &match_info);
+		if (!g_match_info_matches (match_info)) {
+			g_match_info_free (match_info);
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Missing IP6 route gateway address in record: '%s'", *iter);
+			goto error;
+		}
+		next_hop = g_match_info_fetch (match_info, 1);
+		g_match_info_free (match_info);
+		if (inet_pton (AF_INET6, next_hop, &ip6_addr) != 1) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid IP6 route gateway address '%s'", next_hop);
+			g_free (next_hop);
+			goto error;
+		}
+		nm_ip6_route_set_next_hop (route, &ip6_addr);
+		g_free (next_hop);
+
+		/* Metric */
+		g_regex_match (regex_metric, *iter, 0, &match_info);
+		metric_int = 0;
+		if (g_match_info_matches (match_info)) {
+			metric = g_match_info_fetch (match_info, 1);
+			errno = 0;
+			metric_int = strtol (metric, NULL, 10);
+			if (errno || metric_int < 0 || metric_int > G_MAXUINT32) {
+				g_match_info_free (match_info);
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				             "Invalid IP6 route metric '%s'", metric);
+				g_free (metric);
+				goto error;
+			}
+			g_free (metric);
+		}
+
+		nm_ip6_route_set_metric (route, (guint32) metric_int);
+		g_match_info_free (match_info);
+
+		if (!nm_setting_ip6_config_add_route (s_ip6, route))
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP6 route");
+	}
+
+	success = TRUE;
+
+error:
+	g_free (contents);
+	g_strfreev (lines);
+	nm_ip6_route_unref (route);
+	g_regex_unref (regex_to1);
+	g_regex_unref (regex_to2);
+	g_regex_unref (regex_via);
+	g_regex_unref (regex_metric);
+
+	return success;
+}
+#endif
+
+
+static NMSetting *
+make_ip4_setting (shvarFile *ifcfg,
+                  const char *network_file,
+                  const char *iscsiadm_path,
+                  gboolean valid_ip6_config,
+                  GError **error)
+{
+	NMSettingIP4Config *s_ip4 = NULL;
+	char *value = NULL;
+	// char *route_path = NULL;
+	char *method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
+	guint32 i;
+	shvarFile *network_ifcfg;
+	// shvarFile *route_ifcfg;
+	gboolean never_default = FALSE, tmp_success;
+
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	if (!s_ip4) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not allocate IP4 setting");
+		return NULL;
+	}
+
+#if 0
+	/* Mandriva sets DEFROUTE for PPP only */
+	/* First check if DEFROUTE is set for this device; DEFROUTE has the
+	 * opposite meaning from never-default. The default if DEFROUTE is not
+	 * specified is DEFROUTE=yes which means that this connection can be used
+	 * as a default route
+	 */
+	never_default = !svTrueValue (ifcfg, "DEFROUTE", TRUE);
+#endif
+
+	/* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */
+	 network_ifcfg = svNewFile (network_file);
+	 if (network_ifcfg) {
+		char *gatewaydev;
+
+		/* Get the connection ifcfg device name and the global gateway device */
+		value = svGetValue (ifcfg, "DEVICE", FALSE);
+		gatewaydev = svGetValue (network_ifcfg, "GATEWAYDEV", FALSE);
+
+		/* If there was a global gateway device specified, then only connections
+		 * for that device can be the default connection.
+		 */
+		if (gatewaydev && value)
+			never_default = !!strcmp (value, gatewaydev);
+
+		g_free (gatewaydev);
+		g_free (value);
+		// svCloseFile (network_ifcfg);
+	}
+
+	value = svGetValue (ifcfg, "BOOTPROTO", FALSE);
+	if (value) {
+		if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) {
+			method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+#if 0
+		/* Is not used by Mandriva */
+		} else if (!g_ascii_strcasecmp (value, "ibft")) {
+			/* iSCSI Boot Firmware Table: need to read values from the iSCSI 
+			 * firmware for this device and create the IP4 setting using those.
+			 */
+			if (fill_ip4_setting_from_ibft (ifcfg, s_ip4, iscsiadm_path, error))
+				return NM_SETTING (s_ip4);
+			g_object_unref (s_ip4);
+			return NULL;
+		} else if (!g_ascii_strcasecmp (value, "autoip")) {
+			g_free (value);
+			g_object_set (s_ip4,
+			              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
+			              NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
+			              NULL);
+			return NM_SETTING (s_ip4);
+		} else if (!g_ascii_strcasecmp (value, "shared")) {
+			g_free (value);
+			g_object_set (s_ip4,
+			              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED,
+			              NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
+			              NULL);
+			return NM_SETTING (s_ip4);
+#endif
+		} else if (!g_ascii_strcasecmp (value, "none") || !g_ascii_strcasecmp (value, "static")) {
+			/* Static IP */
+		} else if (strlen (value)) {
+			/* FIXME actually it is static on Mandriva */
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Unknown BOOTPROTO '%s'", value);
+			g_free (value);
+			goto done;
+		}
+		g_free (value);
+	} else {
+		char *tmp_ip4, *tmp_prefix, *tmp_netmask;
+
+		/* If there is no BOOTPROTO, no IPADDR, no PREFIX, no NETMASK, but
+		 * valid IPv6 configuration, assume that IPv4 is disabled.  Otherwise,
+		 * if there is no IPv6 configuration, assume DHCP is to be used.
+		 * Happens with minimal ifcfg files like the following that anaconda
+		 * sometimes used to write out:
+		 *
+		 * DEVICE=eth0
+		 * HWADDR=11:22:33:44:55:66
+		 *
+		 */
+		/* FIXME
+		 * This is not strictly speaking true on Mandriva. Interface
+		 * will be up (ip link up) and zeroconf address will be set
+		 * but no DHCP started */
+		tmp_ip4 = svGetValue (ifcfg, "IPADDR", FALSE);
+		tmp_prefix = svGetValue (ifcfg, "PREFIX", FALSE);
+		tmp_netmask = svGetValue (ifcfg, "NETMASK", FALSE);
+		if (!tmp_ip4 && !tmp_prefix && !tmp_netmask) {
+			if (valid_ip6_config) {
+				/* Nope, no IPv4 */
+				g_object_set (s_ip4,
+				              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+				              NULL);
+				return NM_SETTING (s_ip4);
+			}
+
+			method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+		}
+		g_free (tmp_ip4);
+		g_free (tmp_prefix);
+		g_free (tmp_netmask);
+	}
+
+	g_object_set (s_ip4,
+	              NM_SETTING_IP4_CONFIG_METHOD, method,
+	              NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "PEERDNS", TRUE),
+		      // Not exists on Mandriva
+	              // NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "PEERROUTES", TRUE),
+	              NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
+	              NM_SETTING_IP4_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", TRUE),
+	              NULL);
+
+	/* Handle manual settings */
+	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
+		NMIP4Address *addr;
+
+		for (i = 1; i < 256; i++) {
+			addr = read_full_ip4_address (ifcfg, network_file, i, error);
+			if (error && *error)
+				goto done;
+			if (!addr)
+				break;
+
+			if (!nm_setting_ip4_config_add_address (s_ip4, addr))
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP4 address");
+			nm_ip4_address_unref (addr);
+		}
+	} else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
+		value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
+		if (value && strlen (value))
+			g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, value, NULL);
+		g_free (value);
+
+#if 0
+		/* Does not seem to be used on Mandriva */
+		value = svGetValue (ifcfg, "DHCP_CLIENT_ID", FALSE);
+		if (value && strlen (value))
+			g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, value, NULL);
+		g_free (value);
+#endif
+	}
+
+	/* DNS servers
+	 * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
+	 */
+	for (i = 1, tmp_success = TRUE; i <= 10 && tmp_success; i++) {
+		char *tag;
+		guint32 dns;
+		// struct in6_addr ip6_dns;
+		// GError *tmp_err = NULL;
+
+		tag = g_strdup_printf ("DNS%u", i);
+		tmp_success = read_ip4_address (ifcfg, tag, &dns, error);
+#if 0
+		/* No IPv6 on Mandriva */
+		if (!tmp_success) {
+			/* if it's IPv6, don't exit */
+			dns = 0;
+			value = svGetValue (ifcfg, tag, FALSE);
+			if (value) {
+				tmp_success = parse_ip6_address (value, &ip6_dns, &tmp_err);
+				g_clear_error (&tmp_err);
+				g_free (value);
+			}
+			if (!tmp_success) {
+				g_free (tag);
+				goto done;
+			}
+			g_clear_error (error);
+		}
+#endif
+
+		if (dns && !nm_setting_ip4_config_add_dns (s_ip4, dns))
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS server %s", tag);
+		g_free (tag);
+	}
+
+	/* DNS searches */
+	value = svGetValue (ifcfg, "DOMAIN", FALSE);
+	if (value) {
+		char **searches = NULL;
+
+		searches = g_strsplit (value, " ", 0);
+		if (searches) {
+			char **item;
+			for (item = searches; *item; item++) {
+				if (strlen (*item)) {
+					if (!nm_setting_ip4_config_add_dns_search (s_ip4, *item))
+						PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS domain '%s'", *item);
+				}
+			}
+			g_strfreev (searches);
+		}
+		g_free (value);
+	}
+
+#if 0
+	/* Some support is present on Mandriva but no GUI to configure */
+	/* Static routes  - route-<name> file */
+	route_path = utils_get_route_path (ifcfg->fileName);
+	if (!route_path) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not get route file path for '%s'", ifcfg->fileName);
+		goto done;
+	}
+
+	/* First test new/legacy syntax */
+	if (utils_has_route_file_new_syntax (route_path)) {
+		/* Parse route file in new syntax */
+		g_free (route_path);
+		route_ifcfg = utils_get_route_ifcfg (ifcfg->fileName, FALSE);
+		if (route_ifcfg) {
+			NMIP4Route *route;
+			for (i = 0; i < 256; i++) {
+				route = read_one_ip4_route (route_ifcfg, network_file, i, error);
+				if (error && *error) {
+					svCloseFile (route_ifcfg);
+					goto done;
+				}
+				if (!route)
+					break;
+
+				if (!nm_setting_ip4_config_add_route (s_ip4, route))
+					PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP4 route");
+				nm_ip4_route_unref (route);
+			}
+			svCloseFile (route_ifcfg);
+		}
+	} else {
+		read_route_file_legacy (route_path, s_ip4, error);
+		g_free (route_path);
+		if (error && *error)
+			goto done;
+	}
+#endif
+
+#if 0
+	/* Does not seem to be used anyhwere on Mandriva */
+	/* Legacy value NM used for a while but is incorrect (rh #459370) */
+	if (!nm_setting_ip4_config_get_num_dns_searches (s_ip4)) {
+		value = svGetValue (ifcfg, "SEARCH", FALSE);
+		if (value) {
+			char **searches = NULL;
+
+			searches = g_strsplit (value, " ", 0);
+			if (searches) {
+				char **item;
+				for (item = searches; *item; item++) {
+					if (strlen (*item)) {
+						if (!nm_setting_ip4_config_add_dns_search (s_ip4, *item))
+							PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS search '%s'", *item);
+					}
+				}
+				g_strfreev (searches);
+			}
+			g_free (value);
+		}
+	}
+#endif
+
+	return NM_SETTING (s_ip4);
+
+done:
+	g_object_unref (s_ip4);
+	return NULL;
+}
+
+#if 0
+No IPv6 on Mandriva
+static NMSetting *
+make_ip6_setting (shvarFile *ifcfg,
+                  const char *network_file,
+                  const char *iscsiadm_path,
+                  GError **error)
+{
+	NMSettingIP6Config *s_ip6 = NULL;
+	char *value = NULL;
+	char *str_value;
+	char *route6_path = NULL;
+	gboolean bool_value, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE;
+	char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
+	guint32 i;
+	shvarFile *network_ifcfg;
+	gboolean never_default = FALSE, tmp_success;
+
+	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
+	if (!s_ip6) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not allocate IP6 setting");
+		return NULL;
+	}
+
+	/* Is IPV6 enabled? Set method to "ignored", when not enabled */
+	str_value = svGetValue (ifcfg, "IPV6INIT", FALSE);
+	bool_value = svTrueValue (ifcfg, "IPV6INIT", FALSE);
+	if (!str_value) {
+		network_ifcfg = svNewFile (network_file);
+		if (network_ifcfg) {
+			bool_value = svTrueValue (network_ifcfg, "IPV6INIT", FALSE);
+			svCloseFile (network_ifcfg);
+		}
+	}
+	g_free (str_value);
+
+	if (!bool_value) {
+		/* IPv6 is disabled */
+		g_object_set (s_ip6,
+		              NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+		              NULL);
+		return NM_SETTING (s_ip6);
+	}
+
+	/* First check if IPV6_DEFROUTE is set for this device; IPV6_DEFROUTE has the
+	 * opposite meaning from never-default. The default if IPV6_DEFROUTE is not
+	 * specified is IPV6_DEFROUTE=yes which means that this connection can be used
+	 * as a default route
+	 */
+	never_default = !svTrueValue (ifcfg, "IPV6_DEFROUTE", TRUE);
+
+	/* Then check if IPV6_DEFAULTGW or IPV6_DEFAULTDEV is specified;
+	 * they are global and override IPV6_DEFROUTE
+	 * When both are set, the device specified in IPV6_DEFAULTGW takes preference.
+	 */
+	network_ifcfg = svNewFile (network_file);
+	if (network_ifcfg) {
+		char *ipv6_defaultgw, *ipv6_defaultdev;
+		char *default_dev = NULL;
+
+		/* Get the connection ifcfg device name and the global default route device */
+		value = svGetValue (ifcfg, "DEVICE", FALSE);
+		ipv6_defaultgw = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
+		ipv6_defaultdev = svGetValue (network_ifcfg, "IPV6_DEFAULTDEV", FALSE);
+
+		if (ipv6_defaultgw) {
+			default_dev = strchr (ipv6_defaultgw, '%');
+			if (default_dev)
+				default_dev++;
+		}
+		if (!default_dev)
+			default_dev = ipv6_defaultdev;
+
+		/* If there was a global default route device specified, then only connections
+		 * for that device can be the default connection.
+		 */
+		if (default_dev && value)
+			never_default = !!strcmp (value, default_dev);
+
+		g_free (ipv6_defaultgw);
+		g_free (ipv6_defaultdev);
+		g_free (value);
+		svCloseFile (network_ifcfg);
+	}
+
+	/* Find out method property */
+	ipv6forwarding = svTrueValue (ifcfg, "IPV6FORWARDING", FALSE);
+	ipv6_autoconf = svTrueValue (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding);
+	dhcp6 = svTrueValue (ifcfg, "DHCPV6C", FALSE);
+
+	if (ipv6_autoconf)
+		method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
+	else if (dhcp6)
+		method = NM_SETTING_IP6_CONFIG_METHOD_DHCP;
+	else {
+		/* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */
+		str_value = svGetValue (ifcfg, "IPV6ADDR", FALSE);
+		if (!str_value)
+			str_value = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
+
+		if (!str_value)
+			method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
+		g_free (str_value);
+	}
+	/* TODO - handle other methods */
+
+	g_object_set (s_ip6,
+	              NM_SETTING_IP6_CONFIG_METHOD, method,
+	              NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "IPV6_PEERDNS", TRUE),
+	              NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "IPV6_PEERROUTES", TRUE),
+	              NM_SETTING_IP6_CONFIG_NEVER_DEFAULT, never_default,
+	              NM_SETTING_IP6_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE),
+	              NULL);
+
+	if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+		NMIP6Address *addr;
+		char *val;
+		char *ipv6addr, *ipv6addr_secondaries;
+		char **list = NULL, **iter;
+
+		ipv6addr = svGetValue (ifcfg, "IPV6ADDR", FALSE);
+		ipv6addr_secondaries = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
+
+		val = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL,
+		                 ipv6addr ? ipv6addr : "",
+		                 ipv6addr_secondaries ? ipv6addr_secondaries : "",
+		                 NULL);
+		g_free (ipv6addr);
+		g_free (ipv6addr_secondaries);
+
+		list = g_strsplit_set (val, " ", 0);
+		g_free (val);
+		for (iter = list; iter && *iter; iter++, i++) {
+			addr = parse_full_ip6_address (*iter, error);
+			if (!addr) {
+				g_strfreev (list);
+				goto error;
+			}
+
+			if (!nm_setting_ip6_config_add_address (s_ip6, addr))
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate IP6 address");
+			nm_ip6_address_unref (addr);
+		}
+		g_strfreev (list);
+	} else if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
+		/* TODO - autoconf or DHCPv6 stuff goes here */
+	}
+
+	/* DNS servers
+	 * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting())
+	 */
+	for (i = 1, tmp_success = TRUE; i <= 10 && tmp_success; i++) {
+		char *tag;
+		struct in6_addr ip6_dns;
+
+		ip6_dns = in6addr_any;
+		tag = g_strdup_printf ("DNS%u", i);
+		value = svGetValue (ifcfg, tag, FALSE);
+		if (value)
+			tmp_success = parse_ip6_address (value, &ip6_dns, error);
+
+		if (!tmp_success) {
+			struct in_addr ip4_addr;
+			if (inet_pton (AF_INET, value, &ip4_addr) != 1) {
+				g_free (tag);
+				g_free (value);
+				goto error;
+			}
+			/* ignore error - it is IPv4 address */
+			tmp_success = TRUE;
+			g_clear_error (error);
+		}
+
+		if (!IN6_IS_ADDR_UNSPECIFIED (&ip6_dns) && !nm_setting_ip6_config_add_dns (s_ip6, &ip6_dns))
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: duplicate DNS server %s", tag);
+		g_free (tag);
+		g_free (value);
+	}
+
+	/* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIP4Config */
+
+	/* Read static routes from route6-<interface> file */
+	route6_path = utils_get_route6_path (ifcfg->fileName);
+	if (!route6_path) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not get route6 file path for '%s'", ifcfg->fileName);
+		goto error;
+	}
+
+	read_route6_file (route6_path, s_ip6, error);
+	g_free (route6_path);
+	if (error && *error)
+		goto error;
+
+	return NM_SETTING (s_ip6);
+
+error:
+	g_object_unref (s_ip6);
+	return NULL;
+}
+#endif
+
+static gboolean
+add_one_wep_key (shvarFile *ifcfg,
+                 const char *shvar_key,
+                 guint8 key_idx,
+                 gboolean passphrase,
+                 NMSettingWirelessSecurity *s_wsec,
+                 GError **error)
+{
+	char *key = NULL;
+	char *value = NULL;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (ifcfg != NULL, FALSE);
+	g_return_val_if_fail (shvar_key != NULL, FALSE);
+	g_return_val_if_fail (key_idx <= 3, FALSE);
+	g_return_val_if_fail (s_wsec != NULL, FALSE);
+
+	value = svGetValue (ifcfg, shvar_key, FALSE);
+	if (!value || !strlen (value)) {
+		g_free (value);
+		return TRUE;
+	}
+
+	/* Validate keys */
+	if (passphrase) {
+		if (strlen (value) && strlen (value) < 64) {
+			key = g_strdup (value);
+			g_object_set (G_OBJECT (s_wsec),
+			              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
+			              NM_WEP_KEY_TYPE_PASSPHRASE,
+			              NULL);
+		}
+	} else {
+		if (strlen (value) == 10 || strlen (value) == 26) {
+			/* Hexadecimal WEP key */
+			char *p = value;
+
+			while (*p) {
+				if (!g_ascii_isxdigit (*p)) {
+					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					             "Invalid hexadecimal WEP key.");
+					goto out;
+				}
+				p++;
+			}
+			key = g_strdup (value);
+		} else if (   !strncmp (value, "s:", 2)
+		           && (strlen (value) == 7 || strlen (value) == 15)) {
+			/* ASCII key */
+			char *p = value + 2;
+
+			while (*p) {
+				if (!isascii ((int) (*p))) {
+					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					             "Invalid ASCII WEP key.");
+					goto out;
+				}
+				p++;
+			}
+
+			/* Remove 's:' prefix.
+			 * Don't convert to hex string. wpa_supplicant takes 'wep_key0' option over D-Bus as byte array
+			 * and converts it to hex string itself. Even though we convert hex string keys into a bin string
+			 * before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly,
+			 * ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users.
+			 */
+			key = g_strdup (value + 2);
+		}
+	}
+
+	if (key) {
+		nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key);
+		success = TRUE;
+	} else
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid WEP key length.");
+
+out:
+	g_free (value);
+	return success;
+}
+
+static gboolean
+read_wep_keys (shvarFile *ifcfg,
+               guint8 def_idx,
+               NMSettingWirelessSecurity *s_wsec,
+               GError **error)
+{
+	if (!add_one_wep_key (ifcfg, "WIRELESS_ENC_KEY", FALSE, 0, s_wsec, error))
+		return FALSE;
+#if 0
+	/* Mandriva is using only one key */
+	/* Try hex/ascii keys first */
+	if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error))
+		return FALSE;
+
+	/* And then passphrases */
+	if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error))
+		return FALSE;
+#endif
+
+	return TRUE;
+}
+
+static NMSetting *
+make_wep_setting (shvarFile *ifcfg,
+                  const char *file,
+                  GError **error)
+{
+	NMSettingWirelessSecurity *s_wireless_sec;
+	char *value;
+	// shvarFile *keys_ifcfg = NULL;
+	int default_key_idx = 0;
+
+	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);
+
+#if 0
+	/* Mandriva always assumes defalt key #0 */
+	value = svGetValue (ifcfg, "DEFAULTKEY", FALSE);
+	if (value) {
+		gboolean success;
+
+		success = get_int (value, &default_key_idx);
+		if (success && (default_key_idx >= 1) && (default_key_idx <= 4)) {
+			default_key_idx--;  /* convert to [0...3] */
+			g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, default_key_idx, NULL);
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid default WEP key '%s'", value);
+	 		g_free (value);
+			goto error;
+		}
+ 		g_free (value);
+	}
+#endif
+
+	/* Read keys in the ifcfg file */
+	if (!read_wep_keys (ifcfg, default_key_idx, s_wireless_sec, error))
+		goto error;
+
+#if 0
+	/* No shadow on Mandriva */
+	/* Try to get keys from the "shadow" key file */
+	keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
+	if (keys_ifcfg) {
+		if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wireless_sec, error)) {
+			svCloseFile (keys_ifcfg);
+			goto error;
+		}
+		svCloseFile (keys_ifcfg);
+		g_assert (error == NULL || *error == NULL);
+	}
+#endif
+
+#if 0
+	/* Only one key on Mandriva */
+	/* 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, IFCFG_PLUGIN_ERROR, 0,
+		             "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, IFCFG_PLUGIN_ERROR, 0,
+		             "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, IFCFG_PLUGIN_ERROR, 0,
+		             "Default WEP key index was 4, but no valid KEY4 exists.");
+		goto error;
+	}
+#endif
+
+	value = svGetValue (ifcfg, "WIRELESS_ENC_MODE", FALSE);
+	if (value) {
+		char *lcase;
+
+		lcase = g_ascii_strdown (value, -1);
+		g_free (value);
+
+		if (!strcmp (lcase, "open")) {
+			g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL);
+		} else if (!strcmp (lcase, "restricted")) {
+			g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL);
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid WEP authentication algorithm '%s'",
+			             lcase);
+			g_free (lcase);
+			goto error;
+		}
+		g_free (lcase);
+	}
+
+	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)) {
+		const char *auth_alg;
+
+		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wireless_sec);
+		if (auth_alg && !strcmp (auth_alg, "shared")) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "WEP Shared Key authentication is invalid for "
+			             "unencrypted connections.");
+			goto error;
+		}
+
+		/* Unencrypted */
+		g_object_unref (s_wireless_sec);
+		s_wireless_sec = NULL;
+	}
+
+	return (NMSetting *) s_wireless_sec;
+
+error:
+	if (s_wireless_sec)
+		g_object_unref (s_wireless_sec);
+	return NULL;
+}
+
+static gboolean
+fill_wpa_ciphers (WPANetwork *wpan,
+                  NMSettingWirelessSecurity *wsec,
+                  gboolean group,
+                  gboolean adhoc)
+{
+	char *value;
+	char **list = NULL, **iter;
+	int i = 0;
+
+	value = ifcfg_mdv_wpa_network_get_val (wpan, group ? "group" : "pairwise");
+	if (!value)
+		return TRUE;
+
+	list = g_strsplit_set (value, " ", 0);
+	for (iter = list; iter && *iter; iter++, i++) {
+		if (!*iter)
+			continue;
+
+		/* 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)) {
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignoring group cipher '%s' (only one group cipher allowed in Ad-Hoc mode)",
+				             *iter);
+				continue;
+			} else if (!group) {
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: 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 {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignoring invalid %s cipher '%s'",
+			             group ? "group" : "pairwise",
+			             *iter);
+		}
+	}
+
+	if (list)
+		g_strfreev (list);
+	return TRUE;
+}
+
+static char *
+parse_wpa_psk (WPANetwork *wpan,
+               const char *file,
+               const GByteArray *ssid,
+               GError **error)
+{
+	char *psk = NULL, *p, *hashed = NULL;
+	gboolean quoted = FALSE;
+
+	/* 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.
+	 */
+
+	psk = ifcfg_mdv_wpa_network_get_val (wpan, "psk");
+
+	if (!psk) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing WPA psk for WPA-PSK key management");
+		return NULL;
+	}
+
+	psk = p = g_strdup (psk);
+
+	if (p[0] == '"') {
+		if (psk[strlen (psk) - 1] != '"') {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Invalid WPA psk (unterminated quote)");
+			goto out;
+		}
+		quoted = TRUE;
+	}
+
+	if (!quoted) {
+		/* Verify the hex PSK; 64 digits */
+	       	if (strlen (psk) == 64) {
+			while (*p) {
+				if (!isxdigit (*p++)) {
+					g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+						     "Invalid WPA psk (contains non-hexadecimal characters)");
+					goto out;
+				}
+			}
+		} else {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					     "Invalid WPA psk (hex key not equal 64 characters)");
+				goto out;
+		}
+		hashed = g_strdup (psk);
+	} else {
+		/* Prior to 4f6eef9e77265484555663cf666cde4fa8323469 and
+		 * 28e2e446868b94b92edc4a82aa0bf1e3eda8ec54 the writer may not have
+		 * properly quoted passphrases, so just handle anything that's unquoted
+		 * and between 8 and 63 characters as a passphrase.
+		 */
+
+		/* Get rid of the quotes */
+		p++;
+		p[strlen (p) - 1] = '\0';
+
+		/* Length check */
+		if (strlen (p) < 8 || strlen (p) > 63) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid WPA psk (passphrases must be between "
+			             "8 and 63 characters long (inclusive))");
+			goto out;
+		}
+
+		hashed = g_strdup (p);
+	}
+
+	if (!hashed) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Invalid WPA psk (doesn't look like a passphrase or hex key)");
+	}
+
+out:
+	g_free (psk);
+	return hashed;
+}
+
+typedef struct {
+	const char *method;
+	gboolean (*reader)(const char *eap_method,
+			   WPANetwork *wpan,
+	                   shvarFile *ifcfg,
+	                   shvarFile *keys,
+	                   NMSetting8021x *s_8021x,
+	                   gboolean phase2,
+	                   GError **error);
+	gboolean wifi_phase2_only;
+} EAPReader;
+
+static EAPReader eap_readers[] = {
+	{ "md5", 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 }
+};
+
+static gboolean
+eap_simple_reader (const char *eap_method,
+		   WPANetwork *wpan,
+                   shvarFile *ifcfg,
+                   shvarFile *keys,
+                   NMSetting8021x *s_8021x,
+                   gboolean phase2,
+                   GError **error)
+{
+	char *value = NULL;
+
+	/* FIXME wpa identity can contain '\0' */
+	value = ifcfg_mdv_wpa_network_get_str(wpan, "identity");
+	if (!value) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing identity for EAP method '%s'.",
+		             eap_method);
+		return FALSE;
+	}
+	g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
+	g_free(value);
+
+	/* FIXME can we expect hash:XXX password? */
+	value = ifcfg_mdv_wpa_network_get_str (wpan, "password");
+	if (!value) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing password for EAP method '%s'.",
+		             eap_method);
+		return FALSE;
+	}
+	g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL);
+	g_free(value);
+
+	return TRUE;
+}
+
+static gboolean
+eap_tls_reader (const char *eap_method,
+		WPANetwork *wpan,
+                shvarFile *ifcfg,
+                shvarFile *keys,
+                NMSetting8021x *s_8021x,
+                gboolean phase2,
+                GError **error)
+{
+	char *value = NULL;
+	char *ca_cert = NULL;
+	char *client_cert = NULL;
+	char *privkey = NULL;
+	char *privkey_password = NULL;
+	gboolean success = FALSE;
+	NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+
+	/* FIXME wpa identity can contain '\0' */
+	value = ifcfg_mdv_wpa_network_get_str(wpan, "identity");
+	if (!value) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing identity for EAP method '%s'.",
+		             eap_method);
+		return FALSE;
+	}
+	g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
+
+	ca_cert = ifcfg_mdv_wpa_network_get_str(wpan,
+	                      phase2 ? "ca_cert2" : "ca_cert");
+	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 {
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: missing %s for EAP"
+		             " method '%s'; this is insecure!",
+	                     phase2 ? "ca_cert2" : "ca_cert",
+		             eap_method);
+	}
+
+	/* Private key password */
+	privkey_password = ifcfg_mdv_wpa_network_get_str(wpan,
+	                               phase2 ? "private_key2_passwd": "private_key_passwd");
+	if (!privkey_password) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing %s for EAP method '%s'.",
+		             phase2 ? "private_key2_passwd" : "private_key_passwd",
+		             eap_method);
+		goto done;
+	}
+
+	/* The private key itself */
+	privkey = ifcfg_mdv_wpa_network_get_str(wpan,
+	                      phase2 ? "private_key2" : "private_key");
+	if (!privkey) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing %s for EAP method '%s'.",
+	                      phase2 ? "private_key2" : "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 = ifcfg_mdv_wpa_network_get_str(wpan,
+		                          phase2 ? "client_cert2" : "client_cert");
+		if (!client_cert) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Missing %s for EAP method '%s'.",
+			             phase2 ? "client_cert2" : "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(value);
+	g_free(ca_cert);
+	g_free(privkey_password);
+	g_free(privkey);
+	g_free(client_cert);
+	return success;
+}
+
+static gboolean
+eap_peap_reader (const char *eap_method,
+		 WPANetwork *wpan,
+                 shvarFile *ifcfg,
+                 shvarFile *keys,
+                 NMSetting8021x *s_8021x,
+                 gboolean dummy,
+                 GError **error)
+{
+	char *ca_cert = NULL;
+	char *phase1 = NULL;
+	char *phase2 = NULL;
+	char *lower;
+	char **list = NULL, **iter;
+	gboolean success = FALSE;
+
+	ca_cert = ifcfg_mdv_wpa_network_get_str(wpan, "ca_cert");
+	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 {
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: missing "
+		             "ca_cert for EAP method '%s'; this is"
+		             " insecure!",
+		             eap_method);
+	}
+
+	phase1 = ifcfg_mdv_wpa_network_get_str(wpan, "phase1");
+	if (phase1) {
+		list = g_strsplit_set(phase1, " ", 0);
+		for (iter = list; iter && *iter; iter++) {
+			char *p;
+
+		       if (!**iter)
+		       		continue;
+
+			p = strchr(*iter, '=');
+			if (p) {
+				*p++ = '\0';
+				if (!strcmp(*iter, "peapver")) {
+					if (!strcmp (p, "0"))
+						g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
+					else if (!strcmp (p, "1"))
+						g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL);
+					else {
+						g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+						     "Unknown peapver value '%s'",
+			             p);
+						goto done;
+					}
+				} else if (!strcmp(*iter, "peaplabel")) {
+					if (!strcmp(p, "1")) {
+						g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL);
+					}
+				}
+			} else
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: incorrect "
+		             "phase1 parameter '%s' EAP method '%s';"
+			     " key=value expected!",
+		             *iter, eap_method);
+		}
+		if (list)
+			g_strfreev(list);
+	}
+
+	phase2 = ifcfg_mdv_wpa_network_get_str(wpan, "phase2");
+	if (!phase2) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing phase2 (PEAP inner authentication parameters).");
+		goto done;
+	}
+
+	/* Handle options for the inner auth method */
+	list = g_strsplit (phase2, " ", 0);
+	for (iter = list; iter && *iter; iter++) {
+		char *p;
+
+		if (!**iter)
+			continue;
+
+		p = strchr(*iter, '=');
+		if (!p) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Incorrect phase2 parameter '%s'; key=value expected.", *iter);
+			goto done;
+		}
+		*p++ = '\0';
+		if (!strcmp(*iter, "auth")) {
+			if (   !strcmp (p, "MSCHAPV2")
+			    || !strcmp (p, "MD5")
+			    || !strcmp (p, "GTC")) {
+				if (!eap_simple_reader (p, wpan, ifcfg, keys, s_8021x, TRUE, error))
+					goto done;
+			} else if (!strcmp (p, "TLS")) {
+				if (!eap_tls_reader (p, wpan, ifcfg, keys, s_8021x, TRUE, error))
+					goto done;
+			} else {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Unknown PEAP inner authentication method 'auth=%s'.",
+				  p);
+				goto done;
+			}
+		} else if (!strcmp (*iter, "autheap")) {
+			/* These parameters are for EAP-TTLS */
+			continue;
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Unknown phase2 inner authentication method '%s=%s'.",
+			             *iter, p);
+			goto done;
+		}
+
+		lower = g_ascii_strdown (p, -1);
+		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
+		g_free (lower);
+		break;
+	}
+
+	if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "No valid inner authentication methods found.");
+		goto done;
+	}
+
+	success = TRUE;
+
+done:
+	g_free(ca_cert);
+	g_free(phase1);
+	g_free(phase2);
+	if (list)
+		g_strfreev (list);
+	return success;
+}
+
+static gboolean
+eap_ttls_reader (const char *eap_method,
+		 WPANetwork *wpan,
+                 shvarFile *ifcfg,
+                 shvarFile *keys,
+                 NMSetting8021x *s_8021x,
+                 gboolean dummy,
+                 GError **error)
+{
+	gboolean success = FALSE;
+	char *anon_ident = NULL;
+	char *ca_cert = NULL;
+	char *phase2 = NULL;
+	char **list = NULL, **iter;
+
+	ca_cert = ifcfg_mdv_wpa_network_get_str(wpan, "ca_cert");
+	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 {
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: missing "
+		             "ca_cert for EAP method '%s'; this is"
+		             " insecure!",
+		             eap_method);
+	}
+
+	anon_ident = ifcfg_mdv_wpa_network_get_str(wpan, "anonymous_identity");
+	if (anon_ident && strlen (anon_ident))
+		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
+
+	phase2 = ifcfg_mdv_wpa_network_get_str(wpan, "phase2");
+	if (!phase2) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing phase2 (TTLS inner authentication parameters).");
+		goto done;
+	}
+
+	/* Handle options for the inner auth method */
+	list = g_strsplit (phase2, " ", 0);
+	for (iter = list; iter && *iter; iter++) {
+		gboolean  auth = FALSE, autheap = FALSE;
+		char *p, *lower = NULL;
+
+		if (!**iter)
+			continue;
+
+		p = strchr(*iter, '=');
+		if (!p) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Incorrect phase2 parameter '%s'; key=value expected.", *iter);
+			goto done;
+		}
+		*p++ = '\0';
+
+		if (!strcmp(*iter, "auth")) {
+			auth = TRUE;
+			if (   !strcmp (p, "MSCHAPV2")
+			    || !strcmp (p, "MSCHAP")
+			    || !strcmp (p, "PAP")
+			    || !strcmp (p, "CHAP")) {
+				if (!eap_simple_reader (p, wpan, ifcfg, keys, s_8021x, TRUE, error))
+					goto done;
+			} else {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					     "Unknown TTLS inner authentication method 'auth=%s'.",
+					     p);
+				goto done;
+			}
+		} else if (!strcmp(*iter, "autheap")) {
+			autheap = TRUE;
+			if (!strcmp (p, "TLS")) {
+				if (!eap_tls_reader (p, wpan, ifcfg, keys, s_8021x, TRUE, error))
+					goto done;
+			} else if (!strcmp (p, "MSCHAPV2")
+				|| !strcmp (p, "MD5")) {
+				if (!eap_simple_reader (p, wpan, ifcfg, keys, s_8021x, TRUE, error))
+					goto done;
+			} else {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+					     "Unknown TTLS inner authentication method 'autheap=%s'.",
+					     p);
+				goto done;
+			}
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Unknown phase2 inner authentication method '%s=%s'.",
+			             *iter, p);
+			goto done;
+		}
+		lower = g_ascii_strdown (p, -1);
+		if (auth)
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
+		if (autheap)
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, p, NULL);
+		g_free (lower);
+		break;
+	}
+
+	success = TRUE;
+
+done:
+	g_free(ca_cert);
+	g_free(anon_ident);
+	g_free(phase2);
+	if (list)
+		g_strfreev (list);
+	return success;
+}
+
+static NMSetting8021x *
+fill_8021x (shvarFile *ifcfg,
+	    WPANetwork *wpan,
+            const char *file,
+            const char *key_mgmt,
+            gboolean wifi,
+            GError **error)
+{
+	NMSetting8021x *s_8021x;
+	shvarFile *keys = NULL;
+	char *value;
+	char **list, **iter;
+
+	value = ifcfg_mdv_wpa_network_get_val(wpan, "eap");
+	if (!value) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing eap methods for key management '%s'",
+		             key_mgmt);
+		return NULL;
+	}
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+
+	/* Validate and handle each EAP method */
+	list = g_strsplit (value, " ", 0);
+	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 && !found) {
+			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) {
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignored invalid "
+				             "IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
+				             lower);
+				goto next;
+			}
+
+			/* Parse EAP method specific options */
+			if (!(*eap->reader)(lower, wpan, ifcfg, keys, s_8021x, FALSE, error)) {
+				g_free (lower);
+				g_strfreev(list);
+				goto error;
+			}
+			nm_setting_802_1x_add_eap_method (s_8021x, lower);
+			found = TRUE;
+
+		next:
+			eap++;
+		}
+
+		if (!found) {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: 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, IFCFG_PLUGIN_ERROR, 0,
+		             "No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
+		goto error;
+	}
+
+	return s_8021x;
+
+error:
+	g_object_unref (s_8021x);
+	return NULL;
+}
+
+static gboolean
+read_wep_key_from_wpa (WPANetwork *wpan,
+               guint8 idx,
+               NMSettingWirelessSecurity *s_wsec,
+               GError **error)
+{
+	gchar *key_name, *key_val;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail(wpan != NULL, FALSE);
+	g_return_val_if_fail(s_wsec != NULL, FALSE);
+
+	key_name = g_strdup_printf("wep_key%d", idx);
+	key_val = ifcfg_mdv_wpa_network_get_str(wpan, key_name);
+
+	if (key_val) {
+		nm_setting_wireless_security_set_wep_key(s_wsec, idx, key_val);
+		success = TRUE;
+	} else
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			"Missing wep_key%d", idx);
+
+	g_free(key_name);
+	g_free(key_val);
+
+	return success;
+}
+
+static gboolean
+make_wep_from_wpa_supplicant (WPANetwork *wpan,
+                  NMSettingWirelessSecurity *wsec,
+                  GError **error)
+{
+	char *value;
+	int default_key_idx = 0;
+
+	value = ifcfg_mdv_wpa_network_get_val(wpan, "wep_tx_keyidx");
+	if (value) {
+		gboolean success;
+
+		success = get_int (value, &default_key_idx);
+		if (success && (default_key_idx >= 0) && (default_key_idx <= 3)) {
+			/* Mandriva always assumes defalt key #0 */
+			if (default_key_idx != 0)
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: wep_tx_keyidx != 0");
+			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, default_key_idx, NULL);
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid wep_tx_keyidx '%s'", value);
+			goto error;
+		}
+	}
+
+	/* Read default key */
+	if (!read_wep_key_from_wpa(wpan, default_key_idx, wsec, error))
+		goto error;
+
+	value = ifcfg_mdv_wpa_network_get_val(wpan, "auth_alg");
+	if (value) {
+		char *lcase;
+
+		lcase = g_ascii_strdown (value, -1);
+
+		if (!strcmp (lcase, "open")) {
+			g_object_set(wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL);
+		} else if (!strcmp (lcase, "shared")) {
+			g_object_set(wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL);
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid auth_alg '%s'",
+			             lcase);
+			g_free (lcase);
+			goto error;
+		}
+		g_free (lcase);
+	}
+
+	if (   !nm_setting_wireless_security_get_wep_key (wsec, 0)
+	    && !nm_setting_wireless_security_get_wep_key (wsec, 1)
+	    && !nm_setting_wireless_security_get_wep_key (wsec, 2)
+	    && !nm_setting_wireless_security_get_wep_key (wsec, 3)
+	    && !nm_setting_wireless_security_get_wep_tx_keyidx (wsec)) {
+		const char *auth_alg;
+
+		auth_alg = nm_setting_wireless_security_get_auth_alg (wsec);
+		if (auth_alg && !strcmp (auth_alg, "shared")) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "WEP Shared Key authentication is invalid for "
+			             "unencrypted connections.");
+			goto error;
+		}
+
+		return FALSE;
+	}
+
+	return TRUE;
+
+error:
+	return FALSE;
+}
+
+static NMSetting *
+make_wpa_setting (shvarFile *ifcfg,
+		  WPANetwork *wpan,
+                  const char *file,
+                  const GByteArray *ssid,
+                  gboolean adhoc,
+                  NMSetting8021x **s_8021x,
+                  GError **error)
+{
+	NMSettingWirelessSecurity *wsec;
+	char *key_mgmt, *psk, *lower, *proto;
+	char **list = NULL, **iter;
+	int np;
+
+	key_mgmt = ifcfg_mdv_wpa_network_get_val (wpan, "key_mgmt");
+	/*
+	 * Can NM support two alternative methods?
+	 */
+	if (!key_mgmt)
+		key_mgmt = "WPA-PSK";
+
+	wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
+
+	/* Pairwise and Group ciphers */
+	fill_wpa_ciphers (wpan, wsec, FALSE, adhoc);
+	fill_wpa_ciphers (wpan, wsec, TRUE, adhoc);
+
+	/*
+	 * WPA and/or RSN
+	 * Default to both WPA and RSN allowed.
+	 */
+	proto = ifcfg_mdv_wpa_network_get_val(wpan, "proto");
+	if (!proto)
+		proto="WPA RSN";
+
+	list = g_strsplit_set (proto, " ", 0);
+	for (np = 0, iter = list; iter && *iter; iter++) {
+		if (!*iter)
+			continue;
+
+		if (!strcmp (*iter, "WPA")) {
+			np++;
+			nm_setting_wireless_security_add_proto (wsec, "wpa");
+		} else if (!strcmp (*iter, "RSN")) {
+			if (adhoc) {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Ad-Hoc mode cannot be used with proto 'RSN'");
+				goto free_list;
+			}
+			np++;
+			nm_setting_wireless_security_add_proto (wsec, "rsn");
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "Unknown proto '%s'", *iter);
+			goto free_list;
+		}
+	}
+	if (list)
+		g_strfreev(list);
+
+	if (!np) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		     "Empty proto");
+		goto error;
+	}
+
+	/*
+	 * Mandriva adds by default list of available protocols
+	 * FIXME be more intelligent - do not fail completely if
+	 * multiple methods are present; configure the best
+	 * available
+	 */
+	if (strstr (key_mgmt, "WPA-EAP") || strstr (key_mgmt, "IEEE8021X")) {
+		/* Adhoc mode is mutually exclusive with any 802.1x-based authentication */
+		if (adhoc) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Ad-Hoc mode cannot be used with key_mgmt type '%s'", key_mgmt);
+			goto error;
+		}
+
+		*s_8021x = fill_8021x (ifcfg, wpan, file, key_mgmt, TRUE, error);
+		if (!*s_8021x)
+			goto error;
+
+	} else if (strstr (key_mgmt, "WPA-PSK")) {
+		if (adhoc) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Ad-Hoc mode cannot be used with key_mgmt type 'WPA-PSK'");
+			goto error;
+		}
+		psk = parse_wpa_psk (wpan, file, ssid, error);
+		if (!psk)
+			goto error;
+		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL);
+		g_free (psk);
+	} else if (strstr (key_mgmt, "WPA-NONE")) {
+		if (!adhoc) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "key_mgmt type 'WPA_NONE' allowed only in Ad-Hoc mode");
+			goto error;
+		}
+		psk = parse_wpa_psk (wpan, file, ssid, error);
+		if (!psk)
+			goto error;
+		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL);
+		g_free (psk);
+	} else if (strstr (key_mgmt, "NONE")) {
+		if (!make_wep_from_wpa_supplicant(wpan, wsec, error))
+			goto error;
+	} else {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Unknown wireless KEY_MGMT type '%s'", key_mgmt);
+		goto error;
+	}
+	lower = g_ascii_strdown (key_mgmt, -1);
+	g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL);
+	g_free (lower);
+
+	return (NMSetting *) wsec;
+
+free_list:
+	if (list)
+		g_strfreev(list);
+error:
+	if (wsec)
+		g_object_unref (wsec);
+	return NULL;
+}
+
+#if 0
+// LEAP does not seem to be supported by Mandriva
+static NMSetting *
+make_leap_setting (shvarFile *ifcfg,
+                   const char *file,
+                   GError **error)
+{
+	NMSettingWirelessSecurity *wsec;
+	shvarFile *keys_ifcfg;
+	char *value;
+
+	wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
+
+	value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
+	if (!value || strcmp (value, "IEEE8021X"))
+		goto error; /* Not LEAP */
+
+	g_free (value);
+	value = svGetValue (ifcfg, "WIRELESS_ENC_MODE", FALSE);
+	if (!value || strcasecmp (value, "leap"))
+		goto error; /* Not LEAP */
+
+	g_free (value);
+
+	value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
+	if (!value) {
+		/* Try to get keys from the "shadow" key file */
+		keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
+		if (keys_ifcfg) {
+			value = svGetValue (keys_ifcfg, "IEEE_8021X_PASSWORD", FALSE);
+			svCloseFile (keys_ifcfg);
+		}
+	}
+	if (value && strlen (value))
+		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, value, NULL);
+	g_free (value);
+
+	value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
+	if (!value || !strlen (value)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing LEAP identity");
+		goto error;
+	}
+	g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value, NULL);
+	g_free (value);
+
+	g_object_set (wsec,
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
+	              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
+	              NULL);
+
+	return (NMSetting *) wsec;
+
+error:
+	g_free (value);
+	if (wsec)
+		g_object_unref (wsec);
+	return NULL;
+}
+#endif
+
+static NMSetting *
+make_wpa_supplicant_setting (shvarFile *ifcfg,
+                                const char *file,
+                                const GByteArray *ssid,
+                                gboolean adhoc,
+                                NMSetting8021x **s_8021x,
+                                GError **error)
+{
+	NMSetting *wsec = NULL; /* unencrypted by default */
+	WPAConfig *wpac = NULL;
+	WPANetwork *wpan = NULL;
+
+	/*
+	 * Mandriva saves WPA parameters directly in wpa_supplicant.conf
+	 */
+	wpac = ifcfg_mdv_wpa_config_new("/etc/wpa_supplicant.conf");
+	if (wpac && ifcfg_mdv_wpa_config_parse(wpac)) {
+		gboolean found = FALSE;
+
+		ifcfg_mdv_wpa_config_rewind(wpac);
+		while (!found && (wpan = ifcfg_mdv_wpa_config_next(wpac)) != NULL) {
+			GByteArray *b_ssid = ifcfg_mdv_wpa_network_get_ssid(wpan);
+
+			if (b_ssid) {
+				if (b_ssid->len == ssid->len && !memcmp(b_ssid->data, ssid->data, ssid->len))
+					found = TRUE;
+				g_byte_array_unref(b_ssid);
+			} else
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: no SSID in wpa_supplicant.conf network block");
+		}
+	} else {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "WIRELESS_WPA_DRIVER set but /etc/wpa_supplicant.conf missing");
+		goto done;
+	}
+
+	if (!wpan) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "WIRELESS_WPA_DRIVER set but SSID missing in /etc/wpa_supplicant.conf");
+		goto done;
+	}
+
+	wsec = make_wpa_setting (ifcfg, wpan, file, ssid, adhoc, s_8021x, error);
+done:
+	ifcfg_mdv_wpa_config_free (wpac);
+	return wsec;
+}
+
+static NMSetting *
+make_wireless_setting (shvarFile *ifcfg,
+                       gboolean nm_controlled,
+		       gboolean roaming,
+                       char **unmanaged,
+                       char *device,
+                       GError **error)
+{
+	NMSettingWireless *s_wireless;
+	GByteArray *array = NULL;
+	char *value;
+
+	s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
+
+	if (!roaming) {
+		if (read_mac_address (ifcfg, "HWADDR", &array, error)) {
+			/* if we don't have a HWADDR saved in ifcfg file, try to discover it manually */
+			if (!array) {
+				discover_mac_address(device, &array, error);
+			}
+			if (array) {
+				g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, array, NULL);
+
+				/* A connection can only be unmanaged if we know the MAC address */
+				if (!nm_controlled) {
+					*unmanaged = g_strdup_printf ("mac:%02x:%02x:%02x:%02x:%02x:%02x",
+								      array->data[0], array->data[1], array->data[2],
+								      array->data[3], array->data[4], array->data[5]);
+				}
+
+				g_byte_array_free (array, TRUE);
+			} else if (!nm_controlled) {
+				/* If NM_CONTROLLED=no but there wasn't a MAC address, notify
+				 * the user that the device cannot be unmanaged.
+				 */
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: NM_CONTROLLED was false but HWADDR was missing; device will be managed");
+			}
+		} else {
+			g_object_unref (s_wireless);
+			return NULL;
+		}
+	}
+
+	array = NULL;
+	if (read_mac_address (ifcfg, "MACADDR", &array, error)) {
+		if (array) {
+			g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, array, NULL);
+			g_byte_array_free (array, TRUE);
+		}
+	}
+
+	value = svGetValue (ifcfg, "WIRELESS_ESSID", TRUE);
+	if (value) {
+		array = ifcfg_mdv_parse_ssid (value, error);
+		g_free (value);
+
+		if (array) {
+			g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, array, NULL);
+			g_byte_array_free (array, TRUE);
+		} else
+			goto error;
+	} else {
+		/* Only fail on lack of SSID if device is managed */
+		if (nm_controlled) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Missing SSID");
+			goto error;
+		}
+	}
+
+	if (!nm_controlled)
+		goto done;
+
+	value = svGetValue (ifcfg, "WIRELESS_MODE", FALSE);
+	if (value) {
+		char *lcase;
+		const char *mode = NULL;
+
+		lcase = g_ascii_strdown (value, -1);
+		g_free (value);
+
+		if (!strcmp (lcase, "ad-hoc")) {
+			mode = "adhoc";
+		} else if (!strcmp (lcase, "managed") || !strcmp (lcase, "auto")) {
+			mode = "infrastructure";
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid mode '%s' (not 'Ad-Hoc', 'Managed', or 'Auto')",
+			             lcase);
+			g_free (lcase);
+			goto error;
+		}
+		g_free (lcase);
+
+		g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, mode, NULL);
+	}
+
+#if 0
+	value = svGetValue (ifcfg, "WIRELESS_BSSID", FALSE);
+	if (value) {
+		struct ether_addr *eth;
+		GByteArray *bssid;
+
+		eth = ether_aton (value);
+		if (!eth) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid BSSID '%s'", value);
+			goto error;
+		}
+
+		bssid = g_byte_array_sized_new (ETH_ALEN);
+		g_byte_array_append (bssid, eth->ether_addr_octet, ETH_ALEN);
+		g_object_set (s_wireless, NM_SETTING_WIRELESS_BSSID, bssid, NULL);
+		g_byte_array_free (bssid, TRUE);
+	}
+#endif
+
+	value = svGetValue (ifcfg, "WIRELESS_CHANNEL", FALSE);
+	if (value) {
+		long int chan;
+
+		errno = 0;
+		chan = strtol (value, NULL, 10);
+		if (errno || chan <= 0 || chan > 196) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid wireless channel '%s'", value);
+			g_free (value);
+			goto error;
+		}
+		g_object_set (s_wireless, NM_SETTING_WIRELESS_CHANNEL, (guint32) chan, NULL);
+		if (chan > 14)
+			g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "a", NULL);
+		else
+			g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "bg", NULL);
+	}
+
+	value = svGetValue (ifcfg, "MTU", FALSE);
+	if (value) {
+		long int mtu;
+
+		errno = 0;
+		mtu = strtol (value, NULL, 10);
+		if (errno || mtu < 0 || mtu > 50000) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Invalid wireless MTU '%s'", value);
+			g_free (value);
+			goto error;
+		}
+		g_object_set (s_wireless, NM_SETTING_WIRELESS_MTU, (guint32) mtu, NULL);
+	}
+
+done:
+	return NM_SETTING (s_wireless);
+
+error:
+	if (s_wireless)
+		g_object_unref (s_wireless);
+	return NULL;
+}
+
+/*
+ * roaming_connection_from_ifcfg
+ *
+ *   create connection from roaming definition in .../wireless.d
+ *   this is not physical interface, so no interface related settings here
+ *   also it is always managed and marked for automatic activation
+ */
+static NMConnection *
+roaming_connection_from_ifcfg (const char *file,
+                                shvarFile *ifcfg,
+                                GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *wireless_setting = NULL;
+	NMSetting8021x *s_8021x = NULL;
+	const GByteArray *ssid;
+	NMSetting *security_setting = NULL;
+	char *printable_ssid = NULL, *tmp, *name;
+	gboolean adhoc = FALSE;
+
+	g_return_val_if_fail (file != NULL, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+	g_return_val_if_fail (error != NULL, NULL);
+	g_return_val_if_fail (*error == NULL, NULL);
+
+	/* Sanity checks */
+	tmp = svGetValue(ifcfg, "WIRELESS_WPA_DRIVER", FALSE);
+	if (!tmp) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			"WIRELESS_WPA_DRIVER missing in %s", file);
+		return NULL;
+	}
+	g_free(tmp);
+
+	tmp = svGetValue(ifcfg, "WIRELESS_ESSID", FALSE);
+	if (!tmp) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			"WIRELESS_ESSID missing in %s; ignoring connection", file);
+		return NULL;
+	}
+	name = g_path_get_basename(file);
+	if (strcmp(tmp, name)){
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			"WIRELESS_ESSID '%s' does not match file %s; ignoring connection", tmp, file);
+		g_free(name);
+		g_free(tmp);
+		return NULL;
+	}
+	g_free(name);
+	g_free(tmp);
+
+	connection = nm_connection_new ();
+	if (!connection) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to allocate new connection for %s.", file);
+		return NULL;
+	}
+
+	wireless_setting = make_wireless_setting (ifcfg, TRUE, TRUE, NULL, NULL, error);
+	if (!wireless_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, wireless_setting);
+
+	ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (wireless_setting));
+	g_assert(ssid);
+	printable_ssid = nm_utils_ssid_to_utf8 ((const char *) ssid->data, ssid->len);
+
+	/* Wireless security */
+	security_setting = make_wpa_supplicant_setting(ifcfg, file, ssid, adhoc, &s_8021x, error);
+	if (*error) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	if (security_setting) {
+		nm_connection_add_setting (connection, security_setting);
+		if (s_8021x)
+			nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+		g_object_set (wireless_setting, NM_SETTING_WIRELESS_SEC,
+			      NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NULL);
+	}
+
+	/* Connection */
+	con_setting = make_connection_setting (file, ifcfg,
+	                                       NM_SETTING_WIRELESS_SETTING_NAME,
+	                                       printable_ssid);
+	g_free (printable_ssid);
+	if (!con_setting) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to create connection setting.");
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, con_setting);
+
+	return connection;
+}
+
+static NMConnection *
+wireless_connection_from_ifcfg (const char *file,
+                                shvarFile *ifcfg,
+                                gboolean nm_controlled,
+                                char **unmanaged,
+                                char *device,
+                                GError **error,
+				gboolean *ignore_error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *wireless_setting = NULL;
+	NMSetting8021x *s_8021x = NULL;
+	const GByteArray *ssid;
+	NMSetting *security_setting = NULL;
+	char *printable_ssid = NULL;
+	const char *mode;
+	gboolean adhoc = FALSE;
+
+	g_return_val_if_fail (file != NULL, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+	g_return_val_if_fail (error != NULL, NULL);
+	g_return_val_if_fail (*error == NULL, NULL);
+
+	connection = nm_connection_new ();
+	if (!connection) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to allocate new connection for %s.", file);
+		return NULL;
+	}
+
+	/* Wireless */
+	wireless_setting = make_wireless_setting (ifcfg, nm_controlled, FALSE, unmanaged, device, error);
+	if (!wireless_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, wireless_setting);
+
+	ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (wireless_setting));
+	if (ssid)
+		printable_ssid = nm_utils_ssid_to_utf8 ((const char *) ssid->data, ssid->len);
+	else
+		printable_ssid = g_strdup_printf ("unmanaged");
+
+	if (nm_controlled) {
+		gchar *driver;
+		mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (wireless_setting));
+		if (mode && !strcmp (mode, "adhoc"))
+			adhoc = TRUE;
+
+		/* Wireless security */
+		driver = svGetValue (ifcfg, "WIRELESS_WPA_DRIVER", FALSE);
+		if (driver) {
+			g_free (driver);
+
+			/*
+			 * If WIRELESS_WPA_DRIVER is set, it is roaming
+			 * connection which is defined in separate file
+			 * under .../wireless.d directory. To avoid duplicates,
+			 * do not return any connection at all
+			 */
+			PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "    skipping interface in roaming mode (WIRELESS_WPA_DRIVER set)");
+			g_object_unref(connection);
+			connection = NULL;
+			*ignore_error = TRUE;
+			/* FIXME to silence read_one_connection in plugin.c */
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				"Skipped interface in roaming mode.");
+			return connection;
+		} else {
+
+#if 0
+			// LEAP does not seem to be supported by Mandriva
+			if (!adhoc) {
+				wsec = make_leap_setting (ifcfg, file, error);
+				if (wsec)
+					return wsec;
+				else if (*error)
+					goto error;
+			}
+#endif
+			security_setting = make_wep_setting (ifcfg, file, error);
+		}
+		if (*error) {
+			g_object_unref (connection);
+			return NULL;
+		}
+		if (security_setting) {
+			nm_connection_add_setting (connection, security_setting);
+			if (s_8021x)
+				nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+			g_object_set (wireless_setting, NM_SETTING_WIRELESS_SEC,
+			              NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NULL);
+		}
+	}
+
+	/* Connection */
+	con_setting = make_connection_setting (file, ifcfg,
+	                                       NM_SETTING_WIRELESS_SETTING_NAME,
+	                                       printable_ssid);
+	g_free (printable_ssid);
+	if (!con_setting) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to create connection setting.");
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, con_setting);
+
+	/* Don't verify if unmanaged since we may not have an SSID or whatever */
+	if (nm_controlled) {
+		if (!nm_connection_verify (connection, error)) {
+			g_object_unref (connection);
+			return NULL;
+		}
+	}
+
+	return connection;
+}
+
+static NMSetting *
+make_wired_setting (shvarFile *ifcfg,
+                    const char *file,
+                    gboolean nm_controlled,
+                    char **unmanaged,
+                    NMSetting8021x **s_8021x,
+                    char *device,
+                    GError **error)
+{
+	NMSettingWired *s_wired;
+	char *value = NULL;
+	int mtu;
+	GByteArray *mac = NULL;
+
+	s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
+
+	value = svGetValue (ifcfg, "MTU", FALSE);
+	if (value) {
+		if (get_int (value, &mtu)) {
+			if (mtu >= 0 && mtu < 65536)
+				g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu, NULL);
+		} else {
+			/* Shouldn't be fatal... */
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid MTU '%s'", value);
+		}
+		g_free (value);
+	}
+
+	if (read_mac_address (ifcfg, "HWADDR", &mac, error)) {
+		/* if we don't have a HWADDR saved in ifcfg file, try to discover it manually */
+		if (!mac) {
+			discover_mac_address(device, &mac, error);
+		}
+		if (mac) {
+			g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
+
+			/* A connection can only be unmanaged if we know the MAC address */
+			if (!nm_controlled) {
+				*unmanaged = g_strdup_printf ("mac:%02x:%02x:%02x:%02x:%02x:%02x",
+				                              mac->data[0], mac->data[1], mac->data[2],
+				                              mac->data[3], mac->data[4], mac->data[5]);
+			}
+
+			g_byte_array_free (mac, TRUE);
+		} else if (!nm_controlled) {
+			/* If NM_CONTROLLED=no but there wasn't a MAC address, notify
+			 * the user that the device cannot be unmanaged.
+			 */
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: NM_CONTROLLED was false but HWADDR was missing; device will be managed");
+		}
+	} else {
+		g_object_unref (s_wired);
+		s_wired = NULL;
+	}
+
+	mac = NULL;
+	if (read_mac_address (ifcfg, "MACADDR", &mac, error)) {
+		if (mac) {
+			g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, mac, NULL);
+			g_byte_array_free (mac, TRUE);
+		}
+	}
+
+#if 0
+	/* Mandriva does not support IEEE802.1x on wired connections */
+	value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
+	if (value) {
+		if (!strcmp (value, "IEEE8021X")) {
+			*s_8021x = fill_8021x (ifcfg, file, value, FALSE, error);
+			if (!*s_8021x)
+				goto error;
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Unknown wired KEY_MGMT type '%s'", value);
+			goto error;
+		}
+		g_free (value);
+	}
+#endif
+
+	return (NMSetting *) s_wired;
+
+#if 0
+	/* Mandriva does not support IEEE802.1x on wired connections;
+	 * this is unreacheable */
+error:
+	g_free (value);
+	g_object_unref (s_wired);
+	return NULL;
+#endif
+}
+
+static NMConnection *
+wired_connection_from_ifcfg (const char *file,
+                             shvarFile *ifcfg,
+                             gboolean nm_controlled,
+                             char **unmanaged,
+                             char *device,
+                             GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *wired_setting = NULL;
+	NMSetting8021x *s_8021x = NULL;
+
+	g_return_val_if_fail (file != NULL, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+
+	connection = nm_connection_new ();
+	if (!connection) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to allocate new connection for %s.", file);
+		return NULL;
+	}
+
+	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL);
+	if (!con_setting) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to create connection setting.");
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, con_setting);
+
+	wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, device, error);
+	if (!wired_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, wired_setting);
+
+#if 0
+	/* Always NULL on Mandriva */
+	if (s_8021x)
+		nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+#endif
+
+	if (!nm_connection_verify (connection, error)) {
+		g_object_unref (connection);
+		return NULL;
+	}
+
+	return connection;
+}
+
+static gboolean
+is_wireless_device (const char *iface)
+{
+	int fd;
+	struct iw_range range;
+	struct iwreq wrq;
+	gboolean is_wireless = FALSE;
+
+	g_return_val_if_fail (iface != NULL, FALSE);
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (!fd)
+		return FALSE;
+
+	memset (&wrq, 0, sizeof (struct iwreq));
+	memset (&range, 0, sizeof (struct iw_range));
+	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
+	wrq.u.data.pointer = (caddr_t) &range;
+	wrq.u.data.length = sizeof (struct iw_range);
+
+	if (ioctl (fd, SIOCGIWRANGE, &wrq) == 0)
+		is_wireless = TRUE;
+	else {
+		if (errno == EOPNOTSUPP)
+			is_wireless = FALSE;
+		else {
+			/* Sigh... some wired devices (kvm/qemu) return EINVAL when the
+			 * device is down even though it's not a wireless device.  So try
+			 * IWNAME as a fallback.
+			 */
+			memset (&wrq, 0, sizeof (struct iwreq));
+			strncpy (wrq.ifr_name, iface, IFNAMSIZ);
+			if (ioctl (fd, SIOCGIWNAME, &wrq) == 0)
+				is_wireless = TRUE;
+		}
+	}
+
+	close (fd);
+	return is_wireless;
+}
+
+enum {
+	IGNORE_REASON_NONE = 0x00,
+	IGNORE_REASON_BRIDGE = 0x01,
+	IGNORE_REASON_VLAN = 0x02,
+};
+
+NMConnection *
+connection_from_file (const char *filename,
+                      const char *network_file,  /* for unit tests only */
+                      const char *test_type,     /* for unit tests only */
+                      const char *iscsiadm_path, /* for unit tests only */
+                      char **unmanaged,
+                      char **keyfile,
+                      char **routefile,
+                      char **route6file,
+                      GError **out_error,
+                      gboolean *ignore_error)
+{
+	NMConnection *connection = NULL;
+	shvarFile *parsed;
+	char *type = NULL, *nmc = NULL, *tmp;
+	NMSetting *s_ip4;
+	gboolean nm_controlled = FALSE;
+	char *device = NULL;
+	MdvIfcfgType ifcfg_type;
+	gboolean ip6_used = FALSE;
+	GError *error = NULL;
+	guint32 ignore_reason = IGNORE_REASON_NONE;
+
+	g_return_val_if_fail (filename != NULL, NULL);
+	g_return_val_if_fail (unmanaged != NULL, NULL);
+	g_return_val_if_fail (*unmanaged == NULL, NULL);
+	g_return_val_if_fail (keyfile != NULL, NULL);
+	g_return_val_if_fail (*keyfile == NULL, NULL);
+	g_return_val_if_fail (routefile != NULL, NULL);
+	g_return_val_if_fail (*routefile == NULL, NULL);
+	g_return_val_if_fail (route6file != NULL, NULL);
+	g_return_val_if_fail (*route6file == NULL, NULL);
+
+	/* Non-NULL only for unit tests; normally use /etc/sysconfig/network */
+	if (!network_file)
+		network_file = SYSCONFDIR "/sysconfig/network";
+
+	if (!iscsiadm_path)
+		iscsiadm_path = SBINDIR "/iscsiadm";
+
+	ifcfg_type = mdv_get_ifcfg_type(filename);
+	if (ifcfg_type == MdvIfcfgTypeUnknown) {
+		g_set_error(out_error, IFCFG_PLUGIN_ERROR, 0,
+			"Cannot determine connection type for %s; ignored", filename);
+		return NULL;
+	}
+
+	parsed = svNewFile (filename);
+	if (!parsed) {
+		g_set_error (out_error, IFCFG_PLUGIN_ERROR, 0,
+		             "Couldn't parse file '%s'", filename);
+		return NULL;
+	}
+
+	if (ifcfg_type == MdvIfcfgTypeInterface) {
+		/*
+		 * Physical interface, may be umnagaed
+		 */
+		device = svGetValue (parsed, "DEVICE", FALSE);
+		if (!device) {
+			g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
+				 "File '%s' does not have DEVICE key", filename);
+			goto done;
+		}
+
+		if (!strcmp (device, "lo")) {
+			if (ignore_error)
+				*ignore_error = TRUE;
+			g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
+			             "Ignoring loopback device config.");
+			goto done;
+		}
+
+		type = svGetValue (parsed, "TYPE", FALSE);
+		if (!type) {
+
+			/* If no type, if the device has wireless extensions, it's wifi,
+			 * otherwise it's ethernet.
+			 */
+			if (!test_type) {
+				/* Test wireless extensions */
+				if (is_wireless_device (device))
+					type = g_strdup (TYPE_WIRELESS);
+				else
+					type = g_strdup (TYPE_ETHERNET);
+			} else {
+				/* For the unit tests, there won't necessarily be any
+				 * adapters of the connection's type in the system so the
+				 * type can't be tested with ioctls.
+				 */
+				type = g_strdup (test_type);
+			}
+
+		}
+
+		nmc = svGetValue (parsed, "NM_CONTROLLED", FALSE);
+		if (nmc) {
+			char *lower;
+
+			lower = g_ascii_strdown (nmc, -1);
+			g_free (nmc);
+
+			if (!strcmp (lower, "yes") || !strcmp (lower, "y") || !strcmp (lower, "true"))
+				nm_controlled = TRUE;
+			g_free (lower);
+		}
+
+		/* Ignore BRIDGE= and VLAN= connections for now too (rh #619863) */
+		tmp = svGetValue (parsed, "BRIDGE", FALSE);
+		if (tmp) {
+			g_free (tmp);
+			nm_controlled = FALSE;
+			ignore_reason = IGNORE_REASON_BRIDGE;
+		}
+
+		if (nm_controlled) {
+			tmp = svGetValue (parsed, "VLAN", FALSE);
+			if (tmp) {
+				g_free (tmp);
+				nm_controlled = FALSE;
+				ignore_reason = IGNORE_REASON_VLAN;
+			}
+		}
+
+		if (!strcasecmp (type, TYPE_ETHERNET))
+			connection = wired_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, device, &error);
+		else if (!strcasecmp (type, TYPE_WIRELESS))
+			connection = wireless_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, device, &error, ignore_error);
+		else if (!strcasecmp (type, TYPE_BRIDGE)) {
+			g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
+				     "Bridge connections are not yet supported");
+		} else {
+			g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
+				     "Unknown connection type '%s'", type);
+		}
+
+		if (nm_controlled) {
+			g_free (*unmanaged);
+			*unmanaged = NULL;
+		}
+
+		g_free (type);
+
+	} else if (ifcfg_type == MdvIfcfgTypeSSID) {
+		/* TODO directly jump to wireless WPA */
+		connection = roaming_connection_from_ifcfg(filename, parsed, &error);
+	} else {
+		g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
+			"Ignoring BSSID file '%s'", filename);
+			goto done;
+	}
+
+	/* Don't bother reading the connection fully if it's unmanaged or ignored */
+	if (!connection || *unmanaged || ignore_reason) {
+		if (connection && !*unmanaged) {
+			/* However,BRIDGE and VLAN connections that don't have HWADDR won't
+			 * be unmanaged because the unmanaged state is keyed off HWADDR.
+			 * They willl still be tagged 'ignore' from code that checks BRIDGE
+			 * and VLAN above.  Since they aren't marked unmanaged, kill them
+			 * completely.
+			 */
+			if (ignore_reason) {
+				g_object_unref (connection);
+				connection = NULL;
+				g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
+				             "%s connections are not yet supported",
+				             ignore_reason == IGNORE_REASON_BRIDGE ? "Bridge" : "VLAN");
+			}
+		}
+		goto done;
+	}
+
+#if 0
+	s_ip6 = make_ip6_setting (parsed, network_file, iscsiadm_path, &error);
+	if (error) {
+		g_object_unref (connection);
+		connection = NULL;
+		goto done;
+	} else if (s_ip6) {
+		const char *method;
+
+		nm_connection_add_setting (connection, s_ip6);
+		method = nm_setting_ip6_config_get_method (NM_SETTING_IP6_CONFIG (s_ip6));
+		if (method && strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE))
+			ip6_used = TRUE;
+	}
+#endif
+
+	s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, ip6_used, &error);
+	if (error) {
+		g_object_unref (connection);
+		connection = NULL;
+		goto done;
+	} else if (s_ip4)
+		nm_connection_add_setting (connection, s_ip4);
+
+#if 0
+	/* no iSCSI on Mandriva */
+	/* iSCSI / ibft connections are read-only since their settings are
+	 * stored in NVRAM and can only be changed in BIOS.
+	 */
+	bootproto = svGetValue (parsed, "BOOTPROTO", FALSE);
+	if (   bootproto
+	    && connection
+	    && !g_ascii_strcasecmp (bootproto, "ibft")) {
+		NMSettingConnection *s_con;
+
+		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		g_assert (s_con);
+
+		g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_READ_ONLY, TRUE, NULL);
+	}
+#endif
+
+	if (!nm_connection_verify (connection, &error)) {
+		g_object_unref (connection);
+		connection = NULL;
+	}
+
+	*keyfile = utils_get_keys_path (filename);
+	*routefile = utils_get_route_path (filename);
+	*route6file = utils_get_route6_path (filename);
+
+done:
+	g_free(device);
+	svCloseFile (parsed);
+	if (error && out_error)
+		*out_error = error;
+	else
+		g_clear_error (&error);
+	return connection;
+}
+
+const char *
+reader_get_prefix (void)
+{
+	return _("System");
+}
+
diff --git a/system-settings/plugins/ifcfg-mdv/reader.h b/system-settings/plugins/ifcfg-mdv/reader.h
new file mode 100644
index 0000000..94fb235
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/reader.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifndef __READER_H__
+#define __READER_H__
+
+#include <glib.h>
+#include <nm-connection.h>
+
+#include "shvar.h"
+
+NMConnection *connection_from_file (const char *filename,
+                                    const char *network_file,  /* for unit tests only */
+                                    const char *test_type,     /* for unit tests only */
+                                    const char *iscsiadm_path, /* for unit tests only */
+                                    char **unmanaged,
+                                    char **keyfile,
+                                    char **routefile,
+                                    char **route6file,
+                                    GError **error,
+                                    gboolean *ignore_error);
+
+const char *reader_get_prefix (void);
+GByteArray *ifcfg_mdv_parse_ssid(char *, GError **);
+
+#endif  /* __READER_H__ */
diff --git a/system-settings/plugins/ifcfg-mdv/utils-mdv.c b/system-settings/plugins/ifcfg-mdv/utils-mdv.c
new file mode 100644
index 0000000..64db74f
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/utils-mdv.c
@@ -0,0 +1,180 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * 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.
+ *
+ * (C) Copyright 2008 - 2009 Red Hat, Inc.
+ * (C) Copyright 2010 Andrey Borzenkov <arvidjaar@mail.ru>
+ */
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "utils.h"
+#include "utils-mdv.h"
+#include "shvar.h"
+
+/*
+ * split_ifcfg_name
+ *
+ *   split full path name in last component (ifcfg-XXX or wireless SSID)
+ *   and previous (which may be name of .../wireless.d subdir
+ */
+static void
+split_ifcfg_name(const gchar *path, gchar **wireless_d, gchar **name)
+{
+	gchar *tmp;
+
+	g_assert(wireless_d);
+	g_assert(name);
+
+	*wireless_d = *name = NULL;
+	g_return_if_fail(path != NULL);
+
+	*name = g_path_get_basename(path);
+	tmp = g_path_get_dirname(path);
+	*wireless_d = g_path_get_basename(tmp);
+	g_free(tmp);
+}
+
+/*
+ * mdv_should_ignore_file
+ *
+ *   Check whether file name may be valid connection definition file
+ *
+ */
+gboolean
+mdv_should_ignore_file(const gchar *path)
+{
+	gchar *file = NULL, *wireless_d = NULL;
+	gboolean result = FALSE;
+
+	g_return_val_if_fail(path != NULL, TRUE);
+
+	split_ifcfg_name(path, &wireless_d, &file);
+	if (!wireless_d || !file)
+		goto out;
+
+	if (strcmp(wireless_d, "wireless.d")) {
+		/* Standard RH-style ifcfg-XXX */
+		result = utils_should_ignore_file(file, TRUE);
+	} else {
+		/* We really can check only name length */
+		if (strlen(file) > 32)
+			result = TRUE;
+	}
+
+out:
+	g_free(wireless_d);
+	g_free(file);
+
+	return result;
+}
+
+/*
+ * mdv_get_ifcfg_type
+ * 
+ *   return possible type of connecion definition file. If filename
+ *   looks like valid connection, return suggested connection name
+ *   additionally
+ */
+MdvIfcfgType
+mdv_get_ifcfg_type(const gchar *path)
+{
+	gchar *wireless_d = NULL, *file = NULL;
+	const gchar *tmp;
+	static GRegex *bssid_regex;
+	MdvIfcfgType ret = MdvIfcfgTypeUnknown;
+
+	g_return_val_if_fail(path != NULL, MdvIfcfgTypeUnknown);
+
+	split_ifcfg_name(path, &wireless_d, &file);
+	if (!wireless_d || !file)
+		goto out;
+
+	/* Plugin is never unloaded */
+	if (!bssid_regex)
+		bssid_regex = g_regex_new("[[:xdigit:]]{2}(:[[:xdigit:]]{2}){5}", 0, 0, NULL);
+	g_assert(bssid_regex);
+
+	if (strcmp(wireless_d, "wireless.d")) {
+		/* Plain ifcfg */
+		 tmp = utils_get_ifcfg_name(file, TRUE);
+		 if (tmp)
+			 ret = MdvIfcfgTypeInterface;
+	} else {
+		/*
+		 * SSID can really be everything, so just try to check
+		 * whether file name _looks_ like BSSID
+		 */
+		if (g_regex_match(bssid_regex, file, 0, NULL))
+			ret = MdvIfcfgTypeBSSID;
+		else
+			ret = MdvIfcfgTypeSSID;
+	}
+
+out:
+	g_free(wireless_d);
+	g_free(file);
+
+	return ret;
+}
+
+/*
+ * mdv_get_ifcfg_name
+ * 
+ *   return ifcfg name. For plain ifcfg-XXX this is XXX;
+ *   for a file under .../wireless.d this is simply file name
+ */
+gchar *
+mdv_get_ifcfg_name(const gchar *path)
+{
+	switch (mdv_get_ifcfg_type(path)) {
+		case MdvIfcfgTypeInterface:
+			/* RH function return pointer into path */
+			return g_strdup(utils_get_ifcfg_name(path, TRUE));
+			break;
+		case MdvIfcfgTypeSSID:
+		case MdvIfcfgTypeBSSID:
+			return g_path_get_basename(path);
+			break;
+		default:
+			return NULL;
+			break;
+	}
+}
+
+/*
+ * mdv_get_ifcfg_path
+ * 
+ *   return ifcfg path. For RH style names this is .../ifcfg-XXX
+ *   for a file under .../wireless.d this is simply file name
+ */
+gchar *
+mdv_get_ifcfg_path(const gchar *path)
+{
+	switch (mdv_get_ifcfg_type(path)) {
+		case MdvIfcfgTypeInterface:
+			return utils_get_ifcfg_path(path);
+			break;
+		case MdvIfcfgTypeSSID:
+		case MdvIfcfgTypeBSSID:
+			return g_strdup(path);
+			break;
+		default:
+			return NULL;
+			break;
+	}
+}
diff --git a/system-settings/plugins/ifcfg-mdv/utils-mdv.h b/system-settings/plugins/ifcfg-mdv/utils-mdv.h
new file mode 100644
index 0000000..e85e3ac
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/utils-mdv.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * 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.
+ *
+ * (C) Copyright 2008 - 2009 Red Hat, Inc.
+ * (C) Copyright 2010 Andrey Borzenkov <arvidjaar@mail.ru>
+ */
+
+#ifndef _UTILS_MDV_H_
+#define _UTILS_H_MDV_
+
+#include <glib.h>
+#include "shvar.h"
+#include "common.h"
+
+typedef enum {
+	MdvIfcfgTypeUnknown,	/* What is it? */
+	MdvIfcfgTypeInterface,	/* e.g. .../ifcfg-wlan0 */
+	MdvIfcfgTypeSSID,	/* e.g. .../wireless.d/my_ssid */
+	MdvIfcfgTypeBSSID	/* e.g. .../wireless.d/01:23:45:67:89:ab */
+} MdvIfcfgType;
+
+gboolean mdv_should_ignore_file (const gchar *);
+MdvIfcfgType mdv_get_ifcfg_type (const gchar *);
+gchar *mdv_get_ifcfg_name (const gchar *);
+gchar *mdv_get_ifcfg_path (const gchar *);
+
+#if 0
+char *utils_bin2hexstr (const char *bytes, int len, int final_len);
+
+char *utils_hexstr2bin (const char *hex, size_t len);
+
+char *utils_cert_path (const char *parent, const char *suffix);
+
+const char *utils_get_ifcfg_name (const char *file, gboolean only_ifcfg);
+
+gboolean utils_should_ignore_file (const char *filename, gboolean only_ifcfg);
+
+char *utils_get_ifcfg_path (const char *parent);
+char *utils_get_keys_path (const char *parent);
+char *utils_get_route_path (const char *parent);
+char *utils_get_route6_path (const char *parent);
+
+shvarFile *utils_get_extra_ifcfg (const char *parent, const char *tag, gboolean should_create);
+shvarFile *utils_get_keys_ifcfg (const char *parent, gboolean should_create);
+shvarFile *utils_get_route_ifcfg (const char *parent, gboolean should_create);
+shvarFile *utils_get_route6_ifcfg (const char *parent, gboolean should_create);
+
+gboolean utils_has_route_file_new_syntax (const char *filename);
+#endif
+
+#endif  /* _UTILS_MDV_H_ */
+
diff --git a/system-settings/plugins/ifcfg-mdv/writer.c b/system-settings/plugins/ifcfg-mdv/writer.c
new file mode 100644
index 0000000..7e9e400
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/writer.c
@@ -0,0 +1,1835 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service - keyfile plugin
+ *
+ * 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) 2009 - 2010 Red Hat, Inc.
+ * Mandriva-specific changes by Eugeni Dodonov <eugeni@mandriva.com>.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <nm-setting-connection.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-8021x.h>
+#include <nm-setting-ip4-config.h>
+#include <nm-setting-ip6-config.h>
+#include <nm-setting-pppoe.h>
+#include <nm-utils.h>
+
+#include "common.h"
+#include "shvar.h"
+#include "reader.h"
+#include "writer.h"
+#include "utils.h"
+#include "utils-mdv.h"
+#include "crypto.h"
+
+#include "parse_wpa_supplicant_conf.h"
+
+#define PLUGIN_WARN(pname, fmt, args...) \
+	{ g_warning ("   " pname ": " fmt, ##args); }
+
+
+/*
+ * ifcfg reader converts ASCII to HEX. This converts key back to ASCII
+ * before writing
+ */
+
+static gchar *
+wep4ifcfg(const gchar *value)
+{
+	gchar *s;
+	gsize len;
+	GString *str;
+
+	if (!value)
+		return NULL;
+
+	len = strlen(value);
+	str = g_string_new("");
+
+	if (len == 5 || len == 13) {
+		g_string_printf(str, "s:%s", value);
+	} else if (len == 10 || len == 26) {
+		gchar *p;
+		s = utils_hexstr2bin (value, len);
+		for (p = s; *p; p++) {
+			if (!isascii (*p)) {
+				g_free(s);
+				g_string_free(str, TRUE);
+				return g_strdup(value);
+			}
+		}
+		g_string_printf(str, "s:%s", s);
+		g_free(s);
+	} else {
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid WEP key length");
+		g_string_free(str, TRUE);
+		return NULL;
+	}
+
+	s = svEscape(str->str);
+	g_string_free(str, TRUE);
+	return s;
+}
+static void
+set_wep_secret (shvarFile *ifcfg, const char *key, const char *value, gboolean verbatim)
+{
+	char *v = 0;
+	
+	/* Clear the secret from the actual ifcfg */
+	svSetValue (ifcfg, key, NULL, FALSE);
+
+	/* WEP -> WPA will set empty key */
+	if (!value)
+		return;
+
+	v = wep4ifcfg(value);
+	if (!v)
+		return;
+
+	/* Try setting the secret in the actual ifcfg */
+	svSetValue (ifcfg, key, v, TRUE);
+	g_free(v);
+}
+
+#if 0
+static gboolean
+write_secret_file (const char *path,
+                   const char *data,
+                   gsize len,
+                   GError **error)
+{
+	char *tmppath;
+	int fd = -1, written;
+	gboolean success = FALSE;
+
+	tmppath = g_malloc0 (strlen (path) + 10);
+	if (!tmppath) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not allocate memory for temporary file for '%s'",
+		             path);
+		return FALSE;
+	}
+
+	memcpy (tmppath, path, strlen (path));
+	strcat (tmppath, ".XXXXXX");
+
+	errno = 0;
+	fd = mkstemp (tmppath);
+	if (fd < 0) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not create temporary file for '%s': %d",
+		             path, errno);
+		goto out;
+	}
+
+	/* Only readable by root */
+	errno = 0;
+	if (fchmod (fd, S_IRUSR | S_IWUSR)) {
+		close (fd);
+		unlink (tmppath);
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not set permissions for temporary file '%s': %d",
+		             path, errno);
+		goto out;
+	}
+
+	errno = 0;
+	written = write (fd, data, len);
+	if (written != len) {
+		close (fd);
+		unlink (tmppath);
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not write temporary file for '%s': %d",
+		             path, errno);
+		goto out;
+	}
+	close (fd);
+
+	/* Try to rename */
+	errno = 0;
+	if (rename (tmppath, path)) {
+		unlink (tmppath);
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not rename temporary file to '%s': %d",
+		             path, errno);
+		goto out;
+	}
+	success = TRUE;
+
+out:
+	return success;
+}
+#endif
+
+typedef NMSetting8021xCKScheme (*SchemeFunc)(NMSetting8021x *setting);
+typedef const char *           (*PathFunc)  (NMSetting8021x *setting);
+typedef const GByteArray *     (*BlobFunc)  (NMSetting8021x *setting);
+
+typedef struct ObjectType {
+	const char *setting_key;
+	SchemeFunc scheme_func;
+	PathFunc path_func;
+	BlobFunc blob_func;
+	const char *ifcfg_key;
+	const char *suffix;
+} ObjectType;
+
+static const ObjectType ca_type = {
+	NM_SETTING_802_1X_CA_CERT,
+	nm_setting_802_1x_get_ca_cert_scheme,
+	nm_setting_802_1x_get_ca_cert_path,
+	nm_setting_802_1x_get_ca_cert_blob,
+	"ca_cert",
+	"ca-cert.der"
+};
+
+static const ObjectType phase2_ca_type = {
+	NM_SETTING_802_1X_PHASE2_CA_CERT,
+	nm_setting_802_1x_get_phase2_ca_cert_scheme,
+	nm_setting_802_1x_get_phase2_ca_cert_path,
+	nm_setting_802_1x_get_phase2_ca_cert_blob,
+	"ca_cert2",
+	"inner-ca-cert.der"
+};
+
+static const ObjectType client_type = {
+	NM_SETTING_802_1X_CLIENT_CERT,
+	nm_setting_802_1x_get_client_cert_scheme,
+	nm_setting_802_1x_get_client_cert_path,
+	nm_setting_802_1x_get_client_cert_blob,
+	"client_cert",
+	"client-cert.der"
+};
+
+static const ObjectType phase2_client_type = {
+	NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
+	nm_setting_802_1x_get_phase2_client_cert_scheme,
+	nm_setting_802_1x_get_phase2_client_cert_path,
+	nm_setting_802_1x_get_phase2_client_cert_blob,
+	"client_cert2",
+	"inner-client-cert.der"
+};
+
+static const ObjectType pk_type = {
+	NM_SETTING_802_1X_PRIVATE_KEY,
+	nm_setting_802_1x_get_private_key_scheme,
+	nm_setting_802_1x_get_private_key_path,
+	nm_setting_802_1x_get_private_key_blob,
+	"private_key",
+	"private-key.pem"
+};
+
+static const ObjectType phase2_pk_type = {
+	NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
+	nm_setting_802_1x_get_phase2_private_key_scheme,
+	nm_setting_802_1x_get_phase2_private_key_path,
+	nm_setting_802_1x_get_phase2_private_key_blob,
+	"private_key2",
+	"inner-private-key.pem"
+};
+
+static const ObjectType p12_type = {
+	NM_SETTING_802_1X_PRIVATE_KEY,
+	nm_setting_802_1x_get_private_key_scheme,
+	nm_setting_802_1x_get_private_key_path,
+	nm_setting_802_1x_get_private_key_blob,
+	"private_key",
+	"private-key.p12"
+};
+
+static const ObjectType phase2_p12_type = {
+	NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
+	nm_setting_802_1x_get_phase2_private_key_scheme,
+	nm_setting_802_1x_get_phase2_private_key_path,
+	nm_setting_802_1x_get_phase2_private_key_blob,
+	"private_key2",
+	"inner-private-key.p12"
+};
+
+/*
+ * FIXME the name is misleading and should be changed
+ * Mandriva does not use explicit certifcate store so we do nto either
+ * If given BLOB - fail, informing user
+ */
+static gboolean
+write_object (NMSetting8021x *s_8021x,
+	      WPANetwork *wpan,
+              shvarFile *ifcfg,
+              const GByteArray *override_data,
+              const ObjectType *objtype,
+              GError **error)
+{
+	NMSetting8021xCKScheme scheme;
+	const char *path = NULL;
+	const GByteArray *blob = NULL;
+
+	g_return_val_if_fail (ifcfg != NULL, FALSE);
+	g_return_val_if_fail (objtype != NULL, FALSE);
+
+	if (override_data) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "ifcfg-mdv does not support raw certificate data");
+		return FALSE;
+		/* if given explicit data to save, always use that instead of asking
+		 * the setting what to do.
+		 */
+		// blob = override_data;
+	} else {
+		scheme = (*(objtype->scheme_func))(s_8021x);
+		switch (scheme) {
+		case NM_SETTING_802_1X_CK_SCHEME_BLOB:
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "ifcfg-mdv does not support raw certificate data");
+			return FALSE;
+		// 	blob = (*(objtype->blob_func))(s_8021x);
+		// 	break;
+		case NM_SETTING_802_1X_CK_SCHEME_PATH:
+			path = (*(objtype->path_func))(s_8021x);
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* If certificate/private key wasn't sent, the connection may no longer be
+	 * 802.1x and thus we clear out the paths and certs.
+	 */
+	if (!path && !blob) {
+		// char *standard_file;
+		// int ignored;
+
+		/* Since no cert/private key is now being used, delete any standard file
+		 * that was created for this connection, but leave other files alone.
+		 * Thus, for example,
+		 * /etc/sysconfig/network-scripts/ca-cert-Test_Write_Wifi_WPA_EAP-TLS.der
+		 * will be deleted, but /etc/pki/tls/cert.pem will not.
+		 */
+#if 0
+		standard_file = utils_cert_path (ifcfg->fileName, objtype->suffix);
+		if (g_file_test (standard_file, G_FILE_TEST_EXISTS))
+			ignored = unlink (standard_file);
+		g_free (standard_file);
+#endif
+
+		ifcfg_mdv_wpa_network_unset(wpan, objtype->ifcfg_key);
+		return TRUE;
+	}
+
+	/* If the object path was specified, prefer that over any raw cert data that
+	 * may have been sent.
+	 */
+	if (path) {
+		ifcfg_mdv_wpa_network_set_str(wpan, objtype->ifcfg_key, path);
+		return TRUE;
+	}
+
+#if 0
+	/* If it's raw certificate data, write the cert data out to the standard file */
+	if (blob) {
+		gboolean success;
+		char *new_file;
+		GError *write_error = NULL;
+
+		new_file = utils_cert_path (ifcfg->fileName, objtype->suffix);
+		if (!new_file) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Could not create file path for %s / %s",
+			             NM_SETTING_802_1X_SETTING_NAME, objtype->setting_key);
+			return FALSE;
+		}
+
+		/* Write the raw certificate data out to the standard file so that we
+		 * can use paths from now on instead of pushing around the certificate
+		 * data itself.
+		 */
+		success = write_secret_file (new_file, (const char *) blob->data, blob->len, &write_error);
+		if (success) {
+			svSetValue (ifcfg, objtype->ifcfg_key, new_file, FALSE);
+			return TRUE;
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Could not write certificate/key for %s / %s: %s",
+			             NM_SETTING_802_1X_SETTING_NAME, objtype->setting_key,
+			             (write_error && write_error->message) ? write_error->message : "(unknown)");
+			g_clear_error (&write_error);
+		}
+		g_free (new_file);
+	}
+#endif
+
+	return FALSE;
+}
+
+static gboolean
+write_8021x_certs (NMSetting8021x *s_8021x,
+		   WPANetwork *wpan,
+                   gboolean phase2,
+                   shvarFile *ifcfg,
+                   GError **error)
+{
+	GByteArray *enc_key = NULL;
+	const char *password = NULL;
+	// char *generated_pw = NULL;
+	gboolean success = FALSE, is_pkcs12 = FALSE;
+	const ObjectType *otype = NULL;
+	const GByteArray *blob = NULL;
+
+	/* CA certificate */
+	if (phase2)
+		otype = &phase2_ca_type;
+	else
+		otype = &ca_type;
+
+	if (!write_object (s_8021x, wpan, ifcfg, 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 = 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 = nm_setting_802_1x_get_private_key_password (s_8021x);
+	}
+
+	if (is_pkcs12)
+		otype = phase2 ? &phase2_p12_type : &p12_type;
+	else
+		otype = phase2 ? &phase2_pk_type : &pk_type;
+
+	if ((*(otype->scheme_func))(s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "ifcfg-mdv does not support raw certificate data");
+		return FALSE;
+	//	blob = (*(otype->blob_func))(s_8021x);
+	}
+
+#if 0
+	/* 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) {
+		/* Encrypt the unencrypted private key with the fake password */
+		enc_key = nm_utils_rsa_key_encrypt (blob, password, &generated_pw, error);
+		if (!enc_key)
+			goto out;
+
+		if (generated_pw)
+			password = generated_pw;
+	}
+#endif
+
+	/* Save the private key */
+	if (!write_object (s_8021x, wpan, ifcfg, enc_key ? enc_key : blob, otype, error))
+		goto out;
+
+	/* Private key password */
+	/* FIXME what about hash:XXX? */
+	if (phase2)
+		ifcfg_mdv_wpa_network_set_str(wpan, "private_key2_passwd", password);
+	else
+		ifcfg_mdv_wpa_network_set_str(wpan, "private_key_passwd", password);
+
+	/* Client certificate */
+	if (is_pkcs12) {
+		ifcfg_mdv_wpa_network_unset(wpan,
+		            phase2 ? "client_cert2" : "client_cert");
+	} else {
+		if (phase2)
+			otype = &phase2_client_type;
+		else
+			otype = &client_type;
+
+		/* Save the client certificate */
+		if (!write_object (s_8021x, wpan, ifcfg, NULL, otype, error))
+			goto out;
+	}
+
+	success = TRUE;
+
+out:
+#if 0
+	if (generated_pw) {
+		memset (generated_pw, 0, strlen (generated_pw));
+		g_free (generated_pw);
+	}
+	if (enc_key) {
+		memset (enc_key->data, 0, enc_key->len);
+		g_byte_array_free (enc_key, TRUE);
+	}
+#endif
+	return success;
+}
+
+static gboolean
+write_8021x_setting (NMConnection *connection,
+		     WPANetwork *wpan,
+                     shvarFile *ifcfg,
+                     gboolean wired,
+                     GError **error)
+{
+	NMSetting8021x *s_8021x;
+	const char *value;
+	char *tmp = NULL;
+	gboolean success = FALSE;
+	GString *phase2_auth;
+	GString *str;
+
+	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	if (!s_8021x) {
+#if 0
+		/* No wired security in Mandriva */
+		/* If wired, clear KEY_MGMT */
+		if (wired)
+			svSetValue (ifcfg, "KEY_MGMT", NULL, FALSE);
+#endif
+		return TRUE;
+	}
+
+#if 0
+		/* No wired security in Mandriva */
+	/* If wired, write KEY_MGMT */
+	if (wired)
+		svSetValue (ifcfg, "KEY_MGMT", "IEEE8021X", FALSE);
+#endif
+
+	/* 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);
+	}
+	ifcfg_mdv_wpa_network_set_val(wpan, "eap", tmp ? tmp : NULL);
+	g_free (tmp);
+
+	ifcfg_mdv_wpa_network_set_str(wpan, "identity",
+	            nm_setting_802_1x_get_identity (s_8021x));
+
+	ifcfg_mdv_wpa_network_set_str(wpan, "anonymous_identity",
+	            nm_setting_802_1x_get_anonymous_identity (s_8021x));
+
+	ifcfg_mdv_wpa_network_set_str(wpan, "password", nm_setting_802_1x_get_password (s_8021x));
+
+	str = g_string_new("");
+
+	/* PEAP version */
+	value = nm_setting_802_1x_get_phase1_peapver (s_8021x);
+	if (value && (!strcmp (value, "0") || !strcmp (value, "1")))
+		g_string_printf(str, "peapver=%s", value);
+
+	/* Force new PEAP label */
+	value = nm_setting_802_1x_get_phase1_peaplabel (s_8021x);
+	if (value && !strcmp (value, "1")) {
+		if (str->len)
+			g_string_append_c(str, ' ');
+		g_string_printf(str, "peaplabel=%s", value);
+	}
+
+	if (str->len)
+		ifcfg_mdv_wpa_network_set_str(wpan, "phase1", str->str);
+	g_string_free(str, TRUE);
+
+	/* Phase2 auth methods */
+	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_printf (phase2_auth, "auth=%s", tmp);
+		g_free (tmp);
+	}
+
+	value = nm_setting_802_1x_get_phase2_autheap (s_8021x);
+	if (value) {
+		if (phase2_auth->len)
+			g_string_append_c (phase2_auth, ' ');
+
+		tmp = g_ascii_strup (value, -1);
+		g_string_append_printf (phase2_auth, "autheap=%s", tmp);
+		g_free (tmp);
+	}
+
+	if (phase2_auth->len)
+		ifcfg_mdv_wpa_network_set_str(wpan, "phase2", phase2_auth->str);
+	g_string_free (phase2_auth, TRUE);
+
+	success = write_8021x_certs (s_8021x, wpan, FALSE, ifcfg, error);
+	if (success) {
+		/* phase2/inner certs */
+		success = write_8021x_certs (s_8021x, wpan, TRUE, ifcfg, error);
+	}
+
+	return success;
+}
+
+static gboolean
+write_wireless_security_setting (NMConnection *connection,
+                                 shvarFile *ifcfg,
+				 WPANetwork *wpan,
+                                 gboolean adhoc,
+                                 gboolean *no_8021x,
+                                 GError **error)
+{
+	NMSettingWirelessSecurity *s_wsec;
+	const char *key_mgmt, *auth_alg, *key, *proto, *cipher;
+	gboolean wep = FALSE, wpa = FALSE;
+	char *tmp;
+	guint32 i, num;
+	GString *str;
+
+	s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+	if (!s_wsec) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "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);
+
+	// svSetValue (ifcfg, "DEFAULTKEY", NULL, FALSE);
+
+	if (!strcmp (key_mgmt, "none")) {
+		wep = TRUE;
+		*no_8021x = TRUE;
+	} else if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) {
+		ifcfg_mdv_wpa_network_set_val(wpan, "key_mgmt", "WPA-PSK");
+		wpa = TRUE;
+		*no_8021x = TRUE;
+	} else if (!strcmp (key_mgmt, "ieee8021x")) {
+		ifcfg_mdv_wpa_network_set_val(wpan, "key_mgmt", "IEEE8021X");
+	} else if (!strcmp (key_mgmt, "wpa-eap")) {
+		ifcfg_mdv_wpa_network_set_val(wpan, "key_mgmt", "WPA-EAP");
+		wpa = TRUE;
+	}
+
+	/* TODO add additional fields to private object to store extra
+	 * values during parsing configuration */
+	if (strcmp(key_mgmt, "none"))
+		ifcfg_mdv_wpa_network_set_val(wpan, "priority", "1");
+
+	svSetValue (ifcfg, "WIRELESS_ENC_MODE", NULL, FALSE);
+	if (auth_alg) {
+		if (!strcmp (auth_alg, "shared")) {
+			if (wep)
+				svSetValue (ifcfg, "WIRELESS_ENC_MODE", "restricted", FALSE);
+			ifcfg_mdv_wpa_network_set_val(wpan, "auth_alg", "SHARED");
+		} else if (!strcmp (auth_alg, "open")) {
+			if (wep)
+				svSetValue (ifcfg, "WIRELESS_ENC_MODE", "open", FALSE);
+			ifcfg_mdv_wpa_network_set_val(wpan, "auth_alg", "OPEN");
+		} else if (!strcmp (auth_alg, "leap")) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "ifcfg-mdv does not support LEAP authentication");
+			return FALSE;
+#if 0
+			/* Not used by Mandriva */
+			svSetValue (ifcfg, "WIRELESS_ENC_MODE", "leap", FALSE);
+			svSetValue (ifcfg, "IEEE_8021X_IDENTITY",
+			            nm_setting_wireless_security_get_leap_username (s_wsec),
+			            FALSE);
+				     "ifcfg-mdv does not support LEAP authentication");
+			set_secret (ifcfg, "IEEE_8021X_PASSWORD",
+			            nm_setting_wireless_security_get_leap_password (s_wsec),
+			            FALSE);
+			*no_8021x = TRUE;
+#endif
+		}
+	}
+
+	set_wep_secret (ifcfg, "WIRELESS_ENC_KEY", NULL, FALSE);
+	if (wep) {
+		/* Mandriva always sets key_idx == 0 and does not support passphrase */
+		if (nm_setting_wireless_security_get_wep_key_type (s_wsec) == NM_WEP_KEY_TYPE_PASSPHRASE) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				"ifcfg-mdv does not support WEP passphrase");
+			return FALSE;
+		}
+		key = nm_setting_wireless_security_get_wep_key (s_wsec, 0);
+		set_wep_secret (ifcfg, "WIRELESS_ENC_KEY", key, FALSE);
+#if 0
+		/* Default WEP TX key index */
+		tmp = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec) + 1);
+		svSetValue (ifcfg, "DEFAULTKEY", tmp, FALSE);
+		g_free (tmp);
+		for (i = 0; i < 4; i++) {
+			NMWepKeyType key_type;
+
+			key = nm_setting_wireless_security_get_wep_key (s_wsec, i);
+			if (key) {
+				char *ascii_key = NULL;
+
+				/* Passphrase needs a different ifcfg key since with WEP, there
+				 * are some passphrases that are indistinguishable from WEP hex
+				 * keys.
+				 */
+				key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec);
+				if (key_type == NM_WEP_KEY_TYPE_PASSPHRASE)
+					tmp = g_strdup_printf ("KEY_PASSPHRASE%d", i + 1);
+				else {
+					tmp = g_strdup_printf ("KEY%d", i + 1);
+
+					/* Add 's:' prefix for ASCII keys */
+					if (strlen (key) == 5 || strlen (key) == 13) {
+						ascii_key = g_strdup_printf ("s:%s", key);
+						key = ascii_key;
+					}
+				}
+
+				set_secret (ifcfg, tmp, key, FALSE);
+				g_free (tmp);
+				g_free (ascii_key);
+			}
+		}
+#endif
+	}
+
+	/* FIXME What about roaming mode? */
+	if (wep) {
+		/* remove WPA driver to indicate WEP mode */
+		svSetValue (ifcfg, "WIRELESS_WPA_DRIVER", NULL, FALSE);
+
+		/* remove network from wpa_suplicant.conf */
+		ifcfg_mdv_wpa_network_set_val(wpan, "__DELETE__", "yes");
+
+		return TRUE;
+	}
+
+	/* wpa_supplicant driver. NM always uses wext for wireless */
+	svSetValue (ifcfg, "WIRELESS_WPA_DRIVER", "wext", FALSE);
+
+	/* WPA protos */
+	str = g_string_new (NULL);
+	num = nm_setting_wireless_security_get_num_protos (s_wsec);
+	for (i = 0; i < num; i++) {
+		gchar *p = NULL;
+
+		proto = nm_setting_wireless_security_get_proto (s_wsec, i);
+		if (proto && !strcmp (proto, "wpa"))
+			p = "WPA";
+		else if (proto && !strcmp (proto, "rsn"))
+			p = "RSN";
+		if (p) {
+			if (i > 0)
+				g_string_append_c(str, ' ');
+			g_string_append(str, p);
+		}
+	}
+	if (strlen (str->str))
+		ifcfg_mdv_wpa_network_set_val(wpan, "proto", str->str);
+
+	/* WPA Pairwise ciphers */
+	g_string_set_size (str, 0);
+	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))
+		ifcfg_mdv_wpa_network_set_val(wpan, "pairwise", str->str);
+
+	/* WPA Group ciphers */
+	g_string_set_size (str, 0);
+	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))
+		ifcfg_mdv_wpa_network_set_val(wpan, "group", str->str);
+
+
+	/* WPA Passphrase */
+	if (wpa) {
+		const char *psk = nm_setting_wireless_security_get_psk(s_wsec);
+		if (psk) {
+			g_string_assign(str, psk);
+			if (str->len != 64) {
+				/* Quote the PSK since it's a passphrase */
+				g_string_prepend_c (str, '"');
+				g_string_append_c (str, '"');
+			}
+
+			ifcfg_mdv_wpa_network_set_val(wpan, "psk", str->str);
+		}
+	}
+	g_string_free (str, TRUE);
+
+	return TRUE;
+}
+
+static gboolean
+write_wireless_setting (NMConnection *connection,
+                        shvarFile *ifcfg,
+			WPANetwork *wpan,
+                        gboolean *no_8021x,
+                        GError **error)
+{
+	NMSettingWireless *s_wireless;
+	char *tmp = NULL;
+	const GByteArray *ssid, *device_mac, *cloned_mac, *bssid;
+	GByteArray *old_ssid = NULL;
+	const char *mode;
+	guint32 mtu, chan, i;
+	gboolean adhoc = FALSE;
+	gchar buf[33];
+
+	s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	if (!s_wireless) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
+		return FALSE;
+	}
+
+	svSetValue (ifcfg, "HWADDR", NULL, FALSE);
+	device_mac = nm_setting_wireless_get_mac_address (s_wireless);
+	if (device_mac) {
+		tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+		                       device_mac->data[0], device_mac->data[1], device_mac->data[2],
+		                       device_mac->data[3], device_mac->data[4], device_mac->data[5]);
+		svSetValue (ifcfg, "HWADDR", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	svSetValue (ifcfg, "MACADDR", NULL, FALSE);
+	cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
+	if (cloned_mac) {
+		tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+		                       cloned_mac->data[0], cloned_mac->data[1], cloned_mac->data[2],
+		                       cloned_mac->data[3], cloned_mac->data[4], cloned_mac->data[5]);
+		svSetValue (ifcfg, "MACADDR", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	svSetValue (ifcfg, "MTU", NULL, FALSE);
+	mtu = nm_setting_wireless_get_mtu (s_wireless);
+	if (mtu) {
+		tmp = g_strdup_printf ("%u", mtu);
+		svSetValue (ifcfg, "MTU", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	ssid = nm_setting_wireless_get_ssid (s_wireless);
+	if (!ssid) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
+		return FALSE;
+	}
+	if (!ssid->len || ssid->len > 32) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Invalid SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
+		return FALSE;
+	}
+
+	/*
+	 * Mandriva is using SSID as part of file name; check for characters
+	 * that cannot included */
+	for (i = 0; i < ssid->len; i++)
+		if (G_DIR_SEPARATOR == ssid->data[i] || ssid->data[i] == '\0') {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Invalid SSID in '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
+			return FALSE;
+		}
+
+	/*
+	 * If SID changed we have to remove it from wpa_supplicant.conf
+	 */
+	tmp = svGetValue(ifcfg, "WIRELESS_ESSID", TRUE);
+	if (!tmp) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		     "Missing WIRELESS_ESSID in '%s'", ifcfg->fileName);
+		return FALSE;
+	}
+	old_ssid = ifcfg_mdv_parse_ssid(tmp, error);
+	if (!old_ssid)
+		goto free;
+
+	if (ssid->len != old_ssid->len || !memcmp(ssid->data, old_ssid->data, ssid->len)) {
+		WPANetwork *del = ifcfg_mdv_wpa_network_new(NULL);
+
+		if (!del) {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: could not allocate WPANetwork to remove SSID '%s'",
+		             tmp);
+			goto free;
+		}
+
+		ifcfg_mdv_wpa_network_set_ssid(del, old_ssid);
+		ifcfg_mdv_wpa_network_set_val(del, "__DELETE__", "yes");
+		ifcfg_mdv_wpa_network_save(del, "/etc/wpa_supplicant.conf", error);
+		ifcfg_mdv_wpa_network_free(del);
+		if (*error) {
+			goto free;
+		}
+	}
+	g_free(tmp);
+	g_byte_array_free(old_ssid, TRUE);
+
+	/* we just verified that it does not contain '\0' and fits in buf */
+	memcpy(buf, ssid->data, ssid->len);
+	buf[ssid->len] = '\0';
+	tmp = svEscape(buf);
+	svSetValue (ifcfg, "WIRELESS_ESSID", tmp, TRUE);
+	g_free(tmp);
+	ifcfg_mdv_wpa_network_set_ssid(wpan, ssid);
+
+	mode = nm_setting_wireless_get_mode (s_wireless);
+	if (!mode || !strcmp (mode, "infrastructure")) {
+		svSetValue (ifcfg, "WIRELESS_MODE", "Managed", FALSE);
+	} else if (!strcmp (mode, "adhoc")) {
+		svSetValue (ifcfg, "WIRELESS_MODE", "Ad-Hoc", FALSE);
+		adhoc = TRUE;
+	} else {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Invalid mode '%s' in '%s' setting",
+		             mode, NM_SETTING_WIRELESS_SETTING_NAME);
+		return FALSE;
+	}
+
+	svSetValue (ifcfg, "WIRELESS_CHANNEL", NULL, FALSE);
+	chan = nm_setting_wireless_get_channel (s_wireless);
+	if (chan) {
+		tmp = g_strdup_printf ("%u", chan);
+		svSetValue (ifcfg, "WIRELESS_CHANNEL", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	if (nm_setting_wireless_get_security (s_wireless)) {
+		if (!write_wireless_security_setting (connection, ifcfg, wpan, adhoc, no_8021x, error))
+			return FALSE;
+	}
+
+	// svSetValue (ifcfg, "BSSID", NULL, FALSE);
+	bssid = nm_setting_wireless_get_bssid (s_wireless);
+	if (bssid) {
+		tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+				       bssid->data[0], bssid->data[1], bssid->data[2],
+				       bssid->data[3], bssid->data[4], bssid->data[5]);
+		ifcfg_mdv_wpa_network_set_val(wpan, "bssid", tmp);
+		// svSetValue (ifcfg, "BSSID", tmp, FALSE);
+		g_free (tmp);
+	}
+
+
+	// svSetValue (ifcfg, "TYPE", TYPE_WIRELESS, FALSE);
+
+	return TRUE;
+free:
+	g_free(tmp);
+	if (old_ssid)
+		g_byte_array_free(old_ssid, TRUE);
+
+	return FALSE;
+}
+
+static gboolean
+write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
+{
+	NMSettingWired *s_wired;
+	const GByteArray *device_mac, *cloned_mac;
+	char *tmp;
+	guint32 mtu;
+
+	s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+	if (!s_wired) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing '%s' setting", NM_SETTING_WIRED_SETTING_NAME);
+		return FALSE;
+	}
+
+	device_mac = nm_setting_wired_get_mac_address (s_wired);
+	if (device_mac) {
+		tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+		                       device_mac->data[0], device_mac->data[1], device_mac->data[2],
+		                       device_mac->data[3], device_mac->data[4], device_mac->data[5]);
+		svSetValue (ifcfg, "HWADDR", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
+	if (cloned_mac) {
+		tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+		                       cloned_mac->data[0], cloned_mac->data[1], cloned_mac->data[2],
+		                       cloned_mac->data[3], cloned_mac->data[4], cloned_mac->data[5]);
+		svSetValue (ifcfg, "MACADDR", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	svSetValue (ifcfg, "MTU", NULL, FALSE);
+	mtu = nm_setting_wired_get_mtu (s_wired);
+	if (mtu) {
+		tmp = g_strdup_printf ("%u", mtu);
+		svSetValue (ifcfg, "MTU", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	// svSetValue (ifcfg, "TYPE", TYPE_ETHERNET, FALSE);
+
+	return TRUE;
+}
+
+static void
+write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
+{
+	char *tmp;
+
+	svSetValue (ifcfg, "NAME", nm_setting_connection_get_id (s_con), FALSE);
+	svSetValue (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con), FALSE);
+	/* when converting from eralier ifcfg */
+	svSetValue (ifcfg, "_NM_ONBOOT", NULL, FALSE);
+	svSetValue (ifcfg, "ONBOOT",
+	            nm_setting_connection_get_autoconnect (s_con) ? "yes" : "no",
+	            FALSE);
+
+	svSetValue (ifcfg, "LAST_CONNECT", NULL, FALSE);
+	if (nm_setting_connection_get_timestamp (s_con)) {
+		tmp = g_strdup_printf ("%" G_GUINT64_FORMAT, nm_setting_connection_get_timestamp (s_con));
+		svSetValue (ifcfg, "LAST_CONNECT", tmp, FALSE);
+		g_free (tmp);
+	}
+}
+
+#if 0
+No route file on Mandriva
+static gboolean
+write_route_file_legacy (const char *filename, NMSettingIP4Config *s_ip4, GError **error)
+{
+	char dest[INET_ADDRSTRLEN];
+	char next_hop[INET_ADDRSTRLEN];
+	char **route_items;
+	char *route_contents;
+	NMIP4Route *route;
+	guint32 ip, prefix, metric;
+	guint32 i, num;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (filename != NULL, FALSE);
+	g_return_val_if_fail (s_ip4 != NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	num = nm_setting_ip4_config_get_num_routes (s_ip4);
+	if (num == 0) {
+		unlink (filename);
+		return TRUE;
+	}
+
+	route_items = g_malloc0 (sizeof (char*) * (num + 1));
+	for (i = 0; i < num; i++) {
+		route = nm_setting_ip4_config_get_route (s_ip4, i);
+
+		memset (dest, 0, sizeof (dest));
+		ip = nm_ip4_route_get_dest (route);
+		inet_ntop (AF_INET, (const void *) &ip, &dest[0], sizeof (dest));
+
+		prefix = nm_ip4_route_get_prefix (route);
+
+		memset (next_hop, 0, sizeof (next_hop));
+		ip = nm_ip4_route_get_next_hop (route);
+		inet_ntop (AF_INET, (const void *) &ip, &next_hop[0], sizeof (next_hop));
+
+		metric = nm_ip4_route_get_metric (route);
+
+		route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", dest, prefix, next_hop, metric);
+	}
+	route_items[num] = NULL;
+	route_contents = g_strjoinv (NULL, route_items);
+	g_strfreev (route_items);
+
+	if (!g_file_set_contents (filename, route_contents, -1, NULL)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Writing route file '%s' failed", filename);
+		goto error;
+	}
+
+	success = TRUE;
+
+error:
+	g_free (route_contents);
+
+	return success;
+}
+#endif
+
+static char *
+ip4_address_as_string (guint32 ip)
+{
+	char *ip_string;
+	struct in_addr tmp_addr;
+
+	tmp_addr.s_addr = ip;
+	ip_string = g_malloc0 (INET_ADDRSTRLEN + 1);
+	if (!inet_ntop (AF_INET, &tmp_addr, ip_string, INET_ADDRSTRLEN))
+	strcpy (ip_string, "(none)");
+	return ip_string;
+}
+
+static gboolean
+write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
+{
+	NMSettingIP4Config *s_ip4;
+	const char *value;
+	char *addr_key, *prefix_key, *netmask_key, *gw_key, /**metric_key,*/ *tmp;
+	// char *route_path = NULL;
+	guint32 i, num;
+	GString *searches;
+	gboolean success = FALSE;
+	gboolean fake_ip4 = FALSE;
+	const char *method = NULL;
+
+	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+	if (s_ip4)
+		method = nm_setting_ip4_config_get_method (s_ip4);
+
+	/* Missing IP4 setting is assumed to be DHCP */
+	if (!method)
+		method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+
+	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
+		/* IPv4 disabled, clear IPv4 related parameters */
+		svSetValue (ifcfg, "BOOTPROTO", NULL, FALSE);
+		for (i = 0; i < 254; i++) {
+			if (i == 0) {
+				addr_key = g_strdup ("IPADDR");
+				prefix_key = g_strdup ("PREFIX");
+				gw_key = g_strdup ("GATEWAY");
+			} else {
+				addr_key = g_strdup_printf ("IPADDR%d", i + 1);
+				prefix_key = g_strdup_printf ("PREFIX%d", i + 1);
+				gw_key = g_strdup_printf ("GATEWAY%d", i + 1);
+			}
+
+			svSetValue (ifcfg, addr_key, NULL, FALSE);
+			svSetValue (ifcfg, prefix_key, NULL, FALSE);
+			svSetValue (ifcfg, gw_key, NULL, FALSE);
+		}
+
+#if 0
+		/* no routes on Mandriva */
+		route_path = utils_get_route_path (ifcfg->fileName);
+		result = unlink (route_path);
+		g_free (route_path);
+#endif
+		return TRUE;
+	}
+
+	/* Temporarily create fake IP4 setting if missing; method set to DHCP above */
+	if (!s_ip4) {
+		s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+		fake_ip4 = TRUE;
+	}
+
+	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
+		svSetValue (ifcfg, "BOOTPROTO", "dhcp", FALSE);
+	else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
+		svSetValue (ifcfg, "BOOTPROTO", "static", FALSE);
+#if 0
+	else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
+		svSetValue (ifcfg, "BOOTPROTO", "autoip", FALSE);
+	else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED))
+		svSetValue (ifcfg, "BOOTPROTO", "shared", FALSE);
+#endif
+	else {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "ifcfg-mdv: unsupported activation method '%s'", value);
+		goto out;
+	}
+
+	num = nm_setting_ip4_config_get_num_addresses (s_ip4);
+	if (num > 1) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		     "ifcfg-mdv: multiple IPADDRs per interface are not supported");
+			goto out;
+	}
+	//for (i = 0; i < 254; i++) {
+	{
+		char buf[INET_ADDRSTRLEN + 1];
+		NMIP4Address *addr;
+		guint32 ip, netmask;
+
+		// if (i == 0) {
+			addr_key = g_strdup ("IPADDR");
+			prefix_key = g_strdup ("PREFIX");
+			netmask_key = g_strdup ("NETMASK");
+			gw_key = g_strdup ("GATEWAY");
+#if 0
+		} else {
+			addr_key = g_strdup_printf ("IPADDR%d", i + 1);
+			prefix_key = g_strdup_printf ("PREFIX%d", i + 1);
+			gw_key = g_strdup_printf ("GATEWAY%d", i + 1);
+		}
+#endif
+		/* Clean PREFIX in case it was present, otherwise it
+		 * will fool reader.c next time */
+		svSetValue (ifcfg, prefix_key, NULL, FALSE);
+
+		// if (i >= num) {
+		if (num == 0) {
+			svSetValue (ifcfg, addr_key, NULL, FALSE);
+			svSetValue (ifcfg, netmask_key, NULL, FALSE);
+			svSetValue (ifcfg, gw_key, NULL, FALSE);
+		} else {
+			addr = nm_setting_ip4_config_get_address (s_ip4, i);
+
+			memset (buf, 0, sizeof (buf));
+			ip = nm_ip4_address_get_address (addr);
+			inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
+			svSetValue (ifcfg, addr_key, &buf[0], FALSE);
+
+			netmask = nm_utils_ip4_prefix_to_netmask (nm_ip4_address_get_prefix (addr));
+			tmp = ip4_address_as_string(netmask);
+			svSetValue (ifcfg, netmask_key, tmp, FALSE);
+			g_free (tmp);
+
+			if (nm_ip4_address_get_gateway (addr)) {
+				memset (buf, 0, sizeof (buf));
+				ip = nm_ip4_address_get_gateway (addr);
+				inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
+				svSetValue (ifcfg, gw_key, &buf[0], FALSE);
+			} else
+				svSetValue (ifcfg, gw_key, NULL, FALSE);
+		}
+
+		g_free (addr_key);
+		g_free (prefix_key);
+		g_free (netmask_key);
+		g_free (gw_key);
+	}
+
+	num = nm_setting_ip4_config_get_num_dns (s_ip4);
+	if (num > 2) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		     "ifcfg-mdv: max two DNS servers per interface are supported");
+			goto out;
+	}
+	for (i = 0; i <= 2; i++) {
+		char buf[INET_ADDRSTRLEN + 1];
+		guint32 ip;
+
+		addr_key = g_strdup_printf ("DNS%d", i + 1);
+
+		if (i >= num)
+			svSetValue (ifcfg, addr_key, NULL, FALSE);
+		else {
+			ip = nm_setting_ip4_config_get_dns (s_ip4, i);
+
+			memset (buf, 0, sizeof (buf));
+			inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
+			svSetValue (ifcfg, addr_key, &buf[0], FALSE);
+		}
+		g_free (addr_key);
+	}
+
+	num = nm_setting_ip4_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_ip4_config_get_dns_search (s_ip4, i));
+		}
+		svSetValue (ifcfg, "DOMAIN", searches->str, FALSE);
+		g_string_free (searches, TRUE);
+	} else
+		svSetValue (ifcfg, "DOMAIN", NULL, FALSE);
+
+	/*
+	 * Mandriva supports DEFROUTE for PPP connections only, which are
+	 * currently not implemented by ifcfg-mdv
+	 */
+	if (nm_setting_ip4_config_get_never_default (s_ip4)){
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignoring unsupported setting DEFROUTE=no");
+	}
+#if 0
+	/* DEFROUTE; remember that it has the opposite meaning from never-default */
+	svSetValue (ifcfg, "DEFROUTE",
+	            nm_setting_ip4_config_get_never_default (s_ip4) ? "no" : "yes",
+	            FALSE);
+#endif
+
+	/* Mandriva does not support PEERROUTES at all */
+	svSetValue (ifcfg, "PEERDNS", NULL, FALSE);
+	// svSetValue (ifcfg, "PEERROUTES", NULL, FALSE);
+	svSetValue (ifcfg, "DHCP_HOSTNAME", NULL, FALSE);
+	// svSetValue (ifcfg, "DHCP_CLIENT_ID", NULL, FALSE);
+	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
+		svSetValue (ifcfg, "PEERDNS",
+		            nm_setting_ip4_config_get_ignore_auto_dns (s_ip4) ? "no" : "yes",
+		            FALSE);
+
+		if (nm_setting_ip4_config_get_ignore_auto_routes (s_ip4)) {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: ignoring unsupported setting PEERROUTESno");
+		}
+#if 0
+		svSetValue (ifcfg, "PEERROUTES",
+		            nm_setting_ip4_config_get_ignore_auto_routes (s_ip4) ? "no" : "yes",
+		            FALSE);
+#endif
+
+		value = nm_setting_ip4_config_get_dhcp_hostname (s_ip4);
+		if (value)
+			svSetValue (ifcfg, "DHCP_HOSTNAME", value, FALSE);
+
+		/* Mandriva does not support client ID */
+		value = nm_setting_ip4_config_get_dhcp_client_id (s_ip4);
+		if (value) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "ifcfg-mdv: DHCP_CLIENT_ID is not supported");
+				goto out;
+			// svSetValue (ifcfg, "DHCP_CLIENT_ID", value, FALSE);
+		}
+	}
+
+	svSetValue (ifcfg, "IPV4_FAILURE_FATAL",
+	            nm_setting_ip4_config_get_may_fail (s_ip4) ? "no" : "yes",
+	            FALSE);
+
+#if 0
+	No routes on Mandriva
+	/* Static routes - route-<name> file */
+	route_path = utils_get_route_path (ifcfg->fileName);
+	if (!route_path) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not get route file path for '%s'", ifcfg->fileName);
+		goto out;
+	}
+#endif
+
+	num = nm_setting_ip4_config_get_num_routes (s_ip4);
+	if (num > 0) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		     "ifcfg-mdv: static routes are not supported");
+			goto out;
+	}
+#if 0
+	if (utils_has_route_file_new_syntax (route_path)) {
+		shvarFile *routefile;
+
+		g_free (route_path);
+		routefile = utils_get_route_ifcfg (ifcfg->fileName, TRUE);
+		if (!routefile) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Could not create route file '%s'", routefile->fileName);
+			goto out;
+		}
+
+		num = nm_setting_ip4_config_get_num_routes (s_ip4);
+		for (i = 0; i < 256; i++) {
+			char buf[INET_ADDRSTRLEN];
+			NMIP4Route *route;
+			guint32 ip, metric;
+
+			addr_key = g_strdup_printf ("ADDRESS%d", i);
+			netmask_key = g_strdup_printf ("NETMASK%d", i);
+			gw_key = g_strdup_printf ("GATEWAY%d", i);
+			metric_key = g_strdup_printf ("METRIC%d", i);
+
+			if (i >= num) {
+				svSetValue (routefile, addr_key, NULL, FALSE);
+				svSetValue (routefile, netmask_key, NULL, FALSE);
+				svSetValue (routefile, gw_key, NULL, FALSE);
+				svSetValue (routefile, metric_key, NULL, FALSE);
+			} else {
+				route = nm_setting_ip4_config_get_route (s_ip4, i);
+
+				memset (buf, 0, sizeof (buf));
+				ip = nm_ip4_route_get_dest (route);
+				inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
+				svSetValue (routefile, addr_key, &buf[0], FALSE);
+
+				memset (buf, 0, sizeof (buf));
+				ip = nm_utils_ip4_prefix_to_netmask (nm_ip4_route_get_prefix (route));
+				inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
+				svSetValue (routefile, netmask_key, &buf[0], FALSE);
+
+				memset (buf, 0, sizeof (buf));
+				ip = nm_ip4_route_get_next_hop (route);
+				inet_ntop (AF_INET, (const void *) &ip, &buf[0], sizeof (buf));
+				svSetValue (routefile, gw_key, &buf[0], FALSE);
+
+				memset (buf, 0, sizeof (buf));
+				metric = nm_ip4_route_get_metric (route);
+				if (metric == 0)
+					svSetValue (routefile, metric_key, NULL, FALSE);
+				else {
+					tmp = g_strdup_printf ("%u", metric);
+					svSetValue (routefile, metric_key, tmp, FALSE);
+					g_free (tmp);
+				}
+			}
+
+			g_free (addr_key);
+			g_free (netmask_key);
+			g_free (gw_key);
+			g_free (metric_key);
+		}
+		if (svWriteFile (routefile, 0644)) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Could not update route file '%s'", routefile->fileName);
+			svCloseFile (routefile);
+			goto out;
+		}
+		svCloseFile (routefile);
+	} else {
+		write_route_file_legacy (route_path, s_ip4, error);
+		g_free (route_path);
+		if (error && *error)
+			goto out;
+	}
+#endif
+
+	success = TRUE;
+
+out:
+	if (fake_ip4)
+		g_object_unref (s_ip4);
+
+	return success;
+}
+
+#if 0
+No IPv6 on Mandriva
+static gboolean
+write_route6_file (const char *filename, NMSettingIP6Config *s_ip6, GError **error)
+{
+	char dest[INET6_ADDRSTRLEN];
+	char next_hop[INET6_ADDRSTRLEN];
+	char **route_items;
+	char *route_contents;
+	NMIP6Route *route;
+	const struct in6_addr *ip;
+	guint32 prefix, metric;
+	guint32 i, num;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (filename != NULL, FALSE);
+	g_return_val_if_fail (s_ip6 != NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	num = nm_setting_ip6_config_get_num_routes (s_ip6);
+	if (num == 0) {
+		unlink (filename);
+		return TRUE;
+	}
+
+	route_items = g_malloc0 (sizeof (char*) * (num + 1));
+	for (i = 0; i < num; i++) {
+		route = nm_setting_ip6_config_get_route (s_ip6, i);
+
+		memset (dest, 0, sizeof (dest));
+		ip = nm_ip6_route_get_dest (route);
+		inet_ntop (AF_INET6, (const void *) ip, &dest[0], sizeof (dest));
+
+		prefix = nm_ip6_route_get_prefix (route);
+
+		memset (next_hop, 0, sizeof (next_hop));
+		ip = nm_ip6_route_get_next_hop (route);
+		inet_ntop (AF_INET6, (const void *) ip, &next_hop[0], sizeof (next_hop));
+
+		metric = nm_ip6_route_get_metric (route);
+
+		route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", dest, prefix, next_hop, metric);
+	}
+	route_items[num] = NULL;
+	route_contents = g_strjoinv (NULL, route_items);
+	g_strfreev (route_items);
+
+	if (!g_file_set_contents (filename, route_contents, -1, NULL)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Writing route6 file '%s' failed", filename);
+		goto error;
+	}
+
+	success = TRUE;
+
+error:
+	g_free (route_contents);
+	return success;
+}
+#endif
+
+static gboolean
+write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
+{
+	NMSettingIP6Config *s_ip6;
+	// NMSettingIP4Config *s_ip4;
+	const char *value;
+#if 0
+	char *addr_key, *prefix;
+	guint32 i, num, num4;
+	GString *searches;
+	char buf[INET6_ADDRSTRLEN];
+	NMIP6Address *addr;
+	const struct in6_addr *ip;
+	GString *ip_str1, *ip_str2, *ip_ptr;
+	char *route6_path;
+#endif
+
+	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+	if (!s_ip6) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing '%s' setting", NM_SETTING_IP6_CONFIG_SETTING_NAME);
+		return FALSE;
+	}
+
+	value = nm_setting_ip6_config_get_method (s_ip6);
+	g_assert (value);
+	if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
+#if 0
+		svSetValue (ifcfg, "IPV6INIT", "no", FALSE);
+		svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
+#endif
+		return TRUE;
+#if 0
+	} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
+		svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
+		svSetValue (ifcfg, "IPV6_AUTOCONF", "yes", FALSE);
+		svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
+	} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
+		svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
+		svSetValue (ifcfg, "IPV6_AUTOCONF", "no", FALSE);
+		svSetValue (ifcfg, "DHCPV6C", "yes", FALSE);
+	} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+		svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
+		svSetValue (ifcfg, "IPV6_AUTOCONF", "no", FALSE);
+		svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
+	} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
+		svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
+		svSetValue (ifcfg, "IPV6_AUTOCONF", "no", FALSE);
+		svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
+	} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) {
+		svSetValue (ifcfg, "IPV6INIT", "yes", FALSE);
+		svSetValue (ifcfg, "DHCPV6C", NULL, FALSE);
+		/* TODO */
+#endif
+	}
+	g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		     "IPv6 settings not supported");
+	return FALSE;
+
+#if 0
+	if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+		/* Write out IP addresses */
+		num = nm_setting_ip6_config_get_num_addresses (s_ip6);
+
+		ip_str1 = g_string_new (NULL);
+		ip_str2 = g_string_new (NULL);
+		for (i = 0; i < num; i++) {
+			if (i == 0)
+				ip_ptr = ip_str1;
+			else
+				ip_ptr = ip_str2;
+
+			addr = nm_setting_ip6_config_get_address (s_ip6, i);
+			ip = nm_ip6_address_get_address (addr);
+			prefix = g_strdup_printf ("%u", nm_ip6_address_get_prefix (addr));
+			memset (buf, 0, sizeof (buf));
+			inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
+			if (i > 1)
+				g_string_append_c (ip_ptr, ' ');  /* separate addresses in IPV6ADDR_SECONDARIES */
+			g_string_append (ip_ptr, buf);
+			g_string_append_c (ip_ptr, '/');
+			g_string_append (ip_ptr, prefix);
+			g_free (prefix);
+		}
+
+		svSetValue (ifcfg, "IPV6ADDR", ip_str1->str, FALSE);
+		svSetValue (ifcfg, "IPV6ADDR_SECONDARIES", ip_str2->str, FALSE);
+		g_string_free (ip_str1, TRUE);
+		g_string_free (ip_str2, TRUE);
+	} else {
+		svSetValue (ifcfg, "IPV6ADDR", NULL, FALSE);
+		svSetValue (ifcfg, "IPV6ADDR_SECONDARIES", NULL, FALSE);
+	}
+
+	/* Write out DNS - 'DNS' key is used both for IPv4 and IPv6 */
+	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+	num4 = s_ip4 ? nm_setting_ip4_config_get_num_dns (s_ip4) : 0; /* from where to start with IPv6 entries */
+	num = nm_setting_ip6_config_get_num_dns (s_ip6);
+	for (i = 0; i < 254; i++) {
+		addr_key = g_strdup_printf ("DNS%d", i + num4 + 1);
+
+		if (i >= num)
+			svSetValue (ifcfg, addr_key, NULL, FALSE);
+		else {
+			ip = nm_setting_ip6_config_get_dns (s_ip6, i);
+
+			memset (buf, 0, sizeof (buf));
+			inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
+			svSetValue (ifcfg, addr_key, buf, FALSE);
+		}
+		g_free (addr_key);
+	}
+
+	/* Write out DNS domains - 'DOMAIN' key is shared for both IPv4 and IPv6 domains */
+	num = nm_setting_ip6_config_get_num_dns_searches (s_ip6);
+	if (num > 0) {
+		char *ip4_domains;
+		ip4_domains = svGetValue (ifcfg, "DOMAIN", FALSE);
+		searches = g_string_new (ip4_domains);
+		for (i = 0; i < num; i++) {
+			if (searches->len > 0)
+				g_string_append_c (searches, ' ');
+			g_string_append (searches, nm_setting_ip6_config_get_dns_search (s_ip6, i));
+		}
+		svSetValue (ifcfg, "DOMAIN", searches->str, FALSE);
+		g_string_free (searches, TRUE);
+		g_free (ip4_domains);
+	}
+
+	/* handle IPV6_DEFROUTE */
+	/* IPV6_DEFROUTE has the opposite meaning from 'never-default' */
+	if (nm_setting_ip6_config_get_never_default(s_ip6))
+		svSetValue (ifcfg, "IPV6_DEFROUTE", "no", FALSE);
+	else
+		svSetValue (ifcfg, "IPV6_DEFROUTE", "yes", FALSE);
+
+	svSetValue (ifcfg, "IPV6_PEERDNS", NULL, FALSE);
+	svSetValue (ifcfg, "IPV6_PEERROUTES", NULL, FALSE);
+	if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
+		svSetValue (ifcfg, "IPV6_PEERDNS",
+		            nm_setting_ip6_config_get_ignore_auto_dns (s_ip6) ? "no" : "yes",
+		            FALSE);
+
+		svSetValue (ifcfg, "IPV6_PEERROUTES",
+		            nm_setting_ip6_config_get_ignore_auto_routes (s_ip6) ? "no" : "yes",
+		            FALSE);
+	}
+
+	svSetValue (ifcfg, "IPV6_FAILURE_FATAL",
+	            nm_setting_ip6_config_get_may_fail (s_ip6) ? "no" : "yes",
+	            FALSE);
+
+	/* Static routes go to route6-<dev> file */
+	route6_path = utils_get_route6_path (ifcfg->fileName);
+	if (!route6_path) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Could not get route6 file path for '%s'", ifcfg->fileName);
+		goto error;
+	}
+	write_route6_file (route6_path, s_ip6, error);
+	g_free (route6_path);
+	if (error && *error)
+		goto error;
+
+	return TRUE;
+
+error:
+	return FALSE;
+#endif
+}
+
+static char *
+escape_id (const char *id)
+{
+	char *escaped = g_strdup (id);
+	char *p = escaped;
+
+	/* Escape random stuff */
+	while (*p) {
+		if (*p == ' ')
+			*p = '_';
+		else if (*p == '/')
+			*p = '-';
+		else if (*p == '\\')
+			*p = '-';
+		p++;
+	}
+
+	return escaped;
+}
+
+static gboolean
+write_connection (NMConnection *connection,
+                  const char *ifcfg_dir,
+                  const char *filename,
+                  const char *keyfile,
+                  char **out_filename,
+                  GError **error)
+{
+	NMSettingConnection *s_con;
+	NMSettingIP6Config *s_ip6;
+	gboolean success = FALSE;
+	shvarFile *ifcfg = NULL;
+	char *ifcfg_name = NULL;
+	const char *type;
+	gboolean no_8021x = FALSE;
+	gboolean wired = FALSE;
+	WPANetwork *wpan = NULL;
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	if (!s_con) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing '%s' setting", NM_SETTING_CONNECTION_SETTING_NAME);
+		return FALSE;
+	}
+
+	if (filename) {
+		/* For existing connections, 'filename' should be full path to ifcfg file */
+		ifcfg = svNewFile (filename);
+		ifcfg_name = g_strdup (filename);
+	} else {
+		char *escaped;
+
+		escaped = escape_id (nm_setting_connection_get_id (s_con));
+		ifcfg_name = g_strdup_printf ("%s/ifcfg-%s", ifcfg_dir, escaped);
+		ifcfg = svCreateFile (ifcfg_name);
+		g_free (escaped);
+	}
+
+	if (!ifcfg) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to open/create ifcfg file '%s'", ifcfg_name);
+		goto out;
+	}
+
+	type = nm_setting_connection_get_connection_type (s_con);
+	if (!type) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing connection type!");
+		goto out;
+	}
+
+	/* Indicate that NM will manage this connection */
+	svSetValue (ifcfg, "NM_CONTROLLED", "yes", FALSE);
+
+	if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) {
+		// FIXME: can't write PPPoE at this time
+		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE)) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Can't write connection type '%s'",
+			             NM_SETTING_PPPOE_SETTING_NAME);
+			goto out;
+		}
+
+		if (!write_wired_setting (connection, ifcfg, error))
+			goto out;
+		wired = TRUE;
+	} else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) {
+		wpan = ifcfg_mdv_wpa_network_new(NULL);
+		if (!wpan) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				     "Unable to allocate WPA network");
+			goto out;
+		}
+
+		if (!write_wireless_setting (connection, ifcfg, wpan, &no_8021x, error))
+			goto out;
+	} else {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Can't write connection type '%s'", type);
+		goto out;
+	}
+
+	if (!no_8021x) {
+		if (!write_8021x_setting (connection, wpan, ifcfg, wired, error))
+			goto out;
+	}
+
+	if (!write_ip4_setting (connection, ifcfg, error))
+		goto out;
+
+	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+	if (s_ip6) {
+		if (!write_ip6_setting (connection, ifcfg, error))
+			goto out;
+	}
+
+	write_connection_setting (s_con, ifcfg);
+
+	if (svWriteFile (ifcfg, 0600)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Can't write connection '%s'", ifcfg->fileName);
+		goto out;
+	}
+	if (wpan)
+		if (!ifcfg_mdv_wpa_network_save(wpan, "/etc/wpa_supplicant.conf", error)) {
+		goto out;
+		}
+
+
+	/* Only return the filename if this was a newly written ifcfg */
+	if (out_filename && !filename)
+		*out_filename = g_strdup (ifcfg_name);
+
+	success = TRUE;
+
+out:
+	if (ifcfg)
+		svCloseFile (ifcfg);
+	g_free (ifcfg_name);
+	ifcfg_mdv_wpa_network_free(wpan);
+	return success;
+}
+
+gboolean
+writer_new_connection (NMConnection *connection,
+                       const char *ifcfg_dir,
+                       char **out_filename,
+                       GError **error)
+{
+	// return write_connection (connection, ifcfg_dir, NULL, NULL, out_filename, error);
+	/* For now, disable creation of system connection on Mandriva */
+	g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+	     "Creation of system connection not yet implemented in ifcfg-mdv");
+	return FALSE;
+}
+
+gboolean
+writer_update_connection (NMConnection *connection,
+                          const char *ifcfg_dir,
+                          const char *filename,
+                          const char *keyfile,
+                          GError **error)
+{
+	/* Temporary disable updating of roaming connection */
+	if (mdv_get_ifcfg_type(filename) != MdvIfcfgTypeInterface) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Not yet implemented");
+		return FALSE;
+	}
+	return write_connection (connection, ifcfg_dir, filename, keyfile, NULL, error);
+}
+
diff --git a/system-settings/plugins/ifcfg-mdv/writer.h b/system-settings/plugins/ifcfg-mdv/writer.h
new file mode 100644
index 0000000..edeac0c
--- /dev/null
+++ b/system-settings/plugins/ifcfg-mdv/writer.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service - keyfile plugin
+ *
+ * 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) 2009 Red Hat, Inc.
+ */
+
+#ifndef _WRITER_H_
+#define _WRITER_H_
+
+#include <sys/types.h>
+#include <glib.h>
+#include <nm-connection.h>
+
+gboolean writer_new_connection (NMConnection *connection,
+                                const char *ifcfg_dir,
+                                char **out_filename,
+                                GError **error);
+
+gboolean writer_update_connection (NMConnection *connection,
+                                   const char *ifcfg_dir,
+                                   const char *filename,
+                                   const char *keyfile,
+                                   GError **error);
+
+#endif /* _WRITER_H_ */