summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Zaborowski <andrew.zaborowski@intel.com>2018-09-25 10:52:16 +0200
committerThomas Haller <thaller@redhat.com>2018-09-26 13:47:03 +0200
commit2d2fffce645c6ac7bb0865ebb18918dcc806a7f4 (patch)
tree9f6e2431cbcf9b400961f3a11a042f949c6b1539 /src
parent18f62eb4a52ec949fbf9089a600d5f97ea88a549 (diff)
wifi/iwd: handle IWD Station interface disappearing
The net.connman.iwd.Station interface, unlike the Device interface, can go away and come back when the device changes modes or goes DOWN and UP. The GDbusProxy for the interface becomes invalid after the interface disappeared and reappeared. This would make the IWD backend stop working after rfkill was used or after suspend/resume (provided the suspend/resume events are detected, without them everything works and is really fast too). Redo the handling of the Powered property changes, corresponding to device UP state, to get a new GDBusProxy when the Station interface reappears. Simplify some checks knowing that priv->can_scan implies for example that the Station interface is present, and that priv->enabled implies the NM device state is >= DISCONNECTED. https://github.com/NetworkManager/NetworkManager/pull/211
Diffstat (limited to 'src')
-rw-r--r--src/devices/wifi/nm-device-iwd.c167
1 files changed, 88 insertions, 79 deletions
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index 3bdb1e3dc..1d1be742b 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -426,7 +426,7 @@ cleanup_association_attempt (NMDeviceIwd *self, gboolean disconnect)
set_current_ap (self, NULL, TRUE);
- if (disconnect && priv->dbus_obj)
+ if (disconnect && priv->dbus_station_proxy)
send_disconnect (self);
}
@@ -820,13 +820,8 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
{
NMDeviceIwd *self = NM_DEVICE_IWD (device);
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self);
- gs_unref_variant GVariant *value = NULL;
- if (!priv->enabled || !priv->dbus_obj)
- return FALSE;
-
- value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "Powered");
- return get_variant_boolean (value, "Powered");
+ return priv->enabled && priv->dbus_station_proxy;
}
static gboolean
@@ -963,8 +958,7 @@ dbus_request_scan_cb (NMDevice *device,
priv = NM_DEVICE_IWD_GET_PRIVATE (self);
- if ( !priv->enabled
- || !priv->dbus_obj
+ if ( !priv->can_scan
|| nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED
|| nm_device_is_activating (device)) {
g_dbus_method_invocation_return_error_literal (context,
@@ -1005,8 +999,7 @@ _nm_device_iwd_request_scan (NMDeviceIwd *self,
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self);
NMDevice *device = NM_DEVICE (self);
- if ( !priv->enabled
- || !priv->dbus_obj
+ if ( !priv->can_scan
|| nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED
|| nm_device_is_activating (device)) {
g_dbus_method_invocation_return_error_literal (invocation,
@@ -1568,7 +1561,7 @@ device_state_changed (NMDevice *device,
* transition to DISCONNECTED because the device is now
* ready to use.
*/
- if (priv->enabled && priv->dbus_obj) {
+ if (priv->enabled && priv->dbus_station_proxy) {
nm_device_queue_recheck_available (device,
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
@@ -1625,10 +1618,11 @@ set_enabled (NMDevice *device, gboolean enabled)
if (state != NM_DEVICE_STATE_UNAVAILABLE)
_LOGW (LOGD_CORE, "not in expected unavailable state!");
- if (priv->dbus_obj)
+ if (priv->dbus_station_proxy) {
nm_device_queue_recheck_available (device,
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ }
} else {
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
@@ -1841,9 +1835,72 @@ station_properties_changed (GDBusProxy *proxy, GVariant *changed_properties,
static void
powered_changed (NMDeviceIwd *self, gboolean new_powered)
{
+ NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self);
+
nm_device_queue_recheck_available (NM_DEVICE (self),
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+
+ if (new_powered) {
+ GDBusInterface *interface;
+ GVariant *value;
+
+ if (priv->dbus_station_proxy)
+ return;
+
+ interface = g_dbus_object_get_interface (priv->dbus_obj, NM_IWD_STATION_INTERFACE);
+ if (!interface) {
+ /* No Station interface on the device object. Check if the
+ * "State" property is present on the Device interface, that
+ * would mean we're dealing with an IWD version from before the
+ * Device/Station split (0.7 or earlier) and we can easily
+ * handle that by making priv->dbus_device_proxy and
+ * priv->dbus_station_proxy both point at the Device interface.
+ */
+ value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "State");
+ if (!value) {
+ _LOGE (LOGD_WIFI, "Interface %s not found on obj %s",
+ NM_IWD_STATION_INTERFACE,
+ g_dbus_object_get_object_path (priv->dbus_obj));
+ return;
+ }
+
+ g_variant_unref (value);
+ interface = g_object_ref (priv->dbus_device_proxy);
+ }
+
+ priv->dbus_station_proxy = G_DBUS_PROXY (interface);
+
+ value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "Scanning");
+ priv->scanning = get_variant_boolean (value, "Scanning");
+ g_variant_unref (value);
+
+ value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "State");
+ state_changed (self, get_variant_state (value));
+ g_variant_unref (value);
+
+ g_signal_connect (priv->dbus_station_proxy, "g-properties-changed",
+ G_CALLBACK (station_properties_changed), self);
+
+ /* Call Disconnect to make sure IWD's autoconnect is disabled.
+ * Autoconnect is the default state after device is brought UP.
+ */
+ if (priv->enabled)
+ send_disconnect (self);
+ } else {
+ if (!priv->dbus_station_proxy)
+ return;
+
+ g_signal_handlers_disconnect_by_func (priv->dbus_station_proxy,
+ station_properties_changed, self);
+ g_clear_object (&priv->dbus_station_proxy);
+
+ priv->can_scan = FALSE;
+ priv->scanning = FALSE;
+ priv->scan_requested = FALSE;
+ priv->can_connect = FALSE;
+ cleanup_association_attempt (self, FALSE);
+ }
}
static void
@@ -1872,37 +1929,35 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object)
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self);
GDBusInterface *interface;
GVariant *value;
+ gboolean powered;
if (!nm_g_object_ref_set ((GObject **) &priv->dbus_obj, (GObject *) object))
return;
+ if (priv->enabled && priv->dbus_station_proxy) {
+ nm_device_queue_recheck_available (NM_DEVICE (self),
+ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ }
+
if (priv->dbus_device_proxy) {
g_signal_handlers_disconnect_by_func (priv->dbus_device_proxy,
device_properties_changed, self);
g_clear_object (&priv->dbus_device_proxy);
- g_signal_handlers_disconnect_by_func (priv->dbus_station_proxy,
- station_properties_changed, self);
- g_clear_object (&priv->dbus_station_proxy);
- }
-
- if (priv->enabled)
- nm_device_queue_recheck_available (NM_DEVICE (self),
- NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
- NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
- if (!object) {
- priv->can_scan = FALSE;
+ powered_changed (self, FALSE);
+ }
- cleanup_association_attempt (self, FALSE);
+ if (!object)
return;
- }
interface = g_dbus_object_get_interface (object, NM_IWD_DEVICE_INTERFACE);
if (!interface) {
_LOGE (LOGD_WIFI, "Interface %s not found on obj %s",
NM_IWD_DEVICE_INTERFACE,
g_dbus_object_get_object_path (object));
- goto error;
+ g_clear_object (&priv->dbus_obj);
+ return;
}
priv->dbus_device_proxy = G_DBUS_PROXY (interface);
@@ -1910,60 +1965,14 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object)
g_signal_connect (priv->dbus_device_proxy, "g-properties-changed",
G_CALLBACK (device_properties_changed), self);
- interface = g_dbus_object_get_interface (object, NM_IWD_STATION_INTERFACE);
- if (!interface) {
- /* No Station interface on the device object. Check if the
- * "State" property is present on the Device interface, that
- * would mean we're dealing with an IWD version from before the
- * Device/Station split (0.7 or earlier) and we can easily
- * handle that by making priv->dbus_device_proxy and
- * priv->dbus_station_proxy both point at the Device interface.
- *
- * TODO: handle device in a mode initially other than station
- * -- also means the Station interface won't be there.
- */
- value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "State");
- g_variant_unref (value);
- if (!value) {
- _LOGE (LOGD_WIFI, "Interface %s not found on obj %s",
- NM_IWD_STATION_INTERFACE,
- g_dbus_object_get_object_path (object));
- goto error;
- }
-
- interface = g_object_ref (priv->dbus_device_proxy);
- }
-
- priv->dbus_station_proxy = G_DBUS_PROXY (interface);
-
- value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "Scanning");
- priv->scanning = get_variant_boolean (value, "Scanning");
- g_variant_unref (value);
- priv->scan_requested = FALSE;
-
- value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "State");
- state_changed (self, get_variant_state (value));
+ value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "Powered");
+ powered = get_variant_boolean (value, "Powered");
g_variant_unref (value);
- g_signal_connect (priv->dbus_station_proxy, "g-properties-changed",
- G_CALLBACK (station_properties_changed), self);
-
- set_powered (self, priv->enabled);
-
- /* Call Disconnect to make sure IWD's autoconnect is disabled.
- * Autoconnect is the default state after device is brought UP.
- */
- if (priv->enabled)
- send_disconnect (self);
-
- return;
-error:
- g_clear_object (&priv->dbus_obj);
- if (priv->dbus_device_proxy) {
- g_signal_handlers_disconnect_by_func (priv->dbus_device_proxy,
- device_properties_changed, self);
- g_clear_object (&priv->dbus_device_proxy);
- }
+ if (powered != priv->enabled)
+ set_powered (self, priv->enabled);
+ else if (powered)
+ powered_changed (self, TRUE);
}
gboolean