ip6: log ip configuration state changes
[NetworkManager.git] / src / ip6-manager / nm-ip6-manager.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* nm-ip6-manager.c - Handle IPv6 address configuration for NetworkManager
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, or (at your option)
7  * 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) 2009 - 2010 Red Hat, Inc.
19  */
20
21 #include <errno.h>
22 #include <netinet/icmp6.h>
23
24 #include <netlink/route/addr.h>
25 #include <netlink/route/rtnl.h>
26 #include <netlink/route/route.h>
27
28 #include "nm-ip6-manager.h"
29 #include "nm-netlink-monitor.h"
30 #include "nm-netlink-utils.h"
31 #include "nm-netlink-compat.h"
32 #include "NetworkManagerUtils.h"
33 #include "nm-marshal.h"
34 #include "nm-logging.h"
35
36 /* Pre-DHCP addrconf timeout, in seconds */
37 #define NM_IP6_TIMEOUT 20
38
39 /* FIXME? Stolen from the kernel sources */
40 #define IF_RA_OTHERCONF 0x80
41 #define IF_RA_MANAGED   0x40
42 #define IF_RA_RCVD      0x20
43 #define IF_RS_SENT      0x10
44
45 typedef struct {
46         NMNetlinkMonitor *monitor;
47         GHashTable *devices;
48
49         struct nl_sock *nlh;
50         struct nl_cache *addr_cache, *route_cache;
51
52         guint netlink_id;
53 } NMIP6ManagerPrivate;
54
55 #define NM_IP6_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_MANAGER, NMIP6ManagerPrivate))
56
57 G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT)
58
59 enum {
60         ADDRCONF_COMPLETE,
61         CONFIG_CHANGED,
62         LAST_SIGNAL
63 };
64
65 static guint signals[LAST_SIGNAL] = { 0 };
66
67 typedef enum {
68         NM_IP6_DEVICE_UNCONFIGURED,
69         NM_IP6_DEVICE_GOT_LINK_LOCAL,
70         NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT,
71         NM_IP6_DEVICE_GOT_ADDRESS,
72         NM_IP6_DEVICE_TIMED_OUT
73 } NMIP6DeviceState;
74
75 typedef struct {
76         struct in6_addr addr;
77         time_t expires;
78 } NMIP6RDNSS;
79
80 typedef struct {
81         char domain[256];
82         time_t expires;
83 } NMIP6DNSSL;
84
85 /******************************************************************/
86
87 typedef struct {
88         NMIP6Manager *manager;
89         char *iface;
90         int ifindex;
91
92         gboolean has_linklocal;
93         gboolean has_nonlinklocal;
94         guint dhcp_opts;
95
96         char *disable_ip6_path;
97         gboolean disable_ip6_save_valid;
98         gint32 disable_ip6_save;
99
100         guint finish_addrconf_id;
101         guint config_changed_id;
102
103         NMIP6DeviceState state;
104         NMIP6DeviceState target_state;
105         gboolean addrconf_complete;
106
107         GArray *rdnss_servers;
108         guint rdnss_timeout_id;
109
110         GArray *dnssl_domains;
111         guint dnssl_timeout_id;
112
113         guint ip6flags_poll_id;
114
115         guint32 ra_flags;
116 } NMIP6Device;
117
118 static void
119 clear_config_changed (NMIP6Device *device)
120 {
121         if (device->config_changed_id)
122                 g_source_remove (device->config_changed_id);
123         device->config_changed_id = 0;
124 }
125
126 static void
127 nm_ip6_device_destroy (NMIP6Device *device)
128 {
129         g_return_if_fail (device != NULL);
130
131         /* reset the saved IPv6 value */
132         if (device->disable_ip6_save_valid) {
133                 nm_utils_do_sysctl (device->disable_ip6_path,
134                                     device->disable_ip6_save ? "1\n" : "0\n");
135         }
136
137         if (device->finish_addrconf_id)
138                 g_source_remove (device->finish_addrconf_id);
139
140         clear_config_changed (device);
141
142         g_free (device->iface);
143         if (device->rdnss_servers)
144                 g_array_free (device->rdnss_servers, TRUE);
145         if (device->rdnss_timeout_id)
146                 g_source_remove (device->rdnss_timeout_id);
147         if (device->dnssl_domains)
148                 g_array_free (device->dnssl_domains, TRUE);
149         if (device->dnssl_timeout_id)
150                 g_source_remove (device->dnssl_timeout_id);
151         if (device->ip6flags_poll_id)
152                 g_source_remove (device->ip6flags_poll_id);
153
154         g_slice_free (NMIP6Device, device);
155 }
156
157 static NMIP6Device *
158 nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
159 {
160         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
161         NMIP6Device *device;
162
163         g_return_val_if_fail (ifindex > 0, NULL);
164
165         device = g_slice_new0 (NMIP6Device);
166         if (!device) {
167                 nm_log_err (LOGD_IP6, "(%d): out of memory creating IP6 addrconf object.",
168                             ifindex);
169                 return NULL;
170         }
171
172         device->ifindex = ifindex;
173         device->iface = nm_netlink_index_to_iface (ifindex);
174         if (!device->iface) {
175                 nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.",
176                             ifindex);
177                 goto error;
178         }
179
180         device->manager = manager;
181
182         device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
183
184         device->dnssl_domains = g_array_new (FALSE, FALSE, sizeof (NMIP6DNSSL));
185
186         g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device);
187
188         /* and the original value of IPv6 enable/disable */
189         device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
190                                                     device->iface);
191         g_assert (device->disable_ip6_path);
192         device->disable_ip6_save_valid = nm_utils_get_proc_sys_net_value_with_bounds (device->disable_ip6_path,
193                                                                                       device->iface,
194                                                                                       &device->disable_ip6_save,
195                                                                                       0, 1);
196
197         return device;
198
199 error:
200         nm_ip6_device_destroy (device);
201         return NULL;
202 }
203
204 static NMIP6Device *
205 nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex)
206 {
207         NMIP6ManagerPrivate *priv;
208
209         g_return_val_if_fail (manager != NULL, NULL);
210         g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
211
212         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
213         return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
214 }
215
216 static char *
217 device_get_iface (NMIP6Device *device)
218 {
219         return device ? device->iface : "unknown";
220 }
221
222 static const char *
223 state_to_string (NMIP6DeviceState state)
224 {
225         switch (state) {
226         case NM_IP6_DEVICE_UNCONFIGURED:
227                 return "unconfigured";
228         case NM_IP6_DEVICE_GOT_LINK_LOCAL:
229                 return "got-link-local";
230         case NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT:
231                 return "got-ra";
232         case NM_IP6_DEVICE_GOT_ADDRESS:
233                 return "got-address";
234         case NM_IP6_DEVICE_TIMED_OUT:
235                 return "timed-out";
236         default:
237                 return "unknown";
238         }
239 }
240
241 static void
242 device_set_state (NMIP6Device *device, NMIP6DeviceState state)
243 {
244         NMIP6DeviceState oldstate;
245
246         oldstate = device->state;
247
248         device->state = state;
249         nm_log_dbg (LOGD_IP6, "(%s) IP6 device state: %s -> %s",
250                     device_get_iface (device), state_to_string (oldstate), state_to_string (state));
251 }
252
253 /******************************************************************/
254
255 typedef struct {
256         NMIP6Device *device;
257         guint dhcp_opts;
258         gboolean success;
259 } CallbackInfo;
260
261 static gboolean
262 finish_addrconf (gpointer user_data)
263 {
264         CallbackInfo *info = user_data;
265         NMIP6Device *device = info->device;
266         NMIP6Manager *manager = device->manager;
267         int ifindex;
268
269         device->finish_addrconf_id = 0;
270         device->addrconf_complete = TRUE;
271         ifindex = device->ifindex;
272
273         /* We're done, stop polling IPv6 flags */
274         if (device->ip6flags_poll_id) {
275                 g_source_remove (device->ip6flags_poll_id);
276                 device->ip6flags_poll_id = 0;
277         }
278
279         /* And tell listeners that addrconf is complete */
280         if (info->success) {
281                 g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
282                                ifindex, info->dhcp_opts, TRUE);
283         } else {
284                 nm_log_info (LOGD_IP6, "(%s): IP6 addrconf timed out or failed.",
285                              device->iface);
286
287                 nm_ip6_manager_cancel_addrconf (manager, ifindex);
288                 g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
289                                ifindex, info->dhcp_opts, FALSE);
290         }
291
292         return FALSE;
293 }
294
295 static gboolean
296 emit_config_changed (gpointer user_data)
297 {
298         CallbackInfo *info = user_data;
299         NMIP6Device *device = info->device;
300         NMIP6Manager *manager = device->manager;
301
302         device->config_changed_id = 0;
303         g_signal_emit (manager, signals[CONFIG_CHANGED], 0,
304                        device->ifindex,
305                        info->dhcp_opts,
306                        info->success);
307         return FALSE;
308 }
309
310 static void set_rdnss_timeout (NMIP6Device *device);
311
312 static gboolean
313 rdnss_expired (gpointer user_data)
314 {
315         NMIP6Device *device = user_data;
316         CallbackInfo info = { device, IP6_DHCP_OPT_NONE, FALSE };
317
318         nm_log_dbg (LOGD_IP6, "(%s): IPv6 RDNSS information expired", device->iface);
319
320         set_rdnss_timeout (device);
321         clear_config_changed (device);
322         emit_config_changed (&info);
323         return FALSE;
324 }
325
326 static void
327 set_rdnss_timeout (NMIP6Device *device)
328 {
329         time_t expires = 0, now = time (NULL);
330         NMIP6RDNSS *rdnss;
331         int i;
332
333         if (device->rdnss_timeout_id) {
334                 g_source_remove (device->rdnss_timeout_id);
335                 device->rdnss_timeout_id = 0;
336         }
337
338         /* Find the soonest expiration time. */
339         for (i = 0; i < device->rdnss_servers->len; i++) {
340                 rdnss = &g_array_index (device->rdnss_servers, NMIP6RDNSS, i);
341                 if (rdnss->expires == 0)
342                         continue;
343
344                 /* If the entry has already expired, remove it; the "+ 1" is
345                  * because g_timeout_add_seconds() might fudge the timing a
346                  * bit.
347                  */
348                 if (rdnss->expires <= now + 1) {
349                         char buf[INET6_ADDRSTRLEN + 1];
350
351                         if (inet_ntop (AF_INET6, &(rdnss->addr), buf, sizeof (buf)) > 0) {
352                                 nm_log_dbg (LOGD_IP6, "(%s): removing expired RA-provided nameserver %s",
353                                             device->iface, buf);
354                         }
355                         g_array_remove_index (device->rdnss_servers, i--);
356                         continue;
357                 }
358
359                 if (!expires || rdnss->expires < expires)
360                         expires = rdnss->expires;
361         }
362
363         if (expires) {
364                 device->rdnss_timeout_id = g_timeout_add_seconds (MIN (expires - now, G_MAXUINT32 - 1),
365                                                                   rdnss_expired,
366                                                                   device);
367         }
368 }
369
370 static void set_dnssl_timeout (NMIP6Device *device);
371
372 static gboolean
373 dnssl_expired (gpointer user_data)
374 {
375         NMIP6Device *device = user_data;
376         CallbackInfo info = { device, IP6_DHCP_OPT_NONE, FALSE };
377
378         nm_log_dbg (LOGD_IP6, "(%s): IPv6 DNSSL information expired", device->iface);
379
380         set_dnssl_timeout (device);
381         clear_config_changed (device);
382         emit_config_changed (&info);
383         return FALSE;
384 }
385
386 static void
387 set_dnssl_timeout (NMIP6Device *device)
388 {
389         time_t expires = 0, now = time (NULL);
390         NMIP6DNSSL *dnssl;
391         int i;
392
393         if (device->dnssl_timeout_id) {
394                 g_source_remove (device->dnssl_timeout_id);
395                 device->dnssl_timeout_id = 0;
396         }
397
398         /* Find the soonest expiration time. */
399         for (i = 0; i < device->dnssl_domains->len; i++) {
400                 dnssl = &g_array_index (device->dnssl_domains, NMIP6DNSSL, i);
401                 if (dnssl->expires == 0)
402                         continue;
403
404                 /* If the entry has already expired, remove it; the "+ 1" is
405                  * because g_timeout_add_seconds() might fudge the timing a
406                  * bit.
407                  */
408                 if (dnssl->expires <= now + 1) {
409                         nm_log_dbg (LOGD_IP6, "(%s): removing expired RA-provided domain %s",
410                                     device->iface, dnssl->domain);
411                         g_array_remove_index (device->dnssl_domains, i--);
412                         continue;
413                 }
414
415                 if (!expires || dnssl->expires < expires)
416                         expires = dnssl->expires;
417         }
418
419         if (expires) {
420                 device->dnssl_timeout_id = g_timeout_add_seconds (MIN (expires - now, G_MAXUINT32 - 1),
421                                                                   dnssl_expired,
422                                                                   device);
423         }
424 }
425
426 static CallbackInfo *
427 callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success)
428 {
429         CallbackInfo *info;
430
431         info = g_malloc0 (sizeof (CallbackInfo));
432         info->device = device;
433         info->dhcp_opts = dhcp_opts;
434         info->success = success;
435         return info;
436 }
437
438 static void
439 check_addresses (NMIP6Device *device)
440 {
441         NMIP6Manager *manager = device->manager;
442         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
443         struct rtnl_addr *rtnladdr;
444         struct nl_addr *nladdr;
445         struct in6_addr *addr;
446
447         /* Reset address information */
448         device->has_linklocal = FALSE;
449         device->has_nonlinklocal = FALSE;
450
451         /* Look for any IPv6 addresses the kernel may have set for the device */
452         for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache);
453                  rtnladdr;
454                  rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) {
455                 char buf[INET6_ADDRSTRLEN];
456
457                 if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
458                         continue;
459
460                 nladdr = rtnl_addr_get_local (rtnladdr);
461                 if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
462                         continue;
463
464                 addr = nl_addr_get_binary_addr (nladdr);
465
466                 if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) {
467                         nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s/%d",
468                                     device->iface, buf,
469                                     rtnl_addr_get_prefixlen (rtnladdr));
470                 }
471
472                 if (IN6_IS_ADDR_LINKLOCAL (addr)) {
473                         if (device->state == NM_IP6_DEVICE_UNCONFIGURED)
474                                 device_set_state (device, NM_IP6_DEVICE_GOT_LINK_LOCAL);
475                         device->has_linklocal = TRUE;
476                 } else {
477                         if (device->state < NM_IP6_DEVICE_GOT_ADDRESS)
478                                 device_set_state (device, NM_IP6_DEVICE_GOT_ADDRESS);
479                         device->has_nonlinklocal = TRUE;
480                 }
481         }
482
483         /* There might be a LL address hanging around on the interface from
484          * before in the initial run, but if it goes away later, make sure we
485          * regress from GOT_LINK_LOCAL back to UNCONFIGURED.
486          */
487         if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !device->has_linklocal)
488                 device_set_state (device, NM_IP6_DEVICE_UNCONFIGURED);
489
490         nm_log_dbg (LOGD_IP6, "(%s): addresses checked (state %s)",
491                     device->iface, state_to_string (device->state));
492 }
493
494 static void
495 check_ra_flags (NMIP6Device *device)
496 {
497         device->dhcp_opts = IP6_DHCP_OPT_NONE;
498
499         /* We only care about router advertisements if we want a real IPv6 address */
500         if (   (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
501             && (device->ra_flags & IF_RA_RCVD)) {
502
503                 if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
504                         device_set_state (device, NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT);
505
506                 if (device->ra_flags & IF_RA_MANAGED) {
507                         device->dhcp_opts = IP6_DHCP_OPT_MANAGED;
508                         nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6");
509                 } else if (device->ra_flags & IF_RA_OTHERCONF) {
510                         device->dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
511                         nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6");
512                 }
513         }
514         nm_log_dbg (LOGD_IP6, "(%s): router advertisement checked (state %s)",
515                     device->iface, state_to_string (device->state));
516 }
517
518 static void
519 check_addrconf_complete (NMIP6Device *device)
520 {
521         CallbackInfo *info;
522
523         if (!device->addrconf_complete) {
524                 /* Managed mode (ie DHCP only) short-circuits automatic addrconf, so
525                  * we don't bother waiting for the device's target state to be reached
526                  * when the RA requests managed mode.
527                  */
528                 if (   (device->state >= device->target_state)
529                     || (device->dhcp_opts == IP6_DHCP_OPT_MANAGED)) {
530                         /* device->finish_addrconf_id may currently be a timeout
531                          * rather than an idle, so we remove the existing source.
532                          */
533                         if (device->finish_addrconf_id)
534                                 g_source_remove (device->finish_addrconf_id);
535
536                         nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)",
537                                     device->iface, state_to_string (device->state),
538                                     device->dhcp_opts);
539
540                         info = callback_info_new (device, device->dhcp_opts, TRUE);
541                         device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
542                                                                       finish_addrconf,
543                                                                       info,
544                                                                       (GDestroyNotify) g_free);
545                 }
546         } else {
547                 if (!device->config_changed_id) {
548                         gboolean success = TRUE;
549
550                         /* If for some reason an RA-provided address disappeared, we need
551                          * to make sure we fail the connection as it's no longer valid.
552                          */
553                         if (   (device->state == NM_IP6_DEVICE_GOT_ADDRESS)
554                             && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
555                             && !device->has_nonlinklocal) {
556                                 nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer found",
557                                             device->iface);
558                                 success = FALSE;
559                         }
560
561                         info = callback_info_new (device, device->dhcp_opts, success);
562                         device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
563                                                                      emit_config_changed,
564                                                                      info,
565                                                                      (GDestroyNotify) g_free);
566                 }
567         }
568
569         nm_log_dbg (LOGD_IP6, "(%s): dhcp_opts checked (state %s)",
570                     device->iface, state_to_string (device->state));
571 }
572
573 static void
574 nm_ip6_device_sync_from_netlink (NMIP6Device *device)
575 {
576         nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')",
577                     device->iface, device->ra_flags,
578                     state_to_string (device->state),
579                     state_to_string (device->target_state));
580
581         check_addresses (device);
582         check_ra_flags (device);
583         check_addrconf_complete (device);
584 }
585
586 static void
587 ref_object (struct nl_object *obj, void *data)
588 {
589         struct nl_object **out = data;
590
591         nl_object_get (obj);
592         *out = obj;
593 }
594
595 static NMIP6Device *
596 process_addr (NMIP6Manager *manager, struct nl_msg *msg)
597 {
598         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
599         NMIP6Device *device;
600         struct rtnl_addr *rtnladdr;
601         int old_size;
602
603         nm_log_dbg (LOGD_IP6, "processing netlink new/del address message");
604
605         rtnladdr = NULL;
606         nl_msg_parse (msg, ref_object, &rtnladdr);
607         if (!rtnladdr) {
608                 nm_log_dbg (LOGD_IP6, "error processing netlink new/del address message");
609                 return NULL;
610         }
611
612         device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr));
613         if (!device) {
614                 nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
615                 rtnl_addr_put (rtnladdr);
616                 return NULL;
617         }
618
619         old_size = nl_cache_nitems (priv->addr_cache);
620         nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL, NULL);
621         rtnl_addr_put (rtnladdr);
622
623         /* The kernel will re-notify us of automatically-added addresses
624          * every time it gets another router advertisement. We only want
625          * to notify higher levels if we actually changed something.
626          */
627         if (nl_cache_nitems (priv->addr_cache) == old_size) {
628                 nm_log_dbg (LOGD_IP6, "(%s): address cache unchanged, ignoring message",
629                             device->iface);
630                 return NULL;
631         }
632
633         return device;
634 }
635
636 static NMIP6Device *
637 process_route (NMIP6Manager *manager, struct nl_msg *msg)
638 {
639         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
640         NMIP6Device *device;
641         struct rtnl_route *rtnlroute;
642         int old_size;
643
644         nm_log_dbg (LOGD_IP6, "processing netlink new/del route message");
645
646         rtnlroute = NULL;
647         nl_msg_parse (msg, ref_object, &rtnlroute);
648         if (!rtnlroute) {
649                 nm_log_dbg (LOGD_IP6, "error processing netlink new/del route message");
650                 return NULL;
651         }
652
653         device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute));
654         if (!device) {
655                 nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
656                 rtnl_route_put (rtnlroute);
657                 return NULL;
658         }
659
660         old_size = nl_cache_nitems (priv->route_cache);
661         nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL, NULL);
662         rtnl_route_put (rtnlroute);
663
664         /* As above in process_addr */
665         if (nl_cache_nitems (priv->route_cache) == old_size) {
666                 nm_log_dbg (LOGD_IP6, "(%s): route cache unchanged, ignoring message",
667                             device->iface);
668                 return NULL;
669         }
670
671         return device;
672 }
673
674 /* RDNSS parsing code based on rdnssd, Copyright 2007 Pierre Ynard,
675  * RĂ©mi Denis-Courmont. GPLv2/3
676  */
677
678 #define ND_OPT_RDNSS 25
679 #define ND_OPT_DNSSL 31
680
681 struct nd_opt_rdnss {
682         uint8_t nd_opt_rdnss_type;
683         uint8_t nd_opt_rdnss_len;
684         uint16_t nd_opt_rdnss_reserved1;
685         uint32_t nd_opt_rdnss_lifetime;
686         /* followed by one or more IPv6 addresses */
687 } __attribute__ ((packed));
688
689 struct nd_opt_dnssl {
690         uint8_t nd_opt_dnssl_type;
691         uint8_t nd_opt_dnssl_len;
692         uint16_t nd_opt_dnssl_reserved1;
693         uint32_t nd_opt_dnssl_lifetime;
694         /* followed by one or more suffixes */
695 } __attribute__ ((packed));
696
697 static gboolean
698 process_nduseropt_rdnss (NMIP6Device *device, struct nd_opt_hdr *opt)
699 {
700         size_t opt_len;
701         struct nd_opt_rdnss *rdnss_opt;
702         time_t now = time (NULL);
703         struct in6_addr *addr;
704         GArray *new_servers;
705         NMIP6RDNSS server, *cur_server;
706         gboolean changed = FALSE;
707         guint i;
708
709         opt_len = opt->nd_opt_len;
710
711         if (opt_len < 3 || (opt_len & 1) == 0)
712                 return FALSE;
713
714         rdnss_opt = (struct nd_opt_rdnss *) opt;
715
716         new_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
717
718         /* Pad the DNS server expiry somewhat to give a bit of slack in cases
719          * where one RA gets lost or something (which can happen on unreliable
720          * links like WiFi where certain types of frames are not retransmitted).
721          * Note that 0 has special meaning and is therefore not adjusted.
722          */
723         server.expires = ntohl (rdnss_opt->nd_opt_rdnss_lifetime);
724         if (server.expires > 0)
725                 server.expires += now + 10;
726
727         for (addr = (struct in6_addr *) (rdnss_opt + 1); opt_len >= 2; addr++, opt_len -= 2) {
728                 char buf[INET6_ADDRSTRLEN + 1];
729
730                 if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf))) {
731                         nm_log_warn (LOGD_IP6, "(%s): received invalid RA-provided nameserver", device->iface);
732                         continue;
733                 }
734
735                 /* Update the cached timeout if we already saw this server */
736                 for (i = 0; i < device->rdnss_servers->len; i++) {
737                         cur_server = &(g_array_index (device->rdnss_servers, NMIP6RDNSS, i));
738
739                         if (!IN6_ARE_ADDR_EQUAL (addr, &cur_server->addr))
740                                 continue;
741
742                         cur_server->expires = server.expires;
743
744                         if (server.expires > 0) {
745                                 nm_log_dbg (LOGD_IP6, "(%s): refreshing RA-provided nameserver %s (expires in %ld seconds)",
746                                             device->iface, buf,
747                                             server.expires - now);
748                                 break;
749                         }
750
751                         nm_log_dbg (LOGD_IP6, "(%s): removing RA-provided nameserver %s on router request",
752                                     device->iface, buf);
753
754                         g_array_remove_index (device->rdnss_servers, i);
755                         changed = TRUE;
756                         break;
757                 }
758
759                 if (server.expires == 0)
760                         continue;
761                 if (i < device->rdnss_servers->len)
762                         continue;
763
764                 nm_log_dbg (LOGD_IP6, "(%s): found RA-provided nameserver %s (expires in %ld seconds)",
765                             device->iface, buf, server.expires - now);
766
767                 server.addr = *addr;
768                 g_array_append_val (new_servers, server);
769         }
770
771         /* New servers must be added in the order they are listed in the
772          * RA option and before any existing servers.
773          *
774          * Note: This is the place to remove servers if we want to cap the
775          *       number of resolvers. The RFC states that the one to expire
776          *       first of the existing servers should be removed.
777          */
778         if (new_servers->len) {
779                 g_array_prepend_vals (device->rdnss_servers,
780                                       new_servers->data, new_servers->len);
781                 changed = TRUE;
782         }
783
784         g_array_free (new_servers, TRUE);
785
786         /* Timeouts may have changed even if IPs didn't */
787         set_rdnss_timeout (device);
788
789         return changed;
790 }
791
792 static const char *
793 parse_dnssl_domain (const unsigned char *buffer, size_t maxlen)
794 {
795         static char domain[256];
796         size_t label_len;
797
798         domain[0] = '\0';
799
800         while (maxlen > 0) {
801                 label_len = *buffer;
802                 buffer++;
803                 maxlen--;
804
805                 if (label_len == 0)
806                         return domain;
807
808                 if (label_len > maxlen)
809                         return NULL;
810                 if ((sizeof (domain) - strlen (domain)) < (label_len + 2))
811                         return NULL;
812
813                 if (domain[0] != '\0')
814                         strcat (domain, ".");
815                 strncat (domain, (const char *)buffer, label_len);
816                 buffer += label_len;
817                 maxlen -= label_len;
818         }
819
820         return NULL;
821 }
822
823 static gboolean
824 process_nduseropt_dnssl (NMIP6Device *device, struct nd_opt_hdr *opt)
825 {
826         size_t opt_len;
827         struct nd_opt_dnssl *dnssl_opt;
828         unsigned char *opt_ptr;
829         time_t now = time (NULL);
830         GArray *new_domains;
831         NMIP6DNSSL domain, *cur_domain;
832         gboolean changed;
833         guint i;
834
835         opt_len = opt->nd_opt_len;
836
837         if (opt_len < 2)
838                 return FALSE;
839
840         dnssl_opt = (struct nd_opt_dnssl *) opt;
841
842         opt_ptr = (unsigned char *)(dnssl_opt + 1);
843         opt_len = (opt_len - 1) * 8; /* prefer bytes for later handling */
844
845         new_domains = g_array_new (FALSE, FALSE, sizeof (NMIP6DNSSL));
846
847         changed = FALSE;
848
849         /* Pad the DNS server expiry somewhat to give a bit of slack in cases
850          * where one RA gets lost or something (which can happen on unreliable
851          * links like wifi where certain types of frames are not retransmitted).
852          * Note that 0 has special meaning and is therefore not adjusted.
853          */
854         domain.expires = ntohl (dnssl_opt->nd_opt_dnssl_lifetime);
855         if (domain.expires > 0)
856                 domain.expires += now + 10;
857
858         while (opt_len) {
859                 const char *domain_str;
860
861                 domain_str = parse_dnssl_domain (opt_ptr, opt_len);
862                 if (domain_str == NULL) {
863                         nm_log_dbg (LOGD_IP6, "(%s): invalid DNSSL option, parsing aborted",
864                                     device->iface);
865                         break;
866                 }
867
868                 /* The DNSSL encoding of domains happen to occupy the same size
869                  * as the length of the resulting string, including terminating
870                  * null. */
871                 opt_ptr += strlen (domain_str) + 1;
872                 opt_len -= strlen (domain_str) + 1;
873
874                 /* Ignore empty domains. They're probably just padding... */
875                 if (domain_str[0] == '\0')
876                         continue;
877
878                 /* Update cached domain information if we've seen this domain before */
879                 for (i = 0; i < device->dnssl_domains->len; i++) {
880                         cur_domain = &(g_array_index (device->dnssl_domains, NMIP6DNSSL, i));
881
882                         if (strcmp (domain_str, cur_domain->domain) != 0)
883                                 continue;
884
885                         cur_domain->expires = domain.expires;
886
887                         if (domain.expires > 0) {
888                                 nm_log_dbg (LOGD_IP6, "(%s): refreshing RA-provided domain %s (expires in %ld seconds)",
889                                             device->iface, domain_str,
890                                             domain.expires - now);
891                                 break;
892                         }
893
894                         nm_log_dbg (LOGD_IP6, "(%s): removing RA-provided domain %s on router request",
895                                     device->iface, domain_str);
896
897                         g_array_remove_index (device->dnssl_domains, i);
898                         changed = TRUE;
899                         break;
900                 }
901
902                 if (domain.expires == 0)
903                         continue;
904                 if (i < device->dnssl_domains->len)
905                         continue;
906
907                 nm_log_dbg (LOGD_IP6, "(%s): found RA-provided domain %s (expires in %ld seconds)",
908                             device->iface, domain_str, domain.expires - now);
909
910                 g_assert (strlen (domain_str) < sizeof (domain.domain));
911                 strcpy (domain.domain, domain_str);
912                 g_array_append_val (new_domains, domain);
913         }
914
915         /* New domains must be added in the order they are listed in the
916          * RA option and before any existing domains.
917          *
918          * Note: This is the place to remove domains if we want to cap the
919          *       number of domains. The RFC states that the one to expire
920          *       first of the existing domains should be removed.
921          */
922         if (new_domains->len) {
923                 g_array_prepend_vals (device->dnssl_domains,
924                                       new_domains->data, new_domains->len);
925                 changed = TRUE;
926         }
927
928         g_array_free (new_domains, TRUE);
929
930         /* Timeouts may have changed even if domains didn't */
931         set_dnssl_timeout (device);
932
933         return changed;
934 }
935
936 static NMIP6Device *
937 process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg)
938 {
939         NMIP6Device *device;
940         struct nduseroptmsg *ndmsg;
941         struct nd_opt_hdr *opt;
942         guint opts_len;
943         gboolean changed = FALSE;
944
945         nm_log_dbg (LOGD_IP6, "processing netlink nduseropt message");
946
947         ndmsg = (struct nduseroptmsg *) NLMSG_DATA (nlmsg_hdr (msg));
948
949         if (!nlmsg_valid_hdr (nlmsg_hdr (msg), sizeof (*ndmsg)) ||
950             nlmsg_datalen (nlmsg_hdr (msg)) <
951                 (ndmsg->nduseropt_opts_len + sizeof (*ndmsg))) {
952                 nm_log_dbg (LOGD_IP6, "ignoring invalid nduseropt message");
953                 return NULL;
954         }
955
956         if (ndmsg->nduseropt_family != AF_INET6 ||
957                 ndmsg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
958                 ndmsg->nduseropt_icmp_code != 0) {
959                 nm_log_dbg (LOGD_IP6, "ignoring non-Router Advertisement message");
960                 return NULL;
961         }
962
963         device = nm_ip6_manager_get_device (manager, ndmsg->nduseropt_ifindex);
964         if (!device) {
965                 nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
966                 return NULL;
967         }
968
969         opt = (struct nd_opt_hdr *) (ndmsg + 1);
970         opts_len = ndmsg->nduseropt_opts_len;
971
972         while (opts_len >= sizeof (struct nd_opt_hdr)) {
973                 size_t nd_opt_len = opt->nd_opt_len;
974
975                 if (nd_opt_len == 0 || opts_len < (nd_opt_len << 3))
976                         break;
977
978                 switch (opt->nd_opt_type) {
979                 case ND_OPT_RDNSS:
980                         changed = process_nduseropt_rdnss (device, opt);
981                         break;
982                 case ND_OPT_DNSSL:
983                         changed = process_nduseropt_dnssl (device, opt);
984                         break;
985                 }
986
987                 opts_len -= opt->nd_opt_len << 3;
988                 opt = (struct nd_opt_hdr *) ((uint8_t *) opt + (opt->nd_opt_len << 3));
989         }
990
991         if (changed)
992                 return device;
993         else
994                 return NULL;
995 }
996
997 static struct nla_policy link_policy[IFLA_MAX + 1] = {
998         [IFLA_PROTINFO] = { .type = NLA_NESTED },
999 };
1000
1001 static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = {
1002         [IFLA_INET6_FLAGS]      = { .type = NLA_U32 },
1003 };
1004
1005 static char *
1006 ra_flags_to_string (guint32 ra_flags)
1007 {
1008         GString *s = g_string_sized_new (20);
1009
1010         g_string_append (s, " (");
1011         if (ra_flags & IF_RS_SENT)
1012                 g_string_append_c (s, 'S');
1013
1014         if (ra_flags & IF_RA_RCVD)
1015                 g_string_append_c (s, 'R');
1016
1017         if (ra_flags & IF_RA_OTHERCONF)
1018                 g_string_append_c (s, 'O');
1019
1020         if (ra_flags & IF_RA_MANAGED)
1021                 g_string_append_c (s, 'M');
1022
1023         g_string_append_c (s, ')');
1024         return g_string_free (s, FALSE);
1025 }
1026
1027 static NMIP6Device *
1028 process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
1029 {
1030         struct nlmsghdr *hdr = nlmsg_hdr (msg);
1031         struct ifinfomsg *ifi;
1032         NMIP6Device *device;
1033         struct nlattr *tb[IFLA_MAX + 1];
1034         struct nlattr *pi[IFLA_INET6_MAX + 1];
1035         int err;
1036         char *flags_str = NULL;
1037
1038         /* FIXME: we have to do this manually for now since libnl doesn't yet
1039          * support the IFLA_PROTINFO attribute of NEWLINK messages.  When it does,
1040          * we can get rid of this function and just grab IFLA_PROTINFO from
1041          * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
1042          * the PROTINFO.
1043          */
1044         err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
1045         if (err < 0) {
1046                 nm_log_dbg (LOGD_IP6, "ignoring invalid newlink netlink message "
1047                                       "while parsing PROTINFO attribute");
1048                 return NULL;
1049         }
1050
1051         ifi = nlmsg_data (hdr);
1052         if (ifi->ifi_family != AF_INET6) {
1053                 nm_log_dbg (LOGD_IP6, "ignoring netlink message family %d", ifi->ifi_family);
1054                 return NULL;
1055         }
1056
1057         device = nm_ip6_manager_get_device (manager, ifi->ifi_index);
1058         if (!device || device->addrconf_complete) {
1059                 nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device",
1060                             device ? device->iface : "(none)");
1061                 return NULL;
1062         }
1063
1064         if (!tb[IFLA_PROTINFO]) {
1065                 nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO attribute", device->iface);
1066                 return NULL;
1067         }
1068
1069         err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy);
1070         if (err < 0) {
1071                 nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO flags", device->iface);
1072                 return NULL;
1073         }
1074         if (!pi[IFLA_INET6_FLAGS]) {
1075                 nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO flags", device->iface);
1076                 return NULL;
1077         }
1078
1079         device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
1080
1081         if (nm_logging_level_enabled (LOGL_DEBUG))
1082                 flags_str = ra_flags_to_string (device->ra_flags);
1083         nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X%s",
1084                     device->iface, device->ra_flags, flags_str ? flags_str : "");
1085         g_free (flags_str);
1086
1087         return device;
1088 }
1089
1090 static void
1091 netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data)
1092 {
1093         NMIP6Manager *manager = (NMIP6Manager *) user_data;
1094         NMIP6Device *device;
1095         struct nlmsghdr *hdr;
1096
1097         hdr = nlmsg_hdr (msg);
1098         nm_log_dbg (LOGD_HW, "netlink event type %d", hdr->nlmsg_type);
1099         switch (hdr->nlmsg_type) {
1100         case RTM_NEWADDR:
1101         case RTM_DELADDR:
1102                 device = process_addr (manager, msg);
1103                 break;
1104         case RTM_NEWROUTE:
1105         case RTM_DELROUTE:
1106                 device = process_route (manager, msg);
1107                 break;
1108         case RTM_NEWNDUSEROPT:
1109                 device = process_nduseropt (manager, msg);
1110                 break;
1111         case RTM_NEWLINK:
1112                 device = process_newlink (manager, msg);
1113                 break;
1114         default:
1115                 return;
1116         }
1117
1118         if (device) {
1119                 nm_ip6_device_sync_from_netlink (device);
1120         }
1121 }
1122
1123 gboolean
1124 nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
1125                                   int ifindex,
1126                                   NMSettingIP6Config *s_ip6,
1127                                   const char *accept_ra_path)
1128 {
1129         NMIP6ManagerPrivate *priv;
1130         NMIP6Device *device;
1131         const char *method = NULL;
1132
1133         g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), FALSE);
1134         g_return_val_if_fail (ifindex > 0, FALSE);
1135
1136         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1137
1138         device = nm_ip6_device_new (manager, ifindex);
1139         g_return_val_if_fail (device != NULL, FALSE);
1140         g_return_val_if_fail (   strchr (device->iface, '/') == NULL
1141                               && strcmp (device->iface, "all") != 0
1142                               && strcmp (device->iface, "default") != 0,
1143                               FALSE);
1144
1145         if (s_ip6)
1146                 method = nm_setting_ip6_config_get_method (s_ip6);
1147         if (!method)
1148                 method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
1149
1150         /* Establish target state and turn router advertisement acceptance on or off */
1151         if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
1152                 device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
1153                 nm_utils_do_sysctl (accept_ra_path, "0\n");
1154         } else {
1155                 device->target_state = NM_IP6_DEVICE_GOT_ADDRESS;
1156                 nm_utils_do_sysctl (accept_ra_path, "2\n");
1157         }
1158
1159         return TRUE;
1160 }
1161
1162 static gboolean
1163 poll_ip6_flags (gpointer user_data)
1164 {
1165         nm_netlink_monitor_request_ip6_info (NM_NETLINK_MONITOR (user_data), NULL);
1166         return TRUE;
1167 }
1168
1169 void
1170 nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex)
1171 {
1172         NMIP6ManagerPrivate *priv;
1173         NMIP6Device *device;
1174         CallbackInfo *info;
1175
1176         g_return_if_fail (NM_IS_IP6_MANAGER (manager));
1177         g_return_if_fail (ifindex > 0);
1178
1179         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1180
1181         device = (NMIP6Device *) g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
1182         g_return_if_fail (device != NULL);
1183
1184         nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", device->iface);
1185
1186         device->addrconf_complete = FALSE;
1187         device->ra_flags = 0;
1188
1189         /* Set up a timeout on the transaction to kill it after the timeout */
1190         info = callback_info_new (device, 0, FALSE);
1191         device->finish_addrconf_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
1192                                                                  NM_IP6_TIMEOUT,
1193                                                                  finish_addrconf,
1194                                                                  info,
1195                                                                  (GDestroyNotify) g_free);
1196
1197         /* Bounce IPv6 on the interface to ensure the kernel will start looking for
1198          * new RAs; there doesn't seem to be a better way to do this right now.
1199          */
1200         if (device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS) {
1201                 nm_utils_do_sysctl (device->disable_ip6_path, "1\n");
1202                 g_usleep (200);
1203                 nm_utils_do_sysctl (device->disable_ip6_path, "0\n");
1204         }
1205
1206         device->ip6flags_poll_id = g_timeout_add_seconds (1, poll_ip6_flags, priv->monitor);
1207
1208         /* Kick off the initial IPv6 flags request */
1209         nm_netlink_monitor_request_ip6_info (priv->monitor, NULL);
1210
1211         /* Sync flags, etc, from netlink; this will also notice if the
1212          * device is already fully configured and schedule the
1213          * ADDRCONF_COMPLETE signal in that case.
1214          */
1215         nm_ip6_device_sync_from_netlink (device);
1216 }
1217
1218 void
1219 nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, int ifindex)
1220 {
1221         g_return_if_fail (NM_IS_IP6_MANAGER (manager));
1222         g_return_if_fail (ifindex > 0);
1223
1224         g_hash_table_remove (NM_IP6_MANAGER_GET_PRIVATE (manager)->devices,
1225                              GINT_TO_POINTER (ifindex));
1226 }
1227
1228 #define FIRST_ROUTE(m) ((struct rtnl_route *) nl_cache_get_first (m))
1229 #define NEXT_ROUTE(m) ((struct rtnl_route *) nl_cache_get_next ((struct nl_object *) m))
1230
1231 #define FIRST_ADDR(m) ((struct rtnl_addr *) nl_cache_get_first (m))
1232 #define NEXT_ADDR(m) ((struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) m))
1233
1234 NMIP6Config *
1235 nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
1236 {
1237         NMIP6ManagerPrivate *priv;
1238         NMIP6Device *device;
1239         NMIP6Config *config;
1240         struct rtnl_addr *rtnladdr;
1241         struct nl_addr *nladdr;
1242         struct in6_addr *addr;
1243         NMIP6Address *ip6addr;
1244         struct rtnl_route *rtnlroute;
1245         struct nl_addr *nldest, *nlgateway;
1246         struct in6_addr *dest, *gateway;
1247         gboolean defgw_set = FALSE;
1248         struct in6_addr defgw;
1249         uint32_t metric;
1250         NMIP6Route *ip6route;
1251         int i;
1252
1253         g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
1254         g_return_val_if_fail (ifindex > 0, NULL);
1255
1256         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1257
1258         device = (NMIP6Device *) g_hash_table_lookup (priv->devices,
1259                                                       GINT_TO_POINTER (ifindex));
1260         if (!device) {
1261                 nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex);
1262                 return NULL;
1263         }
1264
1265         config = nm_ip6_config_new ();
1266         if (!config) {
1267                 nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.",
1268                             device->iface);
1269                 return NULL;
1270         }
1271
1272         /* Make sure we refill the route and address caches, otherwise we won't get
1273          * up-to-date information here since the netlink route/addr change messages
1274          * may be lagging a bit.
1275          */
1276         nl_cache_refill (priv->nlh, priv->route_cache);
1277         nl_cache_refill (priv->nlh, priv->addr_cache);
1278
1279         /* Add routes */
1280         for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) {
1281                 /* Make sure it's an IPv6 route for this device */
1282                 if (rtnl_route_get_oif (rtnlroute) != device->ifindex)
1283                         continue;
1284                 if (rtnl_route_get_family (rtnlroute) != AF_INET6)
1285                         continue;
1286
1287                 nldest = rtnl_route_get_dst (rtnlroute);
1288                 if (!nldest || nl_addr_get_family (nldest) != AF_INET6)
1289                         continue;
1290                 dest = nl_addr_get_binary_addr (nldest);
1291
1292                 nlgateway = rtnl_route_get_gateway (rtnlroute);
1293                 if (!nlgateway || nl_addr_get_family (nlgateway) != AF_INET6)
1294                         continue;
1295                 gateway = nl_addr_get_binary_addr (nlgateway);
1296
1297                 if (rtnl_route_get_dst_len (rtnlroute) == 0) {
1298                         /* Default gateway route; don't add to normal routes but to each address */
1299                         if (!defgw_set) {
1300                                 memcpy (&defgw, gateway, sizeof (defgw));
1301                                 defgw_set = TRUE;
1302                         }
1303                         continue;
1304                 }
1305
1306                 /* Also ignore link-local routes where the destination and gateway are
1307                  * the same, which apparently get added by the kernel but return -EINVAL
1308                  * when we try to add them via netlink.
1309                  */
1310                 if (gateway && IN6_ARE_ADDR_EQUAL (dest, gateway))
1311                         continue;
1312
1313                 ip6route = nm_ip6_route_new ();
1314                 nm_ip6_route_set_dest (ip6route, dest);
1315                 nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute));
1316                 nm_ip6_route_set_next_hop (ip6route, gateway);
1317                 rtnl_route_get_metric(rtnlroute, 1, &metric);
1318                 if (metric != UINT_MAX)
1319                         nm_ip6_route_set_metric (ip6route, metric);
1320                 nm_ip6_config_take_route (config, ip6route);
1321         }
1322
1323         /* Add addresses */
1324         for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) {
1325                 if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
1326                         continue;
1327
1328                 nladdr = rtnl_addr_get_local (rtnladdr);
1329                 if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
1330                         continue;
1331
1332                 addr = nl_addr_get_binary_addr (nladdr);
1333                 ip6addr = nm_ip6_address_new ();
1334                 nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
1335                 nm_ip6_address_set_address (ip6addr, addr);
1336                 nm_ip6_config_take_address (config, ip6addr);
1337                 if (defgw_set)
1338                         nm_ip6_address_set_gateway (ip6addr, &defgw);
1339         }
1340
1341         /* Add DNS servers */
1342         if (device->rdnss_servers) {
1343                 NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data);
1344
1345                 for (i = 0; i < device->rdnss_servers->len; i++)
1346                         nm_ip6_config_add_nameserver (config, &rdnss[i].addr);
1347         }
1348
1349         /* Add DNS domains */
1350         if (device->dnssl_domains) {
1351                 NMIP6DNSSL *dnssl = (NMIP6DNSSL *)(device->dnssl_domains->data);
1352
1353                 for (i = 0; i < device->dnssl_domains->len; i++)
1354                         nm_ip6_config_add_domain (config, dnssl[i].domain);
1355         }
1356
1357         return config;
1358 }
1359
1360 /******************************************************************/
1361
1362 static NMIP6Manager *
1363 nm_ip6_manager_new (void)
1364 {
1365         NMIP6Manager *manager;
1366         NMIP6ManagerPrivate *priv;
1367
1368         manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL);
1369         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1370
1371         if (!priv->devices) {
1372                 nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables");
1373                 g_object_unref (manager);
1374                 manager = NULL;
1375         }
1376
1377         return manager;
1378 }
1379
1380 static NMIP6Manager *singleton = NULL;
1381
1382 NMIP6Manager *
1383 nm_ip6_manager_get (void)
1384 {
1385         if (!singleton) {
1386                 singleton = nm_ip6_manager_new ();
1387                 g_assert (singleton);
1388         } else
1389                 g_object_ref (singleton);
1390
1391         return singleton;
1392 }
1393
1394 static void
1395 nm_ip6_manager_init (NMIP6Manager *manager)
1396 {
1397         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
1398
1399         priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1400                                                NULL,
1401                                                (GDestroyNotify) nm_ip6_device_destroy);
1402
1403         priv->monitor = nm_netlink_monitor_get ();
1404         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL);
1405         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL);
1406         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_ROUTE, NULL);
1407         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL);
1408         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);
1409
1410         priv->netlink_id = g_signal_connect (priv->monitor, "notification",
1411                                              G_CALLBACK (netlink_notification), manager);
1412
1413         priv->nlh = nm_netlink_get_default_handle ();
1414         rtnl_addr_alloc_cache (priv->nlh, &priv->addr_cache);
1415         g_warn_if_fail (priv->addr_cache != NULL);
1416         rtnl_route_alloc_cache (priv->nlh, NETLINK_ROUTE, NL_AUTO_PROVIDE, &priv->route_cache);
1417         g_warn_if_fail (priv->route_cache != NULL);
1418 }
1419
1420 static void
1421 finalize (GObject *object)
1422 {
1423         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object);
1424
1425         g_signal_handler_disconnect (priv->monitor, priv->netlink_id);
1426
1427         g_hash_table_destroy (priv->devices);
1428         g_object_unref (priv->monitor);
1429         nl_cache_free (priv->addr_cache);
1430         nl_cache_free (priv->route_cache);
1431
1432         singleton = NULL;
1433
1434         G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object);
1435 }
1436
1437 static void
1438 nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class)
1439 {
1440         GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
1441
1442         g_type_class_add_private (manager_class, sizeof (NMIP6ManagerPrivate));
1443
1444         /* virtual methods */
1445         object_class->finalize = finalize;
1446
1447         /* signals */
1448         signals[ADDRCONF_COMPLETE] =
1449                 g_signal_new ("addrconf-complete",
1450                                           G_OBJECT_CLASS_TYPE (object_class),
1451                                           G_SIGNAL_RUN_FIRST,
1452                                           G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete),
1453                                           NULL, NULL,
1454                                           _nm_marshal_VOID__INT_UINT_BOOLEAN,
1455                                           G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);
1456
1457         signals[CONFIG_CHANGED] =
1458                 g_signal_new ("config-changed",
1459                                           G_OBJECT_CLASS_TYPE (object_class),
1460                                           G_SIGNAL_RUN_FIRST,
1461                                           G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed),
1462                                           NULL, NULL,
1463                                           _nm_marshal_VOID__INT_UINT_BOOLEAN,
1464                                           G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);
1465 }
1466