Blame src/connection-editor/page-vlan.c

Packit Service 639700
// SPDX-License-Identifier: GPL-2.0+
Packit fabffb
/* NetworkManager Connection editor -- Connection editor for NetworkManager
Packit fabffb
 *
Packit fabffb
 * Copyright 2008 - 2014 Red Hat, Inc.
Packit fabffb
 */
Packit fabffb
Packit fabffb
#include "nm-default.h"
Packit fabffb
Packit fabffb
#include <stdlib.h>
Packit fabffb
#include <string.h>
Packit fabffb
#include <net/ethernet.h>
Packit fabffb
Packit fabffb
#include "page-vlan.h"
Packit fabffb
#include "connection-helpers.h"
Packit fabffb
#include "nm-connection-editor.h"
Packit fabffb
Packit fabffb
G_DEFINE_TYPE (CEPageVlan, ce_page_vlan, CE_TYPE_PAGE)
Packit fabffb
Packit fabffb
#define CE_PAGE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_VLAN, CEPageVlanPrivate))
Packit fabffb
Packit fabffb
typedef struct {
Packit fabffb
	char *label;
Packit fabffb
	NMDevice *device;
Packit fabffb
	NMConnection *connection;
Packit fabffb
} VlanParent;
Packit fabffb
Packit fabffb
typedef struct {
Packit fabffb
	NMSettingVlan *setting;
Packit fabffb
	NMSetting *s_hw;
Packit fabffb
Packit fabffb
	VlanParent **parents;
Packit fabffb
	char **parent_labels;
Packit fabffb
	int parents_len;
Packit fabffb
Packit fabffb
	GtkWindow *toplevel;
Packit fabffb
Packit fabffb
	GtkComboBox *parent;
Packit fabffb
	GtkEntry *parent_entry;
Packit fabffb
	GtkSpinButton *id_entry;
Packit fabffb
	GtkEntry *name_entry;
Packit fabffb
	GtkComboBoxText *cloned_mac;
Packit fabffb
	GtkSpinButton *mtu;
Packit fabffb
	GtkToggleButton *flag_reorder_hdr, *flag_gvrp, *flag_loose_binding, *flag_mvrp;
Packit fabffb
Packit fabffb
	char *last_parent;
Packit fabffb
	int last_id;
Packit fabffb
} CEPageVlanPrivate;
Packit fabffb
Packit fabffb
static void
Packit fabffb
vlan_private_init (CEPageVlan *self)
Packit fabffb
{
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	GtkBuilder *builder;
Packit fabffb
	GtkWidget *vbox;
Packit fabffb
	GtkLabel *label;
Packit fabffb
Packit fabffb
	builder = CE_PAGE (self)->builder;
Packit fabffb
Packit fabffb
	priv->parent = GTK_COMBO_BOX (gtk_combo_box_text_new_with_entry ());
Packit fabffb
	gtk_combo_box_set_entry_text_column (priv->parent, 0);
Packit fabffb
	priv->parent_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->parent)));
Packit fabffb
Packit fabffb
	vbox = GTK_WIDGET (gtk_builder_get_object (builder, "vlan_parent_vbox"));
Packit fabffb
	gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->parent));
Packit fabffb
	gtk_widget_show_all (GTK_WIDGET (priv->parent));
Packit fabffb
Packit fabffb
	/* Set mnemonic widget for parent label */
Packit fabffb
	label = GTK_LABEL (gtk_builder_get_object (builder, "vlan_parent_label"));
Packit fabffb
	gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->parent));
Packit fabffb
Packit fabffb
	priv->id_entry = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "vlan_id_entry"));
Packit fabffb
	priv->name_entry = GTK_ENTRY (gtk_builder_get_object (builder, "vlan_name_entry"));
Packit fabffb
	priv->cloned_mac = GTK_COMBO_BOX_TEXT (gtk_builder_get_object (builder, "vlan_cloned_mac_entry"));
Packit fabffb
	priv->mtu = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "vlan_mtu"));
Packit fabffb
	priv->flag_reorder_hdr = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "reorder_hdr_flag"));
Packit fabffb
	priv->flag_gvrp = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "gvrp_flag"));
Packit fabffb
	priv->flag_loose_binding = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "loose_binding_flag"));
Packit fabffb
	priv->flag_mvrp = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "mvrp_flag"));
Packit fabffb
Packit fabffb
	priv->toplevel = GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (priv->mtu),
