diff options
author | Andrew Zaborowski <andrew.zaborowski@intel.com> | 2020-11-05 00:51:48 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-11-12 15:38:02 +0100 |
commit | f09a47639066e6a19227a278905b176185f5f7f7 (patch) | |
tree | 7f72ff90b472bb48d26b3bc7fb4097c4e1c1c062 | |
parent | 6a9f33e6475c04dbed75b6d6f07883324e97afae (diff) | |
download | NetworkManager-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.c | 107 |
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); |