89b8c1a665159f872efb66483fc7ab0ae3d1638d
[NetworkManager.git] / src / nm-ip6-config.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Copyright (C) 2005 - 2010 Red Hat, Inc.
19  * Copyright (C) 2006 - 2008 Novell, Inc.
20  */
21
22 #include <glib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "nm-ip6-config.h"
26 #include "nm-dbus-manager.h"
27 #include "NetworkManager.h"
28 #include "NetworkManagerUtils.h"
29 #include "nm-setting-ip6-config.h"
30 #include "nm-utils.h"
31
32 #include <netlink/route/addr.h>
33 #include <netlink/utils.h>
34 #include <netinet/in.h>
35
36 #include "nm-ip6-config-glue.h"
37 #include "nm-dbus-glib-types.h"
38
39
40 G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, G_TYPE_OBJECT)
41
42 #define NM_IP6_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_CONFIG, NMIP6ConfigPrivate))
43
44 typedef struct {
45         char *path;
46
47         GSList *addresses;
48         struct in6_addr ptp_address;
49
50         guint32 mss;    /* Maximum Segment Size of the route */
51
52         GArray *nameservers;
53         GPtrArray *domains;
54         GPtrArray *searches;
55
56         GSList *routes;
57
58         gboolean never_default;
59 } NMIP6ConfigPrivate;
60
61
62 enum {
63         PROP_0,
64         PROP_ADDRESSES,
65         PROP_NAMESERVERS,
66         PROP_DOMAINS,
67         PROP_ROUTES,
68
69         LAST_PROP
70 };
71
72
73 static struct nl_addr *
74 nm_utils_ip6_addr_to_nl_addr (const struct in6_addr *ip6_addr)
75 {
76         struct nl_addr * nla = NULL;
77
78         if (!(nla = nl_addr_alloc (sizeof (struct in6_addr))))
79                 return NULL;
80         nl_addr_set_family (nla, AF_INET6);
81         nl_addr_set_binary_addr (nla, (struct in6_addr *)ip6_addr, sizeof (struct in6_addr));
82
83         return nla;
84 }
85
86
87 NMIP6Config *
88 nm_ip6_config_new (void)
89 {
90         return (NMIP6Config *) g_object_new (NM_TYPE_IP6_CONFIG, NULL);
91 }
92
93 void
94 nm_ip6_config_export (NMIP6Config *config)
95 {
96         NMIP6ConfigPrivate *priv;
97         NMDBusManager *dbus_mgr;
98         DBusGConnection *connection;
99         static guint32 counter = 0;
100
101         g_return_if_fail (NM_IS_IP6_CONFIG (config));
102
103         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
104         g_return_if_fail (priv->path == NULL);
105
106         dbus_mgr = nm_dbus_manager_get ();
107         connection = nm_dbus_manager_get_connection (dbus_mgr);
108         priv->path = g_strdup_printf (NM_DBUS_PATH "/IP6Config/%d", counter++);
109
110         dbus_g_connection_register_g_object (connection, priv->path, G_OBJECT (config));
111         g_object_unref (dbus_mgr);
112 }
113
114 const char *
115 nm_ip6_config_get_dbus_path (NMIP6Config *config)
116 {
117         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), FALSE);
118
119         return NM_IP6_CONFIG_GET_PRIVATE (config)->path;
120 }
121
122 void
123 nm_ip6_config_take_address (NMIP6Config *config, NMIP6Address *address)
124 {
125         NMIP6ConfigPrivate *priv;
126
127         g_return_if_fail (NM_IS_IP6_CONFIG (config));
128         g_return_if_fail (address != NULL);
129
130         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
131         priv->addresses = g_slist_append (priv->addresses, address);
132 }
133
134 void
135 nm_ip6_config_add_address (NMIP6Config *config,
136                            NMIP6Address *address)
137 {
138         NMIP6ConfigPrivate *priv;
139
140         g_return_if_fail (NM_IS_IP6_CONFIG (config));
141         g_return_if_fail (address != NULL);
142
143         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
144         priv->addresses = g_slist_append (priv->addresses, nm_ip6_address_dup (address));
145 }
146
147 void
148 nm_ip6_config_replace_address (NMIP6Config *config,
149                                guint i,
150                                NMIP6Address *new_address)
151 {
152         NMIP6ConfigPrivate *priv;
153         GSList *old;
154
155         g_return_if_fail (NM_IS_IP6_CONFIG (config));
156
157         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
158         old = g_slist_nth (priv->addresses, i);
159         g_return_if_fail (old != NULL);
160         nm_ip6_address_unref ((NMIP6Address *) old->data);
161
162         old->data = nm_ip6_address_dup (new_address);
163 }
164
165 NMIP6Address *nm_ip6_config_get_address (NMIP6Config *config, guint i)
166 {
167         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
168
169         return (NMIP6Address *) g_slist_nth_data (NM_IP6_CONFIG_GET_PRIVATE (config)->addresses, i);
170 }
171
172 guint32 nm_ip6_config_get_num_addresses (NMIP6Config *config)
173 {
174         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
175
176         return g_slist_length (NM_IP6_CONFIG_GET_PRIVATE (config)->addresses);
177 }
178
179 const struct in6_addr *nm_ip6_config_get_ptp_address (NMIP6Config *config)
180 {
181         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
182
183         return &NM_IP6_CONFIG_GET_PRIVATE (config)->ptp_address;
184 }
185
186 void nm_ip6_config_set_ptp_address (NMIP6Config *config, const struct in6_addr *ptp_addr)
187 {
188         g_return_if_fail (NM_IS_IP6_CONFIG (config));
189
190         NM_IP6_CONFIG_GET_PRIVATE (config)->ptp_address = *ptp_addr;
191 }
192
193 void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver)
194 {
195         NMIP6ConfigPrivate *priv;
196         struct in6_addr *nameservers;
197         int i;
198
199         g_return_if_fail (NM_IS_IP6_CONFIG (config));
200         g_return_if_fail (nameserver != NULL);
201
202         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
203
204         /* No dupes */
205         nameservers = (struct in6_addr *)priv->nameservers->data;
206         for (i = 0; i < priv->nameservers->len; i++) {
207                 g_return_if_fail (memcmp (nameserver, &nameservers[i], sizeof (struct in6_addr)) != 0);
208         }
209
210         g_array_append_val (priv->nameservers, *nameserver);
211 }
212
213 const struct in6_addr *nm_ip6_config_get_nameserver (NMIP6Config *config, guint i)
214 {
215         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
216
217         return &g_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->nameservers, struct in6_addr, i);
218 }
219
220 guint32 nm_ip6_config_get_num_nameservers (NMIP6Config *config)
221 {
222         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
223
224         return NM_IP6_CONFIG_GET_PRIVATE (config)->nameservers->len;
225 }
226
227 void nm_ip6_config_reset_nameservers (NMIP6Config *config)
228 {
229         NMIP6ConfigPrivate *priv;
230
231         g_return_if_fail (NM_IS_IP6_CONFIG (config));
232
233         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
234         if (priv->nameservers->len)
235                 g_array_remove_range (priv->nameservers, 0, priv->nameservers->len);
236 }
237
238 void
239 nm_ip6_config_take_route (NMIP6Config *config, NMIP6Route *route)
240 {
241         NMIP6ConfigPrivate *priv;
242
243         g_return_if_fail (NM_IS_IP6_CONFIG (config));
244         g_return_if_fail (route != NULL);
245
246         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
247         priv->routes = g_slist_append (priv->routes, route);
248 }
249
250 void
251 nm_ip6_config_add_route (NMIP6Config *config, NMIP6Route *route)
252 {
253         NMIP6ConfigPrivate *priv;
254
255         g_return_if_fail (NM_IS_IP6_CONFIG (config));
256         g_return_if_fail (route != NULL);
257
258         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
259         priv->routes = g_slist_append (priv->routes, nm_ip6_route_dup (route));
260 }
261
262 void
263 nm_ip6_config_replace_route (NMIP6Config *config,
264                                                          guint i,
265                                                          NMIP6Route *new_route)
266 {
267         NMIP6ConfigPrivate *priv;
268         GSList *old;
269
270         g_return_if_fail (NM_IS_IP6_CONFIG (config));
271
272         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
273         old = g_slist_nth (priv->routes, i);
274         g_return_if_fail (old != NULL);
275         nm_ip6_route_unref ((NMIP6Route *) old->data);
276
277         old->data = nm_ip6_route_dup (new_route);
278 }
279
280 NMIP6Route *
281 nm_ip6_config_get_route (NMIP6Config *config, guint i)
282 {
283         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
284
285         return (NMIP6Route *) g_slist_nth_data (NM_IP6_CONFIG_GET_PRIVATE (config)->routes, i);
286 }
287
288 guint32 nm_ip6_config_get_num_routes (NMIP6Config *config)
289 {
290         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
291
292         return g_slist_length (NM_IP6_CONFIG_GET_PRIVATE (config)->routes);
293 }
294
295 void nm_ip6_config_reset_routes (NMIP6Config *config)
296 {
297         NMIP6ConfigPrivate *priv;
298
299         g_return_if_fail (NM_IS_IP6_CONFIG (config));
300
301         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
302         g_slist_foreach (priv->routes, (GFunc) g_free, NULL);
303         priv->routes = NULL;
304 }
305
306 void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain)
307 {
308         NMIP6ConfigPrivate *priv;
309         int i;
310
311         g_return_if_fail (NM_IS_IP6_CONFIG (config));
312         g_return_if_fail (domain != NULL);
313         g_return_if_fail (strlen (domain) > 0);
314
315         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
316
317         for (i = 0; i < priv->domains->len; i++) {
318                 if (!strcmp (g_ptr_array_index (priv->domains, i), domain))
319                         return;
320         }
321
322         g_ptr_array_add (priv->domains, g_strdup (domain));
323 }
324
325 const char *nm_ip6_config_get_domain (NMIP6Config *config, guint i)
326 {
327         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
328
329         return (const char *) g_ptr_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->domains, i);
330 }
331
332 guint32 nm_ip6_config_get_num_domains (NMIP6Config *config)
333 {
334         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
335
336         return NM_IP6_CONFIG_GET_PRIVATE (config)->domains->len;
337 }
338
339 void nm_ip6_config_reset_domains (NMIP6Config *config)
340 {
341         NMIP6ConfigPrivate *priv;
342         int i;
343
344         g_return_if_fail (NM_IS_IP6_CONFIG (config));
345
346         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
347         for (i = 0; i < priv->domains->len; i++)
348                 g_free (g_ptr_array_index (priv->domains, i));
349         g_ptr_array_free (priv->domains, TRUE);
350         priv->domains = g_ptr_array_sized_new (3);
351 }
352
353 void nm_ip6_config_add_search (NMIP6Config *config, const char *search)
354 {
355         NMIP6ConfigPrivate *priv;
356         int i;
357
358         g_return_if_fail (config != NULL);
359         g_return_if_fail (search != NULL);
360         g_return_if_fail (strlen (search) > 0);
361
362         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
363
364         for (i = 0; i < priv->searches->len; i++) {
365                 if (!strcmp (g_ptr_array_index (priv->searches, i), search))
366                         return;
367         }
368
369         g_ptr_array_add (priv->searches, g_strdup (search));
370 }
371
372 const char *nm_ip6_config_get_search (NMIP6Config *config, guint i)
373 {
374         g_return_val_if_fail (config != NULL, NULL);
375
376         return (const char *) g_ptr_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->searches, i);
377 }
378
379 guint32 nm_ip6_config_get_num_searches (NMIP6Config *config)
380 {
381         g_return_val_if_fail (config != NULL, 0);
382
383         return NM_IP6_CONFIG_GET_PRIVATE (config)->searches->len;
384 }
385
386 void nm_ip6_config_reset_searches (NMIP6Config *config)
387 {
388         NMIP6ConfigPrivate *priv;
389         int i;
390
391         g_return_if_fail (NM_IS_IP6_CONFIG (config));
392
393         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
394         for (i = 0; i < priv->searches->len; i++)
395                 g_free (g_ptr_array_index (priv->searches, i));
396         g_ptr_array_free (priv->searches, TRUE);
397         priv->searches = g_ptr_array_sized_new (3);
398 }
399
400 guint32 nm_ip6_config_get_mss (NMIP6Config *config)
401 {
402         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
403
404         return NM_IP6_CONFIG_GET_PRIVATE (config)->mss;
405 }
406
407 void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss)
408 {
409         g_return_if_fail (NM_IS_IP6_CONFIG (config));
410
411         NM_IP6_CONFIG_GET_PRIVATE (config)->mss = mss;
412 }
413
414 gboolean
415 nm_ip6_config_get_never_default (NMIP6Config *config)
416 {
417         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), FALSE);
418
419         return NM_IP6_CONFIG_GET_PRIVATE (config)->never_default;
420 }
421
422 void
423 nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default)
424 {
425         g_return_if_fail (NM_IS_IP6_CONFIG (config));
426
427         NM_IP6_CONFIG_GET_PRIVATE (config)->never_default = never_default;
428 }
429
430 /* libnl convenience/conversion functions */
431
432 static int ip6_addr_to_rtnl_local (const struct in6_addr *ip6_address, struct rtnl_addr *addr)
433 {
434         struct nl_addr * local = NULL;
435         int err = 0;
436
437         g_return_val_if_fail (addr != NULL, -1);
438
439         local = nm_utils_ip6_addr_to_nl_addr (ip6_address);
440         err = rtnl_addr_set_local (addr, local);
441         nl_addr_put (local);
442
443         return err;
444 }
445
446 static int ip6_addr_to_rtnl_peer (const struct in6_addr *ip6_address, struct rtnl_addr *addr)
447 {
448         struct nl_addr * peer = NULL;
449         int err = 0;
450
451         g_return_val_if_fail (addr != NULL, -1);
452
453         peer = nm_utils_ip6_addr_to_nl_addr (ip6_address);
454         err = rtnl_addr_set_peer (addr, peer);
455         nl_addr_put (peer);
456
457         return err;
458 }
459
460 struct rtnl_addr *
461 nm_ip6_config_to_rtnl_addr (NMIP6Config *config, guint32 i, guint32 flags)
462 {
463         NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
464         NMIP6Address *config_addr;
465         struct rtnl_addr *addr;
466         gboolean success = TRUE;
467
468         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
469
470         config_addr = nm_ip6_config_get_address (config, i);
471         g_return_val_if_fail (config_addr != NULL, NULL);
472
473         if (!(addr = rtnl_addr_alloc()))
474                 return NULL;
475
476         if (flags & NM_RTNL_ADDR_ADDR)
477                 success = (ip6_addr_to_rtnl_local (nm_ip6_address_get_address (config_addr), addr) >= 0);
478
479         if (flags & NM_RTNL_ADDR_PTP_ADDR)
480                 success = (ip6_addr_to_rtnl_peer (&priv->ptp_address, addr) >= 0);
481
482         if (flags & NM_RTNL_ADDR_PREFIX)
483                 rtnl_addr_set_prefixlen (addr, nm_ip6_address_get_prefix (config_addr));
484
485         if (!success) {
486                 rtnl_addr_put (addr);
487                 addr = NULL;
488         }
489
490         return addr;
491 }
492
493 static gboolean
494 addr_slist_compare (GSList *a, GSList *b)
495 {
496         GSList *iter_a, *iter_b;
497         gboolean found = FALSE;
498
499         for (iter_a = a; iter_a; iter_a = g_slist_next (iter_a)) {
500                 NMIP6Address *addr_a = (NMIP6Address *) iter_a->data;
501
502                 for (iter_b = b, found = FALSE; iter_b; iter_b = g_slist_next (iter_b)) {
503                         NMIP6Address *addr_b = (NMIP6Address *) iter_b->data;
504
505                         if (nm_ip6_address_compare (addr_a, addr_b)) {
506                                 found = TRUE;
507                                 break;
508                         }
509                 }
510
511                 if (!found)
512                         return FALSE;
513         }
514         return TRUE;
515 }
516
517 static gboolean
518 route_slist_compare (GSList *a, GSList *b)
519 {
520         GSList *iter_a, *iter_b;
521         gboolean found = FALSE;
522
523         for (iter_a = a; iter_a; iter_a = g_slist_next (iter_a)) {
524                 NMIP6Route *route_a = (NMIP6Route *) iter_a->data;
525
526                 for (iter_b = b, found = FALSE; iter_b; iter_b = g_slist_next (iter_b)) {
527                         NMIP6Route *route_b = (NMIP6Route *) iter_b->data;
528
529                         if (nm_ip6_route_compare (route_a, route_b)) {
530                                 found = TRUE;
531                                 break;
532                         }
533                 }
534
535                 if (!found)
536                         return FALSE;
537         }
538         return TRUE;
539 }
540
541 static gboolean
542 string_array_compare (GPtrArray *a, GPtrArray *b)
543 {
544         int i, j;
545         gboolean found = FALSE;
546
547         for (i = 0; i < a->len; i++) {
548                 for (j = 0, found = FALSE; j < b->len; j++) {
549                         const char *item_a = g_ptr_array_index (a, i);
550                         const char *item_b = g_ptr_array_index (b, j);
551
552                         if ((!item_a && !item_b) || (item_a && item_b && !strcmp (item_a, item_b))) {
553                                 found = TRUE;
554                                 break;
555                         }
556                 }
557
558                 if (!found)
559                         return FALSE;
560         }
561         return TRUE;
562 }
563
564 static gboolean
565 addr_array_compare (GArray *a, GArray *b)
566 {
567         struct in6_addr *addrs_a, *addrs_b;
568         int i, j;
569         gboolean found = FALSE;
570
571         addrs_a = (struct in6_addr *)a->data;
572         addrs_b = (struct in6_addr *)b->data;
573         for (i = 0; i < a->len; i++) {
574                 for (j = 0, found = FALSE; j < b->len; j++) {
575                         if (memcmp (&addrs_a[i], &addrs_b[j], sizeof (struct in6_addr)) == 0) {
576                                 found = TRUE;
577                                 break;
578                         }
579                 }
580
581                 if (!found)
582                         return FALSE;
583         }
584         return TRUE;
585 }
586
587 NMIP6ConfigCompareFlags
588 nm_ip6_config_diff (NMIP6Config *a, NMIP6Config *b)
589 {
590         NMIP6ConfigPrivate *a_priv;
591         NMIP6ConfigPrivate *b_priv;
592         NMIP6ConfigCompareFlags flags = NM_IP6_COMPARE_FLAG_NONE;
593
594         if ((a && !b) || (b && !a))
595                 return 0xFFFFFFFF;
596         if (!a && !b)
597                 return NM_IP6_COMPARE_FLAG_NONE;
598
599         a_priv = NM_IP6_CONFIG_GET_PRIVATE (a);
600         b_priv = NM_IP6_CONFIG_GET_PRIVATE (b);
601
602         if (   !addr_slist_compare (a_priv->addresses, b_priv->addresses)
603             || !addr_slist_compare (b_priv->addresses, a_priv->addresses))
604                 flags |= NM_IP6_COMPARE_FLAG_ADDRESSES;
605
606         if (memcmp (&a_priv->ptp_address, &b_priv->ptp_address, sizeof (struct in6_addr)) != 0)
607                 flags |= NM_IP6_COMPARE_FLAG_PTP_ADDRESS;
608
609         if (   (a_priv->nameservers->len != b_priv->nameservers->len)
610             || !addr_array_compare (a_priv->nameservers, b_priv->nameservers)
611             || !addr_array_compare (b_priv->nameservers, a_priv->nameservers))
612                 flags |= NM_IP6_COMPARE_FLAG_NAMESERVERS;
613
614         if (   !route_slist_compare (a_priv->routes, b_priv->routes)
615             || !route_slist_compare (b_priv->routes, a_priv->routes))
616                 flags |= NM_IP6_COMPARE_FLAG_ROUTES;
617
618         if (   (a_priv->domains->len != b_priv->domains->len)
619             || !string_array_compare (a_priv->domains, b_priv->domains)
620             || !string_array_compare (b_priv->domains, a_priv->domains))
621                 flags |= NM_IP6_COMPARE_FLAG_DOMAINS;
622
623         if (   (a_priv->searches->len != b_priv->searches->len)
624             || !string_array_compare (a_priv->searches, b_priv->searches)
625             || !string_array_compare (b_priv->searches, a_priv->searches))
626                 flags |= NM_IP6_COMPARE_FLAG_SEARCHES;
627
628         if (a_priv->mss != b_priv->mss)
629                 flags |= NM_IP6_COMPARE_FLAG_MSS;
630
631         return flags;
632 }
633
634 static void
635 nm_ip6_config_init (NMIP6Config *config)
636 {
637         NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
638
639         priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr));
640         priv->domains = g_ptr_array_sized_new (3);
641         priv->searches = g_ptr_array_sized_new (3);
642 }
643
644 static void
645 finalize (GObject *object)
646 {
647         NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
648
649         nm_utils_slist_free (priv->addresses, (GDestroyNotify) nm_ip6_address_unref);
650         nm_utils_slist_free (priv->routes, (GDestroyNotify) nm_ip6_route_unref);
651         g_array_free (priv->nameservers, TRUE);
652         g_ptr_array_free (priv->domains, TRUE);
653         g_ptr_array_free (priv->searches, TRUE);
654
655         G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object);
656 }
657
658 static void
659 get_property (GObject *object, guint prop_id,
660                           GValue *value, GParamSpec *pspec)
661 {
662         NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
663
664         switch (prop_id) {
665         case PROP_ADDRESSES:
666                 nm_utils_ip6_addresses_to_gvalue (priv->addresses, value);
667                 break;
668         case PROP_NAMESERVERS:
669                 g_value_set_boxed (value, priv->nameservers);
670                 break;
671         case PROP_DOMAINS:
672                 g_value_set_boxed (value, priv->domains);
673                 break;
674         case PROP_ROUTES:
675                 nm_utils_ip6_routes_to_gvalue (priv->routes, value);
676                 break;
677         default:
678                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
679                 break;
680         }
681 }
682
683 static void
684 nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
685 {
686         GObjectClass *object_class = G_OBJECT_CLASS (config_class);
687
688         g_type_class_add_private (config_class, sizeof (NMIP6ConfigPrivate));
689
690         /* virtual methods */
691         object_class->get_property = get_property;
692         object_class->finalize = finalize;
693
694         /* properties */
695         g_object_class_install_property (object_class, PROP_ADDRESSES,
696                 g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES,
697                                     "Addresses",
698                                     "IP6 addresses",
699                                     DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
700                                     G_PARAM_READABLE));
701
702         g_object_class_install_property (object_class, PROP_NAMESERVERS,
703                 g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS,
704                                     "Nameservers",
705                                     "DNS list",
706                                     DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR,
707                                     G_PARAM_READABLE));
708
709         g_object_class_install_property (object_class, PROP_DOMAINS,
710                 g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS,
711                                     "Domains",
712                                     "Domains",
713                                     DBUS_TYPE_G_ARRAY_OF_STRING,
714                                     G_PARAM_READABLE));
715
716         g_object_class_install_property (object_class, PROP_ROUTES,
717                 g_param_spec_boxed (NM_IP6_CONFIG_ROUTES,
718                                     "Routes",
719                                     "Routes",
720                                     DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE,
721                                     G_PARAM_READABLE));
722
723         dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (config_class),
724                                                                          &dbus_glib_nm_ip6_config_object_info);
725 }