summary refs log tree commit diff
path: root/src/settings/plugins/ifcfg-rh/reader.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2012-03-24 01:37:02 +0100
committerMichael Biebl <biebl@debian.org>2012-03-24 01:37:02 +0100
commitde06e5715e780baade318f3490ac7a4c9ce84e32 (patch)
tree23fbc3fafc12072476eff98bee60100eb54c29db /src/settings/plugins/ifcfg-rh/reader.c
parentb436a68a20ff3114ded32a7a3d70cdd4954039f9 (diff)
Imported Upstream version 0.9.4.0 upstream/0.9.4.0
Diffstat (limited to 'src/settings/plugins/ifcfg-rh/reader.c')
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c834
1 files changed, 699 insertions, 135 deletions
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index 910cca35..01d83c1b 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -15,7 +15,7 @@
  * 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 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <config.h>
@@ -33,25 +33,22 @@
 #include <netinet/ether.h>
 #include <linux/if.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-vlan.h>
 #include <nm-setting-ip6-config.h>
 #include <nm-setting-wired.h>
 #include <nm-setting-wireless.h>
 #include <nm-setting-8021x.h>
+#include <nm-setting-bond.h>
 #include <nm-utils.h>
 
+#include "wifi-utils.h"
+
 #include "common.h"
 #include "shvar.h"
 #include "utils.h"
@@ -77,16 +74,46 @@ get_int (const char *str, int *value)
 	return TRUE;
 }
 
