supplicant: adjust fragment_size according to MTU (bgo #755145)
authorJiří Klimeš <jklimes@redhat.com>
Wed, 16 Sep 2015 16:22:08 +0000 (18:22 +0200)
committerJiří Klimeš <jklimes@redhat.com>
Wed, 23 Sep 2015 10:41:11 +0000 (12:41 +0200)
NetworkManager set wpa_supplicant's fragment_size option to 1300. But if MTU
was lower, wpa_supplicant failed with "l2_packet_send - sendto: Message too
long" due to fragmentation of EAP-TLS or EAP-PEAP packets.

Actually, MTU has to be 14 bytes bigger than the "fragment_size" parameter.

Ideally, wpa_supplicant would take MTU in the account and adjust the
fragmentation limit accordingly. See discussion in
http://lists.shmoo.com/pipermail/hostap/2015-August/033546.html

https://bugzilla.gnome.org/show_bug.cgi?id=755145

configure.ac
src/devices/nm-device-ethernet.c
src/devices/wifi/nm-device-wifi.c
src/supplicant-manager/nm-supplicant-config.c
src/supplicant-manager/nm-supplicant-config.h
src/supplicant-manager/tests/Makefile.am
src/supplicant-manager/tests/certs/Makefile.am [new file with mode: 0644]
src/supplicant-manager/tests/certs/test-ca-cert.pem [new file with mode: 0644]
src/supplicant-manager/tests/certs/test-cert.p12 [new file with mode: 0644]
src/supplicant-manager/tests/test-supplicant-config.c

index 0deb4a4..d4f673f 100644 (file)
@@ -1014,6 +1014,7 @@ src/dhcp-manager/Makefile
 src/dhcp-manager/tests/Makefile
 src/dnsmasq-manager/tests/Makefile
 src/supplicant-manager/tests/Makefile
+src/supplicant-manager/tests/certs/Makefile
 src/ppp-manager/Makefile
 src/settings/plugins/Makefile
 src/settings/plugins/ifupdown/Makefile
index ff3994d..319ce1f 100644 (file)
@@ -566,15 +566,18 @@ build_supplicant_config (NMDeviceEthernet *self)
        NMSupplicantConfig *config = NULL;
        NMSetting8021x *security;
        NMConnection *connection;
+       guint32 mtu;
 
        connection = nm_device_get_applied_connection (NM_DEVICE (self));
        g_assert (connection);
        con_uuid = nm_connection_get_uuid (connection);
+       mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET,
+                                       nm_device_get_ifindex (NM_DEVICE (self)));
 
        config = nm_supplicant_config_new ();
 
        security = nm_connection_get_setting_802_1x (connection);
-       if (!nm_supplicant_config_add_setting_8021x (config, security, con_uuid, TRUE)) {
+       if (!nm_supplicant_config_add_setting_8021x (config, security, con_uuid, mtu, TRUE)) {
                _LOGW (LOGD_DEVICE, "Couldn't add 802.1X security setting to supplicant config.");
                g_object_unref (config);
                config = NULL;
index 2996218..225a477 100644 (file)
@@ -2225,13 +2225,16 @@ build_supplicant_config (NMDeviceWifi *self,
        if (s_wireless_sec) {
                NMSetting8021x *s_8021x;
                const char *con_uuid = nm_connection_get_uuid (connection);
+               guint32 mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET,
+                                                       nm_device_get_ifindex (NM_DEVICE (self)));
 
                g_assert (con_uuid);
                s_8021x = nm_connection_get_setting_802_1x (connection);
                if (!nm_supplicant_config_add_setting_wireless_security (config,
                                                                         s_wireless_sec,
                                                                         s_8021x,
-                                                                        con_uuid)) {
+                                                                        con_uuid,
+                                                                        mtu)) {
                        _LOGE (LOGD_WIFI, "Couldn't add 802-11-wireless-security setting to supplicant config.");
                        goto error;
                }
index 86fd181..65d6e2d 100644 (file)
@@ -610,7 +610,8 @@ gboolean
 nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                     NMSettingWirelessSecurity *setting,
                                                     NMSetting8021x *setting_8021x,
-                                                    const char *con_uuid)
+                                                    const char *con_uuid,
+                                                    guint32 mtu)
 {
        gboolean success = FALSE;
        const char *key_mgmt, *auth_alg;
@@ -727,7 +728,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) {
                    if (!setting_8021x)
                        return FALSE;
-                       if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, FALSE))
+                       if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, mtu, FALSE))
                                return FALSE;
                }
 
