#define ESP_HEADER_SIZE (4 /* SPI */ + 4 /* sequence number */)
#define ESP_FOOTER_SIZE (1 /* pad length */ + 1 /* next header */)
#define UDP_HEADER_SIZE 8
+#define TCP_HEADER_SIZE 20 /* with no options */
#define IPV4_HEADER_SIZE 20
#define IPV6_HEADER_SIZE 40
static int calculate_mtu(struct openconnect_info *vpninfo)
{
int mtu = vpninfo->reqmtu, base_mtu = vpninfo->basemtu;
+ int mss = 0;
#if defined(__linux__) && defined(TCP_INFO)
- if (!mtu || !base_mtu) {
+ if (!mtu) {
struct tcp_info ti;
socklen_t ti_size = sizeof(ti);
base_mtu = ti.tcpi_pmtu;
}
- if (!base_mtu) {
- if (ti.tcpi_rcv_mss < ti.tcpi_snd_mss)
- base_mtu = ti.tcpi_rcv_mss - 21;
- else
- base_mtu = ti.tcpi_snd_mss - 21;
- }
+ /* XXX: GlobalProtect has no mechanism to inform the server about the
+ * desired MTU, so could just ignore the "incoming" MSS (tcpi_rcv_mss).
+ */
+ mss = MIN(ti.tcpi_rcv_mss, ti.tcpi_snd_mss);
}
}
#endif
#ifdef TCP_MAXSEG
- if (!base_mtu) {
- int mss;
+ if (!mtu && !mss) {
socklen_t mss_size = sizeof(mss);
if (!getsockopt(vpninfo->ssl_fd, IPPROTO_TCP, TCP_MAXSEG,
&mss, &mss_size)) {
vpn_progress(vpninfo, PRG_DEBUG, _("TCP_MAXSEG %d\n"), mss);
- base_mtu = mss - 21;
}
}
#endif
if (base_mtu < 1280)
base_mtu = 1280;
- if (!mtu) {
+#ifdef HAVE_ESP
+ /* If we can use the ESP tunnel (got secrets in config),
+ * then we should pick the optimal MTU for ESP.
+ */
+ if (!mtu && vpninfo->dtls_state == DTLS_SECRET) {
/* remove ESP, UDP, IP headers from base (wire) MTU */
mtu = ( base_mtu - UDP_HEADER_SIZE - ESP_HEADER_SIZE
- 12 /* both supported algos (SHA1 and MD5) have 96-bit MAC lengths (RFC2403 and RFC2404) */
mtu -= mtu % (vpninfo->enc_key_len ? : 32);
/* subtract ESP footer, which is included in the payload before padding to the blocksize */
mtu -= ESP_FOOTER_SIZE;
+
+ } else
+#endif
+
+ /* We are definitely using the TLS tunnel (no ESP secrets)
+ * so we should base our MTU on the TCP MSS.
+ */
+ if (!mtu) {
+ if (mss)
+ mtu = mss - 21;
+ else {
+ mtu = base_mtu - TCP_HEADER_SIZE - 21;
+ if (vpninfo->peer_addr->sa_family == AF_INET6)
+ mtu -= IPV6_HEADER_SIZE;
+ else
+ mtu -= IPV4_HEADER_SIZE;
+ }
}
return mtu;
}