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