@@ -754,6 +755,7 @@ gboolean
 nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                         NMSetting8021x *setting,
                                         const char *con_uuid,
+                                        guint32 mtu,
                                         gboolean wired)
 {
        NMSupplicantConfigPrivate *priv;
@@ -766,6 +768,8 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
        guint32 i, num_eap;
        gboolean fast_provisoning_allowed = FALSE;
        const char *ca_path_override = NULL, *ca_cert_override = NULL;
+       guint32 frag, hdrs;
+       gs_free char *frag_str = NULL;
 
        g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
        g_return_val_if_fail (setting != NULL, FALSE);
@@ -817,8 +821,15 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                }
        }
 
-       /* Drop the fragment size a bit for better compatibility */
-       if (!nm_supplicant_config_add_option (self, "fragment_size", "1300", -1, FALSE))
+       /* Adjust the fragment size according to MTU, but do not set it higher than 1280-14
+        * for better compatibility */
+       hdrs = 14; /* EAPOL + EAP-TLS */
+       frag = 1280 - hdrs;
+       if (mtu > hdrs)
+               frag = CLAMP (mtu - hdrs, 100, frag);
+       frag_str = g_strdup_printf ("%u", frag);
+
+       if (!nm_supplicant_config_add_option (self, "fragment_size", frag_str, -1, FALSE))
                return FALSE;
 
        phase1 = g_string_new (NULL);
index 76a404d..0cd3243 100644 (file)
@@ -70,13 +70,15 @@ gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self,
 gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                              NMSettingWirelessSecurity *setting,
                                                              NMSetting8021x *setting_8021x,
-                                                             const char *con_uuid);
+                                                             const char *con_uuid,
+                                                             guint32 mtu);
 
 gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self);
 
 gboolean nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                                  NMSetting8021x *setting,
                                                  const char *con_uuid,
+                                                 guint32 mtu,
                                                  gboolean wired);
 
 G_END_DECLS
index 63193a1..e786664 100644 (file)
@@ -1,3 +1,5 @@
+SUBDIRS=certs
+
 AM_CPPFLAGS = \
        -I$(top_srcdir)/include \
        -I$(top_srcdir)/libnm-core \
@@ -7,6 +9,7 @@ AM_CPPFLAGS = \
        -DG_LOG_DOMAIN=\""NetworkManager"\" \
        -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \
        -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+       -DTEST_CERT_DIR=\"$(srcdir)/certs/\" \
        $(GLIB_CFLAGS)
 
 noinst_PROGRAMS = test-supplicant-config
