1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	
3    	/*
4    	 * Weiping Pan <wpan@redhat.com>
5    	 *
6    	 * This library is free software; you can redistribute it and/or
7    	 * modify it under the terms of the GNU Lesser General Public
8    	 * License as published by the Free Software Foundation; either
9    	 * version 2 of the License, or (at your option) any later version.
10   	 *
11   	 * This library is distributed in the hope that it will be useful,
12   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   	 * Lesser General Public License for more details.
15   	 *
16   	 * You should have received a copy of the GNU Lesser General Public
17   	 * License along with this library; if not, write to the
18   	 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19   	 * Boston, MA 02110-1301 USA.
20   	 *
21   	 * (C) Copyright 2011 - 2013 Red Hat, Inc.
22   	 */
23   	
24   	#include <stdlib.h>
25   	#include <string.h>
26   	#include <dbus/dbus-glib.h>
27   	#include <glib/gi18n.h>
28   	
29   	#include "nm-setting-vlan.h"
30   	#include "nm-param-spec-specialized.h"
31   	#include "nm-utils.h"
32   	#include "nm-dbus-glib-types.h"
33   	#include "nm-setting-connection.h"
34   	#include "nm-setting-private.h"
35   	
36   	/**
37   	 * SECTION:nm-setting-vlan
38   	 * @short_description: Describes connection properties for VLAN interfaces
39   	 * @include: nm-setting-vlan.h
40   	 *
41   	 * The #NMSettingVlan object is a #NMSetting subclass that describes properties
42   	 * necessary for connection to VLAN interfaces.
43   	 **/
44   	
45   	/**
46   	 * nm_setting_vlan_error_quark:
47   	 *
48   	 * Registers an error quark for #NMSettingVlan if necessary.
49   	 *
50   	 * Returns: the error quark used for #NMSettingVlan errors.
51   	 **/
52   	GQuark
53   	nm_setting_vlan_error_quark (void)
54   	{
55   		static GQuark quark;
56   	
57   		if (G_UNLIKELY (!quark))
58   			quark = g_quark_from_static_string ("nm-setting-vlan-error-quark");
59   		return quark;
60   	}
61   	
62   	G_DEFINE_TYPE_WITH_CODE (NMSettingVlan, nm_setting_vlan, NM_TYPE_SETTING,
63   	                         _nm_register_setting (NM_SETTING_VLAN_SETTING_NAME,
64   	                                               g_define_type_id,
65   	                                               1,
66   	                                               NM_SETTING_VLAN_ERROR))
67   	NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_VLAN)
68   	
69   	#define NM_SETTING_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_VLAN, NMSettingVlanPrivate))
70   	
71   	typedef struct {
72   		char *iface_name;
73   		char *parent;
74   		guint32 id;
75   		guint32 flags;
76   		GSList *ingress_priority_map;
77   		GSList *egress_priority_map;
78   	} NMSettingVlanPrivate;
79   	
80   	enum {
81   		PROP_0,
82   		PROP_IFACE_NAME,
83   		PROP_PARENT,
84   		PROP_ID,
85   		PROP_FLAGS,
86   		PROP_INGRESS_PRIORITY_MAP,
87   		PROP_EGRESS_PRIORITY_MAP,
88   		LAST_PROP
89   	};
90   	
91   	#define MAX_SKB_PRIO   G_MAXUINT32
92   	#define MAX_8021P_PRIO 7  /* Max 802.1p priority */
93   	
94   	typedef struct {
95   		guint32 from;
96   		guint32 to;
97   	} PriorityMap;
98   	
99   	/**
100  	 * nm_setting_vlan_new:
101  	 *
102  	 * Creates a new #NMSettingVlan object with default values.
103  	 *
104  	 * Returns: (transfer full): the new empty #NMSettingVlan object
105  	 **/
106  	NMSetting *
107  	nm_setting_vlan_new (void)
108  	{
109  		return (NMSetting *) g_object_new (NM_TYPE_SETTING_VLAN, NULL);
110  	}
111  	
112  	/**
113  	 * nm_setting_vlan_get_interface_name:
114  	 * @setting: the #NMSettingVlan
115  	 *
116  	 * Returns: the #NMSettingVlan:interface_name property of the setting
117  	 **/
118  	const char *
119  	nm_setting_vlan_get_interface_name (NMSettingVlan *setting)
120  	{
121  		g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), NULL);
122  		return NM_SETTING_VLAN_GET_PRIVATE (setting)->iface_name;
123  	}
124  	
125  	/**
126  	 * nm_setting_vlan_get_parent:
127  	 * @setting: the #NMSettingVlan
128  	 *
129  	 * Returns: the #NMSettingVlan:parent property of the setting
130  	 **/
131  	const char *
132  	nm_setting_vlan_get_parent (NMSettingVlan *setting)
133  	{
134  		g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), NULL);
135  		return NM_SETTING_VLAN_GET_PRIVATE (setting)->parent;
136  	}
137  	
138  	/**
139  	 * nm_setting_vlan_get_id:
140  	 * @setting: the #NMSettingVlan
141  	 *
142  	 * Returns: the #NMSettingVlan:id property of the setting
143  	 **/
144  	guint32
145  	nm_setting_vlan_get_id (NMSettingVlan *setting)
146  	{
147  		g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), 0);
148  		return NM_SETTING_VLAN_GET_PRIVATE (setting)->id;
149  	}
150  	
151  	/**
152  	 * nm_setting_vlan_get_flags:
153  	 * @setting: the #NMSettingVlan
154  	 *
155  	 * Returns: the #NMSettingVlan:flags property of the setting
156  	 **/
157  	guint32
158  	nm_setting_vlan_get_flags (NMSettingVlan *setting)
159  	{
160  		g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), 0);
161  		return NM_SETTING_VLAN_GET_PRIVATE (setting)->flags;
162  	}
163  	
164  	static guint32
165  	get_max_prio (NMVlanPriorityMap map, gboolean from)
166  	{
167  		if (map == NM_VLAN_INGRESS_MAP)
168  			return from ? MAX_8021P_PRIO : MAX_SKB_PRIO;
169  		else if (map == NM_VLAN_EGRESS_MAP)
170  			return from ? MAX_SKB_PRIO : MAX_8021P_PRIO;
171  		g_assert_not_reached ();
172  	}
173  	
174  	static PriorityMap *
175  	priority_map_new_from_str (NMVlanPriorityMap map, const char *str)
176  	{
177  		PriorityMap *p = NULL;
178  		gchar **t = NULL;
179  		guint32 len;
180  		guint64 from, to;
181  	
182  		g_return_val_if_fail (str && str[0], NULL);
183  	
184  		t = g_strsplit (str, ":", 0);
185  		len = g_strv_length (t);
186  		if (len == 2) {
187  			from = g_ascii_strtoull (t[0], NULL, 10);
188  			to = g_ascii_strtoull (t[1], NULL, 10);
189  	
190  			if ((from <= get_max_prio (map, TRUE)) && (to <= get_max_prio (map, FALSE))) {
191  				p = g_malloc0 (sizeof (PriorityMap));
192  				p->from = from;
193  				p->to = to;
194  			}
195  		} else {
196  			/* Warn */
197  			g_warn_if_fail (len == 2);
198  		}
199  	
200  		g_strfreev (t);
201  		return p;
202  	}
203  	
204  	static void
205  	priority_map_free (PriorityMap *map)
206  	{
207  		g_return_if_fail (map != NULL);
208  		g_free (map);
209  	}
210  	
211  	static GSList *
212  	get_map (NMSettingVlan *self, NMVlanPriorityMap map)
213  	{
214  		if (map == NM_VLAN_INGRESS_MAP)
215  			return NM_SETTING_VLAN_GET_PRIVATE (self)->ingress_priority_map;
216  		else if (map == NM_VLAN_EGRESS_MAP)
217  			return NM_SETTING_VLAN_GET_PRIVATE (self)->egress_priority_map;
218  		g_assert_not_reached ();
219  		return NULL;
220  	}
221  	
222  	static void
223  	set_map (NMSettingVlan *self, NMVlanPriorityMap map, GSList *list)
224  	{
225  		if (map == NM_VLAN_INGRESS_MAP) {
226  			NM_SETTING_VLAN_GET_PRIVATE (self)->ingress_priority_map = list;
227  			g_object_notify (G_OBJECT (self), NM_SETTING_VLAN_INGRESS_PRIORITY_MAP);
228  		} else if (map == NM_VLAN_EGRESS_MAP) {
229  			NM_SETTING_VLAN_GET_PRIVATE (self)->egress_priority_map = list;
230  			g_object_notify (G_OBJECT (self), NM_SETTING_VLAN_EGRESS_PRIORITY_MAP);
231  		} else
232  			g_assert_not_reached ();
233  	}
234  	
235  	/**
236  	 * nm_setting_vlan_add_priority_str:
237  	 * @setting: the #NMSettingVlan
238  	 * @map: the type of priority map
239  	 * @str: the string which contains a priority map, like "3:7"
240  	 *
241  	 * Adds a priority map entry into either the #NMSettingVlan:ingress_priority_map
242  	 * or the #NMSettingVlan:egress_priority_map properties.  The priority map maps
243  	 * the Linux SKB priorities to 802.1p priorities.
244  	 *
245  	 * Returns: TRUE if the entry was successfully added to the list, or it
246  	 * overwrote the old value, FALSE if error
247  	 */
248  	gboolean
249  	nm_setting_vlan_add_priority_str (NMSettingVlan *setting,
250  	                                  NMVlanPriorityMap map,
251  	                                  const char *str)
252  	{
253  		NMSettingVlanPrivate *priv = NULL;
254  		GSList *list = NULL, *iter = NULL;
255  		PriorityMap *item = NULL;
256  	
257  		g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE);
258  		g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE);
259  		g_return_val_if_fail (str && str[0], FALSE);
260  	
(1) Event returned_pointer: Pointer "priv" returned by "g_type_instance_get_private((GTypeInstance *)setting, nm_setting_vlan_get_type())" is never used.
261  		priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
262  		list = get_map (setting, map);
263  	
264  		item = priority_map_new_from_str (map, str);
265  		g_return_val_if_fail (item != NULL, FALSE);
266  	
267  		/* Duplicates get replaced */
268  		for (iter = list; iter; iter = g_slist_next (iter)) {
269  			PriorityMap *p = iter->data;
270  	
271  			if (p->from == item->from) {
272  				p->to = item->to;
273  				g_free (item);
274  				if (map == NM_VLAN_INGRESS_MAP)
275  					g_object_notify (G_OBJECT (setting), NM_SETTING_VLAN_INGRESS_PRIORITY_MAP);
276  				else
277  					g_object_notify (G_OBJECT (setting), NM_SETTING_VLAN_EGRESS_PRIORITY_MAP);
278  				return TRUE;
279  			}
280  		}
281  	
282  		set_map (setting, map, g_slist_append (list, item));
283  		return TRUE;
284  	}
285  	
286  	/**
287  	 * nm_setting_vlan_get_num_priorities:
288  	 * @setting: the #NMSettingVlan
289  	 * @map: the type of priority map
290  	 *
291  	 * Returns the number of entires in the
292  	 * #NMSettingVlan:ingress_priority_map or #NMSettingVlan:egress_priority_map
293  	 * properties of this setting.
294  	 *
295  	 * Returns: return the number of ingress/egress priority entries, -1 if error
296  	 **/
297  	gint32
298  	nm_setting_vlan_get_num_priorities (NMSettingVlan *setting, NMVlanPriorityMap map)
299  	{
300  		g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), -1);
301  		g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, -1);
302  	
303  		return g_slist_length (get_map (setting, map));
304  	}
305  	
306  	/**
307  	 * nm_setting_vlan_get_priority:
308  	 * @setting: the #NMSettingVlan
309  	 * @map: the type of priority map
310  	 * @idx: the zero-based index of the ingress/egress priority map entry
311  	 * @out_from: (out): on return the value of the priority map's 'from' item
312  	 * @out_to: (out): on return the value of priority map's 'to' item
313  	 *
314  	 * Retrieve one of the entries of the #NMSettingVlan:ingress_priority_map
315  	 * or #NMSettingVlan:egress_priority_map properties of this setting.
316  	 *
317  	 * Returns: %TRUE if a priority map was returned, %FALSE if error
318  	 **/
319  	gboolean
320  	nm_setting_vlan_get_priority (NMSettingVlan *setting,
321  	                              NMVlanPriorityMap map,
322  	                              guint32 idx,
323  	                              guint32 *out_from,
324  	                              guint32 *out_to)
325  	{
326  		GSList *list = NULL;
327  		PriorityMap *item = NULL;
328  	
329  		g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE);
330  		g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE);
331  		g_return_val_if_fail (out_from != NULL, FALSE);
332  		g_return_val_if_fail (out_to != NULL, FALSE);
333  	
334  		list = get_map (setting, map);
335  		g_return_val_if_fail (idx < g_slist_length (list), FALSE);
336  	
337  		item = g_slist_nth_data (list, idx);
338  		g_assert (item);
339  		*out_from = item->from;
340  		*out_to = item->to;
341  		return TRUE;
342  	}
343  	
344  	/**
345  	 * nm_setting_vlan_add_priority:
346  	 * @setting: the #NMSettingVlan
347  	 * @map: the type of priority map
348  	 * @from: the priority to map to @to
349  	 * @to: the priority to map @from to
350  	 *
351  	 * Adds a priority mapping to the #NMSettingVlan:ingress_priority_map or
352  	 * #NMSettingVlan:egress_priority_map properties of the setting. If @from is
353  	 * already in the given priority map, this function will overwrite the
354  	 * existing entry with the new @to.
355  	 *
356  	 * If @map is #NM_VLAN_INGRESS_MAP then @from is the incoming 802.1q VLAN
357  	 * Priority Code Point (PCP) value, and @to is the Linux SKB priority value.
358  	 *
359  	 * If @map is #NM_VLAN_EGRESS_MAP then @from is the Linux SKB priority value and
360  	 * @to is the outgoing 802.1q VLAN Priority Code Point (PCP) value.
361  	 *
362  	 * Returns: TRUE if the new priority mapping was successfully added to the
363  	 * list, FALSE if error
364  	 */
365  	gboolean
366  	nm_setting_vlan_add_priority (NMSettingVlan *setting,
367  	                              NMVlanPriorityMap map,
368  	                              guint32 from,
369  	                              guint32 to)
370  	{
371  		GSList *list = NULL, *iter = NULL;
372  		PriorityMap *item;
373  	
374  		g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE);
375  		g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE);
376  	
377  		list = get_map (setting, map);
378  		for (iter = list; iter; iter = g_slist_next (iter)) {
379  			item = iter->data;
380  			if (item->from == from) {
381  				item->to = to;
382  				if (map == NM_VLAN_INGRESS_MAP)
383  					g_object_notify (G_OBJECT (setting), NM_SETTING_VLAN_INGRESS_PRIORITY_MAP);
384  				else
385  					g_object_notify (G_OBJECT (setting), NM_SETTING_VLAN_EGRESS_PRIORITY_MAP);
386  				return TRUE;
387  			}
388  		}
389  	
390  		item = g_malloc0 (sizeof (PriorityMap));
391  		item->from = from;
392  		item->to = to;
393  		set_map (setting, map, g_slist_append (list, item));
394  	
395  		return TRUE;
396  	}
397  	
398  	/**
399  	 * nm_setting_vlan_remove_priority:
400  	 * @setting: the #NMSettingVlan
401  	 * @map: the type of priority map
402  	 * @idx: the zero-based index of the priority map to remove
403  	 *
404  	 * Removes the priority map at index @idx from the
405  	 * #NMSettingVlan:ingress_priority_map or #NMSettingVlan:egress_priority_map
406  	 * properties.
407  	 */
408  	void
409  	nm_setting_vlan_remove_priority (NMSettingVlan *setting,
410  	                                 NMVlanPriorityMap map,
411  	                                 guint32 idx)
412  	{
413  		GSList *list = NULL, *item = NULL;
414  	
415  		g_return_if_fail (NM_IS_SETTING_VLAN (setting));
416  		g_return_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP);
417  	
418  		list = get_map (setting, map);
419  		g_return_if_fail (idx < g_slist_length (list));
420  	
421  		item = g_slist_nth (list, idx);
422  		priority_map_free ((PriorityMap *) (item->data));
423  		set_map (setting, map, g_slist_delete_link (list, item));
424  	}
425  	
426  	/**
427  	 * nm_setting_vlan_clear_priorities:
428  	 * @setting: the #NMSettingVlan
429  	 * @map: the type of priority map
430  	 *
431  	 * Clear all the entires from #NMSettingVlan:ingress_priority_map or
432  	 * #NMSettingVlan:egress_priority_map properties.
433  	 */
434  	void
435  	nm_setting_vlan_clear_priorities (NMSettingVlan *setting, NMVlanPriorityMap map)
436  	{
437  		GSList *list = NULL;
438  	
439  		g_return_if_fail (NM_IS_SETTING_VLAN (setting));
440  		g_return_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP);
441  	
442  		list = get_map (setting, map);
443  		g_slist_free_full (list, g_free);
444  		set_map (setting, map, NULL);
445  	}
446  	
447  	/*********************************************************************/
448  	
449  	static void
450  	nm_setting_vlan_init (NMSettingVlan *setting)
451  	{
452  		g_object_set (setting, NM_SETTING_NAME, NM_SETTING_VLAN_SETTING_NAME, NULL);
453  	}
454  	
455  	static gboolean
456  	verify (NMSetting *setting, GSList *all_settings, GError **error)
457  	{
458  		NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
459  		NMSettingConnection *s_con = NULL;
460  		NMSettingWired *s_wired = NULL;
461  		GSList *iter;
462  	
463  		for (iter = all_settings; iter; iter = iter->next) {
464  			if (NM_IS_SETTING_CONNECTION (iter->data))
465  				s_con = iter->data;
466  			else if (NM_IS_SETTING_WIRED (iter->data))
467  				s_wired = iter->data;
468  		}
469  	
470  		/* If iface_name is specified, it must be a valid interface name. We
471  		 * don't check that it matches parent and/or id, because we allowing
472  		 * renaming vlans to arbitrary names.
473  		 */
474  		if (priv->iface_name && !nm_utils_iface_valid_name (priv->iface_name)) {
475  			g_set_error (error,
476  			             NM_SETTING_VLAN_ERROR,
477  			             NM_SETTING_VLAN_ERROR_INVALID_PROPERTY,
478  			             _("'%s' is not a valid interface name"),
479  			             priv->iface_name);
480  			g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_INTERFACE_NAME);
481  			return FALSE;
482  		}
483  	
484  		if (priv->parent) {
485  			if (nm_utils_is_uuid (priv->parent)) {
486  				/* If we have an NMSettingConnection:master with slave-type="vlan",
487  				 * then it must be the same UUID.
488  				 */
489  				if (s_con) {
490  					const char *master = NULL, *slave_type = NULL;
491  	
492  					slave_type = nm_setting_connection_get_slave_type (s_con);
493  					if (!g_strcmp0 (slave_type, NM_SETTING_VLAN_SETTING_NAME))
494  						master = nm_setting_connection_get_master (s_con);
495  	
496  					if (master && g_strcmp0 (priv->parent, master) != 0) {
497  						g_set_error (error,
498  						             NM_SETTING_VLAN_ERROR,
499  						             NM_SETTING_VLAN_ERROR_INVALID_PARENT,
500  						             _("'%s' value doesn't match '%s=%s'"),
501  						             priv->parent, NM_SETTING_CONNECTION_MASTER, master);
502  						g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_PARENT);
503  						return FALSE;
504  					}
505  				}
506  			} else if (!nm_utils_iface_valid_name (priv->parent)) {
507  				/* parent must be either a UUID or an interface name */
508  				g_set_error (error,
509  				             NM_SETTING_VLAN_ERROR,
510  				             NM_SETTING_VLAN_ERROR_INVALID_PROPERTY,
511  				             _("'%s' is neither an UUID nor an interface name"),
512  				             priv->parent);
513  				g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_PARENT);
514  				return FALSE;
515  			} 
516  		} else {
517  			/* If parent is NULL, the parent must be specified via
518  			 * NMSettingWired:mac-address.
519  			 */
520  			if (!s_wired || !nm_setting_wired_get_mac_address (s_wired)) {
521  				g_set_error (error,
522  				             NM_SETTING_VLAN_ERROR,
523  				             NM_SETTING_VLAN_ERROR_MISSING_PROPERTY,
524  				             _("property is not specified and neither is '%s:%s'"),
525  				             NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS);
526  				g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_PARENT);
527  				return FALSE;
528  			}
529  		}
530  	
531  		if (priv->flags & ~(NM_VLAN_FLAG_REORDER_HEADERS |
532  		                    NM_VLAN_FLAG_GVRP |
533  		                    NM_VLAN_FLAG_LOOSE_BINDING)) {
534  			g_set_error_literal (error,
535  			                     NM_SETTING_VLAN_ERROR,
536  			                     NM_SETTING_VLAN_ERROR_INVALID_PROPERTY,
537  			                     _("flags are invalid"));
538  			g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_FLAGS);
539  			return FALSE;
540  		}
541  	
542  		return TRUE;
543  	}
544  	
545  	static const char *
546  	get_virtual_iface_name (NMSetting *setting)
547  	{
548  		return nm_setting_vlan_get_interface_name (NM_SETTING_VLAN (setting));
549  	}
550  	
551  	static GSList *
552  	priority_stringlist_to_maplist (NMVlanPriorityMap map, GSList *strlist)
553  	{
554  		GSList *list = NULL, *iter;
555  	
556  		for (iter = strlist; iter; iter = g_slist_next (iter)) {
557  			PriorityMap *item;
558  	
559  			item = priority_map_new_from_str (map, (const char *) iter->data);
560  			if (item)
561  				list = g_slist_prepend (list, item);
562  		}
563  		return g_slist_reverse (list);
564  	}
565  	
566  	static void
567  	set_property (GObject *object, guint prop_id,
568  	              const GValue *value, GParamSpec *pspec)
569  	{
570  		NMSettingVlan *setting = NM_SETTING_VLAN (object);
571  		NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
572  	
573  		switch (prop_id) {
574  		case PROP_IFACE_NAME:
575  			g_free (priv->iface_name);
576  			priv->iface_name = g_value_dup_string (value);
577  			break;
578  		case PROP_PARENT:
579  			g_free (priv->parent);
580  			priv->parent = g_value_dup_string (value);
581  			break;
582  		case PROP_ID:
583  			priv->id = g_value_get_uint (value);
584  			break;
585  		case PROP_FLAGS:
586  			priv->flags = g_value_get_uint (value);
587  			break;
588  		case PROP_INGRESS_PRIORITY_MAP:
589  			g_slist_free_full (priv->ingress_priority_map, g_free);
590  			priv->ingress_priority_map =
591  				priority_stringlist_to_maplist (NM_VLAN_INGRESS_MAP, g_value_get_boxed (value));
592  			break;
593  		case PROP_EGRESS_PRIORITY_MAP:
594  			g_slist_free_full (priv->egress_priority_map, g_free);
595  			priv->egress_priority_map =
596  				priority_stringlist_to_maplist (NM_VLAN_EGRESS_MAP, g_value_get_boxed (value));
597  			break;
598  		default:
599  			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
600  			break;
601  		}
602  	}
603  	
604  	static GSList *
605  	priority_maplist_to_stringlist (GSList *list)
606  	{
607  		GSList *strlist = NULL, *iter;
608  	
609  		for (iter = list; iter; iter = g_slist_next (iter)) {
610  			PriorityMap *item = iter->data;
611  	
612  			strlist = g_slist_prepend (strlist, g_strdup_printf ("%d:%d", item->from, item->to));
613  		}
614  		return g_slist_reverse (strlist);
615  	}
616  	
617  	static void
618  	get_property (GObject *object, guint prop_id,
619  	              GValue *value, GParamSpec *pspec)
620  	{
621  		NMSettingVlan *setting = NM_SETTING_VLAN (object);
622  		NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
623  	
624  		switch (prop_id) {
625  		case PROP_IFACE_NAME:
626  			g_value_set_string (value, priv->iface_name);
627  			break;
628  		case PROP_PARENT:
629  			g_value_set_string (value, priv->parent);
630  			break;
631  		case PROP_ID:
632  			g_value_set_uint (value, priv->id);
633  			break;
634  		case PROP_FLAGS:
635  			g_value_set_uint (value, priv->flags);
636  			break;
637  		case PROP_INGRESS_PRIORITY_MAP:
638  			g_value_take_boxed (value, priority_maplist_to_stringlist (priv->ingress_priority_map));
639  			break;
640  		case PROP_EGRESS_PRIORITY_MAP:
641  			g_value_take_boxed (value, priority_maplist_to_stringlist (priv->egress_priority_map));
642  			break;
643  		default:
644  			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
645  			break;
646  		}
647  	}
648  	
649  	static void
650  	finalize (GObject *object)
651  	{
652  		NMSettingVlan *setting = NM_SETTING_VLAN (object);
653  		NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
654  	
655  		g_free (priv->iface_name);
656  		g_free (priv->parent);
657  		g_slist_free_full (priv->ingress_priority_map, g_free);
658  		g_slist_free_full (priv->egress_priority_map, g_free);
659  	
660  		G_OBJECT_CLASS (nm_setting_vlan_parent_class)->finalize (object);
661  	}
662  	
663  	static void
664  	nm_setting_vlan_class_init (NMSettingVlanClass *setting_class)
665  	{
666  		GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
667  		NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
668  	
669  		g_type_class_add_private (setting_class, sizeof (NMSettingVlanPrivate));
670  	
671  		/* virtual methods */
672  		object_class->set_property = set_property;
673  		object_class->get_property = get_property;
674  		object_class->finalize     = finalize;
675  		parent_class->verify       = verify;
676  		parent_class->get_virtual_iface_name = get_virtual_iface_name;
677  	
678  		/* Properties */
679  	
680  		/**
681  		 * NMSettingVlan:interface-name:
682  		 *
683  		 * If given, specifies the kernel name of the VLAN interface. If not given,
684  		 * a default name will be constructed from the interface described by the
685  		 * parent interface and the #NMSettingVlan:id , ex 'eth2.1'. The parent
686  		 * interface may be given by the #NMSettingVlan:parent property or by the
687  		 * #NMSettingWired:mac-address property of an #NMSettingWired.
688  		 **/
689  		g_object_class_install_property
690  			(object_class, PROP_IFACE_NAME,
691  			g_param_spec_string (NM_SETTING_VLAN_INTERFACE_NAME,
692  			                     "InterfaceName",
693  			                     "If given, specifies the kernel name of the VLAN "
694  			                     "interface. If not given, a default name will be "
695  			                     "constructed from the interface described by the "
696  			                     "parent interface and the 'id' property, ex "
697  			                     "'eth2.1'. The parent interface may be given by "
698  			                     "the 'parent' property or by the 'mac-address' "
699  			                     "property of a 'wired' setting.",
700  			                     NULL,
701  			                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE));
702  	
703  		/**
704  		 * NMSettingVlan:parent:
705  		 *
706  		 * If given, specifies the parent interface name or parent connection UUID
707  		 * from which this VLAN interface should be created.  If this property is
708  		 * not specified, the connection must contain a #NMSettingWired:mac-address
709  		 * in an #NMSettingWired setting.
710  		 **/
711  		g_object_class_install_property
712  			(object_class, PROP_PARENT,
713  			g_param_spec_string (NM_SETTING_VLAN_PARENT,
714  			                     "Parent",
715  			                     "If given, specifies the parent interface name or "
716  			                     "parent connection UUID from which this VLAN "
717  			                     "interface should be created.  If this property is "
718  			                     "not specified, the connection must contain a "
719  			                     "'wired' setting with a 'mac-address' property.",
720  			                     NULL,
721  			                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE));
722  	
723  		/**
724  		 * NMSettingVlan:id:
725  		 *
726  		 * The VLAN identifier the interface created by this connection should be
727  		 * assigned.
728  		 **/
729  		g_object_class_install_property
730  			(object_class, PROP_ID,
731  			 g_param_spec_uint (NM_SETTING_VLAN_ID,
732  			                    "VLAN ID",
733  			                    "The VLAN indentifier the interface created by "
734  			                    "this connection should be assigned.",
735  			                    0, 4095, 0,
736  			                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE));
737  	
738  		/**
739  		 * NMSettingVlan:flags:
740  		 *
741  		 * One or more of %NMVlanFlags which control the behavior and features of
742  		 * the VLAN interface.
743  		 **/
744  		g_object_class_install_property
745  			(object_class, PROP_FLAGS,
746  			 g_param_spec_uint (NM_SETTING_VLAN_FLAGS,
747  			                    "VLAN flags",
748  			                    "One or more flags which control the behavior and "
749  			                    "features of the VLAN interface.  Flags include "
750  			                    "reordering of output packet headers (0x01), use "
751  			                    "of the GVRP protocol (0x02), and loose binding "
752  			                    "of the interface to its master device's operating "
753  			                    "state (0x04).",
754  			                    0, G_MAXUINT32, 0,
755  			                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE));
756  	
757  		/**
758  		 * NMSettingVlan:ingress-priority-map:
759  		 *
760  		 * For incoming packets, a list of mappings from 802.1p priorities to Linux
761  		 * SKB priorities.  The mapping is given in the format 'from:to' where both
762  		 * 'from' and 'to' are unsigned integers, ie '7:3'.
763  		 **/
764  		g_object_class_install_property
765  			(object_class, PROP_INGRESS_PRIORITY_MAP,
766  			_nm_param_spec_specialized (NM_SETTING_VLAN_INGRESS_PRIORITY_MAP,
767  			                            "VLAN ingress priority mapping",
768  			                            "For incoming packets, a list of mappings "
769  			                            "from 802.1p priorities to Linux SKB "
770  			                            "priorities.  The mapping is given in the "
771  			                            "format 'from:to' where both 'from' and "
772  			                            "'to' are unsigned integers, ie '7:3'.",
773  			                            DBUS_TYPE_G_LIST_OF_STRING,
774  			                            G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
775  	
776  		/**
777  		 * NMSettingVlan:egress-priority-map:
778  		 *
779  		 * For outgoing packets, a list of mappings from Linux SKB priorities to
780  		 * 802.1p priorities.  The mapping is given in the format 'from:to'
781  		 * where both 'from' and 'to' are unsigned integers, ie '7:3'.
782  		 **/
783  		g_object_class_install_property
784  			(object_class, PROP_EGRESS_PRIORITY_MAP,
785  			_nm_param_spec_specialized (NM_SETTING_VLAN_EGRESS_PRIORITY_MAP,
786  			                            "VLAN egress priority mapping",
787  			                            "For outgoing packets, a list of mappings "
788  			                            "from Linux SKB priorities to 802.1p "
789  			                            "priorities.  The mapping is given in the "
790  			                            "format 'from:to' where both 'from' and "
791  			                            "'to' are unsigned integers, ie '7:3'.",
792  			                            DBUS_TYPE_G_LIST_OF_STRING,
793  			                            G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
794  	}
795