ip6: save the accept_ra value and re-set it when the device is deactivated
authorDan Williams <dcbw@redhat.com>
Mon, 19 Oct 2009 22:38:21 +0000 (15:38 -0700)
committerDan Williams <dcbw@redhat.com>
Mon, 19 Oct 2009 22:38:21 +0000 (15:38 -0700)
src/ip6-manager/nm-ip6-manager.c
src/nm-device.c

index 7f280ce..8908c86 100644 (file)
@@ -18,6 +18,7 @@
  * Copyright (C) 2009 Red Hat, Inc.
  */
 
+#include <errno.h>
 #include <netinet/icmp6.h>
 
 #include <netlink/route/rtnl.h>
@@ -68,6 +69,10 @@ typedef struct {
        char *iface;
        int index;
 
+       char *accept_ra_path;
+       gboolean accept_ra_save_valid;
+       guint32 accept_ra_save;
+
        guint finish_addrconf_id;
        guint config_changed_id;
 
@@ -179,6 +184,14 @@ nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class)
 static void
 nm_ip6_device_destroy (NMIP6Device *device)
 {
+       g_return_if_fail (device != NULL);
+
+       /* reset the saved RA value */
+       if (device->accept_ra_save_valid) {
+               nm_utils_do_sysctl (device->accept_ra_path,
+                                   device->accept_ra_save ? "1\n" : "0\n");
+       }
+
        if (device->finish_addrconf_id)
                g_source_remove (device->finish_addrconf_id);
        if (device->config_changed_id)
@@ -189,6 +202,7 @@ nm_ip6_device_destroy (NMIP6Device *device)
        if (device->rdnss_timeout_id)
                g_source_remove (device->rdnss_timeout_id);
 
+       g_free (device->accept_ra_path);
        g_slice_free (NMIP6Device, device);
 }
 
@@ -600,6 +614,8 @@ nm_ip6_device_new (NMIP6Manager *manager, const char *iface)
 {
        NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
        NMIP6Device *device;
+       GError *error = NULL;
+       char *contents = NULL;
 
        device = g_slice_new0 (NMIP6Device);
        if (!device) {
@@ -616,6 +632,14 @@ nm_ip6_device_new (NMIP6Manager *manager, const char *iface)
        }
        device->index = nm_netlink_iface_to_index (iface);
 
+       device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", iface);
+       if (!device->accept_ra_path) {
+               nm_warning ("%s: Out of memory creating IP6 addrconf object "
+                           "property 'accept_ra_path'.",
+                           iface);
+               goto error;
+       }
+
        device->manager = manager;
 
        device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
@@ -623,6 +647,27 @@ nm_ip6_device_new (NMIP6Manager *manager, const char *iface)
        g_hash_table_replace (priv->devices_by_iface, device->iface, device);
        g_hash_table_replace (priv->devices_by_index, GINT_TO_POINTER (device->index), device);
 
+       /* Grab the original value of "accept_ra" so we can restore it when the
+        * device is taken down.
+        */
+       if (!g_file_get_contents (device->accept_ra_path, &contents, NULL, &error)) {
+               nm_warning ("%s: error reading %s: (%d) %s",
+                           iface, device->accept_ra_path,
+                           error ? error->code : -1,
+                           error && error->message ? error->message : "(unknown)");
+               g_clear_error (&error);
+       } else {
+               long int tmp;
+
+               errno = 0;
+               tmp = strtol (contents, NULL, 10);
+               if ((errno == 0) && (tmp == 0 || tmp == 1)) {
+                       device->accept_ra_save = (guint32) tmp;
+                       device->accept_ra_save_valid = TRUE;
+               }
+               g_free (contents);
+       }
+
        return device;
 
 error:
@@ -638,7 +683,6 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
        NMIP6ManagerPrivate *priv;
        NMIP6Device *device;
        const char *method = NULL;
-       char *sysctl_path;
 
        g_return_if_fail (NM_IS_IP6_MANAGER (manager));
        g_return_if_fail (iface != NULL);
@@ -662,10 +706,9 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
                                          strcmp (iface, "all") != 0 &&
                                          strcmp (iface, "default") != 0);
 
-       sysctl_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", iface);
-       nm_utils_do_sysctl (sysctl_path,
-                                               device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS ? "1\n" : "0\n");
-       g_free (sysctl_path);
+       /* Turn router advertisement acceptance on or off... */
+       nm_utils_do_sysctl (device->accept_ra_path,
+                           device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS ? "1\n" : "0\n");
 }
 
 void
index 1a7b8f8..6c0f99c 100644 (file)
@@ -607,21 +607,22 @@ nm_device_cleanup_ip6 (NMDevice *self)
 {
        NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-       if (priv->ip6_manager) {
-               if (priv->ip6_addrconf_sigid) {
-                       g_signal_handler_disconnect (priv->ip6_manager,
-                                                                                priv->ip6_addrconf_sigid);
-                       priv->ip6_addrconf_sigid = 0;
-               }
-               if (priv->ip6_config_changed_sigid) {
-                       g_signal_handler_disconnect (priv->ip6_manager,
-                                                                                priv->ip6_config_changed_sigid);
-                       priv->ip6_config_changed_sigid = 0;
-               }
+       if (!priv->ip6_manager)
+               return;
 
-               g_object_unref (priv->ip6_manager);
-               priv->ip6_manager = NULL;
+       if (priv->ip6_addrconf_sigid) {
+               g_signal_handler_disconnect (priv->ip6_manager,
+                                            priv->ip6_addrconf_sigid);
+               priv->ip6_addrconf_sigid = 0;
+       }
+       if (priv->ip6_config_changed_sigid) {
+               g_signal_handler_disconnect (priv->ip6_manager,
+                                            priv->ip6_config_changed_sigid);
+               priv->ip6_config_changed_sigid = 0;
        }
+
+       g_object_unref (priv->ip6_manager);
+       priv->ip6_manager = NULL;
 }
 
 /*