diff options
| author | Sebastien Bacher <seb128@ubuntu.com> | 2021-07-05 20:35:03 +0200 |
|---|---|---|
| committer | Sebastien Bacher <seb128@ubuntu.com> | 2021-07-05 20:35:03 +0200 |
| commit | 35779c6675728fa6f0fd0a21cefb904408509c23 (patch) | |
| tree | 553e7239e0ba182b4f9b29b1e7a9d66a595d08bc /src/core/devices/wifi | |
| parent | d92aa7f298fe84d4cf686c5ad64b73438e00d377 (diff) | |
New upstream version 1.32.2
Diffstat (limited to 'src/core/devices/wifi')
| -rw-r--r-- | src/core/devices/wifi/meson.build | 2 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-device-iwd.c | 206 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-device-olpc-mesh.c | 32 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-device-wifi-p2p.c | 9 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-device-wifi.c | 145 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-device-wifi.h | 2 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-iwd-manager.c | 435 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-iwd-manager.h | 1 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-ap.c | 153 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-ap.h | 3 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-common.c | 38 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-factory.c | 15 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-p2p-peer.c | 7 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-utils.c | 902 | ||||
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-utils.h | 9 | ||||
| -rw-r--r-- | src/core/devices/wifi/tests/test-devices-wifi.c | 58 |
16 files changed, 1660 insertions, 357 deletions
diff --git a/src/core/devices/wifi/meson.build b/src/core/devices/wifi/meson.build index 743937db..85553c53 100644 --- a/src/core/devices/wifi/meson.build +++ b/src/core/devices/wifi/meson.build @@ -22,7 +22,6 @@ libnm_device_plugin_wifi_static = static_library( dependencies: [ core_plugin_dep, ], - c_args: daemon_c_flags, ) libnm_device_plugin_wifi_static_dep = declare_dependency( @@ -38,7 +37,6 @@ libnm_device_plugin_wifi = shared_module( core_plugin_dep, libnm_device_plugin_wifi_static_dep ], - c_args: daemon_c_flags, link_args: ldflags_linker_script_devices, link_depends: linker_script_devices, install: true, diff --git a/src/core/devices/wifi/nm-device-iwd.c b/src/core/devices/wifi/nm-device-iwd.c index 95ade44b..56338743 100644 --- a/src/core/devices/wifi/nm-device-iwd.c +++ b/src/core/devices/wifi/nm-device-iwd.c @@ -13,16 +13,16 @@ #include "devices/nm-device.h" #include "nm-act-request.h" #include "nm-config.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-iwd-manager.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-setting-8021x.h" #include "nm-setting-connection.h" #include "nm-setting-wireless-security.h" #include "nm-setting-wireless.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/nm-dbus-compat.h" #include "nm-utils.h" #include "nm-wifi-common.h" #include "nm-wifi-utils.h" @@ -55,7 +55,7 @@ typedef struct { CList aps_lst_head; NMWifiAP * current_ap; GCancellable * cancellable; - NMDeviceWifiCapabilities capabilities; + _NMDeviceWifiCapabilities capabilities; NMActRequestGetSecretsCallId *wifi_secrets_id; guint periodic_scan_id; guint periodic_update_id; @@ -265,7 +265,7 @@ ap_from_network(NMDeviceIwd *self, .bss_path = bss_path, .last_seen_msec = last_seen_msec, .bssid_valid = TRUE, - .mode = NM_802_11_MODE_INFRA, + .mode = _NM_802_11_MODE_INFRA, .rsn_flags = ap_security_flags_from_network_type(type), .ssid = ssid, .signal_percent = nm_wifi_utils_level_to_quality(signal / 100), @@ -588,10 +588,16 @@ deactivate(NMDevice *device) return; } - cleanup_association_attempt(self, TRUE); + cleanup_association_attempt(self, FALSE); priv->act_mode_switch = FALSE; - if (!priv->dbus_station_proxy) + /* Don't trigger any actions on the IWD side until the device is managed */ + if (priv->iwd_autoconnect && nm_device_get_state(device) < NM_DEVICE_STATE_DISCONNECTED) + return; + + if (priv->dbus_station_proxy) + send_disconnect(self); + else reset_mode(self, NULL, NULL, NULL); } @@ -647,6 +653,11 @@ deactivate_async(NMDevice * device, cleanup_association_attempt(self, FALSE); priv->act_mode_switch = FALSE; + if (priv->iwd_autoconnect && nm_device_get_state(device) < NM_DEVICE_STATE_DISCONNECTED) { + nm_utils_invoke_on_idle(cancellable, disconnect_cb_on_idle, user_data); + return; + } + if (priv->dbus_station_proxy) { g_dbus_proxy_call(priv->dbus_station_proxy, "Disconnect", @@ -801,7 +812,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * NMSettingWirelessSecurity *s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_AP)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, "device does not support Access Point mode"); @@ -819,7 +830,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * NMSettingWirelessSecurity *s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_ADHOC)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, "device does not support Ad-Hoc mode"); @@ -1034,16 +1045,15 @@ complete_connection(NMDevice * device, } ssid_utf8 = iwd_ssid_to_str(ssid); - nm_utils_complete_generic( - nm_device_get_platform(device), - connection, - NM_SETTING_WIRELESS_SETTING_NAME, - existing_connections, - ssid_utf8, - ssid_utf8, - NULL, - nm_setting_wireless_get_mac_address(s_wifi) ? NULL : nm_device_get_iface(device), - TRUE); + nm_utils_complete_generic(nm_device_get_platform(device), + connection, + NM_SETTING_WIRELESS_SETTING_NAME, + existing_connections, + ssid_utf8, + ssid_utf8, + NULL, + NULL, + TRUE); if (hidden) g_object_set(s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); @@ -1306,6 +1316,7 @@ static gboolean try_reply_agent_request(NMDeviceIwd * self, NMConnection * connection, GDBusMethodInvocation *invocation, + gboolean allow_existing, const char ** setting_name, const char ** setting_key, gboolean * replied) @@ -1320,56 +1331,64 @@ try_reply_agent_request(NMDeviceIwd * self, *replied = FALSE; if (nm_streq(method_name, "RequestPassphrase")) { - const char *psk; - if (!s_wireless_sec) return FALSE; - psk = nm_setting_wireless_security_get_psk(s_wireless_sec); - if (psk) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the PSK to the IWD Agent"); + if (allow_existing) { + const char *psk = nm_setting_wireless_security_get_psk(s_wireless_sec); - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", psk)); - *replied = TRUE; - return TRUE; + if (psk) { + _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the PSK to the IWD Agent"); + + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", psk)); + *replied = TRUE; + return TRUE; + } } *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; *setting_key = NM_SETTING_WIRELESS_SECURITY_PSK; return TRUE; } else if (nm_streq(method_name, "RequestPrivateKeyPassphrase")) { - const char *password; - if (!s_8021x) return FALSE; - password = nm_setting_802_1x_get_private_key_password(s_8021x); - if (password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the private key password to the IWD Agent"); + if (allow_existing) { + const char *password = nm_setting_802_1x_get_private_key_password(s_8021x); - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); - *replied = TRUE; - return TRUE; + if (password) { + _LOGD(LOGD_DEVICE | LOGD_WIFI, + "Returning the private key password to the IWD Agent"); + + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); + *replied = TRUE; + return TRUE; + } } *setting_name = NM_SETTING_802_1X_SETTING_NAME; *setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD; return TRUE; } else if (nm_streq(method_name, "RequestUserNameAndPassword")) { - const char *identity, *password; + const char *identity; if (!s_8021x) return FALSE; identity = nm_setting_802_1x_get_identity(s_8021x); - password = nm_setting_802_1x_get_password(s_8021x); - if (identity && password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the username and password to the IWD Agent"); - g_dbus_method_invocation_return_value(invocation, - g_variant_new("(ss)", identity, password)); - *replied = TRUE; - return TRUE; + if (allow_existing) { + const char *password = nm_setting_802_1x_get_password(s_8021x); + + if (identity && password) { + _LOGD(LOGD_DEVICE | LOGD_WIFI, + "Returning the username and password to the IWD Agent"); + + g_dbus_method_invocation_return_value(invocation, + g_variant_new("(ss)", identity, password)); + *replied = TRUE; + return TRUE; + } } *setting_name = NM_SETTING_802_1X_SETTING_NAME; @@ -1379,18 +1398,19 @@ try_reply_agent_request(NMDeviceIwd * self, *setting_key = NM_SETTING_802_1X_PASSWORD; return TRUE; } else if (nm_streq(method_name, "RequestUserPassword")) { - const char *password; - if (!s_8021x) return FALSE; - password = nm_setting_802_1x_get_password(s_8021x); - if (password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the user password to the IWD Agent"); + if (allow_existing) { + const char *password = nm_setting_802_1x_get_password(s_8021x); - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); - *replied = TRUE; - return TRUE; + if (password) { + _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the user password to the IWD Agent"); + + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); + *replied = TRUE; + return TRUE; + } } *setting_name = NM_SETTING_802_1X_SETTING_NAME; @@ -1441,6 +1461,8 @@ wifi_secrets_cb(NMActRequest * req, gboolean replied; NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; + NMIwdNetworkSecurity security; + NMConnection * connection; nm_utils_user_data_unpack(user_data, &self, &invocation); @@ -1473,9 +1495,18 @@ wifi_secrets_cb(NMActRequest * req, goto secrets_error; } + connection = nm_device_get_applied_connection(device); + + if (nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security) + && security == NM_IWD_NETWORK_SECURITY_PSK) { + if (nm_settings_connection_get_timestamp(nm_device_get_settings_connection(device), NULL)) + get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; + } + if (!try_reply_agent_request(self, - nm_act_request_get_applied_connection(req), + connection, invocation, + TRUE, &setting_name, &setting_key, &replied)) @@ -1501,9 +1532,6 @@ wifi_secrets_cb(NMActRequest * req, return; } - 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; - /* Request further secrets if we still need something */ wifi_secrets_get_one(self, setting_name, get_secret_flags, setting_key, invocation); return; @@ -1595,8 +1623,6 @@ network_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data) dbus_error = g_dbus_error_get_remote_error(error); if (nm_streq0(dbus_error, "net.connman.iwd.Failed")) { - nm_connection_clear_secrets(connection); - /* 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") && priv->secrets_failed) { @@ -2610,9 +2636,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) switch (prop_id) { case PROP_MODE: if (!priv->current_ap) - g_value_set_uint(value, NM_802_11_MODE_UNKNOWN); + g_value_set_uint(value, _NM_802_11_MODE_UNKNOWN); else if (nm_wifi_ap_is_hotspot(priv->current_ap)) - g_value_set_uint(value, NM_802_11_MODE_AP); + g_value_set_uint(value, _NM_802_11_MODE_AP); else g_value_set_uint(value, nm_wifi_ap_get_mode(priv->current_ap)); @@ -3034,7 +3060,7 @@ nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object) GVariantIter * iter; const char * mode; gboolean powered; - NMDeviceWifiCapabilities capabilities; + _NMDeviceWifiCapabilities capabilities; if (!nm_g_object_ref_set(&priv->dbus_obj, object)) return; @@ -3096,14 +3122,14 @@ nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object) goto error; } - capabilities = NM_WIFI_DEVICE_CAP_CIPHER_CCMP | NM_WIFI_DEVICE_CAP_RSN; + capabilities = _NM_WIFI_DEVICE_CAP_CIPHER_CCMP | _NM_WIFI_DEVICE_CAP_RSN; g_variant_get(value, "as", &iter); while (g_variant_iter_next(iter, "&s", &mode)) { if (nm_streq(mode, "ap")) - capabilities |= NM_WIFI_DEVICE_CAP_AP; + capabilities |= _NM_WIFI_DEVICE_CAP_AP; else if (nm_streq(mode, "ad-hoc")) - capabilities |= NM_WIFI_DEVICE_CAP_ADHOC; + capabilities |= _NM_WIFI_DEVICE_CAP_ADHOC; } g_variant_iter_free(iter); @@ -3145,8 +3171,11 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) const char * setting_key; gboolean replied; NMWifiAP * ap; + gboolean allow_existing = FALSE; NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; + NMIwdNetworkSecurity security; + NMConnection * connection; nm_auto_ref_string NMRefString *network_path = NULL; if (!invocation) { @@ -3250,9 +3279,37 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) /* Otherwise handle as usual */ } + /* Normally for PSK networks require new secret every time IWD asks for + * it. IWD only queries us if it has not saved the PSK (e.g. by policy) + * or a previous attempt has failed with current secrets so it wants a + * fresh value. It doesn't know about agent-owned secrets so whenever + * possible and the PSK is saved and not asked from NM. However if this + * is a new connection it may include all of the needed settings already + * so allow using these, too. Connection timestamp is set after + * activation or after first activation failure (to 0). + * + * For 802.1x, since IWD assumes the network is pre-provisioned by an + * admin and tested, there's no reason for IWD to save secrets in + * the network config file and there's no reason to ask for a new value + * of a saved (i.e. system-owned) secret because it can't be wrong. + * Since NM has a richer set of secret storage options we never specify + * NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW and let + * nm_settings_connection_get_secrets decide. + */ + connection = nm_device_get_applied_connection(device); + + if (nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security) + && security == NM_IWD_NETWORK_SECURITY_PSK) { + if (nm_settings_connection_get_timestamp(nm_device_get_settings_connection(device), NULL)) + get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; + else + allow_existing = TRUE; + } + if (!try_reply_agent_request(self, - nm_device_get_applied_connection(device), + connection, invocation, + allow_existing, &setting_name, &setting_key, &replied)) { @@ -3263,17 +3320,6 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) if (replied) return TRUE; - /* Normally require new secrets every time IWD asks for them. - * IWD only queries us if it has not saved the secrets (e.g. by policy) - * or a previous attempt has failed with current secrets so it wants - * a fresh set. However if this is a new connection it may include - * all of the needed settings already so allow using these, too. - * Connection timestamp is set after activation or after first - * activation failure (to 0). - */ - if (nm_settings_connection_get_timestamp(nm_device_get_settings_connection(device), NULL)) - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - 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); @@ -3452,9 +3498,9 @@ nm_device_iwd_class_init(NMDeviceIwdClass *klass) obj_properties[PROP_MODE] = g_param_spec_uint(NM_DEVICE_IWD_MODE, "", "", - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_AP, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_UNKNOWN, + _NM_802_11_MODE_AP, + _NM_802_11_MODE_INFRA, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_BITRATE] = g_param_spec_uint(NM_DEVICE_IWD_BITRATE, @@ -3485,7 +3531,7 @@ nm_device_iwd_class_init(NMDeviceIwdClass *klass) "", 0, G_MAXUINT32, - NM_WIFI_DEVICE_CAP_NONE, + _NM_WIFI_DEVICE_CAP_NONE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_SCANNING] = g_param_spec_boolean(NM_DEVICE_IWD_SCANNING, diff --git a/src/core/devices/wifi/nm-device-olpc-mesh.c b/src/core/devices/wifi/nm-device-olpc-mesh.c index af83c4a3..040350d5 100644 --- a/src/core/devices/wifi/nm-device-olpc-mesh.c +++ b/src/core/devices/wifi/nm-device-olpc-mesh.c @@ -28,7 +28,7 @@ #include "nm-setting-connection.h" #include "nm-setting-olpc-mesh.h" #include "nm-manager.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #define _NMLOG_DEVICE_TYPE NMDeviceOlpcMesh #include "devices/nm-device-logging.h" @@ -122,6 +122,17 @@ complete_connection(NMDevice * device, /*****************************************************************************/ +static const char * +get_dhcp_anycast_address(NMDevice *device) +{ + NMSettingOlpcMesh *s_mesh; + + s_mesh = nm_device_get_applied_setting(device, NM_TYPE_SETTING_OLPC_MESH); + return s_mesh ? nm_setting_olpc_mesh_get_dhcp_anycast_address(s_mesh) : NULL; +} + +/*****************************************************************************/ + static NMActStageReturn act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { @@ -178,7 +189,6 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(device); NMSettingOlpcMesh *s_mesh; GBytes * ssid; - const char * anycast_addr; gboolean success; s_mesh = nm_device_get_applied_setting(device, NM_TYPE_SETTING_OLPC_MESH); @@ -197,9 +207,6 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) return NM_ACT_STAGE_RETURN_FAILURE; } - anycast_addr = nm_setting_olpc_mesh_get_dhcp_anycast_address(s_mesh); - nm_device_set_dhcp_anycast_address(device, anycast_addr); - if (!_mesh_set_channel(self, nm_setting_olpc_mesh_get_channel(s_mesh))) { _LOGW(LOGD_WIFI, "Unable to set the mesh channel"); return NM_ACT_STAGE_RETURN_FAILURE; @@ -492,19 +499,15 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_olpc_mesh = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_OLPC_MESH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Companion", - "o", - NM_DEVICE_OLPC_MESH_COMPANION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Companion", + "o", + NM_DEVICE_OLPC_MESH_COMPANION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( "ActiveChannel", "u", NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL), ), ), - .legacy_property_changed = TRUE, }; static void @@ -531,6 +534,7 @@ nm_device_olpc_mesh_class_init(NMDeviceOlpcMeshClass *klass) device_class->act_stage2_config = act_stage2_config; device_class->state_changed = state_changed; device_class->get_dhcp_timeout_for_device = get_dhcp_timeout_for_device; + device_class->get_dhcp_anycast_address = get_dhcp_anycast_address; obj_properties[PROP_COMPANION] = g_param_spec_string(NM_DEVICE_OLPC_MESH_COMPANION, "", diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c index fb987600..a8ea2ed7 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -15,16 +15,16 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" #include "nm-act-request.h" -#include "nm-core-internal.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-ip4-config.h" #include "nm-manager.h" #include "nm-manager.h" #include "nm-setting-wifi-p2p.h" #include "nm-utils.h" #include "nm-wifi-p2p-peer.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" #include "settings/nm-settings.h" #define _NMLOG_DEVICE_TYPE NMDeviceWifiP2P @@ -1149,7 +1149,6 @@ static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Peers", "ao", NM_DEVICE_WIFI_P2P_PEERS), ), ), - .legacy_property_changed = FALSE, }; /*****************************************************************************/ diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 042d4887..fca2fde5 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -12,11 +12,11 @@ #include <unistd.h> #include <linux/if_ether.h> -#include "nm-glib-aux/nm-ref-string.h" -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-c-list.h" #include "nm-device-wifi-p2p.h" #include "nm-wifi-ap.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "devices/nm-device.h" #include "devices/nm-device-private.h" #include "nm-dbus-manager.h" @@ -33,13 +33,13 @@ #include "nm-setting-ip4-config.h" #include "nm-ip4-config.h" #include "nm-setting-ip6-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-auth-utils.h" #include "settings/nm-settings-connection.h" #include "settings/nm-settings.h" #include "nm-wifi-utils.h" #include "nm-wifi-common.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-config.h" #define _NMLOG_DEVICE_TYPE NMDeviceWifi @@ -114,11 +114,11 @@ typedef struct { guint wps_timeout_id; guint sup_timeout_id; /* supplicant association timeout */ - NMDeviceWifiCapabilities capabilities; - NMSettingWirelessWakeOnWLan wowlan_restore; + _NMDeviceWifiCapabilities capabilities; + _NMSettingWirelessWakeOnWLan wowlan_restore; NMDeviceWifiP2P *p2p_device; - NM80211Mode mode; + _NM80211Mode mode; guint32 failed_iface_count; gint32 hw_addr_scan_expire; @@ -487,7 +487,7 @@ _scan_notify_allowed(NMDeviceWifi *self, NMTernary do_kickoff) if (!c_list_is_empty(&priv->scanning_prohibited_lst_head)) { /* something prohibits scanning. */ - } else if (NM_IN_SET(priv->mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_AP)) { + } else if (NM_IN_SET(priv->mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_AP)) { /* Don't scan when a an AP or Ad-Hoc connection is active as it will * disrupt connected clients or peers. */ } else if (NM_IN_SET(state, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_FAILED)) { @@ -678,7 +678,7 @@ update_seen_bssids_cache(NMDeviceWifi *self, NMWifiAP *ap) return; /* Don't cache the BSSID for Ad-Hoc APs */ - if (nm_wifi_ap_get_mode(ap) != NM_802_11_MODE_INFRA) + if (nm_wifi_ap_get_mode(ap) != _NM_802_11_MODE_INFRA) return; if (nm_device_get_state(NM_DEVICE(self)) == NM_DEVICE_STATE_ACTIVATED @@ -712,10 +712,11 @@ set_current_ap(NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available_ priv->current_ap = NULL; if (old_ap) { - NM80211Mode mode = nm_wifi_ap_get_mode(old_ap); + _NM80211Mode mode = nm_wifi_ap_get_mode(old_ap); /* Remove any AP from the internal list if it was created by NM or isn't known to the supplicant */ - if (NM_IN_SET(mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_AP) || nm_wifi_ap_get_fake(old_ap)) + if (NM_IN_SET(mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_AP) + || nm_wifi_ap_get_fake(old_ap)) ap_add_remove(self, FALSE, old_ap, recheck_available_connections); g_object_unref(old_ap); } @@ -750,7 +751,7 @@ periodic_update(NMDeviceWifi *self) return; } - if (priv->mode == NM_802_11_MODE_AP) { + if (priv->mode == _NM_802_11_MODE_AP) { /* In AP mode we currently have nothing to do. */ return; } @@ -845,14 +846,14 @@ remove_all_aps(NMDeviceWifi *self) static gboolean wake_on_wlan_restore(NMDeviceWifi *self) { - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWirelessWakeOnWLan w; + NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); + _NMSettingWirelessWakeOnWLan w; w = priv->wowlan_restore; - if (w == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) + if (w == _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) return TRUE; - priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; + priv->wowlan_restore = _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; return nm_platform_wifi_set_wake_on_wlan(NM_PLATFORM_GET, nm_device_get_ifindex(NM_DEVICE(self)), w); @@ -937,14 +938,14 @@ deactivate(NMDevice *device) * (usually older ones) don't scan well in adhoc mode. */ if (nm_platform_wifi_get_mode(nm_device_get_platform(device), ifindex) - != NM_802_11_MODE_INFRA) { + != _NM_802_11_MODE_INFRA) { nm_device_take_down(NM_DEVICE(self), TRUE); - nm_platform_wifi_set_mode(nm_device_get_platform(device), ifindex, NM_802_11_MODE_INFRA); + nm_platform_wifi_set_mode(nm_device_get_platform(device), ifindex, _NM_802_11_MODE_INFRA); nm_device_bring_up(NM_DEVICE(self), TRUE, NULL); } - if (priv->mode != NM_802_11_MODE_INFRA) { - priv->mode = NM_802_11_MODE_INFRA; + if (priv->mode != _NM_802_11_MODE_INFRA) { + priv->mode = _NM_802_11_MODE_INFRA; _notify(self, PROP_MODE); } @@ -1010,14 +1011,14 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * /* Early exit if supplicant or device doesn't support requested mode */ mode = nm_setting_wireless_get_mode(s_wireless); if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_ADHOC)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "the device does not support Ad-Hoc networks"); return FALSE; } } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_AP) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_AP)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "the device does not support Access Point mode"); @@ -1034,7 +1035,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * } } } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_MESH)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_MESH)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "the device does not support Mesh mode"); @@ -1381,8 +1382,8 @@ _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset) now = nm_utils_get_monotonic_timestamp_sec(); if (now >= priv->hw_addr_scan_expire) { - gs_free char *generate_mac_address_mask = NULL; - gs_free char *hw_addr_scan = NULL; + gs_free char *hw_addr_scan = NULL; + const char * generate_mac_address_mask; /* the random MAC address for scanning expires after a while. * @@ -1433,7 +1434,7 @@ ssids_options_to_ptrarray(GVariant *value, GError **error) v = g_variant_get_child_value(value, i); bytes = g_variant_get_fixed_array(v, &len, sizeof(guint8)); - if (len > 32) { + if (len > NM_IW_ESSID_MAX_SIZE) { g_set_error(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_ARGUMENT, @@ -1822,7 +1823,7 @@ _scan_kickoff(NMDeviceWifi *self) strv = g_new(char *, ssids->len + 1u); for (i = 0; i < ssids->len; i++) - strv[i] = _nm_utils_ssid_to_string(ssids->pdata[i]); + strv[i] = _nm_utils_ssid_to_string_gbytes(ssids->pdata[i]); strv[i] = NULL; nm_assert(ssids->len > 0); @@ -1884,13 +1885,13 @@ ap_list_dump(gpointer user_data) _LOGD(LOGD_WIFI_SCAN, "APs: [now:%u.%03u, last:%s]", - (guint)(now_msec / NM_UTILS_MSEC_PER_SEC), - (guint)(now_msec % NM_UTILS_MSEC_PER_SEC), + (guint) (now_msec / NM_UTILS_MSEC_PER_SEC), + (guint) (now_msec % NM_UTILS_MSEC_PER_SEC), priv->scan_last_complete_msec > 0 ? nm_sprintf_buf(str_buf, "%u.%03u", - (guint)(priv->scan_last_complete_msec / NM_UTILS_MSEC_PER_SEC), - (guint)(priv->scan_last_complete_msec % NM_UTILS_MSEC_PER_SEC)) + (guint) (priv->scan_last_complete_msec / NM_UTILS_MSEC_PER_SEC), + (guint) (priv->scan_last_complete_msec % NM_UTILS_MSEC_PER_SEC)) : "-1"); c_list_for_each_entry (ap, &priv->aps_lst_head, aps_lst) _ap_dump(self, LOGL_DEBUG, ap, "dump", now_msec); @@ -1986,19 +1987,19 @@ supplicant_iface_bss_changed_cb(NMSupplicantInterface *iface, /* Let the manager try to fill in the SSID from seen-bssids lists */ ssid = nm_wifi_ap_get_ssid(ap); - if (!ssid || _nm_utils_is_empty_ssid(ssid)) { + if (!ssid || _nm_utils_is_empty_ssid_gbytes(ssid)) { /* Try to fill the SSID from the AP database */ try_fill_ssid_for_hidden_ap(self, ap); ssid = nm_wifi_ap_get_ssid(ap); - if (ssid && !_nm_utils_is_empty_ssid(ssid)) { + if (ssid && !_nm_utils_is_empty_ssid_gbytes(ssid)) { gs_free char *s = NULL; /* Yay, matched it, no longer treat as hidden */ _LOGD(LOGD_WIFI, "matched hidden AP %s => %s", nm_wifi_ap_get_address(ap), - (s = _nm_utils_ssid_to_string(ssid))); + (s = _nm_utils_ssid_to_string_gbytes(ssid))); } else { /* Didn't have an entry for this AP in the database */ _LOGD(LOGD_WIFI, "failed to match hidden AP %s", nm_wifi_ap_get_address(ap)); @@ -2481,9 +2482,9 @@ supplicant_iface_state(NMDeviceWifi * self, _LOGI(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. %s %s", - priv->mode == NM_802_11_MODE_AP ? "Started Wi-Fi Hotspot" - : "Connected to wireless network", - (ssid_str = _nm_utils_ssid_to_string(ssid))); + priv->mode == _NM_802_11_MODE_AP ? "Started Wi-Fi Hotspot" + : "Connected to wireless network", + (ssid_str = _nm_utils_ssid_to_string_gbytes(ssid))); nm_device_activate_schedule_stage3_ip_config_start(device); } else if (devstate == NM_DEVICE_STATE_ACTIVATED) periodic_update(self); @@ -2565,6 +2566,7 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); NMRefString * current_bss; NMWifiAP * new_ap = NULL; + NMActRequest * req; current_bss = nm_supplicant_interface_get_current_bss(iface); if (current_bss) @@ -2598,9 +2600,9 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, _LOGD(LOGD_WIFI, "roamed from BSSID %s (%s) to %s (%s)", old_bssid ?: "(none)", - (old_ssid_s = _nm_utils_ssid_to_string(old_ssid)), + (old_ssid_s = _nm_utils_ssid_to_string_gbytes(old_ssid)), new_bssid ?: "(none)", - (new_ssid_s = _nm_utils_ssid_to_string(new_ssid))); + (new_ssid_s = _nm_utils_ssid_to_string_gbytes(new_ssid))); if (new_bssid) { /* The new AP could be in a different layer 3 network @@ -2612,6 +2614,13 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, } set_current_ap(self, new_ap, TRUE); + + req = nm_device_get_act_request(NM_DEVICE(self)); + if (req) { + nm_active_connection_set_specific_object( + NM_ACTIVE_CONNECTION(req), + new_ap ? nm_dbus_object_get_path(NM_DBUS_OBJECT(new_ap)) : NULL); + } } } @@ -2782,21 +2791,21 @@ supplicant_connection_timeout_cb(gpointer user_data) connection = nm_act_request_get_applied_connection(req); g_assert(connection); - if (NM_IN_SET(priv->mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_MESH, NM_802_11_MODE_AP)) { + if (NM_IN_SET(priv->mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_MESH, _NM_802_11_MODE_AP)) { /* In Ad-Hoc and AP modes there's nothing to check the encryption key * (if any), so supplicant timeouts here are almost certainly the wifi * driver being really stupid. */ _LOGW(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) %s network creation took too long, failing activation", - priv->mode == NM_802_11_MODE_ADHOC ? "Ad-Hoc" : "Hotspot"); + priv->mode == _NM_802_11_MODE_ADHOC ? "Ad-Hoc" : "Hotspot"); nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); return FALSE; } - g_assert(priv->mode == NM_802_11_MODE_INFRA); + g_assert(priv->mode == _NM_802_11_MODE_INFRA); if (priv->ssid_found && nm_connection_get_setting_wireless_security(connection)) { guint64 timestamp = 0; @@ -2948,9 +2957,10 @@ error: static gboolean wake_on_wlan_enable(NMDeviceWifi *self) { - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWirelessWakeOnWLan wowl; - NMSettingWireless * s_wireless; + NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); + NMSettingWirelessWakeOnWLan wowl; + _NMSettingWirelessWakeOnWLan wowl2; + NMSettingWireless * s_wireless; s_wireless = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_WIRELESS); if (s_wireless) { @@ -2982,9 +2992,11 @@ wake_on_wlan_enable(NMDeviceWifi *self) goto found; wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; + found: - if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) { - priv->wowlan_restore = wowl; + wowl2 = _NM_SETTING_WIRELESS_WAKE_ON_WLAN_CAST(wowl); + if (wowl2 == _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) { + priv->wowlan_restore = wowl2; return TRUE; } @@ -2993,7 +3005,7 @@ found: return nm_platform_wifi_set_wake_on_wlan(NM_PLATFORM_GET, nm_device_get_ifindex(NM_DEVICE(self)), - wowl); + wowl2); } static NMActStageReturn @@ -3022,16 +3034,16 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) mode = nm_setting_wireless_get_mode(s_wireless); if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_INFRA) == 0) - priv->mode = NM_802_11_MODE_INFRA; + priv->mode = _NM_802_11_MODE_INFRA; else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0) - priv->mode = NM_802_11_MODE_ADHOC; + priv->mode = _NM_802_11_MODE_ADHOC; else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_AP) == 0) { - priv->mode = NM_802_11_MODE_AP; + priv->mode = _NM_802_11_MODE_AP; /* Scanning not done in AP mode; clear the scan list */ remove_all_aps(self); } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) - priv->mode = NM_802_11_MODE_MESH; + priv->mode = _NM_802_11_MODE_MESH; _notify(self, PROP_MODE); /* expire the temporary MAC address used during scanning */ @@ -3044,7 +3056,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) } /* AP and Mesh modes never use a specific object or existing scanned AP */ - if (!NM_IN_SET(priv->mode, NM_802_11_MODE_AP, NM_802_11_MODE_MESH)) { + if (!NM_IN_SET(priv->mode, _NM_802_11_MODE_AP, _NM_802_11_MODE_MESH)) { ap_path = nm_active_connection_get_specific_object(NM_ACTIVE_CONNECTION(req)); ap = ap_path ? nm_wifi_ap_lookup_for_device(NM_DEVICE(self), ap_path) : NULL; } @@ -3146,7 +3158,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) NMDeviceWifi * self = NM_DEVICE_WIFI(device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); gs_unref_object NMSupplicantConfig *config = NULL; - NM80211Mode ap_mode; + _NM80211Mode ap_mode; NMActRequest * req; NMWifiAP * ap; NMConnection * connection; @@ -3213,10 +3225,11 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) * if the user didn't specify one and we didn't find an AP that matched * the connection, just pick a frequency the device supports. */ - if (NM_IN_SET(ap_mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_MESH) || nm_wifi_ap_is_hotspot(ap)) + if (NM_IN_SET(ap_mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_MESH) + || nm_wifi_ap_is_hotspot(ap)) ensure_hotspot_frequency(self, s_wireless, ap); - if (ap_mode == NM_802_11_MODE_INFRA) + if (ap_mode == _NM_802_11_MODE_INFRA) set_powersave(device); /* Build up the supplicant configuration */ @@ -3333,7 +3346,7 @@ act_stage4_ip_config_timeout(NMDevice * device, s_ip = nm_connection_get_setting_ip_config(connection, addr_family); may_fail = nm_setting_ip_config_get_may_fail(s_ip); - if (priv->mode == NM_802_11_MODE_AP) + if (priv->mode == _NM_802_11_MODE_AP) goto call_parent; if (may_fail || !is_static_wep(connection)) { @@ -3686,8 +3699,8 @@ nm_device_wifi_init(NMDeviceWifi *self) priv->scan_last_request_started_at_msec = G_MININT64; priv->hidden_probe_scan_warn = TRUE; - priv->mode = NM_802_11_MODE_INFRA; - priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; + priv->mode = _NM_802_11_MODE_INFRA; + priv->wowlan_restore = _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; } static void @@ -3698,7 +3711,7 @@ constructed(GObject *object) G_OBJECT_CLASS(nm_device_wifi_parent_class)->constructed(object); - if (priv->capabilities & NM_WIFI_DEVICE_CAP_AP) + if (priv->capabilities & _NM_WIFI_DEVICE_CAP_AP) _LOGI(LOGD_PLATFORM | LOGD_WIFI, "driver supports Access Point (AP) mode"); /* Connect to the supplicant manager */ @@ -3706,7 +3719,7 @@ constructed(GObject *object) } NMDevice * -nm_device_wifi_new(const char *iface, NMDeviceWifiCapabilities capabilities) +nm_device_wifi_new(const char *iface, _NMDeviceWifiCapabilities capabilities) { return g_object_new(NM_TYPE_DEVICE_WIFI, NM_DEVICE_IFACE, @@ -3814,9 +3827,9 @@ nm_device_wifi_class_init(NMDeviceWifiClass *klass) obj_properties[PROP_MODE] = g_param_spec_uint(NM_DEVICE_WIFI_MODE, "", "", - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_AP, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_UNKNOWN, + _NM_802_11_MODE_AP, + _NM_802_11_MODE_INFRA, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_BITRATE] = g_param_spec_uint(NM_DEVICE_WIFI_BITRATE, @@ -3847,7 +3860,7 @@ nm_device_wifi_class_init(NMDeviceWifiClass *klass) "", 0, G_MAXUINT32, - NM_WIFI_DEVICE_CAP_NONE, + _NM_WIFI_DEVICE_CAP_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_SCANNING] = g_param_spec_boolean(NM_DEVICE_WIFI_SCANNING, diff --git a/src/core/devices/wifi/nm-device-wifi.h b/src/core/devices/wifi/nm-device-wifi.h index d9e9038c..c7ff1a14 100644 --- a/src/core/devices/wifi/nm-device-wifi.h +++ b/src/core/devices/wifi/nm-device-wifi.h @@ -33,7 +33,7 @@ typedef struct _NMDeviceWifiClass NMDeviceWifiClass; GType nm_device_wifi_get_type(void); -NMDevice *nm_device_wifi_new(const char *iface, NMDeviceWifiCapabilities capabilities); +NMDevice *nm_device_wifi_new(const char *iface, _NMDeviceWifiCapabilities capabilities); const CList *_nm_device_wifi_get_aps(NMDeviceWifi *self); diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index b4b019d3..56386c57 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -8,14 +8,20 @@ #include "nm-iwd-manager.h" #include <net/if.h> +#include <glib/gstdio.h> +#include <errno.h> +#include <sys/stat.h> -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-manager.h" #include "nm-device-iwd.h" #include "nm-wifi-utils.h" -#include "nm-glib-aux/nm-random-utils.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-random-utils.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "settings/nm-settings.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/nm-dbus-compat.h" +#include "nm-config.h" /*****************************************************************************/ @@ -28,6 +34,7 @@ typedef struct { typedef struct { GDBusProxy * known_network; NMSettingsConnection *mirror_connection; + const KnownNetworkId *id; } KnownNetworkData; typedef struct { @@ -40,6 +47,8 @@ typedef struct { char * agent_path; GHashTable * known_networks; NMDeviceIwd * last_agent_call_device; + char * last_state_dir; + char * warned_state_dir; } NMIwdManagerPrivate; struct _NMIwdManager { @@ -419,25 +428,94 @@ known_network_update_cb(GObject *source, GAsyncResult *res, gpointer user_data) variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); if (!variant) { nm_log_warn(LOGD_WIFI, - "Updating %s on IWD known network %s failed: %s", + "iwd: updating %s on IWD known network %s failed: %s", (const char *) user_data, g_dbus_proxy_get_object_path(G_DBUS_PROXY(source)), error->message); } } +static gboolean +iwd_config_write(GKeyFile * config, + const char * filepath, + const struct timespec *mtime, + GError ** error) +{ + gsize length; + gs_free char * data = g_key_file_to_data(config, &length, NULL); + struct timespec times[2] = {{.tv_nsec = UTIME_OMIT}, *mtime}; + + /* Atomically write or replace the file with the right permission bits + * and timestamps set. We rely on the temporary file created by + * nm_utils_file_set_contents having only upper-case letters and digits + * in the last few filename characters -- it cannot end in .open, .psk + * or .8021x. + */ + return nm_utils_file_set_contents(filepath, data, length, 0600, times, NULL, error); +} + +static const char * +get_config_path(NMIwdManager *self) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + const char * path; + + path = nm_config_data_get_iwd_config_path(NM_CONFIG_GET_DATA); + if (path && path[0] == '\0') { + nm_clear_g_free(&priv->warned_state_dir); + return NULL; + } + + if (!path || nm_streq(path, "auto")) { + path = priv->last_state_dir; + if (!path) { + nm_clear_g_free(&priv->warned_state_dir); + return NULL; + } + } + + if (priv->warned_state_dir && !nm_streq(priv->warned_state_dir, path)) + nm_clear_g_free(&priv->warned_state_dir); + + if (path && (path[0] != '/' || !g_file_test(path, G_FILE_TEST_IS_DIR))) { + if (!priv->warned_state_dir) { + priv->warned_state_dir = g_strdup(path); + _LOGW("IWD StateDirectory '%s' not accessible", priv->warned_state_dir); + } + return NULL; + } + + return path; +} + static void -sett_conn_changed(NMSettingsConnection *sett_conn, guint update_reason, KnownNetworkData *data) +sett_conn_changed(NMSettingsConnection * sett_conn, + guint update_reason, + const KnownNetworkData *data) { NMSettingsConnectionIntFlags flags; - NMConnection * conn = nm_settings_connection_get_connection(sett_conn); - NMSettingConnection * s_conn = nm_connection_get_setting_connection(conn); - gboolean nm_autoconnectable = nm_setting_connection_get_autoconnect(s_conn); - gboolean iwd_autoconnectable = get_property_bool(data->known_network, "AutoConnect", TRUE); + NMConnection * conn = nm_settings_connection_get_connection(sett_conn); + NMSettingConnection * s_conn = nm_connection_get_setting_connection(conn); + NMSettingWireless * s_wifi = nm_connection_get_setting_wireless(conn); + nm_auto_unref_keyfile GKeyFile *iwd_config = NULL; + const char * iwd_dir; + gs_free char * filename = NULL; + gs_free char * full_path = NULL; + gs_free_error GError *error = NULL; + NMIwdNetworkSecurity security; + GBytes * ssid; + const guint8 * ssid_data; + gsize ssid_len; + gboolean removed; + GStatBuf statbuf; + gboolean have_mtime; nm_assert(sett_conn == data->mirror_connection); - if (iwd_autoconnectable == nm_autoconnectable) + if (!NM_FLAGS_ANY(update_reason, + NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET + | NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_SYSTEM_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS)) return; /* If this is a generated connection it may be ourselves updating it */ @@ -445,21 +523,131 @@ sett_conn_changed(NMSettingsConnection *sett_conn, guint update_reason, KnownNet if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) return; + iwd_dir = get_config_path(nm_iwd_manager_get()); + if (!iwd_dir) { + gboolean nm_autoconnectable = nm_setting_connection_get_autoconnect(s_conn); + gboolean iwd_autoconnectable = get_property_bool(data->known_network, "AutoConnect", TRUE); + + if (iwd_autoconnectable != nm_autoconnectable) { + nm_log_dbg(LOGD_WIFI, + "iwd: updating AutoConnect on known network at %s based on connection %s", + g_dbus_proxy_get_object_path(data->known_network), + nm_settings_connection_get_id(data->mirror_connection)); + g_dbus_proxy_call(data->known_network, + DBUS_INTERFACE_PROPERTIES ".Set", + g_variant_new("(ssv)", + NM_IWD_KNOWN_NETWORK_INTERFACE, + "AutoConnect", + g_variant_new_boolean(nm_autoconnectable)), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + known_network_update_cb, + "AutoConnect"); + } + + return; + } + + /* If the SSID and the security type in the NMSettingsConnection haven't + * changed, we just need to overwrite the original IWD config file. + * Otherwise we need to call Forget on the original KnownNetwork or + * remove its file. IWD will have to delete one D-Bus object and + * create another anyway because the SSID and security type are in the + * D-Bus object path, so no point renaming the file. + */ + ssid = nm_setting_wireless_get_ssid(s_wifi); + ssid_data = ssid ? g_bytes_get_data(ssid, &ssid_len) : NULL; + removed = FALSE; + have_mtime = FALSE; + + if (!nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &security) + || security != data->id->security || !ssid_data || ssid_len != strlen(data->id->name) + || memcmp(ssid_data, data->id->name, ssid_len)) { + gs_free char *orig_filename = + nm_wifi_utils_get_iwd_config_filename(data->id->name, -1, data->id->security); + gs_free char *orig_full_path = g_strdup_printf("%s/%s", iwd_dir, orig_filename); + + if (g_stat(orig_full_path, &statbuf) == 0) + have_mtime = TRUE; + + if (g_remove(orig_full_path) == 0) + nm_log_dbg(LOGD_WIFI, "iwd: profile at %s removed", orig_full_path); + else if (errno != ENOENT) + nm_log_dbg(LOGD_WIFI, + "iwd: profile at %s not removed: %s (%i)", + orig_full_path, + strerror(errno), + errno); + + removed = TRUE; + } + + if (!nm_streq(nm_settings_connection_get_connection_type(sett_conn), "802-11-wireless") + || !s_wifi) + return; + + /* If the connection has any permissions other than the default we don't + * want to save it as an IWD profile. IWD will make it available for + * everybody to attempt a connection, remove, or toggle "autoconnectable". + */ + if (s_conn && nm_setting_connection_get_num_permissions(s_conn)) { + nm_log_dbg( + LOGD_WIFI, + "iwd: changed Wi-Fi connection %s not mirrored as IWD profile because of non-default " + "permissions", + nm_settings_connection_get_id(sett_conn)); + return; + } + + iwd_config = nm_wifi_utils_connection_to_iwd_config(conn, &filename, &error); + if (!iwd_config) { + /* The error message here is not translated and it only goes in + * the logs. + */ + nm_log_dbg(LOGD_WIFI, + "iwd: changed Wi-Fi connection %s not mirrored as IWD profile: %s", + nm_settings_connection_get_id(sett_conn), + error->message); + return; + } + + full_path = g_strdup_printf("%s/%s", iwd_dir, filename); + if (removed && g_file_test(full_path, G_FILE_TEST_EXISTS)) { + nm_log_dbg(LOGD_WIFI, + "iwd: changed Wi-Fi connection %s not mirrored as IWD profile because %s " + "already exists", + nm_settings_connection_get_id(sett_conn), + full_path); + return; + } + + if (!removed && g_stat(full_path, &statbuf) == 0) + have_mtime = TRUE; + + /* If modifying an existing network try to preserve the file mtime, + * otherwise use a small non-zero timespec value to signal that the + * network is autoconnectable (according to its AutoConnect value) + * but hasn't recently been connected to and thus shouldn't be + * prioritized by autoconnect. + */ + if (!have_mtime) { + statbuf.st_mtim.tv_sec = 1; + statbuf.st_mtim.tv_nsec = 0; + } + + if (!iwd_config_write(iwd_config, full_path, &statbuf.st_mtim, &error)) { + nm_log_dbg(LOGD_WIFI, + "iwd: changed Wi-Fi connection %s not mirrored as IWD profile: save error: %s", + nm_settings_connection_get_id(sett_conn), + error->message); + return; + } + nm_log_dbg(LOGD_WIFI, - "Updating AutoConnect on known network at %s based on connection %s", - g_dbus_proxy_get_object_path(data->known_network), - nm_settings_connection_get_id(data->mirror_connection)); - g_dbus_proxy_call(data->known_network, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new("(ssv)", - NM_IWD_KNOWN_NETWORK_INTERFACE, - "AutoConnect", - g_variant_new_boolean(nm_autoconnectable)), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - known_network_update_cb, - "AutoConnect"); + "iwd: changed Wi-Fi connection %s mirrored as IWD profile %s", + nm_settings_connection_get_id(sett_conn), + full_path); } /* Look up an existing NMSettingsConnection for a network that has been @@ -590,8 +778,10 @@ mirror_connection(NMIwdManager * self, NULL); g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_HIDDEN, hidden, NULL); } else { - KnownNetworkData data = {known_network, settings_connection}; - sett_conn_changed(settings_connection, 0, &data); + KnownNetworkData data = {known_network, settings_connection, id}; + sett_conn_changed(settings_connection, + NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET, + &data); } } @@ -621,7 +811,7 @@ mirror_connection(NMIwdManager * self, NM_SETTING_CONNECTION_ID, id->name, NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_buf(uuid), + nm_uuid_generate_random_str_arr(uuid), NM_SETTING_CONNECTION_AUTOCONNECT, autoconnectable, NULL); @@ -779,6 +969,7 @@ interface_added(GDBusObjectManager *object_manager, } else { data = g_slice_new0(KnownNetworkData); data->known_network = g_object_ref(proxy); + data->id = id; g_hash_table_insert(priv->known_networks, id, data); } @@ -907,6 +1098,9 @@ connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpoint const guint8 * ssid_bytes; gsize ssid_len; NMSettingsConnection *new_mirror_conn; + const char * iwd_dir; + gs_free char * filename = NULL; + gs_free char * full_path = NULL; if (!nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &id.security)) return; @@ -923,8 +1117,12 @@ connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpoint ssid_buf[ssid_len] = '\0'; id.name = ssid_buf; data = g_hash_table_lookup(priv->known_networks, &id); - if (!data) - return; + if (!data) { + if (!g_utf8_validate((const char *) ssid_bytes, ssid_len, NULL)) + return; + + goto try_delete_file; + } if (data->mirror_connection != sett_conn) return; @@ -941,7 +1139,7 @@ connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpoint } if (!priv->running) - return; + goto try_delete_file; g_dbus_proxy_call(data->known_network, "Forget", @@ -951,6 +1149,91 @@ connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpoint NULL, NULL, NULL); + return; + +try_delete_file: + if (mirror_connection(self, &id, FALSE, NULL)) + return; + + iwd_dir = get_config_path(self); + if (!iwd_dir) + return; + + filename = nm_wifi_utils_get_iwd_config_filename(id.name, ssid_len, id.security); + full_path = g_strdup_printf("%s/%s", iwd_dir, filename); + if (g_remove(full_path) == 0) + _LOGD("IWD profile at %s removed", full_path); + else if (errno != ENOENT) + _LOGD("IWD profile at %s not removed: %s (%i)", full_path, strerror(errno), errno); +} + +static void +connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) +{ + NMIwdManager * self = user_data; + NMConnection * conn = nm_settings_connection_get_connection(sett_conn); + NMSettingConnection *s_conn = nm_connection_get_setting_connection(conn); + const char * iwd_dir; + gs_free char * filename = NULL; + gs_free char * full_path = NULL; + gs_free_error GError *error = NULL; + nm_auto_unref_keyfile GKeyFile *iwd_config = NULL; + NMSettingsConnectionIntFlags flags; + + if (!nm_streq(nm_settings_connection_get_connection_type(sett_conn), "802-11-wireless")) + return; + + iwd_dir = get_config_path(self); + if (!iwd_dir) + return; + + /* If this is a generated connection it may be ourselves creating it and + * directly assigning it to a KnownNetwork's .mirror_connection. + */ + flags = nm_settings_connection_get_flags(sett_conn); + if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + return; + + /* If the connection has any permissions other than the default we don't + * want to save it as an IWD profile. IWD will make it available for + * everybody to attempt a connection, remove, or toggle "autoconnectable". + */ + if (s_conn && nm_setting_connection_get_num_permissions(s_conn)) { + _LOGD("New Wi-Fi connection %s not mirrored as IWD profile because of non-default " + "permissions", + nm_settings_connection_get_id(sett_conn)); + return; + } + + iwd_config = nm_wifi_utils_connection_to_iwd_config(conn, &filename, &error); + if (!iwd_config) { + /* The error message here is not translated and it only goes in + * the logs. + */ + _LOGD("New Wi-Fi connection %s not mirrored as IWD profile: %s", + nm_settings_connection_get_id(sett_conn), + error->message); + return; + } + + full_path = g_strdup_printf("%s/%s", iwd_dir, filename); + if (g_file_test(full_path, G_FILE_TEST_EXISTS)) { + _LOGD("New Wi-Fi connection %s not mirrored as IWD profile because %s already exists", + nm_settings_connection_get_id(sett_conn), + full_path); + return; + } + + if (!g_key_file_save_to_file(iwd_config, full_path, &error)) { + _LOGD("New Wi-Fi connection %s not mirrored as IWD profile: save error: %s", + nm_settings_connection_get_id(sett_conn), + error->message); + return; + } + + _LOGD("New Wi-Fi connection %s mirrored as IWD profile %s", + nm_settings_connection_get_id(sett_conn), + full_path); } static gboolean @@ -1115,10 +1398,11 @@ device_removed(NMManager *manager, NMDevice *device, gpointer user_data) static int object_compare_interfaces(gconstpointer a, gconstpointer b) { - static const char *interface_order[] = { + static const char *const interface_order[] = { NM_IWD_KNOWN_NETWORK_INTERFACE, NM_IWD_NETWORK_INTERFACE, NM_IWD_DEVICE_INTERFACE, + NULL, }; int rank_a = G_N_ELEMENTS(interface_order); int rank_b = G_N_ELEMENTS(interface_order); @@ -1145,6 +1429,56 @@ object_compare_interfaces(gconstpointer a, gconstpointer b) } static void +get_daemon_info_cb(GObject *source, GAsyncResult *res, gpointer user_data) +{ + NMIwdManager * self = user_data; + NMIwdManagerPrivate *priv; + gs_unref_variant GVariant *properties = NULL; + gs_free_error GError *error = NULL; + GVariantIter * properties_iter; + const char * key; + GVariant * value; + + properties = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); + if (!properties) { + if (nm_utils_error_is_cancelled(error)) + return; + + nm_log_warn(LOGD_WIFI, "iwd: Daemon.GetInfo() failed: %s", error->message); + return; + } + + priv = NM_IWD_MANAGER_GET_PRIVATE(self); + + if (!g_variant_is_of_type(properties, G_VARIANT_TYPE("(a{sv})"))) { + _LOGE("Daemon.GetInfo returned type %s instead of (a{sv})", + g_variant_get_type_string(properties)); + return; + } + + g_variant_get(properties, "(a{sv})", &properties_iter); + + while (g_variant_iter_next(properties_iter, "{&sv}", &key, &value)) { + if (nm_streq(key, "StateDirectory")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { + _LOGE("Daemon.GetInfo property %s is typed '%s' instead of 's'", + key, + g_variant_get_type_string(value)); + goto next; + } + + nm_clear_g_free(&priv->last_state_dir); + priv->last_state_dir = g_variant_dup_string(value, NULL); + } + +next: + g_variant_unref(value); + } + + g_variant_iter_free(properties_iter); +} + +static void got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) { NMIwdManager * self = user_data; @@ -1181,7 +1515,8 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) } if (_om_has_name_owner(object_manager)) { - GList *objects, *iter; + GList * objects, *iter; + gs_unref_object GDBusInterface *daemon = NULL; priv->running = true; @@ -1207,6 +1542,19 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) if (priv->agent_id) register_agent(self); + + daemon = g_dbus_object_manager_get_interface(object_manager, + "/net/connman/iwd", /* IWD 1.15+ */ + NM_IWD_DAEMON_INTERFACE); + if (daemon) + g_dbus_proxy_call(G_DBUS_PROXY(daemon), + "GetInfo", + g_variant_new("()"), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_daemon_info_cb, + self); } } @@ -1304,11 +1652,31 @@ nm_iwd_manager_init(NMIwdManager *self) g_signal_connect(priv->manager, NM_MANAGER_DEVICE_ADDED, G_CALLBACK(device_added), self); g_signal_connect(priv->manager, NM_MANAGER_DEVICE_REMOVED, G_CALLBACK(device_removed), self); + /* The current logic is that we track all creations and removals but + * for modifications we only listen to those connections that are + * currently a KnownNetwork's mirror_connection. There may be multiple + * NMSettingsConnections referring to the same SSID+Security type tuple + * so to the same KnownNetwork. So to make connection profile editing + * work at least for the simple cases, we track one NMSettingsConnection + * out of those, and we map its changes to the IWD KnownNetwork. + * + * When an NMSettingsConnection is created by a user for a completely + * new network and the settings are compatible with IWD, we create an + * IWD KnownNetwork config file for it. IWD will notice that and a + * KnownNetwork objects pops up on D-Bus. We look up a suitable + * mirror_connection for it and only then subscribe to modification + * signals. There are various different ways that this could be done, + * it's not clear which one's the best. + */ priv->settings = g_object_ref(NM_SETTINGS_GET); g_signal_connect(priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, G_CALLBACK(connection_removed), self); + g_signal_connect(priv->settings, + NM_SETTINGS_SIGNAL_CONNECTION_ADDED, + G_CALLBACK(connection_added), + self); priv->cancellable = g_cancellable_new(); @@ -1347,6 +1715,9 @@ dispose(GObject *object) priv->last_agent_call_device = NULL; + nm_clear_g_free(&priv->last_state_dir); + nm_clear_g_free(&priv->warned_state_dir); + G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object); } diff --git a/src/core/devices/wifi/nm-iwd-manager.h b/src/core/devices/wifi/nm-iwd-manager.h index 466f67c7..e794e661 100644 --- a/src/core/devices/wifi/nm-iwd-manager.h +++ b/src/core/devices/wifi/nm-iwd-manager.h @@ -13,6 +13,7 @@ #define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM #define NM_IWD_SERVICE "net.connman.iwd" +#define NM_IWD_DAEMON_INTERFACE "net.connman.iwd.Daemon" #define NM_IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager" #define NM_IWD_WIPHY_INTERFACE "net.connman.iwd.Adapter" #define NM_IWD_DEVICE_INTERFACE "net.connman.iwd.Device" diff --git a/src/core/devices/wifi/nm-wifi-ap.c b/src/core/devices/wifi/nm-wifi-ap.c index 08fa10ec..20ed6833 100644 --- a/src/core/devices/wifi/nm-wifi-ap.c +++ b/src/core/devices/wifi/nm-wifi-ap.c @@ -13,13 +13,13 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-setting-wireless.h" #include "nm-utils.h" #include "nm-wifi-utils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "supplicant/nm-supplicant-interface.h" #define PROTO_WPA "wpa" @@ -41,12 +41,12 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMWifiAP, struct _NMWifiAPPrivate { /* Scanned or cached values */ - GBytes * ssid; - char * address; - NM80211Mode mode; - guint8 strength; - guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */ - guint32 max_bitrate; /* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */ + GBytes * ssid; + char * address; + _NM80211Mode mode; + guint8 strength; + guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */ + guint32 max_bitrate; /* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */ gint64 last_seen_msec; /* Timestamp when the AP was seen lastly (in nm_utils_get_monotonic_timestamp_*() scale). @@ -98,7 +98,7 @@ nm_wifi_ap_set_ssid(NMWifiAP *ap, GBytes *ssid) } l = g_bytes_get_size(ssid); - if (l == 0 || l > 32) + if (l == 0 || l > NM_IW_ESSID_MAX_SIZE) g_return_val_if_reached(FALSE); priv = NM_WIFI_AP_GET_PRIVATE(ap); @@ -191,24 +191,24 @@ nm_wifi_ap_set_address(NMWifiAP *ap, const char *addr) return nm_wifi_ap_set_address_bin(ap, &addr_buf); } -NM80211Mode +_NM80211Mode nm_wifi_ap_get_mode(NMWifiAP *ap) { - g_return_val_if_fail(NM_IS_WIFI_AP(ap), NM_802_11_MODE_UNKNOWN); + g_return_val_if_fail(NM_IS_WIFI_AP(ap), _NM_802_11_MODE_UNKNOWN); return NM_WIFI_AP_GET_PRIVATE(ap)->mode; } static gboolean -nm_wifi_ap_set_mode(NMWifiAP *ap, NM80211Mode mode) +nm_wifi_ap_set_mode(NMWifiAP *ap, _NM80211Mode mode) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); nm_assert(NM_IN_SET(mode, - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_ADHOC, - NM_802_11_MODE_INFRA, - NM_802_11_MODE_MESH)); + _NM_802_11_MODE_UNKNOWN, + _NM_802_11_MODE_ADHOC, + _NM_802_11_MODE_INFRA, + _NM_802_11_MODE_MESH)); if (priv->mode != mode) { priv->mode = mode; @@ -513,34 +513,35 @@ nm_wifi_ap_to_string(const NMWifiAP *self, char *str_buf, gulong buf_len, gint64 nm_utils_get_monotonic_timestamp_msec_cached(&now_msec); - g_snprintf(str_buf, - buf_len, - "%17s %-35s [ %c %3u %3u%% %c%c %c%c W:%04X R:%04X ] %s sup:%s [nm:%s]", - priv->address ?: "(none)", - (ssid_to_free = _nm_utils_ssid_to_string(priv->ssid)), - (priv->mode == NM_802_11_MODE_ADHOC - ? '*' - : (priv->hotspot - ? '#' - : (priv->fake ? 'f' : (priv->mode == NM_802_11_MODE_MESH ? 'm' : 'a')))), - chan, - priv->strength, - priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : '_', - priv->metered ? 'M' : '_', - priv->flags & NM_802_11_AP_FLAGS_WPS ? 'W' : '_', - priv->flags & NM_802_11_AP_FLAGS_WPS_PIN - ? 'p' - : (priv->flags & NM_802_11_AP_FLAGS_WPS_PBC ? '#' : '_'), - priv->wpa_flags & 0xFFFF, - priv->rsn_flags & 0xFFFF, - priv->last_seen_msec != G_MININT64 - ? nm_sprintf_buf(str_buf_ts, - "%3u.%03us", - (guint)((now_msec - priv->last_seen_msec) / 1000), - (guint)((now_msec - priv->last_seen_msec) % 1000)) - : " ", - supplicant_id, - export_path); + g_snprintf( + str_buf, + buf_len, + "%17s %-35s [ %c %3u %3u%% %c%c %c%c W:%04X R:%04X ] %s sup:%s [nm:%s]", + priv->address ?: "(none)", + (ssid_to_free = _nm_utils_ssid_to_string_gbytes(priv->ssid)), + (priv->mode == _NM_802_11_MODE_ADHOC + ? '*' + : (priv->hotspot + ? '#' + : (priv->fake ? 'f' : (priv->mode == _NM_802_11_MODE_MESH ? 'm' : 'a')))), + chan, + priv->strength, + priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : '_', + priv->metered ? 'M' : '_', + priv->flags & NM_802_11_AP_FLAGS_WPS ? 'W' : '_', + priv->flags & NM_802_11_AP_FLAGS_WPS_PIN + ? 'p' + : (priv->flags & NM_802_11_AP_FLAGS_WPS_PBC ? '#' : '_'), + priv->wpa_flags & 0xFFFF, + priv->rsn_flags & 0xFFFF, + priv->last_seen_msec != G_MININT64 + ? nm_sprintf_buf(str_buf_ts, + "%3u.%03us", + (guint) ((now_msec - priv->last_seen_msec) / 1000), + (guint) ((now_msec - priv->last_seen_msec) % 1000)) + : " ", + supplicant_id, + export_path); return str_buf; } @@ -589,13 +590,13 @@ nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection) mode = nm_setting_wireless_get_mode(s_wireless); if (mode) { - if (!strcmp(mode, "infrastructure") && (priv->mode != NM_802_11_MODE_INFRA)) + if (!strcmp(mode, "infrastructure") && (priv->mode != _NM_802_11_MODE_INFRA)) return FALSE; - if (!strcmp(mode, "adhoc") && (priv->mode != NM_802_11_MODE_ADHOC)) + if (!strcmp(mode, "adhoc") && (priv->mode != _NM_802_11_MODE_ADHOC)) return FALSE; - if (!strcmp(mode, "ap") && (priv->mode != NM_802_11_MODE_INFRA || priv->hotspot != TRUE)) + if (!strcmp(mode, "ap") && (priv->mode != _NM_802_11_MODE_INFRA || priv->hotspot != TRUE)) return FALSE; - if (!strcmp(mode, "mesh") && (priv->mode != NM_802_11_MODE_MESH)) + if (!strcmp(mode, "mesh") && (priv->mode != _NM_802_11_MODE_MESH)) return FALSE; } @@ -624,7 +625,7 @@ nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection) priv->flags, priv->wpa_flags, priv->rsn_flags, - priv->mode); + NM_802_11_MODE_CAST(priv->mode)); } gboolean @@ -713,7 +714,7 @@ nm_wifi_ap_init(NMWifiAP *self) c_list_init(&self->aps_lst); - priv->mode = NM_802_11_MODE_INFRA; + priv->mode = _NM_802_11_MODE_INFRA; priv->flags = NM_802_11_AP_FLAGS_NONE; priv->wpa_flags = NM_802_11_AP_SEC_NONE; priv->rsn_flags = NM_802_11_AP_SEC_NONE; @@ -758,19 +759,19 @@ nm_wifi_ap_new_fake_from_connection(NMConnection *connection) mode = nm_setting_wireless_get_mode(s_wireless); if (mode) { if (!strcmp(mode, "infrastructure")) - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); else if (!strcmp(mode, "adhoc")) { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_ADHOC); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_ADHOC); adhoc = TRUE; } else if (!strcmp(mode, "mesh")) - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_MESH); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_MESH); else if (!strcmp(mode, "ap")) { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); NM_WIFI_AP_GET_PRIVATE(ap)->hotspot = TRUE; } else goto error; } else { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); } band = nm_setting_wireless_get_band(s_wireless); @@ -861,27 +862,21 @@ finalize(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_access_point = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_ACCESS_POINT, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Flags", "u", NM_WIFI_AP_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WpaFlags", "u", NM_WIFI_AP_WPA_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("RsnFlags", "u", NM_WIFI_AP_RSN_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ssid", "ay", NM_WIFI_AP_SSID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Frequency", - "u", - NM_WIFI_AP_FREQUENCY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_WIFI_AP_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "u", NM_WIFI_AP_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("MaxBitrate", - "u", - NM_WIFI_AP_MAX_BITRATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Strength", "y", NM_WIFI_AP_STRENGTH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("LastSeen", - "i", - NM_WIFI_AP_LAST_SEEN), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", "u", NM_WIFI_AP_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WpaFlags", "u", NM_WIFI_AP_WPA_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RsnFlags", "u", NM_WIFI_AP_RSN_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ssid", "ay", NM_WIFI_AP_SSID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Frequency", "u", NM_WIFI_AP_FREQUENCY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_WIFI_AP_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "u", NM_WIFI_AP_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MaxBitrate", + "u", + NM_WIFI_AP_MAX_BITRATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Strength", "y", NM_WIFI_AP_STRENGTH), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen", + "i", + NM_WIFI_AP_LAST_SEEN), ), ), }; static void @@ -955,9 +950,9 @@ nm_wifi_ap_class_init(NMWifiAPClass *ap_class) obj_properties[PROP_MODE] = g_param_spec_uint(NM_WIFI_AP_MODE, "", "", - NM_802_11_MODE_ADHOC, - NM_802_11_MODE_INFRA, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_ADHOC, + _NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_MAX_BITRATE] = g_param_spec_uint(NM_WIFI_AP_MAX_BITRATE, diff --git a/src/core/devices/wifi/nm-wifi-ap.h b/src/core/devices/wifi/nm-wifi-ap.h index bdd72415..bffd28a8 100644 --- a/src/core/devices/wifi/nm-wifi-ap.h +++ b/src/core/devices/wifi/nm-wifi-ap.h @@ -10,6 +10,7 @@ #include "nm-dbus-object.h" #include "nm-dbus-interface.h" #include "nm-connection.h" +#include "libnm-base/nm-base.h" #define NM_TYPE_WIFI_AP (nm_wifi_ap_get_type()) #define NM_WIFI_AP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_AP, NMWifiAP)) @@ -69,7 +70,7 @@ gboolean nm_wifi_ap_set_ssid(NMWifiAP *ap, GBytes *ssid); const char * nm_wifi_ap_get_address(const NMWifiAP *ap); gboolean nm_wifi_ap_set_address(NMWifiAP *ap, const char *addr); gboolean nm_wifi_ap_set_address_bin(NMWifiAP *ap, const NMEtherAddr *addr); -NM80211Mode nm_wifi_ap_get_mode(NMWifiAP *ap); +_NM80211Mode nm_wifi_ap_get_mode(NMWifiAP *ap); gboolean nm_wifi_ap_is_hotspot(NMWifiAP *ap); gint8 nm_wifi_ap_get_strength(NMWifiAP *ap); gboolean nm_wifi_ap_set_strength(NMWifiAP *ap, gint8 strength); diff --git a/src/core/devices/wifi/nm-wifi-common.c b/src/core/devices/wifi/nm-wifi-common.c index c715c07c..b98ef222 100644 --- a/src/core/devices/wifi/nm-wifi-common.c +++ b/src/core/devices/wifi/nm-wifi-common.c @@ -146,31 +146,25 @@ const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless = { .in_args = NM_DEFINE_GDBUS_ARG_INFOS( NM_DEFINE_GDBUS_ARG_INFO("options", "a{sv}"), ), ), .handle = impl_device_wifi_request_scan, ), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, - &nm_signal_info_wireless_access_point_added, + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_wireless_access_point_added, &nm_signal_info_wireless_access_point_removed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PermHwAddress", - "s", - NM_DEVICE_PERM_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "u", NM_DEVICE_WIFI_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Bitrate", - "u", - NM_DEVICE_WIFI_BITRATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AccessPoints", - "ao", - NM_DEVICE_WIFI_ACCESS_POINTS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ActiveAccessPoint", - "o", - NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WirelessCapabilities", - "u", - NM_DEVICE_WIFI_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PermHwAddress", + "s", + NM_DEVICE_PERM_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "u", NM_DEVICE_WIFI_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Bitrate", "u", NM_DEVICE_WIFI_BITRATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AccessPoints", + "ao", + NM_DEVICE_WIFI_ACCESS_POINTS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ActiveAccessPoint", + "o", + NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WirelessCapabilities", + "u", + NM_DEVICE_WIFI_CAPABILITIES), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastScan", "x", NM_DEVICE_WIFI_LAST_SCAN), ), ), - .legacy_property_changed = TRUE, }; diff --git a/src/core/devices/wifi/nm-wifi-factory.c b/src/core/devices/wifi/nm-wifi-factory.c index 40375e1c..d2269c74 100644 --- a/src/core/devices/wifi/nm-wifi-factory.c +++ b/src/core/devices/wifi/nm-wifi-factory.c @@ -15,7 +15,7 @@ #include "nm-device-olpc-mesh.h" #include "nm-device-iwd.h" #include "settings/nm-settings-connection.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-config.h" /*****************************************************************************/ @@ -74,7 +74,8 @@ create_device(NMDeviceFactory * factory, NMConnection * connection, gboolean * out_ignore) { - gs_free char *backend = NULL; + gs_free char *backend_free = NULL; + const char * backend; g_return_val_if_fail(iface != NULL, NULL); g_return_val_if_fail(plink != NULL, NULL); @@ -89,7 +90,7 @@ create_device(NMDeviceFactory * factory, plink, "wifi", NULL); - nm_strstrip(backend); + backend = nm_strstrip_avoid_copy_a(300, backend, &backend_free); nm_log_dbg(LOGD_PLATFORM | LOGD_WIFI, "(%s) config: backend is %s%s%s%s", @@ -97,9 +98,9 @@ create_device(NMDeviceFactory * factory, NM_PRINT_FMT_QUOTE_STRING(backend), WITH_IWD ? " (iwd support enabled)" : ""); if (!backend || !g_ascii_strcasecmp(backend, "wpa_supplicant")) { - NMDevice * device; - NMDeviceWifiCapabilities capabilities; - NM80211Mode mode; + NMDevice * device; + _NMDeviceWifiCapabilities capabilities; + _NM80211Mode mode; if (!nm_platform_wifi_get_capabilities(NM_PLATFORM_GET, plink->ifindex, &capabilities)) { nm_log_warn(LOGD_PLATFORM | LOGD_WIFI, @@ -114,7 +115,7 @@ create_device(NMDeviceFactory * factory, * them if/when they change to a handled type. */ mode = nm_platform_wifi_get_mode(NM_PLATFORM_GET, plink->ifindex); - if (mode == NM_802_11_MODE_UNKNOWN) { + if (mode == _NM_802_11_MODE_UNKNOWN) { *out_ignore = TRUE; return NULL; } diff --git a/src/core/devices/wifi/nm-wifi-p2p-peer.c b/src/core/devices/wifi/nm-wifi-p2p-peer.c index 8488f32d..433c2833 100644 --- a/src/core/devices/wifi/nm-wifi-p2p-peer.c +++ b/src/core/devices/wifi/nm-wifi-p2p-peer.c @@ -12,13 +12,13 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-setting-wireless.h" #include "nm-utils.h" #include "nm-wifi-utils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "supplicant/nm-supplicant-types.h" /*****************************************************************************/ @@ -608,7 +608,6 @@ static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen", "i", NM_WIFI_P2P_PEER_LAST_SEEN), ), ), - .legacy_property_changed = FALSE, }; static void diff --git a/src/core/devices/wifi/nm-wifi-utils.c b/src/core/devices/wifi/nm-wifi-utils.c index aed236cc..15ced990 100644 --- a/src/core/devices/wifi/nm-wifi-utils.c +++ b/src/core/devices/wifi/nm-wifi-utils.c @@ -7,10 +7,14 @@ #include "nm-wifi-utils.h" +#include <arpa/inet.h> +#include <netinet/if_ether.h> #include <stdlib.h> #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-core-aux-intern/nm-common-macros.h" +#include "libnm-base/nm-config-base.h" static gboolean verify_no_wep(NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error) @@ -526,7 +530,7 @@ verify_adhoc(NMSettingWirelessSecurity *s_wsec, gboolean nm_wifi_utils_complete_connection(GBytes * ap_ssid, const char * bssid, - NM80211Mode ap_mode, + _NM80211Mode ap_mode, guint32 ap_freq, guint32 ap_flags, guint32 ap_wpa_flags, @@ -575,14 +579,14 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, /* Make sure the supplied mode matches the AP's */ if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_INFRA) || !strcmp(mode, NM_SETTING_WIRELESS_MODE_AP)) { - if (ap_mode == NM_802_11_MODE_INFRA) + if (ap_mode == _NM_802_11_MODE_INFRA) valid = TRUE; } else if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_ADHOC)) { - if (ap_mode == NM_802_11_MODE_ADHOC) + if (ap_mode == _NM_802_11_MODE_ADHOC) valid = TRUE; adhoc = TRUE; } else if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_MESH)) { - if (ap_mode == NM_802_11_MODE_MESH) + if (ap_mode == _NM_802_11_MODE_MESH) valid = TRUE; mesh = TRUE; } @@ -600,10 +604,10 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, } } else { mode = NM_SETTING_WIRELESS_MODE_INFRA; - if (ap_mode == NM_802_11_MODE_ADHOC) { + if (ap_mode == _NM_802_11_MODE_ADHOC) { mode = NM_SETTING_WIRELESS_MODE_ADHOC; adhoc = TRUE; - } else if (ap_mode == NM_802_11_MODE_MESH) { + } else if (ap_mode == _NM_802_11_MODE_MESH) { mode = NM_SETTING_WIRELESS_MODE_MESH; mesh = TRUE; } @@ -810,15 +814,24 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, * setting. Since there's so much configuration required for it, there's * no way it can be automatically completed. */ - } else if ((key_mgmt && !strcmp(key_mgmt, "sae")) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { + } else if (nm_streq0(key_mgmt, "wpa-psk") + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE + && (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK + || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK))) { + g_object_set(s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, + "open", + NULL); + } else if (nm_streq0(key_mgmt, "sae") || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); - } else if ((key_mgmt && !strcmp(key_mgmt, "owe")) + } else if (nm_streq0(key_mgmt, "owe") || NM_FLAGS_ANY(ap_rsn_flags, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { g_object_set(s_wsec, @@ -827,9 +840,8 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); - } else if ((key_mgmt && !strcmp(key_mgmt, "wpa-psk")) - || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { + } else if (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK + || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", @@ -839,7 +851,7 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, /* Leave proto/pairwise/group as client set them; if they are unset the * supplicant will figure out the best combination at connect time. */ - } else if ((key_mgmt && !strcmp(key_mgmt, "wpa-eap-suite-b-192")) + } else if (nm_streq0(key_mgmt, "wpa-eap-suite-b-192") || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192)) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, @@ -943,3 +955,865 @@ nm_wifi_connection_get_iwd_ssid_and_security(NMConnection * connection, return TRUE; } + +/*****************************************************************************/ + +/* Builds the IWD network configuration file name for a given SSID + * and security type pair. The SSID should be valid UTF-8 and in + * any case must contain no NUL-bytes. If @ssid is NUL-terminated, + * @ssid_len can be -1 instead of actual SSID length. + */ +char * +nm_wifi_utils_get_iwd_config_filename(const char * ssid, + gssize ssid_len, + NMIwdNetworkSecurity security) +{ + const char *security_suffix; + const char *ptr; + gboolean alnum_ssid = TRUE; + + for (ptr = ssid; ssid_len != 0 && *ptr != '\0'; ptr++, ssid_len--) + if (!g_ascii_isalnum(*ptr) && !strchr("-_ ", *ptr)) + alnum_ssid = FALSE; + + g_return_val_if_fail(ptr != ssid && ptr - ssid <= NM_IW_ESSID_MAX_SIZE, NULL); + + switch (security) { + case NM_IWD_NETWORK_SECURITY_OPEN: + security_suffix = "open"; + break; + case NM_IWD_NETWORK_SECURITY_PSK: + security_suffix = "psk"; + break; + case NM_IWD_NETWORK_SECURITY_8021X: + security_suffix = "8021x"; + break; + default: + return NULL; + } + + if (alnum_ssid) { + return g_strdup_printf("%.*s.%s", (int) (ptr - ssid), ssid, security_suffix); + } else { + char ssid_buf[NM_IW_ESSID_MAX_SIZE * 2 + 1]; + + return g_strdup_printf("=%s.%s", + nm_utils_bin2hexstr_full(ssid, ptr - ssid, '\0', FALSE, ssid_buf), + security_suffix); + } +} + +/*****************************************************************************/ + +#define SECRETS_DONT_STORE_FLAGS \ + (NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED) + +static gboolean +psk_setting_to_iwd_config(GKeyFile *file, NMSettingWirelessSecurity *s_wsec, GError **error) +{ + NMSettingSecretFlags psk_flags = nm_setting_wireless_security_get_psk_flags(s_wsec); + const char * psk = nm_setting_wireless_security_get_psk(s_wsec); + gsize psk_len; + guint8 buffer[32]; + const char * key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); + + if (!psk || NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) { + if (NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) { + nm_log_info( + LOGD_WIFI, + "IWD network config is being created wihout the PSK but IWD will save the PSK on " + "successful activation not honoring the psk-flags property"); + } + return TRUE; + } + + psk_len = strlen(psk); + if (nm_streq0(key_mgmt, "sae")) { + g_key_file_set_string(file, "Security", "Passphrase", psk); + } else if (psk_len >= 8 && psk_len <= 63) { + g_key_file_set_string(file, "Security", "Passphrase", psk); + } else if (psk_len == 64 && nm_utils_hexstr2bin_buf(psk, FALSE, FALSE, NULL, buffer)) { + g_key_file_set_string(file, "Security", "PreSharedKey", psk); + } else { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Unknown PSK format"); + return FALSE; + } + + return TRUE; +} + +static gboolean +eap_certs_to_iwd_config(GKeyFile * file, + NMSetting8021x *s_8021x, + bool phase2, + char * iwd_prefix, + GError ** error) +{ + NMSetting8021xCKScheme ca_cert_scheme = + phase2 ? nm_setting_802_1x_get_phase2_ca_cert_scheme(s_8021x) + : nm_setting_802_1x_get_ca_cert_scheme(s_8021x); + NMSetting8021xCKScheme client_cert_scheme = + phase2 ? nm_setting_802_1x_get_phase2_client_cert_scheme(s_8021x) + : nm_setting_802_1x_get_client_cert_scheme(s_8021x); + NMSetting8021xCKScheme key_scheme; + NMSettingSecretFlags key_password_flags; + const char * ca_path = phase2 ? nm_setting_802_1x_get_phase2_ca_path(s_8021x) + : nm_setting_802_1x_get_ca_path(s_8021x); + const char * cert_path; + const char * key_path = NULL; + const char * key_password; + const char * domain_suffix_match; + const char * domain_match; + char setting_buf[128]; + + /* TODO: should check that all certificates and the key are RSA */ + /* Note: up to IWD 1.9 only the PEM encoding was supported for certificates + * and only PKCS#8 PEM for keys but we don't know the IWD version here. + * From IWD 1.10 raw (DER) X.509 certificates and PKCS#12 are also supported + * for certificates but a certificate list or chain still has to be PEM + * (i.e. if it contains more than one certificate.) Raw PKCS#12 and + * old-style OpenSSL PEM formats are also supported for keys. Hopefully + * this is in practice the same set of file:// formats as supported by + * nm_crypto_* / wpa_supplicant so we need no conversions here. + */ + + if (nm_setting_802_1x_get_system_ca_certs(s_8021x)) { + /* Either overrides or is added to the certificates in (phase2-)ca-cert + * and ca-path depending on whether it points to a file or a directory. + * We can't ignore this property so it's an error if it is set. + * Fortunately not used by nm-connection-editor. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "The system-ca-certs property is not supported"); + return FALSE; + } + + if (ca_path) { + /* To support this (and this could be applied to system-ca-certs as + * well) we'd have to scan the directory, parse the certificates and + * write a new certificate-list file to point to in the IWD config. + * This is going to create issues of where to store these files, for + * how long and with what permission bits. Fortunately this doesn't + * seem to be used by nm-connection-editor either. + * + * That file would also have to contain whatever the (phase2-)ca-cert + * propterty points to because IWD has only one CACert setting per + * phase. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "The (phase2-)ca-path property is not supported"); + return FALSE; + } + + if (ca_cert_scheme != NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { + if (ca_cert_scheme != NM_SETTING_802_1X_CK_SCHEME_PATH) { + /* To support the blob scheme we'd have to either convert the + * certificate data into a PEM payload and embed the PEM file in + * the IWD config file, which is not supported by GKeyFile, or write + * it into a new file to point to in the IWD config. This is again + * is going to create issues of where to store these files, for how + * long and with what permission bits. Fortunately this scheme isn't + * used in nm-connection-editor either. + * + * PKCS#11 is not supported by IWD in any way so we don't need to + * support the PKCS#11 URI scheme. + * + * If scheme is unknown, assume no value is set. + */ + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)ca-cert property schemes other than file:// not supported"); + return FALSE; + } + + cert_path = phase2 ? nm_setting_802_1x_get_phase2_ca_cert_path(s_8021x) + : nm_setting_802_1x_get_ca_cert_path(s_8021x); + if (cert_path) + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "CACert"), + cert_path); + } + + if (client_cert_scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) + goto private_key_done; + + if (client_cert_scheme != NM_SETTING_802_1X_CK_SCHEME_PATH) { + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)client-cert property schemes other than file:// not supported"); + return FALSE; + } + + cert_path = phase2 ? nm_setting_802_1x_get_phase2_client_cert_path(s_8021x) + : nm_setting_802_1x_get_client_cert_path(s_8021x); + if (!cert_path) + goto private_key_done; + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "ClientCert"), + cert_path); + + key_scheme = phase2 ? nm_setting_802_1x_get_phase2_private_key_scheme(s_8021x) + : nm_setting_802_1x_get_private_key_scheme(s_8021x); + if (key_scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + key_path = phase2 ? nm_setting_802_1x_get_phase2_private_key_path(s_8021x) + : nm_setting_802_1x_get_private_key_path(s_8021x); + if (key_scheme != NM_SETTING_802_1X_CK_SCHEME_PATH || !key_path) { + /* The same comments apply to writing the key into a temporary file + * as for the certificates (above), except this is even more + * sensitive. + */ + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)private-key property schemes other than file:// not supported"); + return FALSE; + } + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "ClientKey"), + key_path); + + key_password = phase2 ? nm_setting_802_1x_get_phase2_private_key_password(s_8021x) + : nm_setting_802_1x_get_private_key_password(s_8021x); + key_password_flags = phase2 ? nm_setting_802_1x_get_phase2_private_key_password_flags(s_8021x) + : nm_setting_802_1x_get_private_key_password_flags(s_8021x); + if (!key_password || NM_FLAGS_ANY(key_password_flags, SECRETS_DONT_STORE_FLAGS)) { + g_key_file_set_comment( + file, + "Security", + setting_buf, + "ClientKeyPassphrase not to be saved, will be queried through the agent if needed", + NULL); + goto private_key_done; + } + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "ClientKeyPassphrase"), + key_password); + +private_key_done: + if (phase2 ? nm_setting_802_1x_get_phase2_subject_match(s_8021x) + : nm_setting_802_1x_get_subject_match(s_8021x)) { + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)subject-match not supported, use domain-match or domain-suffix-match"); + return FALSE; + } + + if (phase2 ? nm_setting_802_1x_get_num_phase2_altsubject_matches(s_8021x) + : nm_setting_802_1x_get_num_altsubject_matches(s_8021x)) { + /* We could convert the "DNS:" entries into a ServerDomainMask but we'd + * have to leave out the "EMAIL:" and "URI:" types or report error. + * The interpretation still wouldn't be exactly the same as in + * wpa_supplicant. + */ + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)altsubject-matches not supported, use domain-match or domain-suffix-match"); + return FALSE; + } + + domain_suffix_match = phase2 ? nm_setting_802_1x_get_phase2_domain_suffix_match(s_8021x) + : nm_setting_802_1x_get_domain_suffix_match(s_8021x); + domain_match = phase2 ? nm_setting_802_1x_get_phase2_domain_match(s_8021x) + : nm_setting_802_1x_get_domain_match(s_8021x); + + if (domain_suffix_match || domain_match) { + GString * s = g_string_sized_new(128); + const char *ptr; + const char *end; + + for (ptr = domain_suffix_match; ptr; ptr = *end == ';' ? end + 1 : NULL) { + if (s->len) + g_string_append_c(s, ';'); + end = strchrnul(ptr, ';'); + /* Use *.<suffix> to get the suffix match effect */ + g_string_append(s, "*."); + g_string_append_len(s, ptr, end - ptr); + } + + /* domain-match can be appended as-is */ + if (domain_match) { + if (s->len) + g_string_append_c(s, ';'); + g_string_append(s, domain_match); + } + + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "ServerDomainMask"), + s->str); + g_string_free(s, TRUE); + } + + return TRUE; +} + +static void +eap_method_name_to_iwd_config(GKeyFile *file, const char *iwd_prefix, const char *method) +{ + char setting_buf[128]; + + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Method"), + method); +} + +static void +eap_optional_identity_to_iwd_config(GKeyFile *file, const char *iwd_prefix, const char *identity) +{ + char setting_buf[128]; + + /* The identity is optional for some methods where an authenticator may + * in theory not ask for it. For our usage here we treat it as always + * optional because it can be omitted in the config file if the user + * wants IWD to query for it on every connection. + */ + if (identity) { + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Identity"), + identity); + } else { + g_key_file_set_comment( + file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Method"), + "Identity not to be saved, will be queried through the agent if needed", + NULL); + } +} + +static gboolean +eap_optional_password_to_iwd_config(GKeyFile * file, + const char * iwd_prefix, + NMSetting8021x *s_8021x, + GError ** error) +{ + char setting_buf[128]; + const char * password = nm_setting_802_1x_get_password(s_8021x); + NMSettingSecretFlags flags = nm_setting_802_1x_get_password_flags(s_8021x); + + if (!password && nm_setting_802_1x_get_password_raw(s_8021x)) { + /* IWD doesn't support passwords that can't be encoded in the config + * file, i.e. containing NUL characters. Those that don't have NULs + * could in theory be written to the config file but GKeyFile may not + * like that if they're no UTF-8, and the password-raw property is + * not written by nm-connection-editor anyway. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Non-UTF-8 passwords are not supported, if the password is UTF-8 set " + "the \"password\" property"); + return FALSE; + } + if (!password || NM_FLAGS_ANY(flags, SECRETS_DONT_STORE_FLAGS)) { + return g_key_file_set_comment(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Method"), + "Password not to be saved, will be queried through the agent", + error); + } else { + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Password"), + password); + return TRUE; + } +} + +static void +eap_phase1_identity_to_iwd_config(GKeyFile *file, const char *iwd_prefix, NMSetting8021x *s_8021x) +{ + const char *phase1_identity = nm_setting_802_1x_get_anonymous_identity(s_8021x); + + if (!phase1_identity) { + phase1_identity = nm_setting_802_1x_get_identity(s_8021x); + + if (phase1_identity) { + nm_log_info(LOGD_WIFI, + "IWD network config will send the same EAP Identity string in " + "plaintext in phase 1 as in phase 2 (encrypted) to mimic legacy " + "behavior, set [%s].%s=anonymous to prevent exposing the value", + NM_SETTING_802_1X_SETTING_NAME, + NM_SETTING_802_1X_ANONYMOUS_IDENTITY); + } + } + + eap_optional_identity_to_iwd_config(file, iwd_prefix, phase1_identity); +} + +static gboolean +eap_method_config_to_iwd_config(GKeyFile * file, + NMSetting8021x *s_8021x, + gboolean phase2, + const char * method, + const char * iwd_prefix, + GError ** error) +{ + char prefix_buf[128]; + + if (nm_streq0(method, "tls")) { + eap_method_name_to_iwd_config(file, iwd_prefix, "TLS"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + + return eap_certs_to_iwd_config(file, + s_8021x, + phase2, + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "TLS-"), + error); + } else if (nm_streq0(method, "ttls") && !phase2) { + const char *noneap_method = nm_setting_802_1x_get_phase2_auth(s_8021x); + + eap_method_name_to_iwd_config(file, iwd_prefix, "TTLS"); + eap_phase1_identity_to_iwd_config(file, iwd_prefix, s_8021x); + + if (!eap_certs_to_iwd_config(file, + s_8021x, + phase2, + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "TTLS-"), + error)) + return FALSE; + + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "TTLS-Phase2-"); + + if (nm_setting_802_1x_get_phase2_autheap(s_8021x)) { + if (noneap_method) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Only one TTLS phase 2 method can be set"); + return FALSE; + } + return eap_method_config_to_iwd_config(file, + s_8021x, + TRUE, + nm_setting_802_1x_get_phase2_autheap(s_8021x), + prefix_buf, + error); + } + + if (NM_IN_STRSET(noneap_method, "chap", "mschap", "mschapv2", "pap")) { + const char *iwd_method; + + if (nm_streq0(noneap_method, "chap")) { + iwd_method = "Tunneled-CHAP"; + } else if (nm_streq0(noneap_method, "mschap")) { + iwd_method = "Tunneled-MSCHAP"; + } else if (nm_streq0(noneap_method, "mschapv2")) { + iwd_method = "Tunneled-MSCHAPv2"; + } else { + iwd_method = "Tunneled-PAP"; + } + + eap_method_name_to_iwd_config(file, prefix_buf, iwd_method); + eap_optional_identity_to_iwd_config(file, + prefix_buf, + nm_setting_802_1x_get_identity(s_8021x)); + return eap_optional_password_to_iwd_config(file, prefix_buf, s_8021x, error); + } + + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Unsupported TTLS non-EAP inner method"); + return FALSE; + } else if (nm_streq0(method, "peap") && !phase2) { + eap_method_name_to_iwd_config(file, iwd_prefix, "PEAP"); + eap_phase1_identity_to_iwd_config(file, iwd_prefix, s_8021x); + + if (!eap_certs_to_iwd_config(file, + s_8021x, + phase2, + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "PEAP-"), + error)) + return FALSE; + + if (nm_setting_802_1x_get_phase1_peapver(s_8021x) + || nm_setting_802_1x_get_phase1_peaplabel(s_8021x)) + nm_log_info(LOGD_WIFI, + "IWD network config will not honour the PEAP version and label properties " + "in the 802.1x setting (unsupported)"); + + if (!nm_setting_802_1x_get_phase2_auth(s_8021x)) { + /* Apparently PEAP can be used without a phase 2 but this is not + * supported by either NM or IWD. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "PEAP without an inner method is unsupported"); + return FALSE; + } + + return eap_method_config_to_iwd_config( + file, + s_8021x, + TRUE, + nm_setting_802_1x_get_phase2_auth(s_8021x), + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "PEAP-Phase2-"), + error); + } else if (nm_streq0(method, "md5") && phase2) { + eap_method_name_to_iwd_config(file, iwd_prefix, "MD5"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + return eap_optional_password_to_iwd_config(file, iwd_prefix, s_8021x, error); + } else if (nm_streq0(method, "gtc") && phase2) { + eap_method_name_to_iwd_config(file, iwd_prefix, "GTC"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + return eap_optional_password_to_iwd_config(file, iwd_prefix, s_8021x, error); + } else if (nm_streq0(method, "pwd")) { + eap_method_name_to_iwd_config(file, iwd_prefix, "PWD"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + return eap_optional_password_to_iwd_config(file, iwd_prefix, s_8021x, error); + } else if (nm_streq0(method, "mschapv2")) { + eap_method_name_to_iwd_config(file, iwd_prefix, "MSCHAPV2"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + /* In this case we can support password-raw but would have to + * MD4-hash it and set as <iwd_prefix>Password-Hash + */ + return eap_optional_password_to_iwd_config(file, iwd_prefix, s_8021x, error); + } else if (nm_streq0(method, "external")) { + /* This may be a connection created by NMIwdManager in whch case there + * may be no need to be convert it back to the IWD format. Ideally we + * would still rewrite the other sections/groups in the IWD settings + * file and preserve the [Security] group -- TODO. Possibly this should + * also not be reported as an error. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Connection contains no EAP method configuration"); + return FALSE; + } else { + /* Some methods are only allowed in phase 1 or only phase 2. + * OTP, LEAP and FAST are not supported by IWD at all. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + phase2 ? "Unsupported phase 2 EAP method" + : "Unsupported phase 1 EAP method"); + return FALSE; + } + + return TRUE; +} + +static gboolean +eap_setting_to_iwd_config(GKeyFile *file, NMSetting8021x *s_8021x, GError **error) +{ + const char *method; + + if (!s_8021x || nm_setting_802_1x_get_num_eap_methods(s_8021x) == 0) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "The 802.1x setting is missing or no EAP method set"); + return FALSE; + } + + if (!nm_setting_verify(NM_SETTING(s_8021x), NULL, error)) + return FALSE; + + method = nm_setting_802_1x_get_eap_method(s_8021x, 0); + + if (nm_setting_802_1x_get_num_eap_methods(s_8021x) > 1) + nm_log_info(LOGD_WIFI, + "IWD network config will only contain the first EAP method: %s", + method); + + if (nm_setting_802_1x_get_phase1_auth_flags(s_8021x)) + nm_log_info(LOGD_WIFI, + "IWD network config will not honour the TLSv1.x-disable flags in the 802.1x " + "setting (unsupported)"); + + if (nm_setting_802_1x_get_auth_timeout(s_8021x)) + nm_log_info(LOGD_WIFI, + "IWD network config will not honour the auth-timeout property in the 802.1x " + "setting (unsupported)"); + + return eap_method_config_to_iwd_config(file, s_8021x, FALSE, method, "EAP-", error); +} + +static gboolean +ip4_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) +{ + guint num; + struct in_addr ip; + + /* These settings are not acutally used unless global + * [General].EnableNetworkConfiguration is true, which we don't support. + * We add them for sake of completness, although many NMSettingIPConfig + * configurations can't be mapped to IWD configs and we simply ignore + * them. If they were to be used we'd need to add a few warnings. + */ + + if (!s_ip) + return TRUE; + + num = nm_setting_ip_config_get_num_dns(s_ip); + if (num) { + nm_auto_free_gstring GString *s = g_string_sized_new(128); + guint i; + + for (i = 0; i < num; i++) { + if (s->len) + g_string_append_c(s, ' '); + g_string_append(s, nm_setting_ip_config_get_dns(s_ip, i)); + } + /* It doesn't matter whether we add the DNS under [IPv4] or [IPv6] + * except that with method=auto the list will override the + * DNS addresses received over the DHCP version corresponing to + * v4 or v6. + * Note ignore-auto-dns=false isn't supported, this list always + * overrides the DHCP DNSes. + */ + g_key_file_set_string(file, "IPv4", "DNS", s->str); + } + + if (!nm_streq0(nm_setting_ip_config_get_method(s_ip), NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + return TRUE; + + num = nm_setting_ip_config_get_num_addresses(s_ip); + if (num) { + NMIPAddress *addr = nm_setting_ip_config_get_address(s_ip, 0); + guint prefix = nm_ip_address_get_prefix(addr); + in_addr_t netmask = _nm_utils_ip4_prefix_to_netmask(prefix); + char buf[INET_ADDRSTRLEN]; + + nm_ip_address_get_address_binary(addr, &ip); + g_key_file_set_string(file, "IPv4", "Address", nm_ip_address_get_address(addr)); + g_key_file_set_string(file, "IPv4", "Netmask", _nm_utils_inet4_ntop(netmask, buf)); + } else { + inet_pton(AF_INET, "10.42.0.100", &ip); + g_key_file_set_string(file, "IPv4", "Address", "10.42.0.100"); + } + + if (nm_setting_ip_config_get_gateway(s_ip)) { + g_key_file_set_string(file, "IPv4", "Gateway", nm_setting_ip_config_get_gateway(s_ip)); + } else { + uint32_t val; + char buf[INET_ADDRSTRLEN]; + + /* IWD won't enable static IP unless both Address and Gateway are + * set so generate a gateway address if not known. + */ + val = (ntohl(ip.s_addr) & 0xfffffff0) + 1; + if (val == ntohl(ip.s_addr)) + val += 1; + g_key_file_set_string(file, "IPv4", "Gateway", _nm_utils_inet4_ntop(htonl(val), buf)); + } + + return TRUE; +} + +static gboolean +ip6_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) +{ + guint num; + NMIPAddress *addr; + char buf[INET6_ADDRSTRLEN + 10]; + + if (!s_ip) + return TRUE; + + num = nm_setting_ip_config_get_num_dns(s_ip); + if (num) { + nm_auto_free_gstring GString *s = g_string_sized_new(128); + guint i; + + for (i = 0; i < num; i++) { + if (s->len) + g_string_append_c(s, ' '); + g_string_append(s, nm_setting_ip_config_get_dns(s_ip, i)); + } + g_key_file_set_string(file, "IPv6", "DNS", s->str); + } + + if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip), + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + return TRUE; + + g_key_file_set_boolean(file, "IPv6", "Enabled", TRUE); + + if (!nm_streq0(nm_setting_ip_config_get_method(s_ip), NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + return TRUE; + + if (!nm_setting_ip_config_get_num_addresses(s_ip)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "IP address required for IPv6 manual config"); + return FALSE; + } + + addr = nm_setting_ip_config_get_address(s_ip, 0); + g_key_file_set_string(file, + "IPv6", + "Address", + nm_sprintf_buf(buf, + "%s/%u", + nm_ip_address_get_address(addr), + nm_ip_address_get_prefix(addr))); + if (nm_setting_ip_config_get_gateway(s_ip)) + g_key_file_set_string(file, "IPv6", "Gateway", nm_setting_ip_config_get_gateway(s_ip)); + return TRUE; +} + +GKeyFile * +nm_wifi_utils_connection_to_iwd_config(NMConnection *connection, + char ** out_filename, + GError ** error) +{ + NMSettingConnection * s_conn = nm_connection_get_setting_connection(connection); + NMSettingWireless * s_wifi = nm_connection_get_setting_wireless(connection); + GBytes * ssid; + const guint8 * ssid_data; + gsize ssid_len; + NMIwdNetworkSecurity security; + const char * cloned_mac_addr; + gs_free char * comment = NULL; + nm_auto_unref_keyfile GKeyFile *file = NULL; + + if (!s_conn || !s_wifi + || !nm_streq(nm_setting_connection_get_connection_type(s_conn), + NM_SETTING_WIRELESS_SETTING_NAME)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Connection and/or wireless settings are missing"); + return NULL; + } + + if (!NM_IN_STRSET(nm_setting_wireless_get_mode(s_wifi), NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Non-infrastructure-mode connections don't have IWD profiles (or aren't supported)"); + return NULL; + } + + ssid = nm_setting_wireless_get_ssid(s_wifi); + ssid_data = ssid ? g_bytes_get_data(ssid, &ssid_len) : NULL; + if (!ssid_data || ssid_len <= 0 || ssid_len > NM_IW_ESSID_MAX_SIZE + || !g_utf8_validate((const char *) ssid_data, ssid_len, NULL)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Empty or non-UTF-8 SSIDs not supported by IWD"); + return NULL; + } + + if (!nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Connection's security type unrecognised"); + return NULL; + } + + file = g_key_file_new(); + + comment = g_strdup_printf(" Auto-generated from NetworkManager connection \"%s\"\n" + " Changes to that connection overwrite this file when " + "enabled by NM's [%s].%s value", + nm_setting_connection_get_id(s_conn), + NM_CONFIG_KEYFILE_GROUP_MAIN, + NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH); + g_key_file_set_comment(file, NULL, NULL, comment, NULL); + + if (!nm_setting_connection_get_autoconnect(s_conn)) + g_key_file_set_boolean(file, "Settings", "AutoConnect", FALSE); + + if (nm_setting_wireless_get_hidden(s_wifi)) + g_key_file_set_boolean(file, "Settings", "Hidden", TRUE); + + /* Only effective if IWD's global [General].AddressRandomization is set + * to "network". "random" maps to [Settings].AlwaysRandomizeAddress=true, + * "stable" is the default, specific address maps to + * [Settings].AddressOverride set to that address. "permanent" is not + * supported and "preserve" can only be achieved using the global + * [General].AddressRandomization=disabled setting. We don't print + * warnings when we can't map the value here because we don't know what + * IWD's [General].AddressRandomization is set to. + */ + cloned_mac_addr = nm_setting_wireless_get_cloned_mac_address(s_wifi); + if (nm_streq0(cloned_mac_addr, NM_CLONED_MAC_RANDOM)) + g_key_file_set_boolean(file, "Settings", "AlwaysRandomizeAddress", TRUE); + else if (cloned_mac_addr && nm_utils_hwaddr_valid(cloned_mac_addr, ETH_ALEN)) + g_key_file_set_string(file, "Settings", "AddressOverride", cloned_mac_addr); + + if (!ip4_config_to_iwd_config( + file, + NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip4_config(connection)), + error)) + return NULL; + + if (!ip6_config_to_iwd_config( + file, + NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip6_config(connection)), + error)) + return NULL; + + switch (security) { + case NM_IWD_NETWORK_SECURITY_OPEN: + break; + case NM_IWD_NETWORK_SECURITY_PSK: + if (!psk_setting_to_iwd_config(file, + nm_connection_get_setting_wireless_security(connection), + error)) + return NULL; + + break; + case NM_IWD_NETWORK_SECURITY_8021X: + if (!eap_setting_to_iwd_config(file, nm_connection_get_setting_802_1x(connection), error)) + return NULL; + + break; + default: + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Connection security type is not supported"); + return NULL; + } + + if (out_filename) + *out_filename = + nm_wifi_utils_get_iwd_config_filename((const char *) ssid_data, ssid_len, security); + + return g_steal_pointer(&file); +} diff --git a/src/core/devices/wifi/nm-wifi-utils.h b/src/core/devices/wifi/nm-wifi-utils.h index 474bea41..2664c03e 100644 --- a/src/core/devices/wifi/nm-wifi-utils.h +++ b/src/core/devices/wifi/nm-wifi-utils.h @@ -11,6 +11,7 @@ #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" +#include "libnm-base/nm-base.h" typedef enum { NM_IWD_NETWORK_SECURITY_OPEN, @@ -21,7 +22,7 @@ typedef enum { gboolean nm_wifi_utils_complete_connection(GBytes * ssid, const char * bssid, - NM80211Mode mode, + _NM80211Mode mode, guint32 ap_freq, guint32 flags, guint32 wpa_flags, @@ -35,5 +36,11 @@ gboolean nm_wifi_utils_is_manf_default_ssid(GBytes *ssid); gboolean nm_wifi_connection_get_iwd_ssid_and_security(NMConnection * connection, char ** ssid, NMIwdNetworkSecurity *security); +char * nm_wifi_utils_get_iwd_config_filename(const char * ssid, + gssize ssid_len, + NMIwdNetworkSecurity security); + +GKeyFile * +nm_wifi_utils_connection_to_iwd_config(NMConnection *conn, char **out_filename, GError **error); #endif /* __NM_WIFI_UTILS_H__ */ diff --git a/src/core/devices/wifi/tests/test-devices-wifi.c b/src/core/devices/wifi/tests/test-devices-wifi.c index bc0ba126..dc278c94 100644 --- a/src/core/devices/wifi/tests/test-devices-wifi.c +++ b/src/core/devices/wifi/tests/test-devices-wifi.c @@ -7,7 +7,7 @@ #include "devices/wifi/nm-wifi-utils.h" #include "devices/wifi/nm-device-wifi.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-test-utils-core.h" @@ -49,7 +49,7 @@ static gboolean complete_connection(const char * ssid, const char * bssid, - NM80211Mode mode, + _NM80211Mode mode, guint32 flags, guint32 wpa_flags, guint32 rsn_flags, @@ -197,7 +197,7 @@ fill_8021x(NMConnection *connection, const KeyData items[]) } static NMConnection * -create_basic(const char *ssid, const char *bssid, NM80211Mode mode) +create_basic(const char *ssid, const char *bssid, _NM80211Mode mode) { NMConnection * connection; NMSettingWireless *s_wifi = NULL; @@ -217,9 +217,9 @@ create_basic(const char *ssid, const char *bssid, NM80211Mode mode) if (bssid) g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL); - if (mode == NM_802_11_MODE_INFRA) + if (mode == _NM_802_11_MODE_INFRA) g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_MODE, "infrastructure", NULL); - else if (mode == NM_802_11_MODE_ADHOC) + else if (mode == _NM_802_11_MODE_ADHOC) g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_MODE, "adhoc", NULL); else g_assert_not_reached(); @@ -241,14 +241,14 @@ test_lock_bssid(void) src = nm_simple_connection_new(); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, TRUE, src, &error); - expected = create_basic(ssid, bssid, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, bssid, _NM_802_11_MODE_INFRA); COMPARE(src, expected, success, error, 0, 0); g_object_unref(src); @@ -273,14 +273,14 @@ test_open_ap_empty_connection(void) src = nm_simple_connection_new(); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, FALSE, src, &error); - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); COMPARE(src, expected, success, error, 0, 0); g_object_unref(src); @@ -311,7 +311,7 @@ test_open_ap_leap_connection_1(gconstpointer add_wifi) success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -345,7 +345,7 @@ test_open_ap_leap_connection_2(void) success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -383,7 +383,7 @@ test_open_ap_wep_connection(gconstpointer add_wifi) fill_wsec(src, src_wsec); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -427,7 +427,7 @@ test_ap_wpa_psk_connection_base(const char * key_mgmt, fill_wsec(src, both_wsec); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, flags, wpa_flags, rsn_flags, @@ -553,7 +553,7 @@ test_ap_wpa_eap_connection_base(const char *key_mgmt, fill_8021x(src, src_empty); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, flags, wpa_flags, rsn_flags, @@ -751,7 +751,7 @@ test_priv_ap_empty_connection(void) src = nm_simple_connection_new(); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -760,7 +760,7 @@ test_priv_ap_empty_connection(void) &error); /* Static WEP connection expected */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); COMPARE(src, expected, success, error, 0, 0); @@ -798,7 +798,7 @@ test_priv_ap_leap_connection_1(gconstpointer add_wifi) fill_wsec(src, src_wsec); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -809,7 +809,7 @@ test_priv_ap_leap_connection_1(gconstpointer add_wifi) * there's no way to determine from the AP's beacon whether it's static WEP, * dynamic WEP, or LEAP. */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); COMPARE(src, expected, success, error, 0, 0); @@ -840,7 +840,7 @@ test_priv_ap_leap_connection_2(void) fill_wsec(src, src_wsec); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -885,7 +885,7 @@ test_priv_ap_dynamic_wep_1(void) fill_8021x(src, both_8021x); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -894,7 +894,7 @@ test_priv_ap_dynamic_wep_1(void) &error); /* We expect a completed Dynamic WEP connection */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); fill_8021x(expected, both_8021x); COMPARE(src, expected, success, error, 0, 0); @@ -933,7 +933,7 @@ test_priv_ap_dynamic_wep_2(void) fill_8021x(src, both_8021x); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -942,7 +942,7 @@ test_priv_ap_dynamic_wep_2(void) &error); /* We expect a completed Dynamic WEP connection */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); fill_8021x(expected, both_8021x); COMPARE(src, expected, success, error, 0, 0); @@ -976,7 +976,7 @@ test_priv_ap_dynamic_wep_3(void) fill_8021x(src, src_8021x); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -1102,7 +1102,7 @@ test_wpa_ap_empty_connection(gconstpointer data) src = nm_simple_connection_new(); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, wpa_flags_for_idx(idx), rsn_flags_for_idx(idx), @@ -1111,7 +1111,7 @@ test_wpa_ap_empty_connection(gconstpointer data) &error); /* WPA connection expected */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); COMPARE(src, expected, success, error, 0, 0); @@ -1144,7 +1144,7 @@ test_wpa_ap_leap_connection_1(gconstpointer data) fill_wsec(src, src_wsec); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, wpa_flags_for_idx(idx), rsn_flags_for_idx(idx), @@ -1180,7 +1180,7 @@ test_wpa_ap_leap_connection_2(gconstpointer data) fill_wsec(src, src_wsec); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, wpa_flags_for_idx(idx), rsn_flags_for_idx(idx), @@ -1214,7 +1214,7 @@ test_wpa_ap_dynamic_wep_connection(gconstpointer data) fill_wsec(src, src_wsec); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, wpa_flags_for_idx(idx), rsn_flags_for_idx(idx), |