Ver código fonte

[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>
tags/v1.20.1
Michael Brown 10 anos atrás
pai
commit
e191298a1d
2 arquivos alterados com 14 adições e 11 exclusões
  1. 0
    10
      src/include/ipxe/tcp.h
  2. 14
    1
      src/net/tcp.c

+ 0
- 10
src/include/ipxe/tcp.h Ver arquivo

@@ -330,16 +330,6 @@ struct tcp_options {
330 330
 #define TCP_PATH_MTU							\
331 331
 	( 1280 - 40 /* IPv6 */ - 20 /* TCP */ - 12 /* TCP timestamp */ )
332 332
 
333
-/**
334
- * Advertised TCP MSS
335
- *
336
- * We currently hardcode this to a reasonable value and hope that the
337
- * sender uses path MTU discovery.  The alternative is breaking the
338
- * abstraction layer so that we can find out the MTU from the IP layer
339
- * (which would have to find out from the net device layer).
340
- */
341
-#define TCP_MSS 1460
342
-
343 333
 /** TCP maximum segment lifetime
344 334
  *
345 335
  * Currently set to 2 minutes, as per RFC 793.

+ 14
- 1
src/net/tcp.c Ver arquivo

@@ -43,6 +43,8 @@ struct tcp_connection {
43 43
 	struct sockaddr_tcpip peer;
44 44
 	/** Local port */
45 45
 	unsigned int local_port;
46
+	/** Maximum segment size */
47
+	size_t mss;
46 48
 
47 49
 	/** Current TCP state */
48 50
 	unsigned int tcp_state;
@@ -250,6 +252,7 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
250 252
 	struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
251 253
 	struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
252 254
 	struct tcp_connection *tcp;
255
+	size_t mtu;
253 256
 	int port;
254 257
 	int rc;
255 258
 
@@ -271,6 +274,16 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
271 274
 	INIT_LIST_HEAD ( &tcp->rx_queue );
272 275
 	memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
273 276
 
277
+	/* Calculate MSS */
278
+	mtu = tcpip_mtu ( &tcp->peer );
279
+	if ( ! mtu ) {
280
+		DBGC ( tcp, "TCP %p has no route to %s\n",
281
+		       tcp, sock_ntoa ( peer ) );
282
+		rc = -ENETUNREACH;
283
+		goto err;
284
+	}
285
+	tcp->mss = ( mtu - sizeof ( struct tcp_header ) );
286
+
274 287
 	/* Bind to local port */
275 288
 	port = tcpip_bind ( st_local, tcp_port_available );
276 289
 	if ( port < 0 ) {
@@ -552,7 +565,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
552 565
 		mssopt = iob_push ( iobuf, sizeof ( *mssopt ) );
553 566
 		mssopt->kind = TCP_OPTION_MSS;
554 567
 		mssopt->length = sizeof ( *mssopt );
555
-		mssopt->mss = htons ( TCP_MSS );
568
+		mssopt->mss = htons ( tcp->mss );
556 569
 		wsopt = iob_push ( iobuf, sizeof ( *wsopt ) );
557 570
 		wsopt->nop = TCP_OPTION_NOP;
558 571
 		wsopt->wsopt.kind = TCP_OPTION_WS;

Carregando…
Cancelar
Salvar