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