github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/transport/tcp/testing/context/context.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package context provides a test context for use in tcp tests. It also
    16  // provides helper methods to assert/check certain behaviours.
    17  package context
    18  
    19  import (
    20  	"bytes"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/FlowerWrong/netstack/tcpip"
    25  	"github.com/FlowerWrong/netstack/tcpip/buffer"
    26  	"github.com/FlowerWrong/netstack/tcpip/checker"
    27  	"github.com/FlowerWrong/netstack/tcpip/header"
    28  	"github.com/FlowerWrong/netstack/tcpip/link/channel"
    29  	"github.com/FlowerWrong/netstack/tcpip/link/sniffer"
    30  	"github.com/FlowerWrong/netstack/tcpip/network/ipv4"
    31  	"github.com/FlowerWrong/netstack/tcpip/network/ipv6"
    32  	"github.com/FlowerWrong/netstack/tcpip/seqnum"
    33  	"github.com/FlowerWrong/netstack/tcpip/stack"
    34  	"github.com/FlowerWrong/netstack/tcpip/transport/tcp"
    35  	"github.com/FlowerWrong/netstack/waiter"
    36  )
    37  
    38  const (
    39  	// StackAddr is the IPv4 address assigned to the stack.
    40  	StackAddr = "\x0a\x00\x00\x01"
    41  
    42  	// StackPort is used as the listening port in tests for passive
    43  	// connects.
    44  	StackPort = 1234
    45  
    46  	// TestAddr is the source address for packets sent to the stack via the
    47  	// link layer endpoint.
    48  	TestAddr = "\x0a\x00\x00\x02"
    49  
    50  	// TestPort is the TCP port used for packets sent to the stack
    51  	// via the link layer endpoint.
    52  	TestPort = 4096
    53  
    54  	// StackV6Addr is the IPv6 address assigned to the stack.
    55  	StackV6Addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
    56  
    57  	// TestV6Addr is the source address for packets sent to the stack via
    58  	// the link layer endpoint.
    59  	TestV6Addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
    60  
    61  	// StackV4MappedAddr is StackAddr as a mapped v6 address.
    62  	StackV4MappedAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + StackAddr
    63  
    64  	// TestV4MappedAddr is TestAddr as a mapped v6 address.
    65  	TestV4MappedAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + TestAddr
    66  
    67  	// V4MappedWildcardAddr is the mapped v6 representation of 0.0.0.0.
    68  	V4MappedWildcardAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00"
    69  
    70  	// testInitialSequenceNumber is the initial sequence number sent in packets that
    71  	// are sent in response to a SYN or in the initial SYN sent to the stack.
    72  	testInitialSequenceNumber = 789
    73  )
    74  
    75  // Headers is used to represent the TCP header fields when building a
    76  // new packet.
    77  type Headers struct {
    78  	// SrcPort holds the src port value to be used in the packet.
    79  	SrcPort uint16
    80  
    81  	// DstPort holds the destination port value to be used in the packet.
    82  	DstPort uint16
    83  
    84  	// SeqNum is the value of the sequence number field in the TCP header.
    85  	SeqNum seqnum.Value
    86  
    87  	// AckNum represents the acknowledgement number field in the TCP header.
    88  	AckNum seqnum.Value
    89  
    90  	// Flags are the TCP flags in the TCP header.
    91  	Flags int
    92  
    93  	// RcvWnd is the window to be advertised in the ReceiveWindow field of
    94  	// the TCP header.
    95  	RcvWnd seqnum.Size
    96  
    97  	// TCPOpts holds the options to be sent in the option field of the TCP
    98  	// header.
    99  	TCPOpts []byte
   100  }
   101  
   102  // Context provides an initialized Network stack and a link layer endpoint
   103  // for use in TCP tests.
   104  type Context struct {
   105  	t      *testing.T
   106  	linkEP *channel.Endpoint
   107  	s      *stack.Stack
   108  
   109  	// IRS holds the initial sequence number in the SYN sent by endpoint in
   110  	// case of an active connect or the sequence number sent by the endpoint
   111  	// in the SYN-ACK sent in response to a SYN when listening in passive
   112  	// mode.
   113  	IRS seqnum.Value
   114  
   115  	// Port holds the port bound by EP below in case of an active connect or
   116  	// the listening port number in case of a passive connect.
   117  	Port uint16
   118  
   119  	// EP is the test endpoint in the stack owned by this context. This endpoint
   120  	// is used in various tests to either initiate an active connect or is used
   121  	// as a passive listening endpoint to accept inbound connections.
   122  	EP tcpip.Endpoint
   123  
   124  	// Wq is the wait queue associated with EP and is used to block for events
   125  	// on EP.
   126  	WQ waiter.Queue
   127  
   128  	// TimeStampEnabled is true if ep is connected with the timestamp option
   129  	// enabled.
   130  	TimeStampEnabled bool
   131  
   132  	// WindowScale is the expected window scale in SYN packets sent by
   133  	// the stack.
   134  	WindowScale uint8
   135  }
   136  
   137  // New allocates and initializes a test context containing a new
   138  // stack and a link-layer endpoint.
   139  func New(t *testing.T, mtu uint32) *Context {
   140  	s := stack.New(stack.Options{
   141  		NetworkProtocols:   []stack.NetworkProtocol{ipv4.NewProtocol(), ipv6.NewProtocol()},
   142  		TransportProtocols: []stack.TransportProtocol{tcp.NewProtocol()},
   143  	})
   144  
   145  	// Allow minimum send/receive buffer sizes to be 1 during tests.
   146  	if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SendBufferSizeOption{1, tcp.DefaultSendBufferSize, 10 * tcp.DefaultSendBufferSize}); err != nil {
   147  		t.Fatalf("SetTransportProtocolOption failed: %v", err)
   148  	}
   149  
   150  	if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.ReceiveBufferSizeOption{1, tcp.DefaultReceiveBufferSize, 10 * tcp.DefaultReceiveBufferSize}); err != nil {
   151  		t.Fatalf("SetTransportProtocolOption failed: %v", err)
   152  	}
   153  
   154  	// Some of the congestion control tests send up to 640 packets, we so
   155  	// set the channel size to 1000.
   156  	ep := channel.New(1000, mtu, "")
   157  	wep := stack.LinkEndpoint(ep)
   158  	if testing.Verbose() {
   159  		wep = sniffer.New(ep)
   160  	}
   161  	if err := s.CreateNamedNIC(1, "nic1", wep); err != nil {
   162  		t.Fatalf("CreateNIC failed: %v", err)
   163  	}
   164  	wep2 := stack.LinkEndpoint(channel.New(1000, mtu, ""))
   165  	if testing.Verbose() {
   166  		wep2 = sniffer.New(channel.New(1000, mtu, ""))
   167  	}
   168  	if err := s.CreateNamedNIC(2, "nic2", wep2); err != nil {
   169  		t.Fatalf("CreateNIC failed: %v", err)
   170  	}
   171  
   172  	if err := s.AddAddress(1, ipv4.ProtocolNumber, StackAddr); err != nil {
   173  		t.Fatalf("AddAddress failed: %v", err)
   174  	}
   175  
   176  	if err := s.AddAddress(1, ipv6.ProtocolNumber, StackV6Addr); err != nil {
   177  		t.Fatalf("AddAddress failed: %v", err)
   178  	}
   179  
   180  	s.SetRouteTable([]tcpip.Route{
   181  		{
   182  			Destination: header.IPv4EmptySubnet,
   183  			NIC:         1,
   184  		},
   185  		{
   186  			Destination: header.IPv6EmptySubnet,
   187  			NIC:         1,
   188  		},
   189  	})
   190  
   191  	return &Context{
   192  		t:           t,
   193  		s:           s,
   194  		linkEP:      ep,
   195  		WindowScale: uint8(tcp.FindWndScale(tcp.DefaultReceiveBufferSize)),
   196  	}
   197  }
   198  
   199  // Cleanup closes the context endpoint if required.
   200  func (c *Context) Cleanup() {
   201  	if c.EP != nil {
   202  		c.EP.Close()
   203  	}
   204  }
   205  
   206  // Stack returns a reference to the stack in the Context.
   207  func (c *Context) Stack() *stack.Stack {
   208  	return c.s
   209  }
   210  
   211  // CheckNoPacketTimeout verifies that no packet is received during the time
   212  // specified by wait.
   213  func (c *Context) CheckNoPacketTimeout(errMsg string, wait time.Duration) {
   214  	c.t.Helper()
   215  
   216  	select {
   217  	case <-c.linkEP.C:
   218  		c.t.Fatal(errMsg)
   219  
   220  	case <-time.After(wait):
   221  	}
   222  }
   223  
   224  // CheckNoPacket verifies that no packet is received for 1 second.
   225  func (c *Context) CheckNoPacket(errMsg string) {
   226  	c.CheckNoPacketTimeout(errMsg, 1*time.Second)
   227  }
   228  
   229  // GetPacket reads a packet from the link layer endpoint and verifies
   230  // that it is an IPv4 packet with the expected source and destination
   231  // addresses. It will fail with an error if no packet is received for
   232  // 2 seconds.
   233  func (c *Context) GetPacket() []byte {
   234  	select {
   235  	case p := <-c.linkEP.C:
   236  		if p.Proto != ipv4.ProtocolNumber {
   237  			c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber)
   238  		}
   239  		b := make([]byte, len(p.Header)+len(p.Payload))
   240  		copy(b, p.Header)
   241  		copy(b[len(p.Header):], p.Payload)
   242  
   243  		if p.GSO != nil && p.GSO.L3HdrLen != header.IPv4MinimumSize {
   244  			c.t.Errorf("L3HdrLen %v (expected %v)", p.GSO.L3HdrLen, header.IPv4MinimumSize)
   245  		}
   246  
   247  		checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr))
   248  		return b
   249  
   250  	case <-time.After(2 * time.Second):
   251  		c.t.Fatalf("Packet wasn't written out")
   252  	}
   253  
   254  	return nil
   255  }
   256  
   257  // GetPacketNonBlocking reads a packet from the link layer endpoint
   258  // and verifies that it is an IPv4 packet with the expected source
   259  // and destination address. If no packet is available it will return
   260  // nil immediately.
   261  func (c *Context) GetPacketNonBlocking() []byte {
   262  	select {
   263  	case p := <-c.linkEP.C:
   264  		if p.Proto != ipv4.ProtocolNumber {
   265  			c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber)
   266  		}
   267  		b := make([]byte, len(p.Header)+len(p.Payload))
   268  		copy(b, p.Header)
   269  		copy(b[len(p.Header):], p.Payload)
   270  
   271  		checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr))
   272  		return b
   273  	default:
   274  		return nil
   275  	}
   276  }
   277  
   278  // SendICMPPacket builds and sends an ICMPv4 packet via the link layer endpoint.
   279  func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code uint8, p1, p2 []byte, maxTotalSize int) {
   280  	// Allocate a buffer data and headers.
   281  	buf := buffer.NewView(header.IPv4MinimumSize + header.ICMPv4PayloadOffset + len(p2))
   282  	if len(buf) > maxTotalSize {
   283  		buf = buf[:maxTotalSize]
   284  	}
   285  
   286  	ip := header.IPv4(buf)
   287  	ip.Encode(&header.IPv4Fields{
   288  		IHL:         header.IPv4MinimumSize,
   289  		TotalLength: uint16(len(buf)),
   290  		TTL:         65,
   291  		Protocol:    uint8(header.ICMPv4ProtocolNumber),
   292  		SrcAddr:     TestAddr,
   293  		DstAddr:     StackAddr,
   294  	})
   295  	ip.SetChecksum(^ip.CalculateChecksum())
   296  
   297  	icmp := header.ICMPv4(buf[header.IPv4MinimumSize:])
   298  	icmp.SetType(typ)
   299  	icmp.SetCode(code)
   300  	const icmpv4VariableHeaderOffset = 4
   301  	copy(icmp[icmpv4VariableHeaderOffset:], p1)
   302  	copy(icmp[header.ICMPv4PayloadOffset:], p2)
   303  
   304  	// Inject packet.
   305  	c.linkEP.Inject(ipv4.ProtocolNumber, buf.ToVectorisedView())
   306  }
   307  
   308  // BuildSegment builds a TCP segment based on the given Headers and payload.
   309  func (c *Context) BuildSegment(payload []byte, h *Headers) buffer.VectorisedView {
   310  	// Allocate a buffer for data and headers.
   311  	buf := buffer.NewView(header.TCPMinimumSize + header.IPv4MinimumSize + len(h.TCPOpts) + len(payload))
   312  	copy(buf[len(buf)-len(payload):], payload)
   313  	copy(buf[len(buf)-len(payload)-len(h.TCPOpts):], h.TCPOpts)
   314  
   315  	// Initialize the IP header.
   316  	ip := header.IPv4(buf)
   317  	ip.Encode(&header.IPv4Fields{
   318  		IHL:         header.IPv4MinimumSize,
   319  		TotalLength: uint16(len(buf)),
   320  		TTL:         65,
   321  		Protocol:    uint8(tcp.ProtocolNumber),
   322  		SrcAddr:     TestAddr,
   323  		DstAddr:     StackAddr,
   324  	})
   325  	ip.SetChecksum(^ip.CalculateChecksum())
   326  
   327  	// Initialize the TCP header.
   328  	t := header.TCP(buf[header.IPv4MinimumSize:])
   329  	t.Encode(&header.TCPFields{
   330  		SrcPort:    h.SrcPort,
   331  		DstPort:    h.DstPort,
   332  		SeqNum:     uint32(h.SeqNum),
   333  		AckNum:     uint32(h.AckNum),
   334  		DataOffset: uint8(header.TCPMinimumSize + len(h.TCPOpts)),
   335  		Flags:      uint8(h.Flags),
   336  		WindowSize: uint16(h.RcvWnd),
   337  	})
   338  
   339  	// Calculate the TCP pseudo-header checksum.
   340  	xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, TestAddr, StackAddr, uint16(len(t)))
   341  
   342  	// Calculate the TCP checksum and set it.
   343  	xsum = header.Checksum(payload, xsum)
   344  	t.SetChecksum(^t.CalculateChecksum(xsum))
   345  
   346  	// Inject packet.
   347  	return buf.ToVectorisedView()
   348  }
   349  
   350  // SendSegment sends a TCP segment that has already been built and written to a
   351  // buffer.VectorisedView.
   352  func (c *Context) SendSegment(s buffer.VectorisedView) {
   353  	c.linkEP.Inject(ipv4.ProtocolNumber, s)
   354  }
   355  
   356  // SendPacket builds and sends a TCP segment(with the provided payload & TCP
   357  // headers) in an IPv4 packet via the link layer endpoint.
   358  func (c *Context) SendPacket(payload []byte, h *Headers) {
   359  	c.linkEP.Inject(ipv4.ProtocolNumber, c.BuildSegment(payload, h))
   360  }
   361  
   362  // SendAck sends an ACK packet.
   363  func (c *Context) SendAck(seq seqnum.Value, bytesReceived int) {
   364  	c.SendAckWithSACK(seq, bytesReceived, nil)
   365  }
   366  
   367  // SendAckWithSACK sends an ACK packet which includes the sackBlocks specified.
   368  func (c *Context) SendAckWithSACK(seq seqnum.Value, bytesReceived int, sackBlocks []header.SACKBlock) {
   369  	options := make([]byte, 40)
   370  	offset := 0
   371  	if len(sackBlocks) > 0 {
   372  		offset += header.EncodeNOP(options[offset:])
   373  		offset += header.EncodeNOP(options[offset:])
   374  		offset += header.EncodeSACKBlocks(sackBlocks, options[offset:])
   375  	}
   376  
   377  	c.SendPacket(nil, &Headers{
   378  		SrcPort: TestPort,
   379  		DstPort: c.Port,
   380  		Flags:   header.TCPFlagAck,
   381  		SeqNum:  seq,
   382  		AckNum:  c.IRS.Add(1 + seqnum.Size(bytesReceived)),
   383  		RcvWnd:  30000,
   384  		TCPOpts: options[:offset],
   385  	})
   386  }
   387  
   388  // ReceiveAndCheckPacket reads a packet from the link layer endpoint and
   389  // verifies that the packet packet payload of packet matches the slice
   390  // of data indicated by offset & size.
   391  func (c *Context) ReceiveAndCheckPacket(data []byte, offset, size int) {
   392  	c.ReceiveAndCheckPacketWithOptions(data, offset, size, 0)
   393  }
   394  
   395  // ReceiveAndCheckPacketWithOptions reads a packet from the link layer endpoint
   396  // and verifies that the packet packet payload of packet matches the slice of
   397  // data indicated by offset & size and skips optlen bytes in addition to the IP
   398  // TCP headers when comparing the data.
   399  func (c *Context) ReceiveAndCheckPacketWithOptions(data []byte, offset, size, optlen int) {
   400  	b := c.GetPacket()
   401  	checker.IPv4(c.t, b,
   402  		checker.PayloadLen(size+header.TCPMinimumSize+optlen),
   403  		checker.TCP(
   404  			checker.DstPort(TestPort),
   405  			checker.SeqNum(uint32(c.IRS.Add(seqnum.Size(1+offset)))),
   406  			checker.AckNum(uint32(seqnum.Value(testInitialSequenceNumber).Add(1))),
   407  			checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)),
   408  		),
   409  	)
   410  
   411  	pdata := data[offset:][:size]
   412  	if p := b[header.IPv4MinimumSize+header.TCPMinimumSize+optlen:]; bytes.Compare(pdata, p) != 0 {
   413  		c.t.Fatalf("Data is different: expected %v, got %v", pdata, p)
   414  	}
   415  }
   416  
   417  // ReceiveNonBlockingAndCheckPacket reads a packet from the link layer endpoint
   418  // and verifies that the packet packet payload of packet matches the slice of
   419  // data indicated by offset & size. It returns true if a packet was received and
   420  // processed.
   421  func (c *Context) ReceiveNonBlockingAndCheckPacket(data []byte, offset, size int) bool {
   422  	b := c.GetPacketNonBlocking()
   423  	if b == nil {
   424  		return false
   425  	}
   426  	checker.IPv4(c.t, b,
   427  		checker.PayloadLen(size+header.TCPMinimumSize),
   428  		checker.TCP(
   429  			checker.DstPort(TestPort),
   430  			checker.SeqNum(uint32(c.IRS.Add(seqnum.Size(1+offset)))),
   431  			checker.AckNum(uint32(seqnum.Value(testInitialSequenceNumber).Add(1))),
   432  			checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)),
   433  		),
   434  	)
   435  
   436  	pdata := data[offset:][:size]
   437  	if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(pdata, p) != 0 {
   438  		c.t.Fatalf("Data is different: expected %v, got %v", pdata, p)
   439  	}
   440  	return true
   441  }
   442  
   443  // CreateV6Endpoint creates and initializes c.ep as a IPv6 Endpoint. If v6Only
   444  // is true then it sets the IP_V6ONLY option on the socket to make it a IPv6
   445  // only endpoint instead of a default dual stack socket.
   446  func (c *Context) CreateV6Endpoint(v6only bool) {
   447  	var err *tcpip.Error
   448  	c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &c.WQ)
   449  	if err != nil {
   450  		c.t.Fatalf("NewEndpoint failed: %v", err)
   451  	}
   452  
   453  	var v tcpip.V6OnlyOption
   454  	if v6only {
   455  		v = 1
   456  	}
   457  	if err := c.EP.SetSockOpt(v); err != nil {
   458  		c.t.Fatalf("SetSockOpt failed failed: %v", err)
   459  	}
   460  }
   461  
   462  // GetV6Packet reads a single packet from the link layer endpoint of the context
   463  // and asserts that it is an IPv6 Packet with the expected src/dest addresses.
   464  func (c *Context) GetV6Packet() []byte {
   465  	select {
   466  	case p := <-c.linkEP.C:
   467  		if p.Proto != ipv6.ProtocolNumber {
   468  			c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv6.ProtocolNumber)
   469  		}
   470  		b := make([]byte, len(p.Header)+len(p.Payload))
   471  		copy(b, p.Header)
   472  		copy(b[len(p.Header):], p.Payload)
   473  
   474  		checker.IPv6(c.t, b, checker.SrcAddr(StackV6Addr), checker.DstAddr(TestV6Addr))
   475  		return b
   476  
   477  	case <-time.After(2 * time.Second):
   478  		c.t.Fatalf("Packet wasn't written out")
   479  	}
   480  
   481  	return nil
   482  }
   483  
   484  // SendV6Packet builds and sends an IPv6 Packet via the link layer endpoint of
   485  // the context.
   486  func (c *Context) SendV6Packet(payload []byte, h *Headers) {
   487  	// Allocate a buffer for data and headers.
   488  	buf := buffer.NewView(header.TCPMinimumSize + header.IPv6MinimumSize + len(payload))
   489  	copy(buf[len(buf)-len(payload):], payload)
   490  
   491  	// Initialize the IP header.
   492  	ip := header.IPv6(buf)
   493  	ip.Encode(&header.IPv6Fields{
   494  		PayloadLength: uint16(header.TCPMinimumSize + len(payload)),
   495  		NextHeader:    uint8(tcp.ProtocolNumber),
   496  		HopLimit:      65,
   497  		SrcAddr:       TestV6Addr,
   498  		DstAddr:       StackV6Addr,
   499  	})
   500  
   501  	// Initialize the TCP header.
   502  	t := header.TCP(buf[header.IPv6MinimumSize:])
   503  	t.Encode(&header.TCPFields{
   504  		SrcPort:    h.SrcPort,
   505  		DstPort:    h.DstPort,
   506  		SeqNum:     uint32(h.SeqNum),
   507  		AckNum:     uint32(h.AckNum),
   508  		DataOffset: header.TCPMinimumSize,
   509  		Flags:      uint8(h.Flags),
   510  		WindowSize: uint16(h.RcvWnd),
   511  	})
   512  
   513  	// Calculate the TCP pseudo-header checksum.
   514  	xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, TestV6Addr, StackV6Addr, uint16(len(t)))
   515  
   516  	// Calculate the TCP checksum and set it.
   517  	xsum = header.Checksum(payload, xsum)
   518  	t.SetChecksum(^t.CalculateChecksum(xsum))
   519  
   520  	// Inject packet.
   521  	c.linkEP.Inject(ipv6.ProtocolNumber, buf.ToVectorisedView())
   522  }
   523  
   524  // CreateConnected creates a connected TCP endpoint.
   525  func (c *Context) CreateConnected(iss seqnum.Value, rcvWnd seqnum.Size, epRcvBuf int) {
   526  	c.CreateConnectedWithRawOptions(iss, rcvWnd, epRcvBuf, nil)
   527  }
   528  
   529  // Connect performs the 3-way handshake for c.EP with the provided Initial
   530  // Sequence Number (iss) and receive window(rcvWnd) and any options if
   531  // specified.
   532  //
   533  // It also sets the receive buffer for the endpoint to the specified
   534  // value in epRcvBuf.
   535  //
   536  // PreCondition: c.EP must already be created.
   537  func (c *Context) Connect(iss seqnum.Value, rcvWnd seqnum.Size, options []byte) {
   538  	// Start connection attempt.
   539  	waitEntry, notifyCh := waiter.NewChannelEntry(nil)
   540  	c.WQ.EventRegister(&waitEntry, waiter.EventOut)
   541  	defer c.WQ.EventUnregister(&waitEntry)
   542  
   543  	if err := c.EP.Connect(tcpip.FullAddress{Addr: TestAddr, Port: TestPort}); err != tcpip.ErrConnectStarted {
   544  		c.t.Fatalf("Unexpected return value from Connect: %v", err)
   545  	}
   546  
   547  	// Receive SYN packet.
   548  	b := c.GetPacket()
   549  	checker.IPv4(c.t, b,
   550  		checker.TCP(
   551  			checker.DstPort(TestPort),
   552  			checker.TCPFlags(header.TCPFlagSyn),
   553  		),
   554  	)
   555  	if got, want := tcp.EndpointState(c.EP.State()), tcp.StateSynSent; got != want {
   556  		c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got)
   557  	}
   558  
   559  	tcpHdr := header.TCP(header.IPv4(b).Payload())
   560  	c.IRS = seqnum.Value(tcpHdr.SequenceNumber())
   561  
   562  	c.SendPacket(nil, &Headers{
   563  		SrcPort: tcpHdr.DestinationPort(),
   564  		DstPort: tcpHdr.SourcePort(),
   565  		Flags:   header.TCPFlagSyn | header.TCPFlagAck,
   566  		SeqNum:  iss,
   567  		AckNum:  c.IRS.Add(1),
   568  		RcvWnd:  rcvWnd,
   569  		TCPOpts: options,
   570  	})
   571  
   572  	// Receive ACK packet.
   573  	checker.IPv4(c.t, c.GetPacket(),
   574  		checker.TCP(
   575  			checker.DstPort(TestPort),
   576  			checker.TCPFlags(header.TCPFlagAck),
   577  			checker.SeqNum(uint32(c.IRS)+1),
   578  			checker.AckNum(uint32(iss)+1),
   579  		),
   580  	)
   581  
   582  	// Wait for connection to be established.
   583  	select {
   584  	case <-notifyCh:
   585  		if err := c.EP.GetSockOpt(tcpip.ErrorOption{}); err != nil {
   586  			c.t.Fatalf("Unexpected error when connecting: %v", err)
   587  		}
   588  	case <-time.After(1 * time.Second):
   589  		c.t.Fatalf("Timed out waiting for connection")
   590  	}
   591  	if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want {
   592  		c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got)
   593  	}
   594  
   595  	c.Port = tcpHdr.SourcePort()
   596  }
   597  
   598  // Create creates a TCP endpoint.
   599  func (c *Context) Create(epRcvBuf int) {
   600  	// Create TCP endpoint.
   601  	var err *tcpip.Error
   602  	c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ)
   603  	if err != nil {
   604  		c.t.Fatalf("NewEndpoint failed: %v", err)
   605  	}
   606  
   607  	if epRcvBuf != -1 {
   608  		if err := c.EP.SetSockOptInt(tcpip.ReceiveBufferSizeOption, epRcvBuf); err != nil {
   609  			c.t.Fatalf("SetSockOpt failed failed: %v", err)
   610  		}
   611  	}
   612  }
   613  
   614  // CreateConnectedWithRawOptions creates a connected TCP endpoint and sends
   615  // the specified option bytes as the Option field in the initial SYN packet.
   616  //
   617  // It also sets the receive buffer for the endpoint to the specified
   618  // value in epRcvBuf.
   619  func (c *Context) CreateConnectedWithRawOptions(iss seqnum.Value, rcvWnd seqnum.Size, epRcvBuf int, options []byte) {
   620  	c.Create(epRcvBuf)
   621  	c.Connect(iss, rcvWnd, options)
   622  }
   623  
   624  // RawEndpoint is just a small wrapper around a TCP endpoint's state to make
   625  // sending data and ACK packets easy while being able to manipulate the sequence
   626  // numbers and timestamp values as needed.
   627  type RawEndpoint struct {
   628  	C          *Context
   629  	SrcPort    uint16
   630  	DstPort    uint16
   631  	Flags      int
   632  	NextSeqNum seqnum.Value
   633  	AckNum     seqnum.Value
   634  	WndSize    seqnum.Size
   635  	RecentTS   uint32 // Stores the latest timestamp to echo back.
   636  	TSVal      uint32 // TSVal stores the last timestamp sent by this endpoint.
   637  
   638  	// SackPermitted is true if SACKPermitted option was negotiated for this endpoint.
   639  	SACKPermitted bool
   640  }
   641  
   642  // SendPacketWithTS embeds the provided tsVal in the Timestamp option
   643  // for the packet to be sent out.
   644  func (r *RawEndpoint) SendPacketWithTS(payload []byte, tsVal uint32) {
   645  	r.TSVal = tsVal
   646  	tsOpt := [12]byte{header.TCPOptionNOP, header.TCPOptionNOP}
   647  	header.EncodeTSOption(r.TSVal, r.RecentTS, tsOpt[2:])
   648  	r.SendPacket(payload, tsOpt[:])
   649  }
   650  
   651  // SendPacket is a small wrapper function to build and send packets.
   652  func (r *RawEndpoint) SendPacket(payload []byte, opts []byte) {
   653  	packetHeaders := &Headers{
   654  		SrcPort: r.SrcPort,
   655  		DstPort: r.DstPort,
   656  		Flags:   r.Flags,
   657  		SeqNum:  r.NextSeqNum,
   658  		AckNum:  r.AckNum,
   659  		RcvWnd:  r.WndSize,
   660  		TCPOpts: opts,
   661  	}
   662  	r.C.SendPacket(payload, packetHeaders)
   663  	r.NextSeqNum = r.NextSeqNum.Add(seqnum.Size(len(payload)))
   664  }
   665  
   666  // VerifyACKWithTS verifies that the tsEcr field in the ack matches the provided
   667  // tsVal.
   668  func (r *RawEndpoint) VerifyACKWithTS(tsVal uint32) {
   669  	// Read ACK and verify that tsEcr of ACK packet is [1,2,3,4]
   670  	ackPacket := r.C.GetPacket()
   671  	checker.IPv4(r.C.t, ackPacket,
   672  		checker.TCP(
   673  			checker.DstPort(r.SrcPort),
   674  			checker.TCPFlags(header.TCPFlagAck),
   675  			checker.SeqNum(uint32(r.AckNum)),
   676  			checker.AckNum(uint32(r.NextSeqNum)),
   677  			checker.TCPTimestampChecker(true, 0, tsVal),
   678  		),
   679  	)
   680  	// Store the parsed TSVal from the ack as recentTS.
   681  	tcpSeg := header.TCP(header.IPv4(ackPacket).Payload())
   682  	opts := tcpSeg.ParsedOptions()
   683  	r.RecentTS = opts.TSVal
   684  }
   685  
   686  // VerifyACKRcvWnd verifies that the window advertised by the incoming ACK
   687  // matches the provided rcvWnd.
   688  func (r *RawEndpoint) VerifyACKRcvWnd(rcvWnd uint16) {
   689  	ackPacket := r.C.GetPacket()
   690  	checker.IPv4(r.C.t, ackPacket,
   691  		checker.TCP(
   692  			checker.DstPort(r.SrcPort),
   693  			checker.TCPFlags(header.TCPFlagAck),
   694  			checker.SeqNum(uint32(r.AckNum)),
   695  			checker.AckNum(uint32(r.NextSeqNum)),
   696  			checker.Window(rcvWnd),
   697  		),
   698  	)
   699  }
   700  
   701  // VerifyACKNoSACK verifies that the ACK does not contain a SACK block.
   702  func (r *RawEndpoint) VerifyACKNoSACK() {
   703  	r.VerifyACKHasSACK(nil)
   704  }
   705  
   706  // VerifyACKHasSACK verifies that the ACK contains the specified SACKBlocks.
   707  func (r *RawEndpoint) VerifyACKHasSACK(sackBlocks []header.SACKBlock) {
   708  	// Read ACK and verify that the TCP options in the segment do
   709  	// not contain a SACK block.
   710  	ackPacket := r.C.GetPacket()
   711  	checker.IPv4(r.C.t, ackPacket,
   712  		checker.TCP(
   713  			checker.DstPort(r.SrcPort),
   714  			checker.TCPFlags(header.TCPFlagAck),
   715  			checker.SeqNum(uint32(r.AckNum)),
   716  			checker.AckNum(uint32(r.NextSeqNum)),
   717  			checker.TCPSACKBlockChecker(sackBlocks),
   718  		),
   719  	)
   720  }
   721  
   722  // CreateConnectedWithOptions creates and connects c.ep with the specified TCP
   723  // options enabled and returns a RawEndpoint which represents the other end of
   724  // the connection.
   725  //
   726  // It also verifies where required(eg.Timestamp) that the ACK to the SYN-ACK
   727  // does not carry an option that was not requested.
   728  func (c *Context) CreateConnectedWithOptions(wantOptions header.TCPSynOptions) *RawEndpoint {
   729  	var err *tcpip.Error
   730  	c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ)
   731  	if err != nil {
   732  		c.t.Fatalf("c.s.NewEndpoint(tcp, ipv4...) = %v", err)
   733  	}
   734  	if got, want := tcp.EndpointState(c.EP.State()), tcp.StateInitial; got != want {
   735  		c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got)
   736  	}
   737  
   738  	// Start connection attempt.
   739  	waitEntry, notifyCh := waiter.NewChannelEntry(nil)
   740  	c.WQ.EventRegister(&waitEntry, waiter.EventOut)
   741  	defer c.WQ.EventUnregister(&waitEntry)
   742  
   743  	testFullAddr := tcpip.FullAddress{Addr: TestAddr, Port: TestPort}
   744  	err = c.EP.Connect(testFullAddr)
   745  	if err != tcpip.ErrConnectStarted {
   746  		c.t.Fatalf("c.ep.Connect(%v) = %v", testFullAddr, err)
   747  	}
   748  	// Receive SYN packet.
   749  	b := c.GetPacket()
   750  	// Validate that the syn has the timestamp option and a valid
   751  	// TS value.
   752  	mss := uint16(c.linkEP.MTU() - header.IPv4MinimumSize - header.TCPMinimumSize)
   753  
   754  	checker.IPv4(c.t, b,
   755  		checker.TCP(
   756  			checker.DstPort(TestPort),
   757  			checker.TCPFlags(header.TCPFlagSyn),
   758  			checker.TCPSynOptions(header.TCPSynOptions{
   759  				MSS:           mss,
   760  				TS:            true,
   761  				WS:            int(c.WindowScale),
   762  				SACKPermitted: c.SACKEnabled(),
   763  			}),
   764  		),
   765  	)
   766  	if got, want := tcp.EndpointState(c.EP.State()), tcp.StateSynSent; got != want {
   767  		c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got)
   768  	}
   769  
   770  	tcpSeg := header.TCP(header.IPv4(b).Payload())
   771  	synOptions := header.ParseSynOptions(tcpSeg.Options(), false)
   772  
   773  	// Build options w/ tsVal to be sent in the SYN-ACK.
   774  	synAckOptions := make([]byte, header.TCPOptionsMaximumSize)
   775  	offset := 0
   776  	if wantOptions.WS != -1 {
   777  		offset += header.EncodeWSOption(wantOptions.WS, synAckOptions[offset:])
   778  	}
   779  	if wantOptions.TS {
   780  		offset += header.EncodeTSOption(wantOptions.TSVal, synOptions.TSVal, synAckOptions[offset:])
   781  	}
   782  	if wantOptions.SACKPermitted {
   783  		offset += header.EncodeSACKPermittedOption(synAckOptions[offset:])
   784  	}
   785  
   786  	offset += header.AddTCPOptionPadding(synAckOptions, offset)
   787  
   788  	// Build SYN-ACK.
   789  	c.IRS = seqnum.Value(tcpSeg.SequenceNumber())
   790  	iss := seqnum.Value(testInitialSequenceNumber)
   791  	c.SendPacket(nil, &Headers{
   792  		SrcPort: tcpSeg.DestinationPort(),
   793  		DstPort: tcpSeg.SourcePort(),
   794  		Flags:   header.TCPFlagSyn | header.TCPFlagAck,
   795  		SeqNum:  iss,
   796  		AckNum:  c.IRS.Add(1),
   797  		RcvWnd:  30000,
   798  		TCPOpts: synAckOptions[:offset],
   799  	})
   800  
   801  	// Read ACK.
   802  	ackPacket := c.GetPacket()
   803  
   804  	// Verify TCP header fields.
   805  	tcpCheckers := []checker.TransportChecker{
   806  		checker.DstPort(TestPort),
   807  		checker.TCPFlags(header.TCPFlagAck),
   808  		checker.SeqNum(uint32(c.IRS) + 1),
   809  		checker.AckNum(uint32(iss) + 1),
   810  	}
   811  
   812  	// Verify that tsEcr of ACK packet is wantOptions.TSVal if the
   813  	// timestamp option was enabled, if not then we verify that
   814  	// there is no timestamp in the ACK packet.
   815  	if wantOptions.TS {
   816  		tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(true, 0, wantOptions.TSVal))
   817  	} else {
   818  		tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(false, 0, 0))
   819  	}
   820  
   821  	checker.IPv4(c.t, ackPacket, checker.TCP(tcpCheckers...))
   822  
   823  	ackSeg := header.TCP(header.IPv4(ackPacket).Payload())
   824  	ackOptions := ackSeg.ParsedOptions()
   825  
   826  	// Wait for connection to be established.
   827  	select {
   828  	case <-notifyCh:
   829  		err = c.EP.GetSockOpt(tcpip.ErrorOption{})
   830  		if err != nil {
   831  			c.t.Fatalf("Unexpected error when connecting: %v", err)
   832  		}
   833  	case <-time.After(1 * time.Second):
   834  		c.t.Fatalf("Timed out waiting for connection")
   835  	}
   836  	if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want {
   837  		c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got)
   838  	}
   839  
   840  	// Store the source port in use by the endpoint.
   841  	c.Port = tcpSeg.SourcePort()
   842  
   843  	// Mark in context that timestamp option is enabled for this endpoint.
   844  	c.TimeStampEnabled = true
   845  
   846  	return &RawEndpoint{
   847  		C:             c,
   848  		SrcPort:       tcpSeg.DestinationPort(),
   849  		DstPort:       tcpSeg.SourcePort(),
   850  		Flags:         header.TCPFlagAck | header.TCPFlagPsh,
   851  		NextSeqNum:    iss + 1,
   852  		AckNum:        c.IRS.Add(1),
   853  		WndSize:       30000,
   854  		RecentTS:      ackOptions.TSVal,
   855  		TSVal:         wantOptions.TSVal,
   856  		SACKPermitted: wantOptions.SACKPermitted,
   857  	}
   858  }
   859  
   860  // AcceptWithOptions initializes a listening endpoint and connects to it with the
   861  // provided options enabled. It also verifies that the SYN-ACK has the expected
   862  // values for the provided options.
   863  //
   864  // The function returns a RawEndpoint representing the other end of the accepted
   865  // endpoint.
   866  func (c *Context) AcceptWithOptions(wndScale int, synOptions header.TCPSynOptions) *RawEndpoint {
   867  	// Create EP and start listening.
   868  	wq := &waiter.Queue{}
   869  	ep, err := c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, wq)
   870  	if err != nil {
   871  		c.t.Fatalf("NewEndpoint failed: %v", err)
   872  	}
   873  	defer ep.Close()
   874  
   875  	if err := ep.Bind(tcpip.FullAddress{Port: StackPort}); err != nil {
   876  		c.t.Fatalf("Bind failed: %v", err)
   877  	}
   878  	if got, want := tcp.EndpointState(ep.State()), tcp.StateBound; got != want {
   879  		c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got)
   880  	}
   881  
   882  	if err := ep.Listen(10); err != nil {
   883  		c.t.Fatalf("Listen failed: %v", err)
   884  	}
   885  	if got, want := tcp.EndpointState(ep.State()), tcp.StateListen; got != want {
   886  		c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got)
   887  	}
   888  
   889  	rep := c.PassiveConnectWithOptions(100, wndScale, synOptions)
   890  
   891  	// Try to accept the connection.
   892  	we, ch := waiter.NewChannelEntry(nil)
   893  	wq.EventRegister(&we, waiter.EventIn)
   894  	defer wq.EventUnregister(&we)
   895  
   896  	c.EP, _, err = ep.Accept()
   897  	if err == tcpip.ErrWouldBlock {
   898  		// Wait for connection to be established.
   899  		select {
   900  		case <-ch:
   901  			c.EP, _, err = ep.Accept()
   902  			if err != nil {
   903  				c.t.Fatalf("Accept failed: %v", err)
   904  			}
   905  
   906  		case <-time.After(1 * time.Second):
   907  			c.t.Fatalf("Timed out waiting for accept")
   908  		}
   909  	}
   910  	if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want {
   911  		c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got)
   912  	}
   913  
   914  	return rep
   915  }
   916  
   917  // PassiveConnect just disables WindowScaling and delegates the call to
   918  // PassiveConnectWithOptions.
   919  func (c *Context) PassiveConnect(maxPayload, wndScale int, synOptions header.TCPSynOptions) {
   920  	synOptions.WS = -1
   921  	c.PassiveConnectWithOptions(maxPayload, wndScale, synOptions)
   922  }
   923  
   924  // PassiveConnectWithOptions initiates a new connection (with the specified TCP
   925  // options enabled) to the port on which the Context.ep is listening for new
   926  // connections. It also validates that the SYN-ACK has the expected values for
   927  // the enabled options.
   928  //
   929  // NOTE: MSS is not a negotiated option and it can be asymmetric
   930  // in each direction. This function uses the maxPayload to set the MSS to be
   931  // sent to the peer on a connect and validates that the MSS in the SYN-ACK
   932  // response is equal to the MTU - (tcphdr len + iphdr len).
   933  //
   934  // wndScale is the expected window scale in the SYN-ACK and synOptions.WS is the
   935  // value of the window scaling option to be sent in the SYN. If synOptions.WS >
   936  // 0 then we send the WindowScale option.
   937  func (c *Context) PassiveConnectWithOptions(maxPayload, wndScale int, synOptions header.TCPSynOptions) *RawEndpoint {
   938  	opts := make([]byte, header.TCPOptionsMaximumSize)
   939  	offset := 0
   940  	offset += header.EncodeMSSOption(uint32(maxPayload), opts)
   941  
   942  	if synOptions.WS >= 0 {
   943  		offset += header.EncodeWSOption(3, opts[offset:])
   944  	}
   945  	if synOptions.TS {
   946  		offset += header.EncodeTSOption(synOptions.TSVal, synOptions.TSEcr, opts[offset:])
   947  	}
   948  
   949  	if synOptions.SACKPermitted {
   950  		offset += header.EncodeSACKPermittedOption(opts[offset:])
   951  	}
   952  
   953  	paddingToAdd := 4 - offset%4
   954  	// Now add any padding bytes that might be required to quad align the
   955  	// options.
   956  	for i := offset; i < offset+paddingToAdd; i++ {
   957  		opts[i] = header.TCPOptionNOP
   958  	}
   959  	offset += paddingToAdd
   960  
   961  	// Send a SYN request.
   962  	iss := seqnum.Value(testInitialSequenceNumber)
   963  	c.SendPacket(nil, &Headers{
   964  		SrcPort: TestPort,
   965  		DstPort: StackPort,
   966  		Flags:   header.TCPFlagSyn,
   967  		SeqNum:  iss,
   968  		RcvWnd:  30000,
   969  		TCPOpts: opts[:offset],
   970  	})
   971  
   972  	// Receive the SYN-ACK reply. Make sure MSS and other expected options
   973  	// are present.
   974  	b := c.GetPacket()
   975  	tcp := header.TCP(header.IPv4(b).Payload())
   976  	c.IRS = seqnum.Value(tcp.SequenceNumber())
   977  
   978  	tcpCheckers := []checker.TransportChecker{
   979  		checker.SrcPort(StackPort),
   980  		checker.DstPort(TestPort),
   981  		checker.TCPFlags(header.TCPFlagAck | header.TCPFlagSyn),
   982  		checker.AckNum(uint32(iss) + 1),
   983  		checker.TCPSynOptions(header.TCPSynOptions{MSS: synOptions.MSS, WS: wndScale, SACKPermitted: synOptions.SACKPermitted && c.SACKEnabled()}),
   984  	}
   985  
   986  	// If TS option was enabled in the original SYN then add a checker to
   987  	// validate the Timestamp option in the SYN-ACK.
   988  	if synOptions.TS {
   989  		tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(synOptions.TS, 0, synOptions.TSVal))
   990  	} else {
   991  		tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(false, 0, 0))
   992  	}
   993  
   994  	checker.IPv4(c.t, b, checker.TCP(tcpCheckers...))
   995  	rcvWnd := seqnum.Size(30000)
   996  	ackHeaders := &Headers{
   997  		SrcPort: TestPort,
   998  		DstPort: StackPort,
   999  		Flags:   header.TCPFlagAck,
  1000  		SeqNum:  iss + 1,
  1001  		AckNum:  c.IRS + 1,
  1002  		RcvWnd:  rcvWnd,
  1003  	}
  1004  
  1005  	// If WS was expected to be in effect then scale the advertised window
  1006  	// correspondingly.
  1007  	if synOptions.WS > 0 {
  1008  		ackHeaders.RcvWnd = rcvWnd >> byte(synOptions.WS)
  1009  	}
  1010  
  1011  	parsedOpts := tcp.ParsedOptions()
  1012  	if synOptions.TS {
  1013  		// Echo the tsVal back to the peer in the tsEcr field of the
  1014  		// timestamp option.
  1015  		// Increment TSVal by 1 from the value sent in the SYN and echo
  1016  		// the TSVal in the SYN-ACK in the TSEcr field.
  1017  		opts := [12]byte{header.TCPOptionNOP, header.TCPOptionNOP}
  1018  		header.EncodeTSOption(synOptions.TSVal+1, parsedOpts.TSVal, opts[2:])
  1019  		ackHeaders.TCPOpts = opts[:]
  1020  	}
  1021  
  1022  	// Send ACK.
  1023  	c.SendPacket(nil, ackHeaders)
  1024  
  1025  	c.Port = StackPort
  1026  
  1027  	return &RawEndpoint{
  1028  		C:             c,
  1029  		SrcPort:       TestPort,
  1030  		DstPort:       StackPort,
  1031  		Flags:         header.TCPFlagPsh | header.TCPFlagAck,
  1032  		NextSeqNum:    iss + 1,
  1033  		AckNum:        c.IRS + 1,
  1034  		WndSize:       rcvWnd,
  1035  		SACKPermitted: synOptions.SACKPermitted && c.SACKEnabled(),
  1036  		RecentTS:      parsedOpts.TSVal,
  1037  		TSVal:         synOptions.TSVal + 1,
  1038  	}
  1039  }
  1040  
  1041  // SACKEnabled returns true if the TCP Protocol option SACKEnabled is set to true
  1042  // for the Stack in the context.
  1043  func (c *Context) SACKEnabled() bool {
  1044  	var v tcp.SACKEnabled
  1045  	if err := c.Stack().TransportProtocolOption(tcp.ProtocolNumber, &v); err != nil {
  1046  		// Stack doesn't support SACK. So just return.
  1047  		return false
  1048  	}
  1049  	return bool(v)
  1050  }
  1051  
  1052  // SetGSOEnabled enables or disables generic segmentation offload.
  1053  func (c *Context) SetGSOEnabled(enable bool) {
  1054  	c.linkEP.GSO = enable
  1055  }
  1056  
  1057  // MSSWithoutOptions returns the value for the MSS used by the stack when no
  1058  // options are in use.
  1059  func (c *Context) MSSWithoutOptions() uint16 {
  1060  	return uint16(c.linkEP.MTU() - header.IPv4MinimumSize - header.TCPMinimumSize)
  1061  }