diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c index b3b8c70f96..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. * @@ -1142,6 +1161,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 +1211,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 +1290,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 */ @@ -3623,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)); 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;