Skip to content

Commit

Permalink
[tcp] Calculate correct MSS from peer address
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed Mar 4, 2014
1 parent 6414b5c commit e191298
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 11 deletions.
10 changes: 0 additions & 10 deletions src/include/ipxe/tcp.h
Expand Up @@ -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.
Expand Down
15 changes: 14 additions & 1 deletion src/net/tcp.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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 ) {
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit e191298

Please sign in to comment.