wifi/iwd: merge branch 'balrog-kun:iwd-hidden-networks-cleanup'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/646
This commit is contained in:
Thomas Haller 2020-10-19 18:53:49 +02:00
commit ba1e1c364c
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
3 changed files with 263 additions and 172 deletions

View file

@ -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)
static NMWifiAP *
ap_from_network(NMDeviceIwd *self,
GDBusProxy * network,
NMRefString *bss_path,
gint64 last_seen_msec,
int16_t signal)
{
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;
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 *

View file

@ -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__ */

View file

@ -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);
_LOGE("agent-request: unable to find the network object");
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);
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;
}
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);
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