[NetworkManager/f16] Fix some issues related to NM restarting and carrier detect

Daniel Williams dcbw at fedoraproject.org
Mon Apr 30 22:03:37 UTC 2012


commit 7b5003cf772939338d9a4783ee7df7944346bfb6
Author: Dan Williams <dcbw at redhat.com>
Date:   Mon Apr 30 17:03:18 2012 -0500

    Fix some issues related to NM restarting and carrier detect

 ...-carrier-is-always-on-for-devices-that-do.patch |   82 +++
 ...ibnm-glib-NULL-out-priv-fields-on-dispose.patch |  695 ++++++++++++++++++++
 ...discard-devices-and-active-connections-wh.patch |  118 ++++
 ...ensure-NMRemoteConnection-signals-are-dis.patch |  196 ++++++
 ...ensure-object-cache-is-cleared-when-NM-st.patch |   80 +++
 ...protect-against-potentially-NULL-changed-.patch |   34 +
 NetworkManager.spec                                |   18 +-
 7 files changed, 1221 insertions(+), 2 deletions(-)
---
diff --git a/0001-core-ensure-carrier-is-always-on-for-devices-that-do.patch b/0001-core-ensure-carrier-is-always-on-for-devices-that-do.patch
new file mode 100644
index 0000000..d559bbb
--- /dev/null
+++ b/0001-core-ensure-carrier-is-always-on-for-devices-that-do.patch
@@ -0,0 +1,82 @@
+From a091c7aa0f15ca2eb7a0c3d3e99405aa98855965 Mon Sep 17 00:00:00 2001
+From: Dan Williams <dcbw at redhat.com>
+Date: Sat, 28 Apr 2012 11:48:01 -0500
+Subject: [PATCH] core: ensure carrier is always on for devices that don't
+ support detection (rh #816719)
+
+We broke this when splitting NMDeviceWired out of NMDeviceEthernet.
+---
+ src/nm-device-wired.c |   24 ++++++++++++++++--------
+ 1 files changed, 16 insertions(+), 8 deletions(-)
+
+diff --git a/src/nm-device-wired.c b/src/nm-device-wired.c
+index a476faa..e9934fb 100644
+--- a/src/nm-device-wired.c
++++ b/src/nm-device-wired.c
+@@ -162,6 +162,7 @@ set_carrier (NMDeviceWired *self,
+ {
+ 	NMDeviceWiredPrivate *priv;
+ 	NMDeviceState state;
++	guint32 caps;
+ 
+ 	g_return_if_fail (NM_IS_DEVICE (self));
+ 
+@@ -172,6 +173,13 @@ set_carrier (NMDeviceWired *self,
+ 	/* Clear any previous deferred action */
+ 	carrier_action_defer_clear (self);
+ 
++	/* Warn if we try to set carrier down on a device that
++	 * doesn't support carrier detect.  These devices assume
++	 * the carrier is always up.
++	 */
++	caps = nm_device_get_capabilities (NM_DEVICE (self));
++	g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT);
++
+ 	priv->carrier = carrier;
+ 	g_object_notify (G_OBJECT (self), "carrier");
+ 
+@@ -200,10 +208,8 @@ carrier_on (NMNetlinkMonitor *monitor,
+ 
+ 	/* Make sure signal is for us */
+ 	if (idx == nm_device_get_ifindex (device)) {
+-		/* Ignore spurious netlink messages */
+ 		caps = nm_device_get_capabilities (device);
+-		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
+-			return;
++		g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT);
+ 
+ 		set_carrier (self, TRUE, FALSE);
+ 		set_speed (self, ethtool_get_speed (self));
+@@ -224,10 +230,8 @@ carrier_off (NMNetlinkMonitor *monitor,
+ 		NMDeviceState state;
+ 		gboolean defer = FALSE;
+ 
+-		/* Ignore spurious netlink messages */
+ 		caps = nm_device_get_capabilities (device);
+-		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
+-			return;
++		g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT);
+ 
+ 		/* Defer carrier-off event actions while connected by a few seconds
+ 		 * so that tripping over a cable, power-cycling a switch, or breaking
+@@ -350,11 +354,15 @@ static gboolean
+ real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
+ {
+ 	gboolean success, carrier;
++	guint32 caps;
+ 
+ 	success = nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
+ 	if (success) {
+-		carrier = get_carrier_sync (NM_DEVICE_WIRED (dev));
+-		set_carrier (NM_DEVICE_WIRED (dev), carrier, carrier ? FALSE : TRUE);
++		caps = nm_device_get_capabilities (dev);
++		if (caps & NM_DEVICE_CAP_CARRIER_DETECT) {
++			carrier = get_carrier_sync (NM_DEVICE_WIRED (dev));
++			set_carrier (NM_DEVICE_WIRED (dev), carrier, carrier ? FALSE : TRUE);
++		}
+ 	}
+ 	return success;
+ }
+-- 
+1.7.7.6
+
diff --git a/0001-libnm-glib-NULL-out-priv-fields-on-dispose.patch b/0001-libnm-glib-NULL-out-priv-fields-on-dispose.patch
new file mode 100644
index 0000000..b0a7986
--- /dev/null
+++ b/0001-libnm-glib-NULL-out-priv-fields-on-dispose.patch
@@ -0,0 +1,695 @@
+From be18dd06cd138be232ff68ec7af19cfcf2f969ed Mon Sep 17 00:00:00 2001
+From: Dan Winship <danw at gnome.org>
+Date: Mon, 23 Apr 2012 11:02:48 -0400
+Subject: [PATCH] libnm-glib: NULL out priv fields on dispose()
+
+In some situations, objects might get used after being disposed, so
+clear out their various priv fields so we don't try to access unreffed
+objects, freed strings, etc.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=674473
+---
+ include/nm-glib-compat.h          |   10 ++++++++++
+ libnm-glib/nm-access-point.c      |   10 +---------
+ libnm-glib/nm-active-connection.c |   12 +++---------
+ libnm-glib/nm-client.c            |   17 +++++++----------
+ libnm-glib/nm-device-bond.c       |    5 +----
+ libnm-glib/nm-device-bt.c         |   10 +---------
+ libnm-glib/nm-device-ethernet.c   |   11 +----------
+ libnm-glib/nm-device-infiniband.c |    5 +----
+ libnm-glib/nm-device-modem.c      |   11 +----------
+ libnm-glib/nm-device-olpc-mesh.c  |   10 ++--------
+ libnm-glib/nm-device-vlan.c       |    5 +----
+ libnm-glib/nm-device-wifi.c       |   10 +---------
+ libnm-glib/nm-device-wimax.c      |   17 ++++++++---------
+ libnm-glib/nm-device.c            |   28 +++++++---------------------
+ libnm-glib/nm-object.c            |   19 +++++++++----------
+ libnm-glib/nm-remote-connection.c |   11 +++++------
+ libnm-glib/nm-remote-settings.c   |   32 ++++++++++++++++++--------------
+ libnm-glib/nm-secret-agent.c      |   37 +++++++++++++++++--------------------
+ libnm-glib/nm-vpn-plugin.c        |   14 +++-----------
+ libnm-glib/nm-wimax-nsp.c         |   10 +---------
+ 20 files changed, 98 insertions(+), 186 deletions(-)
+
+diff --git a/include/nm-glib-compat.h b/include/nm-glib-compat.h
+index 30b83e0..e953f6e 100644
+--- a/include/nm-glib-compat.h
++++ b/include/nm-glib-compat.h
+@@ -42,6 +42,16 @@
+ 		g_simple_async_result_set_from_error (result, __error); \
+ 		g_error_free (__error); \
+ 	} G_STMT_END
++
++#define g_clear_object(object_ptr) \
++	G_STMT_START { \
++		GObject **__obj_p = object_ptr; \
++		if (*__obj_p) { \
++			g_object_unref (*__obj_p); \
++			*__obj_p = NULL; \
++		} \
++	} G_STMT_END
++
+ #endif
+ 
+ #endif  /* NM_GLIB_COMPAT_H */
+diff --git a/libnm-glib/nm-access-point.c b/libnm-glib/nm-access-point.c
+index a6218ed..9c11c04 100644
+--- a/libnm-glib/nm-access-point.c
++++ b/libnm-glib/nm-access-point.c
+@@ -41,7 +41,6 @@ G_DEFINE_TYPE (NMAccessPoint, nm_access_point, NM_TYPE_OBJECT)
+ #define NM_ACCESS_POINT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ACCESS_POINT, NMAccessPointPrivate))
+ 
+ typedef struct {
+-	gboolean disposed;
+ 	DBusGProxy *proxy;
+ 
+ 	NM80211ApFlags flags;
+@@ -431,14 +430,7 @@ dispose (GObject *object)
+ {
+ 	NMAccessPointPrivate *priv = NM_ACCESS_POINT_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_access_point_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+-	g_object_unref (priv->proxy);
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_access_point_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c
+index 81b1f01..f170121 100644
+--- a/libnm-glib/nm-active-connection.c
++++ b/libnm-glib/nm-active-connection.c
+@@ -49,7 +49,6 @@ G_DEFINE_TYPE_WITH_CODE (NMActiveConnection, nm_active_connection, NM_TYPE_OBJEC
+ #define NM_ACTIVE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate))
+ 
+ typedef struct {
+-	gboolean disposed;
+ 	DBusGProxy *proxy;
+ 
+ 	char *connection;
+@@ -357,18 +356,13 @@ dispose (GObject *object)
+ {
+ 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+ 	if (priv->devices) {
+ 		g_ptr_array_foreach (priv->devices, (GFunc) g_object_unref, NULL);
+ 		g_ptr_array_free (priv->devices, TRUE);
++		priv->devices = NULL;
+ 	}
+-	g_object_unref (priv->proxy);
++
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
+index 781ce4c..4a908e0 100644
+--- a/libnm-glib/nm-client.c
++++ b/libnm-glib/nm-client.c
+@@ -53,8 +53,6 @@ G_DEFINE_TYPE_WITH_CODE (NMClient, nm_client, NM_TYPE_OBJECT,
+ #define NM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CLIENT, NMClientPrivate))
+ 
+ typedef struct {
+-	gboolean disposed;
+-
+ 	DBusGProxy *client_proxy;
+ 	DBusGProxy *bus_proxy;
+ 	gboolean manager_running;
+@@ -1517,24 +1515,23 @@ dispose (GObject *object)
+ {
+ 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	if (priv->perm_call)
++	if (priv->perm_call) {
+ 		dbus_g_proxy_cancel_call (priv->client_proxy, priv->perm_call);
++		priv->perm_call = NULL;
++	}
+ 
+-	g_object_unref (priv->client_proxy);
+-	g_object_unref (priv->bus_proxy);
++	g_clear_object (&priv->client_proxy);
++	g_clear_object (&priv->bus_proxy);
+ 
+ 	free_object_array (&priv->devices);
+ 	dispose_and_free_object_array (&priv->active_connections);
+ 
+ 	g_slist_foreach (priv->pending_activations, (GFunc) activate_info_free, NULL);
+ 	g_slist_free (priv->pending_activations);
++	priv->pending_activations = NULL;
+ 
+ 	g_hash_table_destroy (priv->permissions);
++	priv->permissions = NULL;
+ 
+ 	G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-bond.c b/libnm-glib/nm-device-bond.c
+index 7d8bf57..07ec4e8 100644
+--- a/libnm-glib/nm-device-bond.c
++++ b/libnm-glib/nm-device-bond.c
+@@ -215,10 +215,7 @@ dispose (GObject *object)
+ {
+ 	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (object);
+ 
+-	if (priv->proxy) {
+-		g_object_unref (priv->proxy);
+-		priv->proxy = NULL;
+-	}
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_bond_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-bt.c b/libnm-glib/nm-device-bt.c
+index bd8ccd2..b175f37 100644
+--- a/libnm-glib/nm-device-bt.c
++++ b/libnm-glib/nm-device-bt.c
+@@ -42,8 +42,6 @@ typedef struct {
+ 	char *hw_address;
+ 	char *name;
+ 	guint32 bt_capabilities;
+-
+-	gboolean disposed;
+ } NMDeviceBtPrivate;
+ 
+ enum {
+@@ -273,13 +271,7 @@ dispose (GObject *object)
+ {
+ 	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_device_bt_parent_class)->dispose (object);
+-		return;
+-	}
+-	priv->disposed = TRUE;
+-
+-	g_object_unref (priv->proxy);
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_bt_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-ethernet.c b/libnm-glib/nm-device-ethernet.c
+index 2c35a97..bc61b1f 100644
+--- a/libnm-glib/nm-device-ethernet.c
++++ b/libnm-glib/nm-device-ethernet.c
+@@ -44,8 +44,6 @@ typedef struct {
+ 	char *perm_hw_address;
+ 	guint32 speed;
+ 	gboolean carrier;
+-
+-	gboolean disposed;
+ } NMDeviceEthernetPrivate;
+ 
+ enum {
+@@ -280,14 +278,7 @@ dispose (GObject *object)
+ {
+ 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_device_ethernet_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+-	g_object_unref (priv->proxy);
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_ethernet_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-infiniband.c b/libnm-glib/nm-device-infiniband.c
+index 4f28823..4dee29d 100644
+--- a/libnm-glib/nm-device-infiniband.c
++++ b/libnm-glib/nm-device-infiniband.c
+@@ -224,10 +224,7 @@ dispose (GObject *object)
+ {
+ 	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (object);
+ 
+-	if (priv->proxy) {
+-		g_object_unref (priv->proxy);
+-		priv->proxy = NULL;
+-	}
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_infiniband_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-modem.c b/libnm-glib/nm-device-modem.c
+index 09b6df1..40597bf 100644
+--- a/libnm-glib/nm-device-modem.c
++++ b/libnm-glib/nm-device-modem.c
+@@ -44,8 +44,6 @@ typedef struct {
+ 
+ 	NMDeviceModemCapabilities caps;
+ 	NMDeviceModemCapabilities current_caps;
+-
+-	gboolean disposed;
+ } NMDeviceModemPrivate;
+ 
+ enum {
+@@ -225,14 +223,7 @@ dispose (GObject *object)
+ {
+ 	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_device_modem_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+-	g_object_unref (priv->proxy);
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_modem_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-olpc-mesh.c b/libnm-glib/nm-device-olpc-mesh.c
+index 96e1c36..9d14aa0 100644
+--- a/libnm-glib/nm-device-olpc-mesh.c
++++ b/libnm-glib/nm-device-olpc-mesh.c
+@@ -227,14 +227,8 @@ dispose (GObject *object)
+ {
+ 	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (object);
+ 
+-	if (priv->companion) {
+-		g_object_unref (priv->companion);
+-		priv->companion = NULL;
+-	}
+-	if (priv->proxy) {
+-		g_object_unref (priv->proxy);
+-		priv->proxy = NULL;
+-	}
++	g_clear_object (&priv->companion);
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-vlan.c b/libnm-glib/nm-device-vlan.c
+index 7ebc8dd..6ff7292 100644
+--- a/libnm-glib/nm-device-vlan.c
++++ b/libnm-glib/nm-device-vlan.c
+@@ -238,10 +238,7 @@ dispose (GObject *object)
+ {
+ 	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object);
+ 
+-	if (priv->proxy) {
+-		g_object_unref (priv->proxy);
+-		priv->proxy = NULL;
+-	}
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
+index aba43f9..01f0468 100644
+--- a/libnm-glib/nm-device-wifi.c
++++ b/libnm-glib/nm-device-wifi.c
+@@ -43,7 +43,6 @@ G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
+ void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled);
+ 
+ typedef struct {
+-	gboolean disposed;
+ 	DBusGProxy *proxy;
+ 
+ 	char *hw_address;
+@@ -608,15 +607,8 @@ dispose (GObject *object)
+ {
+ 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+ 	clean_up_aps (NM_DEVICE_WIFI (object), FALSE);
+-	g_object_unref (priv->proxy);
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device-wimax.c b/libnm-glib/nm-device-wimax.c
+index e49b4f3..de99b7c 100644
+--- a/libnm-glib/nm-device-wimax.c
++++ b/libnm-glib/nm-device-wimax.c
+@@ -42,7 +42,6 @@ G_DEFINE_TYPE (NMDeviceWimax, nm_device_wimax, NM_TYPE_DEVICE)
+ void _nm_device_wimax_set_wireless_enabled (NMDeviceWimax *wimax, gboolean enabled);
+ 
+ typedef struct {
+-	gboolean disposed;
+ 	DBusGProxy *proxy;
+ 
+ 	char *hw_address;
+@@ -593,18 +592,18 @@ dispose (GObject *object)
+ {
+ 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_device_wimax_parent_class)->dispose (object);
+-		return;
++	if (priv->hw_address) {
++		g_free (priv->hw_address);
++		priv->hw_address = NULL;
+ 	}
+ 
+-	priv->disposed = TRUE;
+-
+-	g_free (priv->hw_address);
+-	g_free (priv->bsid);
++	if (priv->bsid) {
++		g_free (priv->bsid);
++		priv->bsid = NULL;
++	}
+ 
+ 	clean_up_nsps (NM_DEVICE_WIMAX (object), FALSE);
+-	g_object_unref (priv->proxy);
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_device_wimax_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
+index a8a6338..5346b9d 100644
+--- a/libnm-glib/nm-device.c
++++ b/libnm-glib/nm-device.c
+@@ -60,7 +60,6 @@ G_DEFINE_TYPE_WITH_CODE (NMDevice, nm_device, NM_TYPE_OBJECT,
+ #define NM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE, NMDevicePrivate))
+ 
+ typedef struct {
+-	gboolean disposed;
+ 	DBusGProxy *proxy;
+ 
+ 	char *iface;
+@@ -265,26 +264,13 @@ dispose (GObject *object)
+ {
+ 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+-	g_object_unref (priv->proxy);
+-	if (priv->ip4_config)
+-		g_object_unref (priv->ip4_config);
+-	if (priv->dhcp4_config)
+-		g_object_unref (priv->dhcp4_config);
+-	if (priv->ip6_config)
+-		g_object_unref (priv->ip6_config);
+-	if (priv->dhcp6_config)
+-		g_object_unref (priv->dhcp6_config);
+-	if (priv->client)
+-		g_object_unref (priv->client);
+-	if (priv->active_connection)
+-		g_object_unref (priv->active_connection);
++	g_clear_object (&priv->proxy);
++	g_clear_object (&priv->ip4_config);
++	g_clear_object (&priv->dhcp4_config);
++	g_clear_object (&priv->ip6_config);
++	g_clear_object (&priv->dhcp6_config);
++	g_clear_object (&priv->client);
++	g_clear_object (&priv->active_connection);
+ 
+ 	G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c
+index 43f5dec..e333f9f 100644
+--- a/libnm-glib/nm-object.c
++++ b/libnm-glib/nm-object.c
+@@ -78,7 +78,7 @@ typedef struct {
+ 
+ 	GSList *notify_props;
+ 	guint32 notify_id;
+-	gboolean inited, disposed;
++	gboolean inited;
+ 
+ 	GSList *reload_results;
+ 	guint reload_remaining;
+@@ -194,13 +194,6 @@ dispose (GObject *object)
+ {
+ 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_object_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+ 	if (priv->notify_id) {
+ 		g_source_remove (priv->notify_id);
+ 		priv->notify_id = 0;
+@@ -208,12 +201,18 @@ dispose (GObject *object)
+ 
+ 	g_slist_foreach (priv->notify_props, (GFunc) g_free, NULL);
+ 	g_slist_free (priv->notify_props);
++	priv->notify_props = NULL;
+ 
+ 	g_slist_foreach (priv->property_interfaces, (GFunc) g_free, NULL);
+ 	g_slist_free (priv->property_interfaces);
++	priv->property_interfaces = NULL;
++
++	g_clear_object (&priv->properties_proxy);
+ 
+-	g_object_unref (priv->properties_proxy);
+-	dbus_g_connection_unref (priv->connection);
++	if (priv->connection) {
++		dbus_g_connection_unref (priv->connection);
++		priv->connection = NULL;
++	}
+ 
+ 	G_OBJECT_CLASS (nm_object_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-remote-connection.c b/libnm-glib/nm-remote-connection.c
+index c5e3864..e8b99df 100644
+--- a/libnm-glib/nm-remote-connection.c
++++ b/libnm-glib/nm-remote-connection.c
+@@ -72,7 +72,6 @@ typedef struct {
+ 	GSList *calls;
+ 
+ 	gboolean visible;
+-	gboolean disposed;
+ } NMRemoteConnectionPrivate;
+ 
+ #define NM_REMOTE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_REMOTE_CONNECTION, NMRemoteConnectionPrivate))
+@@ -477,14 +476,14 @@ dispose (GObject *object)
+ 	NMRemoteConnection *self = NM_REMOTE_CONNECTION (object);
+ 	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (object);
+ 
+-	if (!priv->disposed) {
+-		priv->disposed = TRUE;
++	while (g_slist_length (priv->calls))
++		remote_call_complete (self, priv->calls->data);
+ 
+-		while (g_slist_length (priv->calls))
+-			remote_call_complete (self, priv->calls->data);
++	g_clear_object (&priv->proxy);
+ 
+-		g_object_unref (priv->proxy);
++	if (priv->bus) {
+ 		dbus_g_connection_unref (priv->bus);
++		priv->bus = NULL;
+ 	}
+ 
+ 	G_OBJECT_CLASS (nm_remote_connection_parent_class)->dispose (object);
+diff --git a/libnm-glib/nm-remote-settings.c b/libnm-glib/nm-remote-settings.c
+index 040d912..19d865c 100644
+--- a/libnm-glib/nm-remote-settings.c
++++ b/libnm-glib/nm-remote-settings.c
+@@ -61,8 +61,6 @@ typedef struct {
+ 	DBusGProxy *dbus_proxy;
+ 
+ 	guint fetch_id;
+-
+-	gboolean disposed;
+ } NMRemoteSettingsPrivate;
+ 
+ enum {
+@@ -1043,29 +1041,35 @@ dispose (GObject *object)
+ 	NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
+ 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
+ 
+-	if (priv->disposed)
+-		return;
+-
+-	priv->disposed = TRUE;
+-
+-	if (priv->fetch_id)
++	if (priv->fetch_id) {
+ 		g_source_remove (priv->fetch_id);
++		priv->fetch_id = 0;
++	}
+ 
+ 	while (g_slist_length (priv->add_list))
+ 		add_connection_info_dispose (self, (AddConnectionInfo *) priv->add_list->data);
+ 
+-	if (priv->connections)
++	if (priv->connections) {
+ 		g_hash_table_destroy (priv->connections);
++		priv->connections = NULL;
++	}
+ 
+-	if (priv->pending)
++	if (priv->pending) {
+ 		g_hash_table_destroy (priv->pending);
++		priv->pending = NULL;
++	}
+ 
+ 	g_free (priv->hostname);
++	priv->hostname = NULL;
+ 
+-	g_object_unref (priv->dbus_proxy);
+-	g_object_unref (priv->proxy);
+-	g_object_unref (priv->props_proxy);
+-	dbus_g_connection_unref (priv->bus);
++	g_clear_object (&priv->dbus_proxy);
++	g_clear_object (&priv->proxy);
++	g_clear_object (&priv->props_proxy);
++
++	if (priv->bus) {
++		dbus_g_connection_unref (priv->bus);
++		priv->bus = NULL;
++	}
+ 
+ 	G_OBJECT_CLASS (nm_remote_settings_parent_class)->dispose (object);
+ }
+diff --git a/libnm-glib/nm-secret-agent.c b/libnm-glib/nm-secret-agent.c
+index 19f55c0..02f7419 100644
+--- a/libnm-glib/nm-secret-agent.c
++++ b/libnm-glib/nm-secret-agent.c
+@@ -79,8 +79,6 @@ typedef struct {
+ 	gboolean auto_register;
+ 	gboolean suppress_auto;
+ 	gboolean auto_register_id;
+-
+-	gboolean disposed;
+ } NMSecretAgentPrivate;
+ 
+ enum {
+@@ -878,29 +876,28 @@ dispose (GObject *object)
+ 	NMSecretAgent *self = NM_SECRET_AGENT (object);
+ 	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
+ 
+-	if (!priv->disposed) {
+-		priv->disposed = TRUE;
+-
+-		if (priv->registered)
+-			nm_secret_agent_unregister (self);
+-
+-		if (priv->auto_register_id)
+-			g_source_remove (priv->auto_register_id);
++	if (priv->registered)
++		nm_secret_agent_unregister (self);
+ 
+-		g_free (priv->identifier);
+-		g_free (priv->nm_owner);
++	if (priv->auto_register_id) {
++		g_source_remove (priv->auto_register_id);
++		priv->auto_register_id = 0;
++	}
+ 
+-		while (priv->pending_gets)
+-			get_secrets_info_finalize (self, priv->pending_gets->data);
++	g_free (priv->identifier);
++	priv->identifier = NULL;
++	g_free (priv->nm_owner);
++	priv->nm_owner = NULL;
+ 
+-		if (priv->dbus_proxy)
+-			g_object_unref (priv->dbus_proxy);
++	while (priv->pending_gets)
++		get_secrets_info_finalize (self, priv->pending_gets->data);
+ 
+-		if (priv->manager_proxy)
+-			g_object_unref (priv->manager_proxy);
++	g_clear_object (&priv->dbus_proxy);
++	g_clear_object (&priv->manager_proxy);
+ 
+-		if (priv->bus)
+-			dbus_g_connection_unref (priv->bus);
++	if (priv->bus) {
++		dbus_g_connection_unref (priv->bus);
++		priv->bus = NULL;
+ 	}
+ 
+ 	G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object);
+diff --git a/libnm-glib/nm-vpn-plugin.c b/libnm-glib/nm-vpn-plugin.c
+index 2368538..2de3e9f 100644
+--- a/libnm-glib/nm-vpn-plugin.c
++++ b/libnm-glib/nm-vpn-plugin.c
+@@ -63,9 +63,6 @@ typedef struct {
+ 	DBusGConnection *connection;
+ 	char *dbus_service_name;
+ 
+-	/* GObject-y stuff */
+-	gboolean disposed;
+-
+ 	/* Temporary stuff */
+ 	guint connect_timer;
+ 	guint quit_timer;
+@@ -590,15 +587,10 @@ dispose (GObject *object)
+ 	NMVPNServiceState state;
+ 	GError *err = NULL;
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_vpn_plugin_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+-	if (priv->fail_stop_id)
++	if (priv->fail_stop_id) {
+ 		g_source_remove (priv->fail_stop_id);
++		priv->fail_stop_id = 0;
++	}
+ 
+ 	state = nm_vpn_plugin_get_state (plugin);
+ 
+diff --git a/libnm-glib/nm-wimax-nsp.c b/libnm-glib/nm-wimax-nsp.c
+index 39553ce..980f7ce 100644
+--- a/libnm-glib/nm-wimax-nsp.c
++++ b/libnm-glib/nm-wimax-nsp.c
+@@ -37,7 +37,6 @@ G_DEFINE_TYPE (NMWimaxNsp, nm_wimax_nsp, NM_TYPE_OBJECT)
+ #define NM_WIMAX_NSP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_WIMAX_NSP, NMWimaxNspPrivate))
+ 
+ typedef struct {
+-	gboolean disposed;
+ 	DBusGProxy *proxy;
+ 
+ 	char *name;
+@@ -217,14 +216,7 @@ dispose (GObject *object)
+ {
+ 	NMWimaxNspPrivate *priv = NM_WIMAX_NSP_GET_PRIVATE (object);
+ 
+-	if (priv->disposed) {
+-		G_OBJECT_CLASS (nm_wimax_nsp_parent_class)->dispose (object);
+-		return;
+-	}
+-
+-	priv->disposed = TRUE;
+-
+-	g_object_unref (priv->proxy);
++	g_clear_object (&priv->proxy);
+ 
+ 	G_OBJECT_CLASS (nm_wimax_nsp_parent_class)->dispose (object);
+ }
+-- 
+1.7.7.6
+
diff --git a/0001-libnm-glib-discard-devices-and-active-connections-wh.patch b/0001-libnm-glib-discard-devices-and-active-connections-wh.patch
new file mode 100644
index 0000000..42ac6a8
--- /dev/null
+++ b/0001-libnm-glib-discard-devices-and-active-connections-wh.patch
@@ -0,0 +1,118 @@
+From 17d5973ef64b9f0c35bd13581eb244cf137f5794 Mon Sep 17 00:00:00 2001
+From: Dan Winship <danw at gnome.org>
+Date: Mon, 23 Apr 2012 12:20:14 -0400
+Subject: [PATCH] libnm-glib: discard devices and active connections when NM
+ goes down
+
+When NMClient changes state to "not running", don't just unref all the
+devices and connections: emit notify::active-connections and
+device-removed signals too, so the app will drop its copies of them.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=674473
+---
+ libnm-glib/nm-client.c |   59 ++++++++++++++++++++++++++++++++---------------
+ 1 files changed, 40 insertions(+), 19 deletions(-)
+
+diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
+index 4a908e0..bed1b4e 100644
+--- a/libnm-glib/nm-client.c
++++ b/libnm-glib/nm-client.c
+@@ -1016,30 +1016,50 @@ nm_client_get_permission_result (NMClient *client, NMClientPermission permission
+ /****************************************************************/
+ 
+ static void
+-free_object_array (GPtrArray **array)
++free_devices (NMClient *client, gboolean emit_signals)
+ {
+-	g_return_if_fail (array != NULL);
++	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
++	GPtrArray *devices;
++	NMDevice *device;
++	int i;
+ 
+-	if (*array) {
+-		g_ptr_array_foreach (*array, (GFunc) g_object_unref, NULL);
+-		g_ptr_array_free (*array, TRUE);
+-		*array = NULL;
++	if (!priv->devices)
++		return;
++
++	devices = priv->devices;
++	priv->devices = NULL;
++	for (i = 0; i < devices->len; i++) {
++		device = devices->pdata[i];
++		if (emit_signals)
++			g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
++		g_object_unref (device);
+ 	}
++	g_ptr_array_free (devices, TRUE);
+ }
+ 
+ static void
+-dispose_and_free_object_array (GPtrArray **array)
++free_active_connections (NMClient *client, gboolean emit_signals)
+ {
+-	g_return_if_fail (array != NULL);
++	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
++	GPtrArray *active_connections;
++	NMActiveConnection *active_connection;
++	int i;
+ 
+-	if (*array) {
+-		/* The objects in the array may have circular refs with other
+-		 * objects, which the caller will need to know to break by
+-		 * calling this function rather than free_object_array().
+-		 */
+-		g_ptr_array_foreach (*array, (GFunc) g_object_run_dispose, NULL);
+-		free_object_array (array);
++	if (!priv->active_connections)
++		return;
++
++	active_connections = priv->active_connections;
++	priv->active_connections = NULL;
++	for (i = 0; i < active_connections->len; i++) {
++		active_connection = active_connections->pdata[i];
++		/* Break circular refs */
++		g_object_run_dispose (G_OBJECT (active_connection));
++		g_object_unref (active_connection);
+ 	}
++	g_ptr_array_free (active_connections, TRUE);
++
++	if (emit_signals)
++		g_object_notify (G_OBJECT (client), NM_CLIENT_ACTIVE_CONNECTIONS);
+ }
+ 
+ static void
+@@ -1086,8 +1106,8 @@ proxy_name_owner_changed (DBusGProxy *proxy,
+ 		_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
+ 		_nm_object_suppress_property_updates (NM_OBJECT (client), TRUE);
+ 		poke_wireless_devices_with_rf_status (client);
+-		free_object_array (&priv->devices);
+-		dispose_and_free_object_array (&priv->active_connections);
++		free_devices (client, TRUE);
++		free_active_connections (client, TRUE);
+ 		priv->wireless_enabled = FALSE;
+ 		priv->wireless_hw_enabled = FALSE;
+ 		priv->wwan_enabled = FALSE;
+@@ -1513,6 +1533,7 @@ init_async (GAsyncInitable *initable, int io_priority,
+ static void
+ dispose (GObject *object)
+ {
++	NMClient *client = NM_CLIENT (object);
+ 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+ 
+ 	if (priv->perm_call) {
+@@ -1523,8 +1544,8 @@ dispose (GObject *object)
+ 	g_clear_object (&priv->client_proxy);
+ 	g_clear_object (&priv->bus_proxy);
+ 
+-	free_object_array (&priv->devices);
+-	dispose_and_free_object_array (&priv->active_connections);
++	free_devices (client, FALSE);
++	free_active_connections (client, FALSE);
+ 
+ 	g_slist_foreach (priv->pending_activations, (GFunc) activate_info_free, NULL);
+ 	g_slist_free (priv->pending_activations);
+-- 
+1.7.7.6
+
diff --git a/0001-libnm-glib-ensure-NMRemoteConnection-signals-are-dis.patch b/0001-libnm-glib-ensure-NMRemoteConnection-signals-are-dis.patch
new file mode 100644
index 0000000..f6113cd
--- /dev/null
+++ b/0001-libnm-glib-ensure-NMRemoteConnection-signals-are-dis.patch
@@ -0,0 +1,196 @@
+From 494f0a2e2047ca42adc73ecd6080068ce1fc9687 Mon Sep 17 00:00:00 2001
+From: Dan Williams <dcbw at redhat.com>
+Date: Mon, 23 Apr 2012 13:40:43 -0500
+Subject: [PATCH] libnm-glib: ensure NMRemoteConnection signals are
+ disconnected (bgo #674484) (lp:949743)
+
+If a client keeps the connection around after NMRemoteSettings is done
+with it (and has emitted 'removed' for that connection) then the
+RemoteSettings object was still registered to receive signals for
+that connection.  To prevent clients from being able to screw up
+the RemoteSettings, disconnect any signals it may be listening for
+when the connection is removed.  (it should be doing that anyway)
+---
+ libnm-glib/nm-remote-settings.c |  102 ++++++++++++++++++++++++++-------------
+ 1 files changed, 69 insertions(+), 33 deletions(-)
+
+diff --git a/libnm-glib/nm-remote-settings.c b/libnm-glib/nm-remote-settings.c
+index 68aaeb4..040d912 100644
+--- a/libnm-glib/nm-remote-settings.c
++++ b/libnm-glib/nm-remote-settings.c
+@@ -258,6 +258,43 @@ connection_removed_cb (NMRemoteConnection *remote, gpointer user_data)
+ 	g_hash_table_remove (priv->pending, path);
+ }
+ 
++static void connection_visible_cb (NMRemoteConnection *remote,
++                                   gboolean visible,
++                                   gpointer user_data);
++
++/* Takes a reference to the connection when adding to 'to' */
++static void
++move_connection (NMRemoteSettings *self,
++                 NMRemoteConnection *remote,
++                 GHashTable *from,
++                 GHashTable *to)
++{
++	const char *path = nm_connection_get_path (NM_CONNECTION (remote));
++
++	g_hash_table_insert (to, g_strdup (path), g_object_ref (remote));
++	if (from)
++		g_hash_table_remove (from, path);
++
++	/* Setup connection signals since removing from 'from' clears them, but
++	 * also the first time the connection is added to a hash if 'from' is NULL.
++	 */
++	if (!g_signal_handler_find (remote, G_SIGNAL_MATCH_FUNC,
++	                            0, 0, NULL, connection_removed_cb, NULL)) {
++		g_signal_connect (remote,
++		                  NM_REMOTE_CONNECTION_REMOVED,
++		                  G_CALLBACK (connection_removed_cb),
++		                  self);
++	}
++
++	if (!g_signal_handler_find (remote, G_SIGNAL_MATCH_FUNC,
++	                            0, 0, NULL, connection_visible_cb, NULL)) {
++		g_signal_connect (remote,
++		                  "visible",
++		                  G_CALLBACK (connection_visible_cb),
++		                  self);
++	}
++}
++
+ static void
+ connection_visible_cb (NMRemoteConnection *remote,
+                        gboolean visible,
+@@ -278,16 +315,14 @@ connection_visible_cb (NMRemoteConnection *remote,
+ 		/* Connection visible to this user again */
+ 		if (g_hash_table_lookup (priv->pending, path)) {
+ 			/* Move connection from pending to visible hash; emit for clients */
+-			g_hash_table_insert (priv->connections, g_strdup (path), g_object_ref (remote));
+-			g_hash_table_remove (priv->pending, path);
++			move_connection (self, remote, priv->pending, priv->connections);
+ 			g_signal_emit (self, signals[NEW_CONNECTION], 0, remote);
+ 		}
+ 	} else {
+ 		/* Connection now invisible to this user */
+ 		if (g_hash_table_lookup (priv->connections, path)) {
+ 			/* Move connection to pending hash and wait for it to become visible again */
+-			g_hash_table_insert (priv->pending, g_strdup (path), g_object_ref (remote));
+-			g_hash_table_remove (priv->connections, path);
++			move_connection (self, remote, priv->connections, priv->pending);
+ 
+ 			/* Signal to clients that the connection is gone; but we have to
+ 			 * block our connection removed handler so we don't destroy
+@@ -308,17 +343,14 @@ connection_inited (GObject *source, GAsyncResult *result, gpointer user_data)
+ 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
+ 	AddConnectionInfo *addinfo;
+ 	const char *path;
+-	GError *error = NULL;
+-	gboolean remove_from_pending = TRUE;
++	GError *error = NULL, *local;
+ 
+ 	path = nm_connection_get_path (NM_CONNECTION (remote));
+ 	addinfo = add_connection_info_find (self, remote);
+ 
+ 	if (g_async_initable_init_finish (G_ASYNC_INITABLE (remote), result, &error)) {
+-		/* ref it when adding to ->connections, since removing it from ->pending
+-		 * will unref it.
+-		 */
+-		g_hash_table_insert (priv->connections, g_strdup (path), g_object_ref (remote));
++		/* Connection is initialized and visible; expose it to clients */
++		move_connection (self, remote, priv->pending, priv->connections);
+ 
+ 		/* If there's a pending AddConnection request, complete that here before
+ 		 * signaling new-connection.
+@@ -331,23 +363,23 @@ connection_inited (GObject *source, GAsyncResult *result, gpointer user_data)
+ 		 */
+ 		g_signal_emit (self, signals[NEW_CONNECTION], 0, remote);
+ 	} else {
+-		if (dbus_g_error_has_name (error, "org.freedesktop.NetworkManager.Settings.PermissionDenied")) {
+-			/* Connection doesn't exist, or isn't visible to this user */
+-			remove_from_pending = FALSE;
+-		}
+-		g_error_free (error);
+-
+ 		if (addinfo) {
+-			error = g_error_new_literal (NM_REMOTE_SETTINGS_ERROR,
++			local = g_error_new_literal (NM_REMOTE_SETTINGS_ERROR,
+ 			                             NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE,
+ 			                             "Connection not visible or not available");
+-			add_connection_info_complete (self, addinfo, error);
+-			g_error_free (error);
++			add_connection_info_complete (self, addinfo, local);
++			g_error_free (local);
+ 		}
+-	}
+ 
+-	if (remove_from_pending)
+-		g_hash_table_remove (priv->pending, path);
++		/* PermissionDenied means the connection isn't visible to this user, so
++		 * keep it in priv->pending to be notified later of visibility changes.
++		 * Otherwise forget it.
++		 */
++		if (!dbus_g_error_has_name (error, "org.freedesktop.NetworkManager.Settings.PermissionDenied"))
++			g_hash_table_remove (priv->pending, path);
++
++		g_error_free (error);
++	}
+ 
+ 	/* Let listeners know that all connections have been found */
+ 	priv->init_left--;
+@@ -373,14 +405,6 @@ new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data)
+ 	/* Create a new connection object for it */
+ 	connection = nm_remote_connection_new (priv->bus, path);
+ 	if (connection) {
+-		g_signal_connect (connection, NM_REMOTE_CONNECTION_REMOVED,
+-		                  G_CALLBACK (connection_removed_cb),
+-		                  self);
+-
+-		g_signal_connect (connection, "visible",
+-		                  G_CALLBACK (connection_visible_cb),
+-		                  self);
+-
+ 		g_async_initable_init_async (G_ASYNC_INITABLE (connection),
+ 		                             G_PRIORITY_DEFAULT, NULL,
+ 		                             connection_inited, self);
+@@ -389,7 +413,8 @@ new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data)
+ 		 * it's settings asynchronously over D-Bus.  The connection isn't
+ 		 * really valid until it has all its settings, so hide it until it does.
+ 		 */
+-		g_hash_table_insert (priv->pending, g_strdup (path), connection);
++		move_connection (self, connection, NULL, priv->pending);
++		g_object_unref (connection); /* move_connection() takes a ref */
+ 	}
+ 	return connection;
+ }
+@@ -796,14 +821,25 @@ nm_remote_settings_new_finish (GAsyncResult *result, GError **error)
+ 		return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+ }
+ 
++static void
++forget_connection (gpointer user_data)
++{
++	NMRemoteConnection *remote = NM_REMOTE_CONNECTION (user_data);
++
++	g_signal_handlers_disconnect_matched (remote, G_SIGNAL_MATCH_FUNC,
++	                                      0, 0, NULL, connection_removed_cb, NULL);
++	g_signal_handlers_disconnect_matched (remote, G_SIGNAL_MATCH_FUNC,
++	                                      0, 0, NULL, connection_visible_cb, NULL);
++	g_object_unref (remote);
++}
+ 
+ static void
+ nm_remote_settings_init (NMRemoteSettings *self)
+ {
+ 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
+ 
+-	priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+-	priv->pending = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
++	priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, forget_connection);
++	priv->pending = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, forget_connection);
+ }
+ 
+ static void
+-- 
+1.7.7.6
+
diff --git a/0001-libnm-glib-ensure-object-cache-is-cleared-when-NM-st.patch b/0001-libnm-glib-ensure-object-cache-is-cleared-when-NM-st.patch
new file mode 100644
index 0000000..3af248a
--- /dev/null
+++ b/0001-libnm-glib-ensure-object-cache-is-cleared-when-NM-st.patch
@@ -0,0 +1,80 @@
+From 48981a6166208152890b6c57af19cc3c5db5837f Mon Sep 17 00:00:00 2001
+From: Dan Williams <dcbw at redhat.com>
+Date: Mon, 23 Apr 2012 17:07:18 -0500
+Subject: [PATCH] libnm-glib: ensure object cache is cleared when NM stops
+ (bgo #674473)
+
+Otherwise if a client holds references to the objects (or in the
+JavaScript case, uses deferred garbage collection) they'll still
+be in the cache when NM restarts, and the old object may have the
+same path as some new object, which isn't good.
+---
+ libnm-glib/nm-client.c       |    5 +++++
+ libnm-glib/nm-object-cache.c |   25 +++++++++++++++++++++++++
+ libnm-glib/nm-object-cache.h |    1 +
+ 3 files changed, 31 insertions(+), 0 deletions(-)
+
+diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
+index bed1b4e..311b1d2 100644
+--- a/libnm-glib/nm-client.c
++++ b/libnm-glib/nm-client.c
+@@ -1116,6 +1116,11 @@ proxy_name_owner_changed (DBusGProxy *proxy,
+ 		priv->wimax_hw_enabled = FALSE;
+ 		g_free (priv->version);
+ 		priv->version = NULL;
++
++		/* Clear object cache to ensure bad refcounting by clients doesn't
++		 * keep objects in the cache.
++		 */
++		_nm_object_cache_clear (NM_OBJECT (client));
+ 	} else {
+ 		_nm_object_suppress_property_updates (NM_OBJECT (client), FALSE);
+ 		_nm_object_reload_properties_async (NM_OBJECT (client), updated_properties, client);
+diff --git a/libnm-glib/nm-object-cache.c b/libnm-glib/nm-object-cache.c
+index 741f129..2748b1d 100644
+--- a/libnm-glib/nm-object-cache.c
++++ b/libnm-glib/nm-object-cache.c
+@@ -64,3 +64,28 @@ _nm_object_cache_get (const char *path)
+ 	return object ? g_object_ref (object) : NULL;
+ }
+ 
++void
++_nm_object_cache_clear (NMObject *except)
++{
++	GHashTableIter iter;
++	NMObject *obj;
++	const char *path;
++	char *foo;
++
++	_init_cache ();
++	g_hash_table_iter_init (&iter, cache);
++	while (g_hash_table_iter_next (&iter, (gpointer) &path, (gpointer) &obj)) {
++		if (obj != except) {
++			/* Remove the callback so that if the object isn't yet released
++			 * by a client, when it does finally get unrefed, it won't trigger
++			 * the cache removal for a new object with the same path as the
++			 * one being released.
++			 */
++			foo = g_object_steal_data (G_OBJECT (obj), "nm-object-cache-tag");
++			g_free (foo);
++
++			g_hash_table_iter_remove (&iter);
++		}
++	}
++}
++
+diff --git a/libnm-glib/nm-object-cache.h b/libnm-glib/nm-object-cache.h
+index 8386591..8475213 100644
+--- a/libnm-glib/nm-object-cache.h
++++ b/libnm-glib/nm-object-cache.h
+@@ -32,6 +32,7 @@ G_BEGIN_DECLS
+ /* Returns referenced object from the cache */
+ NMObject *_nm_object_cache_get (const char *path);
+ void _nm_object_cache_add (NMObject *object);
++void _nm_object_cache_clear (NMObject *except);
+ 
+ G_END_DECLS
+ 
+-- 
+1.7.7.6
+
diff --git a/0001-libnm-glib-protect-against-potentially-NULL-changed-.patch b/0001-libnm-glib-protect-against-potentially-NULL-changed-.patch
new file mode 100644
index 0000000..18ee175
--- /dev/null
+++ b/0001-libnm-glib-protect-against-potentially-NULL-changed-.patch
@@ -0,0 +1,34 @@
+From 411cb363444177369e55e98d613ae35ae7bddd81 Mon Sep 17 00:00:00 2001
+From: Dan Williams <dcbw at redhat.com>
+Date: Mon, 23 Apr 2012 14:30:42 -0500
+Subject: [PATCH] libnm-glib: protect against potentially NULL changed
+ property values (rh #808784)
+
+No idea *why* they're NULL, unless perhaps that dbus-glib can't demarshal
+the variants for some reason, but until we know why at least log the
+problem so we know what properties the issue might affect.
+
+diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c
+index fc9d7f8..43f5dec 100644
+--- a/libnm-glib/nm-object.c
++++ b/libnm-glib/nm-object.c
+@@ -844,8 +844,14 @@ process_properties_changed (NMObject *self, GHashTable *properties, gboolean syn
+ 		return;
+ 
+ 	g_hash_table_iter_init (&iter, properties);
+-	while (g_hash_table_iter_next (&iter, &name, &value))
+-		handle_property_changed (self, name, value, synchronously);
++	while (g_hash_table_iter_next (&iter, &name, &value)) {
++		if (value)
++			handle_property_changed (self, name, value, synchronously);
++		else {
++			g_warning ("%s:%d %s(): object %s property '%s' value is unexpectedly NULL",
++			           __FILE__, __LINE__, __func__, G_OBJECT_TYPE_NAME (self), (const char *) name);
++		}
++	}
+ }
+ 
+ static void
+-- 
+1.7.7.6
+
diff --git a/NetworkManager.spec b/NetworkManager.spec
index f62ecc0..d57d977 100644
--- a/NetworkManager.spec
+++ b/NetworkManager.spec
@@ -15,7 +15,7 @@ Name: NetworkManager
 Summary: Network connection manager and user applications
 Epoch: 1
 Version: 0.9.4
-Release: 3%{snapshot}%{?dist}
+Release: 4%{snapshot}%{?dist}
 Group: System Environment/Base
 License: GPLv2+
 URL: http://www.gnome.org/projects/NetworkManager/
@@ -31,6 +31,12 @@ Patch5: nm-applet-wifi-dialog-ui-fixes.patch
 Patch6: nss-error.patch
 Patch7: applet-ignore-deprecated.patch
 Patch8: nm-ip6-default-route.patch
+Patch9: 0001-libnm-glib-ensure-NMRemoteConnection-signals-are-dis.patch
+Patch10: 0001-libnm-glib-protect-against-potentially-NULL-changed-.patch
+Patch11: 0001-libnm-glib-NULL-out-priv-fields-on-dispose.patch
+Patch12: 0001-libnm-glib-discard-devices-and-active-connections-wh.patch
+Patch13: 0001-libnm-glib-ensure-object-cache-is-cleared-when-NM-st.patch
+Patch14: 0001-core-ensure-carrier-is-always-on-for-devices-that-do.patch
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 Requires(post): chkconfig
@@ -200,6 +206,12 @@ tar -xjf %{SOURCE1}
 %patch6 -p1 -b .nss-error
 %patch7 -p1 -b .no-deprecated
 %patch8 -p1 -b .ip6-default-route
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
 
 %build
 
@@ -469,8 +481,10 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
 %{_libdir}/libnm-gtk.so
 
 %changelog
-* Tue Apr 24 2012 Dan Williams <dcbw at redhat.com> - 0.9.4-4.git20120403
+* Mon Apr 30 2012 Dan Williams <dcbw at redhat.com> - 0.9.4-4.git20120403
 - don't restart NM on upgrade or uninstall (rh #812967)
+- libnm-glib: fix some segfaults when NM restarts due to rh #812967 (rh #806649)
+- core: fix carrier handling on devices that don't support carrier detection (rh #816719)
 
 * Thu Apr 19 2012 Dan Winship <danw at redhat.com> - 0.9.4-3.git20120403
 - Fix IPv6 connectivity problems (rh #785772)


More information about the scm-commits mailing list