diff options
Diffstat (limited to 'src/devices/wifi')
| -rw-r--r-- | src/devices/wifi/meson.build | 6 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-iwd.c | 729 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-olpc-mesh.c | 58 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 428 | ||||
| -rw-r--r-- | src/devices/wifi/nm-iwd-manager.c | 552 | ||||
| -rw-r--r-- | src/devices/wifi/nm-iwd-manager.h | 20 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-ap.c | 122 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-ap.h | 8 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-utils.c | 56 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-utils.h | 16 | ||||
| -rw-r--r-- | src/devices/wifi/tests/test-general.c | 34 |
11 files changed, 1207 insertions, 822 deletions
diff --git a/src/devices/wifi/meson.build b/src/devices/wifi/meson.build index a27f8e6a..2745040b 100644 --- a/src/devices/wifi/meson.build +++ b/src/devices/wifi/meson.build @@ -33,10 +33,10 @@ libnm_device_plugin_wifi = shared_module( core_plugins += libnm_device_plugin_wifi -run_target( +test( 'check-local-devices-wifi', - command: [check_exports, libnm_device_plugin_wifi.full_path(), linker_script_devices], - depends: libnm_device_plugin_wifi + check_exports, + args: [libnm_device_plugin_wifi.full_path(), linker_script_devices], ) # FIXME: check_so_symbols replacement diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 7667816a..1d1be742 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -67,7 +67,8 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { GDBusObject * dbus_obj; - GDBusProxy * dbus_proxy; + GDBusProxy * dbus_device_proxy; + GDBusProxy * dbus_station_proxy; CList aps_lst_head; NMWifiAP * current_ap; GCancellable * cancellable; @@ -204,11 +205,11 @@ remove_all_aps (NMDeviceIwd *self) } static GVariant * -vardict_from_network_type (const gchar *type) +vardict_from_network_type (const char *type) { GVariantBuilder builder; - const gchar *key_mgmt = ""; - const gchar *pairwise = "ccmp"; + const char *key_mgmt = ""; + const char *pairwise = "ccmp"; if (!strcmp (type, "psk")) key_mgmt = "wpa-psk"; @@ -228,6 +229,78 @@ vardict_from_network_type (const gchar *type) } static void +insert_ap_from_network (GHashTable *aps, const char *path, int16_t signal, uint32_t ap_id) +{ + gs_unref_object GDBusProxy *network_proxy = NULL; + gs_unref_variant GVariant *name_value = NULL, *type_value = NULL; + const char *name, *type; + GVariantBuilder builder; + gs_unref_variant GVariant *props = NULL; + GVariant *rsn; + uint8_t bssid[6]; + NMWifiAP *ap; + + network_proxy = nm_iwd_manager_get_dbus_interface (nm_iwd_manager_get (), + path, + NM_IWD_NETWORK_INTERFACE); + if (!network_proxy) + return; + + name_value = g_dbus_proxy_get_cached_property (network_proxy, "Name"); + type_value = g_dbus_proxy_get_cached_property (network_proxy, "Type"); + if ( !name_value + || !g_variant_is_of_type (name_value, G_VARIANT_TYPE_STRING) + || !type_value + || !g_variant_is_of_type (type_value, G_VARIANT_TYPE_STRING)) + return; + + name = g_variant_get_string (name_value, NULL); + type = g_variant_get_string (type_value, NULL); + + /* What we get from IWD are networks, or ESSs, that may contain + * multiple APs, or BSSs, each. We don't get information about any + * specific BSSs within an ESS but we can safely present each ESS + * as an individual BSS to NM, which will be seen as ESSs comprising + * a single BSS each. NM won't be able to handle roaming but IWD + * already does that. We fake the BSSIDs as they don't play any + * role either. + */ + bssid[0] = 0x00; + bssid[1] = 0x01; + bssid[2] = 0x02; + bssid[3] = ap_id >> 16; + bssid[4] = ap_id >> 8; + bssid[5] = ap_id; + + /* WEP not supported */ + if (nm_streq (type, "wep")) + return; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&builder, "{sv}", "BSSID", + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1)); + g_variant_builder_add (&builder, "{sv}", "Mode", + g_variant_new_string ("infrastructure")); + + rsn = vardict_from_network_type (type); + if (rsn) + g_variant_builder_add (&builder, "{sv}", "RSN", rsn); + + props = g_variant_new ("a{sv}", &builder); + + ap = nm_wifi_ap_new_from_properties (path, props); + + nm_wifi_ap_set_ssid_arr (ap, + (const guint8 *) name, + NM_MIN (32, strlen (name))); + + nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100)); + nm_wifi_ap_set_freq (ap, 2417); + nm_wifi_ap_set_max_bitrate (ap, 65000); + g_hash_table_insert (aps, (gpointer) nm_wifi_ap_get_supplicant_path (ap), ap); +} + +static void get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NMDeviceIwd *self = user_data; @@ -235,75 +308,39 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) gs_free_error GError *error = NULL; gs_unref_variant GVariant *variant = NULL; GVariantIter *networks; - const gchar *path, *name, *type; + const char *path, *name, *type; int16_t signal; NMWifiAP *ap, *ap_safe, *new_ap; gboolean changed = FALSE; GHashTableIter ap_iter; gs_unref_hashtable GHashTable *new_aps = NULL; + /* Depending on whether we're using the Station interface or the Device + * interface for compatibility with IWD <= 0.7, the return signature of + * GetOrderedNetworks will be different. + */ + gboolean compat = priv->dbus_station_proxy == priv->dbus_device_proxy; + const char *return_sig = compat ? "(a(osns))" : "(a(on))"; + static uint32_t ap_id = 0; variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, - G_VARIANT_TYPE ("(a(osns))"), + G_VARIANT_TYPE (return_sig), &error); if (!variant) { - _LOGE (LOGD_WIFI, "Device.GetOrderedNetworks failed: %s", + _LOGE (LOGD_WIFI, "Station.GetOrderedNetworks failed: %s", error->message); return; } new_aps = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); - g_variant_get (variant, "(a(osns))", &networks); - - while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type)) { - GVariantBuilder builder; - gs_unref_variant GVariant *props = NULL; - GVariant *rsn; - static uint32_t ap_id = 0; - uint8_t bssid[6]; + g_variant_get (variant, return_sig, &networks); - /* - * What we get from IWD are networks, or ESSs, that may - * contain multiple APs, or BSSs, each. We don't get - * information about any specific BSSs within an ESS but - * we can safely present each ESS as an individual BSS to - * NM, which will be seen as ESSs comprising a single BSS - * each. NM won't be able to handle roaming but IWD already - * does that. We fake the BSSIDs as they don't play any - * role either. - */ - bssid[0] = 0x00; - bssid[1] = 0x01; - bssid[2] = 0x02; - bssid[3] = ap_id >> 16; - bssid[4] = ap_id >> 8; - bssid[5] = ap_id++; - - /* WEP not supported */ - if (!strcmp (type, "wep")) - continue; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&builder, "{sv}", "BSSID", - g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1)); - g_variant_builder_add (&builder, "{sv}", "Mode", - g_variant_new_string ("infrastructure")); - - rsn = vardict_from_network_type (type); - if (rsn) - g_variant_builder_add (&builder, "{sv}", "RSN", rsn); - - props = g_variant_new ("a{sv}", &builder); - - ap = nm_wifi_ap_new_from_properties (path, props); - if (name[0] != '\0') - nm_wifi_ap_set_ssid (ap, (const guint8 *) name, strlen (name)); - nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100)); - nm_wifi_ap_set_freq (ap, 2417); - nm_wifi_ap_set_max_bitrate (ap, 65000); - g_hash_table_insert (new_aps, - (gpointer) nm_wifi_ap_get_supplicant_path (ap), - ap); + if (compat) { + while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type)) + insert_ap_from_network (new_aps, path, signal, ap_id++); + } else { + while (g_variant_iter_next (networks, "(&on)", &path, &signal)) + insert_ap_from_network (new_aps, path, signal, ap_id++); } g_variant_iter_free (networks); @@ -355,7 +392,7 @@ update_aps (NMDeviceIwd *self) if (!priv->cancellable) priv->cancellable = g_cancellable_new (); - g_dbus_proxy_call (priv->dbus_proxy, "GetOrderedNetworks", + g_dbus_proxy_call (priv->dbus_station_proxy, "GetOrderedNetworks", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, 2000, priv->cancellable, get_ordered_networks_cb, self); @@ -366,7 +403,7 @@ send_disconnect (NMDeviceIwd *self) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - g_dbus_proxy_call (priv->dbus_proxy, "Disconnect", g_variant_new ("()"), + g_dbus_proxy_call (priv->dbus_station_proxy, "Disconnect", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } @@ -389,7 +426,7 @@ cleanup_association_attempt (NMDeviceIwd *self, gboolean disconnect) set_current_ap (self, NULL, TRUE); - if (disconnect && priv->dbus_obj) + if (disconnect && priv->dbus_station_proxy) send_disconnect (self); } @@ -405,7 +442,7 @@ deactivate_async_finish (NMDevice *device, GAsyncResult *res, GError **error) NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (NM_DEVICE_IWD (device)); gs_unref_variant GVariant *variant = NULL; - variant = g_dbus_proxy_call_finish (priv->dbus_proxy, res, error); + variant = g_dbus_proxy_call_finish (priv->dbus_station_proxy, res, error); return variant != NULL; } @@ -441,39 +478,18 @@ deactivate_async (NMDevice *device, ctx->callback = callback; ctx->user_data = user_data; - g_dbus_proxy_call (priv->dbus_proxy, "Disconnect", g_variant_new ("()"), + g_dbus_proxy_call (priv->dbus_station_proxy, "Disconnect", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, disconnect_cb, ctx); } -static NMIwdNetworkSecurity -get_connection_iwd_security (NMConnection *connection) -{ - NMSettingWirelessSecurity *s_wireless_sec; - const char *key_mgmt = NULL; - - s_wireless_sec = nm_connection_get_setting_wireless_security (connection); - if (!s_wireless_sec) - return NM_IWD_NETWORK_SECURITY_NONE; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); - nm_assert (key_mgmt); - - if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x")) - return NM_IWD_NETWORK_SECURITY_WEP; - - if (!strcmp (key_mgmt, "wpa-psk")) - return NM_IWD_NETWORK_SECURITY_PSK; - - nm_assert (!strcmp (key_mgmt, "wpa-eap")); - return NM_IWD_NETWORK_SECURITY_8021X; -} - static gboolean is_connection_known_network (NMConnection *connection) { NMSettingWireless *s_wireless; + NMIwdNetworkSecurity security; + gboolean security_ok; GBytes *ssid; - gs_free gchar *str_ssid = NULL; + gs_free char *ssid_utf8 = NULL; s_wireless = nm_connection_get_setting_wireless (connection); if (!s_wireless) @@ -483,68 +499,73 @@ is_connection_known_network (NMConnection *connection) if (!ssid) return FALSE; - str_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); + + security = nm_wifi_connection_get_iwd_security (connection, &security_ok); + if (!security_ok) + return FALSE; return nm_iwd_manager_is_known_network (nm_iwd_manager_get (), - str_ssid, - get_connection_iwd_security (connection)); + ssid_utf8, security); } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMSettingConnection *s_con; NMSettingWireless *s_wireless; const char *mac; const char * const *mac_blacklist; int i; - const char *mode; const char *perm_hw_addr; - if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return FALSE; perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wireless_get_mac_address (s_wireless); if (perm_hw_addr) { - if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) + if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device MAC address does not match the profile"); return FALSE; + } /* Check for MAC address blacklist */ mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); - return FALSE; - } + nm_assert (nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)); - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MAC address blacklisted"); return FALSE; + } } - } else if (mac) + } else if (mac) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no valid MAC address as required by profile"); return FALSE; + } - mode = nm_setting_wireless_get_mode (s_wireless); - if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) + if (!NM_IN_STRSET (nm_setting_wireless_get_mode (s_wireless), + NULL, + NM_SETTING_WIRELESS_MODE_INFRA)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IWD only support infrastructure type profiles"); return FALSE; + } /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) + if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { + if (!is_connection_known_network (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "802.1x profile is not a known network"); return FALSE; + } } return TRUE; @@ -554,7 +575,8 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); @@ -566,19 +588,28 @@ check_connection_available (NMDevice *device, /* Only Infrastrusture mode at this time */ mode = nm_setting_wireless_get_mode (s_wifi); - if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) + if (!NM_IN_STRSET (mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "iwd only supports infrastructure mode connections"); return FALSE; + } /* Hidden SSIDs not supported yet */ - if (nm_setting_wireless_get_hidden (s_wifi)) + if (nm_setting_wireless_get_hidden (s_wifi)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "hidden networks not supported by iwd"); return FALSE; + } /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) + if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { + if (!is_connection_known_network (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "network is not known to iwd"); return FALSE; + } } /* a connection that is available for a certain @specific_object, MUST @@ -588,14 +619,29 @@ check_connection_available (NMDevice *device, NMWifiAP *ap; ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); - return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE; + if (!ap) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point not found"); + return FALSE; + } + if (!nm_wifi_ap_check_compatible (ap, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point is not compatible with profile"); + return FALSE; + } + return TRUE; } if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; - /* Check at least one AP is compatible with this connection */ - return !!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + if (!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "no compatible access point found"); + return FALSE; + } + + return TRUE; } static gboolean @@ -609,10 +655,9 @@ complete_connection (NMDevice *device, NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMSettingWireless *s_wifi; const char *setting_mac; - char *str_ssid = NULL; + gs_free char *ssid_utf8 = NULL; NMWifiAP *ap; - const GByteArray *ssid = NULL; - GByteArray *tmp_ssid = NULL; + GBytes *ssid; GBytes *setting_ssid = NULL; const char *perm_hw_addr; const char *mode; @@ -676,8 +721,7 @@ complete_connection (NMDevice *device, } ssid = nm_wifi_ap_get_ssid (ap); - - if (ssid == NULL) { + if (!ssid) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, @@ -688,30 +732,23 @@ complete_connection (NMDevice *device, if (!nm_wifi_ap_complete_connection (ap, connection, nm_wifi_utils_is_manf_default_ssid (ssid), - error)) { - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); + error)) return FALSE; - } - - str_ssid = nm_utils_ssid_to_utf8 (ssid->data, ssid->len); + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_WIRELESS_SETTING_NAME, existing_connections, - str_ssid, - str_ssid, + ssid_utf8, + ssid_utf8, NULL, TRUE); - g_free (str_ssid); - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { + if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { if (!is_connection_known_network (connection)) { g_set_error_literal (error, NM_CONNECTION_ERROR, @@ -753,17 +790,38 @@ complete_connection (NMDevice *device, } static gboolean +get_variant_boolean (GVariant *v, const char *property) +{ + if (!v || !g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)) { + nm_log_warn (LOGD_DEVICE | LOGD_WIFI, + "Property %s not cached or not boolean type", property); + + return FALSE; + } + + return g_variant_get_boolean (v); +} + +static const char * +get_variant_state (GVariant *v) +{ + if (!v || !g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)) { + nm_log_warn (LOGD_DEVICE | LOGD_WIFI, + "State property not cached or not a string"); + + return "unknown"; + } + + return g_variant_get_string (v, NULL); +} + +static gboolean is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - gs_unref_variant GVariant *value = NULL; - - if (!priv->enabled || !priv->dbus_obj) - return FALSE; - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Powered"); - return g_variant_get_boolean (value); + return priv->enabled && priv->dbus_station_proxy; } static gboolean @@ -777,11 +835,12 @@ get_autoconnect_allowed (NMDevice *device) static gboolean can_auto_connect (NMDevice *device, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + NMConnection *connection; NMSettingWireless *s_wifi; NMWifiAP *ap; const char *mode; @@ -789,9 +848,11 @@ can_auto_connect (NMDevice *device, nm_assert (!specific_object || !*specific_object); - if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->can_auto_connect (device, connection, NULL)) + if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->can_auto_connect (device, sett_conn, NULL)) return FALSE; + connection = nm_settings_connection_get_connection (sett_conn); + s_wifi = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wifi, FALSE); @@ -804,7 +865,7 @@ can_auto_connect (NMDevice *device, * but haven't been successful, since these are often accidental choices * from the menu and the user may not know the password. */ - if (nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (connection), ×tamp)) { + if (nm_settings_connection_get_timestamp (sett_conn, ×tamp)) { if (timestamp == 0) return FALSE; } @@ -812,7 +873,7 @@ can_auto_connect (NMDevice *device, /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { + if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { if (!is_connection_known_network (connection)) return FALSE; } @@ -897,8 +958,7 @@ dbus_request_scan_cb (NMDevice *device, priv = NM_DEVICE_IWD_GET_PRIVATE (self); - if ( !priv->enabled - || !priv->dbus_obj + if ( !priv->can_scan || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED || nm_device_is_activating (device)) { g_dbus_method_invocation_return_error_literal (context, @@ -921,7 +981,7 @@ dbus_request_scan_cb (NMDevice *device, } if (!priv->scanning && !priv->scan_requested) { - g_dbus_proxy_call (priv->dbus_proxy, "Scan", + g_dbus_proxy_call (priv->dbus_station_proxy, "Scan", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, priv->cancellable, scan_cb, self); @@ -939,8 +999,7 @@ _nm_device_iwd_request_scan (NMDeviceIwd *self, NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); - if ( !priv->enabled - || !priv->dbus_obj + if ( !priv->can_scan || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED || nm_device_is_activating (device)) { g_dbus_method_invocation_return_error_literal (invocation, @@ -1005,11 +1064,11 @@ static gboolean try_reply_agent_request (NMDeviceIwd *self, NMConnection *connection, GDBusMethodInvocation *invocation, - const gchar **setting_name, - const gchar **setting_key, + const char **setting_name, + const char **setting_key, gboolean *replied) { - const gchar *method_name = g_dbus_method_invocation_get_method_name (invocation); + const char *method_name = g_dbus_method_invocation_get_method_name (invocation); NMSettingWirelessSecurity *s_wireless_sec; NMSetting8021x *s_8021x; @@ -1019,7 +1078,7 @@ try_reply_agent_request (NMDeviceIwd *self, *replied = FALSE; if (!strcmp (method_name, "RequestPassphrase")) { - const gchar *psk; + const char *psk; if (!s_wireless_sec) return FALSE; @@ -1039,7 +1098,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_key = NM_SETTING_WIRELESS_SECURITY_PSK; return TRUE; } else if (!strcmp (method_name, "RequestPrivateKeyPassphrase")) { - const gchar *password; + const char *password; if (!s_8021x) return FALSE; @@ -1059,7 +1118,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD; return TRUE; } else if (!strcmp (method_name, "RequestUserNameAndPassword")) { - const gchar *identity, *password; + const char *identity, *password; if (!s_8021x) return FALSE; @@ -1083,7 +1142,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_key = NM_SETTING_802_1X_PASSWORD; return TRUE; } else if (!strcmp (method_name, "RequestUserPassword")) { - const gchar *password; + const char *password; if (!s_8021x) return FALSE; @@ -1124,8 +1183,8 @@ wifi_secrets_cb (NMActRequest *req, NMDeviceIwdPrivate *priv; NMDevice *device; GDBusMethodInvocation *invocation; - const gchar *setting_name; - const gchar *setting_key; + const char *setting_name; + const char *setting_key; gboolean replied; NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; @@ -1182,12 +1241,7 @@ secrets_error: g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "NM secrets request failed"); - - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - - cleanup_association_attempt (self, TRUE); + /* Now wait for the Connect callback to update device state */ } static void @@ -1219,16 +1273,19 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NMDeviceIwd *self = user_data; NMDevice *device = NM_DEVICE (self); + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); gs_free_error GError *error = NULL; NMConnection *connection; NMSettingWireless *s_wifi; GBytes *ssid; - gs_free gchar *str_ssid = NULL; + gs_free char *ssid_utf8 = NULL; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED; + GVariant *value; if (!_nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, G_VARIANT_TYPE ("()"), &error)) { - gs_free gchar *dbus_error = NULL; + gs_free char *dbus_error = NULL; /* Connection failed; radio problems or if the network wasn't * open, the passwords or certificates may be wrong. @@ -1238,6 +1295,12 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) "Activation: (wifi) Network.Connect failed: %s", error->message); + if (nm_utils_error_is_cancelled (error, TRUE)) + return; + + if (!NM_IN_SET (nm_device_get_state (device), NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_NEED_AUTH)) + return; + connection = nm_device_get_applied_connection (device); if (!connection) goto failed; @@ -1245,20 +1308,17 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) dbus_error = g_dbus_error_get_remote_error (error); - /* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */ if (nm_streq0 (dbus_error, "net.connman.iwd.Failed")) { nm_connection_clear_secrets (connection); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } else if ( !nm_utils_error_is_cancelled (error, TRUE) - && nm_device_is_activating (device)) - goto failed; - - /* Call Disconnect to make sure IWD's autoconnect is disabled */ - cleanup_association_attempt (self, TRUE); + /* 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")) { + /* If agent call was cancelled we'd be getting a net.connman.iwd.Aborted */ + reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + } - return; + goto failed; } nm_assert (nm_device_get_state (device) == NM_DEVICE_STATE_CONFIG); @@ -1275,23 +1335,27 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) if (!ssid) goto failed; - str_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); _LOGI (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. Connected to '%s'.", - str_ssid); + ssid_utf8); nm_device_activate_schedule_stage3_ip_config_start (device); - nm_iwd_manager_network_connected (nm_iwd_manager_get (), str_ssid, - get_connection_iwd_security (connection)); - return; failed: - cleanup_association_attempt (self, FALSE); - nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + /* Call Disconnect to make sure IWD's autoconnect is disabled */ + cleanup_association_attempt (self, TRUE); + + nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, reason); + + value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "State"); + if (!priv->can_connect && nm_streq0 (get_variant_state (value), "disconnected")) { + priv->can_connect = true; + nm_device_emit_recheck_auto_activate (device); + } + g_variant_unref (value); } static void @@ -1299,7 +1363,7 @@ set_powered (NMDeviceIwd *self, gboolean powered) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - g_dbus_proxy_call (priv->dbus_proxy, + g_dbus_proxy_call (priv->dbus_device_proxy, "org.freedesktop.DBus.Properties.Set", g_variant_new ("(ssv)", NM_IWD_DEVICE_INTERFACE, "Powered", @@ -1361,7 +1425,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMActRequest *req; NMWifiAP *ap; NMConnection *connection; - GError *error = NULL; GDBusProxy *network_proxy; req = nm_device_get_act_request (device); @@ -1391,21 +1454,13 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) goto out; } - /* Locate the IWD Network object */ - network_proxy = g_dbus_proxy_new_for_bus_sync (NM_IWD_BUS_TYPE, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - NM_IWD_SERVICE, - nm_wifi_ap_get_supplicant_path (ap), - NM_IWD_NETWORK_INTERFACE, - NULL, &error); + network_proxy = nm_iwd_manager_get_dbus_interface (nm_iwd_manager_get (), + nm_wifi_ap_get_supplicant_path (ap), + NM_IWD_NETWORK_INTERFACE); if (!network_proxy) { _LOGE (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) could not get Network interface proxy for %s: %s", - nm_wifi_ap_get_supplicant_path (ap), - error->message); - g_clear_error (&error); + "Activation: (wifi) could not get Network interface proxy for %s", + nm_wifi_ap_get_supplicant_path (ap)); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); goto out; } @@ -1452,7 +1507,7 @@ periodic_scan_timeout_cb (gpointer user_data) if (priv->scanning || priv->scan_requested) return FALSE; - g_dbus_proxy_call (priv->dbus_proxy, "Scan", g_variant_new ("()"), + g_dbus_proxy_call (priv->dbus_station_proxy, "Scan", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, priv->cancellable, scan_cb, self); priv->scan_requested = TRUE; @@ -1506,7 +1561,7 @@ device_state_changed (NMDevice *device, * transition to DISCONNECTED because the device is now * ready to use. */ - if (priv->enabled && priv->dbus_obj) { + if (priv->enabled && priv->dbus_station_proxy) { nm_device_queue_recheck_available (device, NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); @@ -1556,17 +1611,18 @@ set_enabled (NMDevice *device, gboolean enabled) return; } - if (priv->dbus_proxy) + if (priv->dbus_obj) set_powered (self, enabled); if (enabled) { if (state != NM_DEVICE_STATE_UNAVAILABLE) _LOGW (LOGD_CORE, "not in expected unavailable state!"); - if (priv->dbus_obj) + if (priv->dbus_station_proxy) { nm_device_queue_recheck_available (device, NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + } } else { nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE, @@ -1667,7 +1723,7 @@ set_property (GObject *object, guint prop_id, /*****************************************************************************/ static void -state_changed (NMDeviceIwd *self, const gchar *new_state) +state_changed (NMDeviceIwd *self, const char *new_state) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); @@ -1684,13 +1740,6 @@ state_changed (NMDeviceIwd *self, const gchar *new_state) /* Don't allow scanning while connecting, disconnecting or roaming */ priv->can_scan = NM_IN_STRSET (new_state, "connected", "disconnected"); - /* Don't allow new connection until iwd exits disconnecting */ - can_connect = NM_IN_STRSET (new_state, "disconnected"); - if (can_connect != priv->can_connect) { - priv->can_connect = can_connect; - nm_device_emit_recheck_auto_activate (device); - } - if (NM_IN_STRSET (new_state, "connecting", "connected", "roaming")) { /* If we were connecting, do nothing, the confirmation of * a connection success is handled in the Device.Connect @@ -1704,39 +1753,39 @@ state_changed (NMDeviceIwd *self, const gchar *new_state) _LOGW (LOGD_DEVICE | LOGD_WIFI, "Unsolicited connection success, asking IWD to disconnect"); send_disconnect (self); - - return; } else if (NM_IN_STRSET (new_state, "disconnecting", "disconnected")) { - if (!iwd_connection) - return; - /* Call Disconnect on the IWD device object to make sure it * disables its own autoconnect. - * - * Note we could instead call net.connman.iwd.KnownNetworks.ForgetNetwork - * and leave the device in autoconnect. This way if NetworkManager - * changes any settings for this connection, they'd be taken into - * account on the next connection attempt. But both methods are - * a hack, we'll perhaps need an IWD API to "connect once" without - * storing anything. */ send_disconnect (self); /* - * If IWD is still handling the Connect call, let our callback - * for the dbus method handle the failure. + * If IWD is still handling the Connect call, let our Connect + * callback for the dbus method handle the failure. The main + * reason we can't handle the failure here is because the method + * callback will have more information on the specific failure + * reason. */ if (dev_state == NM_DEVICE_STATE_CONFIG) return; - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - + if (iwd_connection) + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + } else if (!nm_streq (new_state, "unknown")) { + _LOGE (LOGD_WIFI, "State %s unknown", new_state); return; } - _LOGE (LOGD_WIFI, "State %s unknown", new_state); + /* Don't allow new connection until iwd exits disconnecting and no + * Connect callback is pending. + */ + can_connect = NM_IN_STRSET (new_state, "disconnected"); + if (can_connect != priv->can_connect) { + priv->can_connect = can_connect; + nm_device_emit_recheck_auto_activate (device); + } } static void @@ -1761,32 +1810,112 @@ scanning_changed (NMDeviceIwd *self, gboolean new_scanning) } static void +station_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, + GStrv invalidate_properties, gpointer user_data) +{ + NMDeviceIwd *self = user_data; + GVariantIter *iter; + const char *key; + GVariant *value; + + g_variant_get (changed_properties, "a{sv}", &iter); + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { + if (!strcmp (key, "State")) + state_changed (self, get_variant_state (value)); + + if (!strcmp (key, "Scanning")) + scanning_changed (self, get_variant_boolean (value, "Scanning")); + + g_variant_unref (value); + } + + g_variant_iter_free (iter); +} + +static void powered_changed (NMDeviceIwd *self, gboolean new_powered) { + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + nm_device_queue_recheck_available (NM_DEVICE (self), NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + + if (new_powered) { + GDBusInterface *interface; + GVariant *value; + + if (priv->dbus_station_proxy) + return; + + interface = g_dbus_object_get_interface (priv->dbus_obj, NM_IWD_STATION_INTERFACE); + if (!interface) { + /* No Station interface on the device object. Check if the + * "State" property is present on the Device interface, that + * would mean we're dealing with an IWD version from before the + * Device/Station split (0.7 or earlier) and we can easily + * handle that by making priv->dbus_device_proxy and + * priv->dbus_station_proxy both point at the Device interface. + */ + value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "State"); + if (!value) { + _LOGE (LOGD_WIFI, "Interface %s not found on obj %s", + NM_IWD_STATION_INTERFACE, + g_dbus_object_get_object_path (priv->dbus_obj)); + return; + } + + g_variant_unref (value); + interface = g_object_ref (priv->dbus_device_proxy); + } + + priv->dbus_station_proxy = G_DBUS_PROXY (interface); + + value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "Scanning"); + priv->scanning = get_variant_boolean (value, "Scanning"); + g_variant_unref (value); + + value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "State"); + state_changed (self, get_variant_state (value)); + g_variant_unref (value); + + g_signal_connect (priv->dbus_station_proxy, "g-properties-changed", + G_CALLBACK (station_properties_changed), self); + + /* Call Disconnect to make sure IWD's autoconnect is disabled. + * Autoconnect is the default state after device is brought UP. + */ + if (priv->enabled) + send_disconnect (self); + } else { + if (!priv->dbus_station_proxy) + return; + + g_signal_handlers_disconnect_by_func (priv->dbus_station_proxy, + station_properties_changed, self); + g_clear_object (&priv->dbus_station_proxy); + + priv->can_scan = FALSE; + priv->scanning = FALSE; + priv->scan_requested = FALSE; + priv->can_connect = FALSE; + cleanup_association_attempt (self, FALSE); + } } static void -properties_changed (GDBusProxy *proxy, GVariant *changed_properties, - GStrv invalidate_properties, gpointer user_data) +device_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, + GStrv invalidate_properties, gpointer user_data) { NMDeviceIwd *self = user_data; GVariantIter *iter; - const gchar *key; + const char *key; GVariant *value; g_variant_get (changed_properties, "a{sv}", &iter); while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { - if (!strcmp (key, "State")) - state_changed (self, g_variant_get_string (value, NULL)); - - if (!strcmp (key, "Scanning")) - scanning_changed (self, g_variant_get_boolean (value)); - if (!strcmp (key, "Powered")) - powered_changed (self, g_variant_get_boolean (value)); + powered_changed (self, get_variant_boolean (value, "Powered")); g_variant_unref (value); } @@ -1800,51 +1929,50 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); GDBusInterface *interface; GVariant *value; + gboolean powered; if (!nm_g_object_ref_set ((GObject **) &priv->dbus_obj, (GObject *) object)) return; - if (priv->dbus_proxy) { - g_signal_handlers_disconnect_by_func (priv->dbus_proxy, - properties_changed, self); - - g_clear_object (&priv->dbus_proxy); - } - - if (priv->enabled) + if (priv->enabled && priv->dbus_station_proxy) { nm_device_queue_recheck_available (NM_DEVICE (self), NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + } - if (!object) { - priv->can_scan = FALSE; + if (priv->dbus_device_proxy) { + g_signal_handlers_disconnect_by_func (priv->dbus_device_proxy, + device_properties_changed, self); + g_clear_object (&priv->dbus_device_proxy); - cleanup_association_attempt (self, FALSE); - return; + powered_changed (self, FALSE); } - interface = g_dbus_object_get_interface (object, NM_IWD_DEVICE_INTERFACE); - priv->dbus_proxy = G_DBUS_PROXY (interface); + if (!object) + return; - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Scanning"); - priv->scanning = g_variant_get_boolean (value); - g_variant_unref (value); - priv->scan_requested = FALSE; + interface = g_dbus_object_get_interface (object, NM_IWD_DEVICE_INTERFACE); + if (!interface) { + _LOGE (LOGD_WIFI, "Interface %s not found on obj %s", + NM_IWD_DEVICE_INTERFACE, + g_dbus_object_get_object_path (object)); + g_clear_object (&priv->dbus_obj); + return; + } - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "State"); - state_changed (self, g_variant_get_string (value, NULL)); - g_variant_unref (value); + priv->dbus_device_proxy = G_DBUS_PROXY (interface); - g_signal_connect (priv->dbus_proxy, "g-properties-changed", - G_CALLBACK (properties_changed), self); + g_signal_connect (priv->dbus_device_proxy, "g-properties-changed", + G_CALLBACK (device_properties_changed), self); - set_powered (self, priv->enabled); + value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "Powered"); + powered = get_variant_boolean (value, "Powered"); + g_variant_unref (value); - /* Call Disconnect to make sure IWD's autoconnect is disabled. - * Autoconnect is the default state after device is brought UP. - */ - if (priv->enabled) - send_disconnect (self); + if (powered != priv->enabled) + set_powered (self, priv->enabled); + else if (powered) + powered_changed (self, TRUE); } gboolean @@ -1852,8 +1980,8 @@ nm_device_iwd_agent_query (NMDeviceIwd *self, GDBusMethodInvocation *invocation) { NMActRequest *req; - const gchar *setting_name; - const gchar *setting_key; + const char *setting_name; + const char *setting_key; gboolean replied; NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; @@ -1937,7 +2065,8 @@ dispose (GObject *object) cleanup_association_attempt (self, TRUE); - g_clear_object (&priv->dbus_proxy); + g_clear_object (&priv->dbus_device_proxy); + g_clear_object (&priv->dbus_station_proxy); g_clear_object (&priv->dbus_obj); remove_all_aps (self); @@ -1952,9 +2081,7 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; object_class->set_property = set_property; @@ -1962,25 +2089,29 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); - parent_class->can_auto_connect = can_auto_connect; - parent_class->is_available = is_available; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->get_enabled = get_enabled; - parent_class->set_enabled = set_enabled; - parent_class->get_type_description = get_type_description; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->deactivate = deactivate; - parent_class->deactivate_async = deactivate_async; - parent_class->deactivate_async_finish = deactivate_async_finish; - parent_class->can_reapply_change = can_reapply_change; - - parent_class->state_changed = device_state_changed; + device_class->connection_type_supported = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIFI); + + device_class->can_auto_connect = can_auto_connect; + device_class->is_available = is_available; + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->get_enabled = get_enabled; + device_class->set_enabled = set_enabled; + device_class->get_type_description = get_type_description; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->deactivate = deactivate; + device_class->deactivate_async = deactivate_async; + device_class->deactivate_async_finish = deactivate_async_finish; + device_class->can_reapply_change = can_reapply_change; + + device_class->state_changed = device_state_changed; klass->scanning_prohibited = scanning_prohibited; diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index fd7bf3f7..9ae81139 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -80,28 +80,6 @@ G_DEFINE_TYPE (NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE) /*****************************************************************************/ static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingConnection *s_con; - NMSettingOlpcMesh *s_mesh; - - if (!NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) - return FALSE; - - s_mesh = nm_connection_get_setting_olpc_mesh (connection); - if (!s_mesh) - return FALSE; - - return TRUE; -} - -static gboolean get_autoconnect_allowed (NMDevice *device) { return FALSE; @@ -117,7 +95,6 @@ complete_connection (NMDevice *device, GError **error) { NMSettingOlpcMesh *s_mesh; - GByteArray *tmp; s_mesh = nm_connection_get_setting_olpc_mesh (connection); if (!s_mesh) { @@ -126,10 +103,10 @@ complete_connection (NMDevice *device, } if (!nm_setting_olpc_mesh_get_ssid (s_mesh)) { - tmp = g_byte_array_sized_new (strlen (DEFAULT_SSID)); - g_byte_array_append (tmp, (const guint8 *) DEFAULT_SSID, strlen (DEFAULT_SSID)); - g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_SSID, tmp, NULL); - g_byte_array_free (tmp, TRUE); + gs_unref_bytes GBytes *ssid = NULL; + + ssid = g_bytes_new_static (DEFAULT_SSID, NM_STRLEN (DEFAULT_SSID)); + g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_SSID, ssid, NULL); } if (!nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh)) { @@ -302,7 +279,7 @@ companion_state_changed_cb (NMDeviceWifi *companion, } static gboolean -companion_scan_prohibited_cb (NMDeviceWifi *companion, gpointer user_data) +companion_scan_prohibited_cb (NMDeviceWifi *companion, gboolean periodic, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); @@ -369,7 +346,7 @@ device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data) nm_device_queue_recheck_available (NM_DEVICE (self), NM_DEVICE_STATE_REASON_NONE, NM_DEVICE_STATE_REASON_NONE); - nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_COMPANION, TRUE); + nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_COMPANION, FALSE); } } @@ -515,9 +492,7 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_OLPC_MESH_SETTING_NAME, NM_LINK_TYPE_OLPC_MESH) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->get_property = get_property; @@ -525,14 +500,17 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_olpc_mesh); - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->complete_connection = complete_connection; - parent_class->is_available = is_available; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->state_changed = state_changed; - parent_class->get_dhcp_timeout = get_dhcp_timeout; + device_class->connection_type_supported = NM_SETTING_OLPC_MESH_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OLPC_MESH_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_OLPC_MESH); + + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->complete_connection = complete_connection; + device_class->is_available = is_available; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->state_changed = state_changed; + device_class->get_dhcp_timeout = get_dhcp_timeout; obj_properties[PROP_COMPANION] = g_param_spec_string (NM_DEVICE_OLPC_MESH_COMPANION, "", "", diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 0dd6fa74..2ce84618 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -96,6 +96,7 @@ typedef struct { bool requested_scan:1; bool ssid_found:1; bool is_scanning:1; + bool hidden_probe_scan_warn:1; gint64 last_scan; /* milliseconds */ gint32 scheduled_scan_time; /* seconds */ @@ -121,6 +122,8 @@ typedef struct { gint32 hw_addr_scan_expire; guint wps_timeout_id; + + NMSettingWirelessWakeOnWLan wowlan_restore; } NMDeviceWifiPrivate; struct _NMDeviceWifi @@ -436,7 +439,7 @@ periodic_update (NMDeviceWifi *self) percent = nm_platform_wifi_get_quality (nm_device_get_platform (NM_DEVICE (self)), ifindex); if (percent >= 0 || ++priv->invalid_strength_counter > 3) { if (nm_wifi_ap_set_strength (priv->current_ap, (gint8) percent)) { -#ifdef NM_MORE_LOGGING +#if NM_MORE_LOGGING _ap_dump (self, LOGL_TRACE, priv->current_ap, "updated", 0); #endif } @@ -508,6 +511,22 @@ remove_all_aps (NMDeviceWifi *self) nm_device_recheck_available_connections (NM_DEVICE (self)); } +static gboolean +wake_on_wlan_restore (NMDeviceWifi *self) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMSettingWirelessWakeOnWLan w; + + w = priv->wowlan_restore; + if (w == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) + return TRUE; + + 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); +} + static void deactivate (NMDevice *device) { @@ -524,6 +543,9 @@ deactivate (NMDevice *device) set_current_ap (self, NULL, TRUE); + if (!wake_on_wlan_restore (self)) + _LOGW (LOGD_DEVICE | LOGD_WIFI, "Cannot unconfigure WoWLAN."); + /* Clear any critical protocol notification in the Wi-Fi stack */ nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), ifindex, FALSE); @@ -583,11 +605,10 @@ is_adhoc_wpa (NMConnection *connection) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMSettingConnection *s_con; NMSettingWireless *s_wireless; const char *mac; const char * const *mac_blacklist; @@ -595,24 +616,19 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char *mode; const char *perm_hw_addr; - if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return FALSE; perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wireless_get_mac_address (s_wireless); if (perm_hw_addr) { - if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) + if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device MAC address does not match the profile"); return FALSE; + } /* Check for MAC address blacklist */ mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); @@ -622,27 +638,45 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; } - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MAC address blacklisted"); return FALSE; + } } - } else if (mac) + } else if (mac) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no valid MAC address as required by profile"); return FALSE; + } - if (is_adhoc_wpa (connection)) + if (is_adhoc_wpa (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "Ad-Hoc WPA networks are not supported"); return FALSE; + } /* 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"); return FALSE; + } if (priv->sup_iface) { - if (nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) + if (nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "wpa_supplicant does not support Access Point mode"); return FALSE; + } } } @@ -657,7 +691,8 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -674,7 +709,17 @@ check_connection_available (NMDevice *device, NMWifiAP *ap; ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); - return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE; + if (!ap) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point not found"); + return FALSE; + } + if (!nm_wifi_ap_check_compatible (ap, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point is not compatible with profile"); + return FALSE; + } + return TRUE; } /* Ad-Hoc and AP connections are always available because they may be @@ -693,11 +738,17 @@ check_connection_available (NMDevice *device, * activating but the network isn't available let the device recheck * availability. */ - if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) + if ( nm_setting_wireless_get_hidden (s_wifi) + || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; - /* check at least one AP is compatible with this connection */ - return !!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + if (!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "no compatible access point found"); + return FALSE; + } + + return TRUE; } static gboolean @@ -711,10 +762,9 @@ complete_connection (NMDevice *device, NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; const char *setting_mac; - char *str_ssid = NULL; + gs_free char *ssid_utf8 = NULL; NMWifiAP *ap; - const GByteArray *ssid = NULL; - GByteArray *tmp_ssid = NULL; + GBytes *ssid = NULL; GBytes *setting_ssid = NULL; gboolean hidden = FALSE; const char *perm_hw_addr; @@ -786,19 +836,14 @@ complete_connection (NMDevice *device, if (ap) ssid = nm_wifi_ap_get_ssid (ap); + if (ssid == NULL) { /* The AP must be hidden. Connecting to a WiFi AP requires the SSID * as part of the initial handshake, so check the connection details * for the SSID. The AP object will still be used for encryption * settings and such. */ - setting_ssid = nm_setting_wireless_get_ssid (s_wifi); - if (setting_ssid) { - ssid = tmp_ssid = g_byte_array_new (); - g_byte_array_append (tmp_ssid, - g_bytes_get_data (setting_ssid, NULL), - g_bytes_get_size (setting_ssid)); - } + ssid = nm_setting_wireless_get_ssid (s_wifi); } if (ssid == NULL) { @@ -821,11 +866,8 @@ complete_connection (NMDevice *device, if (!nm_wifi_ap_complete_connection (ap, connection, nm_wifi_utils_is_manf_default_ssid (ssid), - error)) { - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); + error)) return FALSE; - } } /* The kernel doesn't support Ad-Hoc WPA connections well at this time, @@ -838,24 +880,18 @@ complete_connection (NMDevice *device, NM_CONNECTION_ERROR_INVALID_SETTING, _("WPA Ad-Hoc disabled due to kernel bugs")); g_prefix_error (error, "%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); return FALSE; } - str_ssid = nm_utils_ssid_to_utf8 (ssid->data, ssid->len); - + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_WIRELESS_SETTING_NAME, existing_connections, - str_ssid, - str_ssid, + ssid_utf8, + ssid_utf8, NULL, TRUE); - g_free (str_ssid); - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); if (hidden) g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); @@ -923,11 +959,12 @@ get_autoconnect_allowed (NMDevice *device) static gboolean can_auto_connect (NMDevice *device, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMConnection *connection; NMSettingWireless *s_wifi; NMWifiAP *ap; const char *method, *mode; @@ -935,26 +972,28 @@ can_auto_connect (NMDevice *device, nm_assert (!specific_object || !*specific_object); - if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->can_auto_connect (device, connection, NULL)) + if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->can_auto_connect (device, sett_conn, NULL)) return FALSE; + connection = nm_settings_connection_get_connection (sett_conn); + s_wifi = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wifi, FALSE); /* Always allow autoconnect for AP and non-autoconf Ad-Hoc */ method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); mode = nm_setting_wireless_get_mode (s_wifi); - if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0) + if (nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_AP)) return TRUE; - else if ( g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0 - && g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) != 0) + else if ( nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) + && !nm_streq0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) return TRUE; /* Don't autoconnect to networks that have been tried at least once * but haven't been successful, since these are often accidental choices * from the menu and the user may not know the password. */ - if (nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (connection), ×tamp)) { + if (nm_settings_connection_get_timestamp (sett_conn, ×tamp)) { if (timestamp == 0) return FALSE; } @@ -1033,7 +1072,6 @@ static GPtrArray * ssids_options_to_ptrarray (GVariant *value, GError **error) { GPtrArray *ssids = NULL; - GByteArray *ssid_array; GVariant *v; const guint8 *bytes; gsize len; @@ -1049,7 +1087,7 @@ ssids_options_to_ptrarray (GVariant *value, GError **error) } if (num_ssids) { - ssids = g_ptr_array_new_full (num_ssids, (GDestroyNotify) g_byte_array_unref); + ssids = g_ptr_array_new_full (num_ssids, (GDestroyNotify) g_bytes_unref); for (i = 0; i < num_ssids; i++) { v = g_variant_get_child_value (value, i); bytes = g_variant_get_fixed_array (v, &len, sizeof (guint8)); @@ -1062,9 +1100,7 @@ ssids_options_to_ptrarray (GVariant *value, GError **error) return NULL; } - ssid_array = g_byte_array_new (); - g_byte_array_append (ssid_array, bytes, len); - g_ptr_array_add (ssids, ssid_array); + g_ptr_array_add (ssids, g_bytes_new (bytes, len)); } } return ssids; @@ -1232,14 +1268,15 @@ check_scanning_prohibited (NMDeviceWifi *self, gboolean periodic) static gboolean hidden_filter_func (NMSettings *settings, - NMSettingsConnection *connection, + NMSettingsConnection *set_con, gpointer user_data) { + NMConnection *connection = nm_settings_connection_get_connection (set_con); NMSettingWireless *s_wifi; - if (!nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_WIRELESS_SETTING_NAME)) + if (!nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME)) return FALSE; - s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (connection)); + s_wifi = nm_connection_get_setting_wireless (connection); if (!s_wifi) return FALSE; if (nm_streq0 (nm_setting_wireless_get_mode (s_wifi), NM_SETTING_WIRELESS_MODE_AP)) @@ -1255,7 +1292,7 @@ build_hidden_probe_list (NMDeviceWifi *self) gs_free NMSettingsConnection **connections = NULL; guint i, len; GPtrArray *ssids = NULL; - static GByteArray *nullssid = NULL; + static GBytes *nullssid = NULL; /* Need at least two: wildcard SSID and one or more hidden SSIDs */ if (max_scan_ssids < 2) @@ -1270,30 +1307,23 @@ build_hidden_probe_list (NMDeviceWifi *self) g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_timestamp_p_with_data, NULL); - ssids = g_ptr_array_new_full (max_scan_ssids, (GDestroyNotify) g_byte_array_unref); + ssids = g_ptr_array_new_full (max_scan_ssids, (GDestroyNotify) g_bytes_unref); /* Add wildcard SSID using a static wildcard SSID used for every scan */ if (G_UNLIKELY (nullssid == NULL)) - nullssid = g_byte_array_new (); - g_ptr_array_add (ssids, g_byte_array_ref (nullssid)); + nullssid = g_bytes_new_static ("", 0); + g_ptr_array_add (ssids, g_bytes_ref (nullssid)); for (i = 0; connections[i]; i++) { NMSettingWireless *s_wifi; GBytes *ssid; - GByteArray *ssid_array; if (i >= max_scan_ssids - 1) break; - s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (NM_CONNECTION (connections[i])); - g_assert (s_wifi); + s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (nm_settings_connection_get_connection (connections[i])); ssid = nm_setting_wireless_get_ssid (s_wifi); - g_assert (ssid); - ssid_array = g_byte_array_new (); - g_byte_array_append (ssid_array, - g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); - g_ptr_array_add (ssids, ssid_array); + g_ptr_array_add (ssids, g_bytes_ref (ssid)); } return ssids; @@ -1321,23 +1351,30 @@ request_wireless_scan (NMDeviceWifi *self, _LOGD (LOGD_WIFI, "wifi-scan: scanning requested"); if (!ssids) { - ssids = hidden_ssids = build_hidden_probe_list (self); + hidden_ssids = build_hidden_probe_list (self); + if (hidden_ssids) { + if (priv->hidden_probe_scan_warn) { + priv->hidden_probe_scan_warn = FALSE; + _LOGW (LOGD_WIFI, "wifi-scan: active scanning for networks due to profiles with wifi.hidden=yes. This makes you trackable"); + } + ssids = hidden_ssids; + } else + priv->hidden_probe_scan_warn = TRUE; } if (_LOGD_ENABLED (LOGD_WIFI)) { if (ssids) { - const GByteArray *ssid; guint i; - char *foo; for (i = 0; i < ssids->len; i++) { - ssid = g_ptr_array_index (ssids, i); - foo = ssid->len > 0 - ? nm_utils_ssid_to_utf8 (ssid->data, ssid->len) - : NULL; - _LOGD (LOGD_WIFI, "wifi-scan: (%u) probe scanning SSID %s%s%s", - i, NM_PRINT_FMT_QUOTED (foo, "\"", foo, "\"", "*any*")); - g_free (foo); + gs_free char *ssid_str = NULL; + GBytes *ssid = ssids->pdata[i]; + + ssid_str = g_bytes_get_size (ssid) > 0 + ? _nm_utils_ssid_to_string (ssid) + : NULL; + _LOGD (LOGD_WIFI, "wifi-scan: (%u) probe scanning SSID %s", + i, ssid_str ?: "*any*"); } } else _LOGD (LOGD_WIFI, "wifi-scan: no SSIDs to probe scan"); @@ -1345,7 +1382,9 @@ request_wireless_scan (NMDeviceWifi *self, _hw_addr_set_scanning (self, FALSE); - nm_supplicant_interface_request_scan (priv->sup_iface, ssids); + nm_supplicant_interface_request_scan (priv->sup_iface, + ssids ? (GBytes *const*) ssids->pdata : NULL, + ssids ? ssids->len : 0u); request_started = TRUE; } else _LOGD (LOGD_WIFI, "wifi-scan: scanning requested but not allowed at this time"); @@ -1484,17 +1523,13 @@ try_fill_ssid_for_hidden_ap (NMDeviceWifi *self, * and if a match is found, copy over the SSID */ connections = nm_settings_get_connections (nm_device_get_settings ((NMDevice *) self), NULL); for (i = 0; connections[i]; i++) { - NMConnection *connection = (NMConnection *) connections[i]; + NMSettingsConnection *sett_conn = connections[i]; NMSettingWireless *s_wifi; - s_wifi = nm_connection_get_setting_wireless (connection); + s_wifi = nm_connection_get_setting_wireless (nm_settings_connection_get_connection (sett_conn)); if (s_wifi) { - if (nm_settings_connection_has_seen_bssid (NM_SETTINGS_CONNECTION (connection), bssid)) { - GBytes *ssid = nm_setting_wireless_get_ssid (s_wifi); - - nm_wifi_ap_set_ssid (ap, - g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); + if (nm_settings_connection_has_seen_bssid (sett_conn, bssid)) { + nm_wifi_ap_set_ssid (ap, nm_setting_wireless_get_ssid (s_wifi)); break; } } @@ -1510,7 +1545,7 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDeviceState state; NMWifiAP *found_ap = NULL; - const GByteArray *ssid; + GBytes *ssid; g_return_if_fail (self != NULL); g_return_if_fail (properties != NULL); @@ -1539,15 +1574,19 @@ supplicant_iface_bss_updated_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->data, ssid->len)) { + if (!ssid || _nm_utils_is_empty_ssid (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->data, ssid->len) == FALSE)) { + if ( ssid + && !_nm_utils_is_empty_ssid (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), nm_utils_escape_ssid (ssid->data, ssid->len)); + _LOGD (LOGD_WIFI, "matched hidden AP %s => %s", + nm_wifi_ap_get_address (ap), + (s = _nm_utils_ssid_to_string (ssid))); } else { /* Didn't have an entry for this AP in the database */ _LOGD (LOGD_WIFI, "failed to match hidden AP %s", @@ -1859,7 +1898,7 @@ need_new_8021x_secrets (NMDeviceWifi *self, static gboolean need_new_wpa_psk (NMDeviceWifi *self, NMSupplicantInterfaceState old_state, - gint disconnect_reason, + int disconnect_reason, const char **setting_name) { NMSettingWirelessSecurity *s_wsec; @@ -2004,6 +2043,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMConnection *connection; NMSettingWireless *s_wifi; GBytes *ssid; + gs_free char *ssid_str = NULL; connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_return_if_fail (connection); @@ -2015,11 +2055,11 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, g_return_if_fail (ssid); _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 ? nm_utils_escape_ssid (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)) : "(none)"); + "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))); nm_device_activate_schedule_stage3_ip_config_start (device); } else if (devstate == NM_DEVICE_STATE_ACTIVATED) periodic_update (self); @@ -2127,9 +2167,11 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, if (new_ap != priv->current_ap) { const char *new_bssid = NULL; - const GByteArray *new_ssid = NULL; + GBytes *new_ssid = NULL; const char *old_bssid = NULL; - const GByteArray *old_ssid = NULL; + GBytes *old_ssid = NULL; + gs_free char *new_ssid_s = NULL; + gs_free char *old_ssid_s = NULL; /* Don't ever replace a "fake" current AP if we don't know about the * supplicant's current BSS yet. It'll get replaced when we receive @@ -2150,9 +2192,9 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, _LOGD (LOGD_WIFI, "roamed from BSSID %s (%s) to %s (%s)", old_bssid ?: "(none)", - old_ssid ? nm_utils_escape_ssid (old_ssid->data, old_ssid->len) : "(none)", + (old_ssid_s = _nm_utils_ssid_to_string (old_ssid)), new_bssid ?: "(none)", - new_ssid ? nm_utils_escape_ssid (new_ssid->data, new_ssid->len) : "(none)"); + (new_ssid_s = _nm_utils_ssid_to_string (new_ssid))); set_current_ap (self, new_ap, TRUE); } @@ -2332,7 +2374,6 @@ build_supplicant_config (NMDeviceWifi *self, NMSettingWirelessSecurity *s_wireless_sec; NMSettingWirelessSecurityPmf pmf; NMSettingWirelessSecurityFils fils; - gs_free char *value = NULL; g_return_val_if_fail (priv->sup_iface, NULL); @@ -2374,25 +2415,23 @@ build_supplicant_config (NMDeviceWifi *self, /* Configure PMF (802.11w) */ pmf = nm_setting_wireless_security_get_pmf (s_wireless_sec); if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT) { - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi-sec.pmf", - NM_DEVICE (self)); - pmf = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE, - NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED, - NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL); + pmf = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi-sec.pmf", + NM_DEVICE (self), + NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE, + NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED, + NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL); } /* Configure FILS (802.11ai) */ fils = nm_setting_wireless_security_get_fils (s_wireless_sec); if (fils == NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT) { - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi-sec.fils", - NM_DEVICE (self)); - fils = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE, - NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED, - NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL); + fils = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi-sec.fils", + NM_DEVICE (self), + NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE, + NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED, + NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL); } s_8021x = nm_connection_get_setting_802_1x (connection); @@ -2426,9 +2465,9 @@ error: static gboolean wake_on_wlan_enable (NMDeviceWifi *self) { + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWirelessWakeOnWLan wowl; NMSettingWireless *s_wireless; - gs_free char *value = NULL; s_wireless = (NMSettingWireless *) nm_device_get_applied_setting (NM_DEVICE (self), NM_TYPE_SETTING_WIRELESS); if (s_wireless) { @@ -2437,32 +2476,39 @@ wake_on_wlan_enable (NMDeviceWifi *self) goto found; } - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi.wake-on-wlan", - NM_DEVICE (self)); - - if (value) { - wowl = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, - G_MAXINT32, - NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT); + wowl = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi.wake-on-wlan", + NM_DEVICE (self), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, + G_MAXINT32, + NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT); - if (NM_FLAGS_ANY (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS)) { - if (!nm_utils_is_power_of_two (wowl)) { - _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan: " - "'default' and 'ignore' are exclusive flags", (guint) wowl); - wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; - } - } else if (NM_FLAGS_ANY (wowl, ~NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL)) { - _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan", (guint) wowl); + if (NM_FLAGS_ANY (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS)) { + if (!nm_utils_is_power_of_two (wowl)) { + _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan: " + "'default' and 'ignore' are exclusive flags", (guint) wowl); wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; } - if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) - goto found; + } else if (NM_FLAGS_ANY (wowl, ~NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL)) { + _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan", (guint) wowl); + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; } + if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) + goto found; + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; found: - return nm_platform_wifi_set_wake_on_wlan (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), wowl); + if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) { + priv->wowlan_restore = wowl; + return TRUE; + } + + priv->wowlan_restore = nm_platform_wifi_get_wake_on_wlan (NM_PLATFORM_GET, + nm_device_get_ifindex (NM_DEVICE (self))); + + return nm_platform_wifi_set_wake_on_wlan (NM_PLATFORM_GET, + nm_device_get_ifindex (NM_DEVICE (self)), + wowl); } static NMActStageReturn @@ -2598,31 +2644,29 @@ set_powersave (NMDevice *device) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMSettingWireless *s_wireless; - NMSettingWirelessPowersave powersave; - gs_free char *value = NULL; + NMSettingWirelessPowersave val; s_wireless = (NMSettingWireless *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRELESS); g_return_if_fail (s_wireless); - powersave = nm_setting_wireless_get_powersave (s_wireless); - if (powersave == NM_SETTING_WIRELESS_POWERSAVE_DEFAULT) { - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi.powersave", - device); - powersave = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_POWERSAVE_IGNORE, - NM_SETTING_WIRELESS_POWERSAVE_ENABLE, - NM_SETTING_WIRELESS_POWERSAVE_IGNORE); + val = nm_setting_wireless_get_powersave (s_wireless); + if (val == NM_SETTING_WIRELESS_POWERSAVE_DEFAULT) { + val = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi.powersave", + device, + NM_SETTING_WIRELESS_POWERSAVE_IGNORE, + NM_SETTING_WIRELESS_POWERSAVE_ENABLE, + NM_SETTING_WIRELESS_POWERSAVE_IGNORE); } - _LOGT (LOGD_WIFI, "powersave is set to %u", (unsigned) powersave); + _LOGT (LOGD_WIFI, "powersave is set to %u", (unsigned) val); - if (powersave == NM_SETTING_WIRELESS_POWERSAVE_IGNORE) + if (val == NM_SETTING_WIRELESS_POWERSAVE_IGNORE) return; nm_platform_wifi_set_powersave (nm_device_get_platform (device), nm_device_get_ifindex (device), - powersave == NM_SETTING_WIRELESS_POWERSAVE_ENABLE); + val == NM_SETTING_WIRELESS_POWERSAVE_ENABLE); } static NMActStageReturn @@ -2659,8 +2703,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) s_wireless = nm_connection_get_setting_wireless (connection); g_assert (s_wireless); - wake_on_wlan_enable (self); - /* If we need secrets, get them */ setting_name = nm_connection_need_secrets (connection, NULL); if (setting_name) { @@ -2677,6 +2719,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) goto out; } + if (!wake_on_wlan_enable (self)) + _LOGW (LOGD_DEVICE | LOGD_WIFI, "Cannot configure WoWLAN."); + /* have secrets, or no secrets required */ if (nm_connection_get_setting_wireless_security (connection)) { _LOGI (LOGD_DEVICE | LOGD_WIFI, @@ -2727,8 +2772,10 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) ret = NM_ACT_STAGE_RETURN_POSTPONE; out: - if (ret == NM_ACT_STAGE_RETURN_FAILURE) + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { cleanup_association_attempt (self, TRUE); + wake_on_wlan_restore (self); + } if (config) { /* Supplicant interface object refs the config; we no longer care about @@ -3134,7 +3181,8 @@ reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_n _LOGD (LOGD_DEVICE, "reapplying wireless settings"); - wake_on_wlan_enable (self); + if (!wake_on_wlan_enable (self)) + _LOGW (LOGD_DEVICE | LOGD_WIFI, "Cannot configure WoWLAN."); } /*****************************************************************************/ @@ -3206,7 +3254,9 @@ nm_device_wifi_init (NMDeviceWifi *self) c_list_init (&priv->aps_lst_head); + priv->hidden_probe_scan_warn = TRUE; priv->mode = NM_802_11_MODE_INFRA; + priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; } static void @@ -3274,9 +3324,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->get_property = get_property; @@ -3286,29 +3334,33 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); - parent_class->can_auto_connect = can_auto_connect; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->is_available = is_available; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->get_enabled = get_enabled; - parent_class->set_enabled = set_enabled; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; - parent_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; - parent_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; - parent_class->deactivate = deactivate; - parent_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; - parent_class->unmanaged_on_quit = unmanaged_on_quit; - parent_class->can_reapply_change = can_reapply_change; - parent_class->reapply_connection = reapply_connection; - - parent_class->state_changed = device_state_changed; + device_class->connection_type_supported = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIFI); + + device_class->can_auto_connect = can_auto_connect; + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->is_available = is_available; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->get_enabled = get_enabled; + device_class->set_enabled = set_enabled; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; + device_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; + device_class->deactivate = deactivate; + device_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; + device_class->unmanaged_on_quit = unmanaged_on_quit; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; + + device_class->state_changed = device_state_changed; klass->scanning_prohibited = scanning_prohibited; diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index d6511296..a3da9791 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -29,13 +29,21 @@ #include "nm-core-internal.h" #include "nm-manager.h" #include "nm-device-iwd.h" +#include "nm-wifi-utils.h" #include "nm-utils/nm-random-utils.h" +#include "settings/nm-settings.h" /*****************************************************************************/ typedef struct { - gchar *name; + const char *name; NMIwdNetworkSecurity security; + char buf[0]; +} KnownNetworkId; + +typedef struct { + GDBusProxy *known_network; + NMSettingsConnection *mirror_connection; } KnownNetworkData; typedef struct { @@ -44,8 +52,8 @@ typedef struct { gboolean running; GDBusObjectManager *object_manager; guint agent_id; - gchar *agent_path; - GSList *known_networks; + char *agent_path; + GHashTable *known_networks; } NMIwdManagerPrivate; struct _NMIwdManager { @@ -83,20 +91,49 @@ G_DEFINE_TYPE (NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT) /*****************************************************************************/ +static void mirror_8021x_connection_take_and_delete (NMSettingsConnection *sett_conn); + +/*****************************************************************************/ + +static const char * +get_variant_string_or_null (GVariant *v) +{ + if (!v) + return NULL; + + if ( !g_variant_is_of_type (v, G_VARIANT_TYPE_STRING) + && !g_variant_is_of_type (v, G_VARIANT_TYPE_OBJECT_PATH)) + return NULL; + + return g_variant_get_string (v, NULL); +} + +static const char * +get_property_string_or_null (GDBusProxy *proxy, const char *property) +{ + gs_unref_variant GVariant *value = NULL; + + if (!proxy || !property) + return NULL; + + value = g_dbus_proxy_get_cached_property (proxy, property); + + return get_variant_string_or_null (value); +} + static void agent_dbus_method_cb (GDBusConnection *connection, - const gchar *sender, const gchar *object_path, - const gchar *interface_name, const gchar *method_name, + const char *sender, const char *object_path, + const char *interface_name, const char *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { NMIwdManager *self = user_data; NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - const gchar *network_path, *device_path, *ifname; + const char *network_path, *device_path, *ifname; gs_unref_object GDBusInterface *network = NULL, *device_obj = NULL; - gs_unref_variant GVariant *value = NULL; - gint ifindex; + int ifindex; NMDevice *device; gs_free char *name_owner = NULL; @@ -113,9 +150,8 @@ agent_dbus_method_cb (GDBusConnection *connection, network = g_dbus_object_manager_get_interface (priv->object_manager, network_path, NM_IWD_NETWORK_INTERFACE); - value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (network), "Device"); - device_path = g_variant_get_string (value, NULL); + device_path = get_property_string_or_null (G_DBUS_PROXY (network), "Device"); if (!device_path) { _LOGD ("agent-request: device not cached for network %s in IWD Agent request", network_path); @@ -125,10 +161,8 @@ agent_dbus_method_cb (GDBusConnection *connection, device_obj = g_dbus_object_manager_get_interface (priv->object_manager, device_path, NM_IWD_DEVICE_INTERFACE); - g_variant_unref (value); - value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (device_obj), "Name"); - ifname = g_variant_get_string (value, NULL); + ifname = get_property_string_or_null (G_DBUS_PROXY (device_obj), "Name"); if (!ifname) { _LOGD ("agent-request: name not cached for device %s in IWD Agent request", device_path); @@ -207,12 +241,12 @@ static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE static guint iwd_agent_export (GDBusConnection *connection, gpointer user_data, - gchar **agent_path, GError **error) + char **agent_path, GError **error) { static const GDBusInterfaceVTable vtable = { .method_call = agent_dbus_method_cb, }; - gchar path[50]; + char path[50]; unsigned int rnd; guint id; @@ -251,38 +285,68 @@ register_agent (NMIwdManager *self) /*****************************************************************************/ -static void -set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface, - GDBusObject *object) +static KnownNetworkId * +known_network_id_new (const char *name, NMIwdNetworkSecurity security) { - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusProxy *proxy; - GVariant *value; - const char *ifname; - gint ifindex; - NMDevice *device; + KnownNetworkId *id; + gsize strsize = strlen (name) + 1; - if (!priv->running) - return; + id = g_malloc (sizeof (KnownNetworkId) + strsize); + id->name = id->buf; + id->security = security; + memcpy (id->buf, name, strsize); - g_return_if_fail (G_IS_DBUS_PROXY (interface)); + return id; +} - proxy = G_DBUS_PROXY (interface); +static guint +known_network_id_hash (KnownNetworkId *id) +{ + NMHashState h; - if (strcmp (g_dbus_proxy_get_interface_name (proxy), - NM_IWD_DEVICE_INTERFACE)) + nm_hash_init (&h, 1947951703u); + nm_hash_update_val (&h, id->security); + nm_hash_update_str (&h, id->name); + return nm_hash_complete (&h); +} + +static gboolean +known_network_id_equal (KnownNetworkId *a, KnownNetworkId *b) +{ + return a->security == b->security + && nm_streq (a->name, b->name); +} + +static void +known_network_data_free (KnownNetworkData *network) +{ + if (!network) return; - value = g_dbus_proxy_get_cached_property (proxy, "Name"); - if (!value) { + g_object_unref (network->known_network); + mirror_8021x_connection_take_and_delete (network->mirror_connection); + g_slice_free (KnownNetworkData, network); +} + +/*****************************************************************************/ + +static void +set_device_dbus_object (NMIwdManager *self, GDBusProxy *proxy, + GDBusObject *object) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); + const char *ifname; + int ifindex; + NMDevice *device; + + ifname = get_property_string_or_null (proxy, "Name"); + if (!ifname) { _LOGE ("Name not cached for Device at %s", g_dbus_proxy_get_object_path (proxy)); return; } - ifname = g_variant_get_string (value, NULL); ifindex = if_nametoindex (ifname); - g_variant_unref (value); if (!ifindex) { _LOGE ("if_nametoindex failed for Name %s for Device at %s: %i", @@ -299,13 +363,192 @@ set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface, nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object); } +/* Create an in-memory NMConnection for a WPA2-Enterprise network that + * has been preprovisioned with an IWD config file so that NM autoconnect + * mechanism and the clients know this networks needs no additional EAP + * configuration from the user. Only do this if no existing connection + * SSID and security type match that network yet. + */ +static NMSettingsConnection * +mirror_8021x_connection (NMIwdManager *self, + const char *name) +{ + NMSettings *settings = NM_SETTINGS_GET; + NMSettingsConnection *const*iter; + gs_unref_object NMConnection *connection = NULL; + NMSettingsConnection *settings_connection; + char uuid[37]; + NMSetting *setting; + GError *error = NULL; + gs_unref_bytes GBytes *new_ssid = NULL; + + for (iter = nm_settings_get_connections (settings, NULL); *iter; iter++) { + NMSettingsConnection *sett_conn = *iter; + NMConnection *conn = nm_settings_connection_get_connection (sett_conn); + NMIwdNetworkSecurity security; + gs_free char *ssid_name = NULL; + NMSettingWireless *s_wifi; + + security = nm_wifi_connection_get_iwd_security (conn, NULL); + if (security != NM_IWD_NETWORK_SECURITY_8021X) + continue; + + s_wifi = nm_connection_get_setting_wireless (conn); + if (!s_wifi) + continue; + + ssid_name = _nm_utils_ssid_to_utf8 (nm_setting_wireless_get_ssid (s_wifi)); + + /* We already have an NMSettingsConnection matching this + * KnownNetwork, whether it's saved or an in-memory connection + * potentially created by ourselves. Nothing to do here. + */ + if (nm_streq (ssid_name, name)) + return NULL; + } + + connection = nm_simple_connection_new (); + + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_CONNECTION, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_CONNECTION_ID, name, + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), + NM_SETTING_CONNECTION_READ_ONLY, TRUE, + NULL)); + nm_connection_add_setting (connection, setting); + + new_ssid = g_bytes_new (name, strlen (name)); + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_WIRELESS, + NM_SETTING_WIRELESS_SSID, new_ssid, + NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, + NULL)); + nm_connection_add_setting (connection, setting); + + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_WIRELESS_SECURITY, + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", + NULL)); + nm_connection_add_setting (connection, setting); + + /* "password" and "private-key-password" may be requested by the IWD agent + * from NM and IWD will implement a specific secret cache policy so by + * default respect that policy and don't save copies of those secrets in + * NM settings. The saved values can not be used anyway because of our + * use of NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW. + */ + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_802_1X, + NM_SETTING_802_1X_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED, + NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED, + NULL)); + nm_setting_802_1x_add_eap_method (NM_SETTING_802_1X (setting), "external"); + nm_connection_add_setting (connection, setting); + + if (!nm_connection_normalize (connection, NULL, NULL, NULL)) + return NULL; + + settings_connection = nm_settings_add_connection (settings, connection, + FALSE, &error); + if (!settings_connection) { + _LOGW ("failed to add a mirror NMConnection for IWD's Known Network '%s': %s", + name, error->message); + g_error_free (error); + return NULL; + } + + nm_settings_connection_set_flags (settings_connection, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | + NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED, + TRUE); + return settings_connection; +} + +static void +mirror_8021x_connection_take_and_delete (NMSettingsConnection *sett_conn) +{ + NMSettingsConnectionIntFlags flags; + + if (!sett_conn) + return; + + flags = nm_settings_connection_get_flags (sett_conn); + + /* If connection has not been saved since we created it + * in interface_added it too can be removed now. */ + if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + nm_settings_connection_delete (sett_conn, NULL); + + g_object_unref (sett_conn); +} + static void interface_added (GDBusObjectManager *object_manager, GDBusObject *object, GDBusInterface *interface, gpointer user_data) { NMIwdManager *self = user_data; + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); + GDBusProxy *proxy; + const char *iface_name; + + if (!priv->running) + return; - set_device_dbus_object (self, interface, object); + g_return_if_fail (G_IS_DBUS_PROXY (interface)); + + proxy = G_DBUS_PROXY (interface); + iface_name = g_dbus_proxy_get_interface_name (proxy); + + if (nm_streq (iface_name, NM_IWD_DEVICE_INTERFACE)) { + set_device_dbus_object (self, proxy, object); + return; + } + + if (nm_streq (iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) { + KnownNetworkId *id; + KnownNetworkData *data; + NMIwdNetworkSecurity security; + const char *type_str, *name; + NMSettingsConnection *sett_conn = NULL; + + type_str = get_property_string_or_null (proxy, "Type"); + name = get_property_string_or_null (proxy, "Name"); + if (!type_str || !name) + return; + + if (nm_streq (type_str, "open")) + security = NM_IWD_NETWORK_SECURITY_NONE; + else if (nm_streq (type_str, "psk")) + security = NM_IWD_NETWORK_SECURITY_PSK; + else if (nm_streq (type_str, "8021x")) + security = NM_IWD_NETWORK_SECURITY_8021X; + else + return; + + id = known_network_id_new (name, security); + + data = g_hash_table_lookup (priv->known_networks, id); + if (data) + g_free (id); + else { + data = g_slice_new0 (KnownNetworkData); + data->known_network = g_object_ref (proxy); + g_hash_table_insert (priv->known_networks, id, data); + } + + if (security == NM_IWD_NETWORK_SECURITY_8021X) { + sett_conn = mirror_8021x_connection (self, name); + + if ( sett_conn + && sett_conn != data->mirror_connection) { + NMSettingsConnection *sett_conn_old = data->mirror_connection; + + data->mirror_connection = nm_g_object_ref (sett_conn); + mirror_8021x_connection_take_and_delete (sett_conn_old); + } + } else + mirror_8021x_connection_take_and_delete (g_steal_pointer (&data->mirror_connection)); + + return; + } } static void @@ -313,15 +556,41 @@ interface_removed (GDBusObjectManager *object_manager, GDBusObject *object, GDBusInterface *interface, gpointer user_data) { NMIwdManager *self = user_data; + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); + GDBusProxy *proxy; + const char *iface_name; - /* - * TODO: we may need to save the GDBusInterface or GDBusObject - * pointer in the hash table because we may be no longer able to - * access the Name property or map the name to ifindex with - * if_nametoindex at this point. - */ + g_return_if_fail (G_IS_DBUS_PROXY (interface)); + + proxy = G_DBUS_PROXY (interface); + iface_name = g_dbus_proxy_get_interface_name (proxy); - set_device_dbus_object (self, interface, NULL); + if (nm_streq (iface_name, NM_IWD_DEVICE_INTERFACE)) { + set_device_dbus_object (self, proxy, NULL); + return; + } + + if (nm_streq (iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) { + KnownNetworkId id; + const char *type_str; + + type_str = get_property_string_or_null (proxy, "Type"); + id.name = get_property_string_or_null (proxy, "Name"); + if (!type_str || !id.name) + return; + + if (nm_streq (type_str, "open")) + id.security = NM_IWD_NETWORK_SECURITY_NONE; + else if (nm_streq (type_str, "psk")) + id.security = NM_IWD_NETWORK_SECURITY_PSK; + else if (nm_streq (type_str, "8021x")) + id.security = NM_IWD_NETWORK_SECURITY_8021X; + else + return; + + g_hash_table_remove (priv->known_networks, &id); + return; + } } static gboolean @@ -341,106 +610,42 @@ object_added (NMIwdManager *self, GDBusObject *object) GList *interfaces, *iter; interfaces = g_dbus_object_get_interfaces (object); + for (iter = interfaces; iter; iter = iter->next) { GDBusInterface *interface = G_DBUS_INTERFACE (iter->data); - set_device_dbus_object (self, interface, object); + interface_added (NULL, object, interface, self); } g_list_free_full (interfaces, g_object_unref); } static void -known_network_free (KnownNetworkData *network) -{ - g_free (network->name); - g_free (network); -} - -static void -list_known_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) +release_object_manager (NMIwdManager *self) { - NMIwdManager *self = user_data; NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *variant = NULL; - GVariantIter *networks, *props; - - variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, - G_VARIANT_TYPE ("(aa{sv})"), - &error); - if (!variant) { - _LOGE ("ListKnownNetworks() failed: %s", error->message); - return; - } - - g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free); - priv->known_networks = NULL; - - g_variant_get (variant, "(aa{sv})", &networks); - - while (g_variant_iter_next (networks, "a{sv}", &props)) { - const gchar *key; - const gchar *name = NULL; - const gchar *type = NULL; - GVariant *val; - KnownNetworkData *network_data; - while (g_variant_iter_next (props, "{&sv}", &key, &val)) { - if (!strcmp (key, "Name")) - name = g_variant_get_string (val, NULL); - - if (!strcmp (key, "Type")) - type = g_variant_get_string (val, NULL); - - g_variant_unref (val); - } + if (!priv->object_manager) + return; - if (!name || !type) - goto next; + g_signal_handlers_disconnect_by_data (priv->object_manager, self); - network_data = g_new (KnownNetworkData, 1); - network_data->name = g_strdup (name); - if (!strcmp (type, "open")) - network_data->security = NM_IWD_NETWORK_SECURITY_NONE; - else if (!strcmp (type, "psk")) - network_data->security = NM_IWD_NETWORK_SECURITY_PSK; - else if (!strcmp (type, "8021x")) - network_data->security = NM_IWD_NETWORK_SECURITY_8021X; + if (priv->agent_id) { + GDBusConnection *agent_connection; + GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager); - priv->known_networks = g_slist_append (priv->known_networks, - network_data); + agent_connection = g_dbus_object_manager_client_get_connection (omc); -next: - g_variant_iter_free (props); + /* We're is called when we're shutting down (i.e. our DBus connection + * is being closed, and IWD will detect this) or IWD was stopped so + * in either case calling UnregisterAgent will not do anything. + */ + g_dbus_connection_unregister_object (agent_connection, priv->agent_id); + priv->agent_id = 0; + nm_clear_g_free (&priv->agent_path); } - g_variant_iter_free (networks); - - /* For completness we may want to call nm_device_emit_recheck_auto_activate - * and nm_device_recheck_available_connections for all affected devices - * now but the ListKnownNetworks call should have been really fast, - * faster than any scan on any newly created devices could have happened. - */ -} - -static void -update_known_networks (NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusInterface *known_networks_if; - - known_networks_if = g_dbus_object_manager_get_interface (priv->object_manager, - "/", - NM_IWD_KNOWN_NETWORKS_INTERFACE); - - g_dbus_proxy_call (G_DBUS_PROXY (known_networks_if), - "ListKnownNetworks", - g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, - priv->cancellable, list_known_networks_cb, self); - - g_object_unref (known_networks_if); + g_clear_object (&priv->object_manager); } static void prepare_object_manager (NMIwdManager *self); @@ -455,8 +660,7 @@ name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data) nm_assert (object_manager == priv->object_manager); if (_om_has_name_owner (object_manager)) { - g_signal_handlers_disconnect_by_data (object_manager, self); - g_clear_object (&priv->object_manager); + release_object_manager (self); prepare_object_manager (self); } else { const CList *tmp_lst; @@ -492,28 +696,14 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data) objects = g_dbus_object_manager_get_objects (priv->object_manager); for (iter = objects; iter; iter = iter->next) { GDBusObject *object = G_DBUS_OBJECT (iter->data); - GDBusInterface *interface; - GDBusProxy *proxy; - GVariant *value; + gs_unref_object GDBusInterface *interface = NULL; const char *obj_ifname; interface = g_dbus_object_get_interface (object, NM_IWD_DEVICE_INTERFACE); - if (!interface) - continue; - - proxy = G_DBUS_PROXY (interface); - value = g_dbus_proxy_get_cached_property (proxy, "Name"); - if (!value) { - g_object_unref (interface); - continue; - } - - obj_ifname = g_variant_get_string (value, NULL); - g_variant_unref (value); - g_object_unref (interface); + obj_ifname = get_property_string_or_null ((GDBusProxy *) interface, "Name"); - if (strcmp (nm_device_get_iface (device), obj_ifname)) + if (!obj_ifname || strcmp (nm_device_get_iface (device), obj_ifname)) continue; nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object); @@ -535,7 +725,7 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) object_manager = g_dbus_object_manager_client_new_for_bus_finish (result, &error); if (object_manager == NULL) { _LOGE ("failed to acquire IWD Object Manager: Wi-Fi will not be available (%s)", - NM_G_ERROR_MSG (error)); + error->message); g_clear_error (&error); return; } @@ -549,11 +739,13 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) connection = g_dbus_object_manager_client_get_connection (G_DBUS_OBJECT_MANAGER_CLIENT (object_manager)); - priv->agent_id = iwd_agent_export (connection, self, - &priv->agent_path, &error); + priv->agent_id = iwd_agent_export (connection, + self, + &priv->agent_path, + &error); if (!priv->agent_id) { - _LOGE ("failed to export the IWD Agent: PSK/8021x WiFi networks will not work: %s", - NM_G_ERROR_MSG (error)); + _LOGE ("failed to export the IWD Agent: PSK/8021x WiFi networks may not work: %s", + error->message); g_clear_error (&error); } @@ -567,6 +759,8 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) g_signal_connect (priv->object_manager, "interface-removed", G_CALLBACK (interface_removed), self); + g_hash_table_remove_all (priv->known_networks); + objects = g_dbus_object_manager_get_objects (object_manager); for (iter = objects; iter; iter = iter->next) object_added (self, G_DBUS_OBJECT (iter->data)); @@ -575,8 +769,6 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) if (priv->agent_id) register_agent (self); - - update_known_networks (self); } } @@ -594,36 +786,28 @@ prepare_object_manager (NMIwdManager *self) } gboolean -nm_iwd_manager_is_known_network (NMIwdManager *self, const gchar *name, +nm_iwd_manager_is_known_network (NMIwdManager *self, const char *name, NMIwdNetworkSecurity security) { NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - const GSList *iter; - - for (iter = priv->known_networks; iter; iter = g_slist_next (iter)) { - const KnownNetworkData *network = iter->data; - - if (!strcmp (network->name, name) && network->security == security) - return true; - } + KnownNetworkId kn_id = { name, security }; - return false; + return g_hash_table_contains (priv->known_networks, &kn_id); } -void -nm_iwd_manager_network_connected (NMIwdManager *self, const gchar *name, - NMIwdNetworkSecurity security) +GDBusProxy * +nm_iwd_manager_get_dbus_interface (NMIwdManager *self, const char *path, + const char *name) { NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - KnownNetworkData *network_data; + GDBusInterface *interface; - if (nm_iwd_manager_is_known_network (self, name, security)) - return; + if (!priv->object_manager) + return NULL; + + interface = g_dbus_object_manager_get_interface (priv->object_manager, path, name); - network_data = g_new (KnownNetworkData, 1); - network_data->name = g_strdup (name); - network_data->security = security; - priv->known_networks = g_slist_append (priv->known_networks, network_data); + return interface ? G_DBUS_PROXY (interface) : NULL; } /*****************************************************************************/ @@ -642,6 +826,11 @@ nm_iwd_manager_init (NMIwdManager *self) priv->cancellable = g_cancellable_new (); + priv->known_networks = g_hash_table_new_full ((GHashFunc) known_network_id_hash, + (GEqualFunc) known_network_id_equal, + g_free, + (GDestroyNotify) known_network_data_free); + prepare_object_manager (self); } @@ -651,30 +840,11 @@ dispose (GObject *object) NMIwdManager *self = (NMIwdManager *) object; NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - if (priv->object_manager) { - if (priv->agent_id) { - GDBusConnection *connection; - GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager); - - /* No need to unregister the agent as IWD will detect - * our DBus connection being closed. - */ - - connection = g_dbus_object_manager_client_get_connection (omc); - - g_dbus_connection_unregister_object (connection, priv->agent_id); - priv->agent_id = 0; - } - - g_clear_object (&priv->object_manager); - } - - nm_clear_g_free (&priv->agent_path); + release_object_manager (self); nm_clear_g_cancellable (&priv->cancellable); - g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free); - priv->known_networks = NULL; + nm_clear_pointer (&priv->known_networks, g_hash_table_destroy); if (priv->manager) { g_signal_handlers_disconnect_by_data (priv->manager, self); diff --git a/src/devices/wifi/nm-iwd-manager.h b/src/devices/wifi/nm-iwd-manager.h index 8e6b66ff..57b7007a 100644 --- a/src/devices/wifi/nm-iwd-manager.h +++ b/src/devices/wifi/nm-iwd-manager.h @@ -22,6 +22,7 @@ #define __NETWORKMANAGER_IWD_MANAGER_H__ #include "devices/nm-device.h" +#include "nm-wifi-utils.h" #define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM #define NM_IWD_SERVICE "net.connman.iwd" @@ -33,15 +34,11 @@ #define NM_IWD_AGENT_INTERFACE "net.connman.iwd.Agent" #define NM_IWD_WSC_INTERFACE \ "net.connman.iwd.WiFiSimpleConfiguration" -#define NM_IWD_KNOWN_NETWORKS_INTERFACE "net.connman.iwd.KnownNetworks" +#define NM_IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork" #define NM_IWD_SIGNAL_AGENT_INTERFACE "net.connman.iwd.SignalLevelAgent" - -typedef enum { - NM_IWD_NETWORK_SECURITY_NONE, - NM_IWD_NETWORK_SECURITY_WEP, - NM_IWD_NETWORK_SECURITY_PSK, - NM_IWD_NETWORK_SECURITY_8021X, -} NMIwdNetworkSecurity; +#define NM_IWD_AP_INTERFACE "net.connman.iwd.AccessPoint" +#define NM_IWD_ADHOC_INTERFACE "net.connman.iwd.AdHoc" +#define NM_IWD_STATION_INTERFACE "net.connman.iwd.Station" #define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type ()) #define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IWD_MANAGER, NMIwdManager)) @@ -57,9 +54,10 @@ GType nm_iwd_manager_get_type (void); NMIwdManager *nm_iwd_manager_get (void); -gboolean nm_iwd_manager_is_known_network (NMIwdManager *self, const gchar *name, +gboolean nm_iwd_manager_is_known_network (NMIwdManager *self, const char *name, NMIwdNetworkSecurity security); -void nm_iwd_manager_network_connected (NMIwdManager *self, const gchar *name, - NMIwdNetworkSecurity security); + +GDBusProxy *nm_iwd_manager_get_dbus_interface (NMIwdManager *self, const char *path, + const char *name); #endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */ diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index dd6d1deb..e5573383 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -58,7 +58,7 @@ struct _NMWifiAPPrivate { char *supplicant_path; /* D-Bus object path of this AP from wpa_supplicant */ /* Scanned or cached values */ - GByteArray * ssid; + GBytes * ssid; char * address; NM80211Mode mode; guint8 strength; @@ -95,7 +95,7 @@ nm_wifi_ap_get_supplicant_path (NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->supplicant_path; } -const GByteArray * +GBytes * nm_wifi_ap_get_ssid (const NMWifiAP *ap) { g_return_val_if_fail (NM_IS_WIFI_AP (ap), NULL); @@ -103,43 +103,57 @@ nm_wifi_ap_get_ssid (const NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->ssid; } -static GVariant * -nm_wifi_ap_get_ssid_as_variant (const NMWifiAP *self) +gboolean +nm_wifi_ap_set_ssid_arr (NMWifiAP *ap, + const guint8 *ssid, + gsize ssid_len) { - const NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (self); + NMWifiAPPrivate *priv; + + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + + if (ssid_len > 32) + g_return_val_if_reached (FALSE); + + priv = NM_WIFI_AP_GET_PRIVATE (ap); + + if (nm_utils_gbytes_equal_mem (priv->ssid, ssid, ssid_len)) + return FALSE; + + nm_clear_pointer (&priv->ssid, g_bytes_unref); + if (ssid_len > 0) + priv->ssid = g_bytes_new (ssid, ssid_len); - if (priv->ssid) { - return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - priv->ssid->data, priv->ssid->len, 1); - } else - return g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0); + _notify (ap, PROP_SSID); + return TRUE; } gboolean -nm_wifi_ap_set_ssid (NMWifiAP *ap, const guint8 *ssid, gsize len) +nm_wifi_ap_set_ssid (NMWifiAP *ap, GBytes *ssid) { NMWifiAPPrivate *priv; + gsize l; g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - g_return_val_if_fail (ssid == NULL || len > 0, FALSE); - priv = NM_WIFI_AP_GET_PRIVATE (ap); - - /* same SSID */ - if ((ssid && priv->ssid) && (len == priv->ssid->len)) { - if (!memcmp (ssid, priv->ssid->data, len)) - return FALSE; + if (ssid) { + l = g_bytes_get_size (ssid); + if (l == 0 || l > 32) + g_return_val_if_reached (FALSE); } - if (priv->ssid) { - g_byte_array_free (priv->ssid, TRUE); - priv->ssid = NULL; - } + priv = NM_WIFI_AP_GET_PRIVATE (ap); - if (ssid) { - priv->ssid = g_byte_array_new (); - g_byte_array_append (priv->ssid, ssid, len); - } + if (ssid == priv->ssid) + return FALSE; + if ( ssid + && priv->ssid + && g_bytes_equal (ssid, priv->ssid)) + return FALSE; + + nm_clear_pointer (&priv->ssid, g_bytes_unref); + if (ssid) + priv->ssid = g_bytes_ref (ssid); _notify (ap, PROP_SSID); return TRUE; @@ -814,10 +828,16 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, len = MIN (32, len); /* Stupid ieee80211 layer uses <hidden> */ - if ( bytes && len - && !(((len == 8) || (len == 9)) && !memcmp (bytes, "<hidden>", 8)) - && !nm_utils_is_empty_ssid (bytes, len)) - changed |= nm_wifi_ap_set_ssid (ap, bytes, len); + if ( bytes + && len + && !( NM_IN_SET (len, 8, 9) + && memcmp (bytes, "<hidden>", len) == 0) + && !nm_utils_is_empty_ssid (bytes, len)) { + /* good */ + } else + len = 0; + + changed |= nm_wifi_ap_set_ssid_arr (ap, bytes, len); g_variant_unref (v); } @@ -961,7 +981,7 @@ nm_wifi_ap_to_string (const NMWifiAP *self, const char *supplicant_id = "-"; const char *export_path; guint32 chan; - char b1[200]; + gs_free char *ssid_to_free = NULL; g_return_val_if_fail (NM_IS_WIFI_AP (self), NULL); @@ -977,10 +997,9 @@ nm_wifi_ap_to_string (const NMWifiAP *self, export_path = "/"; g_snprintf (str_buf, buf_len, - "%17s %-32s [ %c %3u %3u%% %c W:%04X R:%04X ] %3us sup:%s [nm:%s]", + "%17s %-35s [ %c %3u %3u%% %c W:%04X R:%04X ] %3us sup:%s [nm:%s]", priv->address ?: "(none)", - nm_sprintf_buf (b1, "%s%s%s", - NM_PRINT_FMT_QUOTED (priv->ssid, "\"", nm_utils_escape_ssid (priv->ssid->data, priv->ssid->len), "\"", "(none)")), + (ssid_to_free = _nm_utils_ssid_to_string (priv->ssid)), (priv->mode == NM_802_11_MODE_ADHOC ? '*' : (priv->hotspot @@ -1032,15 +1051,12 @@ nm_wifi_ap_check_compatible (NMWifiAP *self, return FALSE; ssid = nm_setting_wireless_get_ssid (s_wireless); - if ( (ssid && !priv->ssid) - || (priv->ssid && !ssid)) - return FALSE; - - if ( ssid && priv->ssid && - !nm_utils_same_ssid (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid), - priv->ssid->data, priv->ssid->len, - TRUE)) - return FALSE; + if (ssid != priv->ssid) { + if (!ssid || !priv->ssid) + return FALSE; + if (!g_bytes_equal (ssid, priv->ssid)) + return FALSE; + } bssid = nm_setting_wireless_get_bssid (s_wireless); if (bssid && (!priv->address || !nm_utils_hwaddr_matches (bssid, -1, priv->address, -1))) @@ -1126,7 +1142,8 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->rsn_flags); break; case PROP_SSID: - g_value_take_variant (value, nm_wifi_ap_get_ssid_as_variant (self)); + g_value_take_variant (value, + nm_utils_gbytes_to_variant_ay (priv->ssid)); break; case PROP_FREQUENCY: g_value_set_uint (value, priv->freq); @@ -1146,7 +1163,7 @@ get_property (GObject *object, guint prop_id, case PROP_LAST_SEEN: g_value_set_int (value, priv->last_seen > 0 - ? (gint) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) + ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) : -1); break; default: @@ -1202,7 +1219,6 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection) NMWifiAPPrivate *priv; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; - GBytes *ssid; const char *mode, *band, *key_mgmt; guint32 channel; NM80211ApSecurityFlags flags; @@ -1213,14 +1229,12 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection) s_wireless = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wireless != NULL, NULL); - ssid = nm_setting_wireless_get_ssid (s_wireless); - g_return_val_if_fail (ssid != NULL, NULL); - g_return_val_if_fail (g_bytes_get_size (ssid) > 0, NULL); - ap = (NMWifiAP *) g_object_new (NM_TYPE_WIFI_AP, NULL); priv = NM_WIFI_AP_GET_PRIVATE (ap); priv->fake = TRUE; - nm_wifi_ap_set_ssid (ap, g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); + + nm_wifi_ap_set_ssid (ap, + nm_setting_wireless_get_ssid (s_wireless)); // FIXME: bssid too? @@ -1334,7 +1348,7 @@ finalize (GObject *object) g_free (priv->supplicant_path); if (priv->ssid) - g_byte_array_free (priv->ssid, TRUE); + g_bytes_unref (priv->ssid); g_free (priv->address); G_OBJECT_CLASS (nm_wifi_ap_parent_class)->finalize (object); @@ -1520,8 +1534,8 @@ nm_wifi_ap_lookup_for_device (NMDevice *device, const char *exported_path) g_return_val_if_fail (NM_IS_DEVICE (device), NULL); - ap = (NMWifiAP *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (device)), - exported_path); + ap = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (device)), + exported_path); if ( !ap || !NM_IS_WIFI_AP (ap) || ap->wifi_device != device) diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 4fdeee93..7462e9d1 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -72,10 +72,12 @@ gboolean nm_wifi_ap_complete_connection (NMWifiAP *self, GError **error); const char * nm_wifi_ap_get_supplicant_path (NMWifiAP *ap); -const GByteArray *nm_wifi_ap_get_ssid (const NMWifiAP *ap); -gboolean nm_wifi_ap_set_ssid (NMWifiAP *ap, +GBytes *nm_wifi_ap_get_ssid (const NMWifiAP *ap); +gboolean nm_wifi_ap_set_ssid_arr (NMWifiAP *ap, const guint8 *ssid, - gsize len); + gsize ssid_len); +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); diff --git a/src/devices/wifi/nm-wifi-utils.c b/src/devices/wifi/nm-wifi-utils.c index 044bd392..0f7836be 100644 --- a/src/devices/wifi/nm-wifi-utils.c +++ b/src/devices/wifi/nm-wifi-utils.c @@ -525,7 +525,7 @@ verify_adhoc (NMSettingWirelessSecurity *s_wsec, } gboolean -nm_wifi_utils_complete_connection (const GByteArray *ap_ssid, +nm_wifi_utils_complete_connection (GBytes *ap_ssid, const char *bssid, NM80211Mode ap_mode, guint32 ap_flags, @@ -538,7 +538,7 @@ nm_wifi_utils_complete_connection (const GByteArray *ap_ssid, NMSettingWireless *s_wifi; NMSettingWirelessSecurity *s_wsec; NMSetting8021x *s_8021x; - GBytes *ssid, *ap_ssid_bytes; + GBytes *ssid; const char *mode, *key_mgmt, *auth_alg, *leap_username; gboolean adhoc = FALSE; @@ -548,20 +548,17 @@ nm_wifi_utils_complete_connection (const GByteArray *ap_ssid, s_8021x = nm_connection_get_setting_802_1x (connection); /* Fill in missing SSID */ - ap_ssid_bytes = ap_ssid ? g_bytes_new (ap_ssid->data, ap_ssid->len) : NULL; ssid = nm_setting_wireless_get_ssid (s_wifi); if (!ssid) - g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid_bytes, NULL); - else if (!ap_ssid_bytes || !g_bytes_equal (ssid, ap_ssid_bytes)) { + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid, NULL); + else if (!ap_ssid || !g_bytes_equal (ssid, ap_ssid)) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("connection does not match access point")); g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SSID); - g_bytes_unref (ap_ssid_bytes); return FALSE; } - g_bytes_unref (ap_ssid_bytes); if (lock_bssid && !nm_setting_wireless_get_bssid (s_wifi)) g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL); @@ -764,7 +761,7 @@ nm_wifi_utils_complete_connection (const GByteArray *ap_ssid, } guint32 -nm_wifi_utils_level_to_quality (gint val) +nm_wifi_utils_level_to_quality (int val) { if (val < 0) { /* Assume dBm already; rough conversion: best = -40, worst = -100 */ @@ -783,8 +780,10 @@ nm_wifi_utils_level_to_quality (gint val) } gboolean -nm_wifi_utils_is_manf_default_ssid (const GByteArray *ssid) +nm_wifi_utils_is_manf_default_ssid (GBytes *ssid) { + const guint8 *ssid_p; + gsize ssid_l; int i; /* * List of manufacturer default SSIDs that are often unchanged by users. @@ -806,11 +805,46 @@ nm_wifi_utils_is_manf_default_ssid (const GByteArray *ssid) "TURBONETT", }; + ssid_p = g_bytes_get_data (ssid, &ssid_l); + for (i = 0; i < G_N_ELEMENTS (manf_defaults); i++) { - if (ssid->len == strlen (manf_defaults[i])) { - if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0) + if (ssid_l == strlen (manf_defaults[i])) { + if (memcmp (manf_defaults[i], ssid_p, ssid_l) == 0) return TRUE; } } return FALSE; } + +NMIwdNetworkSecurity +nm_wifi_connection_get_iwd_security (NMConnection *connection, + gboolean *mapped) +{ + NMSettingWirelessSecurity *s_wireless_sec; + const char *key_mgmt = NULL; + + if (!nm_connection_get_setting_wireless (connection)) + goto error; + + NM_SET_OUT (mapped, TRUE); + + s_wireless_sec = nm_connection_get_setting_wireless_security (connection); + if (!s_wireless_sec) + return NM_IWD_NETWORK_SECURITY_NONE; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); + nm_assert (key_mgmt); + + if (NM_IN_STRSET (key_mgmt, "none", "ieee8021x")) + return NM_IWD_NETWORK_SECURITY_WEP; + + if (nm_streq (key_mgmt, "wpa-psk")) + return NM_IWD_NETWORK_SECURITY_PSK; + + if (nm_streq (key_mgmt, "wpa-eap")) + return NM_IWD_NETWORK_SECURITY_8021X; + +error: + NM_SET_OUT (mapped, FALSE); + return NM_IWD_NETWORK_SECURITY_NONE; +} diff --git a/src/devices/wifi/nm-wifi-utils.h b/src/devices/wifi/nm-wifi-utils.h index def64dd6..03238c24 100644 --- a/src/devices/wifi/nm-wifi-utils.h +++ b/src/devices/wifi/nm-wifi-utils.h @@ -27,7 +27,14 @@ #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" -gboolean nm_wifi_utils_complete_connection (const GByteArray *ssid, +typedef enum { + NM_IWD_NETWORK_SECURITY_NONE, + NM_IWD_NETWORK_SECURITY_WEP, + NM_IWD_NETWORK_SECURITY_PSK, + NM_IWD_NETWORK_SECURITY_8021X, +} NMIwdNetworkSecurity; + +gboolean nm_wifi_utils_complete_connection (GBytes *ssid, const char *bssid, NM80211Mode mode, guint32 flags, @@ -37,8 +44,11 @@ gboolean nm_wifi_utils_complete_connection (const GByteArray *ssid, gboolean lock_bssid, GError **error); -guint32 nm_wifi_utils_level_to_quality (gint val); +guint32 nm_wifi_utils_level_to_quality (int val); + +gboolean nm_wifi_utils_is_manf_default_ssid (GBytes *ssid); -gboolean nm_wifi_utils_is_manf_default_ssid (const GByteArray *ssid); +NMIwdNetworkSecurity nm_wifi_connection_get_iwd_security (NMConnection *connection, + gboolean *mapped); #endif /* __NM_WIFI_UTILS_H__ */ diff --git a/src/devices/wifi/tests/test-general.c b/src/devices/wifi/tests/test-general.c index 89eebb22..f752bbfc 100644 --- a/src/devices/wifi/tests/test-general.c +++ b/src/devices/wifi/tests/test-general.c @@ -74,8 +74,7 @@ complete_connection (const char *ssid, NMConnection *src, GError **error) { - GByteArray *tmp; - gboolean success; + gs_unref_bytes GBytes *ssid_b = NULL; NMSettingWireless *s_wifi; /* Add a wifi setting if one doesn't exist */ @@ -85,20 +84,17 @@ complete_connection (const char *ssid, nm_connection_add_setting (src, NM_SETTING (s_wifi)); } - tmp = g_byte_array_sized_new (strlen (ssid)); - g_byte_array_append (tmp, (const guint8 *) ssid, strlen (ssid)); - - success = nm_wifi_utils_complete_connection (tmp, - bssid, - mode, - flags, - wpa_flags, - rsn_flags, - src, - lock_bssid, - error); - g_byte_array_free (tmp, TRUE); - return success; + ssid_b = g_bytes_new (ssid, strlen (ssid)); + + return nm_wifi_utils_complete_connection (ssid_b, + bssid, + mode, + flags, + wpa_flags, + rsn_flags, + src, + lock_bssid, + error); } typedef struct { @@ -127,7 +123,7 @@ set_items (NMSetting *setting, const KeyData *items) g_assert (item->str == NULL); g_object_set (G_OBJECT (setting), item->key, item->uint, NULL); } else if (pspec->value_type == G_TYPE_INT) { - gint foo = (gint) item->uint; + int foo = (int) item->uint; g_assert (item->str == NULL); g_object_set (G_OBJECT (setting), item->key, foo, NULL); @@ -1462,7 +1458,7 @@ main (int argc, char **argv) test_ap_wpa_eap_connection_5); #define ADD_FUNC(func) do { \ - gchar *name_idx = g_strdup_printf ("/wifi/wpa_psk/" G_STRINGIFY (func) "/%zd", i); \ + char *name_idx = g_strdup_printf ("/wifi/wpa_psk/" G_STRINGIFY (func) "/%zd", i); \ g_test_add_data_func (name_idx, (gconstpointer) i, func); \ g_free (name_idx); \ } while (0) @@ -1487,7 +1483,7 @@ main (int argc, char **argv) #undef ADD_FUNC #define ADD_FUNC(func) do { \ - gchar *name_idx = g_strdup_printf ("/wifi/rsn_psk/" G_STRINGIFY (func) "/%zd", i); \ + char *name_idx = g_strdup_printf ("/wifi/rsn_psk/" G_STRINGIFY (func) "/%zd", i); \ g_test_add_data_func (name_idx, (gconstpointer) i, func); \ g_free (name_idx); \ } while (0) |