core: fix unmanaging of devices when quitting
When NM quits, we don't want to unmanage a device that has an active connection and can take that connection over again when NM starts back up. This makes '/etc/init.d/NetworkManager restart' work seamlessly. All other devices get unmanaged so their connection (and any dependent VPN connections or wpa_supplicant processes) get terminated. This bug caused active VPN connections over wifi to be left running even when they didn't have IP connectivity. There were two bugs: 1) the NMDevice class implemented connection_match_config() for all device subclasses, but only Ethernet devices can assume connections at startup. Thus the quit-time check passed for active wifi devices too, and they weren't properly cleaned up 2) The logic for figuring out which devices to clean up after when quitting was somewhat flawed; we want to default to unmanaging devices and then skip that step for ones that meet specific criteria. Instead the code defaulted to leaving all devices active at shutdown.
This commit is contained in:
@@ -398,11 +398,13 @@ nm_device_interface_connection_match_config (NMDeviceInterface *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
nm_device_interface_can_assume_connection (NMDeviceInterface *device)
|
nm_device_interface_can_assume_connections (NMDeviceInterface *device)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
|
g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
|
||||||
|
|
||||||
return !!NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config;
|
if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->can_assume_connections)
|
||||||
|
return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->can_assume_connections (device);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -109,6 +109,8 @@ struct _NMDeviceInterface {
|
|||||||
|
|
||||||
NMConnection * (*connection_match_config) (NMDeviceInterface *device, const GSList *specs);
|
NMConnection * (*connection_match_config) (NMDeviceInterface *device, const GSList *specs);
|
||||||
|
|
||||||
|
gboolean (*can_assume_connections) (NMDeviceInterface *device);
|
||||||
|
|
||||||
void (*set_enabled) (NMDeviceInterface *device, gboolean enabled);
|
void (*set_enabled) (NMDeviceInterface *device, gboolean enabled);
|
||||||
|
|
||||||
gboolean (*get_enabled) (NMDeviceInterface *device);
|
gboolean (*get_enabled) (NMDeviceInterface *device);
|
||||||
@@ -145,7 +147,7 @@ gboolean nm_device_interface_spec_match_list (NMDeviceInterface *device,
|
|||||||
NMConnection * nm_device_interface_connection_match_config (NMDeviceInterface *device,
|
NMConnection * nm_device_interface_connection_match_config (NMDeviceInterface *device,
|
||||||
const GSList *connections);
|
const GSList *connections);
|
||||||
|
|
||||||
gboolean nm_device_interface_can_assume_connection (NMDeviceInterface *device);
|
gboolean nm_device_interface_can_assume_connections (NMDeviceInterface *device);
|
||||||
|
|
||||||
gboolean nm_device_interface_get_enabled (NMDeviceInterface *device);
|
gboolean nm_device_interface_get_enabled (NMDeviceInterface *device);
|
||||||
|
|
||||||
|
@@ -159,6 +159,7 @@ static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason
|
|||||||
static gboolean device_disconnect (NMDeviceInterface *device, GError **error);
|
static gboolean device_disconnect (NMDeviceInterface *device, GError **error);
|
||||||
static gboolean spec_match_list (NMDeviceInterface *device, const GSList *specs);
|
static gboolean spec_match_list (NMDeviceInterface *device, const GSList *specs);
|
||||||
static NMConnection *connection_match_config (NMDeviceInterface *device, const GSList *connections);
|
static NMConnection *connection_match_config (NMDeviceInterface *device, const GSList *connections);
|
||||||
|
static gboolean can_assume_connections (NMDeviceInterface *device);
|
||||||
|
|
||||||
static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family);
|
static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family);
|
||||||
|
|
||||||
@@ -196,6 +197,7 @@ device_interface_init (NMDeviceInterface *device_interface_class)
|
|||||||
device_interface_class->disconnect = device_disconnect;
|
device_interface_class->disconnect = device_disconnect;
|
||||||
device_interface_class->spec_match_list = spec_match_list;
|
device_interface_class->spec_match_list = spec_match_list;
|
||||||
device_interface_class->connection_match_config = connection_match_config;
|
device_interface_class->connection_match_config = connection_match_config;
|
||||||
|
device_interface_class->can_assume_connections = can_assume_connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3310,7 +3312,7 @@ dispose (GObject *object)
|
|||||||
/* Don't down can-assume-connection capable devices that are activated with
|
/* Don't down can-assume-connection capable devices that are activated with
|
||||||
* a connection that can be assumed.
|
* a connection that can be assumed.
|
||||||
*/
|
*/
|
||||||
if ( nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (self))
|
if ( nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (self))
|
||||||
&& (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) {
|
&& (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) {
|
||||||
NMConnection *connection;
|
NMConnection *connection;
|
||||||
NMSettingIP4Config *s_ip4;
|
NMSettingIP4Config *s_ip4;
|
||||||
@@ -3868,6 +3870,14 @@ connection_match_config (NMDeviceInterface *device, const GSList *connections)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
can_assume_connections (NMDeviceInterface *device)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (device != NULL, FALSE);
|
||||||
|
|
||||||
|
return !!NM_DEVICE_GET_CLASS (device)->connection_match_config;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout)
|
nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout)
|
||||||
{
|
{
|
||||||
|
@@ -139,8 +139,7 @@ static NMDevice *find_device_by_iface (NMManager *self, const gchar *iface);
|
|||||||
static GSList * remove_one_device (NMManager *manager,
|
static GSList * remove_one_device (NMManager *manager,
|
||||||
GSList *list,
|
GSList *list,
|
||||||
NMDevice *device,
|
NMDevice *device,
|
||||||
gboolean quitting,
|
gboolean quitting);
|
||||||
gboolean force_unmanage);
|
|
||||||
|
|
||||||
static NMDevice *nm_manager_get_device_by_udi (NMManager *manager, const char *udi);
|
static NMDevice *nm_manager_get_device_by_udi (NMManager *manager, const char *udi);
|
||||||
|
|
||||||
@@ -371,8 +370,7 @@ modem_added (NMModemManager *modem_manager,
|
|||||||
priv->devices = remove_one_device (NM_MANAGER (user_data),
|
priv->devices = remove_one_device (NM_MANAGER (user_data),
|
||||||
priv->devices,
|
priv->devices,
|
||||||
replace_device,
|
replace_device,
|
||||||
FALSE,
|
FALSE);
|
||||||
TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Give Bluetooth DUN devices first chance to claim the modem */
|
/* Give Bluetooth DUN devices first chance to claim the modem */
|
||||||
@@ -471,20 +469,22 @@ static GSList *
|
|||||||
remove_one_device (NMManager *manager,
|
remove_one_device (NMManager *manager,
|
||||||
GSList *list,
|
GSList *list,
|
||||||
NMDevice *device,
|
NMDevice *device,
|
||||||
gboolean quitting,
|
gboolean quitting)
|
||||||
gboolean force_unmanage)
|
|
||||||
{
|
{
|
||||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||||
|
|
||||||
if (nm_device_get_managed (device)) {
|
if (nm_device_get_managed (device)) {
|
||||||
gboolean unmanage = !quitting;
|
/* When quitting, we want to leave up interfaces & connections
|
||||||
|
* that can be taken over again (ie, "assumed") when NM restarts
|
||||||
|
* so that '/etc/init.d/NetworkManager restart' will not distrupt
|
||||||
|
* networking for interfaces that support connection assumption.
|
||||||
|
* All other devices get unmanaged when NM quits so that their
|
||||||
|
* connections get torn down and the interface is deactivated.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Don't unmanage active assume-connection-capable devices at shutdown */
|
if ( !nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (device))
|
||||||
if ( nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device))
|
|| (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED)
|
||||||
&& nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
|
|| !quitting)
|
||||||
unmanage = FALSE;
|
|
||||||
|
|
||||||
if (unmanage || force_unmanage)
|
|
||||||
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
|
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,7 +518,7 @@ modem_removed (NMModemManager *modem_manager,
|
|||||||
/* Otherwise remove the standalone modem */
|
/* Otherwise remove the standalone modem */
|
||||||
found = nm_manager_get_device_by_udi (self, nm_modem_get_path (modem));
|
found = nm_manager_get_device_by_udi (self, nm_modem_get_path (modem));
|
||||||
if (found)
|
if (found)
|
||||||
priv->devices = remove_one_device (self, priv->devices, found, FALSE, TRUE);
|
priv->devices = remove_one_device (self, priv->devices, found, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2069,7 +2069,7 @@ add_device (NMManager *self, NMDevice *device)
|
|||||||
/* Check if we should assume the device's active connection by matching its
|
/* Check if we should assume the device's active connection by matching its
|
||||||
* config with an existing system connection.
|
* config with an existing system connection.
|
||||||
*/
|
*/
|
||||||
if (nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device))) {
|
if (nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (device))) {
|
||||||
GSList *connections = NULL;
|
GSList *connections = NULL;
|
||||||
|
|
||||||
g_hash_table_iter_init (&iter, priv->system_connections);
|
g_hash_table_iter_init (&iter, priv->system_connections);
|
||||||
@@ -2229,7 +2229,7 @@ bluez_manager_resync_devices (NMManager *self)
|
|||||||
priv->devices = keep;
|
priv->devices = keep;
|
||||||
|
|
||||||
while (g_slist_length (gone))
|
while (g_slist_length (gone))
|
||||||
gone = remove_one_device (self, gone, NM_DEVICE (gone->data), FALSE, TRUE);
|
gone = remove_one_device (self, gone, NM_DEVICE (gone->data), FALSE);
|
||||||
} else {
|
} else {
|
||||||
g_slist_free (keep);
|
g_slist_free (keep);
|
||||||
g_slist_free (gone);
|
g_slist_free (gone);
|
||||||
@@ -2298,7 +2298,7 @@ bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
|
|||||||
NMDevice *device = NM_DEVICE (iter->data);
|
NMDevice *device = NM_DEVICE (iter->data);
|
||||||
|
|
||||||
if (!strcmp (nm_device_get_udi (device), object_path)) {
|
if (!strcmp (nm_device_get_udi (device), object_path)) {
|
||||||
priv->devices = remove_one_device (self, priv->devices, device, FALSE, TRUE);
|
priv->devices = remove_one_device (self, priv->devices, device, FALSE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2367,7 +2367,7 @@ udev_device_removed_cb (NMUdevManager *manager,
|
|||||||
ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
|
ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
|
||||||
device = find_device_by_ifindex (self, ifindex);
|
device = find_device_by_ifindex (self, ifindex);
|
||||||
if (device)
|
if (device)
|
||||||
priv->devices = remove_one_device (self, priv->devices, device, FALSE, TRUE);
|
priv->devices = remove_one_device (self, priv->devices, device, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -4065,8 +4065,7 @@ dispose (GObject *object)
|
|||||||
priv->devices = remove_one_device (manager,
|
priv->devices = remove_one_device (manager,
|
||||||
priv->devices,
|
priv->devices,
|
||||||
NM_DEVICE (priv->devices->data),
|
NM_DEVICE (priv->devices->data),
|
||||||
TRUE,
|
TRUE);
|
||||||
FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user_proxy_cleanup (manager, FALSE);
|
user_proxy_cleanup (manager, FALSE);
|
||||||
|
Reference in New Issue
Block a user