ip6: use IN6_ARE_ADDR_EQUAL not memcmp
[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 (IN6_ARE_ADDR_EQUAL (nameserver, &nameservers[i]) == FALSE);
208
209         g_array_append_val (priv->nameservers, *nameserver);
210 }
211
212 const struct in6_addr *nm_ip6_config_get_nameserver (NMIP6Config *config, guint i)
213 {
214         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
215
216         return &g_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->nameservers, struct in6_addr, i);
217 }
218
219 guint32 nm_ip6_config_get_num_nameservers (NMIP6Config *config)
220 {
221         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
222
223         return NM_IP6_CONFIG_GET_PRIVATE (config)->nameservers->len;
224 }
225
226 void nm_ip6_config_reset_nameservers (NMIP6Config *config)
227 {
228         NMIP6ConfigPrivate *priv;
229
230         g_return_if_fail (NM_IS_IP6_CONFIG (config));
231
232         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
233         if (priv->nameservers->len)
234                 g_array_remove_range (priv->nameservers, 0, priv->nameservers->len);
235 }
236
237 void
238 nm_ip6_config_take_route (NMIP6Config *config, NMIP6Route *route)
239 {
240         NMIP6ConfigPrivate *priv;
241
242         g_return_if_fail (NM_IS_IP6_CONFIG (config));
243         g_return_if_fail (route != NULL);
244
245         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
246         priv->routes = g_slist_append (priv->routes, route);
247 }
248
249 void
250 nm_ip6_config_add_route (NMIP6Config *config, NMIP6Route *route)
251 {
252         NMIP6ConfigPrivate *priv;
253
254         g_return_if_fail (NM_IS_IP6_CONFIG (config));
255         g_return_if_fail (route != NULL);
256
257         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
258         priv->routes = g_slist_append (priv->routes, nm_ip6_route_dup (route));
259 }
260
261 void
262 nm_ip6_config_replace_route (NMIP6Config *config,
263                                                          guint i,
264                                                          NMIP6Route *new_route)
265 {
266         NMIP6ConfigPrivate *priv;
267         GSList *old;
268
269         g_return_if_fail (NM_IS_IP6_CONFIG (config));
270
271         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
272         old = g_slist_nth (priv->routes, i);
273         g_return_if_fail (old != NULL);
274         nm_ip6_route_unref ((NMIP6Route *) old->data);
275
276         old->data = nm_ip6_route_dup (new_route);
277 }
278
279 NMIP6Route *
280 nm_ip6_config_get_route (NMIP6Config *config, guint i)
281 {
282         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
283
284         return (NMIP6Route *) g_slist_nth_data (NM_IP6_CONFIG_GET_PRIVATE (config)->routes, i);
285 }
286
287 guint32 nm_ip6_config_get_num_routes (NMIP6Config *config)
288 {
289         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
290
291         return g_slist_length (NM_IP6_CONFIG_GET_PRIVATE (config)->routes);
292 }
293
294 void nm_ip6_config_reset_routes (NMIP6Config *config)
295 {
296         NMIP6ConfigPrivate *priv;
297
298         g_return_if_fail (NM_IS_IP6_CONFIG (config));
299
300         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
301         g_slist_foreach (priv->routes, (GFunc) g_free, NULL);
302         priv->routes = NULL;
303 }
304
305 void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain)
306 {
307         NMIP6ConfigPrivate *priv;
308         int i;
309
310         g_return_if_fail (NM_IS_IP6_CONFIG (config));
311         g_return_if_fail (domain != NULL);
312         g_return_if_fail (strlen (domain) > 0);
313
314         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
315
316         for (i = 0; i < priv->domains->len; i++) {
317                 if (!strcmp (g_ptr_array_index (priv->domains, i), domain))
318                         return;
319         }
320
321         g_ptr_array_add (priv->domains, g_strdup (domain));
322 }
323
324 const char *nm_ip6_config_get_domain (NMIP6Config *config, guint i)
325 {
326         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
327
328         return (const char *) g_ptr_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->domains, i);
329 }
330
331 guint32 nm_ip6_config_get_num_domains (NMIP6Config *config)
332 {
333         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
334
335         return NM_IP6_CONFIG_GET_PRIVATE (config)->domains->len;
336 }
337
338 void nm_ip6_config_reset_domains (NMIP6Config *config)
339 {
340         NMIP6ConfigPrivate *priv;
341         int i;
342
343         g_return_if_fail (NM_IS_IP6_CONFIG (config));
344
345         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
346         for (i = 0; i < priv->domains->len; i++)
347                 g_free (g_ptr_array_index (priv->domains, i));
348         g_ptr_array_free (priv->domains, TRUE);
349         priv->domains = g_ptr_array_sized_new (3);
350 }
351
352 void nm_ip6_config_add_search (NMIP6Config *config, const char *search)
353 {
354         NMIP6ConfigPrivate *priv;
355         int i;
356
357         g_return_if_fail (config != NULL);
358         g_return_if_fail (search != NULL);
359         g_return_if_fail (strlen (search) > 0);
360
361         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
362
363         for (i = 0; i < priv->searches->len; i++) {
364                 if (!strcmp (g_ptr_array_index (priv->searches, i), search))
365                         return;
366         }
367
368         g_ptr_array_add (priv->searches, g_strdup (search));
369 }
370
371 const char *nm_ip6_config_get_search (NMIP6Config *config, guint i)
372 {
373         g_return_val_if_fail (config != NULL, NULL);
374
375         return (const char *) g_ptr_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->searches, i);
376 }
377
378 guint32 nm_ip6_config_get_num_searches (NMIP6Config *config)
379 {
380         g_return_val_if_fail (config != NULL, 0);
381
382         return NM_IP6_CONFIG_GET_PRIVATE (config)->searches->len;
383 }
384
385 void nm_ip6_config_reset_searches (NMIP6Config *config)
386 {
387         NMIP6ConfigPrivate *priv;
388         int i;
389
390         g_return_if_fail (NM_IS_IP6_CONFIG (config));
391
392         priv = NM_IP6_CONFIG_GET_PRIVATE (config);
393         for (i = 0; i < priv->searches->len; i++)
394                 g_free (g_ptr_array_index (priv->searches, i));
395         g_ptr_array_free (priv->searches, TRUE);
396         priv->searches = g_ptr_array_sized_new (3);
397 }
398
399 guint32 nm_ip6_config_get_mss (NMIP6Config *config)
400 {
401         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
402
403         return NM_IP6_CONFIG_GET_PRIVATE (config)->mss;
404 }
405
406 void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss)
407 {
408         g_return_if_fail (NM_IS_IP6_CONFIG (config));
409
410         NM_IP6_CONFIG_GET_PRIVATE (config)->mss = mss;
411 }
412
413 gboolean
414 nm_ip6_config_get_never_default (NMIP6Config *config)
415 {
416         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), FALSE);
417
418         return NM_IP6_CONFIG_GET_PRIVATE (config)->never_default;
419 }
420
421 void
422 nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default)
423 {
424         g_return_if_fail (NM_IS_IP6_CONFIG (config));
425
426         NM_IP6_CONFIG_GET_PRIVATE (config)->never_default = never_default;
427 }
428
429 /* libnl convenience/conversion functions */
430
431 static int ip6_addr_to_rtnl_local (const struct in6_addr *ip6_address, struct rtnl_addr *addr)
432 {
433         struct nl_addr * local = NULL;
434         int err = 0;
435
436         g_return_val_if_fail (addr != NULL, -1);
437
438         local = nm_utils_ip6_addr_to_nl_addr (ip6_address);
439         err = rtnl_addr_set_local (addr, local);
440         nl_addr_put (local);
441
442         return err;
443 }
444
445 static int ip6_addr_to_rtnl_peer (const struct in6_addr *ip6_address, struct rtnl_addr *addr)
446 {
447         struct nl_addr * peer = NULL;
448         int err = 0;
449
450         g_return_val_if_fail (addr != NULL, -1);
451
452         peer = nm_utils_ip6_addr_to_nl_addr (ip6_address);
453         err = rtnl_addr_set_peer (addr, peer);
454         nl_addr_put (peer);
455
456         return err;
457 }
458
459 struct rtnl_addr *
460 nm_ip6_config_to_rtnl_addr (NMIP6Config *config, guint32 i, guint32 flags)
461 {
462         NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
463         NMIP6Address *config_addr;
464         struct rtnl_addr *addr;
465         gboolean success = TRUE;
466
467         g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
468
469         config_addr = nm_ip6_config_get_address (config, i);
470         g_return_val_if_fail (config_addr != NULL, NULL);
471
472         if (!(addr = rtnl_addr_alloc()))
473                 return NULL;
474
475         if (flags & NM_RTNL_ADDR_ADDR)
476                 success = (ip6_addr_to_rtnl_local (nm_ip6_address_get_address (config_addr), addr) >= 0);
477
478         if (flags & NM_RTNL_ADDR_PTP_ADDR)
479                 success = (ip6_addr_to_rtnl_peer (&priv->ptp_address, addr) >= 0);
480
481         if (flags & NM_RTNL_ADDR_PREFIX)
482                 rtnl_addr_set_prefixlen (addr, nm_ip6_address_get_prefix (config_addr));
483
484         if (!success) {
485                 rtnl_addr_put (addr);
486                 addr = NULL;
487         }
488
489         return addr;
490 }
491
492 static gboolean
493 addr_slist_compare (GSList *a, GSList *b)
494 {
495         GSList *iter_a, *iter_b;
496         gboolean found = FALSE;
497
498         for (iter_a = a; iter_a; iter_a = g_slist_next (iter_a)) {
499                 NMIP6Address *addr_a = (NMIP6Address *) iter_a->data;
500
501                 for (iter_b = b, found = FALSE; iter_b; iter_b = g_slist_next (iter_b)) {
502                         NMIP6Address *addr_b = (NMIP6Address *) iter_b->data;
503
504                         if (nm_ip6_address_compare (addr_a, addr_b)) {
505                                 found = TRUE;
506                                 break;
507                         }
508                 }
509
510                 if (!found)
511                         return FALSE;
512         }
513         return TRUE;
514 }
515
516 static gboolean
517 route_slist_compare (GSList *a, GSList *b)
518 {
519         GSList *iter_a, *iter_b;
520         gboolean found = FALSE;
521
522         for (iter_a = a; iter_a; iter_a = g_slist_next (iter_a)) {
523                 NMIP6Route *route_a = (NMIP6Route *) iter_a->data;
524
525                 for (iter_b = b, found = FALSE; iter_b; iter_b = g_slist_next (iter_b)) {
526                         NMIP6Route *route_b = (NMIP6Route *) iter_b->data;
527
528                         if (nm_ip6_route_compare (route_a, route_b)) {
529                                 found = TRUE;
530                                 break;
531                         }
532                 }
533
534                 if (!found)
535                         return FALSE;
536         }
537         return TRUE;
538 }
539
540 static gboolean
541 string_array_compare (GPtrArray *a, GPtrArray *b)
542 {
543         int i, j;
544         gboolean found = FALSE;
545
546         for (i = 0; i < a->len; i++) {
547                 for (j = 0, found = FALSE; j < b->len; j++) {
548                         const char *item_a = g_ptr_array_index (a, i);
549                         const char *item_b = g_ptr_array_index (b, j);
550
551                         if ((!item_a && !item_b) || (item_a && item_b && !strcmp (item_a, item_b))) {
552                                 found = TRUE;
553                                 break;
554                         }
555                 }
556
557                 if (!found)
558                         return FALSE;
559         }
560         return TRUE;
561 }
562
563 static gboolean
564 addr_array_compare (GArray *a, GArray *b)
565 {
566         struct in6_addr *addrs_a, *addrs_b;
567         int i, j;
568         gboolean found = FALSE;
569
570         addrs_a = (struct in6_addr *)a->data;
571         addrs_b = (struct in6_addr *)b->data;
572         for (i = 0; i < a->len; i++) {
573                 for (j = 0, found = FALSE; j < b->len; j++) {
574                         if (IN6_ARE_ADDR_EQUAL (&addrs_a[i], &addrs_b[j])) {
575                                 found = TRUE;
576                                 break;
577                         }
578                 }
579
580                 if (!found)
581                         return FALSE;
582         }
583         return TRUE;
584 }
585
586 NMIP6ConfigCompareFlags
587 nm_ip6_config_diff (NMIP6Config *a, NMIP6Config *b)
588 {
589         NMIP6ConfigPrivate *a_priv;
590         NMIP6ConfigPrivate *b_priv;
591         NMIP6ConfigCompareFlags flags = NM_IP6_COMPARE_FLAG_NONE;
592
593         if ((a && !b) || (b && !a))
594                 return 0xFFFFFFFF;
595         if (!a && !b)
596                 return NM_IP6_COMPARE_FLAG_NONE;
597
598         a_priv = NM_IP6_CONFIG_GET_PRIVATE (a);
599         b_priv = NM_IP6_CONFIG_GET_PRIVATE (b);
600
601         if (   !addr_slist_compare (a_priv->addresses, b_priv->addresses)
602             || !addr_slist_compare (b_priv->addresses, a_priv->addresses))
603                 flags |= NM_IP6_COMPARE_FLAG_ADDRESSES;
604
605         if (memcmp (&a_priv->ptp_address, &b_priv->ptp_address, sizeof (struct in6_addr)) != 0)
606                 flags |= NM_IP6_COMPARE_FLAG_PTP_ADDRESS;
607
608         if (   (a_priv->nameservers->len != b_priv->nameservers->len)
609             || !addr_array_compare (a_priv->nameservers, b_priv->nameservers)
610             || !addr_array_compare (b_priv->nameservers, a_priv->nameservers))
611                 flags |= NM_IP6_COMPARE_FLAG_NAMESERVERS;
612
613         if (   !route_slist_compare (a_priv->routes, b_priv->routes)
614             || !route_slist_compare (b_priv->routes, a_priv->routes))
615                 flags |= NM_IP6_COMPARE_FLAG_ROUTES;
616
617         if (   (a_priv->domains->len != b_priv->domains->len)
618             || !string_array_compare (a_priv->domains, b_priv->domains)
619             || !string_array_compare (b_priv->domains, a_priv->domains))
620                 flags |= NM_IP6_COMPARE_FLAG_DOMAINS;
621
622         if (   (a_priv->searches->len != b_priv->searches->len)
623             || !string_array_compare (a_priv->searches, b_priv->searches)
624             || !string_array_compare (b_priv->searches, a_priv->searches))
625                 flags |= NM_IP6_COMPARE_FLAG_SEARCHES;
626
627         if (a_priv->mss != b_priv->mss)
628                 flags |= NM_IP6_COMPARE_FLAG_MSS;
629
630         return flags;
631 }
632
633 static void
634 nm_ip6_config_init (NMIP6Config *config)
635 {
636         NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
637
638         priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr));
639         priv->domains = g_ptr_array_sized_new (3);
640         priv->searches = g_ptr_array_sized_new (3);
641 }
642
643 static void
644 finalize (GObject *object)
645 {
646         NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
647
648         nm_utils_slist_free (priv->addresses, (GDestroyNotify) nm_ip6_address_unref);
649         nm_utils_slist_free (priv->routes, (GDestroyNotify) nm_ip6_route_unref);
650         g_array_free (priv->nameservers, TRUE);
651         g_ptr_array_free (priv->domains, TRUE);
652         g_ptr_array_free (priv->searches, TRUE);
653
654         G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object);
655 }
656
657 static void
658 get_property (GObject *object, guint prop_id,
659                           GValue *value, GParamSpec *pspec)
660 {
661         NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
662
663         switch (prop_id) {
664         case PROP_ADDRESSES:
665                 nm_utils_ip6_addresses_to_gvalue (priv->addresses, value);
666                 break;
667         case PROP_NAMESERVERS:
668                 g_value_set_boxed (value, priv->nameservers);
669                 break;
670         case PROP_DOMAINS:
671                 g_value_set_boxed (value, priv->domains);
672                 break;
673         case PROP_ROUTES:
674                 nm_utils_ip6_routes_to_gvalue (priv->routes, value);
675                 break;
676         default:
677                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
678                 break;
679         }
680 }
681
682 static void
683 nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
684 {
685         GObjectClass *object_class = G_OBJECT_CLASS (config_class);
686
687         g_type_class_add_private (config_class, sizeof (NMIP6ConfigPrivate));
688
689         /* virtual methods */
690         object_class->get_property = get_property;
691         object_class->finalize = finalize;
692
693         /* properties */
694         g_object_class_install_property (object_class, PROP_ADDRESSES,
695                 g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES,
696                                     "Addresses",
697                                     "IP6 addresses",
698                                     DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
699                                     G_PARAM_READABLE));
700
701         g_object_class_install_property (object_class, PROP_NAMESERVERS,
702                 g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS,
703                                     "Nameservers",
704                                     "DNS list",
705                                     DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR,
706                                     G_PARAM_READABLE));
707
708         g_object_class_install_property (object_class, PROP_DOMAINS,
709                 g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS,
710                                     "Domains",
711                                     "Domains",
712                                     DBUS_TYPE_G_ARRAY_OF_STRING,
713                                     G_PARAM_READABLE));
714
715         g_object_class_install_property (object_class, PROP_ROUTES,
716                 g_param_spec_boxed (NM_IP6_CONFIG_ROUTES,
717                                     "Routes",
718                                     "Routes",
719                                     DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE,
720                                     G_PARAM_READABLE));
721
722         dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (config_class),
723                                                                          &dbus_glib_nm_ip6_config_object_info);
724 }