From 85905a1ecff6407e02c22f272cb3758e3c5c3200 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 28 Feb 2014 16:34:20 -0600 Subject: [PATCH 1/3] ifcfg-rh: add support for SSID_HIDDEN (rh #1069844) Read and write the hidden SSID flag, which helps NM figure out when to probe-scan for hidden networks. --- src/settings/plugins/ifcfg-rh/reader.c | 5 + .../tests/network-scripts/Makefile.am | 1 + .../network-scripts/ifcfg-test-wifi-hidden | 10 ++ .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 116 ++++++++++++++++++ src/settings/plugins/ifcfg-rh/writer.c | 2 + 5 files changed, 134 insertions(+) create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-hidden diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index ef73205b8b..c1fd181463 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -3650,6 +3650,11 @@ make_wireless_setting (shvarFile *ifcfg, g_free (value); } + g_object_set (s_wireless, + NM_SETTING_WIRELESS_HIDDEN, + svTrueValue (ifcfg, "SSID_HIDDEN", FALSE), + NULL); + return NM_SETTING (s_wireless); error: diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am index b3bd6936e3..db9cba22b7 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am @@ -57,6 +57,7 @@ EXTRA_DIST = \ keys-test-wifi-wpa-eap-tls \ ifcfg-test-wifi-wpa-eap-ttls-tls \ keys-test-wifi-wpa-eap-ttls-tls \ + ifcfg-test-wifi-hidden \ test_ca_cert.pem \ test1_key_and_cert.pem \ ifcfg-test-ibft-dhcp \ diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-hidden b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-hidden new file mode 100644 index 0000000000..08b9a730a6 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-hidden @@ -0,0 +1,10 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +TYPE=Wireless +DEVICE=eth2 +HWADDR=00:16:41:11:22:33 +BOOTPROTO=dhcp +ONBOOT=yes +ESSID=blahblah +MODE=Managed +SSID_HIDDEN=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 715b110b0a..e4346c6bc3 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -5760,6 +5760,120 @@ test_read_wifi_wep_eap_ttls_chap (void) g_object_unref (connection); } +static void +test_read_wifi_hidden (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + gboolean success; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-hidden", + NULL, TYPE_WIRELESS, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_no_error (error); + g_assert (connection); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRELESS_SETTING_NAME); + + s_wifi = nm_connection_get_setting_wireless (connection); + g_assert (s_wifi); + g_assert (nm_setting_wireless_get_hidden (s_wifi) == TRUE); + + g_object_unref (connection); +} + +static void +test_write_wifi_hidden (void) +{ + NMConnection *connection, *reread; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + char *uuid, *testfile = NULL, *val; + gboolean success; + GError *error = NULL; + shvarFile *f; + GByteArray *ssid; + const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 }; + + connection = nm_connection_new (); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Write WiFi Hidden", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + g_free (uuid); + + /* Wifi setting */ + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + ssid = g_byte_array_sized_new (sizeof (ssid_data)); + g_byte_array_append (ssid, ssid_data, sizeof (ssid_data)); + + g_object_set (s_wifi, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_MODE, "infrastructure", + NM_SETTING_WIRELESS_HIDDEN, TRUE, + NULL); + + g_byte_array_free (ssid, TRUE); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + f = svNewFile (testfile); + g_assert (f); + + g_assert_no_error (error); + g_assert (success); + + /* re-read the file to check that what key was written. */ + val = svGetValue (f, "SSID_HIDDEN", FALSE); + g_assert (val); + g_assert_cmpstr (val, ==, "yes"); + g_free (val); + svCloseFile (f); + + /* reread will be normalized, so we must normalize connection too. */ + nm_utils_normalize_connection (connection, TRUE); + + /* re-read the connection for comparison */ + reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL, + NULL, NULL, NULL, NULL, &error, NULL); + unlink (testfile); + g_assert_no_error (error); + g_assert (reread); + + success = nm_connection_verify (reread, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + + g_free (testfile); + g_object_unref (connection); + g_object_unref (reread); +} + #define TEST_IFCFG_WIRED_QETH_STATIC TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-qeth-static" static void @@ -13781,6 +13895,7 @@ int main (int argc, char **argv) test_read_wifi_wpa_eap_tls (); test_read_wifi_wpa_eap_ttls_tls (); test_read_wifi_wep_eap_ttls_chap (); + g_test_add_func (TPATH "wifi/read-hidden", test_read_wifi_hidden); test_read_wired_qeth_static (); test_read_wired_ctc_static (); test_read_wifi_wep_no_keys (); @@ -13857,6 +13972,7 @@ int main (int argc, char **argv) test_write_wifi_dynamic_wep_leap (); test_write_wifi_wpa_then_open (); test_write_wifi_wpa_then_wep_with_perms (); + g_test_add_func (TPATH "wifi/write-hidden", test_write_wifi_hidden); test_write_wired_qeth_dhcp (); test_write_wired_ctc_dhcp (); test_write_permissions (); diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index b687beedad..5584f6ed3e 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -984,6 +984,8 @@ write_wireless_setting (NMConnection *connection, g_free (keys_path); } + svSetValue (ifcfg, "SSID_HIDDEN", nm_setting_wireless_get_hidden (s_wireless) ? "yes" : NULL, TRUE); + svSetValue (ifcfg, "TYPE", TYPE_WIRELESS, FALSE); return TRUE; From 787455bae149a1f9fd7152aab290be6c7a4d39f3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 Mar 2014 11:49:28 -0600 Subject: [PATCH 2/3] wifi: add HIDDEN flag for completed connections without an AP (rh #1069844) If an AP object is not given, and no compatible AP can be found in the scan list, the AP is most likely not broadcasting its SSID and should be marked as 'hidden'. --- src/devices/nm-device-wifi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c index b3b8c70f96..06ac602a2a 100644 --- a/src/devices/nm-device-wifi.c +++ b/src/devices/nm-device-wifi.c @@ -1142,6 +1142,7 @@ complete_connection (NMDevice *device, NMAccessPoint *ap = NULL; const GByteArray *ssid = NULL; GSList *iter; + gboolean hidden = FALSE; s_wifi = nm_connection_get_setting_wireless (connection); s_wsec = nm_connection_get_setting_wireless_security (connection); @@ -1191,6 +1192,8 @@ complete_connection (NMDevice *device, g_slist_free (settings); if (!valid) return FALSE; + + hidden = TRUE; } } else { ap = get_ap_by_path (self, specific_object); @@ -1268,6 +1271,9 @@ complete_connection (NMDevice *device, g_free (str_ssid); g_free (format); + if (hidden) + g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); + setting_mac = nm_setting_wireless_get_mac_address (s_wifi); if (setting_mac) { /* Make sure the setting MAC (if any) matches the device's permanent MAC */ From 23a5ae2f4490c5e64787af4fcab7a4bc63cfc852 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 5 Mar 2014 10:16:39 -0600 Subject: [PATCH 3/3] wifi: bypass available check for hidden APs during activation (rh #1069844) Because not all clients set the 'hidden' property in a connection for hidden/non-SSID-broadcasting networks, they may not show up in the device's available-connections property. After the PendingActivation object removal, all activations require the connection to be in available-connections, and thus hidden SSID networks could not be activated. Unfortunately check_connection_available() is used both during activation and to populate the available-connections array, but we only want to special-case activation paths, and still ensure that SSIDs not found in the scan list are not in available-connections. To make it clear this is a WiFi only hack, and that we should remove it at some point in the future, create another class method specifically for hidden WiFi and use that in activation paths to special-case hidden WiFi connection activation. --- src/devices/nm-device-wifi.c | 28 ++++++++++++++++++++++++---- src/devices/nm-device.c | 33 ++++++++++++++++++++++++++++++--- src/devices/nm-device.h | 12 +++++++++++- src/nm-manager.c | 6 +++--- 4 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c index 06ac602a2a..363b83ab54 100644 --- a/src/devices/nm-device-wifi.c +++ b/src/devices/nm-device-wifi.c @@ -1050,9 +1050,10 @@ check_connection_compatible (NMDevice *device, static gboolean -check_connection_available (NMDevice *device, - NMConnection *connection, - const char *specific_object) +_internal_check_connection_available (NMDevice *device, + NMConnection *connection, + const char *specific_object, + gboolean ignore_ap_list) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); NMSettingWireless *s_wifi; @@ -1077,7 +1078,7 @@ check_connection_available (NMDevice *device, return TRUE; /* Hidden SSIDs obviously don't always appear in the scan list either */ - if (nm_setting_wireless_get_hidden (s_wifi)) + if (nm_setting_wireless_get_hidden (s_wifi) || ignore_ap_list) return TRUE; /* check if its visible */ @@ -1089,6 +1090,24 @@ check_connection_available (NMDevice *device, return FALSE; } +static gboolean +check_connection_available (NMDevice *device, + NMConnection *connection, + const char *specific_object) +{ + return _internal_check_connection_available (device, connection, specific_object, FALSE); +} + +/* FIXME: remove this function when we require the 'hidden' property to be + * set before a hidden connection can be activated. + */ +static gboolean +check_connection_available_wifi_hidden (NMDevice *device, + NMConnection *connection) +{ + return _internal_check_connection_available (device, connection, NULL, TRUE); +} + /* * List of manufacturer default SSIDs that are often unchanged by users. * @@ -3629,6 +3648,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; parent_class->check_connection_available = check_connection_available; + parent_class->check_connection_available_wifi_hidden = check_connection_available_wifi_hidden; parent_class->complete_connection = complete_connection; parent_class->set_enabled = set_enabled; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 699b9785c7..fb37c968d6 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1643,7 +1643,7 @@ can_auto_connect (NMDevice *device, if (!nm_setting_connection_get_autoconnect (s_con)) return FALSE; - return nm_device_connection_is_available (device, connection); + return nm_device_connection_is_available (device, connection, FALSE); } static gboolean @@ -7046,10 +7046,26 @@ nm_device_get_autoconnect (NMDevice *device) return NM_DEVICE_GET_PRIVATE (device)->autoconnect; } +/** + * nm_device_connection_is_available(): + * @device: the #NMDevice + * @connection: the #NMConnection to check for availability + * @allow_device_override: set to %TRUE to let the device do specific checks + * + * Check if @connection is available to be activated on @device. Normally this + * only checks if the connection is in @device's AvailableConnections property. + * If @allow_device_override is %TRUE then the device is asked to do specific + * checks that may bypass the AvailableConnections property. + * + * Returns: %TRUE if @connection can be activated on @device + */ gboolean -nm_device_connection_is_available (NMDevice *device, NMConnection *connection) +nm_device_connection_is_available (NMDevice *device, + NMConnection *connection, + gboolean allow_device_override) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + gboolean available = FALSE; if (priv->default_unmanaged && (priv->state == NM_DEVICE_STATE_UNMANAGED)) { /* default-unmanaged devices in UNMANAGED state have no available connections @@ -7060,7 +7076,18 @@ nm_device_connection_is_available (NMDevice *device, NMConnection *connection) return TRUE; } - return !!g_hash_table_lookup (priv->available_connections, connection); + available = !!g_hash_table_lookup (priv->available_connections, connection); + if (!available && allow_device_override) { + /* FIXME: hack for hidden WiFi becuase clients didn't consistently + * set the 'hidden' property to indicate hidden SSID networks. If + * activating but the network isn't available let the device recheck + * availability. + */ + if (NM_DEVICE_GET_CLASS (device)->check_connection_available_wifi_hidden) + available = NM_DEVICE_GET_CLASS (device)->check_connection_available_wifi_hidden (device, connection); + } + + return available; } static void diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 297bbe9cfc..47d7856f34 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -153,6 +153,14 @@ typedef struct { NMConnection *connection, const char *specific_object); + /* Same as check_connection_available() but called if the connection + * is not present in the activating-connections array during activation, + * to give the device a chance to allow/deny the activation. This is a + * hack only meant for hidden WiFi networks. + */ + gboolean (* check_connection_available_wifi_hidden) (NMDevice *self, + NMConnection *connection); + gboolean (* complete_connection) (NMDevice *self, NMConnection *connection, const char *specific_object, @@ -331,7 +339,9 @@ const char *nm_device_get_physical_port_id (NMDevice *device); guint32 nm_device_get_mtu (NMDevice *device); -gboolean nm_device_connection_is_available (NMDevice *device, NMConnection *connection); +gboolean nm_device_connection_is_available (NMDevice *device, + NMConnection *connection, + gboolean allow_device_override); gboolean nm_device_notify_component_added (NMDevice *device, GObject *component); diff --git a/src/nm-manager.c b/src/nm-manager.c index 26e65d84fe..1466a429f0 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2501,7 +2501,7 @@ ensure_master_active_connection (NMManager *self, if (!is_compatible_with_slave (candidate, connection)) continue; - if (nm_device_connection_is_available (master_device, candidate)) { + if (nm_device_connection_is_available (master_device, candidate, TRUE)) { master_ac = nm_manager_activate_connection (self, candidate, NULL, @@ -2542,7 +2542,7 @@ ensure_master_active_connection (NMManager *self, continue; } - if (!nm_device_connection_is_available (candidate, master_connection)) + if (!nm_device_connection_is_available (candidate, master_connection, TRUE)) continue; found_device = TRUE; @@ -2658,7 +2658,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } /* Final connection must be available on device */ - if (!nm_device_connection_is_available (device, connection)) { + if (!nm_device_connection_is_available (device, connection, TRUE)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "Connection '%s' is not available on the device %s at this time.", nm_connection_get_id (connection), nm_device_get_iface (device));