diff --git a/src/supplicant-manager/tests/certs/Makefile.am b/src/supplicant-manager/tests/certs/Makefile.am
new file mode 100644 (file)
index 0000000..f2e889f
--- /dev/null
@@ -0,0 +1,6 @@
+CERTS = \
+       test-ca-cert.pem \
+       test-cert.p12
+
+EXTRA_DIST = $(CERTS)
+
diff --git a/src/supplicant-manager/tests/certs/test-ca-cert.pem b/src/supplicant-manager/tests/certs/test-ca-cert.pem
new file mode 100644 (file)
index 0000000..ef1be20
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEjzCCA3egAwIBAgIJAOvnZPt59yIZMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYD
+VQQGEwJVUzESMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcw
+FQYDVQQKEw5NeSBDb21wYW55IEx0ZDEQMA4GA1UECxMHVGVzdGluZzENMAsGA1UE
+AxMEdGVzdDEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTAeFw0wOTAzMTAx
+NTEyMTRaFw0xOTAzMDgxNTEyMTRaMIGLMQswCQYDVQQGEwJVUzESMBAGA1UECBMJ
+QmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5NeSBDb21wYW55
+IEx0ZDEQMA4GA1UECxMHVGVzdGluZzENMAsGA1UEAxMEdGVzdDEcMBoGCSqGSIb3
+DQEJARYNdGVzdEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAKot9j+/+CX1/gZLgJHIXCRgCItKLGnf7qGbgqB9T2ACBqR0jllKWwDKrcWU
+xjXNIc+GF9Wnv+lX6G0Okn4Zt3/uRNobL+2b/yOF7M3Td3/9W873zdkQQX930YZc
+Rr8uxdRPP5bxiCgtcw632y21sSEbG9mjccAUnV/0jdvfmMNj0i8gN6E0fMBiJ9S3
+FkxX/KFvt9JWE9CtoyL7ki7UIDq+6vj7Gd5N0B3dOa1y+rRHZzKlJPcSXQSEYUS4
+HmKDwiKSVahft8c4tDn7KPi0vex91hlgZVd3usL2E/Vq7o5D9FAZ5kZY0AdFXwdm
+J4lO4Mj7ac7GE4vNERNcXVIX59sCAwEAAaOB8zCB8DAdBgNVHQ4EFgQUuDU3Mr7P
+T3n1e3Sy8hBauoDFahAwgcAGA1UdIwSBuDCBtYAUuDU3Mr7PT3n1e3Sy8hBauoDF
+ahChgZGkgY4wgYsxCzAJBgNVBAYTAlVTMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAO
+BgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMRAwDgYDVQQL
+EwdUZXN0aW5nMQ0wCwYDVQQDEwR0ZXN0MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRl
+c3QuY29tggkA6+dk+3n3IhkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC
+AQEAVRG4aALIvCXCiKfe7K+iJxjBVRDFPEf7JWA9LGgbFOn6pNvbxonrR+0BETdc
+JV1ET4ct2xsE7QNFIkp9GKRC+6J32zCo8qtLCD5+v436r8TUG2/t2JRMkb9I2XVT
+p7RJoot6M0Ltf8KNQUPYh756xmKZ4USfQUwc58MOSDGY8VWEXJOYij9Pf0e0c52t
+qiCEjXH7uXiS8Pgq9TYm7AkWSOrglYhSa83x0f8mtT8Q15nBESIHZ6o8FAS2bBgn
+B0BkrKRjtBUkuJG3vTox+bYINh2Gxi1JZHWSV1tN5z3hd4VFcKqanW5OgQwToBqp
+3nniskIjbH0xjgZf/nVMyLnjxg==
+-----END CERTIFICATE-----
diff --git a/src/supplicant-manager/tests/certs/test-cert.p12 b/src/supplicant-manager/tests/certs/test-cert.p12
new file mode 100644 (file)
index 0000000..ae4a683
Binary files /dev/null and b/src/supplicant-manager/tests/certs/test-cert.p12 differ
index 24bfbfd..11b027a 100644 (file)
@@ -268,7 +268,8 @@ test_wifi_wep_key (const char *detail,
        g_assert (nm_supplicant_config_add_setting_wireless_security (config,
                                                                      s_wsec,
                                                                      NULL,
-                                                                     "376aced7-b28c-46be-9a62-fcdf072571da"));
+                                                                     "376aced7-b28c-46be-9a62-fcdf072571da",
+                                                                     1500));
        g_test_assert_expected_messages ();
 
        config_dict = nm_supplicant_config_to_variant (config);
@@ -408,7 +409,8 @@ test_wifi_wpa_psk (const char *detail,
        g_assert (nm_supplicant_config_add_setting_wireless_security (config,
                                                                      s_wsec,
                                                                      NULL,
-                                                                     "376aced7-b28c-46be-9a62-fcdf072571da"));
+                                                                     "376aced7-b28c-46be-9a62-fcdf072571da",
+                                                                     1500));
        g_test_assert_expected_messages ();
 
        config_dict = nm_supplicant_config_to_variant (config);
@@ -438,6 +440,142 @@ test_wifi_wpa_psk_types (void)
        test_wifi_wpa_psk ("wifi-wep-psk-passphrase", TYPE_STRING, key2, (gconstpointer) key2, strlen (key2));
 }
 
