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