]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[tcp] Calculate correct MSS from peer address
authorMichael Brown <mcb30@ipxe.org>
Tue, 4 Mar 2014 13:14:13 +0000 (13:14 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 4 Mar 2014 13:23:29 +0000 (13:23 +0000)
iPXE currently advertises a fixed MSS of 1460, which is correct only
for IPv4 over Ethernet.  For IPv6 over Ethernet, the value should be
1440 (allowing for the larger IPv6 header).  For non-Ethernet link
layers, the value should reflect the MTU of the underlying network
device.

Use tcpip_mtu() to calculate the transport-layer MTU associated with
the peer address, and calculate the MSS to allow for an optionless TCP
header as per RFC 6691.

As a side benefit, we can now fail a connection immediately with a
meaningful error message if we have no route to the destination
address.

Reported-by: Anton D. Kachalov <mouse@yandex-team.ru>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/tcp.h
src/net/tcp.c

index eb4b7b222954df992bb762efb1ff56eb406902c9..9baa6391cd621b4e3b84fd4f89b641aea29d7e71 100644 (file)
@@ -330,16 +330,6 @@ struct tcp_options {
 #define TCP_PATH_MTU                                                   \
        ( 1280 - 40 /* IPv6 */ - 20 /* TCP */ - 12 /* TCP timestamp */ )
 
-/**
- * Advertised TCP MSS
- *
- * We currently hardcode this to a reasonable value and hope that the
- * sender uses path MTU discovery.  The alternative is breaking the
- * abstraction layer so that we can find out the MTU from the IP layer
- * (which would have to find out from the net device layer).
- */
-#define TCP_MSS 1460
-
 /** TCP maximum segment lifetime
  *
  * Currently set to 2 minutes, as per RFC 793.
index 7087203aa123b299b94449163f24f2ffe29f7cab..548bd4d988c70b1cc87efdcf4be6d3b5eadb32f7 100644 (file)
@@ -43,6 +43,8 @@ struct tcp_connection {
        struct sockaddr_tcpip peer;
        /** Local port */
        unsigned int local_port;
+       /** Maximum segment size */
+       size_t mss;
 
        /** Current TCP state */
        unsigned int tcp_state;
@@ -250,6 +252,7 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
        struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
        struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
        struct tcp_connection *tcp;
+       size_t mtu;
        int port;
        int rc;
 
@@ -271,6 +274,16 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
        INIT_LIST_HEAD ( &tcp->rx_queue );
        memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
 
+       /* Calculate MSS */
+       mtu = tcpip_mtu ( &tcp->peer );
+       if ( ! mtu ) {
+               DBGC ( tcp, "TCP %p has no route to %s\n",
+                      tcp, sock_ntoa ( peer ) );
+               rc = -ENETUNREACH;
+               goto err;
+       }
+       tcp->mss = ( mtu - sizeof ( struct tcp_header ) );
+
        /* Bind to local port */
        port = tcpip_bind ( st_local, tcp_port_available );
        if ( port < 0 ) {
@@ -552,7 +565,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
                mssopt = iob_push ( iobuf, sizeof ( *mssopt ) );
                mssopt->kind = TCP_OPTION_MSS;
                mssopt->length = sizeof ( *mssopt );
-               mssopt->mss = htons ( TCP_MSS );
+               mssopt->mss = htons ( tcp->mss );
                wsopt = iob_push ( iobuf, sizeof ( *wsopt ) );
                wsopt->nop = TCP_OPTION_NOP;
                wsopt->wsopt.kind = TCP_OPTION_WS;