summary refs log tree commit diff
path: root/libnm-core/nm-setting-wireless.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-core/nm-setting-wireless.c')
-rw-r--r--libnm-core/nm-setting-wireless.c190
1 files changed, 137 insertions, 53 deletions
diff --git a/libnm-core/nm-setting-wireless.c b/libnm-core/nm-setting-wireless.c
index d8056c6c..cc04e1a0 100644
--- a/libnm-core/nm-setting-wireless.c
+++ b/libnm-core/nm-setting-wireless.c
@@ -1,5 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-
 /*
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -73,8 +71,8 @@ typedef struct {
 	char *cloned_mac_address;
 	char *generate_mac_address_mask;
 	GArray *mac_address_blacklist;
+	GPtrArray *seen_bssids;
 	guint32 mtu;
-	GSList *seen_bssids;
 	gboolean hidden;
 	guint32 powersave;
 	NMSettingMacRandomization mac_address_randomization;
@@ -660,33 +658,27 @@ nm_setting_wireless_add_seen_bssid (NMSettingWireless *setting,
                                     const char *bssid)
 {
 	NMSettingWirelessPrivate *priv;
-	char *lower_bssid;
-	GSList *iter;
-	gboolean found = FALSE;
+	gs_free char *lower_bssid = NULL;
 
 	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), FALSE);
 	g_return_val_if_fail (bssid != NULL, FALSE);
 
-	lower_bssid = g_ascii_strdown (bssid, -1);
-	if (!lower_bssid)
-		return FALSE;
-
 	priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting);
 
-	for (iter = priv->seen_bssids; iter; iter = iter->next) {
-		if (!strcmp ((char *) iter->data, lower_bssid)) {
-			found = TRUE;
-			break;
-		}
-	}
+	lower_bssid = g_ascii_strdown (bssid, -1);
 
-	if (!found) {
-		priv->seen_bssids = g_slist_prepend (priv->seen_bssids, lower_bssid);
-		_notify (setting, PROP_SEEN_BSSIDS);
-	} else
-		g_free (lower_bssid);
+	if (!priv->seen_bssids) {
+		priv->seen_bssids = g_ptr_array_new_with_free_func (g_free);
+	} else {
+		if (nm_utils_strv_find_first ((char **) priv->seen_bssids->pdata,
+		                              priv->seen_bssids->len,
+		                              lower_bssid) >= 0)
+			return FALSE;
+	}
 
-	return !found;
+	g_ptr_array_add (priv->seen_bssids, g_steal_pointer (&lower_bssid));
+	_notify (setting, PROP_SEEN_BSSIDS);
+	return TRUE;
 }
 
 /**
@@ -698,9 +690,15 @@ nm_setting_wireless_add_seen_bssid (NMSettingWireless *setting,
 guint32
 nm_setting_wireless_get_num_seen_bssids (NMSettingWireless *setting)
 {
+	NMSettingWirelessPrivate *priv;
+
 	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), 0);
 
-	return g_slist_length (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->seen_bssids);
+	priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting);
+
+	return   priv->seen_bssids
+	       ? priv->seen_bssids->len
+	       : 0u;
 }
 
 /**
@@ -714,19 +712,60 @@ const char *
 nm_setting_wireless_get_seen_bssid (NMSettingWireless *setting,
                                     guint32 i)
 {
-	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), NULL);
+	NMSettingWirelessPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), 0);
+
+	priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting);
+
+	if (   !priv->seen_bssids
+	    || i >= priv->seen_bssids->len)
+		return NULL;
+
+	return priv->seen_bssids->pdata[i];
+}
+
+static GVariant *
+_to_dbus_fcn_seen_bssids (const NMSettInfoSetting *sett_info,
+                          guint property_idx,
+                          NMConnection *connection,
+                          NMSetting *setting,
+                          NMConnectionSerializationFlags flags,
+                          const NMConnectionSerializationOptions *options)
+{
+	NMSettingWirelessPrivate *priv;
+
+	if (   options
+	    && options->seen_bssids) {
+		return   options->seen_bssids[0]
+		       ? g_variant_new_strv (options->seen_bssids, -1)
+		       : NULL;
+	}
 
-	return (const char *) g_slist_nth_data (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->seen_bssids, i);
+	priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting);
+
+	if (   !priv->seen_bssids
+	    || priv->seen_bssids->len == 0)
+		return NULL;
+
+	return g_variant_new_strv ((const char *const*) priv->seen_bssids->pdata, priv->seen_bssids->len);
 }
 
+/*****************************************************************************/
+
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
 	NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting);