Packit fabffb
	                                                      GTK_TYPE_WINDOW));
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
stuff_changed (GtkWidget *w, gpointer user_data)
Packit fabffb
{
Packit fabffb
	ce_page_changed (CE_PAGE (user_data));
Packit fabffb
}
Packit fabffb
Packit fabffb
static void name_changed (GtkWidget *widget, gpointer user_data);
Packit fabffb
Packit fabffb
static void
Packit fabffb
sync_iface (CEPageVlan *self, GtkEntry *changed_entry)
Packit fabffb
{
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	const char *iface, *iface_end, *parent_text;
Packit fabffb
	char *new_iface, *end;
Packit fabffb
	int iface_id, iface_len, parent_iface_len, id;
Packit fabffb
	gboolean vlan_style_name;
Packit fabffb
Packit fabffb
	iface = gtk_entry_get_text (priv->name_entry);
Packit fabffb
	if (!*iface)
Packit fabffb
		return;
Packit fabffb
Packit fabffb
	if (g_str_has_prefix (iface, "vlan")) {
Packit fabffb
		iface_end = iface + 4;
Packit fabffb
		iface_id = strtoul (iface_end, &end, 10);
Packit fabffb
		vlan_style_name = TRUE;
Packit fabffb
	} else if ((iface_end = strchr (iface, '.'))) {
Packit fabffb
		iface_id = strtoul (iface_end + 1, &end, 10);
Packit fabffb
		vlan_style_name = FALSE;
Packit fabffb
	} else
Packit fabffb
		return;
Packit fabffb
	if (*end)
Packit fabffb
		return;
Packit fabffb
	iface_len = iface_end - iface;
Packit fabffb
Packit fabffb
	parent_text = gtk_entry_get_text (priv->parent_entry);
Packit fabffb
	parent_iface_len = strcspn (parent_text, " ");
Packit fabffb
	id = gtk_spin_button_get_value_as_int (priv->id_entry);
Packit fabffb
Packit fabffb
	if (changed_entry == priv->name_entry) {
Packit fabffb
		/* The user changed the interface name. If it now matches
Packit fabffb
		 * parent and id, then update the last_* members, so we'll
Packit fabffb
		 * start keeping it in sync again.
Packit fabffb
		 */
Packit fabffb
		if (iface_id == id)
Packit fabffb
			priv->last_id = iface_id;
Packit fabffb
		else
Packit fabffb
			priv->last_id = -1;
Packit fabffb
Packit fabffb
		g_free (priv->last_parent);
Packit fabffb
		if (   iface_len == parent_iface_len
Packit fabffb
		    && !strncmp (iface, parent_text, iface_len))
Packit fabffb
			priv->last_parent = g_strndup (iface, iface_len);
Packit fabffb
		else
Packit fabffb
			priv->last_parent = NULL;
Packit fabffb
		return;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	/* The user changed the parent or ID; if the previous parent and
Packit fabffb
	 * ID matched the interface name, then update the interface name
Packit fabffb
	 * to match the new one as well.
Packit fabffb
	 */
Packit fabffb
	if (iface_id != priv->last_id)
Packit fabffb
		return;
Packit fabffb
	if (   !vlan_style_name
Packit fabffb
	    && priv->last_parent
Packit fabffb
	    && strncmp (iface, priv->last_parent, iface_len) != 0)
Packit fabffb
		return;
Packit fabffb
Packit fabffb
	if (vlan_style_name) {
Packit fabffb
		new_iface = g_strdup_printf ("vlan%d", id);
Packit fabffb
	} else if (changed_entry == priv->parent_entry) {
Packit fabffb
		new_iface = g_strdup_printf ("%.*s.%d",
Packit fabffb
		                             parent_iface_len,
Packit fabffb
		                             parent_text, id);
Packit fabffb
	} else {
Packit fabffb
		new_iface = g_strdup_printf ("%.*s.%d", iface_len, iface, id);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_signal_handlers_block_by_func (priv->name_entry, G_CALLBACK (name_changed), self);
Packit fabffb
	gtk_entry_set_text (priv->name_entry, new_iface);
Packit fabffb
	g_signal_handlers_unblock_by_func (priv->name_entry, G_CALLBACK (name_changed), self);
Packit fabffb
Packit fabffb
	g_free (new_iface);
Packit fabffb
Packit fabffb
	if (changed_entry == priv->parent_entry) {
Packit fabffb
		g_free (priv->last_parent);
Packit fabffb
		priv->last_parent = g_strndup (parent_text, parent_iface_len);
Packit fabffb
	} else if (changed_entry == GTK_ENTRY (priv->id_entry))
Packit fabffb
		priv->last_id = id;
Packit fabffb
}
Packit fabffb
Packit fabffb
/* The first item in the combo box may be an arbitrary string not contained in parents array */
Packit fabffb
static int
Packit fabffb
get_parents_index (int parents_len, GtkComboBox *box, int combo_index)
Packit fabffb
{
Packit fabffb
	int size;
Packit fabffb
	GtkTreeModel *model;
Packit fabffb
Packit fabffb
	/* Get number of items in the combo box */
Packit fabffb
	model = gtk_combo_box_get_model (box);
Packit fabffb
	size = gtk_tree_model_iter_n_children (model, NULL);
Packit fabffb
Packit fabffb
	return combo_index - (size - parents_len);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
edit_parent_cb (NMConnectionEditor *editor, GtkResponseType response, gpointer user_data)
Packit fabffb
{
Packit fabffb
	CEPageVlan *self = user_data;
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	NMConnection *connection;
Packit fabffb
	NMConnection *parent;
Packit fabffb
	NMSettingConnection *s_con;
Packit fabffb
Packit fabffb
	if (response != GTK_RESPONSE_OK)
Packit fabffb
		goto finish;
Packit fabffb
Packit fabffb
	connection = nm_connection_editor_get_connection (editor);
Packit fabffb
	parent = (NMConnection *)nm_client_get_connection_by_uuid (CE_PAGE (self)->client,
Packit fabffb
	                                                           nm_connection_get_uuid (connection));
Packit fabffb
Packit fabffb
	s_con = nm_connection_get_setting_connection (parent);
Packit fabffb
	gtk_entry_set_text (priv->parent_entry, nm_setting_connection_get_interface_name (s_con));
Packit fabffb
Packit fabffb
finish:
Packit fabffb
	g_object_unref (editor);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
edit_parent (FUNC_TAG_NEW_CONNECTION_RESULT_IMPL,
Packit fabffb
             NMConnection *connection,
Packit fabffb
             gpointer user_data)
Packit fabffb
{
Packit fabffb
	CEPageVlan *self = user_data;
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	NMSettingConnection *s_con;
Packit fabffb
	NMConnectionEditor *editor;
Packit fabffb
Packit fabffb
	if (!connection)
Packit fabffb
		return;
Packit fabffb
Packit fabffb
	s_con = nm_connection_get_setting_connection (CE_PAGE (self)->connection);
Packit fabffb
	g_object_set (G_OBJECT (s_con),
Packit fabffb
	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
Packit fabffb
	              NULL);
Packit fabffb
Packit fabffb
Packit fabffb
	editor = ce_page_new_editor (CE_PAGE (self), priv->toplevel, connection);
Packit fabffb
	if (!editor)
Packit fabffb
		return;
Packit fabffb
Packit fabffb
	g_signal_connect (editor, NM_CONNECTION_EDITOR_DONE, G_CALLBACK (edit_parent_cb), self);
Packit fabffb
	nm_connection_editor_run (editor);
Packit fabffb
}
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
connection_type_filter (FUNC_TAG_NEW_CONNECTION_TYPE_FILTER_IMPL,
Packit fabffb
                        GType type,
Packit fabffb
                        gpointer self)
Packit fabffb
{
Packit fabffb
	return nm_utils_check_virtual_device_compatibility (NM_TYPE_SETTING_VLAN, type);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parent_changed (GtkWidget *widget, gpointer user_data)
Packit fabffb
{
Packit fabffb
	CEPageVlan *self = user_data;
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	int active_id, parent_id;
Packit fabffb
Packit fabffb
	active_id = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->parent));
Packit fabffb
	parent_id = get_parents_index (priv->parents_len, GTK_COMBO_BOX (priv->parent), active_id);
Packit fabffb
Packit fabffb
	if (parent_id == priv->parents_len - 1) {
Packit fabffb
		gtk_entry_set_text (priv->parent_entry, "");
Packit fabffb
		new_connection_dialog (priv->toplevel,
Packit fabffb
		                       CE_PAGE (self)->client,
Packit fabffb
		                       connection_type_filter,
Packit fabffb
		                       edit_parent,
Packit fabffb
		                       self);
Packit fabffb
		return;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	if (parent_id > -1 && priv->parents[parent_id]->device != NULL) {
Packit fabffb
		gtk_widget_set_sensitive (GTK_WIDGET (priv->cloned_mac), TRUE);
Packit fabffb
		gtk_widget_set_sensitive (GTK_WIDGET (priv->mtu), TRUE);
Packit fabffb
	} else {
Packit fabffb
		gtk_widget_set_sensitive (GTK_WIDGET (priv->cloned_mac), FALSE);
Packit fabffb
		ce_page_setup_cloned_mac_combo (priv->cloned_mac, NULL);
Packit fabffb
		gtk_widget_set_sensitive (GTK_WIDGET (priv->mtu), FALSE);
Packit fabffb
		gtk_spin_button_set_value (priv->mtu, 1500);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	sync_iface (self, priv->parent_entry);
Packit fabffb
	ce_page_changed (CE_PAGE (self));
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
name_changed (GtkWidget *w, gpointer user_data)
Packit fabffb
{
Packit fabffb
	CEPageVlan *self = user_data;
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
Packit fabffb
	sync_iface (self, priv->name_entry);
Packit fabffb
	ce_page_changed (CE_PAGE (self));
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
id_changed (GtkWidget *w, gpointer user_data)
Packit fabffb
{
Packit fabffb
	CEPageVlan *self = user_data;
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
Packit fabffb
	sync_iface (self, GTK_ENTRY (priv->id_entry));
Packit fabffb
	ce_page_changed (CE_PAGE (self));
Packit fabffb
}
Packit fabffb
Packit fabffb
static int
Packit fabffb
sort_parents (gconstpointer a, gconstpointer b)
Packit fabffb
{
Packit fabffb
	VlanParent *pa = *(VlanParent **)a;
Packit fabffb
	VlanParent *pb = *(VlanParent **)b;
Packit fabffb
Packit fabffb
	if (pa->connection && !pb->connection)
Packit fabffb
		return 1;
Packit fabffb
	else if (pb->connection && !pa->connection)
Packit fabffb
		return -1;
Packit fabffb
	return strcmp (pa->label, pb->label);
Packit fabffb
}
Packit fabffb
Packit fabffb
static GSList *
Packit fabffb
get_vlan_devices (CEPageVlan *self)
Packit fabffb
{
Packit fabffb
	const GPtrArray *devices_array;
Packit fabffb
	GSList *devices;
Packit fabffb
	NMDevice *device;
Packit fabffb
	int i;
Packit fabffb
Packit fabffb
	devices_array = nm_client_get_devices (CE_PAGE (self)->client);
Packit fabffb
	devices = NULL;
Packit fabffb
	for (i = 0; i < devices_array->len; i++) {
Packit fabffb
		device = devices_array->pdata[i];
Packit fabffb
Packit fabffb
		if (!nm_utils_check_virtual_device_compatibility (NM_TYPE_SETTING_VLAN,
Packit fabffb
		                                                  nm_device_get_setting_type (device)))
Packit fabffb
			continue;
Packit fabffb
Packit fabffb
		devices = g_slist_prepend (devices, device);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	return devices;
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
build_vlan_parent_list (CEPageVlan *self, GSList *devices)
Packit fabffb
{
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	const GPtrArray *connections;
Packit fabffb
	GSList *d_iter;
Packit fabffb
	GPtrArray *parents;
Packit fabffb
	VlanParent *parent;
Packit fabffb
	NMDevice *device;
Packit fabffb
	const char *iface, *mac, *id;
Packit fabffb
	int i;
Packit fabffb
Packit fabffb
	parents = g_ptr_array_new ();
Packit fabffb
Packit fabffb
	/* Devices with no interesting L2 configuration can spawn VLANs directly. At the
Packit fabffb
	 * moment, this means just Ethernet.
Packit fabffb
	 */
Packit fabffb
	for (d_iter = devices; d_iter; d_iter = d_iter->next) {
Packit fabffb
		device = d_iter->data;
Packit fabffb
Packit fabffb
		if (!NM_IS_DEVICE_ETHERNET (device))
Packit fabffb
			continue;
Packit fabffb
Packit fabffb
		parent = g_slice_new (VlanParent);
Packit fabffb
		parent->device = device;
Packit fabffb
		parent->connection = NULL;
Packit fabffb
Packit fabffb
		iface = nm_device_get_iface (device);
Packit fabffb
		mac = nm_device_ethernet_get_permanent_hw_address (NM_DEVICE_ETHERNET (device));
Packit fabffb
		parent->label = g_strdup_printf ("%s (%s)", iface, mac);
Packit fabffb
Packit fabffb
		g_ptr_array_add (parents, parent);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	/* Otherwise, VLANs have to be built on top of configured connections */
Packit fabffb
	connections = nm_client_get_connections (CE_PAGE (self)->client);
Packit fabffb
	for (i = 0; i < connections->len; i++) {
Packit fabffb
		NMConnection *candidate = connections->pdata[i];
Packit fabffb
		NMSettingConnection *s_con = nm_connection_get_setting_connection (candidate);
Packit fabffb
		GType connection_gtype;
Packit fabffb
Packit fabffb
		if (nm_setting_connection_get_master (s_con))
Packit fabffb
			continue;
Packit fabffb
Packit fabffb
		connection_gtype = nm_setting_lookup_type (nm_setting_connection_get_connection_type (s_con));
Packit fabffb
		if (!nm_utils_check_virtual_device_compatibility (NM_TYPE_SETTING_VLAN, connection_gtype))
Packit fabffb
			continue;
Packit fabffb
Packit fabffb
		for (d_iter = devices; d_iter; d_iter = d_iter->next) {
Packit fabffb
			device = d_iter->data;
Packit fabffb
Packit fabffb
			if (nm_device_connection_valid (device, candidate)) {
Packit fabffb
				parent = g_slice_new (VlanParent);
Packit fabffb
				parent->device = device;
Packit fabffb
				parent->connection = candidate;
Packit fabffb
Packit fabffb
				iface = nm_device_get_iface (device);
Packit fabffb
				id = nm_setting_connection_get_id (s_con);
Packit fabffb
Packit fabffb
				/* Translators: the first %s is a device name (eg, "em1"), the
Packit fabffb
				 * second is a connection name (eg, "Auto Ethernet").
Packit fabffb
				 */
Packit fabffb
				parent->label = g_strdup_printf (_("%s (via “%s”)"), iface, id);
Packit fabffb
				g_ptr_array_add (parents, parent);
Packit fabffb
				/* no break here; the connection may apply to multiple devices */
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_ptr_array_sort (parents, sort_parents);
Packit fabffb
Packit fabffb
	parent = g_slice_new (VlanParent);
Packit fabffb
	parent->device = NULL;
Packit fabffb
	parent->connection = NULL;
Packit fabffb
	parent->label = g_strdup_printf (_("New connection…"));
Packit fabffb
	g_ptr_array_add (parents, parent);
Packit fabffb
Packit fabffb
	g_ptr_array_add (parents, NULL);
Packit fabffb
Packit fabffb
	priv->parent_labels = g_new (char *, parents->len);
Packit fabffb
	priv->parents = (VlanParent **)g_ptr_array_free (parents, FALSE);
Packit fabffb
Packit fabffb
	for (i = 0; priv->parents[i]; i++)
Packit fabffb
		priv->parent_labels[i] = priv->parents[i]->label;
Packit fabffb
	priv->parent_labels[i] = NULL;
Packit fabffb
	priv->parents_len = i;
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
populate_ui (CEPageVlan *self)
Packit fabffb
{
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	GSList *devices, *d_iter;
Packit fabffb
	NMConnection *parent_connection = NULL;
Packit fabffb
	NMDevice *device, *parent_device = NULL;
Packit fabffb
	const char *parent, *iface, *current_parent;
Packit fabffb
	int i, mtu_def, mtu_val;
Packit fabffb
	guint32 flags;
Packit fabffb
Packit fabffb
	devices = get_vlan_devices (self);
Packit fabffb
Packit fabffb
	/* Parent */
Packit fabffb
	build_vlan_parent_list (self, devices);
Packit fabffb
Packit fabffb
	parent = nm_setting_vlan_get_parent (priv->setting);
Packit fabffb
	if (parent) {
Packit fabffb
		/* UUID? */
Packit fabffb
		parent_connection = (NMConnection *)nm_client_get_connection_by_uuid (CE_PAGE (self)->client, parent);
Packit fabffb
		if (!parent_connection) {
Packit fabffb
			/* Interface name? */
Packit fabffb
			for (d_iter = devices; d_iter; d_iter = d_iter->next) {
Packit fabffb
				device = d_iter->data;
Packit fabffb
Packit fabffb
				if (!g_strcmp0 (parent, nm_device_get_iface (device))) {
Packit fabffb
					parent_device = device;
Packit fabffb
					break;
Packit fabffb
				}
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
Packit fabffb
	/* If NMSettingVlan:parent didn't indicate a device, but we have a
Packit fabffb
	 * wired setting, figure out the device from that.
Packit fabffb
	 */
Packit fabffb
	if (priv->s_hw && !parent_device) {
Packit fabffb
		const char *device_mac;
Packit fabffb
		const char *mac;
Packit fabffb
Packit fabffb
		if (NM_IS_SETTING_WIRED (priv->s_hw))
Packit fabffb
			mac = nm_setting_wired_get_mac_address (NM_SETTING_WIRED (priv->s_hw));
Packit fabffb
		else
Packit fabffb
			mac = NULL;
Packit fabffb
Packit fabffb
		if (mac) {
Packit fabffb
			for (d_iter = devices; d_iter; d_iter = d_iter->next) {
Packit fabffb
				device = d_iter->data;
Packit fabffb
Packit fabffb
				if (NM_IS_DEVICE_ETHERNET (device))
Packit fabffb
					device_mac = nm_device_ethernet_get_permanent_hw_address (NM_DEVICE_ETHERNET (device));
Packit fabffb
				else
Packit fabffb
					device_mac = NULL;
Packit fabffb
Packit fabffb
				if (device_mac && nm_utils_hwaddr_matches (mac, -1, device_mac, -1)) {
Packit fabffb
					parent_device = device;
Packit fabffb
					break;
Packit fabffb
				}
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
Packit fabffb
	current_parent = parent;
Packit fabffb
	if (parent_device || parent_connection) {
Packit fabffb
		for (i = 0; priv->parents[i]; i++) {
Packit fabffb
			if (parent_device && parent_device != priv->parents[i]->device)
Packit fabffb
				continue;
Packit fabffb
			if (parent_connection != priv->parents[i]->connection)
Packit fabffb
				continue;
Packit fabffb
Packit fabffb
			current_parent = priv->parents[i]->label;
Packit fabffb
			break;
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
	g_signal_connect (priv->parent, "changed", G_CALLBACK (parent_changed), self);
Packit fabffb
	ce_page_setup_data_combo (CE_PAGE (self), priv->parent, current_parent, priv->parent_labels);
Packit fabffb
Packit fabffb
	if (current_parent)
Packit fabffb
		priv->last_parent = g_strndup (current_parent, strcspn (current_parent, " "));
Packit fabffb
Packit fabffb
	/* Name */
Packit fabffb
	iface = nm_connection_get_interface_name (CE_PAGE (self)->connection);
Packit fabffb
	if (iface)
Packit fabffb
		gtk_entry_set_text (priv->name_entry, iface);
Packit fabffb
	g_signal_connect (priv->name_entry, "changed", G_CALLBACK (name_changed), self);
Packit fabffb
Packit fabffb
	/* ID */
Packit fabffb
	priv->last_id = nm_setting_vlan_get_id (priv->setting);
Packit fabffb
	gtk_spin_button_set_value (priv->id_entry, priv->last_id);
Packit fabffb
	g_signal_connect (priv->id_entry, "value-changed", G_CALLBACK (id_changed), self);
Packit fabffb
Packit fabffb
	/* Cloned MAC address */
Packit fabffb
	if (NM_IS_SETTING_WIRED (priv->s_hw)) {
Packit fabffb
		const char *mac = nm_setting_wired_get_cloned_mac_address (NM_SETTING_WIRED (priv->s_hw));
Packit fabffb
		ce_page_setup_cloned_mac_combo (priv->cloned_mac, mac);
Packit fabffb
	} else {
Packit fabffb
		ce_page_setup_cloned_mac_combo (priv->cloned_mac, NULL);
Packit fabffb
	}
Packit fabffb
	g_signal_connect (priv->cloned_mac, "changed", G_CALLBACK (stuff_changed), self);
Packit fabffb
Packit fabffb
	/* MTU */
Packit fabffb
	if (NM_IS_SETTING_WIRED (priv->s_hw)) {
Packit fabffb
		mtu_def = ce_get_property_default (priv->s_hw, NM_SETTING_WIRED_MTU);
Packit fabffb
		mtu_val = nm_setting_wired_get_mtu (NM_SETTING_WIRED (priv->s_hw));
Packit fabffb
	} else {
Packit fabffb
		mtu_def = mtu_val = 1500;
Packit fabffb
	}
Packit fabffb
	ce_spin_automatic_val (priv->mtu, mtu_def);
Packit fabffb
Packit fabffb
	gtk_spin_button_set_value (priv->mtu, (gdouble) mtu_val);
Packit fabffb
	g_signal_connect (priv->mtu, "value-changed", G_CALLBACK (stuff_changed), self);
Packit fabffb
Packit fabffb
	/* Flags */
Packit fabffb
	flags = nm_setting_vlan_get_flags (priv->setting);
Packit fabffb
	if (flags & NM_VLAN_FLAG_REORDER_HEADERS)
Packit fabffb
		gtk_toggle_button_set_active (priv->flag_reorder_hdr, TRUE);
Packit fabffb
	if (flags & NM_VLAN_FLAG_GVRP)
Packit fabffb
		gtk_toggle_button_set_active (priv->flag_gvrp, TRUE);
Packit fabffb
	if (flags & NM_VLAN_FLAG_LOOSE_BINDING)
Packit fabffb
		gtk_toggle_button_set_active (priv->flag_loose_binding, TRUE);
Packit fabffb
	if (flags & NM_VLAN_FLAG_MVRP)
Packit fabffb
		gtk_toggle_button_set_active (priv->flag_mvrp, TRUE);
Packit fabffb
Packit fabffb
	g_slist_free (devices);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
finish_setup (CEPageVlan *self, gpointer user_data)
Packit fabffb
{
Packit fabffb
	populate_ui (self);
Packit fabffb
}
Packit fabffb
Packit fabffb
CEPage *
Packit fabffb
ce_page_vlan_new (NMConnectionEditor *editor,
Packit fabffb
                  NMConnection *connection,
Packit fabffb
                  GtkWindow *parent_window,
Packit fabffb
                  NMClient *client,
Packit fabffb
                  const char **out_secrets_setting_name,
Packit fabffb
                  GError **error)
Packit fabffb
{
Packit fabffb
	CEPageVlan *self;
Packit fabffb
	CEPageVlanPrivate *priv;
Packit fabffb
Packit fabffb
	self = CE_PAGE_VLAN (ce_page_new (CE_TYPE_PAGE_VLAN,
Packit fabffb
	                                  editor,
Packit fabffb
	                                  connection,
Packit fabffb
	                                  parent_window,
Packit fabffb
	                                  client,
Packit fabffb
	                                  "/org/gnome/nm_connection_editor/ce-page-vlan.ui",
Packit fabffb
	                                  "VlanPage",
Packit fabffb
	                                  _("VLAN")));
Packit fabffb
	if (!self) {
Packit fabffb
		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not load vlan user interface."));
Packit fabffb
		return NULL;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	vlan_private_init (self);
Packit fabffb
	priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
Packit fabffb
	priv->setting = nm_connection_get_setting_vlan (connection);
Packit fabffb
	if (!priv->setting) {
Packit fabffb
		priv->setting = NM_SETTING_VLAN (nm_setting_vlan_new ());
Packit fabffb
		nm_connection_add_setting (connection, NM_SETTING (priv->setting));
Packit fabffb
	}
Packit fabffb
	priv->s_hw = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
Packit fabffb
Packit fabffb
	g_signal_connect (self, CE_PAGE_INITIALIZED, G_CALLBACK (finish_setup), NULL);
Packit fabffb
Packit fabffb
	return CE_PAGE (self);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
ui_to_setting (CEPageVlan *self)
Packit fabffb
{
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	NMConnection *connection = CE_PAGE (self)->connection;
Packit fabffb
	NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
Packit fabffb
	char *cloned_mac = NULL;
Packit fabffb
	VlanParent *parent = NULL;
Packit fabffb
	int active_id, parent_id, vid;
Packit fabffb
	const char *parent_iface = NULL, *parent_uuid = NULL;
Packit fabffb
	const char *slave_type;
Packit fabffb
	const char *iface;
Packit fabffb
	char *tmp_parent_iface = NULL;
Packit fabffb
	GType hwtype;
Packit fabffb
	gboolean mtu_set;
Packit fabffb
	int mtu;
Packit fabffb
	guint32 flags = 0;
Packit fabffb
Packit fabffb
	active_id = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->parent));
Packit fabffb
	parent_id = get_parents_index (priv->parents_len, GTK_COMBO_BOX (priv->parent), active_id);
Packit fabffb
	if (parent_id < 0) {
Packit fabffb
		parent_iface = gtk_entry_get_text (priv->parent_entry);
Packit fabffb
		tmp_parent_iface = g_strndup (parent_iface, strcspn (parent_iface, " "));
Packit fabffb
		parent_iface = tmp_parent_iface;
Packit fabffb
	} else {
Packit fabffb
		parent = priv->parents[parent_id];
Packit fabffb
		if (parent->connection)
Packit fabffb
			parent_uuid = nm_connection_get_uuid (parent->connection);
Packit fabffb
		if (parent->device)
Packit fabffb
			parent_iface = nm_device_get_iface (parent->device);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_assert (parent_uuid != NULL || parent_iface != NULL);
Packit fabffb
Packit fabffb
	slave_type = nm_setting_connection_get_slave_type (s_con);
Packit fabffb
	if (parent_uuid) {
Packit fabffb
		/* Update NMSettingConnection:master if it's set, but don't
Packit fabffb
		 * set it if it's not.
Packit fabffb
		 */
Packit fabffb
		if (!g_strcmp0 (slave_type, NM_SETTING_VLAN_SETTING_NAME)) {
Packit fabffb
			g_object_set (s_con,
Packit fabffb
			              NM_SETTING_CONNECTION_MASTER, parent_uuid,
Packit fabffb
			              NULL);
Packit fabffb
		}
Packit fabffb
	} else if (!g_strcmp0 (slave_type, NM_SETTING_VLAN_SETTING_NAME)) {
Packit fabffb
		g_object_set (s_con,
Packit fabffb
		              NM_SETTING_CONNECTION_MASTER, NULL,
Packit fabffb
		              NM_SETTING_CONNECTION_SLAVE_TYPE, NULL,
Packit fabffb
		              NULL);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	if (parent && NM_IS_DEVICE_ETHERNET (parent->device))
Packit fabffb
		hwtype = NM_TYPE_SETTING_WIRED;
Packit fabffb
	else
Packit fabffb
		hwtype = G_TYPE_NONE;
Packit fabffb
Packit fabffb
	if (priv->s_hw && G_OBJECT_TYPE (priv->s_hw) != hwtype) {
Packit fabffb
		nm_connection_remove_setting (connection, G_OBJECT_TYPE (priv->s_hw));
Packit fabffb
		priv->s_hw = NULL;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	iface = gtk_entry_get_text (priv->name_entry);
Packit fabffb
	vid = gtk_spin_button_get_value_as_int (priv->id_entry);
Packit fabffb
Packit fabffb
	/* Flags */
Packit fabffb
	if (gtk_toggle_button_get_active (priv->flag_reorder_hdr))
Packit fabffb
		flags |= NM_VLAN_FLAG_REORDER_HEADERS;
Packit fabffb
	if (gtk_toggle_button_get_active (priv->flag_gvrp))
Packit fabffb
		flags |= NM_VLAN_FLAG_GVRP;
Packit fabffb
	if (gtk_toggle_button_get_active (priv->flag_loose_binding))
Packit fabffb
		flags |= NM_VLAN_FLAG_LOOSE_BINDING;
Packit fabffb
	if (gtk_toggle_button_get_active (priv->flag_mvrp))
Packit fabffb
		flags |= NM_VLAN_FLAG_MVRP;
Packit fabffb
Packit fabffb
	g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, *iface ? iface : NULL, NULL);
Packit fabffb
	g_object_set (priv->setting,
Packit fabffb
	              NM_SETTING_VLAN_PARENT, parent_uuid ? parent_uuid : parent_iface,
Packit fabffb
	              NM_SETTING_VLAN_ID, vid,
Packit fabffb
	              NM_SETTING_VLAN_FLAGS, flags,
Packit fabffb
	              NULL);
Packit fabffb
Packit fabffb
	if (hwtype != G_TYPE_NONE) {
Packit fabffb
		cloned_mac = ce_page_cloned_mac_get (priv->cloned_mac);
Packit fabffb
		if (cloned_mac && !*cloned_mac)
Packit fabffb
			cloned_mac = NULL;
Packit fabffb
		mtu_set = g_ascii_isdigit (*gtk_entry_get_text (GTK_ENTRY (priv->mtu)));
Packit fabffb
		mtu = gtk_spin_button_get_value_as_int (priv->mtu);
Packit fabffb
Packit fabffb
		if (cloned_mac || mtu_set) {
Packit fabffb
			if (!priv->s_hw) {
Packit fabffb
				priv->s_hw = g_object_new (hwtype, NULL);
Packit fabffb
				nm_connection_add_setting (connection, priv->s_hw);
Packit fabffb
			}
Packit fabffb
Packit fabffb
			g_object_set (priv->s_hw,
Packit fabffb
			              NM_SETTING_WIRED_CLONED_MAC_ADDRESS, cloned_mac,
Packit fabffb
			              NM_SETTING_WIRED_MTU, (guint32) mtu,
Packit fabffb
			              NULL);
Packit fabffb
Packit fabffb
		} else if (priv->s_hw) {
Packit fabffb
			nm_connection_remove_setting (connection, G_OBJECT_TYPE (priv->s_hw));
Packit fabffb
			priv->s_hw = NULL;
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_free (tmp_parent_iface);
Packit fabffb
	g_free (cloned_mac);
Packit fabffb
}
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
ce_page_validate_v (CEPage *page, NMConnection *connection, GError **error)
Packit fabffb
{
Packit fabffb
	CEPageVlan *self = CE_PAGE_VLAN (page);
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	const char *parent;
Packit fabffb
	char *parent_iface;
Packit fabffb
Packit fabffb
	if (gtk_combo_box_get_active (GTK_COMBO_BOX (priv->parent)) == -1) {
Packit fabffb
		parent = gtk_entry_get_text (priv->parent_entry);
Packit fabffb
		parent_iface = g_strndup (parent, strcspn (parent, " "));
Packit fabffb
		if (!ce_page_interface_name_valid (parent_iface, _("vlan parent"), error)) {
Packit fabffb
			g_free (parent_iface);
Packit fabffb
			return FALSE;
Packit fabffb
		}
Packit fabffb
		g_free (parent_iface);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	if (!ce_page_cloned_mac_combo_valid (priv->cloned_mac, ARPHRD_ETHER, _("cloned MAC"), error))
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	ui_to_setting (self);
Packit fabffb
Packit fabffb
	if (   priv->s_hw
Packit fabffb
	    && !nm_setting_verify (priv->s_hw, NULL, error))
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
finalize (GObject *object)
Packit fabffb
{
Packit fabffb
	CEPageVlan *self = CE_PAGE_VLAN (object);
Packit fabffb
	CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
Packit fabffb
	int i;
Packit fabffb
Packit fabffb
	g_free (priv->last_parent);
Packit fabffb
Packit fabffb
	for (i = 0; priv->parents[i]; i++)
Packit fabffb
		g_slice_free (VlanParent, priv->parents[i]);
Packit fabffb
	g_free (priv->parents);
Packit fabffb
Packit fabffb
	G_OBJECT_CLASS (ce_page_vlan_parent_class)->finalize (object);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
ce_page_vlan_init (CEPageVlan *self)
Packit fabffb
{
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
ce_page_vlan_class_init (CEPageVlanClass *vlan_class)
Packit fabffb
{
Packit fabffb
	GObjectClass *object_class = G_OBJECT_CLASS (vlan_class);
Packit fabffb
	CEPageClass *parent_class = CE_PAGE_CLASS (vlan_class);
Packit fabffb
Packit fabffb
	g_type_class_add_private (object_class, sizeof (CEPageVlanPrivate));
Packit fabffb
Packit fabffb
	/* virtual methods */
Packit fabffb
	object_class->finalize = finalize;
Packit fabffb
	parent_class->ce_page_validate_v = ce_page_validate_v;
Packit fabffb
}
Packit fabffb
Packit fabffb
Packit fabffb
void
Packit fabffb
vlan_connection_new (FUNC_TAG_PAGE_NEW_CONNECTION_IMPL,
Packit fabffb
                     GtkWindow *parent,
Packit fabffb
                     const char *detail,
Packit fabffb
                     gpointer detail_data,
Packit fabffb
                     NMConnection *connection,
Packit fabffb
                     NMClient *client,
Packit fabffb
                     PageNewConnectionResultFunc result_func,
Packit fabffb
                     gpointer user_data)
Packit fabffb
{
Packit fabffb
	gs_unref_object NMConnection *connection_tmp = NULL;
Packit fabffb
Packit fabffb
	connection = _ensure_connection_other (connection, &connection_tmp);
Packit fabffb
	ce_page_complete_connection (connection,
Packit fabffb
	                             _("VLAN connection %d"),
Packit fabffb
	                             NM_SETTING_VLAN_SETTING_NAME,
Packit fabffb
	                             TRUE,
Packit fabffb
	                             client);
Packit fabffb
	nm_connection_add_setting (connection, nm_setting_vlan_new ());
Packit fabffb
Packit fabffb
	(*result_func) (FUNC_TAG_PAGE_NEW_CONNECTION_RESULT_CALL, connection, FALSE, NULL, user_data);
Packit fabffb
}