+static void
+test_wifi_eap (void)
+{
+       gs_unref_object NMConnection *connection = NULL;
+       gs_unref_object NMSupplicantConfig *config = NULL;
+       gs_unref_variant GVariant *config_dict = NULL;
+       NMSettingConnection *s_con;
+       NMSettingWireless *s_wifi;
+       NMSettingWirelessSecurity *s_wsec;
+       NMSetting8021x *s_8021x;
+       NMSettingIPConfig *s_ip4;
+       char *uuid;
+       gboolean success;
+       GError *error = NULL;
+       GBytes *ssid;
+       const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+       const char *bssid_str = "11:22:33:44:55:66";
+       guint32 mtu = 1100;
+
+       connection = nm_simple_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 Wifi EAP-TLS",
+                     NM_SETTING_CONNECTION_UUID, uuid,
+                     NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+                     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_bytes_new (ssid_data, sizeof (ssid_data));
+
+       g_object_set (s_wifi,
+                     NM_SETTING_WIRELESS_SSID, ssid,
+                     NM_SETTING_WIRELESS_BSSID, bssid_str,
+                     NM_SETTING_WIRELESS_MODE, "infrastructure",
+                     NM_SETTING_WIRELESS_BAND, "bg",
+                     NULL);
+
+       g_bytes_unref (ssid);
+
+       /* Wifi Security setting */
+       s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+       nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+       g_object_set (s_wsec,
+                     NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
+                     NULL);
+
+       nm_setting_wireless_security_add_proto (s_wsec, "wpa");
+       nm_setting_wireless_security_add_proto (s_wsec, "rsn");
+       nm_setting_wireless_security_add_pairwise (s_wsec, "tkip");
+       nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp");
+       nm_setting_wireless_security_add_group (s_wsec, "tkip");
+       nm_setting_wireless_security_add_group (s_wsec, "ccmp");
+
+       /* 802-1X setting */
+       s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+       nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+       nm_setting_802_1x_add_eap_method (s_8021x, "tls");
+       nm_setting_802_1x_set_client_cert (s_8021x, TEST_CERT_DIR "test-cert.p12", NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL);
+       nm_setting_802_1x_set_ca_cert (s_8021x, TEST_CERT_DIR "test-ca-cert.pem", NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL);
+       nm_setting_802_1x_set_private_key (s_8021x, TEST_CERT_DIR "test-cert.p12", NULL, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL);
+
+       /* IP4 setting */
+       s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+       nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+       g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+       success = nm_connection_verify (connection, &error);
+       g_assert_no_error (error);
+       g_assert (success);
+
+       config = nm_supplicant_config_new ();
+
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*added 'ssid' value 'Test SSID'*");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*added 'scan_ssid' value '1'*");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*added 'bssid' value '11:22:33:44:55:66'*");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*added 'freq_list' value *");
+       g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0));
+       g_test_assert_expected_messages ();
+
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*added 'key_mgmt' value 'WPA-EAP'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*added 'proto' value 'WPA RSN'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*added 'pairwise' value 'TKIP CCMP'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*added 'group' value 'TKIP CCMP'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*Config: added 'eap' value 'TLS'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*Config: added 'fragment_size' value '1086'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "* Config: added 'ca_cert' value '*/test-ca-cert.pem'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "* Config: added 'private_key' value '*/test-cert.p12'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*Config: added 'bgscan' value 'simple:30:-65:300'");
+       g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+                              "*Config: added 'proactive_key_caching' value '1'");
+       g_assert (nm_supplicant_config_add_setting_wireless_security (config,
+                                                                     s_wsec,
+                                                                     s_8021x,
+                                                                     "d5b488af-9cab-41ed-bad4-97709c58430f",
+                                                                     mtu));
+       g_test_assert_expected_messages ();
+
+       config_dict = nm_supplicant_config_to_variant (config);
+       g_assert (config_dict);
+
+       validate_opt ("wifi-eap", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1);
+       validate_opt ("wifi-eap", config_dict, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data));
+       validate_opt ("wifi-eap", config_dict, "bssid", TYPE_KEYWORD, bssid_str, -1);
+       validate_opt ("wifi-eap", config_dict, "key_mgmt", TYPE_KEYWORD, "WPA-EAP", -1);
+       validate_opt ("wifi-eap", config_dict, "eap", TYPE_KEYWORD, "TLS", -1);
+       validate_opt ("wifi-eap", config_dict, "proto", TYPE_KEYWORD, "WPA RSN", -1);
+       validate_opt ("wifi-eap", config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP", -1);
+       validate_opt ("wifi-eap", config_dict, "group", TYPE_KEYWORD, "TKIP CCMP", -1);
+       validate_opt ("wifi-eap", config_dict, "fragment_size", TYPE_INT, GINT_TO_POINTER(mtu-14), -1);
+}
+
 NMTST_DEFINE ();
 
 int main (int argc, char **argv)
@@ -447,6 +585,7 @@ int main (int argc, char **argv)
        g_test_add_func ("/supplicant-config/wifi-open", test_wifi_open);
        g_test_add_func ("/supplicant-config/wifi-wep", test_wifi_wep);
        g_test_add_func ("/supplicant-config/wifi-wpa-psk-types", test_wifi_wpa_psk_types);
+       g_test_add_func ("/supplicant-config/wifi-eap", test_wifi_eap);
 
        return g_test_run ();
 }