summaryrefslogtreecommitdiffstats
path: root/src/net/tcp.c
diff options
context:
space:
mode:
authorMichael Brown2014-03-04 14:14:13 +0100
committerMichael Brown2014-03-04 14:23:29 +0100
commite191298a1d62446646922b1f3d899dfb16da73ff (patch)
tree45aed089b8aafd2efd15d2171e314cee37eb1302 /src/net/tcp.c
parent[tcpip] Provide tcpip_mtu() to determine the maximum transmission unit (diff)
downloadipxe-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.c15
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;