From 214114fb2d8cb88a5446175b23fc0ede8be13129 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 7 Nov 2008 13:57:39 +0000 Subject: [PATCH] 2008-11-07 Dan Williams Fix deletion of VPN gateway route on DHCP renew (bgo #558133) * src/NetworkManagerSystem.c src/NetworkManagerSystem.h - (nm_system_device_set_ip4_route): return the route that was added - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() public, clean up, and return the route that was added - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, since nm_system_add_ip4_vpn_gateway_route() is now available; add flags to allow only certain attributes of the NMIP4Config to be applied * src/nm-device.c - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply what's really changed between the old and new configs; don't export the new IP4 config on failure; always send the DNS info to the named manager * src/vpn-manager/nm-vpn-connection.c - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the parent device's IP4Config and re-add the VPN gateway route when it changes - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since nm_system_apply_ip4_config() no longer does) and cache it for later - (connection_state_changed): move cleanup code to its own function - (vpn_cleanup): delete any previously added VPN gateway route; and re-apply the parent device's addresses and routes using nm_system_apply_ip4_config(), not nm_device_set_ip4_config() git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4277 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 32 +++++++ src/NetworkManagerSystem.c | 111 ++++++++++++----------- src/NetworkManagerSystem.h | 11 ++- src/nm-device.c | 60 ++++++++----- src/nm-device.h | 3 - src/vpn-manager/nm-vpn-connection.c | 135 +++++++++++++++++++--------- 6 files changed, 231 insertions(+), 121 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4f086833d2..59bae46436 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2008-11-07 Dan Williams + + Fix deletion of VPN gateway route on DHCP renew (bgo #558133) + + * src/NetworkManagerSystem.c + src/NetworkManagerSystem.h + - (nm_system_device_set_ip4_route): return the route that was added + - (nm_system_add_ip4_vpn_gateway_route): make add_vpn_gateway_route() + public, clean up, and return the route that was added + - (nm_system_apply_ip4_config): remove VPN related stuff to simplify, + since nm_system_add_ip4_vpn_gateway_route() is now available; add + flags to allow only certain attributes of the NMIP4Config to be + applied + + * src/nm-device.c + - (handle_dhcp_lease_change): don't touch the DHCP4 config on failure + - (nm_device_set_ip4_config): use nm_ip4_config_diff() to only apply + what's really changed between the old and new configs; don't export + the new IP4 config on failure; always send the DNS info to the + named manager + + * src/vpn-manager/nm-vpn-connection.c + - (device_ip4_config_changed, nm_vpn_connection_new, dispose): track the + parent device's IP4Config and re-add the VPN gateway route when it + changes + - (nm_vpn_connection_ip4_config_get): add the VPN gateway route (since + nm_system_apply_ip4_config() no longer does) and cache it for later + - (connection_state_changed): move cleanup code to its own function + - (vpn_cleanup): delete any previously added VPN gateway route; and + re-apply the parent device's addresses and routes using + nm_system_apply_ip4_config(), not nm_device_set_ip4_config() + 2008-11-07 Dan Williams * src/nm-ip4-config.c diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index ae75e4e667..218101794e 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -103,7 +103,7 @@ create_route (int iface_idx, int mss) return route; } -static void +static struct rtnl_route * nm_system_device_set_ip4_route (const char *iface, guint32 ip4_dest, guint32 ip4_prefix, @@ -118,17 +118,17 @@ nm_system_device_set_ip4_route (const char *iface, int err, iface_idx; nlh = nm_netlink_get_default_handle (); - g_return_if_fail (nlh != NULL); + g_return_val_if_fail (nlh != NULL, NULL); iface_idx = nm_netlink_iface_to_index (iface); - g_return_if_fail (iface_idx >= 0); + g_return_val_if_fail (iface_idx >= 0, NULL); route = create_route (iface_idx, mss); - g_return_if_fail (route != NULL); + g_return_val_if_fail (route != NULL, NULL); /* Destination */ dest_addr = nl_addr_build (AF_INET, &ip4_dest, sizeof (ip4_dest)); - g_return_if_fail (dest_addr != NULL); + g_return_val_if_fail (dest_addr != NULL, NULL); nl_addr_set_prefixlen (dest_addr, (int) ip4_prefix); rtnl_route_set_dst (route, dest_addr); @@ -143,7 +143,7 @@ nm_system_device_set_ip4_route (const char *iface, } else { nm_warning ("Invalid gateway"); rtnl_route_put (route); - return; + return NULL; } } @@ -168,17 +168,20 @@ nm_system_device_set_ip4_route (const char *iface, if (err) rtnl_route_del (nlh, route2, 0); } - rtnl_route_put (route2); } } - if (err) - nm_warning ("Failed to set IPv4 route on '%s': %s", iface, nl_geterror ()); - - rtnl_route_put (route); if (gw_addr) nl_addr_put (gw_addr); + + if (err) { + nm_warning ("Failed to set IPv4 route on '%s': %s", iface, nl_geterror ()); + rtnl_route_put (route); + route = NULL; + } + + return route; } typedef struct { @@ -267,23 +270,22 @@ add_ip4_addresses (NMIP4Config *config, const char *iface) return TRUE; } -static void -add_vpn_gateway_route (NMDevice *parent_device, - const char *iface, - NMIP4Config *vpn_config) +struct rtnl_route * +nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_config) { NMIP4Config *parent_config; guint32 parent_gw = 0, parent_prefix = 0, vpn_gw = 0, i; NMIP4Address *tmp; + struct rtnl_route *route = NULL; - g_return_if_fail (NM_IS_DEVICE (parent_device)); + g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL); /* Set up a route to the VPN gateway's public IP address through the default * network device if the VPN gateway is on a different subnet. */ parent_config = nm_device_get_ip4_config (parent_device); - g_return_if_fail (parent_config != NULL); + g_return_val_if_fail (parent_config != NULL, NULL); for (i = 0; i < nm_ip4_config_get_num_addresses (parent_config); i++) { tmp = nm_ip4_config_get_address (parent_config, i); @@ -303,19 +305,21 @@ add_vpn_gateway_route (NMDevice *parent_device, } if (!parent_gw || !vpn_gw) - return; + return NULL; /* If the VPN gateway is in the same subnet as one of the parent device's * IP addresses, don't add the host route to it, but a route through the * parent device. */ if (ip4_dest_in_same_subnet (parent_config, vpn_gw, parent_prefix)) { - nm_system_device_set_ip4_route (nm_device_get_ip_iface (parent_device), - vpn_gw, 32, 0, 0, nm_ip4_config_get_mss (parent_config)); + route = nm_system_device_set_ip4_route (nm_device_get_ip_iface (parent_device), + vpn_gw, 32, 0, 0, nm_ip4_config_get_mss (parent_config)); } else { - nm_system_device_set_ip4_route (nm_device_get_ip_iface (parent_device), - vpn_gw, 32, parent_gw, 0, nm_ip4_config_get_mss (parent_config)); + route = nm_system_device_set_ip4_route (nm_device_get_ip_iface (parent_device), + vpn_gw, 32, parent_gw, 0, nm_ip4_config_get_mss (parent_config)); } + + return route; } /* @@ -325,46 +329,49 @@ add_vpn_gateway_route (NMDevice *parent_device, * */ gboolean -nm_system_apply_ip4_config (NMDevice *device, - const char *iface, +nm_system_apply_ip4_config (const char *iface, NMIP4Config *config, int priority, - gboolean is_vpn) + NMIP4ConfigCompareFlags flags) { int i; g_return_val_if_fail (iface != NULL, FALSE); g_return_val_if_fail (config != NULL, FALSE); - if (!add_ip4_addresses (config, iface)) - return FALSE; - - if (is_vpn) - add_vpn_gateway_route (device, iface, config); - - sleep (1); - - for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) { - NMIP4Route *route = nm_ip4_config_get_route (config, i); - - /* Don't add the route if it's more specific than one of the subnets - * the device already has an IP address on. - */ - if (ip4_dest_in_same_subnet (config, - nm_ip4_route_get_dest (route), - nm_ip4_route_get_prefix (route))) - continue; - - nm_system_device_set_ip4_route (iface, - nm_ip4_route_get_dest (route), - nm_ip4_route_get_prefix (route), - nm_ip4_route_get_next_hop (route), - nm_ip4_route_get_metric (route), - nm_ip4_config_get_mss (config)); + if (flags & NM_IP4_COMPARE_FLAG_ADDRESSES) { + if (!add_ip4_addresses (config, iface)) + return FALSE; + sleep (1); } - if (nm_ip4_config_get_mtu (config)) - nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config)); + if (flags & NM_IP4_COMPARE_FLAG_ROUTES) { + for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) { + NMIP4Route *route = nm_ip4_config_get_route (config, i); + struct rtnl_route *tmp; + + /* Don't add the route if it's more specific than one of the subnets + * the device already has an IP address on. + */ + if (ip4_dest_in_same_subnet (config, + nm_ip4_route_get_dest (route), + nm_ip4_route_get_prefix (route))) + continue; + + tmp = nm_system_device_set_ip4_route (iface, + nm_ip4_route_get_dest (route), + nm_ip4_route_get_prefix (route), + nm_ip4_route_get_next_hop (route), + nm_ip4_route_get_metric (route), + nm_ip4_config_get_mss (config)); + rtnl_route_put (tmp); + } + } + + if (flags & NM_IP4_COMPARE_FLAG_MTU) { + if (nm_ip4_config_get_mtu (config)) + nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config)); + } if (priority > 0) nm_system_device_set_priority (iface, config, priority); diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index cfa7ab5bce..b83a663d00 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -22,6 +22,9 @@ #ifndef NETWORK_MANAGER_SYSTEM_H #define NETWORK_MANAGER_SYSTEM_H +#include +#include + #include #include "nm-device.h" #include "nm-ip4-config.h" @@ -44,17 +47,19 @@ gboolean nm_system_replace_default_ip4_route_vpn (const char *iface, const char *parent_iface, guint32 parent_mss); +struct rtnl_route *nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_config); + + void nm_system_device_flush_ip4_addresses (NMDevice *dev); void nm_system_device_flush_ip4_addresses_with_iface (const char *iface); void nm_system_enable_loopback (void); void nm_system_update_dns (void); -gboolean nm_system_apply_ip4_config (NMDevice *device, - const char *iface, +gboolean nm_system_apply_ip4_config (const char *iface, NMIP4Config *config, int priority, - gboolean is_vpn); + NMIP4ConfigCompareFlags flags); gboolean nm_system_device_set_up_down (NMDevice *dev, gboolean up, diff --git a/src/nm-device.c b/src/nm-device.c index 3f8e8b3b15..5cf26d905b 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -120,6 +120,8 @@ static void nm_device_take_down (NMDevice *dev, gboolean wait, NMDeviceStateReas static gboolean nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware); static gboolean nm_device_is_up (NMDevice *self); +static gboolean nm_device_set_ip4_config (NMDevice *dev, NMIP4Config *config, NMDeviceStateReason *reason); + static void device_interface_init (NMDeviceInterface *device_interface_class) { @@ -1754,12 +1756,12 @@ handle_dhcp_lease_change (NMDevice *device) g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config); - if (!nm_device_set_ip4_config (device, config, &reason)) { + if (nm_device_set_ip4_config (device, config, &reason)) + nm_dhcp_manager_set_dhcp4_config (priv->dhcp_manager, ip_iface, priv->dhcp4_config); + else { nm_warning ("Failed to update IP4 config in response to DHCP event."); nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); } - - nm_dhcp_manager_set_dhcp4_config (priv->dhcp_manager, ip_iface, priv->dhcp4_config); } static void @@ -1905,12 +1907,17 @@ nm_device_get_ip4_config (NMDevice *self) } -gboolean -nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, NMDeviceStateReason *reason) +static gboolean +nm_device_set_ip4_config (NMDevice *self, + NMIP4Config *new_config, + NMDeviceStateReason *reason) { NMDevicePrivate *priv; const char *ip_iface; - gboolean success; + NMIP4Config *old_config = NULL; + gboolean success = TRUE; + NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL; + NMNamedManager *named_mgr; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); g_return_val_if_fail (reason != NULL, FALSE); @@ -1918,30 +1925,39 @@ nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, NMDeviceStateReas priv = NM_DEVICE_GET_PRIVATE (self); ip_iface = nm_device_get_ip_iface (self); - if (priv->ip4_config) { - NMNamedManager *named_mgr; + old_config = priv->ip4_config; + if (new_config && old_config) + diff = nm_ip4_config_diff (new_config, old_config); + + /* No actual change, do nothing */ + if (diff == NM_IP4_COMPARE_FLAG_NONE) + return TRUE; + + named_mgr = nm_named_manager_get (); + if (old_config) { /* Remove any previous IP4 Config from the named manager */ - named_mgr = nm_named_manager_get (); - nm_named_manager_remove_ip4_config (named_mgr, ip_iface, priv->ip4_config); - g_object_unref (named_mgr); - - g_object_unref (priv->ip4_config); + nm_named_manager_remove_ip4_config (named_mgr, ip_iface, old_config); + g_object_unref (old_config); priv->ip4_config = NULL; } - if (!config) - return TRUE; + if (new_config) { + priv->ip4_config = g_object_ref (new_config); - priv->ip4_config = g_object_ref (config); + success = nm_system_apply_ip4_config (ip_iface, new_config, nm_device_get_priority (self), diff); + if (success) { + /* Export over D-Bus */ + if (!nm_ip4_config_get_dbus_path (new_config)) + nm_ip4_config_export (new_config); - /* Export over D-Bus if needed */ - if (!nm_ip4_config_get_dbus_path (config)) - nm_ip4_config_export (config); + /* Add the DNS information to the named manager */ + nm_named_manager_add_ip4_config (named_mgr, ip_iface, new_config, NM_NAMED_IP_CONFIG_TYPE_DEFAULT); - success = nm_system_apply_ip4_config (self, ip_iface, config, nm_device_get_priority (self), FALSE); - if (success) - nm_device_update_ip4_address (self); + nm_device_update_ip4_address (self); + } + } + g_object_unref (named_mgr); g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP4_CONFIG); diff --git a/src/nm-device.h b/src/nm-device.h index 305af73bbd..f78e1e8e94 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -139,9 +139,6 @@ void nm_device_set_use_dhcp (NMDevice *dev, NMDHCP4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMIP4Config * nm_device_get_ip4_config (NMDevice *dev); -gboolean nm_device_set_ip4_config (NMDevice *dev, - NMIP4Config *config, - NMDeviceStateReason *reason); void * nm_device_get_system_config_data (NMDevice *dev); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 389e1bd942..8c0a7a9c0b 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -44,6 +44,7 @@ #include "nm-dbus-glib-types.h" #include "NetworkManagerUtils.h" #include "nm-named-manager.h" +#include "nm-netlink.h" #include "nm-vpn-connection-glue.h" @@ -56,22 +57,25 @@ typedef struct { DBusGProxyCall *secrets_call; NMActRequest *act_request; - NMDevice *parent_dev; char *ac_path; + NMDevice *parent_dev; + gulong device_monitor; + gulong device_ip4; + gboolean is_default; NMActiveConnectionState state; NMVPNConnectionState vpn_state; NMVPNConnectionStateReason failure_reason; - gulong device_monitor; DBusGProxy *proxy; guint ipconfig_timeout; NMIP4Config *ip4_config; guint32 ip4_internal_gw; char *tundev; - char *tapdev; char *banner; + + struct rtnl_route *gw_route; } NMVPNConnectionPrivate; #define NM_VPN_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_CONNECTION, NMVPNConnectionPrivate)) @@ -155,7 +159,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, nm_utils_call_dispatcher ("vpn-up", priv->connection, priv->parent_dev, - priv->tapdev ? priv->tapdev : priv->tundev); + priv->tundev); break; case NM_VPN_CONNECTION_STATE_FAILED: case NM_VPN_CONNECTION_STATE_DISCONNECTED: @@ -163,7 +167,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, nm_utils_call_dispatcher ("vpn-down", priv->connection, priv->parent_dev, - priv->tapdev ? priv->tapdev : priv->tundev); + priv->tundev); } break; default: @@ -193,6 +197,24 @@ device_state_changed (NMDevice *device, } } +static void +device_ip4_config_changed (NMDevice *device, + GParamSpec *pspec, + gpointer user_data) +{ + NMVPNConnection *vpn = NM_VPN_CONNECTION (user_data); + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (vpn); + + if (priv->vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED) + return; + + if (priv->gw_route) + rtnl_route_put (priv->gw_route); + + /* Re-add the VPN gateway route */ + priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, priv->ip4_config); +} + NMVPNConnection * nm_vpn_connection_new (NMConnection *connection, NMActRequest *act_request, @@ -218,6 +240,10 @@ nm_vpn_connection_new (NMConnection *connection, priv->device_monitor = g_signal_connect (parent_device, "state-changed", G_CALLBACK (device_state_changed), vpn_connection); + + priv->device_ip4 = g_signal_connect (parent_device, "notify::" NM_DEVICE_INTERFACE_IP4_CONFIG, + G_CALLBACK (device_ip4_config_changed), + vpn_connection); return vpn_connection; } @@ -470,9 +496,12 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, nm_system_device_set_up_down_with_iface (priv->tundev, TRUE, NULL); - if (nm_system_apply_ip4_config (priv->parent_dev, priv->tundev, config, 0, TRUE)) { + if (nm_system_apply_ip4_config (priv->tundev, config, 0, NM_IP4_COMPARE_FLAG_ALL)) { NMNamedManager *named_mgr; + /* Add any explicit route to the VPN gateway through the parent device */ + priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, config); + /* Add the VPN to DNS */ named_mgr = nm_named_manager_get (); nm_named_manager_add_ip4_config (named_mgr, priv->tundev, config, NM_NAMED_IP_CONFIG_TYPE_VPN); @@ -889,6 +918,58 @@ call_need_secrets (NMVPNConnection *vpn_connection) g_hash_table_destroy (settings); } +static void +vpn_cleanup (NMVPNConnection *connection) +{ + NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + + if (priv->tundev) { + nm_system_device_set_up_down_with_iface (priv->tundev, FALSE, NULL); + nm_system_device_flush_ip4_routes_with_iface (priv->tundev); + nm_system_device_flush_ip4_addresses_with_iface (priv->tundev); + } + + if (priv->ip4_config) { + NMIP4Config *parent_config; + NMNamedManager *named_mgr; + + /* Remove attributes of the VPN's IP4 Config */ + named_mgr = nm_named_manager_get (); + nm_named_manager_remove_ip4_config (named_mgr, priv->tundev, priv->ip4_config); + g_object_unref (named_mgr); + + /* Remove any previously added VPN gateway host route */ + if (priv->gw_route) + rtnl_route_del (nm_netlink_get_default_handle (), priv->gw_route, 0); + + /* Reset routes and addresses of the currently active device */ + parent_config = nm_device_get_ip4_config (priv->parent_dev); + if (parent_config) { + if (!nm_system_apply_ip4_config (nm_device_get_ip_iface (priv->parent_dev), + nm_device_get_ip4_config (priv->parent_dev), + nm_device_get_priority (priv->parent_dev), + NM_IP4_COMPARE_FLAG_ADDRESSES | NM_IP4_COMPARE_FLAG_ROUTES)) { + nm_warning ("%s: failed to re-apply VPN parent device addresses and routes.", __func__); + } + } + } + + if (priv->gw_route) { + rtnl_route_put (priv->gw_route); + priv->gw_route = NULL; + } + + if (priv->banner) { + g_free (priv->banner); + priv->banner = NULL; + } + + if (priv->tundev) { + g_free (priv->tundev); + priv->tundev = NULL; + } +} + static void connection_state_changed (NMVPNConnection *connection, NMVPNConnectionState state, @@ -916,41 +997,7 @@ connection_state_changed (NMVPNConnection *connection, g_object_unref (priv->proxy); priv->proxy = NULL; } - - if (priv->tundev) { - nm_system_device_set_up_down_with_iface (priv->tundev, FALSE, NULL); - nm_system_device_flush_ip4_routes_with_iface (priv->tundev); - nm_system_device_flush_ip4_addresses_with_iface (priv->tundev); - } - - if (priv->ip4_config) { - NMIP4Config *dev_ip4_config; - NMNamedManager *named_mgr; - - /* Remove attributes of the VPN's IP4 Config */ - named_mgr = nm_named_manager_get (); - nm_named_manager_remove_ip4_config (named_mgr, priv->tundev, priv->ip4_config); - g_object_unref (named_mgr); - - /* Reset routes, nameservers, and domains of the currently active device */ - dev_ip4_config = nm_device_get_ip4_config (priv->parent_dev); - if (dev_ip4_config) { - NMDeviceStateReason dev_reason = NM_DEVICE_STATE_REASON_NONE; - - /* Since the config we're setting is also the device's current - * config, have to ref the config to ensure it doesn't get - * destroyed when the device unrefs it in nm_device_set_ip4_config(). - */ - nm_device_set_ip4_config (priv->parent_dev, - g_object_ref (dev_ip4_config), - &dev_reason); - } - } - - if (priv->banner) { - g_free (priv->banner); - priv->banner = NULL; - } + vpn_cleanup (connection); break; default: break; @@ -987,7 +1034,13 @@ dispose (GObject *object) cleanup_secrets_dbus_call (NM_VPN_CONNECTION (object)); + if (priv->gw_route) + rtnl_route_put (priv->gw_route); + if (priv->parent_dev) { + if (priv->device_ip4) + g_signal_handler_disconnect (priv->parent_dev, priv->device_ip4); + if (priv->device_monitor) g_signal_handler_disconnect (priv->parent_dev, priv->device_monitor);