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 }