iwd: Ensure WFD IE is present during activation

If the connection has wfd_ies set, we want to ensure that a WFD
connection is being established so we want to check that the target peer
also supports WFD.  For now this in the IWD backend only.

However, WFD peers will send us their WFD IEs in their Probe Responses
only if our own Probe Request contained a WFD IE, or at least that's
when the spec mandates that they include the WFD IE.  This implies that
the discovery phase (NM.Device.WifiP2P.StartFind(options) / .StopFind())
needs to know the value of the local WFD IE and include it in the Probe
Requests, which existing clients (gnome-network-displays) doesn't do and
in fact can't do because there's no API for the client to pass the WFD
IE -- that is easy to add in the options parameter though (a
dictionary).

The current situation is that with the wpa_supplicant backend we'll
sometimes see the WFD IE (when the peer is discovered from a Probe
Request that it has sent, rather than from a Probe Response) and
sometimes not, while with the IWD backend we'll never see the WFD
information because IWD assumes that the client (NM) is not interested
in seeing it if it hasn't registered the local WFD information before
starting discovery.

So, for compatibility with this existing situation and with the
wpa_supplicant backend, ignore whether the peer is a WFD peer except in
the PREPARE stage.  In PREPARE, if we have a peer compatible with the
connection being activated -- except for the WFD information -- force a
new discovery, this time passing the WFD information from the
NMSettingConnection's wfd_ies, and only progress to CONFIG if the target
peer is re-discovered as a WFD peer within 10 seconds.

We don't actually check the contents of the WFD IEs to match, e.g. we
don't check the sink/source/dual role compatibility between our and the
peer's properties, but IWD will do some of these checks later during
activation.
This commit is contained in:
Andrew Zaborowski 2021-11-09 03:02:09 +01:00 committed by Thomas Haller
parent 524675db75
commit 4822d1a1d1
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
4 changed files with 24 additions and 14 deletions

View file

@ -194,14 +194,14 @@ check_connection_available(NMDevice *device,
return FALSE;
}
if (!nm_wifi_p2p_peer_check_compatible(peer, connection)) {
if (!nm_wifi_p2p_peer_check_compatible(peer, connection, FALSE)) {
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"Requested P2P peer is not compatible with profile");
return FALSE;
}
} else {
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
if (!peer) {
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
@ -596,7 +596,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
priv->wfd_registered = TRUE;
}
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, TRUE);
if (!peer) {
iwd_request_discovery(self, 10);
return NM_ACT_STAGE_RETURN_POSTPONE;
@ -674,7 +674,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
NM_IS_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)));
/* The prepare stage ensures that the peer has been found */
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, TRUE);
if (!peer) {
cleanup_connect_attempt(self);
NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
@ -742,7 +742,7 @@ act_check_new_peer_compatible(NMDeviceIwdP2P *self, NMWifiP2PPeer *peer)
connection = nm_device_get_applied_connection(device);
nm_assert(NM_IS_CONNECTION(connection));
if (nm_wifi_p2p_peer_check_compatible(peer, connection)) {
if (nm_wifi_p2p_peer_check_compatible(peer, connection, TRUE)) {
/* A peer for the connection was found, cancel the timeout and go to configure state. */
iwd_release_discovery(self);
nm_device_activate_schedule_stage2_device_config(device, FALSE);

View file

@ -168,7 +168,7 @@ check_connection_peer_joined(NMDeviceWifiP2P *device)
return FALSE;
/* NOTE: We currently only support connections to a specific peer */
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, conn);
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, conn, FALSE);
if (!peer)
return FALSE;
@ -369,7 +369,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
g_return_val_if_fail(s_wifi_p2p, NM_ACT_STAGE_RETURN_FAILURE);
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
if (!peer) {
/* Set up a timeout on the find attempt and run a find for the same period of time */
if (priv->find_peer_timeout_id == 0) {
@ -436,7 +436,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
NM_IS_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)));
/* The prepare stage ensures that the peer has been found */
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
if (!peer) {
NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
return NM_ACT_STAGE_RETURN_FAILURE;
@ -521,7 +521,8 @@ peer_add_remove(NMDeviceWifiP2P *self,
connection = nm_device_get_applied_connection(device);
nm_assert(NM_IS_CONNECTION(connection));
peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
peer =
nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
if (peer) {
/* A peer for the connection was found, cancel the timeout and go to configure state. */
nm_clear_g_source(&priv->find_peer_timeout_id);

View file

@ -101,14 +101,16 @@ nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head)
}
NMWifiP2PPeer *
nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head, NMConnection *connection)
nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head,
NMConnection *connection,
gboolean check_wfd)
{
NMWifiP2PPeer *peer;
g_return_val_if_fail(connection, NULL);
c_list_for_each_entry (peer, peers_lst_head, peers_lst) {
if (nm_wifi_p2p_peer_check_compatible(peer, connection))
if (nm_wifi_p2p_peer_check_compatible(peer, connection, check_wfd))
return peer;
}
return NULL;
@ -543,7 +545,7 @@ nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_l
}
gboolean
nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection)
nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection, gboolean check_wfd)
{
NMWifiP2PPeerPrivate *priv;
NMSettingWifiP2P *s_wifi_p2p;
@ -563,6 +565,10 @@ nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection)
if (hwaddr && (!priv->address || !nm_utils_hwaddr_matches(hwaddr, -1, priv->address, -1)))
return FALSE;
if (check_wfd && nm_setting_wifi_p2p_get_wfd_ies(s_wifi_p2p)
&& !nm_wifi_p2p_peer_get_wfd_ies(self))
return FALSE;
return TRUE;
}

View file

@ -51,7 +51,9 @@ gboolean nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer
const struct _NMSupplicantPeerInfo *peer_info);
gboolean nm_wifi_p2p_peer_update_from_iwd_object(NMWifiP2PPeer *peer, GDBusObject *obj);
gboolean nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection);
gboolean nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self,
NMConnection *connection,
gboolean check_wfd);
const char *nm_wifi_p2p_peer_get_supplicant_path(NMWifiP2PPeer *peer);
@ -83,7 +85,8 @@ nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_l
const char **nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head);
NMWifiP2PPeer *nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head,
NMConnection *connection);
NMConnection *connection,
gboolean check_wfd);
NMWifiP2PPeer *nm_wifi_p2p_peers_find_by_supplicant_path(const CList *peers_lst_head,
const char *path);