mirror of https://github.com/ipxe/ipxe.git
[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>pull/17/head
parent
6414b5ca03
commit
e191298a1d
|
@ -330,16 +330,6 @@ struct tcp_options {
|
||||||
#define TCP_PATH_MTU \
|
#define TCP_PATH_MTU \
|
||||||
( 1280 - 40 /* IPv6 */ - 20 /* TCP */ - 12 /* TCP timestamp */ )
|
( 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
|
/** TCP maximum segment lifetime
|
||||||
*
|
*
|
||||||
* Currently set to 2 minutes, as per RFC 793.
|
* Currently set to 2 minutes, as per RFC 793.
|
||||||
|
|
|
@ -43,6 +43,8 @@ struct tcp_connection {
|
||||||
struct sockaddr_tcpip peer;
|
struct sockaddr_tcpip peer;
|
||||||
/** Local port */
|
/** Local port */
|
||||||
unsigned int local_port;
|
unsigned int local_port;
|
||||||
|
/** Maximum segment size */
|
||||||
|
size_t mss;
|
||||||
|
|
||||||
/** Current TCP state */
|
/** Current TCP state */
|
||||||
unsigned int 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_peer = ( struct sockaddr_tcpip * ) peer;
|
||||||
struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
|
struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
|
||||||
struct tcp_connection *tcp;
|
struct tcp_connection *tcp;
|
||||||
|
size_t mtu;
|
||||||
int port;
|
int port;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -271,6 +274,16 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
|
||||||
INIT_LIST_HEAD ( &tcp->rx_queue );
|
INIT_LIST_HEAD ( &tcp->rx_queue );
|
||||||
memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
|
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 */
|
/* Bind to local port */
|
||||||
port = tcpip_bind ( st_local, tcp_port_available );
|
port = tcpip_bind ( st_local, tcp_port_available );
|
||||||
if ( port < 0 ) {
|
if ( port < 0 ) {
|
||||||
|
@ -552,7 +565,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
|
||||||
mssopt = iob_push ( iobuf, sizeof ( *mssopt ) );
|
mssopt = iob_push ( iobuf, sizeof ( *mssopt ) );
|
||||||
mssopt->kind = TCP_OPTION_MSS;
|
mssopt->kind = TCP_OPTION_MSS;
|
||||||
mssopt->length = sizeof ( *mssopt );
|
mssopt->length = sizeof ( *mssopt );
|
||||||
mssopt->mss = htons ( TCP_MSS );
|
mssopt->mss = htons ( tcp->mss );
|
||||||
wsopt = iob_push ( iobuf, sizeof ( *wsopt ) );
|
wsopt = iob_push ( iobuf, sizeof ( *wsopt ) );
|
||||||
wsopt->nop = TCP_OPTION_NOP;
|
wsopt->nop = TCP_OPTION_NOP;
|
||||||
wsopt->wsopt.kind = TCP_OPTION_WS;
|
wsopt->wsopt.kind = TCP_OPTION_WS;
|
||||||
|
|
Loading…
Reference in New Issue