[network-manager-applet] connection-editor: Add VLAN connection support
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [network-manager-applet] connection-editor: Add VLAN connection support
- Date: Thu, 4 Oct 2012 12:43:53 +0000 (UTC)
commit af406e5f2e206cbd4f756d935466f31210a77669
Author: Dan Winship <danw gnome org>
Date: Tue Jul 31 10:58:39 2012 -0400
connection-editor: Add VLAN connection support
src/connection-editor/Makefile.am | 5 +-
src/connection-editor/ce-page-vlan.ui | 223 +++++++++
src/connection-editor/new-connection.c | 6 +
src/connection-editor/nm-connection-editor.c | 4 +
src/connection-editor/page-vlan.c | 676 ++++++++++++++++++++++++++
src/connection-editor/page-vlan.h | 62 +++
6 files changed, 975 insertions(+), 1 deletions(-)
---
diff --git a/src/connection-editor/Makefile.am b/src/connection-editor/Makefile.am
index 85a1492..08cbb7f 100644
--- a/src/connection-editor/Makefile.am
+++ b/src/connection-editor/Makefile.am
@@ -52,6 +52,8 @@ nm_connection_editor_SOURCES = \
page-vpn.c \
page-bond.h \
page-bond.c \
+ page-vlan.h \
+ page-vlan.c \
vpn-helpers.h \
vpn-helpers.c \
ip4-routes-dialog.h \
@@ -94,7 +96,8 @@ ui_DATA = \
ce-page-dsl.ui \
ce-page-mobile.ui \
ce-page-ppp.ui \
- ce-ppp-auth-methods.ui
+ ce-ppp-auth-methods.ui \
+ ce-page-vlan.ui
BUILT_SOURCES = nm-connection-editor-service-glue.h
diff --git a/src/connection-editor/ce-page-vlan.ui b/src/connection-editor/ce-page-vlan.ui
new file mode 100644
index 0000000..081c8de
--- /dev/null
+++ b/src/connection-editor/ce-page-vlan.ui
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="vlan_id_adjustment">
+ <property name="upper">4095</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkTable" id="VlanPage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">12</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="vlan_parent_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Parent interface:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="vlan_name_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">VLAN interface _name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">vlan_name_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="vlan_cloned_mac_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Cloned MAC address:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">vlan_cloned_mac_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="vlan_cloned_mac_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">â</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="vlan_mtu_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_MTU:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">vlan_mtu</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkSpinButton" id="vlan_mtu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">â</property>
+ <property name="invisible_char_set">True</property>
+ <property name="adjustment">vlan_id_adjustment</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label29">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">bytes</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="vlan_id_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">VLAN _id:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">vlan_id_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="vlan_parent_alignment">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="vlan_id_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">4</property>
+ <property name="invisible_char">â</property>
+ <property name="width_chars">4</property>
+ <property name="invisible_char_set">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="numeric">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="vlan_name_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">â</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkListStore" id="vlan_name_type_model">
+ <columns>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes" comments="In context, this means "concatenate the device name and the VLAN ID number together"">Device name + number</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes" comments="LEAVE "vlan" UNTRANSLATED. In context, this means "concatenate the string 'vlan' and the VLAN ID number together".">"vlan" + number</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="vlan_parent_model">
+ <columns>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+</interface>
diff --git a/src/connection-editor/new-connection.c b/src/connection-editor/new-connection.c
index 69fc0a6..4dc20bd 100644
--- a/src/connection-editor/new-connection.c
+++ b/src/connection-editor/new-connection.c
@@ -32,6 +32,7 @@
#include "page-dsl.h"
#include "page-infiniband.h"
#include "page-bond.h"
+#include "page-vlan.h"
#include "page-vpn.h"
#include "vpn-helpers.h"
@@ -138,6 +139,11 @@ get_connection_type_list (void)
data.virtual = TRUE;
g_array_append_val (array, data);
+ data.name = _("VLAN");
+ data.new_connection_func = vlan_connection_new;
+ data.setting_type = NM_TYPE_SETTING_VLAN;
+ g_array_append_val (array, data);
+
/* Add "VPN" only if there are plugins */
vpn_plugins_hash = vpn_get_plugins (NULL);
have_vpn_plugins = vpn_plugins_hash && g_hash_table_size (vpn_plugins_hash);
diff --git a/src/connection-editor/nm-connection-editor.c b/src/connection-editor/nm-connection-editor.c
index 802b41c..a17e365 100644
--- a/src/connection-editor/nm-connection-editor.c
+++ b/src/connection-editor/nm-connection-editor.c
@@ -69,6 +69,7 @@
#include "page-wimax.h"
#include "page-infiniband.h"
#include "page-bond.h"
+#include "page-vlan.h"
#include "ce-polkit-button.h"
#include "vpn-helpers.h"
@@ -858,6 +859,9 @@ nm_connection_editor_set_connection (NMConnectionEditor *editor,
} 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_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);
}
diff --git a/src/connection-editor/page-vlan.c b/src/connection-editor/page-vlan.c
new file mode 100644
index 0000000..a2b478c
--- /dev/null
+++ b/src/connection-editor/page-vlan.c
@@ -0,0 +1,676 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 - 2011 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <net/ethernet.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <nm-setting-connection.h>
+#include <nm-setting-vlan.h>
+#include <nm-device-ethernet.h>
+#include <nm-utils.h>
+
+#include "page-vlan.h"
+
+G_DEFINE_TYPE (CEPageVlan, ce_page_vlan, CE_TYPE_PAGE)
+
+#define CE_PAGE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_VLAN, CEPageVlanPrivate))
+
+typedef struct {
+ char *label;
+ NMDevice *device;
+ NMConnection *connection;
+} VlanParent;
+
+typedef struct {
+ NMSettingVlan *setting;
+ NMSetting *s_hw;
+
+ VlanParent **parents;
+ char **parent_labels;
+
+ GtkComboBox *parent;
+ GtkEntry *parent_entry;
+ GtkSpinButton *id_entry;
+ GtkEntry *name_entry;
+ GtkEntry *cloned_mac;
+ GtkSpinButton *mtu;
+
+ char *last_parent;
+ int last_id;
+} CEPageVlanPrivate;
+
+static void
+vlan_private_init (CEPageVlan *self)
+{
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+ GtkBuilder *builder;
+ GtkWidget *align;
+ GtkLabel *label;
+
+ builder = CE_PAGE (self)->builder;
+
+#if GTK_CHECK_VERSION(2,24,0)
+ priv->parent = GTK_COMBO_BOX (gtk_combo_box_text_new_with_entry ());
+ gtk_combo_box_set_entry_text_column (priv->parent, 0);
+#else
+ priv->parent = GTK_COMBO_BOX (gtk_combo_box_entry_new_text ());
+ gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (priv->parent), 0);
+#endif
+ priv->parent_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->parent)));
+
+ align = GTK_WIDGET (gtk_builder_get_object (builder, "vlan_parent_alignment"));
+ gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->parent));
+ gtk_widget_show_all (GTK_WIDGET (priv->parent));
+
+ /* Set mnemonic widget for parent label */
+ label = GTK_LABEL (GTK_WIDGET (gtk_builder_get_object (builder, "vlan_parent_label")));
+ gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->parent));
+
+ priv->id_entry = GTK_SPIN_BUTTON (GTK_WIDGET (gtk_builder_get_object (builder, "vlan_id_entry")));
+ priv->name_entry = GTK_ENTRY (GTK_WIDGET (gtk_builder_get_object (builder, "vlan_name_entry")));
+ priv->cloned_mac = GTK_ENTRY (GTK_WIDGET (gtk_builder_get_object (builder, "vlan_cloned_mac_entry")));
+ priv->mtu = GTK_SPIN_BUTTON (GTK_WIDGET (gtk_builder_get_object (builder, "vlan_mtu")));
+}
+
+static void
+stuff_changed (GtkWidget *w, gpointer user_data)
+{
+ ce_page_changed (CE_PAGE (user_data));
+}
+
+static void name_changed (GtkWidget *widget, gpointer user_data);
+
+static void
+sync_iface (CEPageVlan *self, GtkEntry *changed_entry)
+{
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+ const char *iface, *iface_end, *parent_text;
+ char *new_iface, *end;
+ int iface_id, iface_len, parent_iface_len, id;
+ gboolean vlan_style_name;
+
+ iface = gtk_entry_get_text (priv->name_entry);
+ if (!*iface)
+ return;
+
+ if (g_str_has_prefix (iface, "vlan")) {
+ iface_end = iface + 4;
+ iface_id = strtoul (iface_end, &end, 10);
+ vlan_style_name = TRUE;
+ } else if ((iface_end = strchr (iface, '.'))) {
+ iface_id = strtoul (iface_end + 1, &end, 10);
+ vlan_style_name = FALSE;
+ } else
+ return;
+ if (*end)
+ return;
+ iface_len = iface_end - iface;
+
+ parent_text = gtk_entry_get_text (priv->parent_entry);
+ parent_iface_len = strcspn (parent_text, " ");
+ id = gtk_spin_button_get_value_as_int (priv->id_entry);
+
+ if (changed_entry == priv->name_entry) {
+ /* The user changed the interface name. If it now matches
+ * parent and id, then update the last_* members, so we'll
+ * start keeping it in sync again.
+ */
+ if (iface_id == id)
+ priv->last_id = iface_id;
+ else
+ priv->last_id = -1;
+
+ g_free (priv->last_parent);
+ if ( iface_len == parent_iface_len
+ && !strncmp (iface, parent_text, iface_len))
+ priv->last_parent = g_strndup (iface, iface_len);
+ else
+ priv->last_parent = NULL;
+ return;
+ }
+
+ /* The user changed the parent or ID; if the previous parent and
+ * ID matched the interface name, then update the interface name
+ * to match the new one as well.
+ */
+ if (iface_id != priv->last_id)
+ return;
+ if ( !vlan_style_name
+ && priv->last_parent
+ && strncmp (iface, priv->last_parent, iface_len) != 0)
+ return;
+
+ if (vlan_style_name) {
+ new_iface = g_strdup_printf ("vlan%d", id);
+ } else if (changed_entry == priv->parent_entry) {
+ new_iface = g_strdup_printf ("%.*s.%d",
+ parent_iface_len,
+ parent_text, id);
+ } else {
+ new_iface = g_strdup_printf ("%.*s.%d", iface_len, iface, id);
+ }
+
+ g_signal_handlers_block_by_func (priv->name_entry, G_CALLBACK (name_changed), self);
+ gtk_entry_set_text (priv->name_entry, new_iface);
+ g_signal_handlers_unblock_by_func (priv->name_entry, G_CALLBACK (name_changed), self);
+
+ g_free (new_iface);
+
+ if (changed_entry == priv->parent_entry) {
+ g_free (priv->last_parent);
+ priv->last_parent = g_strndup (parent_text, parent_iface_len);
+ } else if (changed_entry == GTK_ENTRY (priv->id_entry))
+ priv->last_id = id;
+}
+
+static void
+parent_changed (GtkWidget *widget, gpointer user_data)
+{
+ CEPageVlan *self = user_data;
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+ int parent_id;
+
+ parent_id = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->parent));
+ if (parent_id > -1 && priv->parents[parent_id]->device != NULL) {
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->cloned_mac), TRUE);
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->mtu), TRUE);
+ } else {
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->cloned_mac), FALSE);
+ gtk_entry_set_text (priv->cloned_mac, "");
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->mtu), FALSE);
+ gtk_spin_button_set_value (priv->mtu, 1500);
+ }
+
+ sync_iface (self, priv->parent_entry);
+ ce_page_changed (CE_PAGE (self));
+}
+
+static void
+name_changed (GtkWidget *w, gpointer user_data)
+{
+ CEPageVlan *self = user_data;
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+
+ sync_iface (self, priv->name_entry);
+ ce_page_changed (CE_PAGE (self));
+}
+
+static void
+id_changed (GtkWidget *w, gpointer user_data)
+{
+ CEPageVlan *self = user_data;
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+
+ sync_iface (self, GTK_ENTRY (priv->id_entry));
+ ce_page_changed (CE_PAGE (self));
+}
+
+static int
+sort_parents (gconstpointer a, gconstpointer b)
+{
+ VlanParent *pa = *(VlanParent **)a;
+ VlanParent *pb = *(VlanParent **)b;
+
+ return strcmp (pa->label, pb->label);
+}
+
+static GSList *
+get_vlan_devices (CEPageVlan *self)
+{
+ const GPtrArray *devices_array;
+ GSList *devices;
+ NMDevice *device;
+ int i;
+
+ devices_array = nm_client_get_devices (CE_PAGE (self)->client);
+ devices = NULL;
+ for (i = 0; devices_array && (i < devices_array->len); i++) {
+ device = devices_array->pdata[i];
+
+ /* FIXME: this supported-device-types logic belongs in NM somewhere. */
+ if (!NM_IS_DEVICE_ETHERNET (device))
+ continue;
+
+ devices = g_slist_prepend (devices, device);
+ }
+
+ return devices;
+}
+
+static void
+build_vlan_parent_list (CEPageVlan *self, GSList *devices)
+{
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+ GSList *connections, *c_iter, *d_iter;
+ GPtrArray *parents;
+ VlanParent *parent;
+ NMDevice *device;
+ const char *iface, *mac, *id;
+ int i;
+
+ parents = g_ptr_array_new ();
+
+ /* Devices with no L2 configuration can spawn VLANs directly. At the
+ * moment, this means just Ethernet.
+ */
+ for (d_iter = devices; d_iter; d_iter = d_iter->next) {
+ device = d_iter->data;
+
+ if (!NM_IS_DEVICE_ETHERNET (device))
+ continue;
+
+ parent = g_slice_new (VlanParent);
+ parent->device = device;
+ parent->connection = NULL;
+
+ iface = nm_device_get_iface (device);
+ mac = nm_device_ethernet_get_permanent_hw_address (NM_DEVICE_ETHERNET (device));
+ parent->label = g_strdup_printf ("%s (%s)", iface, mac);
+
+ g_ptr_array_add (parents, parent);
+ }
+
+ /* Otherwise, VLANs have to be built on top of configured connections */
+ connections = nm_remote_settings_list_connections (CE_PAGE (self)->settings);
+ for (c_iter = connections; c_iter; c_iter = c_iter->next) {
+ NMConnection *candidate = c_iter->data;
+ NMSettingConnection *s_con = nm_connection_get_setting_connection (candidate);
+
+ if (nm_setting_connection_get_master (s_con))
+ continue;
+
+ for (d_iter = devices; d_iter; d_iter = d_iter->next) {
+ device = d_iter->data;
+
+ if (nm_device_connection_valid (device, candidate)) {
+ parent = g_slice_new (VlanParent);
+ parent->device = device;
+ parent->connection = candidate;
+
+ iface = nm_device_get_iface (device);
+ id = nm_setting_connection_get_id (s_con);
+
+ parent->label = g_strdup_printf ("%s (%s)", iface, id);
+ g_ptr_array_add (parents, parent);
+ /* no break here; the connection may apply to multiple devices */
+ }
+ }
+ }
+
+ g_slist_free (connections);
+
+ g_ptr_array_sort (parents, sort_parents);
+ g_ptr_array_add (parents, NULL);
+
+ priv->parent_labels = g_new (char *, parents->len);
+ priv->parents = (VlanParent **)g_ptr_array_free (parents, FALSE);
+
+ for (i = 0; priv->parents[i]; i++)
+ priv->parent_labels[i] = priv->parents[i]->label;
+ priv->parent_labels[i] = NULL;
+}
+
+static void
+populate_ui (CEPageVlan *self)
+{
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+ GSList *devices, *d_iter;
+ NMConnection *parent_connection = NULL;
+ NMDevice *device, *parent_device = NULL;
+ const char *parent, *iface, *current_parent;
+ int i, mtu_def, mtu_val;
+
+ devices = get_vlan_devices (self);
+
+ /* Parent */
+ build_vlan_parent_list (self, devices);
+
+ parent = nm_setting_vlan_get_parent (priv->setting);
+ if (parent) {
+ /* UUID? */
+ parent_connection = (NMConnection *)nm_remote_settings_get_connection_by_uuid (CE_PAGE (self)->settings, parent);
+ if (!parent_connection) {
+ /* Interface name? */
+ for (d_iter = devices; d_iter; d_iter = d_iter->next) {
+ device = d_iter->data;
+
+ if (!g_strcmp0 (parent, nm_device_get_iface (device))) {
+ parent_device = device;
+ break;
+ }
+ }
+ }
+ }
+
+ /* If NMSettingVlan:parent didn't indicate a device, but we have a
+ * wired setting, figure out the device from that.
+ */
+ if (priv->s_hw && !parent_device) {
+ const GByteArray *mac;
+ const char *device_mac_str;
+ char *mac_str;
+
+ if (NM_IS_SETTING_WIRED (priv->s_hw))
+ mac = nm_setting_wired_get_mac_address (NM_SETTING_WIRED (priv->s_hw));
+ else
+ mac = NULL;
+
+ if (mac) {
+ mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
+
+ for (d_iter = devices; d_iter; d_iter = d_iter->next) {
+ device = d_iter->data;
+
+ if (NM_IS_DEVICE_ETHERNET (device))
+ device_mac_str = nm_device_ethernet_get_permanent_hw_address (NM_DEVICE_ETHERNET (device));
+ else
+ device_mac_str = NULL;
+
+ if (!g_strcmp0 (mac_str, device_mac_str)) {
+ parent_device = device;
+ break;
+ }
+ }
+ }
+ }
+
+ current_parent = parent;
+ if (parent_device || parent_connection) {
+ for (i = 0; priv->parents[i]; i++) {
+ if (parent_device && parent_device != priv->parents[i]->device)
+ continue;
+ if (parent_connection && parent_connection != priv->parents[i]->connection)
+ continue;
+
+ current_parent = priv->parents[i]->label;
+ break;
+ }
+ }
+ ce_page_setup_mac_combo (CE_PAGE (self), priv->parent, current_parent, priv->parent_labels);
+ g_signal_connect (priv->parent, "changed", G_CALLBACK (parent_changed), self);
+
+ if (current_parent)
+ priv->last_parent = g_strndup (current_parent, strcspn (current_parent, " "));
+
+ /* Name */
+ iface = nm_setting_vlan_get_interface_name (priv->setting);
+ if (iface)
+ gtk_entry_set_text (priv->name_entry, iface);
+ g_signal_connect (priv->name_entry, "changed", G_CALLBACK (name_changed), self);
+
+ /* ID */
+ priv->last_id = nm_setting_vlan_get_id (priv->setting);
+ gtk_spin_button_set_value (priv->id_entry, priv->last_id);
+ g_signal_connect (priv->id_entry, "value-changed", G_CALLBACK (id_changed), self);
+
+ /* Cloned MAC address */
+ if (NM_IS_SETTING_WIRED (priv->s_hw)) {
+ ce_page_mac_to_entry (nm_setting_wired_get_cloned_mac_address (NM_SETTING_WIRED (priv->s_hw)),
+ ARPHRD_ETHER, priv->cloned_mac);
+ }
+ g_signal_connect (priv->cloned_mac, "changed", G_CALLBACK (stuff_changed), self);
+
+ /* MTU */
+ if (NM_IS_SETTING_WIRED (priv->s_hw)) {
+ mtu_def = ce_get_property_default (priv->s_hw, NM_SETTING_WIRED_MTU);
+ mtu_val = nm_setting_wired_get_mtu (NM_SETTING_WIRED (priv->s_hw));
+ } else {
+ mtu_def = mtu_val = 1500;
+ }
+ g_signal_connect (priv->mtu, "output",
+ G_CALLBACK (ce_spin_output_with_default),
+ GINT_TO_POINTER (mtu_def));
+
+ gtk_spin_button_set_value (priv->mtu, (gdouble) mtu_val);
+ g_signal_connect (priv->mtu, "value-changed", G_CALLBACK (stuff_changed), self);
+
+ g_slist_free (devices);
+}
+
+static void
+finish_setup (CEPageVlan *self, gpointer unused, GError *error, gpointer user_data)
+{
+ if (error)
+ return;
+
+ populate_ui (self);
+}
+
+CEPage *
+ce_page_vlan_new (NMConnection *connection,
+ GtkWindow *parent_window,
+ NMClient *client,
+ NMRemoteSettings *settings,
+ const char **out_secrets_setting_name,
+ GError **error)
+{
+ CEPageVlan *self;
+ CEPageVlanPrivate *priv;
+
+ self = CE_PAGE_VLAN (ce_page_new (CE_TYPE_PAGE_VLAN,
+ connection,
+ parent_window,
+ client,
+ settings,
+ UIDIR "/ce-page-vlan.ui",
+ "VlanPage",
+ _("VLAN")));
+ if (!self) {
+ g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not load vlan user interface."));
+ return NULL;
+ }
+
+ vlan_private_init (self);
+ priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+
+ priv->setting = nm_connection_get_setting_vlan (connection);
+ if (!priv->setting) {
+ priv->setting = NM_SETTING_VLAN (nm_setting_vlan_new ());
+ nm_connection_add_setting (connection, NM_SETTING (priv->setting));
+ }
+ priv->s_hw = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+
+ g_signal_connect (self, "initialized", G_CALLBACK (finish_setup), NULL);
+
+ return CE_PAGE (self);
+}
+
+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;
+ 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);
+ 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;
+ }
+ }
+}
+
+static gboolean
+validate (CEPage *page, NMConnection *connection, GError **error)
+{
+ CEPageVlan *self = CE_PAGE_VLAN (page);
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+ gboolean invalid = FALSE;
+ GByteArray *ignore;
+ int parent_id;
+ const char *parent_iface;
+
+ 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);
+ if (!nm_utils_iface_valid_name (parent_iface))
+ return FALSE;
+ }
+
+ ignore = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, &invalid);
+ if (invalid)
+ return FALSE;
+ if (ignore)
+ g_byte_array_free (ignore, TRUE);
+
+ ui_to_setting (self);
+
+ if ( priv->s_hw
+ && !nm_setting_verify (priv->s_hw, NULL, error))
+ return FALSE;
+
+ return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
+}
+
+static void
+finalize (GObject *object)
+{
+ CEPageVlan *self = CE_PAGE_VLAN (object);
+ CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
+ int i;
+
+ g_free (priv->last_parent);
+
+ for (i = 0; priv->parents[i]; i++)
+ g_slice_free (VlanParent, priv->parents[i]);
+ g_free (priv->parents);
+
+ G_OBJECT_CLASS (ce_page_vlan_parent_class)->finalize (object);
+}
+
+static void
+ce_page_vlan_init (CEPageVlan *self)
+{
+}
+
+static void
+ce_page_vlan_class_init (CEPageVlanClass *vlan_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (vlan_class);
+ CEPageClass *parent_class = CE_PAGE_CLASS (vlan_class);
+
+ g_type_class_add_private (object_class, sizeof (CEPageVlanPrivate));
+
+ /* virtual methods */
+ object_class->finalize = finalize;
+ parent_class->validate = validate;
+}
+
+
+void
+vlan_connection_new (GtkWindow *parent,
+ const char *detail,
+ NMRemoteSettings *settings,
+ PageNewConnectionResultFunc result_func,
+ gpointer user_data)
+{
+ NMConnection *connection;
+
+ connection = ce_page_new_connection (_("VLAN connection %d"),
+ NM_SETTING_VLAN_SETTING_NAME,
+ TRUE,
+ settings,
+ user_data);
+ nm_connection_add_setting (connection, nm_setting_vlan_new ());
+
+ (*result_func) (connection, FALSE, NULL, user_data);
+}
+
diff --git a/src/connection-editor/page-vlan.h b/src/connection-editor/page-vlan.h
new file mode 100644
index 0000000..0e66a06
--- /dev/null
+++ b/src/connection-editor/page-vlan.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 - 2011 Red Hat, Inc.
+ */
+
+#ifndef __PAGE_VLAN_H__
+#define __PAGE_VLAN_H__
+
+#include <nm-connection.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "ce-page.h"
+
+#define CE_TYPE_PAGE_VLAN (ce_page_vlan_get_type ())
+#define CE_PAGE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CE_TYPE_PAGE_VLAN, CEPageVlan))
+#define CE_PAGE_VLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CE_TYPE_PAGE_VLAN, CEPageVlanClass))
+#define CE_IS_PAGE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CE_TYPE_PAGE_VLAN))
+#define CE_IS_PAGE_VLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), CE_TYPE_PAGE_VLAN))
+#define CE_PAGE_VLAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CE_TYPE_PAGE_VLAN, CEPageVlanClass))
+
+typedef struct {
+ CEPage parent;
+} CEPageVlan;
+
+typedef struct {
+ CEPageClass parent;
+} CEPageVlanClass;
+
+GType ce_page_vlan_get_type (void);
+
+CEPage *ce_page_vlan_new (NMConnection *connection,
+ GtkWindow *parent,
+ NMClient *client,
+ NMRemoteSettings *settings,
+ const char **out_secrets_setting_name,
+ GError **error);
+
+void vlan_connection_new (GtkWindow *parent,
+ const char *detail,
+ NMRemoteSettings *settings,
+ PageNewConnectionResultFunc result_func,
+ gpointer user_data);
+
+#endif /* __PAGE_VLAN_H__ */
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]