static gboolean
nmt_slave_list_connection_filter (NmtEditConnectionList *list,
                                  NMConnection          *connection,
                                  gpointer               user_data)
{
	NmtSlaveListPrivate *priv = NMT_SLAVE_LIST_GET_PRIVATE (list);
	NMSettingConnection *s_con;
	const char *master, *master_ifname, *slave_type;

	s_con = nm_connection_get_setting_connection (connection);
	g_return_val_if_fail (s_con != NULL, FALSE);

	slave_type = nm_setting_connection_get_slave_type (s_con);
	if (g_strcmp0 (slave_type, priv->master_type) != 0)
		return FALSE;

	master = nm_setting_connection_get_master (s_con);
	if (!master)
		return FALSE;

	master_ifname = nm_connection_get_virtual_iface_name (priv->master);
	if (g_strcmp0 (master, master_ifname) != 0 && g_strcmp0 (master, priv->master_uuid) != 0)
		return FALSE;

	return TRUE;
}
static void
get_property (GObject *object, guint prop_id,
              GValue *value, GParamSpec *pspec)
{
	NMSettingConnection *setting = NM_SETTING_CONNECTION (object);
	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting);

	switch (prop_id) {
	case PROP_ID:
		g_value_set_string (value, nm_setting_connection_get_id (setting));
		break;
	case PROP_UUID:
		g_value_set_string (value, nm_setting_connection_get_uuid (setting));
		break;
	case PROP_TYPE:
		g_value_set_string (value, nm_setting_connection_get_connection_type (setting));
		break;
	case PROP_PERMISSIONS:
		g_value_take_boxed (value, perm_permlist_to_stringlist (priv->permissions));
		break;
	case PROP_AUTOCONNECT:
		g_value_set_boolean (value, nm_setting_connection_get_autoconnect (setting));
		break;
	case PROP_TIMESTAMP:
		g_value_set_uint64 (value, nm_setting_connection_get_timestamp (setting));
		break;
	case PROP_READ_ONLY:
		g_value_set_boolean (value, nm_setting_connection_get_read_only (setting));
		break;
	case PROP_ZONE:
		g_value_set_string (value, nm_setting_connection_get_zone (setting));
		break;
	case PROP_MASTER:
		g_value_set_string (value, nm_setting_connection_get_master (setting));
		break;
	case PROP_SLAVE_TYPE:
		g_value_set_string (value, nm_setting_connection_get_slave_type (setting));
		break;
	case PROP_SECONDARIES:
		g_value_set_boxed (value, priv->secondaries);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
	NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);

	if (priv->config) {
		if (!_nm_utils_check_valid_json (priv->config, error)) {
			g_prefix_error (error,
			                "%s.%s: ",
			                NM_SETTING_TEAM_PORT_SETTING_NAME,
			                NM_SETTING_TEAM_PORT_CONFIG);
			return FALSE;
		}
	}

	if (connection) {
		NMSettingConnection *s_con;
		const char *slave_type;

		s_con = nm_connection_get_setting_connection (connection);
		if (!s_con) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_MISSING_SETTING,
			             _("missing setting"));
			g_prefix_error (error, "%s: ", NM_SETTING_CONNECTION_SETTING_NAME);
			return FALSE;
		}

		slave_type = nm_setting_connection_get_slave_type (s_con);
		if (   slave_type
		    && strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("A connection with a '%s' setting must have the slave-type set to '%s'. Instead it is '%s'"),
			             NM_SETTING_TEAM_PORT_SETTING_NAME,
			             NM_SETTING_TEAM_SETTING_NAME,
			             slave_type);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE);
			return FALSE;
		}
	}
	return TRUE;
}
static gboolean
tree_model_visible_func (GtkTreeModel *model,
                         GtkTreeIter *iter,
                         gpointer user_data)
{
	NMConnectionList *self = user_data;
	NMConnection *connection;
	NMSettingConnection *s_con;
	const char *master;
	const char *slave_type;

	gtk_tree_model_get (model, iter, COL_CONNECTION, &connection, -1);
	if (!connection) {
		/* Top-level type nodes are visible iff they have children */
		return gtk_tree_model_iter_has_child  (model, iter);
	}

	/* A connection node is visible unless it is a slave to a known
	 * bond or bridge.
	 */
	s_con = nm_connection_get_setting_connection (connection);
	g_object_unref (connection);
	g_return_val_if_fail (s_con != NULL, FALSE);

	master = nm_setting_connection_get_master (s_con);
	if (!master)
		return TRUE;
	slave_type = nm_setting_connection_get_slave_type (s_con);
	if (   g_strcmp0 (slave_type, NM_SETTING_BOND_SETTING_NAME) != 0
	    && g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME) != 0)
		return TRUE;

	if (nm_remote_settings_get_connection_by_uuid (self->settings, master))
		return FALSE;
	if (nm_connection_editor_get_master (connection))
		return FALSE;

	/* FIXME: what if master is an interface name */

	return TRUE;
}
static gboolean
edit_connection_list_filter (NmtEditConnectionList *list,
                             NMConnection          *connection,
                             gpointer               user_data)
{
	NMSettingConnection *s_con;
	const char *master, *slave_type;
	const char *uuid, *ifname;
	const GPtrArray *conns;
	int i;
	gboolean found_master = FALSE;

	s_con = nm_connection_get_setting_connection (connection);
	g_return_val_if_fail (s_con != NULL, FALSE);

	master = nm_setting_connection_get_master (s_con);
	if (!master)
		return TRUE;
	slave_type = nm_setting_connection_get_slave_type (s_con);
	if (   g_strcmp0 (slave_type, NM_SETTING_BOND_SETTING_NAME) != 0
	    && g_strcmp0 (slave_type, NM_SETTING_TEAM_SETTING_NAME) != 0
	    && g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME) != 0)
		return TRUE;

	conns = nm_client_get_connections (nm_client);
	for (i = 0; i < conns->len; i++) {
		NMConnection *candidate = conns->pdata[i];

		uuid = nm_connection_get_uuid (candidate);
		ifname = nm_connection_get_interface_name (candidate);
		if (!g_strcmp0 (master, uuid) || !g_strcmp0 (master, ifname)) {
			found_master = TRUE;
			break;
		}
	}

	return !found_master;
}
Exemple #6
0
static void
ensure_slave_setting (NMConnection *connection)
{
	NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
	const char *slave_type;
	GType slave_gtype = G_TYPE_INVALID;
	NMSetting *setting;

	slave_type = nm_setting_connection_get_slave_type (s_con);
	if (!slave_type)
		return;

	if (g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME) == 0)
		slave_gtype = NM_TYPE_SETTING_BRIDGE_PORT;
	else if (g_strcmp0 (slave_type, NM_SETTING_TEAM_SETTING_NAME) == 0)
		slave_gtype = NM_TYPE_SETTING_TEAM_PORT;

	if (slave_gtype != G_TYPE_INVALID && !nm_connection_get_setting (connection, slave_gtype)) {
		setting = (NMSetting *) g_object_new (slave_gtype, NULL);
		g_assert (setting);
		nm_connection_add_setting (connection, setting);
	}
}
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
	NMSettingBridgePortPrivate *priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (setting);

	if (priv->priority > BR_MAX_PORT_PRIORITY) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%d' is not a valid value for the property (should be <= %d)"),
		             priv->priority, BR_MAX_PORT_PRIORITY);
		g_prefix_error (error, "%s.%s: ",
		                NM_SETTING_BRIDGE_PORT_SETTING_NAME,
		                NM_SETTING_BRIDGE_PORT_PRIORITY);
		return FALSE;
	}

	if (priv->path_cost > BR_MAX_PATH_COST) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%d' is not a valid value for the property (should be <= %d)"),
		             priv->path_cost, BR_MAX_PATH_COST);
		g_prefix_error (error, "%s.%s: ",
		                NM_SETTING_BRIDGE_PORT_SETTING_NAME,
		                NM_SETTING_BRIDGE_PORT_PATH_COST);
		return FALSE;
	}


	if (connection) {
		NMSettingConnection *s_con;
		const char *slave_type;

		s_con = nm_connection_get_setting_connection (connection);
		if (!s_con) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_MISSING_SETTING,
			             _("missing setting"));
			g_prefix_error (error, "%s: ", NM_SETTING_CONNECTION_SETTING_NAME);
			return FALSE;
		}

		slave_type = nm_setting_connection_get_slave_type (s_con);
		if (   slave_type
		    && strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("A connection with a '%s' setting must have the slave-type set to '%s'. Instead it is '%s'"),
			             NM_SETTING_BRIDGE_PORT_SETTING_NAME,
			             NM_SETTING_BRIDGE_SETTING_NAME,
			             slave_type);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE);
			return FALSE;
		}
	}

	return TRUE;
}
static void
ui_to_setting (CEPageVlan *self)
{
    CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
    NMConnection *connection = CE_PAGE (self)->connection;
    NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
    GByteArray *cloned_mac = NULL;
    VlanParent *parent = NULL;
    int parent_id, vid;
    const char *parent_iface = NULL, *parent_uuid = NULL;
    const char *slave_type;
    const char *iface;
    char *tmp_parent_iface = NULL;
    GType hwtype;
    gboolean mtu_set;
    int mtu;

    parent_id = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->parent));
    if (parent_id == -1) {
        parent_iface = gtk_entry_get_text (priv->parent_entry);
        tmp_parent_iface = g_strndup (parent_iface, strcspn (parent_iface, " "));
        parent_iface = tmp_parent_iface;
    } else {
        parent = priv->parents[parent_id];
        if (parent->connection)
            parent_uuid = nm_connection_get_uuid (parent->connection);
        if (parent->device)
            parent_iface = nm_device_get_iface (parent->device);
    }

    g_assert (parent_uuid != NULL || parent_iface != NULL);

    slave_type = nm_setting_connection_get_slave_type (s_con);
    if (parent_uuid) {
        /* Update NMSettingConnection:master if it's set, but don't
         * set it if it's not.
         */
        if (!g_strcmp0 (slave_type, NM_SETTING_VLAN_SETTING_NAME)) {
            g_object_set (s_con,
                          NM_SETTING_CONNECTION_MASTER, parent_uuid,
                          NULL);
        }
    } else if (!g_strcmp0 (slave_type, NM_SETTING_VLAN_SETTING_NAME)) {
        g_object_set (s_con,
                      NM_SETTING_CONNECTION_MASTER, NULL,
                      NM_SETTING_CONNECTION_SLAVE_TYPE, NULL,
                      NULL);
    }

    if (parent && NM_IS_DEVICE_ETHERNET (parent->device))
        hwtype = NM_TYPE_SETTING_WIRED;
    else
        hwtype = G_TYPE_NONE;

    if (priv->s_hw && G_OBJECT_TYPE (priv->s_hw) != hwtype) {
        nm_connection_remove_setting (connection, G_OBJECT_TYPE (priv->s_hw));
        priv->s_hw = NULL;
    }

    iface = gtk_entry_get_text (priv->name_entry);
    vid = gtk_spin_button_get_value_as_int (priv->id_entry);

    g_object_set (priv->setting,
                  NM_SETTING_VLAN_PARENT, parent_uuid ? parent_uuid : parent_iface,
                  NM_SETTING_VLAN_INTERFACE_NAME, iface,
                  NM_SETTING_VLAN_ID, vid,
                  NULL);

    if (hwtype != G_TYPE_NONE) {
        cloned_mac = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, NULL);
        mtu_set = g_ascii_isdigit (*gtk_entry_get_text (GTK_ENTRY (priv->mtu)));
        mtu = gtk_spin_button_get_value_as_int (priv->mtu);

        if (cloned_mac || mtu_set) {
            if (!priv->s_hw) {
                priv->s_hw = g_object_new (hwtype, NULL);
                nm_connection_add_setting (connection, priv->s_hw);
            }

            g_object_set (priv->s_hw,
                          NM_SETTING_WIRED_CLONED_MAC_ADDRESS, cloned_mac,
                          NM_SETTING_WIRED_MTU, (guint32) mtu,
                          NULL);

            if (cloned_mac)
                g_byte_array_free (cloned_mac, TRUE);
        } else if (priv->s_hw) {
            nm_connection_remove_setting (connection, G_OBJECT_TYPE (priv->s_hw));
            priv->s_hw = NULL;
        }
    }

    g_free (tmp_parent_iface);
}
static gboolean
nm_connection_editor_set_connection (NMConnectionEditor *editor,
                                     NMConnection *orig_connection,
                                     GError **error)
{
	NMSettingConnection *s_con;
	const char *connection_type;
	const char *slave_type;
	gboolean success = FALSE;
	GSList *iter, *copy;

	g_return_val_if_fail (NM_IS_CONNECTION_EDITOR (editor), FALSE);
	g_return_val_if_fail (NM_IS_CONNECTION (orig_connection), FALSE);

	/* clean previous connection */
	if (editor->connection)
		g_object_unref (editor->connection);

	editor->connection = nm_simple_connection_new_clone (orig_connection);

	editor->orig_connection = g_object_ref (orig_connection);
	nm_connection_editor_update_title (editor);

	/* Handle CA cert ignore stuff */
	eap_method_ca_cert_ignore_load (editor->connection);

	s_con = nm_connection_get_setting_connection (editor->connection);
	g_assert (s_con);

	connection_type = nm_setting_connection_get_connection_type (s_con);
	if (!add_page (editor, ce_page_general_new, editor->connection, error))
		goto out;
	if (!strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)) {
		if (!add_page (editor, ce_page_ethernet_new, editor->connection, error))
			goto out;
		if (!add_page (editor, ce_page_8021x_security_new, editor->connection, error))
			goto out;
		if (!add_page (editor, ce_page_dcb_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_WIRELESS_SETTING_NAME)) {
		if (!add_page (editor, ce_page_wifi_new, editor->connection, error))
			goto out;
		if (!add_page (editor, ce_page_wifi_security_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_VPN_SETTING_NAME)) {
		if (!add_page (editor, ce_page_vpn_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_IP_TUNNEL_SETTING_NAME)) {
		if (!add_page (editor, ce_page_ip_tunnel_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) {
		if (!add_page (editor, ce_page_dsl_new, editor->connection, error))
			goto out;
		if (!add_page (editor, ce_page_ethernet_new, editor->connection, error))
			goto out;
		if (!add_page (editor, ce_page_ppp_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_GSM_SETTING_NAME) || 
	           !strcmp (connection_type, NM_SETTING_CDMA_SETTING_NAME)) {
		if (!add_page (editor, ce_page_mobile_new, editor->connection, error))
			goto out;
		if (!add_page (editor, ce_page_ppp_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_BLUETOOTH_SETTING_NAME)) {
		NMSettingBluetooth *s_bt = nm_connection_get_setting_bluetooth (editor->connection);
		const char *type = nm_setting_bluetooth_get_connection_type (s_bt);
		g_assert (type);

		if (!add_page (editor, ce_page_bluetooth_new, editor->connection, error))
			goto out;
		if (!g_strcmp0 (type, "dun")) {
			if (!add_page (editor, ce_page_mobile_new, editor->connection, error))
				goto out;
			if (!add_page (editor, ce_page_ppp_new, editor->connection, error))
				goto out;
		}
	} else if (!strcmp (connection_type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
		if (!add_page (editor, ce_page_infiniband_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_BOND_SETTING_NAME)) {
		if (!add_page (editor, ce_page_bond_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_TEAM_SETTING_NAME)) {
		if (!add_page (editor, ce_page_team_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
		if (!add_page (editor, ce_page_bridge_new, editor->connection, error))
			goto out;
	} else if (!strcmp (connection_type, NM_SETTING_VLAN_SETTING_NAME)) {
		if (!add_page (editor, ce_page_vlan_new, editor->connection, error))
			goto out;
	} else {
		g_warning ("Unhandled setting type '%s'", connection_type);
	}

	slave_type = nm_setting_connection_get_slave_type (s_con);
	if (!g_strcmp0 (slave_type, NM_SETTING_TEAM_SETTING_NAME)) {
		if (!add_page (editor, ce_page_team_port_new, editor->connection, error))
			goto out;
	} else if (!g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
		if (!add_page (editor, ce_page_bridge_port_new, editor->connection, error))
			goto out;
	}

	if (   nm_connection_get_setting_ip4_config (editor->connection)
	    && !add_page (editor, ce_page_ip4_new, editor->connection, error))
		goto out;
	if (   nm_connection_get_setting_ip6_config (editor->connection)
	    && !add_page (editor, ce_page_ip6_new, editor->connection, error))
		goto out;

	/* After all pages are created, then kick off secrets requests that any
	 * the pages may need to make; if they don't need any secrets, then let
	 * them finish initialization.  The list might get modified during the loop
	 * which is why copy the list here.
	 */
	copy = g_slist_copy (editor->initializing_pages);
	for (iter = copy; iter; iter = g_slist_next (iter)) {
		CEPage *page = CE_PAGE (iter->data);
		const char *setting_name = g_object_get_data (G_OBJECT (page), SECRETS_TAG);

		if (!setting_name) {
			/* page doesn't need any secrets */
			ce_page_complete_init (page, NULL, NULL, NULL);
		} else if (!NM_IS_REMOTE_CONNECTION (editor->orig_connection)) {
			/* We want to get secrets using ->orig_connection, since that's the
			 * remote connection which can actually respond to secrets requests.
			 * ->connection is a plain NMConnection copy of ->orig_connection
			 * which is what gets changed when users modify anything.  But when
			 * creating or importing, ->orig_connection will be an NMConnection
			 * since the new connection hasn't been added to NetworkManager yet.
			 * So basically, skip requesting secrets if the connection can't
			 * handle a secrets request.
			 */
			ce_page_complete_init (page, setting_name, NULL, NULL);
		} else {
			/* Page wants secrets, get them */
			get_secrets_for_page (editor, page, setting_name);
		}
		g_object_set_data (G_OBJECT (page), SECRETS_TAG, NULL);
	}
	g_slist_free (copy);

	/* set the UI */
	recheck_initialization (editor);
	success = TRUE;

out:
	return success;
}
static gboolean
verify (NMSetting *setting, GSList *all_settings, GError **error)
{
	NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
	NMSettingConnection *s_con = NULL;
	NMSettingWired *s_wired = NULL;
	GSList *iter;

	for (iter = all_settings; iter; iter = iter->next) {
		if (NM_IS_SETTING_CONNECTION (iter->data))
			s_con = iter->data;
		else if (NM_IS_SETTING_WIRED (iter->data))
			s_wired = iter->data;
	}

	/* If iface_name is specified, it must be a valid interface name. We
	 * don't check that it matches parent and/or id, because we allowing
	 * renaming vlans to arbitrary names.
	 */
	if (priv->iface_name && !nm_utils_iface_valid_name (priv->iface_name)) {
		g_set_error (error,
		             NM_SETTING_VLAN_ERROR,
		             NM_SETTING_VLAN_ERROR_INVALID_PROPERTY,
		             NM_SETTING_VLAN_INTERFACE_NAME);
		return FALSE;
	}

	if (priv->parent) {
		if (nm_utils_is_uuid (priv->parent)) {
			/* If we have an NMSettingConnection:master with slave-type="vlan",
			 * then it must be the same UUID.
			 */
			if (s_con) {
				const char *master = NULL, *slave_type = NULL;

				slave_type = nm_setting_connection_get_slave_type (s_con);
				if (!g_strcmp0 (slave_type, NM_SETTING_VLAN_SETTING_NAME))
					master = nm_setting_connection_get_master (s_con);

				if (master && g_strcmp0 (priv->parent, master) != 0) {
					g_set_error (error,
					             NM_SETTING_VLAN_ERROR,
					             NM_SETTING_VLAN_ERROR_INVALID_PARENT,
					             NM_SETTING_CONNECTION_MASTER);
					return FALSE;
				}
			}
		} else if (!nm_utils_iface_valid_name (priv->parent)) {
			/* parent must be either a UUID or an interface name */
			g_set_error (error,
			             NM_SETTING_VLAN_ERROR,
			             NM_SETTING_VLAN_ERROR_INVALID_PROPERTY,
			             NM_SETTING_VLAN_PARENT);
			return FALSE;
		} 
	} else {
		/* If parent is NULL, the parent must be specified via
		 * NMSettingWired:mac-address.
		 */
		if (!s_wired || !nm_setting_wired_get_mac_address (s_wired)) {
			g_set_error (error,
			             NM_SETTING_VLAN_ERROR,
			             NM_SETTING_VLAN_ERROR_MISSING_PROPERTY,
			             NM_SETTING_VLAN_PARENT);
			return FALSE;
		}
	}

	if (priv->flags & ~(NM_VLAN_FLAG_REORDER_HEADERS |
	                    NM_VLAN_FLAG_GVRP |
	                    NM_VLAN_FLAG_LOOSE_BINDING)) {
		g_set_error (error,
		             NM_SETTING_VLAN_ERROR,
		             NM_SETTING_VLAN_ERROR_INVALID_PROPERTY,
		             NM_SETTING_VLAN_FLAGS);
		return FALSE;
	}

	return TRUE;
}
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
	NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
	NMSettingConnection *s_con;
	NMSettingWired *s_wired;

	if (connection) {
		s_con = nm_connection_get_setting_connection (connection);
		s_wired = nm_connection_get_setting_wired (connection);
	} else {
		s_con = NULL;
		s_wired = NULL;
	}

	if (priv->parent) {
		if (nm_utils_is_uuid (priv->parent)) {
			/* If we have an NMSettingConnection:master with slave-type="vlan",
			 * then it must be the same UUID.
			 */
			if (s_con) {
				const char *master = NULL, *slave_type = NULL;

				slave_type = nm_setting_connection_get_slave_type (s_con);
				if (!g_strcmp0 (slave_type, NM_SETTING_VLAN_SETTING_NAME))
					master = nm_setting_connection_get_master (s_con);

				if (master && g_strcmp0 (priv->parent, master) != 0) {
					g_set_error (error,
					             NM_CONNECTION_ERROR,
					             NM_CONNECTION_ERROR_INVALID_PROPERTY,
					             _("'%s' value doesn't match '%s=%s'"),
					             priv->parent, NM_SETTING_CONNECTION_MASTER, master);
					g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_PARENT);
					return FALSE;
				}
			}
		} else if (!nm_utils_iface_valid_name (priv->parent)) {
			/* parent must be either a UUID or an interface name */
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s' is neither an UUID nor an interface name"),
			             priv->parent);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_PARENT);
			return FALSE;
		}
	} else {
		/* If parent is NULL, the parent must be specified via
		 * NMSettingWired:mac-address.
		 */
		if (   connection
		    && (!s_wired || !nm_setting_wired_get_mac_address (s_wired))) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_MISSING_PROPERTY,
			             _("property is not specified and neither is '%s:%s'"),
			             NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_PARENT);
			return FALSE;
		}
	}

	if (priv->id >= 4095) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("the vlan id must be in range 0-4094 but is %u"),
		             priv->id);
		g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_ID);
	}

	if (priv->flags & ~NM_VLAN_FLAGS_ALL) {
		g_set_error_literal (error,
		                     NM_CONNECTION_ERROR,
		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
		                     _("flags are invalid"));
		g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_FLAGS);
		return FALSE;
	}

	return TRUE;
}