wifi/iwd: merge branch 'balrog-kun/NetworkManager:iwd-fixes'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1338
This commit is contained in:
@@ -70,6 +70,7 @@ typedef struct {
|
||||
bool secrets_failed : 1;
|
||||
bool networks_requested : 1;
|
||||
bool networks_changed : 1;
|
||||
bool assuming : 1;
|
||||
gint64 last_scan;
|
||||
uint32_t ap_id;
|
||||
guint32 rate;
|
||||
@@ -77,6 +78,7 @@ typedef struct {
|
||||
GDBusMethodInvocation *pending_agent_request;
|
||||
NMActiveConnection *assumed_ac;
|
||||
guint assumed_ac_timeout;
|
||||
NMIwdManager *manager;
|
||||
} NMDeviceIwdPrivate;
|
||||
|
||||
struct _NMDeviceIwd {
|
||||
@@ -289,6 +291,7 @@ insert_ap_from_network(NMDeviceIwd *self,
|
||||
gint64 last_seen_msec,
|
||||
int16_t signal)
|
||||
{
|
||||
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
|
||||
gs_unref_object GDBusProxy *network_proxy = NULL;
|
||||
nm_auto_ref_string NMRefString *bss_path = nm_ref_string_new(path);
|
||||
NMWifiAP *ap;
|
||||
@@ -299,7 +302,7 @@ insert_ap_from_network(NMDeviceIwd *self,
|
||||
}
|
||||
|
||||
network_proxy =
|
||||
nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), path, NM_IWD_NETWORK_INTERFACE);
|
||||
nm_iwd_manager_get_dbus_interface(priv->manager, path, NM_IWD_NETWORK_INTERFACE);
|
||||
|
||||
ap = ap_from_network(self, network_proxy, bss_path, last_seen_msec, signal);
|
||||
if (!ap)
|
||||
@@ -581,6 +584,10 @@ deactivate(NMDevice *device)
|
||||
if (!priv->dbus_obj)
|
||||
return;
|
||||
|
||||
/* Don't cause IWD to break the connection being assumed */
|
||||
if (priv->assuming)
|
||||
return;
|
||||
|
||||
if (priv->dbus_station_proxy) {
|
||||
gs_unref_variant GVariant *value =
|
||||
g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State");
|
||||
@@ -673,7 +680,7 @@ deactivate_async(NMDevice *device,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_connection_known_network(NMConnection *connection)
|
||||
is_connection_known_network(NMIwdManager *manager, NMConnection *connection)
|
||||
{
|
||||
NMIwdNetworkSecurity security;
|
||||
gs_free char *ssid = NULL;
|
||||
@@ -681,17 +688,17 @@ is_connection_known_network(NMConnection *connection)
|
||||
if (!nm_wifi_connection_get_iwd_ssid_and_security(connection, &ssid, &security))
|
||||
return FALSE;
|
||||
|
||||
return nm_iwd_manager_is_known_network(nm_iwd_manager_get(), ssid, security);
|
||||
return nm_iwd_manager_is_known_network(manager, ssid, security);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_ap_known_network(NMWifiAP *ap)
|
||||
is_ap_known_network(NMIwdManager *manager, NMWifiAP *ap)
|
||||
{
|
||||
gs_unref_object GDBusProxy *network_proxy = NULL;
|
||||
gs_unref_variant GVariant *known_network = NULL;
|
||||
|
||||
network_proxy =
|
||||
nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(),
|
||||
nm_iwd_manager_get_dbus_interface(manager,
|
||||
nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)),
|
||||
NM_IWD_NETWORK_INTERFACE);
|
||||
if (!network_proxy)
|
||||
@@ -794,7 +801,8 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
|
||||
* thus are Known Networks.
|
||||
*/
|
||||
if (security == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (!is_connection_known_network(connection)) {
|
||||
if (!is_connection_known_network(priv->manager, connection)
|
||||
&& !nm_iwd_manager_is_recently_mirrored(priv->manager, ssid)) {
|
||||
nm_utils_error_set_literal(error,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
|
||||
"802.1x connections must have IWD provisioning files");
|
||||
@@ -927,7 +935,9 @@ check_connection_available(NMDevice *device,
|
||||
*/
|
||||
if (nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security)
|
||||
&& security == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (!is_ap_known_network(ap)) {
|
||||
if (!is_ap_known_network(priv->manager, ap)
|
||||
&& !nm_iwd_manager_is_recently_mirrored(priv->manager,
|
||||
nm_setting_wireless_get_ssid(s_wifi))) {
|
||||
nm_utils_error_set_literal(
|
||||
error,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||
@@ -2044,7 +2054,7 @@ assume_connection(NMDeviceIwd *self, NMWifiAP *ap)
|
||||
* becomes "managed" only when ACTIVATED but for IWD it's really
|
||||
* managed when IP_CONFIG starts.
|
||||
*/
|
||||
sett_conn = nm_iwd_manager_get_ap_mirror_connection(nm_iwd_manager_get(), ap);
|
||||
sett_conn = nm_iwd_manager_get_ap_mirror_connection(priv->manager, ap);
|
||||
if (!sett_conn)
|
||||
goto error;
|
||||
|
||||
@@ -2217,7 +2227,8 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
||||
* 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))
|
||||
if (!nm_setting_wireless_get_hidden(s_wireless)
|
||||
|| is_connection_known_network(priv->manager, connection))
|
||||
return NM_ACT_STAGE_RETURN_FAILURE;
|
||||
|
||||
add_new:
|
||||
@@ -2270,6 +2281,18 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
/* With priv->iwd_autoconnect we have to let IWD handle retries for
|
||||
* infrastructure networks. IWD will not necessarily retry the same
|
||||
* network after a failure but it will likely go into an autoconnect
|
||||
* mode and we don't want to try to override the logic. We don't need
|
||||
* to reset the retry count so we set no timeout.
|
||||
*/
|
||||
if (priv->iwd_autoconnect) {
|
||||
NMSettingsConnection *sett_conn = nm_act_request_get_settings_connection(req);
|
||||
|
||||
nm_settings_connection_autoconnect_retries_set(sett_conn, 0);
|
||||
}
|
||||
|
||||
/* With priv->iwd_autoconnect, if we're assuming a connection because
|
||||
* of a state change to "connecting", signal stage 2 is still running.
|
||||
* If "connected" or "roaming", we can go right to the IP_CONFIG state
|
||||
@@ -2310,7 +2333,9 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
||||
* fail, for other combinations we will let the Connect call fail
|
||||
* or ask us for any missing secrets through the Agent.
|
||||
*/
|
||||
if (nm_connection_get_setting_802_1x(connection) && !is_ap_known_network(ap)) {
|
||||
if (nm_connection_get_setting_802_1x(connection) && !is_ap_known_network(priv->manager, ap)
|
||||
&& !nm_iwd_manager_is_recently_mirrored(priv->manager,
|
||||
nm_setting_wireless_get_ssid(s_wireless))) {
|
||||
_LOGI(LOGD_DEVICE | LOGD_WIFI,
|
||||
"Activation: (wifi) access point '%s' has 802.1x security but is not configured "
|
||||
"in IWD.",
|
||||
@@ -2351,7 +2376,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
||||
}
|
||||
|
||||
network_proxy = nm_iwd_manager_get_dbus_interface(
|
||||
nm_iwd_manager_get(),
|
||||
priv->manager,
|
||||
nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)),
|
||||
NM_IWD_NETWORK_INTERFACE);
|
||||
if (!network_proxy) {
|
||||
@@ -2719,12 +2744,20 @@ state_changed(NMDeviceIwd *self, const char *new_state)
|
||||
"IWD is connecting to the wrong AP, %s activation",
|
||||
switch_ap ? "replacing" : "aborting");
|
||||
cleanup_association_attempt(self, !switch_ap);
|
||||
nm_device_state_changed(device,
|
||||
NM_DEVICE_STATE_FAILED,
|
||||
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
|
||||
|
||||
if (switch_ap)
|
||||
assume_connection(self, ap);
|
||||
if (!switch_ap) {
|
||||
nm_device_state_changed(device,
|
||||
NM_DEVICE_STATE_FAILED,
|
||||
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->assuming = TRUE; /* Don't send Station.Disconnect() */
|
||||
nm_device_state_changed(device,
|
||||
NM_DEVICE_STATE_DISCONNECTED,
|
||||
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
|
||||
priv->assuming = FALSE;
|
||||
assume_connection(self, ap);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3101,7 +3134,7 @@ nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object)
|
||||
goto error;
|
||||
}
|
||||
|
||||
adapter_proxy = nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(),
|
||||
adapter_proxy = nm_iwd_manager_get_dbus_interface(priv->manager,
|
||||
g_variant_get_string(value, NULL),
|
||||
NM_IWD_WIPHY_INTERFACE);
|
||||
if (!adapter_proxy) {
|
||||
@@ -3411,7 +3444,7 @@ nm_device_iwd_init(NMDeviceIwd *self)
|
||||
g_signal_connect(self, "notify::" NM_DEVICE_AUTOCONNECT, G_CALLBACK(autoconnect_changed), self);
|
||||
|
||||
/* Make sure the manager is running */
|
||||
(void) nm_iwd_manager_get();
|
||||
priv->manager = g_object_ref(nm_iwd_manager_get());
|
||||
}
|
||||
|
||||
NMDevice *
|
||||
@@ -3443,6 +3476,8 @@ dispose(GObject *object)
|
||||
G_OBJECT_CLASS(nm_device_iwd_parent_class)->dispose(object);
|
||||
|
||||
nm_assert(c_list_is_empty(&priv->aps_lst_head));
|
||||
|
||||
g_clear_object(&priv->manager);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -46,6 +46,11 @@ typedef struct {
|
||||
const KnownNetworkId *id;
|
||||
} KnownNetworkData;
|
||||
|
||||
typedef struct {
|
||||
GBytes *ssid;
|
||||
gint64 timestamp;
|
||||
} RecentlyMirroredData;
|
||||
|
||||
typedef struct {
|
||||
NMManager *manager;
|
||||
NMSettings *settings;
|
||||
@@ -62,6 +67,7 @@ typedef struct {
|
||||
GHashTable *p2p_devices;
|
||||
NMIwdWfdInfo wfd_info;
|
||||
guint wfd_use_count;
|
||||
GSList *recently_mirrored;
|
||||
} NMIwdManagerPrivate;
|
||||
|
||||
struct _NMIwdManager {
|
||||
@@ -353,6 +359,70 @@ register_agent(NMIwdManager *self)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
recently_mirrored_data_free(void *data)
|
||||
{
|
||||
RecentlyMirroredData *rmd = data;
|
||||
|
||||
g_bytes_unref(rmd->ssid);
|
||||
g_free(rmd);
|
||||
}
|
||||
|
||||
/* When we mirror an 802.1x connection to an IWD config file, and there's an
|
||||
* AP in range with matching SSID, that connection should become available
|
||||
* for activation. In IWD terms when an 802.1x network becomes a Known
|
||||
* Network, it can be connected to using the .Connect D-Bus method.
|
||||
*
|
||||
* However there's a delay between writing the IWD config file and receiving
|
||||
* the InterfaceAdded event for the Known Network so we don't immediately
|
||||
* find out that the network can now be used. If an NM client creates a
|
||||
* new connection for an 802.1x AP and tries to activate it immediately,
|
||||
* NMDeviceIWD will not allow it to because it doesn't know the network is
|
||||
* known yet. To work around this, we save the SSIDs of 802.1x connections
|
||||
* we recently mirrored to IWD config files, for 2 seconds, and we treat
|
||||
* them as Known Networks in that period since in theory activations should
|
||||
* succeed.
|
||||
*/
|
||||
bool
|
||||
nm_iwd_manager_is_recently_mirrored(NMIwdManager *self, const GBytes *ssid)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
gint64 now = nm_utils_get_monotonic_timestamp_nsec();
|
||||
GSList *iter;
|
||||
RecentlyMirroredData *rmd;
|
||||
|
||||
/* Drop entries older than 2 seconds */
|
||||
while (priv->recently_mirrored) {
|
||||
rmd = priv->recently_mirrored->data;
|
||||
if (now < rmd->timestamp + 2000000000)
|
||||
break;
|
||||
|
||||
priv->recently_mirrored = g_slist_remove(priv->recently_mirrored, rmd);
|
||||
recently_mirrored_data_free(rmd);
|
||||
}
|
||||
|
||||
for (iter = priv->recently_mirrored; iter; iter = iter->next) {
|
||||
rmd = iter->data;
|
||||
if (g_bytes_equal(ssid, rmd->ssid))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
save_mirrored(NMIwdManager *self, GBytes *ssid)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
|
||||
RecentlyMirroredData *rmd = g_malloc(sizeof(RecentlyMirroredData));
|
||||
|
||||
rmd->ssid = g_bytes_ref(ssid);
|
||||
rmd->timestamp = nm_utils_get_monotonic_timestamp_nsec();
|
||||
priv->recently_mirrored = g_slist_append(priv->recently_mirrored, rmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static KnownNetworkId *
|
||||
known_network_id_new(const char *name, NMIwdNetworkSecurity security)
|
||||
{
|
||||
@@ -721,6 +791,9 @@ sett_conn_changed(NMSettingsConnection *sett_conn,
|
||||
"iwd: changed Wi-Fi connection %s mirrored as IWD profile %s",
|
||||
nm_settings_connection_get_id(sett_conn),
|
||||
full_path);
|
||||
|
||||
if (security == NM_IWD_NETWORK_SECURITY_8021X)
|
||||
save_mirrored(nm_iwd_manager_get(), ssid);
|
||||
}
|
||||
|
||||
/* Look up an existing NMSettingsConnection for a network that has been
|
||||
@@ -1283,6 +1356,7 @@ connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer
|
||||
gs_free_error GError *error = NULL;
|
||||
nm_auto_unref_keyfile GKeyFile *iwd_config = NULL;
|
||||
NMSettingsConnectionIntFlags flags;
|
||||
NMIwdNetworkSecurity security;
|
||||
|
||||
if (!nm_streq(nm_settings_connection_get_connection_type(sett_conn), "802-11-wireless"))
|
||||
return;
|
||||
@@ -1338,6 +1412,12 @@ connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer
|
||||
_LOGD("New Wi-Fi connection %s mirrored as IWD profile %s",
|
||||
nm_settings_connection_get_id(sett_conn),
|
||||
full_path);
|
||||
|
||||
if (nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &security)
|
||||
&& security == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
NMSettingWireless *s_wifi = nm_connection_get_setting_wireless(conn);
|
||||
save_mirrored(nm_iwd_manager_get(), nm_setting_wireless_get_ssid(s_wifi));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1952,6 +2032,8 @@ dispose(GObject *object)
|
||||
|
||||
g_hash_table_unref(nm_steal_pointer(&priv->p2p_devices));
|
||||
|
||||
g_slist_free_full(nm_steal_pointer(&priv->recently_mirrored), recently_mirrored_data_free);
|
||||
|
||||
G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
|
@@ -63,4 +63,6 @@ gboolean nm_iwd_manager_check_wfd_info_compatible(NMIwdManager *self, const NMIw
|
||||
gboolean nm_iwd_manager_register_wfd(NMIwdManager *self, const NMIwdWfdInfo *wfd_info);
|
||||
void nm_iwd_manager_unregister_wfd(NMIwdManager *self);
|
||||
|
||||
bool nm_iwd_manager_is_recently_mirrored(NMIwdManager *self, const GBytes *ssid);
|
||||
|
||||
#endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */
|
||||
|
Reference in New Issue
Block a user