ip6: fail if the RA-provided address disappears or RDNSS expires
authorDan Williams <dcbw@redhat.com>
Mon, 3 May 2010 10:02:57 +0000 (03:02 -0700)
committerDan Williams <dcbw@redhat.com>
Mon, 3 May 2010 10:02:57 +0000 (03:02 -0700)
src/ip6-manager/nm-ip6-manager.c
src/ip6-manager/nm-ip6-manager.h
src/nm-device.c

index 1b544a2..5101faf 100644 (file)
@@ -282,7 +282,10 @@ emit_config_changed (gpointer user_data)
        NMIP6Manager *manager = device->manager;
 
        device->config_changed_id = 0;
-       g_signal_emit (manager, signals[CONFIG_CHANGED], 0, device->ifindex, info->dhcp_opts);
+       g_signal_emit (manager, signals[CONFIG_CHANGED], 0,
+                      device->ifindex,
+                      info->dhcp_opts,
+                      info->success);
        return FALSE;
 }
 
@@ -386,7 +389,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
        struct in6_addr *addr;
        CallbackInfo *info;
        guint dhcp_opts = IP6_DHCP_OPT_NONE;
-       gboolean found_linklocal = FALSE;
+       gboolean found_linklocal = FALSE, found_other = FALSE;
 
        nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')",
                    device->iface, device->ra_flags,
@@ -420,6 +423,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
                } else {
                        if (device->state < NM_IP6_DEVICE_GOT_ADDRESS)
                                device->state = NM_IP6_DEVICE_GOT_ADDRESS;
+                       found_other = TRUE;
                }
        }
 
@@ -473,7 +477,20 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
                }
        } else if (config_changed) {
                if (!device->config_changed_id) {
-                       info = callback_info_new (device, dhcp_opts, TRUE);
+                       gboolean success = TRUE;
+
+                       /* If for some reason an RA-provided address disappeared, we need
+                        * to make sure we fail the connection as it's no longer valid.
+                        */
+                       if (   (device->state == NM_IP6_DEVICE_GOT_ADDRESS)
+                           && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
+                           && !found_other) {
+                               nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer valid",
+                                           device->iface);
+                               success = FALSE;
+                       }
+
+                       info = callback_info_new (device, dhcp_opts, success);
                        device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
                                                                     emit_config_changed,
                                                                     info,
@@ -1141,7 +1158,7 @@ nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class)
                                          G_SIGNAL_RUN_FIRST,
                                          G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed),
                                          NULL, NULL,
-                                         _nm_marshal_VOID__INT_UINT,
-                                         G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT);
+                                         _nm_marshal_VOID__INT_UINT_BOOLEAN,
+                                         G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);
 }
 
index db92066..7cd0ef7 100644 (file)
@@ -64,7 +64,8 @@ typedef struct {
         */
        void (*config_changed)    (NMIP6Manager *manager,
                                   guint32 ifindex,
-                                  guint dhcp_opts);
+                                  guint dhcp_opts,
+                                  gboolean success);
 } NMIP6ManagerClass;
 
 GType nm_ip6_manager_get_type (void);
index a09a692..d8f7b64 100644 (file)
@@ -681,6 +681,7 @@ static void
 ip6_config_changed (NMIP6Manager *ip6_manager,
                     int ifindex,
                     guint dhcp_opts,
+                    gboolean success,
                     gpointer user_data)
 {
        NMDevice *self = NM_DEVICE (user_data);
@@ -692,6 +693,13 @@ ip6_config_changed (NMIP6Manager *ip6_manager,
 
        /* FIXME: re-run DHCPv6 here to get any new nameservers or whatever */
 
+       if (!success && (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) {
+               nm_device_state_changed (self,
+                                        NM_DEVICE_STATE_FAILED,
+                                        NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+               return;
+       }
+
        nm_device_activate_schedule_stage4_ip6_config_get (self);
 }