wifi: set the BridgeIfname supplicant property when needed

When a wifi device is in a bridge, the supplicant must be aware of it,
as a socket must be opened on the bridge to receive packets.

Set the BridgeIfname property of the supplicant Interface object
before starting the association. Note that the property was read-only
in the past and recently [1] became read-write. When using a
supplicant version without the patch, writing the property will return
an InvalidArgs error and NetworkManager will print a warning.

[1] https://w1.fi/cgit/hostap/commit/?id=1c58317f56e312576b6872440f125f794e45f991

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/83
This commit is contained in:
Beniamino Galvani 2020-09-30 13:35:49 +02:00
parent ef9510e30c
commit ae31b4bf4e
3 changed files with 62 additions and 0 deletions

View file

@ -3136,6 +3136,9 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
NMSettingWireless * s_wireless;
GError * error = NULL;
guint timeout;
NMActRequest * request;
NMActiveConnection * master_ac;
NMDevice * master;
nm_clear_g_source(&priv->sup_timeout_id);
nm_clear_g_source(&priv->link_timeout_id);
@ -3209,6 +3212,15 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
goto out_fail;
}
/* Tell the supplicant in which bridge the interface is */
if ((request = nm_device_get_act_request(device))
&& (master_ac = nm_active_connection_get_master(NM_ACTIVE_CONNECTION(request)))
&& (master = nm_active_connection_get_device(master_ac))
&& nm_device_get_device_type(master) == NM_DEVICE_TYPE_BRIDGE) {
nm_supplicant_interface_set_bridge(priv->sup_iface, nm_device_get_iface(master));
} else
nm_supplicant_interface_set_bridge(priv->sup_iface, NULL);
nm_supplicant_interface_assoc(priv->sup_iface, config, supplicant_iface_assoc_cb, self);
/* Set up a timeout on the association attempt */

View file

@ -1322,6 +1322,54 @@ nm_supplicant_interface_get_capabilities(NMSupplicantInterface *self)
return caps;
}
static void
set_bridge_cb(GVariant *ret, GError *error, gpointer user_data)
{
NMSupplicantInterface *self;
NMLogLevel level;
gs_free const char * bridge = NULL;
nm_utils_user_data_unpack(user_data, &self, &bridge);
if (nm_utils_error_is_cancelled(error))
return;
/* The supplicant supports writing the bridge property since
* version 2.10. Before that version, trying to set the property
* results in a InvalidArgs error. Don't log a warning unless we
* are trying to set a non-NULL bridge. */
if (!error)
level = LOGL_DEBUG;
else if (bridge == NULL && g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS)) {
level = LOGL_DEBUG;
} else
level = LOGL_WARN;
_NMLOG(level,
"set bridge %s%s%s result: %s",
NM_PRINT_FMT_QUOTE_STRING(bridge),
error ? error->message : "success");
}
void
nm_supplicant_interface_set_bridge(NMSupplicantInterface *self, const char *bridge)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
_LOGT("set bridge %s%s%s", NM_PRINT_FMT_QUOTE_STRING(bridge));
nm_dbus_connection_call_set(priv->dbus_connection,
priv->name_owner->str,
priv->object_path->str,
NM_WPAS_DBUS_IFACE_INTERFACE,
"BridgeIfname",
g_variant_new_string(bridge ?: ""),
DBUS_TIMEOUT_MSEC,
priv->main_cancellable,
set_bridge_cb,
nm_utils_user_data_pack(self, g_strdup(bridge)));
}
void
nm_supplicant_interface_set_global_capabilities(NMSupplicantInterface *self, NMSupplCapMask value)
{

View file

@ -190,4 +190,6 @@ void nm_supplicant_interface_cancel_wps(NMSupplicantInterface *self);
NMSupplicantAuthState nm_supplicant_interface_get_auth_state(NMSupplicantInterface *self);
void nm_supplicant_interface_set_bridge(NMSupplicantInterface *self, const char *bridge);
#endif /* __NM_SUPPLICANT_INTERFACE_H__ */