6bf928c1a8a777c29e21982cd3992076cf0178a9
[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 "NetworkManagerUtils.h"
31 #include "nm-marshal.h"
32 #include "nm-logging.h"
33 #include "nm-system.h"
34
35 /* Pre-DHCP addrconf timeout, in seconds */
36 #define NM_IP6_TIMEOUT 10
37
38 /* FIXME? Stolen from the kernel sources */
39 #define IF_RA_OTHERCONF 0x80
40 #define IF_RA_MANAGED   0x40
41 #define IF_RA_RCVD      0x20
42 #define IF_RS_SENT      0x10
43
44 typedef struct {
45         NMNetlinkMonitor *monitor;
46         GHashTable *devices;
47
48         struct nl_handle *nlh;
49         struct nl_cache *addr_cache, *route_cache;
50 } NMIP6ManagerPrivate;
51
52 #define NM_IP6_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_MANAGER, NMIP6ManagerPrivate))
53
54 typedef enum {
55         NM_IP6_DEVICE_UNCONFIGURED,
56         NM_IP6_DEVICE_GOT_LINK_LOCAL,
57         NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT,
58         NM_IP6_DEVICE_GOT_ADDRESS,
59         NM_IP6_DEVICE_TIMED_OUT
60 } NMIP6DeviceState;
61
62 typedef struct {
63         struct in6_addr addr;
64         time_t expires;
65 } NMIP6RDNSS;
66
67 typedef struct {
68         NMIP6Manager *manager;
69         char *iface;
70         int ifindex;
71
72         char *accept_ra_path;
73         gboolean accept_ra_save_valid;
74         guint32 accept_ra_save;
75
76         char *disable_ip6_path;
77         gboolean disable_ip6_save_valid;
78         guint32 disable_ip6_save;
79
80         guint finish_addrconf_id;
81         guint config_changed_id;
82
83         NMIP6DeviceState state;
84         NMIP6DeviceState target_state;
85         gboolean addrconf_complete;
86
87         GArray *rdnss_servers;
88         guint rdnss_timeout_id;
89
90         guint ip6flags_poll_id;
91
92         guint32 ra_flags;
93 } NMIP6Device;
94
95 G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT)
96
97 enum {
98         ADDRCONF_COMPLETE,
99         CONFIG_CHANGED,
100         LAST_SIGNAL
101 };
102
103 static guint signals[LAST_SIGNAL] = { 0 };
104
105 static NMIP6Manager *nm_ip6_manager_new (void);
106
107 static void netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data);
108
109 static void nm_ip6_device_destroy (NMIP6Device *device);
110
111 NMIP6Manager *
112 nm_ip6_manager_get (void)
113 {
114         static NMIP6Manager *singleton = NULL;
115
116         if (!singleton)
117                 singleton = nm_ip6_manager_new ();
118         g_assert (singleton);
119
120         return g_object_ref (singleton);
121 }
122
123 static void
124 nm_ip6_manager_init (NMIP6Manager *manager)
125 {
126         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
127
128         priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal,
129                                                NULL,
130                                                (GDestroyNotify) nm_ip6_device_destroy);
131
132         priv->monitor = nm_netlink_monitor_get ();
133         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL);
134         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL);
135         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL);
136         nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);
137
138         g_signal_connect (priv->monitor, "notification",
139                           G_CALLBACK (netlink_notification), manager);
140
141         priv->nlh = nm_netlink_get_default_handle ();
142         priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh);
143         priv->route_cache = rtnl_route_alloc_cache (priv->nlh);
144 }
145
146 static void
147 finalize (GObject *object)
148 {
149         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object);
150
151         g_hash_table_destroy (priv->devices);
152         g_object_unref (priv->monitor);
153         nl_cache_free (priv->addr_cache);
154         nl_cache_free (priv->route_cache);
155
156         G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object);
157 }
158
159 static void
160 nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class)
161 {
162         GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
163
164         g_type_class_add_private (manager_class, sizeof (NMIP6ManagerPrivate));
165
166         /* virtual methods */
167         object_class->finalize = finalize;
168
169         /* signals */
170         signals[ADDRCONF_COMPLETE] =
171                 g_signal_new ("addrconf-complete",
172                                           G_OBJECT_CLASS_TYPE (object_class),
173                                           G_SIGNAL_RUN_FIRST,
174                                           G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete),
175                                           NULL, NULL,
176                                           _nm_marshal_VOID__INT_UINT_BOOLEAN,
177                                           G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);
178
179         signals[CONFIG_CHANGED] =
180                 g_signal_new ("config-changed",
181                                           G_OBJECT_CLASS_TYPE (object_class),
182                                           G_SIGNAL_RUN_FIRST,
183                                           G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed),
184                                           NULL, NULL,
185                                           _nm_marshal_VOID__INT_UINT,
186                                           G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT);
187 }
188
189 static void
190 nm_ip6_device_destroy (NMIP6Device *device)
191 {
192         g_return_if_fail (device != NULL);
193
194         /* reset the saved RA value */
195         if (device->accept_ra_save_valid) {
196                 nm_utils_do_sysctl (device->accept_ra_path,
197                                     device->accept_ra_save ? "1\n" : "0\n");
198         }
199
200         /* reset the saved IPv6 value */
201         if (device->disable_ip6_save_valid) {
202                 nm_utils_do_sysctl (device->disable_ip6_path,
203                                     device->disable_ip6_save ? "1\n" : "0\n");
204         }
205
206         if (device->finish_addrconf_id)
207                 g_source_remove (device->finish_addrconf_id);
208         if (device->config_changed_id)
209                 g_source_remove (device->config_changed_id);
210         g_free (device->iface);
211         if (device->rdnss_servers)
212                 g_array_free (device->rdnss_servers, TRUE);
213         if (device->rdnss_timeout_id)
214                 g_source_remove (device->rdnss_timeout_id);
215         if (device->ip6flags_poll_id)
216                 g_source_remove (device->ip6flags_poll_id);
217
218         g_free (device->accept_ra_path);
219         g_slice_free (NMIP6Device, device);
220 }
221
222 static NMIP6Manager *
223 nm_ip6_manager_new (void)
224 {
225         NMIP6Manager *manager;
226         NMIP6ManagerPrivate *priv;
227
228         manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL);
229         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
230
231         if (!priv->devices) {
232                 nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables");
233                 g_object_unref (manager);
234                 manager = NULL;
235         }
236
237         return manager;
238 }
239
240 static NMIP6Device *
241 nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex)
242 {
243         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
244
245         return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
246 }
247
248 typedef struct {
249         NMIP6Device *device;
250         guint dhcp_opts;
251         gboolean success;
252 } CallbackInfo;
253
254 static gboolean
255 finish_addrconf (gpointer user_data)
256 {
257         CallbackInfo *info = user_data;
258         NMIP6Device *device = info->device;
259         NMIP6Manager *manager = device->manager;
260         int ifindex;
261
262         device->finish_addrconf_id = 0;
263         device->addrconf_complete = TRUE;
264         ifindex = device->ifindex;
265
266         /* We're done, stop polling IPv6 flags */
267         if (device->ip6flags_poll_id) {
268                 g_source_remove (device->ip6flags_poll_id);
269                 device->ip6flags_poll_id = 0;
270         }
271
272         /* And tell listeners that addrconf is complete */
273         if (info->success) {
274                 g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
275                                ifindex, info->dhcp_opts, TRUE);
276         } else {
277                 nm_log_info (LOGD_IP6, "(%s): IP6 addrconf timed out or failed.",
278                              device->iface);
279
280                 nm_ip6_manager_cancel_addrconf (manager, ifindex);
281                 g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
282                                ifindex, info->dhcp_opts, FALSE);
283         }
284
285         return FALSE;
286 }
287
288 static gboolean
289 emit_config_changed (gpointer user_data)
290 {
291         CallbackInfo *info = user_data;
292         NMIP6Device *device = info->device;
293         NMIP6Manager *manager = device->manager;
294
295         device->config_changed_id = 0;
296         g_signal_emit (manager, signals[CONFIG_CHANGED], 0, device->ifindex, info->dhcp_opts);
297         return FALSE;
298 }
299
300 static void set_rdnss_timeout (NMIP6Device *device);
301
302 static gboolean
303 rdnss_expired (gpointer user_data)
304 {
305         NMIP6Device *device = user_data;
306         CallbackInfo info = { device, IP6_DHCP_OPT_NONE };
307
308         set_rdnss_timeout (device);
309         emit_config_changed (&info);
310         return FALSE;
311 }
312
313 static void
314 set_rdnss_timeout (NMIP6Device *device)
315 {
316         time_t expires = 0, now = time (NULL);
317         NMIP6RDNSS *rdnss;
318         int i;
319
320         if (device->rdnss_timeout_id) {
321                 g_source_remove (device->rdnss_timeout_id);
322                 device->rdnss_timeout_id = 0;
323         }
324
325         /* Find the soonest expiration time. */
326         for (i = 0; i < device->rdnss_servers->len; i++) {
327                 rdnss = &g_array_index (device->rdnss_servers, NMIP6RDNSS, i);
328                 if (rdnss->expires == 0)
329                         continue;
330
331                 /* If the entry has already expired, remove it; the "+ 1" is
332                  * because g_timeout_add_seconds() might fudge the timing a
333                  * bit.
334                  */
335                 if (rdnss->expires <= now + 1) {
336                         g_array_remove_index_fast (device->rdnss_servers, i--);
337                         continue;
338                 }
339
340                 if (!expires || rdnss->expires < expires)
341                         expires = rdnss->expires;
342         }
343
344         if (expires) {
345                 device->rdnss_timeout_id = g_timeout_add_seconds (expires - now,
346                                                                                                                   rdnss_expired,
347                                                                                                                   device);
348         }
349 }
350
351 static CallbackInfo *
352 callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success)
353 {
354         CallbackInfo *info;
355
356         info = g_malloc0 (sizeof (CallbackInfo));
357         info->device = device;
358         info->dhcp_opts = dhcp_opts;
359         info->success = success;
360         return info;
361 }
362
363 static void
364 nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
365 {
366         NMIP6Manager *manager = device->manager;
367         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
368         struct rtnl_addr *rtnladdr;
369         struct nl_addr *nladdr;
370         struct in6_addr *addr;
371         CallbackInfo *info;
372         guint dhcp_opts = IP6_DHCP_OPT_NONE;
373
374         /* Look for any IPv6 addresses the kernel may have set for the device */
375         for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache);
376                  rtnladdr;
377                  rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) {
378                 if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
379                         continue;
380
381                 nladdr = rtnl_addr_get_local (rtnladdr);
382                 if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
383                         continue;
384
385                 addr = nl_addr_get_binary_addr (nladdr);
386                 if (IN6_IS_ADDR_LINKLOCAL (addr)) {
387                         if (device->state == NM_IP6_DEVICE_UNCONFIGURED)
388                                 device->state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
389                 } else {
390                         if (device->state < NM_IP6_DEVICE_GOT_ADDRESS)
391                                 device->state = NM_IP6_DEVICE_GOT_ADDRESS;
392                 }
393         }
394
395         /* We only care about router advertisements if we want for a real IPv6 address */
396         if (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) {
397                 if (   (device->ra_flags & IF_RA_RCVD)
398                     && (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT))
399                         device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT;
400
401                 if (device->ra_flags & IF_RA_MANAGED) {
402                         dhcp_opts = IP6_DHCP_OPT_MANAGED;
403                         nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6");
404                 } else if (device->ra_flags & IF_RA_OTHERCONF) {
405                         dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
406                         nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6");
407                 }
408         }
409
410         if (!device->addrconf_complete) {
411                 /* Managed mode (ie DHCP only) short-circuits automatic addrconf, so
412                  * we don't bother waiting for the device's target state to be reached
413                  * when the RA requests managed mode.
414                  */
415                 if (   (device->state >= device->target_state)
416                     || (dhcp_opts == IP6_DHCP_OPT_MANAGED)) {
417                         /* device->finish_addrconf_id may currently be a timeout
418                          * rather than an idle, so we remove the existing source.
419                          */
420                         if (device->finish_addrconf_id)
421                                 g_source_remove (device->finish_addrconf_id);
422
423                         info = callback_info_new (device, dhcp_opts, TRUE);
424                         device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
425                                                                       finish_addrconf,
426                                                                       info,
427                                                                       (GDestroyNotify) g_free);
428                 }
429         } else if (config_changed) {
430                 if (!device->config_changed_id) {
431                         info = callback_info_new (device, dhcp_opts, TRUE);
432                         device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
433                                                                      emit_config_changed,
434                                                                      info,
435                                                                      (GDestroyNotify) g_free);
436                 }
437         }
438 }
439
440 static void
441 ref_object (struct nl_object *obj, void *data)
442 {
443         struct nl_object **out = data;
444
445         nl_object_get (obj);
446         *out = obj;
447 }
448
449 static NMIP6Device *
450 process_addr (NMIP6Manager *manager, struct nl_msg *msg)
451 {
452         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
453         NMIP6Device *device;
454         struct rtnl_addr *rtnladdr;
455         int old_size;
456
457         rtnladdr = NULL;
458         nl_msg_parse (msg, ref_object, &rtnladdr);
459         if (!rtnladdr)
460                 return NULL;
461
462         device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr));
463
464         old_size = nl_cache_nitems (priv->addr_cache);
465         nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL);
466         rtnl_addr_put (rtnladdr);
467
468         /* The kernel will re-notify us of automatically-added addresses
469          * every time it gets another router advertisement. We only want
470          * to notify higher levels if we actually changed something.
471          */
472         if (nl_cache_nitems (priv->addr_cache) == old_size)
473                 return NULL;
474
475         return device;
476 }
477
478 static NMIP6Device *
479 process_route (NMIP6Manager *manager, struct nl_msg *msg)
480 {
481         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
482         NMIP6Device *device;
483         struct rtnl_route *rtnlroute;
484         int old_size;
485
486         rtnlroute = NULL;
487         nl_msg_parse (msg, ref_object, &rtnlroute);
488         if (!rtnlroute)
489                 return NULL;
490
491         device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute));
492
493         old_size = nl_cache_nitems (priv->route_cache);
494         nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL);
495         rtnl_route_put (rtnlroute);
496
497         /* As above in process_addr */
498         if (nl_cache_nitems (priv->route_cache) == old_size)
499                 return NULL;
500
501         return device;
502 }
503
504 static NMIP6Device *
505 process_prefix (NMIP6Manager *manager, struct nl_msg *msg)
506 {
507         struct prefixmsg *pmsg;
508         NMIP6Device *device;
509
510         /* We don't care about the prefix itself, but if we receive a
511          * router advertisement telling us to use DHCP, we might not
512          * get any RTM_NEWADDRs or RTM_NEWROUTEs, so this is our only
513          * way to notice immediately that an RA was received.
514          */
515
516         pmsg = (struct prefixmsg *) NLMSG_DATA (nlmsg_hdr (msg));
517         device = nm_ip6_manager_get_device (manager, pmsg->prefix_ifindex);
518
519         if (!device || device->addrconf_complete)
520                 return NULL;
521
522         return device;
523 }
524
525 /* RDNSS parsing code based on rdnssd, Copyright 2007 Pierre Ynard,
526  * RĂ©mi Denis-Courmont. GPLv2/3
527  */
528
529 #define ND_OPT_RDNSS 25
530 struct nd_opt_rdnss {
531         uint8_t nd_opt_rdnss_type;
532         uint8_t nd_opt_rdnss_len;
533         uint16_t nd_opt_rdnss_reserved1;
534         uint32_t nd_opt_rdnss_lifetime;
535         /* followed by one or more IPv6 addresses */
536 };
537
538 static NMIP6Device *
539 process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg)
540 {
541         NMIP6Device *device;
542         struct nduseroptmsg *ndmsg;
543         struct nd_opt_hdr *opt;
544         guint opts_len, i;
545         time_t now = time (NULL);
546         struct nd_opt_rdnss *rdnss_opt;
547         struct in6_addr *addr;
548         GArray *servers;
549         NMIP6RDNSS server, *sa, *sb;
550         gboolean changed;
551
552         ndmsg = (struct nduseroptmsg *) NLMSG_DATA (nlmsg_hdr (msg));
553
554         if (ndmsg->nduseropt_family != AF_INET6 ||
555                 ndmsg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
556                 ndmsg->nduseropt_icmp_code != 0)
557                 return NULL;
558
559         device = nm_ip6_manager_get_device (manager, ndmsg->nduseropt_ifindex);
560         if (!device)
561                 return NULL;
562
563         servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
564
565         opt = (struct nd_opt_hdr *) (ndmsg + 1);
566         opts_len = ndmsg->nduseropt_opts_len;
567
568         while (opts_len >= sizeof (struct nd_opt_hdr)) {
569                 size_t nd_opt_len = opt->nd_opt_len;
570
571                 if (nd_opt_len == 0 || opts_len < (nd_opt_len << 3))
572                         break;
573
574                 if (opt->nd_opt_type != ND_OPT_RDNSS)
575                         goto next;
576
577                 if (nd_opt_len < 3 || (nd_opt_len & 1) == 0)
578                         goto next;
579
580                 rdnss_opt = (struct nd_opt_rdnss *) opt;
581
582                 server.expires = now + ntohl (rdnss_opt->nd_opt_rdnss_lifetime);
583                 for (addr = (struct in6_addr *) (rdnss_opt + 1); nd_opt_len >= 2; addr++, nd_opt_len -= 2) {
584                         server.addr = *addr;
585                         g_array_append_val (servers, server);
586                 }
587
588         next:
589                 opts_len -= opt->nd_opt_len << 3;
590                 opt = (struct nd_opt_hdr *) ((uint8_t *) opt + (opt->nd_opt_len << 3));
591         }
592
593         /* See if anything (other than expiration time) changed */
594         if (servers->len != device->rdnss_servers->len)
595                 changed = TRUE;
596         else {
597                 for (i = 0; i < servers->len; i++) {
598                         sa = &(g_array_index (servers, NMIP6RDNSS, i));
599                         sb = &(g_array_index (device->rdnss_servers, NMIP6RDNSS, i));
600                         if (memcmp (&sa->addr, &sb->addr, sizeof (struct in6_addr)) != 0) {
601                                 changed = TRUE;
602                                 break;
603                         }
604                 }
605                 changed = FALSE;
606         }
607
608         if (changed) {
609                 g_array_free (device->rdnss_servers, TRUE);
610                 device->rdnss_servers = servers;
611         } else
612                 g_array_free (servers, TRUE);
613
614         /* Timeouts may have changed even if IPs didn't */
615         set_rdnss_timeout (device);
616
617         if (changed)
618                 return device;
619         else
620                 return NULL;
621 }
622
623 static struct nla_policy link_policy[IFLA_MAX + 1] = {
624         [IFLA_PROTINFO] = { .type = NLA_NESTED },
625 };
626
627 static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = {
628         [IFLA_INET6_FLAGS]      = { .type = NLA_U32 },
629 };
630
631 static NMIP6Device *
632 process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
633 {
634         struct nlmsghdr *hdr = nlmsg_hdr (msg);
635         struct ifinfomsg *ifi;
636         NMIP6Device *device;
637         struct nlattr *tb[IFLA_MAX + 1];
638         struct nlattr *pi[IFLA_INET6_MAX + 1];
639         int err;
640
641         ifi = nlmsg_data (hdr);
642         if (ifi->ifi_family != AF_INET6)
643                 return NULL;
644
645         device = nm_ip6_manager_get_device (manager, ifi->ifi_index);
646         if (!device || device->addrconf_complete)
647                 return NULL;
648
649         /* FIXME: we have to do this manually for now since libnl doesn't yet
650          * support the IFLA_PROTINFO attribute of NEWLINK messages.  When it does,
651          * we can get rid of this function and just grab IFLA_PROTINFO from
652          * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
653          * the PROTINFO.
654          */
655
656         err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
657         if (err < 0)
658                 return NULL;
659         if (!tb[IFLA_PROTINFO])
660                 return NULL;
661
662         err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy);
663         if (err < 0)
664                 return NULL;
665         if (!pi[IFLA_INET6_FLAGS])
666                 return NULL;
667
668         device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
669         nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags);
670
671         return device;
672 }
673
674 static void
675 netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data)
676 {
677         NMIP6Manager *manager = (NMIP6Manager *) user_data;
678         NMIP6Device *device;
679         struct nlmsghdr *hdr;
680         gboolean config_changed = FALSE;
681
682         hdr = nlmsg_hdr (msg);
683         switch (hdr->nlmsg_type) {
684         case RTM_NEWADDR:
685         case RTM_DELADDR:
686                 device = process_addr (manager, msg);
687                 config_changed = TRUE;
688                 break;
689         case RTM_NEWROUTE:
690         case RTM_DELROUTE:
691                 device = process_route (manager, msg);
692                 config_changed = TRUE;
693                 break;
694         case RTM_NEWPREFIX:
695                 device = process_prefix (manager, msg);
696                 break;
697         case RTM_NEWNDUSEROPT:
698                 device = process_nduseropt (manager, msg);
699                 config_changed = TRUE;
700                 break;
701         case RTM_NEWLINK:
702                 device = process_newlink (manager, msg);
703                 config_changed = TRUE;
704                 break;
705         default:
706                 return;
707         }
708
709         if (device)
710                 nm_ip6_device_sync_from_netlink (device, config_changed);
711 }
712
713 static gboolean
714 get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value)
715 {
716         GError *error;
717         char *contents = NULL;
718         gboolean success = FALSE;
719         long int tmp;
720
721         if (!g_file_get_contents (path, &contents, NULL, &error)) {
722                 nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s",
723                              iface, path,
724                              error ? error->code : -1,
725                              error && error->message ? error->message : "(unknown)");
726                 g_clear_error (&error);
727         } else {
728                 errno = 0;
729                 tmp = strtol (contents, NULL, 10);
730                 if ((errno == 0) && (tmp == 0 || tmp == 1)) {
731                         *out_value = (guint32) tmp;
732                         success = TRUE;
733                 }
734                 g_free (contents);
735         }
736
737         return success;
738 }
739
740 static NMIP6Device *
741 nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
742 {
743         NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
744         NMIP6Device *device;
745
746         g_return_val_if_fail (ifindex > 0, NULL);
747
748         device = g_slice_new0 (NMIP6Device);
749         if (!device) {
750                 nm_log_err (LOGD_IP6, "(%d): out of memory creating IP6 addrconf object.",
751                             ifindex);
752                 return NULL;
753         }
754
755         device->ifindex = ifindex;
756         device->iface = g_strdup (nm_netlink_index_to_iface (ifindex));
757         if (!device->iface) {
758                 nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.",
759                             ifindex);
760                 goto error;
761         }
762
763         device->manager = manager;
764
765         device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
766
767         g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device);
768
769         /* Grab the original value of "accept_ra" so we can restore it when the
770          * device is taken down.
771          */
772         device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra",
773                                                   device->iface);
774         g_assert (device->accept_ra_path);
775         device->accept_ra_save_valid = get_proc_sys_net_value (device->accept_ra_path,
776                                                                device->iface,
777                                                                &device->accept_ra_save);
778
779         /* and the original value of IPv6 enable/disable */
780         device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
781                                                     device->iface);
782         g_assert (device->disable_ip6_path);
783         device->disable_ip6_save_valid = get_proc_sys_net_value (device->disable_ip6_path,
784                                                                  device->iface,
785                                                                  &device->disable_ip6_save);
786
787         return device;
788
789 error:
790         nm_ip6_device_destroy (device);
791         return NULL;
792 }
793
794 void
795 nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
796                                                                   int ifindex,
797                                                                   NMSettingIP6Config *s_ip6)
798 {
799         NMIP6ManagerPrivate *priv;
800         NMIP6Device *device;
801         const char *method = NULL;
802
803         g_return_if_fail (NM_IS_IP6_MANAGER (manager));
804         g_return_if_fail (ifindex > 0);
805
806         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
807
808         device = nm_ip6_device_new (manager, ifindex);
809         g_return_if_fail (device != NULL);
810         g_return_if_fail (   strchr (device->iface, '/') == NULL
811                           && strcmp (device->iface, "all") != 0
812                           && strcmp (device->iface, "default") != 0);
813
814         if (s_ip6)
815                 method = nm_setting_ip6_config_get_method (s_ip6);
816         if (!method)
817                 method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
818
819         /* Establish target state and turn router advertisement acceptance on or off */
820         if (   !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)
821                 || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
822                 device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
823                 nm_utils_do_sysctl (device->accept_ra_path, "0\n");
824         } else {
825                 device->target_state = NM_IP6_DEVICE_GOT_ADDRESS;
826                 nm_utils_do_sysctl (device->accept_ra_path, "1\n");
827         }
828 }
829
830 static gboolean
831 poll_ip6_flags (gpointer user_data)
832 {
833         nm_netlink_monitor_request_ip6_info (NM_NETLINK_MONITOR (user_data), NULL);
834         return TRUE;
835 }
836
837 void
838 nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex)
839 {
840         NMIP6ManagerPrivate *priv;
841         NMIP6Device *device;
842         CallbackInfo *info;
843
844         g_return_if_fail (NM_IS_IP6_MANAGER (manager));
845         g_return_if_fail (ifindex > 0);
846
847         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
848
849         device = (NMIP6Device *) g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
850         g_return_if_fail (device != NULL);
851
852         nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", device->iface);
853
854         device->addrconf_complete = FALSE;
855         device->ra_flags = 0;
856
857         /* Set up a timeout on the transaction to kill it after the timeout */
858         info = callback_info_new (device, 0, FALSE);
859         device->finish_addrconf_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
860                                                                  NM_IP6_TIMEOUT,
861                                                                  finish_addrconf,
862                                                                  info,
863                                                                  (GDestroyNotify) g_free);
864
865         /* Bounce IPv6 on the interface to ensure the kernel will start looking for
866          * new RAs; there doesn't seem to be a better way to do this right now.
867          */
868         if (device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS) {
869                 nm_utils_do_sysctl (device->disable_ip6_path, "1\n");
870                 g_usleep (200);
871                 nm_utils_do_sysctl (device->disable_ip6_path, "0\n");
872         }
873
874         device->ip6flags_poll_id = g_timeout_add_seconds (1, poll_ip6_flags, priv->monitor);
875
876         /* Kick off the initial IPv6 flags request */
877         nm_netlink_monitor_request_ip6_info (priv->monitor, NULL);
878
879         /* Sync flags, etc, from netlink; this will also notice if the
880          * device is already fully configured and schedule the
881          * ADDRCONF_COMPLETE signal in that case.
882          */
883         nm_ip6_device_sync_from_netlink (device, FALSE);
884 }
885
886 void
887 nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, int ifindex)
888 {
889         g_return_if_fail (NM_IS_IP6_MANAGER (manager));
890         g_return_if_fail (ifindex > 0);
891
892         g_hash_table_remove (NM_IP6_MANAGER_GET_PRIVATE (manager)->devices,
893                              GINT_TO_POINTER (ifindex));
894 }
895
896 #define FIRST_ROUTE(m) ((struct rtnl_route *) nl_cache_get_first (m))
897 #define NEXT_ROUTE(m) ((struct rtnl_route *) nl_cache_get_next ((struct nl_object *) m))
898
899 #define FIRST_ADDR(m) ((struct rtnl_addr *) nl_cache_get_first (m))
900 #define NEXT_ADDR(m) ((struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) m))
901
902 NMIP6Config *
903 nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
904 {
905         NMIP6ManagerPrivate *priv;
906         NMIP6Device *device;
907         NMIP6Config *config;
908         struct rtnl_addr *rtnladdr;
909         struct nl_addr *nladdr;
910         struct in6_addr *addr;
911         NMIP6Address *ip6addr;
912         struct rtnl_route *rtnlroute;
913         struct nl_addr *nldest, *nlgateway;
914         struct in6_addr *dest, *gateway;
915         gboolean defgw_set = FALSE;
916         struct in6_addr defgw;
917         uint32_t metric;
918         NMIP6Route *ip6route;
919         int i;
920
921         g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
922         g_return_val_if_fail (ifindex > 0, NULL);
923
924         priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
925
926         device = (NMIP6Device *) g_hash_table_lookup (priv->devices,
927                                                       GINT_TO_POINTER (ifindex));
928         if (!device) {
929                 nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex);
930                 return NULL;
931         }
932
933         config = nm_ip6_config_new ();
934         if (!config) {
935                 nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.",
936                             device->iface);
937                 return NULL;
938         }
939
940         /* Make sure we refill the route and address caches, otherwise we won't get
941          * up-to-date information here since the netlink route/addr change messages
942          * may be lagging a bit.
943          */
944         nl_cache_refill (priv->nlh, priv->route_cache);
945         nl_cache_refill (priv->nlh, priv->addr_cache);
946
947         /* Add routes */
948         for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) {
949                 /* Make sure it's an IPv6 route for this device */
950                 if (rtnl_route_get_oif (rtnlroute) != device->ifindex)
951                         continue;
952                 if (rtnl_route_get_family (rtnlroute) != AF_INET6)
953                         continue;
954
955                 nldest = rtnl_route_get_dst (rtnlroute);
956                 if (!nldest || nl_addr_get_family (nldest) != AF_INET6)
957                         continue;
958                 dest = nl_addr_get_binary_addr (nldest);
959
960                 nlgateway = rtnl_route_get_gateway (rtnlroute);
961                 if (!nlgateway || nl_addr_get_family (nlgateway) != AF_INET6)
962                         continue;
963                 gateway = nl_addr_get_binary_addr (nlgateway);
964
965                 if (rtnl_route_get_dst_len (rtnlroute) == 0) {
966                         /* Default gateway route; don't add to normal routes but to each address */
967                         if (!defgw_set) {
968                                 memcpy (&defgw, gateway, sizeof (defgw));
969                                 defgw_set = TRUE;
970                         }
971                         continue;
972                 }
973
974                 ip6route = nm_ip6_route_new ();
975                 nm_ip6_route_set_dest (ip6route, dest);
976                 nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute));
977                 nm_ip6_route_set_next_hop (ip6route, gateway);
978                 metric = rtnl_route_get_metric (rtnlroute, 1);
979                 if (metric != UINT_MAX)
980                         nm_ip6_route_set_metric (ip6route, metric);
981                 nm_ip6_config_take_route (config, ip6route);
982         }
983
984         /* Add addresses */
985         for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) {
986                 if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
987                         continue;
988
989                 nladdr = rtnl_addr_get_local (rtnladdr);
990                 if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
991                         continue;
992
993                 addr = nl_addr_get_binary_addr (nladdr);
994                 ip6addr = nm_ip6_address_new ();
995                 nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
996                 nm_ip6_address_set_address (ip6addr, addr);
997                 nm_ip6_config_take_address (config, ip6addr);
998                 if (defgw_set)
999                         nm_ip6_address_set_gateway (ip6addr, &defgw);
1000         }
1001
1002         /* Add DNS servers */
1003         if (device->rdnss_servers) {
1004                 NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data);
1005
1006                 for (i = 0; i < device->rdnss_servers->len; i++)
1007                         nm_ip6_config_add_nameserver (config, &rdnss[i].addr);
1008         }
1009
1010         return config;
1011 }