summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-10-19 18:53:49 +0200
committerThomas Haller <thaller@redhat.com>2020-10-19 18:54:04 +0200
commitba1e1c364caab1c7c9dae8b470d37c1803043fc7 (patch)
treea2dacd6946286b5604b9de707be38b5f1db470a7
parenta9ffb5b73ea3f5ccea8ea93f1f495d4810d16efc (diff)
parentc92ad05cee6ed8f1edb17d0cc4a6dd2c7d8a2f46 (diff)
downloadNetworkManager-ba1e1c364caab1c7c9dae8b470d37c1803043fc7.tar.gz
wifi/iwd: merge branch 'balrog-kun:iwd-hidden-networks-cleanup'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/646
-rw-r--r--src/devices/wifi/nm-device-iwd.c318
-rw-r--r--src/devices/wifi/nm-device-iwd.h2
-rw-r--r--src/devices/wifi/nm-iwd-manager.c117
3 files changed, 264 insertions, 173 deletions
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index 64ac3de7e6..15c1191701 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -60,7 +60,11 @@ typedef struct {
bool scanning : 1;
bool scan_requested : 1;
bool act_mode_switch : 1;
+ bool secrets_failed : 1;
+ bool networks_requested : 1;
+ bool networks_changed : 1;
gint64 last_scan;
+ uint32_t ap_id;
} NMDeviceIwdPrivate;
struct _NMDeviceIwd {
@@ -161,6 +165,7 @@ set_current_ap(NMDeviceIwd *self, NMWifiAP *new_ap, gboolean recheck_available_c
_notify(self, PROP_ACTIVE_ACCESS_POINT);
_notify(self, PROP_MODE);
+ schedule_periodic_scan(self, TRUE);
}
static void
@@ -198,49 +203,36 @@ ap_security_flags_from_network_type(const char *type)
return flags;
}
-static void
-insert_ap_from_network(NMDeviceIwd *self,
- GHashTable * aps,
- const char * path,
- gint64 last_seen_msec,
- int16_t signal,
- uint32_t ap_id)
-{
- gs_unref_object GDBusProxy *network_proxy = NULL;
- gs_unref_variant GVariant *name_value = NULL;
- gs_unref_variant GVariant *type_value = NULL;
- nm_auto_ref_string NMRefString *bss_path = NULL;
- const char * name;
- const char * type;
- NMSupplicantBssInfo bss_info;
- uint8_t bssid[6];
- NMWifiAP * ap;
+static NMWifiAP *
+ap_from_network(NMDeviceIwd *self,
+ GDBusProxy * network,
+ NMRefString *bss_path,
+ gint64 last_seen_msec,
+ int16_t signal)
+{
+ NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+ gs_unref_variant GVariant *name_value = NULL;
+ gs_unref_variant GVariant *type_value = NULL;
+ const char * name;
+ const char * type;
+ uint32_t ap_id;
+ uint8_t bssid[6];
gs_unref_bytes GBytes *ssid = NULL;
+ NMWifiAP * ap;
+ NMSupplicantBssInfo bss_info;
- bss_path = nm_ref_string_new(path);
-
- if (g_hash_table_lookup(aps, path)) {
- _LOGD(LOGD_WIFI, "Duplicate network at %s", path);
- return;
- }
-
- network_proxy =
- nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), path, NM_IWD_NETWORK_INTERFACE);
- if (!network_proxy)
- return;
-
- name_value = g_dbus_proxy_get_cached_property(network_proxy, "Name");
- type_value = g_dbus_proxy_get_cached_property(network_proxy, "Type");
+ name_value = g_dbus_proxy_get_cached_property(network, "Name");
+ type_value = g_dbus_proxy_get_cached_property(network, "Type");
if (!name_value || !g_variant_is_of_type(name_value, G_VARIANT_TYPE_STRING) || !type_value
|| !g_variant_is_of_type(type_value, G_VARIANT_TYPE_STRING))
- return;
+ return NULL;
name = g_variant_get_string(name_value, NULL);
type = g_variant_get_string(type_value, NULL);
if (nm_streq(type, "wep")) {
/* WEP not supported */
- return;
+ return NULL;
}
/* What we get from IWD are networks, or ESSs, that may contain
@@ -251,6 +243,7 @@ insert_ap_from_network(NMDeviceIwd *self,
* already does that. We fake the BSSIDs as they don't play any
* role either.
*/
+ ap_id = priv->ap_id++;
bssid[0] = 0x00;
bssid[1] = 0x01;
bssid[2] = 0x02;
@@ -277,6 +270,34 @@ insert_ap_from_network(NMDeviceIwd *self,
nm_assert(bss_path == nm_wifi_ap_get_supplicant_path(ap));
+ return ap;
+}
+
+static void
+insert_ap_from_network(NMDeviceIwd *self,
+ GHashTable * aps,
+ const char * path,
+ gint64 last_seen_msec,
+ int16_t signal)
+{
+ gs_unref_object GDBusProxy *network_proxy = NULL;
+ nm_auto_ref_string NMRefString *bss_path = nm_ref_string_new(path);
+ NMWifiAP * ap;
+
+ if (g_hash_table_lookup(aps, bss_path)) {
+ _LOGD(LOGD_WIFI, "Duplicate network at %s", path);
+ return;
+ }
+
+ network_proxy =
+ nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), path, NM_IWD_NETWORK_INTERFACE);
+ if (!network_proxy)
+ return;
+
+ ap = ap_from_network(self, network_proxy, bss_path, last_seen_msec, signal);
+ if (!ap)
+ return;
+
g_hash_table_insert(aps, bss_path, ap);
}
@@ -288,55 +309,45 @@ get_ordered_networks_cb(GObject *source, GAsyncResult *res, gpointer user_data)
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *variant = NULL;
GVariantIter * networks;
- const char * path, *name, *type;
+ const char * path;
int16_t signal;
NMWifiAP * ap, *ap_safe, *new_ap;
- gboolean changed = FALSE;
+ gboolean changed;
GHashTableIter ap_iter;
gs_unref_hashtable GHashTable *new_aps = NULL;
- gboolean compat;
- const char * return_sig;
- static uint32_t ap_id = 0;
gint64 last_seen_msec;
variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (!variant && nm_utils_error_is_cancelled(error))
+ return;
+
+ priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+ priv->networks_requested = FALSE;
+
if (!variant) {
_LOGE(LOGD_WIFI, "Station.GetOrderedNetworks failed: %s", error->message);
return;
}
- priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-
- /* Depending on whether we're using the Station interface or the Device
- * interface for compatibility with IWD <= 0.7, the return signature of
- * GetOrderedNetworks will be different.
- */
- compat = priv->dbus_station_proxy == priv->dbus_device_proxy;
- return_sig = compat ? "(a(osns))" : "(a(on))";
-
- if (!g_variant_is_of_type(variant, G_VARIANT_TYPE(return_sig))) {
+ if (!g_variant_is_of_type(variant, G_VARIANT_TYPE("(a(on))"))) {
_LOGE(LOGD_WIFI,
- "Station.GetOrderedNetworks returned type %s instead of %s",
- g_variant_get_type_string(variant),
- return_sig);
+ "Station.GetOrderedNetworks returned type %s instead of (a(on))",
+ g_variant_get_type_string(variant));
return;
}
new_aps = g_hash_table_new_full(nm_direct_hash, NULL, NULL, g_object_unref);
-
- g_variant_get(variant, return_sig, &networks);
+ g_variant_get(variant, "(a(on))", &networks);
last_seen_msec = nm_utils_get_monotonic_timestamp_msec();
- if (compat) {
- while (g_variant_iter_next(networks, "(&o&sn&s)", &path, &name, &signal, &type))
- insert_ap_from_network(self, new_aps, path, last_seen_msec, signal, ap_id++);
- } else {
- while (g_variant_iter_next(networks, "(&on)", &path, &signal))
- insert_ap_from_network(self, new_aps, path, last_seen_msec, signal, ap_id++);
- }
+ while (g_variant_iter_next(networks, "(&on)", &path, &signal))
+ insert_ap_from_network(self, new_aps, path, last_seen_msec, signal);
g_variant_iter_free(networks);
+ changed = priv->networks_changed;
+ priv->networks_changed = FALSE;
+
c_list_for_each_entry_safe (ap, ap_safe, &priv->aps_lst_head, aps_lst) {
new_ap = g_hash_table_lookup(new_aps, nm_wifi_ap_get_supplicant_path(ap));
if (new_ap) {
@@ -389,6 +400,7 @@ update_aps(NMDeviceIwd *self)
priv->cancellable,
get_ordered_networks_cb,
self);
+ priv->networks_requested = TRUE;
}
static void
@@ -597,7 +609,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
if (perm_hw_addr) {
if (mac && !nm_utils_hwaddr_matches(mac, -1, perm_hw_addr, -1)) {
nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"device MAC address does not match the profile");
return FALSE;
}
@@ -624,7 +636,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
security = nm_wifi_connection_get_iwd_security(connection, &mapped);
if (!mapped) {
nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"connection authentication type not supported by IWD backend");
return FALSE;
}
@@ -636,7 +648,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
&& !NM_IN_STRSET(mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) {
nm_utils_error_set_literal(
error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"non-infrastructure hidden networks not supported by the IWD backend");
return FALSE;
}
@@ -648,7 +660,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
if (security == NM_IWD_NETWORK_SECURITY_8021X) {
if (!is_connection_known_network(connection)) {
nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"802.1x connections must have IWD provisioning files");
return FALSE;
}
@@ -656,7 +668,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
NM_IWD_NETWORK_SECURITY_NONE,
NM_IWD_NETWORK_SECURITY_PSK)) {
nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"IWD backend only supports Open, PSK and 802.1x network "
"authentication in Infrastructure mode");
return FALSE;
@@ -664,21 +676,21 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
} else if (nm_streq(mode, NM_SETTING_WIRELESS_MODE_AP)) {
if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) {
nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"device does not support Access Point mode");
return FALSE;
}
if (!NM_IN_SET(security, NM_IWD_NETWORK_SECURITY_PSK)) {
nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"IWD backend only supports PSK authentication in AP mode");
return FALSE;
}
} else if (nm_streq(mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) {
nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"device does not support Ad-Hoc mode");
return FALSE;
}
@@ -686,14 +698,15 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
if (!NM_IN_SET(security, NM_IWD_NETWORK_SECURITY_NONE, NM_IWD_NETWORK_SECURITY_PSK)) {
nm_utils_error_set_literal(
error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"IWD backend only supports Open and PSK authentication in Ad-Hoc mode");
return FALSE;
}
} else {
- nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
- "%s type profiles not supported by IWD backend");
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
+ "'%s' type profiles not supported by IWD backend",
+ mode);
return FALSE;
}
@@ -740,7 +753,16 @@ check_connection_available(NMDevice * device,
if (NM_IN_STRSET(mode, NM_SETTING_WIRELESS_MODE_AP, NM_SETTING_WIRELESS_MODE_ADHOC))
return TRUE;
- if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP))
+ /* Hidden SSIDs obviously don't always appear in the scan list either.
+ *
+ * For an explicit user-activation-request, a connection is considered
+ * available because for hidden Wi-Fi, clients didn't consistently
+ * set the 'hidden' property to indicate hidden SSID networks. If
+ * activating but the network isn't available let the device recheck
+ * availability.
+ */
+ if (nm_setting_wireless_get_hidden(s_wifi)
+ || NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP))
return TRUE;
if (!ap)
@@ -824,6 +846,12 @@ complete_connection(NMDevice * device,
if (!nm_setting_verify(NM_SETTING(s_wifi), connection, error))
return FALSE;
+ /* We could either require the profile to be marked as hidden by the
+ * client or at least check that a hidden AP with a matching security
+ * type is in range using Station.GetHiddenAccessPoints(). For now
+ * assume it is hidden even though that will reveal the SSID on the
+ * air.
+ */
hidden = TRUE;
}
} else {
@@ -1273,6 +1301,7 @@ wifi_secrets_cb(NMActRequest * req,
priv->wifi_secrets_id = NULL;
if (nm_utils_error_is_cancelled(error)) {
+ priv->secrets_failed = TRUE;
g_dbus_method_invocation_return_error_literal(invocation,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_INVALID_CONNECTION,
@@ -1313,6 +1342,7 @@ wifi_secrets_cb(NMActRequest * req,
return;
secrets_error:
+ priv->secrets_failed = TRUE;
g_dbus_method_invocation_return_error_literal(invocation,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_INVALID_CONNECTION,
@@ -1391,7 +1421,7 @@ network_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data)
/* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */
reason = NM_DEVICE_STATE_REASON_NO_SECRETS;
- } else if (nm_streq0(dbus_error, "net.connman.iwd.Aborted")) {
+ } else if (nm_streq0(dbus_error, "net.connman.iwd.Aborted") && priv->secrets_failed) {
/* If agent call was cancelled we'd be getting a net.connman.iwd.Aborted */
reason = NM_DEVICE_STATE_REASON_NO_SECRETS;
}
@@ -1740,9 +1770,9 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
s_wireless = nm_connection_get_setting_wireless(connection);
g_return_val_if_fail(s_wireless, NM_ACT_STAGE_RETURN_FAILURE);
- /* AP mode never uses a specific object or existing scanned AP */
+ /* AP, Ad-Hoc modes never use a specific object or existing scanned AP */
mode = nm_setting_wireless_get_mode(s_wireless);
- if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP))
+ if (NM_IN_STRSET(mode, NM_SETTING_WIRELESS_MODE_AP, NM_SETTING_WIRELESS_MODE_ADHOC))
goto add_new;
ap_path = nm_active_connection_get_specific_object(NM_ACTIVE_CONNECTION(req));
@@ -1760,14 +1790,16 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
return NM_ACT_STAGE_RETURN_SUCCESS;
}
- if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_INFRA)) {
- /* Hidden networks not supported at this time */
+ /* In infrastructure mode the specific object should be set by now except
+ * for a first-time connection to a hidden network. If a hidden network is
+ * a Known Network it should still have been in the AP list.
+ */
+ if (!nm_setting_wireless_get_hidden(s_wireless) || is_connection_known_network(connection))
return NM_ACT_STAGE_RETURN_FAILURE;
- }
add_new:
/* If the user is trying to connect to an AP that NM doesn't yet know about
- * (hidden network or something) or starting a Hotspot, create an fake AP
+ * (hidden network or something) or starting a Hotspot, create a fake AP
* from the security settings in the connection. This "fake" AP gets used
* until the real one is found in the scan list (Ad-Hoc or Hidden), or until
* the device is deactivated (Ad-Hoc or Hotspot).
@@ -1828,10 +1860,19 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
goto out_fail;
}
- if (!is_connection_known_network(connection)
- && nm_setting_wireless_get_hidden(s_wireless)) {
+ priv->secrets_failed = FALSE;
+
+ if (nm_wifi_ap_get_fake(ap)) {
gs_free char *ssid_str = NULL;
+ if (!nm_setting_wireless_get_hidden(s_wireless)) {
+ _LOGW(LOGD_DEVICE | LOGD_WIFI,
+ "Activation: (wifi) target network not known to IWD but is not "
+ "marked hidden");
+ NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ goto out_fail;
+ }
+
/* Use Station.ConnectHiddenNetwork method instead of Network proxy. */
ssid_str = _nm_utils_ssid_to_utf8(nm_setting_wireless_get_ssid(s_wireless));
g_dbus_proxy_call(priv->dbus_station_proxy,
@@ -1845,14 +1886,6 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
return NM_ACT_STAGE_RETURN_POSTPONE;
}
- if (!nm_wifi_ap_get_supplicant_path(ap)) {
- _LOGW(LOGD_DEVICE | LOGD_WIFI,
- "Activation: (wifi) network is provisioned but dbus supplicant path for AP "
- "unknown");
- NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
- goto out_fail;
- }
-
network_proxy = nm_iwd_manager_get_dbus_interface(
nm_iwd_manager_get(),
nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)),
@@ -1951,16 +1984,8 @@ static void
schedule_periodic_scan(NMDeviceIwd *self, gboolean initial_scan)
{
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
- GVariant * value;
- gboolean disconnected = TRUE;
guint interval;
- if (priv->can_scan) {
- value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State");
- disconnected = nm_streq0(get_variant_state(value), "disconnected");
- g_variant_unref(value);
- }
-
/* Start scan immediately after a disconnect, mode change or
* device UP, otherwise wait 10 seconds. When connected, update
* AP list mainly on UI requests.
@@ -1972,7 +1997,7 @@ schedule_periodic_scan(NMDeviceIwd *self, gboolean initial_scan)
* exit autoconnect and interrupt the ongoing scan, meaning that
* we still want a new scan ASAP.
*/
- if (!priv->can_scan || !disconnected || priv->scan_requested || priv->scanning)
+ if (!priv->can_scan || priv->scan_requested || priv->scanning || priv->current_ap)
interval = -1;
else if (initial_scan)
interval = 0;
@@ -2281,7 +2306,6 @@ powered_changed(NMDeviceIwd *self, gboolean new_powered)
{
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
GDBusInterface * interface;
- GVariant * value;
nm_device_queue_recheck_available(NM_DEVICE(self),
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
@@ -2340,24 +2364,11 @@ powered_changed(NMDeviceIwd *self, gboolean new_powered)
if (new_powered && !priv->dbus_ap_proxy && !priv->dbus_adhoc_proxy) {
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) {
- g_variant_unref(value);
- interface = g_object_ref(G_DBUS_INTERFACE(priv->dbus_device_proxy));
- } else {
- _LOGE(LOGD_WIFI,
- "Interface %s not found on obj %s",
- NM_IWD_STATION_INTERFACE,
- g_dbus_object_get_object_path(priv->dbus_obj));
- interface = NULL;
- }
+ _LOGE(LOGD_WIFI,
+ "Interface %s not found on obj %s",
+ NM_IWD_STATION_INTERFACE,
+ g_dbus_object_get_object_path(priv->dbus_obj));
+ interface = NULL;
}
} else
interface = NULL;
@@ -2370,6 +2381,8 @@ powered_changed(NMDeviceIwd *self, gboolean new_powered)
}
if (interface) {
+ GVariant *value;
+
priv->dbus_station_proxy = G_DBUS_PROXY(interface);
g_signal_connect(priv->dbus_station_proxy,
"g-properties-changed",
@@ -2513,6 +2526,8 @@ error:
gboolean
nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation)
{
+ NMDevice * device = NM_DEVICE(self);
+ NMDeviceIwdPrivate * priv = NM_DEVICE_IWD_GET_PRIVATE(self);
NMActRequest * req;
const char * setting_name;
const char * setting_key;
@@ -2520,17 +2535,22 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation)
NMSecretAgentGetSecretsFlags get_secret_flags =
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION;
- req = nm_device_get_act_request(NM_DEVICE(self));
- if (!req)
+ req = nm_device_get_act_request(device);
+ if (!req || nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG) {
+ _LOGI(LOGD_WIFI, "IWD asked for secrets without explicit connect request");
+ send_disconnect(self);
return FALSE;
+ }
if (!try_reply_agent_request(self,
nm_act_request_get_applied_connection(req),
invocation,
&setting_name,
&setting_key,
- &replied))
+ &replied)) {
+ priv->secrets_failed = TRUE;
return FALSE;
+ }
if (replied)
return TRUE;
@@ -2546,14 +2566,64 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation)
if (nm_settings_connection_get_timestamp(nm_act_request_get_settings_connection(req), NULL))
get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW;
- nm_device_state_changed(NM_DEVICE(self),
- NM_DEVICE_STATE_NEED_AUTH,
- NM_DEVICE_STATE_REASON_NO_SECRETS);
+ nm_device_state_changed(device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NO_SECRETS);
wifi_secrets_get_one(self, setting_name, get_secret_flags, setting_key, invocation);
return TRUE;
}
+void
+nm_device_iwd_network_add_remove(NMDeviceIwd *self, GDBusProxy *network, bool add)
+{
+ NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+ NMWifiAP * ap = NULL;
+ NMWifiAP * tmp;
+ bool recheck;
+ nm_auto_ref_string NMRefString *bss_path = NULL;
+
+ bss_path = nm_ref_string_new(g_dbus_proxy_get_object_path(network));
+ c_list_for_each_entry (tmp, &priv->aps_lst_head, aps_lst)
+ if (nm_wifi_ap_get_supplicant_path(tmp) == bss_path) {
+ ap = tmp;
+ break;
+ }
+
+ /* We could schedule an update_aps(self) idle call here but up to IWD 1.9
+ * when a hidden network connection is attempted, that network is initially
+ * only added as a Network object but not shown in GetOrderedNetworks()
+ * return values, and for some corner case scenarios it's beneficial to
+ * have that Network reflected in our ap list so that we don't attempt
+ * calling ConnectHiddenNetwork() on it, as that will fail in 1.9. But we
+ * can skip recheck-available if we're currently scanning or in the middle
+ * of a GetOrderedNetworks() call as that will trigger the recheck too.
+ */
+ recheck = !priv->scanning && !priv->networks_requested;
+
+ if (!add) {
+ if (ap) {
+ ap_add_remove(self, FALSE, ap, recheck);
+ priv->networks_changed |= !recheck;
+ }
+
+ return;
+ }
+
+ if (!ap) {
+ ap = ap_from_network(self,
+ network,
+ bss_path,
+ nm_utils_get_monotonic_timestamp_msec(),
+ -10000);
+ if (!ap)
+ return;
+
+ ap_add_remove(self, TRUE, ap, recheck);
+ g_object_unref(ap);
+ priv->networks_changed |= !recheck;
+ return;
+ }
+}
+
/*****************************************************************************/
static const char *
diff --git a/src/devices/wifi/nm-device-iwd.h b/src/devices/wifi/nm-device-iwd.h
index e364beaf3d..d4bf5dd61d 100644
--- a/src/devices/wifi/nm-device-iwd.h
+++ b/src/devices/wifi/nm-device-iwd.h
@@ -44,4 +44,6 @@ void _nm_device_iwd_request_scan(NMDeviceIwd * self,
GVariant * options,
GDBusMethodInvocation *invocation);
+void nm_device_iwd_network_add_remove(NMDeviceIwd *device, GDBusProxy *network, bool add);
+
#endif /* __NETWORKMANAGER_DEVICE_IWD_H__ */
diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c
index 6a56201440..a19c8b2afd 100644
--- a/src/devices/wifi/nm-iwd-manager.c
+++ b/src/devices/wifi/nm-iwd-manager.c
@@ -117,6 +117,44 @@ get_property_string_or_null(GDBusProxy *proxy, const char *property)
return get_variant_string_or_null(value);
}
+static NMDeviceIwd *
+get_device_from_network(NMIwdManager *self, GDBusProxy *network)
+{
+ NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+ const char * ifname;
+ const char * device_path;
+ NMDevice * device;
+ gs_unref_object GDBusInterface *device_obj = NULL;
+
+ /* Try not to rely on the path of the Device being a prefix of the
+ * Network's object path.
+ */
+
+ device_path = get_property_string_or_null(network, "Device");
+ if (!device_path) {
+ _LOGD("Device not cached for network at %s", g_dbus_proxy_get_object_path(network));
+ return NULL;
+ }
+
+ device_obj = g_dbus_object_manager_get_interface(priv->object_manager,
+ device_path,
+ NM_IWD_DEVICE_INTERFACE);
+
+ ifname = get_property_string_or_null(G_DBUS_PROXY(device_obj), "Name");
+ if (!ifname) {
+ _LOGD("Name not cached for device at %s", device_path);
+ return NULL;
+ }
+
+ device = nm_manager_get_device(priv->manager, ifname, NM_DEVICE_TYPE_WIFI);
+ if (!device || !NM_IS_DEVICE_IWD(device)) {
+ _LOGD("NM device %s is not an IWD-managed device", ifname);
+ return NULL;
+ }
+
+ return NM_DEVICE_IWD(device);
+}
+
static void
agent_dbus_method_cb(GDBusConnection * connection,
const char * sender,
@@ -129,12 +167,10 @@ agent_dbus_method_cb(GDBusConnection * connection,
{
NMIwdManager * self = user_data;
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
- const char * network_path, *device_path, *ifname;
- gs_unref_object GDBusInterface *network = NULL, *device_obj = NULL;
- int ifindex;
- NMDevice * device;
- gs_free char * name_owner = NULL;
- int errsv;
+ const char * network_path;
+ NMDeviceIwd * device;
+ gs_free char * name_owner = NULL;
+ gs_unref_object GDBusInterface *network = NULL;
/* Be paranoid and check the sender address */
name_owner = g_dbus_object_manager_client_get_name_owner(
@@ -151,47 +187,21 @@ agent_dbus_method_cb(GDBusConnection * connection,
network_path,
NM_IWD_NETWORK_INTERFACE);
if (!network) {
- _LOGE("unable to find the network object");
- return;
- }
-
- device_path = get_property_string_or_null(G_DBUS_PROXY(network), "Device");
- if (!device_path) {
- _LOGD("agent-request: device not cached for network %s in IWD Agent request", network_path);
- goto return_error;
- }
-
- device_obj = g_dbus_object_manager_get_interface(priv->object_manager,
- device_path,
- NM_IWD_DEVICE_INTERFACE);
-
- ifname = get_property_string_or_null(G_DBUS_PROXY(device_obj), "Name");
- if (!ifname) {
- _LOGD("agent-request: name not cached for device %s in IWD Agent request", device_path);
+ _LOGE("agent-request: unable to find the network object");
goto return_error;
}
- ifindex = if_nametoindex(ifname);
- if (!ifindex) {
- errsv = errno;
- _LOGD("agent-request: if_nametoindex failed for Name %s for Device at %s: %i",
- ifname,
- device_path,
- errsv);
+ device = get_device_from_network(self, G_DBUS_PROXY(network));
+ if (!device) {
+ _LOGD("agent-request: device not found in IWD Agent request");
goto return_error;
}
- device = nm_manager_get_device_by_ifindex(priv->manager, ifindex);
- if (!NM_IS_DEVICE_IWD(device)) {
- _LOGD("agent-request: IWD device named %s is not a Wifi device in IWD Agent request",
- ifname);
- goto return_error;
- }
-
- if (nm_device_iwd_agent_query(NM_DEVICE_IWD(device), invocation))
+ if (nm_device_iwd_agent_query(device, invocation))
return;
- _LOGD("agent-request: device %s did not handle the IWD Agent request", ifname);
+ _LOGD("agent-request: device %s did not handle the IWD Agent request",
+ nm_device_get_iface(NM_DEVICE(device)));
return_error:
/* IWD doesn't look at the specific error */
@@ -259,17 +269,8 @@ register_agent(NMIwdManager *self)
GDBusInterface * agent_manager;
agent_manager = g_dbus_object_manager_get_interface(priv->object_manager,
- "/net/connman/iwd",
+ "/net/connman/iwd", /* IWD 1.0+ */
NM_IWD_AGENT_MANAGER_INTERFACE);
-
- if (!agent_manager) {
- /* IWD prior to 1.0 dated 30 October, 2019 has the agent manager on a
- * different path. */
- agent_manager = g_dbus_object_manager_get_interface(priv->object_manager,
- "/",
- NM_IWD_AGENT_MANAGER_INTERFACE);
- }
-
if (!agent_manager) {
_LOGE("unable to register the IWD Agent: PSK/8021x Wi-Fi networks may not work");
return;
@@ -585,6 +586,15 @@ interface_added(GDBusObjectManager *object_manager,
return;
}
+
+ if (nm_streq(iface_name, NM_IWD_NETWORK_INTERFACE)) {
+ NMDeviceIwd *device = get_device_from_network(self, proxy);
+
+ if (device)
+ nm_device_iwd_network_add_remove(device, proxy, TRUE);
+
+ return;
+ }
}
static void
@@ -629,6 +639,15 @@ interface_removed(GDBusObjectManager *object_manager,
g_hash_table_remove(priv->known_networks, &id);
return;
}
+
+ if (nm_streq(iface_name, NM_IWD_NETWORK_INTERFACE)) {
+ NMDeviceIwd *device = get_device_from_network(self, proxy);
+
+ if (device)
+ nm_device_iwd_network_add_remove(device, proxy, FALSE);
+
+ return;
+ }
}
static void