-	const char *valid_modes[] = { NM_SETTING_WIRELESS_MODE_INFRA, NM_SETTING_WIRELESS_MODE_ADHOC, NM_SETTING_WIRELESS_MODE_AP, NULL };
+	const char *valid_modes[] = {
+		NM_SETTING_WIRELESS_MODE_INFRA,
+		NM_SETTING_WIRELESS_MODE_ADHOC,
+		NM_SETTING_WIRELESS_MODE_AP,
+		NM_SETTING_WIRELESS_MODE_MESH,
+		NULL
+	};
 	const char *valid_bands[] = { "a", "bg", NULL };
-	GSList *iter;
-	int i;
+	guint i;
 	gsize length;
 	GError *local = NULL;
 
@@ -791,6 +830,16 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		}
 	}
 
+	if ((g_strcmp0 (priv->mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) && !(priv->channel && priv->band)) {
+		g_set_error (error,
+		             NM_CONNECTION_ERROR,
+		             NM_CONNECTION_ERROR_MISSING_PROPERTY,
+		             _("'%s' requires '%s' and '%s' property"),
+		             priv->mode, NM_SETTING_WIRELESS_BAND, NM_SETTING_WIRELESS_CHANNEL);
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MODE);
+		return FALSE;
+	}
+
 	if (priv->bssid && !nm_utils_hwaddr_valid (priv->bssid, ETH_ALEN)) {
 		g_set_error_literal (error,
 		                     NM_CONNECTION_ERROR,
@@ -848,15 +897,20 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		}
 	}
 
-	for (iter = priv->seen_bssids; iter; iter = iter->next) {
-		if (!nm_utils_hwaddr_valid (iter->data, ETH_ALEN)) {
-			g_set_error (error,
-			             NM_CONNECTION_ERROR,
-			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
-			             _("'%s' is not a valid MAC address"),
-			             (const char *) iter->data);
-			g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SEEN_BSSIDS);
-			return FALSE;
+	if (priv->seen_bssids) {
+		for (i = 0; i < priv->seen_bssids->len; i++) {
+			const char *b;
+
+			b = priv->seen_bssids->pdata[i];
+			if (!nm_utils_hwaddr_valid (b, ETH_ALEN)) {
+				g_set_error (error,
+				             NM_CONNECTION_ERROR,
+				             NM_CONNECTION_ERROR_INVALID_PROPERTY,
+				             _("'%s' is not a valid MAC address"),
+				             b);
+				g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SEEN_BSSIDS);
+				return FALSE;
+			}
 		}
 	}
 
@@ -919,20 +973,24 @@ mac_addr_rand_ok:
 static NMTernary
 compare_property (const NMSettInfoSetting *sett_info,
                   guint property_idx,
-                  NMSetting *setting,
-                  NMSetting *other,
+                  NMConnection *con_a,
+                  NMSetting *set_a,
+                  NMConnection *con_b,
+                  NMSetting *set_b,
                   NMSettingCompareFlags flags)
 {
 	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)) {
-		return    !other
-		       || nm_streq0 (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address,
-		                     NM_SETTING_WIRELESS_GET_PRIVATE (other)->cloned_mac_address);
+		return    !set_b
+		       || nm_streq0 (NM_SETTING_WIRELESS_GET_PRIVATE (set_a)->cloned_mac_address,
+		                     NM_SETTING_WIRELESS_GET_PRIVATE (set_b)->cloned_mac_address);
 	}
 
 	return NM_SETTING_CLASS (nm_setting_wireless_parent_class)->compare_property (sett_info,
 	                                                                              property_idx,
-	                                                                              setting,
-	                                                                              other,
+	                                                                              con_a,
+	                                                                              set_a,
+	                                                                              con_b,
+	                                                                              set_b,
 	                                                                              flags);
 }
 
