summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Zaborowski <andrew.zaborowski@intel.com>2020-11-05 00:51:48 +0100
committerThomas Haller <thaller@redhat.com>2020-11-12 15:38:02 +0100
commitf09a47639066e6a19227a278905b176185f5f7f7 (patch)
tree7f72ff90b472bb48d26b3bc7fb4097c4e1c1c062
parent6a9f33e6475c04dbed75b6d6f07883324e97afae (diff)
downloadNetworkManager-f09a47639066e6a19227a278905b176185f5f7f7.tar.gz
iwd: Roughly respect the NMDevice::autoconnect property
Watch the NMDevice::autoconnect property to disable IWD autoconnect if requested by user. We have no way to re-enable it when the device is idle though. Make sure to not disable IWD's autoconnect in .deactivate() if not necessary. There's not much we can do if we have to call Station.Disconnect() but we can avoid calling it if unnecessary -- a slight optimization regardless of the autoconnect block flags. Fortunately NM and IWD block autoconnect on a manual deactivation in the same way (in MANAGED mode) and unblock it on an activation in the same way too (in MANAGED mode). Also if wifi.iwd.autoconnect is in use, unset NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT under the same conditions as IWD normally would. This could be made optional but with wifi.iwd.autoconnect by default we should follow IWD's autoconnect logic.
-rw-r--r--src/devices/wifi/nm-device-iwd.c107
1 files changed, 78 insertions, 29 deletions
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index ae4f2c89cd..be3474d662 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -553,6 +553,32 @@ reset_mode(NMDeviceIwd * self,
user_data);
}
+static gboolean
+get_variant_boolean(GVariant *v, const char *property)
+{
+ if (!v || !g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN)) {
+ nm_log_warn(LOGD_DEVICE | LOGD_WIFI,
+ "Property %s not cached or not boolean type",
+ property);
+
+ return FALSE;
+ }
+
+ return g_variant_get_boolean(v);
+}
+
+static const char *
+get_variant_state(GVariant *v)
+{
+ if (!v || !g_variant_is_of_type(v, G_VARIANT_TYPE_STRING)) {
+ nm_log_warn(LOGD_DEVICE | LOGD_WIFI, "State property not cached or not a string");
+
+ return "unknown";
+ }
+
+ return g_variant_get_string(v, NULL);
+}
+
static void
deactivate(NMDevice *device)
{
@@ -562,6 +588,14 @@ deactivate(NMDevice *device)
if (!priv->dbus_obj)
return;
+ if (priv->dbus_station_proxy) {
+ gs_unref_variant GVariant *value =
+ g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State");
+
+ if (NM_IN_STRSET(get_variant_state(value), "disconnecting", "disconnected"))
+ return;
+ }
+
cleanup_association_attempt(self, TRUE);
priv->act_mode_switch = FALSE;
@@ -1016,32 +1050,6 @@ complete_connection(NMDevice * device,
}
static gboolean
-get_variant_boolean(GVariant *v, const char *property)
-{
- if (!v || !g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN)) {
- nm_log_warn(LOGD_DEVICE | LOGD_WIFI,
- "Property %s not cached or not boolean type",
- property);
-
- return FALSE;
- }
-
- return g_variant_get_boolean(v);
-}
-
-static const char *
-get_variant_state(GVariant *v)
-{
- if (!v || !g_variant_is_of_type(v, G_VARIANT_TYPE_STRING)) {
- nm_log_warn(LOGD_DEVICE | LOGD_WIFI, "State property not cached or not a string");
-
- return "unknown";
- }
-
- return g_variant_get_string(v, NULL);
-}
-
-static gboolean
is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
{
NMDeviceIwd * self = NM_DEVICE_IWD(device);
@@ -1554,7 +1562,10 @@ network_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data)
gs_free char * ssid = NULL;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED;
GVariant * value;
- gboolean disconnect = !priv->iwd_autoconnect;
+ gboolean disconnect;
+
+ disconnect = !priv->iwd_autoconnect
+ || nm_device_autoconnect_blocked_get(device, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL);
variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
if (!variant) {
@@ -2761,7 +2772,9 @@ state_changed(NMDeviceIwd *self, const char *new_state)
/* If necessary, call Disconnect on the IWD device object to make sure
* it disables its autoconnect.
*/
- if (!priv->iwd_autoconnect)
+ if (!priv->iwd_autoconnect
+ || nm_device_autoconnect_blocked_get(device, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)
+ || priv->wifi_secrets_id || priv->pending_agent_request)
send_disconnect(self);
/*
@@ -2945,6 +2958,16 @@ powered_changed(NMDeviceIwd *self, gboolean new_powered)
g_variant_unref(value);
update_aps(self);
+
+ /* When a device is brought UP in station mode, including after a mode
+ * switch, IWD re-enables autoconnect. This is unlike NM's autoconnect
+ * where a mode change doesn't interfere with the
+ * BLOCKED_MANUAL_DISCONNECT flag.
+ */
+ if (priv->iwd_autoconnect) {
+ nm_device_autoconnect_blocked_unset(NM_DEVICE(self),
+ NM_DEVICE_AUTOCONNECT_BLOCKED_INTERNAL);
+ }
} else {
set_can_scan(self, FALSE);
priv->scanning = FALSE;
@@ -3087,6 +3110,7 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation)
if (!invocation) {
gs_unref_variant GVariant *value =
g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State");
+ gboolean disconnect;
if (!priv->wifi_secrets_id && !priv->pending_agent_request)
return FALSE;
@@ -3109,7 +3133,8 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation)
if (!nm_streq(get_variant_state(value), "disconnected"))
return TRUE;
- cleanup_association_attempt(self, FALSE);
+ disconnect = nm_device_autoconnect_blocked_get(device, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL);
+ cleanup_association_attempt(self, disconnect);
nm_device_state_changed(device,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
@@ -3260,6 +3285,27 @@ nm_device_iwd_network_add_remove(NMDeviceIwd *self, GDBusProxy *network, bool ad
}
}
+static void
+autoconnect_changed(NMDevice *device, GParamSpec *pspec, NMDeviceIwd *self)
+{
+ NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+ gs_unref_variant GVariant *value = NULL;
+
+ /* Note IWD normally remains in "disconnected" during a secret request
+ * and we don't want to interrupt it by calling Station.Disconnect().
+ */
+ if (!priv->dbus_station_proxy || !priv->iwd_autoconnect
+ || !nm_device_autoconnect_blocked_get(device, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)
+ || priv->wifi_secrets_id || priv->pending_agent_request)
+ return;
+
+ value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State");
+ if (!nm_streq(get_variant_state(value), "disconnected"))
+ return;
+
+ send_disconnect(self);
+}
+
/*****************************************************************************/
static const char *
@@ -3286,6 +3332,8 @@ nm_device_iwd_init(NMDeviceIwd *self)
TRUE,
TRUE);
+ g_signal_connect(self, "notify::" NM_DEVICE_AUTOCONNECT, G_CALLBACK(autoconnect_changed), self);
+
/* Make sure the manager is running */
(void) nm_iwd_manager_get();
}
@@ -3315,6 +3363,7 @@ dispose(GObject *object)
nm_clear_g_cancellable(&priv->cancellable);
+ g_signal_handlers_disconnect_by_func(self, autoconnect_changed, self);
nm_device_iwd_set_dbus_object(self, NULL);
G_OBJECT_CLASS(nm_device_iwd_parent_class)->dispose(object);