summary refs log tree commit diff
path: root/src/nm-wifi-ap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-wifi-ap.c')
-rw-r--r--src/nm-wifi-ap.c281
1 files changed, 159 insertions, 122 deletions
diff --git a/src/nm-wifi-ap.c b/src/nm-wifi-ap.c
index 7770b8bc..6eab9581 100644
--- a/src/nm-wifi-ap.c
+++ b/src/nm-wifi-ap.c
@@ -22,8 +22,10 @@
 #include "wireless-helper.h"
 
 #include <string.h>
+#include <stdlib.h>
 
 #include "nm-wifi-ap.h"
+#include "nm-wifi-ap-utils.h"
 #include "NetworkManagerUtils.h"
 #include "nm-utils.h"
 #include "nm-logging.h"
@@ -49,9 +51,9 @@ typedef struct
 	guint32			freq;		/* Frequency in MHz; ie 2412 (== 2.412 GHz) */
 	guint32			max_bitrate;/* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */
 
-	guint32			flags;		/* General flags */
-	guint32			wpa_flags;	/* WPA-related flags */
-	guint32			rsn_flags;	/* RSN (WPA2) -related flags */
+	NM80211ApFlags         flags;      /* General flags */
+	NM80211ApSecurityFlags wpa_flags;  /* WPA-related flags */
+	NM80211ApSecurityFlags rsn_flags;  /* RSN (WPA2) -related flags */
 
 	/* Non-scanned attributes */
 	gboolean			fake;	/* Whether or not the AP is from a scan */
