diff --git a/pkg/tcpip/header/tcp.go b/pkg/tcpip/header/tcp.go index 84611e470..ed4952319 100644 --- a/pkg/tcpip/header/tcp.go +++ b/pkg/tcpip/header/tcp.go @@ -222,6 +222,10 @@ const ( // same as the value TCP_MIN_MSS defined net/tcp.h. TCPMinimumMSS = IPv4MaximumHeaderSize + TCPHeaderMaximumSize + MinIPFragmentPayloadSize - IPv4MinimumSize - TCPMinimumSize + // TCPMinimumSendMSS is the minimum value for MSS in a sender. This is the + // same as the value TCP_MIN_SND_MSS in net/tcp.h. + TCPMinimumSendMSS = TCPOptionsMaximumSize + MinIPFragmentPayloadSize + // TCPMaximumMSS is the maximum acceptable value for MSS. TCPMaximumMSS = 0xffff @@ -458,6 +462,9 @@ func ParseSynOptions(opts []byte, isAck bool) TCPSynOptions { return synOpts } synOpts.MSS = mss + if mss < TCPMinimumSendMSS { + synOpts.MSS = TCPMinimumSendMSS + } i += 4 case TCPOptionWS: diff --git a/pkg/tcpip/transport/tcp/snd.go b/pkg/tcpip/transport/tcp/snd.go index 99700c2ca..c99e84e56 100644 --- a/pkg/tcpip/transport/tcp/snd.go +++ b/pkg/tcpip/transport/tcp/snd.go @@ -861,11 +861,6 @@ func (s *sender) maybeSendSegment(seg *segment, limit int, end seqnum.Value) (se if seg.payloadSize() > available { // A negative value causes splitSeg to panic anyways, so just panic // earlier to get more information about the cause. - // TOOD(b/236090764): Remove this panic once the cause of negative values - // of "available" is understood. - if available < 0 { - panic(fmt.Sprintf("got available=%d, want available>=0. limit %d, s.MaxPayloadSize %d, seg.payloadSize() %d, gso.MaxSize %d, gso.MSS %d", available, limit, s.MaxPayloadSize, seg.payloadSize(), s.ep.gso.MaxSize, s.ep.gso.MSS)) - } s.splitSeg(seg, available) } diff --git a/pkg/tcpip/transport/tcp/test/e2e/tcp_test.go b/pkg/tcpip/transport/tcp/test/e2e/tcp_test.go index c1a7abb32..59cf6606f 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/tcp_test.go +++ b/pkg/tcpip/transport/tcp/test/e2e/tcp_test.go @@ -3573,6 +3573,28 @@ func TestSetTTL(t *testing.T) { } } +func TestSendMSSLessThanOptionsSize(t *testing.T) { + const mss = 10 + const writeSize = 300 + c := context.New(t, 65535) + defer c.Cleanup() + + // The sizes of these options add up to 12. + c.CreateConnectedWithRawOptions(context.TestInitialSequenceNumber, 30000, -1 /* epRcvBuf */, []byte{ + header.TCPOptionMSS, 4, byte(mss / 256), byte(mss % 256), + header.TCPOptionTS, header.TCPOptionTSLength, 1, 2, 3, 4, 5, 6, 7, 8, + header.TCPOptionSACKPermitted, header.TCPOptionSackPermittedLength, + }) + e2e.CheckBrokenUpWrite(t, c, writeSize) + + var r bytes.Reader + r.Reset(make([]byte, writeSize)) + _, err := c.EP.Write(&r, tcpip.WriteOptions{}) + if err != nil { + t.Fatalf("Write failed: %s", err) + } +} + func TestActiveSendMSSLessThanMTU(t *testing.T) { const maxPayload = 100 c := context.New(t, 65535)