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 }