diff options
author | Thomas Haller <thaller@redhat.com> | 2020-10-19 18:53:49 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-10-19 18:54:04 +0200 |
commit | ba1e1c364caab1c7c9dae8b470d37c1803043fc7 (patch) | |
tree | a2dacd6946286b5604b9de707be38b5f1db470a7 | |
parent | a9ffb5b73ea3f5ccea8ea93f1f495d4810d16efc (diff) | |
parent | c92ad05cee6ed8f1edb17d0cc4a6dd2c7d8a2f46 (diff) | |
download | NetworkManager-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.c | 318 | ||||
-rw-r--r-- | src/devices/wifi/nm-device-iwd.h | 2 | ||||
-rw-r--r-- | src/devices/wifi/nm-iwd-manager.c | 117 |
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 |