@@ -943,7 +1001,8 @@ nm_setting_wireless_get_security (const NMSettInfoSetting *sett_info,
                                   guint property_idx,
                                   NMConnection *connection,
                                   NMSetting *setting,
-                                  NMConnectionSerializationFlags flags)
+                                  NMConnectionSerializationFlags flags,
+                                  const NMConnectionSerializationOptions *options)
 {
 	if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
 		return NULL;
@@ -1028,7 +1087,11 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_uint (value, nm_setting_wireless_get_mtu (setting));
 		break;
 	case PROP_SEEN_BSSIDS:
-		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->seen_bssids, TRUE));
+		g_value_take_boxed (value,
+		                      priv->seen_bssids
+		                    ? nm_utils_strv_dup (priv->seen_bssids->pdata,
+		                                         priv->seen_bssids->len)
+		                    : NULL);
 		break;
 	case PROP_HIDDEN:
 		g_value_set_boolean (value, nm_setting_wireless_get_hidden (setting));
@@ -1056,7 +1119,6 @@ set_property (GObject *object, guint prop_id,
 	const char * const *blacklist;
 	const char *mac;
 	gboolean bool_val;
-	int i;
 
 	switch (prop_id) {
 	case PROP_SSID:
@@ -1111,7 +1173,9 @@ set_property (GObject *object, guint prop_id,
 	case PROP_MAC_ADDRESS_BLACKLIST:
 		blacklist = g_value_get_boxed (value);
 		g_array_set_size (priv->mac_address_blacklist, 0);
-		if (blacklist && *blacklist) {
+		if (blacklist && blacklist[0]) {
+			gsize i;
+
 			for (i = 0; blacklist[i]; i++) {
 				mac = _nm_utils_hwaddr_canonical_or_invalid (blacklist[i], ETH_ALEN);
 				g_array_append_val (priv->mac_address_blacklist, mac);
@@ -1121,10 +1185,23 @@ set_property (GObject *object, guint prop_id,
 	case PROP_MTU:
 		priv->mtu = g_value_get_uint (value);
 		break;
-	case PROP_SEEN_BSSIDS:
-		g_slist_free_full (priv->seen_bssids, g_free);
-		priv->seen_bssids = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
+	case PROP_SEEN_BSSIDS: {
+		gs_unref_ptrarray GPtrArray *arr_old = NULL;
+		const char *const*strv;
+
+		arr_old = g_steal_pointer (&priv->seen_bssids);
+
+		strv = g_value_get_boxed (value);
+		if (strv && strv[0]) {
+			gsize i, l;
+
+			l = NM_PTRARRAY_LEN (strv);
+			priv->seen_bssids = g_ptr_array_new_full (l, g_free);
+			for (i = 0; i < l; i++)
+				g_ptr_array_add (priv->seen_bssids, g_strdup (strv[i]));
+		}
 		break;
+	}
 	case PROP_HIDDEN:
 		priv->hidden = g_value_get_boolean (value);
 		break;
@@ -1183,7 +1260,7 @@ finalize (GObject *object)
 	g_free (priv->cloned_mac_address);
 	g_free (priv->generate_mac_address_mask);
 	g_array_unref (priv->mac_address_blacklist);
-	g_slist_free_full (priv->seen_bssids, g_free);
+	nm_clear_pointer (&priv->seen_bssids, g_ptr_array_unref);
 
 	G_OBJECT_CLASS (nm_setting_wireless_parent_class)->finalize (object);
 }
@@ -1231,7 +1308,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	/**
 	 * NMSettingWireless:mode:
 	 *
-	 * Wi-Fi network mode; one of "infrastructure", "adhoc" or "ap".  If blank,
+	 * Wi-Fi network mode; one of "infrastructure", "mesh", "adhoc" or "ap".  If blank,
 	 * infrastructure is assumed.
 	 **/
 	/* ---ifcfg-rh---
@@ -1572,6 +1649,13 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	                        NM_SETTING_PARAM_FUZZY_IGNORE |
 	                        G_PARAM_STATIC_STRINGS);
 
+	_properties_override_add_override (properties_override,
+	                                   obj_properties[PROP_SEEN_BSSIDS],
+	                                   G_VARIANT_TYPE_STRING_ARRAY,
+	                                   _to_dbus_fcn_seen_bssids,
+	                                   NULL,
+	                                   NULL);
+
 	/**
 	 * NMSettingWireless:mtu:
 	 *