@@ -213,7 +215,17 @@ static void
 nm_ap_class_init (NMAccessPointClass *ap_class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (ap_class);
-	guint32 all_sec_flags;
+	const NM80211ApSecurityFlags all_sec_flags =   NM_802_11_AP_SEC_NONE
+	                                             | NM_802_11_AP_SEC_PAIR_WEP40
+	                                             | NM_802_11_AP_SEC_PAIR_WEP104
+	                                             | NM_802_11_AP_SEC_PAIR_TKIP
+	                                             | NM_802_11_AP_SEC_PAIR_CCMP
+	                                             | NM_802_11_AP_SEC_GROUP_WEP40
+	                                             | NM_802_11_AP_SEC_GROUP_WEP104
+	                                             | NM_802_11_AP_SEC_GROUP_TKIP
+	                                             | NM_802_11_AP_SEC_GROUP_CCMP
+	                                             | NM_802_11_AP_SEC_KEY_MGMT_PSK
+	                                             | NM_802_11_AP_SEC_KEY_MGMT_802_1X;
 
 	g_type_class_add_private (ap_class, sizeof (NMAccessPointPrivate));
 
@@ -223,19 +235,6 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
 	object_class->finalize = finalize;
 
 	/* properties */
-
-	all_sec_flags =   NM_802_11_AP_SEC_NONE
-	                | NM_802_11_AP_SEC_PAIR_WEP40
-	                | NM_802_11_AP_SEC_PAIR_WEP104
-	                | NM_802_11_AP_SEC_PAIR_TKIP
-	                | NM_802_11_AP_SEC_PAIR_CCMP
-	                | NM_802_11_AP_SEC_GROUP_WEP40
-	                | NM_802_11_AP_SEC_GROUP_WEP104
-	                | NM_802_11_AP_SEC_GROUP_TKIP
-	                | NM_802_11_AP_SEC_GROUP_CCMP
-	                | NM_802_11_AP_SEC_KEY_MGMT_PSK
-	                | NM_802_11_AP_SEC_KEY_MGMT_802_1X;
-
 	g_object_class_install_property
 		(object_class, PROP_FLAGS,
 		 g_param_spec_uint (NM_AP_FLAGS,
@@ -369,10 +368,69 @@ NMAccessPoint *nm_ap_new (void)
 	return (NMAccessPoint *) object;
 }
 
+static NM80211ApSecurityFlags
+pair_to_flags (const char *str)
+{
+	g_return_val_if_fail (str != NULL, NM_802_11_AP_SEC_NONE);
+
+	if (strcmp (str, "wep40") == 0)
+		return NM_802_11_AP_SEC_PAIR_WEP40;
+	if (strcmp (str, "wep104") == 0)
+		return NM_802_11_AP_SEC_PAIR_WEP104;
+	if (strcmp (str, "tkip") == 0)
+		return NM_802_11_AP_SEC_PAIR_TKIP;
+	if (strcmp (str, "ccmp") == 0)
+		return NM_802_11_AP_SEC_PAIR_CCMP;
+	return NM_802_11_AP_SEC_NONE;
+}
+
+static NM80211ApSecurityFlags
+group_to_flags (const char *str)
+{
+	g_return_val_if_fail (str != NULL, NM_802_11_AP_SEC_NONE);
+
+	if (strcmp (str, "wep40") == 0)
+		return NM_802_11_AP_SEC_GROUP_WEP40;
+	if (strcmp (str, "wep104") == 0)
+		return NM_802_11_AP_SEC_GROUP_WEP104;
+	if (strcmp (str, "tkip") == 0)
+		return NM_802_11_AP_SEC_GROUP_TKIP;
+	if (strcmp (str, "ccmp") == 0)
+		return NM_802_11_AP_SEC_GROUP_CCMP;
+	return NM_802_11_AP_SEC_NONE;
+}
+
+static NM80211ApSecurityFlags
+security_from_dict (GHashTable *security)
+{
+	GValue *value;
+	NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE;
+	const char **items, **iter;
+
+	value = g_hash_table_lookup (security, "KeyMgmt");
+	if (value) {
+		items = g_value_get_boxed (value);
+		for (iter = items; iter && *iter; iter++) {
+			if (strcmp (*iter, "wpa-psk") == 0)
+				flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK;
+			else if (strcmp (*iter, "wpa-eap") == 0)
+				flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X;
+		}
+	}
+
+	value = g_hash_table_lookup (security, "Pairwise");
+	if (value) {
+		items = g_value_get_boxed (value);
+		for (iter = items; iter && *iter; iter++)
+			flags |= pair_to_flags (*iter);
+	}
+
+	value = g_hash_table_lookup (security, "Group");
+	if (value)
+		flags |= group_to_flags (g_value_get_string (value));
 
-#define IEEE80211_CAP_ESS       0x0001
-#define IEEE80211_CAP_IBSS      0x0002
-#define IEEE80211_CAP_PRIVACY   0x0010
+	return flags;
+}
 
 static void
 foreach_property_cb (gpointer key, gpointer value, gpointer user_data)
@@ -383,9 +441,9 @@ foreach_property_cb (gpointer key, gpointer value, gpointer user_data)
 	if (G_VALUE_HOLDS_BOXED (variant)) {
 		GArray *array = g_value_get_boxed (variant);
 
-		if (!strcmp (key, "ssid")) {
+		if (!strcmp (key, "SSID")) {
 			guint32 len = MIN (IW_ESSID_MAX_SIZE, array->len);
-			GByteArray * ssid;
+			GByteArray *ssid;
 
 			/* Stupid ieee80211 layer uses <hidden> */
 			if (((len == 8) || (len == 9))
@@ -399,7 +457,7 @@ foreach_property_cb (gpointer key, gpointer value, gpointer user_data)
 			g_byte_array_append (ssid, (const guint8 *) array->data, len);
 			nm_ap_set_ssid (ap, ssid);
 			g_byte_array_free (ssid, TRUE);
-		} else if (!strcmp (key, "bssid")) {
+		} else if (!strcmp (key, "BSSID")) {
 			struct ether_addr addr;
 
 			if (array->len != ETH_ALEN)
@@ -407,51 +465,61 @@ foreach_property_cb (gpointer key, gpointer value, gpointer user_data)
 			memset (&addr, 0, sizeof (struct ether_addr));
 			memcpy (&addr, array->data, ETH_ALEN);
 			nm_ap_set_address (ap, &addr);
-		} else if (!strcmp (key, "wpaie")) {
-			guint8 * ie = (guint8 *) array->data;
-			guint32 flags = nm_ap_get_wpa_flags (ap);
+		} else if (!strcmp (key, "Rates")) {
+			guint32 maxrate = 0;
+			int i;
+
+			/* Find the max AP rate */
+			for (i = 0; i < array->len; i++) {
+				guint32 r = g_array_index (array, guint32, i);
+
+				if (r > maxrate) {
+					maxrate = r;
+					nm_ap_set_max_bitrate (ap, r / 1000);
+				}
+			}
+		} else if (!strcmp (key, "WPA")) {
+			NM80211ApSecurityFlags flags = nm_ap_get_wpa_flags (ap);
 
-			if (array->len <= 0 || array->len > WPA_MAX_IE_LEN)
-				return;
-			flags = nm_ap_add_security_from_ie (flags, ie, array->len);
+			flags |= security_from_dict (g_value_get_boxed (variant));
 			nm_ap_set_wpa_flags (ap, flags);
-		} else if (!strcmp (key, "rsnie")) {
-			guint8 * ie = (guint8 *) array->data;
-			guint32 flags = nm_ap_get_rsn_flags (ap);
+		} else if (!strcmp (key, "RSN")) {
+			NM80211ApSecurityFlags flags = nm_ap_get_rsn_flags (ap);
 
-			if (array->len <= 0 || array->len > WPA_MAX_IE_LEN)
-				return;
-			flags = nm_ap_add_security_from_ie (flags, ie, array->len);
+			flags |= security_from_dict (g_value_get_boxed (variant));
 			nm_ap_set_rsn_flags (ap, flags);
 		}
-	} else if (G_VALUE_HOLDS_INT (variant)) {
-		gint32 int_val = g_value_get_int (variant);
-
-		if (!strcmp (key, "frequency")) {
-			nm_ap_set_freq (ap, (guint32) int_val);
-		} else if (!strcmp (key, "maxrate")) {
-			/* Supplicant reports as b/s, we use Kb/s internally */
-			nm_ap_set_max_bitrate (ap, int_val / 1000);
-		}
 	} else if (G_VALUE_HOLDS_UINT (variant)) {
 		guint32 val = g_value_get_uint (variant);
 
-		if (!strcmp (key, "capabilities")) {
-			if (val & IEEE80211_CAP_ESS) {
+		if (!strcmp (key, "Frequency"))
+			nm_ap_set_freq (ap, val);
+	} else if (G_VALUE_HOLDS_INT (variant)) {
+		gint val = g_value_get_int (variant);
+
+		if (!strcmp (key, "Signal"))
+			nm_ap_set_strength (ap, nm_ap_utils_level_to_quality (val));
+	} else if (G_VALUE_HOLDS_STRING (variant)) {
+		const char *val = g_value_get_string (variant);
+
+		if (val && !strcmp (key, "Mode")) {
+			if (strcmp (val, "infrastructure") == 0)
 				nm_ap_set_mode (ap, NM_802_11_MODE_INFRA);
-			} else if (val & IEEE80211_CAP_IBSS) {
+			else if (strcmp (val, "ad-hoc") == 0)
 				nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC);
-			}
+		}
+	} else if (G_VALUE_HOLDS_BOOLEAN (variant)) {
+		gboolean val = g_value_get_boolean (variant);
 
-			if (val & IEEE80211_CAP_PRIVACY) {
-				guint32 flags = nm_ap_get_flags (ap);
+		if (strcmp (key, "Privacy") == 0) {
+			if (val) {
+				NM80211ApFlags flags = nm_ap_get_flags (ap);
 				nm_ap_set_flags (ap, flags | NM_802_11_AP_FLAGS_PRIVACY);
 			}
 		}
 	}
 }
 
-
 NMAccessPoint *
 nm_ap_new_from_properties (GHashTable *properties)
 {
@@ -510,7 +578,7 @@ static void
 add_pair_ciphers (NMAccessPoint *ap, NMSettingWirelessSecurity *sec)
 {
 	guint32 num = nm_setting_wireless_security_get_num_pairwise (sec);
-	guint32 flags = NM_802_11_AP_SEC_NONE;
+	NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE;
 	guint32 i;
 
 	/* If no ciphers are specified, that means "all" WPA ciphers */
@@ -537,7 +605,7 @@ static void
 add_group_ciphers (NMAccessPoint *ap, NMSettingWirelessSecurity *sec)
 {
 	guint32 num = nm_setting_wireless_security_get_num_groups (sec);
-	guint32 flags = NM_802_11_AP_SEC_NONE;
+	NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE;
 	guint32 i;
 
 	/* If no ciphers are specified, that means "all" WPA ciphers */
@@ -572,7 +640,8 @@ nm_ap_new_fake_from_connection (NMConnection *connection)
 	NMSettingWirelessSecurity *s_wireless_sec;
 	const GByteArray *ssid;
 	const char *mode, *band, *key_mgmt;
-	guint32 channel, flags;
+	guint32 channel;
+	NM80211ApSecurityFlags flags;
 	gboolean psk = FALSE, eap = FALSE;
 
 	g_return_val_if_fail (connection != NULL, NULL);
@@ -803,21 +872,17 @@ nm_ap_set_ssid (NMAccessPoint *ap, const GByteArray * ssid)
 }
 
 
-guint32
+NM80211ApFlags
 nm_ap_get_flags (NMAccessPoint *ap)
 {
-	guint32 flags;
-
-	g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_FLAGS_NONE);
-
-	g_object_get (ap, NM_AP_FLAGS, &flags, NULL);
+	g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_SEC_NONE);
 
-	return flags;
+	return NM_AP_GET_PRIVATE (ap)->flags;
 }
 
 
 void
-nm_ap_set_flags (NMAccessPoint *ap, guint32 flags)
+nm_ap_set_flags (NMAccessPoint *ap, NM80211ApFlags flags)
 {
 	NMAccessPointPrivate *priv;
 
@@ -831,56 +896,46 @@ nm_ap_set_flags (NMAccessPoint *ap, guint32 flags)
 	}
 }
 
-guint32
+NM80211ApSecurityFlags
 nm_ap_get_wpa_flags (NMAccessPoint *ap)
 {
-	guint32 flags;
-
 	g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_SEC_NONE);
 
-	g_object_get (ap, NM_AP_WPA_FLAGS, &flags, NULL);
-
-	return flags;
+	return NM_AP_GET_PRIVATE (ap)->wpa_flags;
 }
 
 
 void
-nm_ap_set_wpa_flags (NMAccessPoint *ap, guint32 flags)
+nm_ap_set_wpa_flags (NMAccessPoint *ap, NM80211ApSecurityFlags flags)
 {
 	NMAccessPointPrivate *priv;
 
 	g_return_if_fail (NM_IS_AP (ap));
 
 	priv = NM_AP_GET_PRIVATE (ap);
-
 	if (priv->wpa_flags != flags) {
 		priv->wpa_flags = flags;
 		g_object_notify (G_OBJECT (ap), NM_AP_WPA_FLAGS);
 	}
 }
 
-guint32
+NM80211ApSecurityFlags
 nm_ap_get_rsn_flags (NMAccessPoint *ap)
 {
-	guint32 flags;
-
 	g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_SEC_NONE);
 
-	g_object_get (ap, NM_AP_RSN_FLAGS, &flags, NULL);
-
-	return flags;
+	return NM_AP_GET_PRIVATE (ap)->rsn_flags;
 }
 
 
 void
-nm_ap_set_rsn_flags (NMAccessPoint *ap, guint32 flags)
+nm_ap_set_rsn_flags (NMAccessPoint *ap, NM80211ApSecurityFlags flags)
 {
 	NMAccessPointPrivate *priv;
 
 	g_return_if_fail (NM_IS_AP (ap));
 
 	priv = NM_AP_GET_PRIVATE (ap);
-
 	if (priv->rsn_flags != flags) {
 		priv->rsn_flags = flags;
 		g_object_notify (G_OBJECT (ap), NM_AP_RSN_FLAGS);
@@ -1170,45 +1225,6 @@ void nm_ap_set_user_addresses (NMAccessPoint *ap, GSList *list)
 }
 
 
-guint32
-nm_ap_add_security_from_ie (guint32 flags,
-                            const guint8 *wpa_ie,
-                            guint32 length)
-{
-	wpa_ie_data * cap_data;
-
-	if (!(cap_data = wpa_parse_wpa_ie (wpa_ie, length)))
-		return NM_802_11_AP_SEC_NONE;
-
-	/* Pairwise cipher flags */
-	if (cap_data->pairwise_cipher & IW_AUTH_CIPHER_WEP40)
-		flags |= NM_802_11_AP_SEC_PAIR_WEP40;
-	if (cap_data->pairwise_cipher & IW_AUTH_CIPHER_WEP104)
-		flags |= NM_802_11_AP_SEC_PAIR_WEP104;
-	if (cap_data->pairwise_cipher & IW_AUTH_CIPHER_TKIP)
-		flags |= NM_802_11_AP_SEC_PAIR_TKIP;
-	if (cap_data->pairwise_cipher & IW_AUTH_CIPHER_CCMP)
-		flags |= NM_802_11_AP_SEC_PAIR_CCMP;
-
-	/* Group cipher flags */
-	if (cap_data->group_cipher & IW_AUTH_CIPHER_WEP40)
-		flags |= NM_802_11_AP_SEC_GROUP_WEP40;
-	if (cap_data->group_cipher & IW_AUTH_CIPHER_WEP104)
-		flags |= NM_802_11_AP_SEC_GROUP_WEP104;
-	if (cap_data->group_cipher & IW_AUTH_CIPHER_TKIP)
-		flags |= NM_802_11_AP_SEC_GROUP_TKIP;
-	if (cap_data->group_cipher & IW_AUTH_CIPHER_CCMP)
-		flags |= NM_802_11_AP_SEC_GROUP_CCMP;
-
-	if (cap_data->key_mgmt & IW_AUTH_KEY_MGMT_802_1X)
-		flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X;
-	if (cap_data->key_mgmt & IW_AUTH_KEY_MGMT_PSK)
-		flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK;
-
-	g_slice_free (wpa_ie_data, cap_data);
-	return flags;
-}
-
 gboolean
 nm_ap_check_compatible (NMAccessPoint *self,
                         NMConnection *connection)
@@ -1275,8 +1291,29 @@ nm_ap_check_compatible (NMAccessPoint *self,
 	                                                   nm_ap_get_mode (self));
 }
 
+gboolean
+nm_ap_complete_connection (NMAccessPoint *self,
+                           NMConnection *connection,
+                           gboolean lock_bssid,
+                           GError **error)
+{
+	NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (self);
+
+	g_return_val_if_fail (connection != NULL, FALSE);
+
+	return nm_ap_utils_complete_connection (priv->ssid,
+	                                        priv->address.ether_addr_octet,
+	                                        priv->mode,
+	                                        priv->flags,
+	                                        priv->wpa_flags,
+	                                        priv->rsn_flags,
+	                                        connection,
+	                                        lock_bssid,
+	                                        error);
+}
+
 static gboolean
-capabilities_compatible (guint32 a_flags, guint32 b_flags)
+capabilities_compatible (NM80211ApSecurityFlags a_flags, NM80211ApSecurityFlags b_flags)
 {
 	if (a_flags == b_flags)
 		return TRUE;
@@ -1349,10 +1386,10 @@ nm_ap_match_in_list (NMAccessPoint *find_ap,
 			if (nm_ap_get_rsn_flags (list_ap) != nm_ap_get_rsn_flags (find_ap))
 				continue;
 		} else {
-			guint32 list_wpa_flags = nm_ap_get_wpa_flags (list_ap);
-			guint32 find_wpa_flags = nm_ap_get_wpa_flags (find_ap);
-			guint32 list_rsn_flags = nm_ap_get_rsn_flags (list_ap);
-			guint32 find_rsn_flags = nm_ap_get_rsn_flags (find_ap);
+			NM80211ApSecurityFlags list_wpa_flags = nm_ap_get_wpa_flags (list_ap);
+			NM80211ApSecurityFlags find_wpa_flags = nm_ap_get_wpa_flags (find_ap);
+			NM80211ApSecurityFlags list_rsn_flags = nm_ap_get_rsn_flags (list_ap);
+			NM80211ApSecurityFlags find_rsn_flags = nm_ap_get_rsn_flags (find_ap);
 
 			/* Just ensure that there is overlap in the capabilities */
 			if (   !capabilities_compatible (list_wpa_flags, find_wpa_flags)