+static char *
+make_connection_name (shvarFile *ifcfg,
+                      const char *ifcfg_name,
+                      const char *suggested,
+                      const char *prefix)
+{
+	char *full_name = NULL, *name;
+
+	/* If the ifcfg file already has a NAME, always use that */
+	name = svGetValue (ifcfg, "NAME", FALSE);
+	if (name && strlen (name))
+		return name;
+
+	/* Otherwise construct a new NAME */
+	g_free (name);
+	if (!prefix)
+		prefix = _("System");
+
+	/* 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 (suggested && strcmp (ifcfg_name, suggested))
+		full_name = g_strdup_printf ("%s %s (%s)", prefix, suggested, ifcfg_name);
+	else
+		full_name = g_strdup_printf ("%s %s", prefix, ifcfg_name);
+
+	return full_name;
+}
+
 static NMSetting *
 make_connection_setting (const char *file,
                          shvarFile *ifcfg,
                          const char *type,
-                         const char *suggested)
+                         const char *suggested,
+                         const char *prefix)
 {
 	NMSettingConnection *s_con;
 	const char *ifcfg_name = NULL;
-	char *new_id = NULL, *uuid = NULL, *value;
-	char *ifcfg_id;
+	char *new_id, *uuid = NULL, *zone = NULL, *value;
 
 	ifcfg_name = utils_get_ifcfg_name (file, TRUE);
 	if (!ifcfg_name)
@@ -94,32 +121,9 @@ make_connection_setting (const char *file,
 
 	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);
-		}
-	}
-
+	new_id = make_connection_name (ifcfg, ifcfg_name, suggested, prefix);
+	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);
@@ -127,6 +131,7 @@ make_connection_setting (const char *file,
 		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,
@@ -153,14 +158,23 @@ make_connection_setting (const char *file,
 		g_strfreev (items);
 	}
 
+
+	zone = svGetValue(ifcfg, "ZONE", FALSE);
+	if (!zone || !strlen (zone)) {
+		g_free (zone);
+		zone = NULL;
+	}
+	g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL);
+	g_free (zone);
+
 	return NM_SETTING (s_con);
 }
 
 static gboolean
-read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError **error)
+read_mac_address (shvarFile *ifcfg, const char *key, int type,
+                  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);
@@ -174,8 +188,8 @@ read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError
 		return TRUE;
 	}
 
-	mac = ether_aton (value);
-	if (!mac) {
+	*array = nm_utils_hwaddr_atoba (value, type);
+	if (!*array) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "%s: the MAC address '%s' was invalid.", key, value);
 		g_free (value);
@@ -183,8 +197,6 @@ read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError
 	}
 
 	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;
 }
 
@@ -266,7 +278,7 @@ fill_ip4_setting_from_ibft (shvarFile *ifcfg,
 		goto done;
 	}
 
-	if (!read_mac_address (ifcfg, "HWADDR", &ifcfg_mac, error))
+	if (!read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &ifcfg_mac, error))
 		goto done;
 	/* Ensure we got a MAC */
 	if (!ifcfg_mac) {
@@ -627,7 +639,6 @@ read_one_ip4_route (shvarFile *ifcfg,
 
 	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 ();
 
@@ -1115,7 +1126,7 @@ static NMSetting *
 make_ip4_setting (shvarFile *ifcfg,
                   const char *network_file,
                   const char *iscsiadm_path,
-                  gboolean valid_ip6_config,
+                  gboolean can_disable_ip4,
                   GError **error)
 {
 	NMSettingIP4Config *s_ip4 = NULL;
@@ -1230,7 +1241,7 @@ make_ip4_setting (shvarFile *ifcfg,
 		    && !tmp_ip4_0 && !tmp_prefix_0 && !tmp_netmask_0
 		    && !tmp_ip4_1 && !tmp_prefix_1 && !tmp_netmask_1
 		    && !tmp_ip4_2 && !tmp_prefix_2 && !tmp_netmask_2) {
-			if (valid_ip6_config)
+			if (can_disable_ip4)
 				/* Nope, no IPv4 */
 				method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
 			else
@@ -1255,7 +1266,7 @@ make_ip4_setting (shvarFile *ifcfg,
 	              NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "PEERDNS", TRUE),
 	              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),
+	              NM_SETTING_IP4_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", FALSE),
 	              NULL);
 
 	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
@@ -1424,6 +1435,9 @@ make_ip6_setting (shvarFile *ifcfg,
 	guint32 i;
 	shvarFile *network_ifcfg;
 	gboolean never_default = FALSE, tmp_success;
+	gboolean ip6_privacy, ip6_privacy_prefer_public_ip;
+	char *ip6_privacy_str;
+	NMSettingIP6ConfigPrivacy ip6_privacy_val;
 
 	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
 	if (!s_ip6) {
@@ -1510,12 +1524,29 @@ make_ip6_setting (shvarFile *ifcfg,
 	}
 	/* TODO - handle other methods */
 
+	/* Read IPv6 Privacy Extensions configuration */
+	ip6_privacy_str = svGetValue (ifcfg, "IPV6_PRIVACY", FALSE);
+	if (ip6_privacy_str) {
+		ip6_privacy = svTrueValue (ifcfg, "IPV6_PRIVACY", FALSE);
+		if (!ip6_privacy)
+			ip6_privacy = g_strcmp0 (ip6_privacy_str, "rfc4941") == 0 ||
+			              g_strcmp0 (ip6_privacy_str, "rfc3041") == 0;
+	}
+	ip6_privacy_prefer_public_ip = svTrueValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE);
+	ip6_privacy_val = ip6_privacy_str ?
+	                      (ip6_privacy ?
+	                          (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) :
+	                          NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) :
+	                      NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
+	g_free (ip6_privacy_str);
+
 	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),
+	              NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val,
 	              NULL);
 
 	/* Don't bother to read IP, DNS and routes when IPv6 is disabled */
@@ -1926,6 +1957,7 @@ parse_wpa_psk (shvarFile *ifcfg,
 {
 	shvarFile *keys_ifcfg;
 	char *psk = NULL, *p, *hashed = NULL;
+	size_t plen;
 	gboolean quoted = FALSE;
 
 	/* Passphrase must be between 10 and 66 characters in length because WPA
@@ -1949,8 +1981,10 @@ parse_wpa_psk (shvarFile *ifcfg,
 		return NULL;
 
 	p = psk;
+	plen = strlen (p);
 
-	if (p[0] == '"' && psk[strlen (psk) - 1] == '"')
+	if (   (plen >= 2 && (p[0] == '"' || p[0] == '\'') && p[0] == p[plen - 1])
+	    || (plen >= 3 && p[0] == '$' && p[1] == '\'' && p[1] == p[plen - 1]))
 		quoted = TRUE;
 
 	if (!quoted && (strlen (psk) == 64)) {
@@ -1970,21 +2004,18 @@ parse_wpa_psk (shvarFile *ifcfg,
 		 * and between 8 and 63 characters as a passphrase.
 		 */
 
-		if (quoted) {
-			/* Get rid of the quotes */
-			p++;
-			p[strlen (p) - 1] = '\0';
-		}
+		/* Get rid of the quotes */
+		hashed = utils_single_unquote_string (p);
 
 		/* Length check */
-		if (strlen (p) < 8 || strlen (p) > 63) {
+		if (strlen (hashed) < 8 || strlen (hashed) > 63) {
 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 			             "Invalid WPA_PSK (passphrases must be between "
 			             "8 and 63 characters long (inclusive))");
+			g_free (hashed);
+			hashed = NULL;
 			goto out;
 		}
-
-		hashed = g_strdup (p);
 	}
 
 	if (!hashed) {
@@ -2045,18 +2076,18 @@ eap_simple_reader (const char *eap_method,
 }
 
 static char *
-get_cert_file (const char *ifcfg_path, const char *cert_path)
+get_full_file_path (const char *ifcfg_path, const char *file_path)
 {
-	const char *base = cert_path;
+	const char *base = file_path;
 	char *p, *ret, *dirname;
 
 	g_return_val_if_fail (ifcfg_path != NULL, NULL);
-	g_return_val_if_fail (cert_path != NULL, NULL);
+	g_return_val_if_fail (file_path != NULL, NULL);
 
-	if (cert_path[0] == '/')
-		return g_strdup (cert_path);
+	if (file_path[0] == '/')
+		return g_strdup (file_path);
 
-	p = strrchr (cert_path, '/');
+	p = strrchr (file_path, '/');
 	if (p)
 		base = p + 1;
 
@@ -2102,7 +2133,7 @@ eap_tls_reader (const char *eap_method,
 
 	ca_cert = svGetValue (ifcfg, ca_cert_key, FALSE);
 	if (ca_cert) {
-		real_path = get_cert_file (ifcfg->fileName, ca_cert);
+		real_path = get_full_file_path (ifcfg->fileName, ca_cert);
 		if (phase2) {
 			if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
 			                                           real_path,
@@ -2159,7 +2190,7 @@ eap_tls_reader (const char *eap_method,
 		goto done;
 	}
 
-	real_path = get_cert_file (ifcfg->fileName, privkey);
+	real_path = get_full_file_path (ifcfg->fileName, privkey);
 	if (phase2) {
 		if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
 		                                               real_path,
@@ -2196,7 +2227,7 @@ eap_tls_reader (const char *eap_method,
 			goto done;
 		}
 
-		real_path = get_cert_file (ifcfg->fileName, client_cert);
+		real_path = get_full_file_path (ifcfg->fileName, client_cert);
 		if (phase2) {
 			if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
 			                                               real_path,
@@ -2246,7 +2277,7 @@ eap_peap_reader (const char *eap_method,
 
 	ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
 	if (ca_cert) {
-		real_cert_path = get_cert_file (ifcfg->fileName, ca_cert);
+		real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
 		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
 		                                    real_cert_path,
 		                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
@@ -2352,7 +2383,7 @@ eap_ttls_reader (const char *eap_method,
 
 	ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
 	if (ca_cert) {
-		real_cert_path = get_cert_file (ifcfg->fileName, ca_cert);
+		real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
 		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
 		                                    real_cert_path,
 		                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
@@ -2422,6 +2453,111 @@ done:
 	return success;
 }
 
+static gboolean
+eap_fast_reader (const char *eap_method,
+                 shvarFile *ifcfg,
+                 shvarFile *keys,
+                 NMSetting8021x *s_8021x,
+                 gboolean phase2,
+                 GError **error)
+{
+	char *anon_ident = NULL;
+	char *pac_file = NULL;
+	char *real_pac_path = NULL;
+	char *inner_auth = NULL;
+	char *fast_provisioning = NULL;
+	char *lower;
+	char **list = NULL, **iter;
+	const char* pac_prov_str;
+	gboolean allow_unauth = FALSE, allow_auth = FALSE;
+	gboolean success = FALSE;
+
+	pac_file = svGetValue (ifcfg, "IEEE_8021X_PAC_FILE", FALSE);
+	if (pac_file) {
+		real_pac_path = get_full_file_path (ifcfg->fileName, pac_file);
+		g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL);
+	}
+
+	fast_provisioning = svGetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", FALSE);
+	if (fast_provisioning) {
+		list = g_strsplit_set (fast_provisioning, " \t", 0);
+		for (iter = list; iter && *iter; iter++) {
+			if (**iter == '\0')
+				continue;
+			if (strcmp (*iter, "allow-unauth") == 0)
+				allow_unauth = TRUE;
+			else if (strcmp (*iter, "allow-auth") == 0)
+				allow_auth = TRUE;
+			else {
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid IEEE_8021X_FAST_PROVISIONING '%s' "
+				             "(space-separated list of these values [allow-auth, allow-unauth] expected)",
+				             *iter);
+			}
+		}
+		g_strfreev (list);
+		list = NULL;
+	}
+	pac_prov_str = allow_unauth ? (allow_auth ? "3" : "1") : (allow_auth ? "2" : "0");
+	g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, pac_prov_str, NULL);
+
+	if (!pac_file && !(allow_unauth || allow_auth)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled.");
+		goto done;
+	}
+
+	anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
+	if (anon_ident && strlen (anon_ident))
+		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
+
+	inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
+	if (!inner_auth) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
+		goto done;
+	}
+
+	/* Handle options for the inner auth method */
+	list = g_strsplit (inner_auth, " ", 0);
+	for (iter = list; iter && *iter; iter++) {
+		if (!strlen (*iter))
+			continue;
+
+		if (   !strcmp (*iter, "MSCHAPV2")
+		    || !strcmp (*iter, "GTC")) {
+			if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
+				goto done;
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
+			             *iter);
+			goto done;
+		}
+
+		lower = g_ascii_strdown (*iter, -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 IEEE_8021X_INNER_AUTH_METHODS found.");
+		goto done;
+	}
+
+	success = TRUE;
+
+done:
+	g_strfreev (list);
+	g_free (inner_auth);
+	g_free (fast_provisioning);
+	g_free (real_pac_path);
+	g_free (pac_file);
+	g_free (anon_ident);
+	return success;
+}
+
 typedef struct {
 	const char *method;
 	gboolean (*reader)(const char *eap_method,
@@ -2443,6 +2579,7 @@ static EAPReader eap_readers[] = {
 	{ "tls", eap_tls_reader, FALSE },
 	{ "peap", eap_peap_reader, FALSE },
 	{ "ttls", eap_ttls_reader, FALSE },
+	{ "fast", eap_fast_reader, FALSE },
 	{ NULL, NULL }
 };
 
@@ -2749,7 +2886,7 @@ make_wireless_setting (shvarFile *ifcfg,
 
 	s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
 
-	if (read_mac_address (ifcfg, "HWADDR", &array, error)) {
+	if (read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &array, error)) {
 		if (array) {
 			g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, array, NULL);
 
@@ -2773,7 +2910,7 @@ make_wireless_setting (shvarFile *ifcfg,
 	}
 
 	array = NULL;
-	if (read_mac_address (ifcfg, "MACADDR", &array, error)) {
+	if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &array, error)) {
 		if (array) {
 			g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, array, NULL);
 			g_byte_array_free (array, TRUE);
@@ -2901,19 +3038,16 @@ make_wireless_setting (shvarFile *ifcfg,
 
 	value = svGetValue (ifcfg, "BSSID", FALSE);
 	if (value) {
-		struct ether_addr *eth;
 		GByteArray *bssid;
 
-		eth = ether_aton (value);
-		if (!eth) {
+		bssid = nm_utils_hwaddr_atoba (value, ARPHRD_ETHER);
+		if (!bssid) {
 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 			             "Invalid BSSID '%s'", value);
 			g_free (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);
 		g_free (value);
@@ -3032,7 +3166,7 @@ wireless_connection_from_ifcfg (const char *file,
 	/* Connection */
 	con_setting = make_connection_setting (file, ifcfg,
 	                                       NM_SETTING_WIRELESS_SETTING_NAME,
-	                                       printable_ssid);
+	                                       printable_ssid, NULL);
 	g_free (printable_ssid);
 	if (!con_setting) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
@@ -3082,7 +3216,7 @@ make_wired_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	if (read_mac_address (ifcfg, "HWADDR", &mac, error)) {
+	if (read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &mac, error)) {
 		if (mac) {
 			g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
 
@@ -3193,7 +3327,7 @@ make_wired_setting (shvarFile *ifcfg,
 	}
 
 	mac = NULL;
-	if (read_mac_address (ifcfg, "MACADDR", &mac, error)) {
+	if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &mac, error)) {
 		if (mac) {
 			g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, mac, NULL);
 			g_byte_array_free (mac, TRUE);
@@ -3260,6 +3394,7 @@ wired_connection_from_ifcfg (const char *file,
 	NMSetting *con_setting = NULL;
 	NMSetting *wired_setting = NULL;
 	NMSetting8021x *s_8021x = NULL;
+	char *value;
 
 	g_return_val_if_fail (file != NULL, NULL);
 	g_return_val_if_fail (ifcfg != NULL, NULL);
@@ -3271,7 +3406,7 @@ wired_connection_from_ifcfg (const char *file,
 		return NULL;
 	}
 
-	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL);
+	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL, NULL);
 	if (!con_setting) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "Failed to create connection setting.");
@@ -3280,6 +3415,238 @@ wired_connection_from_ifcfg (const char *file,
 	}
 	nm_connection_add_setting (connection, con_setting);
 
+	/* Might be a bond slave; handle master device or connection */
+	value = svGetValue (ifcfg, "MASTER", FALSE);
+	if (value) {
+		g_object_set (con_setting, NM_SETTING_CONNECTION_MASTER, value, NULL);
+		g_object_set (con_setting,
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
+		              NULL);
+		g_free (value);
+	}
+
+	wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
+	if (!wired_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, wired_setting);
+
+	if (s_8021x)
+		nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+	if (!nm_connection_verify (connection, error)) {
+		g_object_unref (connection);
+		return NULL;
+	}
+
+	return connection;
+}
+
+static NMSetting *
+make_infiniband_setting (shvarFile *ifcfg,
+                         const char *file,
+                         gboolean nm_controlled,
+                         char **unmanaged,
+                         GError **error)
+{
+	NMSettingInfiniband *s_infiniband;
+	char *value = NULL;
+	GByteArray *mac = NULL;
+	int mtu;
+
+	s_infiniband = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ());
+
+	value = svGetValue (ifcfg, "MTU", FALSE);
+	if (value) {
+		if (get_int (value, &mtu)) {
+			if (mtu >= 0 && mtu < 65536)
+				g_object_set (s_infiniband, NM_SETTING_INFINIBAND_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", ARPHRD_INFINIBAND, &mac, error)) {
+		if (mac) {
+			g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL);
+
+			/* A connection can only be unmanaged if we know the MAC address */
+			if (!nm_controlled) {
+				char *mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_INFINIBAND);
+				*unmanaged = g_strdup_printf ("mac:%s", mac_str);
+				g_free (mac_str);
+			}
+
+			g_byte_array_free (mac, TRUE);
+		}
+	} else {
+		g_object_unref (s_infiniband);
+		return NULL;
+	}
+
+	if (svTrueValue (ifcfg, "CONNECTED_MODE", FALSE))
+		g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL);
+	else
+		g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);
+
+	if (!nm_controlled && !*unmanaged) {
+		/* 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");
+	}
+
+	return (NMSetting *) s_infiniband;
+}
+
+static NMConnection *
+infiniband_connection_from_ifcfg (const char *file,
+                                  shvarFile *ifcfg,
+                                  gboolean nm_controlled,
+                                  char **unmanaged,
+                                  GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *infiniband_setting = 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_INFINIBAND_SETTING_NAME, NULL, 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);
+
+	infiniband_setting = make_infiniband_setting (ifcfg, file, nm_controlled, unmanaged, error);
+	if (!infiniband_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, infiniband_setting);
+
+	if (!nm_connection_verify (connection, error)) {
+		g_object_unref (connection);
+		return NULL;
+	}
+
+	return connection;
+}
+
+static void
+handle_bond_option (NMSettingBond *s_bond,
+                    const char *key,
+                    const char *value)
+{
+	if (!nm_setting_bond_add_option (s_bond, key, value))
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid bonding option '%s'", key);
+}
+
+static NMSetting *
+make_bond_setting (shvarFile *ifcfg,
+                   const char *file,
+                   gboolean nm_controlled,
+                   char **unmanaged,
+                   GError **error)
+{
+	NMSettingBond *s_bond;
+	char *value;
+
+	s_bond = NM_SETTING_BOND (nm_setting_bond_new ());
+
+	value = svGetValue (ifcfg, "DEVICE", FALSE);
+	if (!value || !strlen (value)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "mandatory DEVICE keyword missing");
+		goto error;
+	}
+
+	g_object_set (s_bond, NM_SETTING_BOND_INTERFACE_NAME, value, NULL);
+	g_free (value);
+
+	value = svGetValue (ifcfg, "BONDING_OPTS", FALSE);
+	if (value) {
+		char **items, **iter;
+
+		items = g_strsplit_set (value, " ", -1);
+		for (iter = items; iter && *iter; iter++) {
+			if (strlen (*iter)) {
+				char **keys, *key, *val;
+
+				keys = g_strsplit_set (*iter, "=", 2);
+				if (keys && *keys) {
+					key = *keys;
+					val = *(keys + 1);
+					if (val && strlen(key) && strlen(val))
+						handle_bond_option (s_bond, key, val);
+				}
+
+				g_strfreev (keys);
+			}
+		}
+		g_free (value);
+		g_strfreev (items);
+	}
+
+	return (NMSetting *) s_bond;
+
+error:
+	g_object_unref (s_bond);
+	return NULL;
+}
+
+static NMConnection *
+bond_connection_from_ifcfg (const char *file,
+                            shvarFile *ifcfg,
+                            gboolean nm_controlled,
+                            char **unmanaged,
+                            GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *bond_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_BOND_SETTING_NAME, NULL, _("Bond"));
+	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);
+
+	bond_setting = make_bond_setting (ifcfg, file, nm_controlled, unmanaged, error);
+	if (!bond_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, bond_setting);
+
 	wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
 	if (!wired_setting) {
 		g_object_unref (connection);
@@ -3299,50 +3666,245 @@ wired_connection_from_ifcfg (const char *file,
 }
 
 static gboolean
-is_wireless_device (const char *iface)
+is_bond_device (const char *name, shvarFile *parsed)
 {
-	int fd;
-	struct iw_range range;
-	struct iwreq wrq;
-	gboolean is_wireless = FALSE;
+	g_return_val_if_fail (name != NULL, FALSE);
+	g_return_val_if_fail (parsed != NULL, FALSE);
+
+	if (svTrueValue (parsed, "BONDING_MASTER", FALSE))
+		return TRUE;
+	
+	/* XXX: Check for "bond[\d]+"? */
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	return FALSE;
+}
 
-	fd = socket(AF_INET, SOCK_DGRAM, 0);
-	if (fd == -1)
-		return FALSE;
+static gboolean
+is_vlan_device (const char *name, shvarFile *parsed)
+{
+	g_return_val_if_fail (name != NULL, FALSE);
+	g_return_val_if_fail (parsed != NULL, 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 (svTrueValue (parsed, "VLAN", FALSE))
+		return TRUE;
 
-	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;
+	return FALSE;
+}
+
+static void
+parse_prio_map_list (NMSettingVlan *s_vlan,
+                     shvarFile *ifcfg,
+                     const char *key,
+                     NMVlanPriorityMap map)
+{
+	char *value;
+	gchar **list = NULL, **iter;
+
+	value = svGetValue (ifcfg, key, FALSE);
+	if (!value)
+		return;
+
+	list = g_strsplit_set (value, ",", -1);
+	g_free (value);
+
+	for (iter = list; iter && *iter; iter++) {
+		if (!*iter || !strchr (*iter, ':'))
+			continue;
+
+		if (!nm_setting_vlan_add_priority_str (s_vlan, map, *iter)) {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid %s priority map item '%s'",
+			             key, *iter);
+		}
+	}
+	g_strfreev (list);
+}
+
+static NMSetting *
+make_vlan_setting (shvarFile *ifcfg,
+                   const char *file,
+                   gboolean nm_controlled,
+                   char **out_master,
+                   char **unmanaged,
+                   NMSetting8021x **s_8021x,
+                   GError **error)
+{
+	NMSettingVlan *s_vlan = NULL;
+	char *value = NULL;
+	char *iface_name = NULL;
+	char *parent = NULL;
+	const char *p = NULL, *w;
+	gboolean has_numbers = FALSE;
+	gint vlan_id = -1;
+	guint32 vlan_flags = 0;
+
+	value = svGetValue (ifcfg, "VLAN_ID", FALSE);
+	if (value) {
+		errno = 0;
+		vlan_id = (gint) g_ascii_strtoll (value, NULL, 10);
+		if (vlan_id < 0 || vlan_id > 4096 || errno) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid VLAN_ID '%s'", value);
+			g_free (value);
+			return NULL;
+		}
+		g_free (value);
+	}
+
+	/* Need DEVICE if we don't have a separate VLAN_ID property */
+	iface_name = svGetValue (ifcfg, "DEVICE", FALSE);
+	if (!iface_name && vlan_id < 0) {
+		g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
+		                     "Missing DEVICE property; cannot determine VLAN ID.");
+		return NULL;
+	}
+
+	s_vlan = NM_SETTING_VLAN (nm_setting_vlan_new ());
+
+	if (iface_name) {
+		g_object_set (s_vlan, NM_SETTING_VLAN_INTERFACE_NAME, iface_name, NULL);
+
+		p = strchr (iface_name, '.');
+		if (p) {
+			/* eth0.43; PHYSDEV is assumed from it */
+			parent = g_strndup (iface_name, p - iface_name);
+			p++;
+		} else {
+			/* format like vlan43; PHYSDEV or MASTER must be set */
+			if (g_str_has_prefix (iface_name, "vlan"))
+				p = iface_name + 4;
 		}
+
+		w = p;
+		while (*w && !has_numbers)
+			has_numbers = g_ascii_isdigit (*w);
+
+		/* Grab VLAN ID from interface name; this takes precedence over the
+		 * separate VLAN_ID property for backwards compat.
+		 */
+		if (has_numbers) {
+			errno = 0;
+			vlan_id = (gint) g_ascii_strtoll (p, NULL, 10);
+			if (vlan_id < 0 || vlan_id > 4095 || errno) {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				             "Failed to determine VLAN ID from DEVICE '%s'",
+				             iface_name);
+				goto error;
+			}
+		}
+	}
+
+	if (vlan_id < 0) {
+		g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
+		                     "Failed to determine VLAN ID from DEVICE or VLAN_ID.");
+		goto error;
 	}
+	g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
 
-	close (fd);
-	return is_wireless;
+	if (!parent)
+		parent = svGetValue (ifcfg, "PHYSDEV", FALSE);
+	if (parent == NULL) {
+		g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
+		                     "Failed to determine VLAN parent from DEVICE or PHYSDEV");
+		goto error;
+	}
+	g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
+
+	if (svTrueValue (ifcfg, "REORDER_HDR", FALSE))
+		vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS;
+
+	value = svGetValue (ifcfg, "VLAN_FLAGS", FALSE);
+	if (value) {
+		if (g_strstr_len (value, -1, "GVRP"))
+			vlan_flags |= NM_VLAN_FLAG_GVRP;
+		if (g_strstr_len (value, -1, "LOOSE_BINDING"))
+			vlan_flags |= NM_VLAN_FLAG_LOOSE_BINDING;
+	}
+
+	g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, vlan_flags, NULL);
+	g_free (value);
+
+	parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP);
+	parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP);
+
+	if (out_master)
+		*out_master = svGetValue (ifcfg, "MASTER", FALSE);
+	return (NMSetting *) s_vlan;
+
+error:
+	g_free (parent);
+	g_free (iface_name);
+	g_object_unref (s_vlan);
+	return NULL;
+}
+
+static NMConnection *
+vlan_connection_from_ifcfg (const char *file,
+                            shvarFile *ifcfg,
+                            gboolean nm_controlled,
+                            char **unmanaged,
+                            GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *wired_setting = NULL;
+	NMSetting *vlan_setting = NULL;
+	NMSetting8021x *s_8021x = NULL;
+	char *master = 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_VLAN_SETTING_NAME, NULL, "Vlan");
+	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);
+
+	vlan_setting = make_vlan_setting (ifcfg, file, nm_controlled, &master, unmanaged, &s_8021x, error);
+	if (!vlan_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, vlan_setting);
+
+	/* Handle master interface or connection */
+	if (master) {
+		g_object_set (con_setting, NM_SETTING_CONNECTION_MASTER, master, NULL);
+		g_object_set (con_setting,
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_VLAN_SETTING_NAME,
+		              NULL);
+		g_free (master);
+	}
+
+	wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
+	if (!wired_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, wired_setting);
+
+	if (s_8021x)
+		nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+	if (!nm_connection_verify (connection, error)) {
+		g_object_unref (connection);
+		return NULL;
+	}
+
+	return connection;
 }
 
 enum {
 	IGNORE_REASON_NONE = 0x00,
 	IGNORE_REASON_BRIDGE = 0x01,
-	IGNORE_REASON_VLAN = 0x02,
 };
 
 NMConnection *
@@ -3363,7 +3925,7 @@ connection_from_file (const char *filename,
 	NMSetting *s_ip4, *s_ip6;
 	const char *ifcfg_name = NULL;
 	gboolean nm_controlled = TRUE;
-	gboolean ip6_used = FALSE;
+	gboolean can_disable_ip4 = FALSE;
 	GError *error = NULL;
 	guint32 ignore_reason = IGNORE_REASON_NONE;
 
@@ -3402,9 +3964,6 @@ connection_from_file (const char *filename,
 	if (!type) {
 		char *device;
 
-		/* If no type, if the device has wireless extensions, it's wifi,
-		 * otherwise it's ethernet.
-		 */
 		device = svGetValue (parsed, "DEVICE", FALSE);
 		if (!device) {
 			g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
@@ -3422,8 +3981,12 @@ connection_from_file (const char *filename,
 		}
 
 		if (!test_type) {
+			if (is_bond_device (device, parsed))
+				type = g_strdup (TYPE_BOND);
+			else if (is_vlan_device (device, parsed))
+				type = g_strdup (TYPE_VLAN);
 			/* Test wireless extensions */
-			if (is_wireless_device (device))
+			else if (wifi_utils_is_wifi (device, NULL))
 				type = g_strdup (TYPE_WIRELESS);
 			else
 				type = g_strdup (TYPE_ETHERNET);
@@ -3456,7 +4019,14 @@ connection_from_file (const char *filename,
 		g_free (lower);
 	}
 
-	/* Ignore BRIDGE= and VLAN= connections for now too (rh #619863) */
+	if (svTrueValue (parsed, "BONDING_MASTER", FALSE) &&
+	    strcasecmp (type, TYPE_BOND)) {
+		g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
+		             "BONDING_MASTER=yes key only allowed in TYPE=bond connections");
+		goto done;
+	}
+
+	/* Ignore BRIDGE= connections for now too (rh #619863) */
 	tmp = svGetValue (parsed, "BRIDGE", FALSE);
 	if (tmp) {
 		g_free (tmp);
@@ -3464,24 +4034,21 @@ connection_from_file (const char *filename,
 		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;
-		}
-	}
-
 	/* Construct the connection */
 	if (!strcasecmp (type, TYPE_ETHERNET))
 		connection = wired_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
 	else if (!strcasecmp (type, TYPE_WIRELESS))
 		connection = wireless_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
-	else if (!strcasecmp (type, TYPE_BRIDGE)) {
+	else if (!strcasecmp (type, TYPE_INFINIBAND))
+		connection = infiniband_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
+	else if (!strcasecmp (type, TYPE_BOND))
+		connection = bond_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
+	else if (!strcasecmp (type, TYPE_VLAN))
+		connection = vlan_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
+	else if (!strcasecmp (type, TYPE_BRIDGE))
 		g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
 		             "Bridge connections are not yet supported");
-	} else {
+	else {
 		g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
 		             "Unknown connection type '%s'", type);
 	}
@@ -3524,10 +4091,13 @@ connection_from_file (const char *filename,
 		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;
+			can_disable_ip4 = TRUE;
 	}
 
-	s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, ip6_used, &error);
+	if (utils_disabling_ip4_config_allowed (connection))
+		can_disable_ip4 = TRUE;
+
+	s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, can_disable_ip4, &error);
 	if (error) {
 		g_object_unref (connection);
 		connection = NULL;
@@ -3544,7 +4114,7 @@ connection_from_file (const char *filename,
 	    && !g_ascii_strcasecmp (bootproto, "ibft")) {
 		NMSettingConnection *s_con;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		g_assert (s_con);
 
 		g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_READ_ONLY, TRUE, NULL);
@@ -3569,9 +4139,3 @@ done:
 	return connection;
 }
 
-const char *
-reader_get_prefix (void)
-{
-	return _("System");
-}
-