github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/tcpip/transport/tcp/segment.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 tcp
    16  
    17  import (
    18  	"sync/atomic"
    19  	"time"
    20  
    21  	"github.com/google/netstack/tcpip"
    22  	"github.com/google/netstack/tcpip/buffer"
    23  	"github.com/google/netstack/tcpip/header"
    24  	"github.com/google/netstack/tcpip/seqnum"
    25  	"github.com/google/netstack/tcpip/stack"
    26  )
    27  
    28  // segment represents a TCP segment. It holds the payload and parsed TCP segment
    29  // information, and can be added to intrusive lists.
    30  // segment is mostly immutable, the only field allowed to change is viewToDeliver.
    31  //
    32  // +stateify savable
    33  type segment struct {
    34  	segmentEntry
    35  	refCnt int32
    36  	id     stack.TransportEndpointID
    37  	route  stack.Route
    38  	data   buffer.VectorisedView
    39  	// views is used as buffer for data when its length is large
    40  	// enough to store a VectorisedView.
    41  	views [8]buffer.View
    42  	// viewToDeliver keeps track of the next View that should be
    43  	// delivered by the Read endpoint.
    44  	viewToDeliver  int
    45  	sequenceNumber seqnum.Value
    46  	ackNumber      seqnum.Value
    47  	flags          uint8
    48  	window         seqnum.Size
    49  	// csum is only populated for received segments.
    50  	csum uint16
    51  	// csumValid is true if the csum in the received segment is valid.
    52  	csumValid bool
    53  
    54  	// parsedOptions stores the parsed values from the options in the segment.
    55  	parsedOptions  header.TCPOptions
    56  	options        []byte
    57  	hasNewSACKInfo bool
    58  	rcvdTime       time.Time
    59  	// xmitTime is the last transmit time of this segment. A zero value
    60  	// indicates that the segment has yet to be transmitted.
    61  	xmitTime time.Time
    62  }
    63  
    64  func newSegment(r *stack.Route, id stack.TransportEndpointID, pkt tcpip.PacketBuffer) *segment {
    65  	s := &segment{
    66  		refCnt: 1,
    67  		id:     id,
    68  		route:  r.Clone(),
    69  	}
    70  	s.data = pkt.Data.Clone(s.views[:])
    71  	s.rcvdTime = time.Now()
    72  	return s
    73  }
    74  
    75  func newSegmentFromView(r *stack.Route, id stack.TransportEndpointID, v buffer.View) *segment {
    76  	s := &segment{
    77  		refCnt: 1,
    78  		id:     id,
    79  		route:  r.Clone(),
    80  	}
    81  	s.views[0] = v
    82  	s.data = buffer.NewVectorisedView(len(v), s.views[:1])
    83  	s.rcvdTime = time.Now()
    84  	return s
    85  }
    86  
    87  func (s *segment) clone() *segment {
    88  	t := &segment{
    89  		refCnt:         1,
    90  		id:             s.id,
    91  		sequenceNumber: s.sequenceNumber,
    92  		ackNumber:      s.ackNumber,
    93  		flags:          s.flags,
    94  		window:         s.window,
    95  		route:          s.route.Clone(),
    96  		viewToDeliver:  s.viewToDeliver,
    97  		rcvdTime:       s.rcvdTime,
    98  	}
    99  	t.data = s.data.Clone(t.views[:])
   100  	return t
   101  }
   102  
   103  // flagIsSet checks if at least one flag in flags is set in s.flags.
   104  func (s *segment) flagIsSet(flags uint8) bool {
   105  	return s.flags&flags != 0
   106  }
   107  
   108  // flagsAreSet checks if all flags in flags are set in s.flags.
   109  func (s *segment) flagsAreSet(flags uint8) bool {
   110  	return s.flags&flags == flags
   111  }
   112  
   113  func (s *segment) decRef() {
   114  	if atomic.AddInt32(&s.refCnt, -1) == 0 {
   115  		s.route.Release()
   116  	}
   117  }
   118  
   119  func (s *segment) incRef() {
   120  	atomic.AddInt32(&s.refCnt, 1)
   121  }
   122  
   123  // logicalLen is the segment length in the sequence number space. It's defined
   124  // as the data length plus one for each of the SYN and FIN bits set.
   125  func (s *segment) logicalLen() seqnum.Size {
   126  	l := seqnum.Size(s.data.Size())
   127  	if s.flagIsSet(header.TCPFlagSyn) {
   128  		l++
   129  	}
   130  	if s.flagIsSet(header.TCPFlagFin) {
   131  		l++
   132  	}
   133  	return l
   134  }
   135  
   136  // parse populates the sequence & ack numbers, flags, and window fields of the
   137  // segment from the TCP header stored in the data. It then updates the view to
   138  // skip the header.
   139  //
   140  // Returns boolean indicating if the parsing was successful.
   141  //
   142  // If checksum verification is not offloaded then parse also verifies the
   143  // TCP checksum and stores the checksum and result of checksum verification in
   144  // the csum and csumValid fields of the segment.
   145  func (s *segment) parse() bool {
   146  	h := header.TCP(s.data.First())
   147  
   148  	// h is the header followed by the payload. We check that the offset to
   149  	// the data respects the following constraints:
   150  	// 1. That it's at least the minimum header size; if we don't do this
   151  	//    then part of the header would be delivered to user.
   152  	// 2. That the header fits within the buffer; if we don't do this, we
   153  	//    would panic when we tried to access data beyond the buffer.
   154  	//
   155  	// N.B. The segment has already been validated as having at least the
   156  	//      minimum TCP size before reaching here, so it's safe to read the
   157  	//      fields.
   158  	offset := int(h.DataOffset())
   159  	if offset < header.TCPMinimumSize || offset > len(h) {
   160  		return false
   161  	}
   162  
   163  	s.options = []byte(h[header.TCPMinimumSize:offset])
   164  	s.parsedOptions = header.ParseTCPOptions(s.options)
   165  
   166  	// Query the link capabilities to decide if checksum validation is
   167  	// required.
   168  	verifyChecksum := true
   169  	if s.route.Capabilities()&stack.CapabilityRXChecksumOffload != 0 {
   170  		s.csumValid = true
   171  		verifyChecksum = false
   172  		s.data.TrimFront(offset)
   173  	}
   174  	if verifyChecksum {
   175  		s.csum = h.Checksum()
   176  		xsum := s.route.PseudoHeaderChecksum(ProtocolNumber, uint16(s.data.Size()))
   177  		xsum = h.CalculateChecksum(xsum)
   178  		s.data.TrimFront(offset)
   179  		xsum = header.ChecksumVV(s.data, xsum)
   180  		s.csumValid = xsum == 0xffff
   181  	}
   182  
   183  	s.sequenceNumber = seqnum.Value(h.SequenceNumber())
   184  	s.ackNumber = seqnum.Value(h.AckNumber())
   185  	s.flags = h.Flags()
   186  	s.window = seqnum.Size(h.WindowSize())
   187  	return true
   188  }
   189  
   190  // sackBlock returns a header.SACKBlock that represents this segment.
   191  func (s *segment) sackBlock() header.SACKBlock {
   192  	return header.SACKBlock{s.sequenceNumber, s.sequenceNumber.Add(s.logicalLen())}
   193  }