diff options
author | Michael Brown | 2014-03-04 14:14:13 +0100 |
---|---|---|
committer | Michael Brown | 2014-03-04 14:23:29 +0100 |
commit | e191298a1d62446646922b1f3d899dfb16da73ff (patch) | |
tree | 45aed089b8aafd2efd15d2171e314cee37eb1302 /src/net/tcp.c | |
parent | [tcpip] Provide tcpip_mtu() to determine the maximum transmission unit (diff) | |
download | ipxe-e191298a1d62446646922b1f3d899dfb16da73ff.tar.gz ipxe-e191298a1d62446646922b1f3d899dfb16da73ff.tar.xz ipxe-e191298a1d62446646922b1f3d899dfb16da73ff.zip |
[tcp] Calculate correct MSS from peer address
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>
Diffstat (limited to 'src/net/tcp.c')
-rw-r--r-- | src/net/tcp.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/src/net/tcp.c b/src/net/tcp.c index 7087203a..548bd4d9 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -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; |