github.com/FlowerWrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/header/checksum.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 header provides the implementation of the encoding and decoding of
    16  // network protocol headers.
    17  package header
    18  
    19  import (
    20  	"encoding/binary"
    21  
    22  	"github.com/FlowerWrong/netstack/tcpip"
    23  	"github.com/FlowerWrong/netstack/tcpip/buffer"
    24  )
    25  
    26  func calculateChecksum(buf []byte, initial uint32) uint16 {
    27  	v := initial
    28  
    29  	l := len(buf)
    30  	if l&1 != 0 {
    31  		l--
    32  		v += uint32(buf[l]) << 8
    33  	}
    34  
    35  	for i := 0; i < l; i += 2 {
    36  		v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
    37  	}
    38  
    39  	return ChecksumCombine(uint16(v), uint16(v>>16))
    40  }
    41  
    42  // Checksum calculates the checksum (as defined in RFC 1071) of the bytes in the
    43  // given byte array.
    44  //
    45  // The initial checksum must have been computed on an even number of bytes.
    46  func Checksum(buf []byte, initial uint16) uint16 {
    47  	return calculateChecksum(buf, uint32(initial))
    48  }
    49  
    50  // ChecksumVV calculates the checksum (as defined in RFC 1071) of the bytes in
    51  // the given VectorizedView.
    52  //
    53  // The initial checksum must have been computed on an even number of bytes.
    54  func ChecksumVV(vv buffer.VectorisedView, initial uint16) uint16 {
    55  	var odd bool
    56  	sum := initial
    57  	for _, v := range vv.Views() {
    58  		if len(v) == 0 {
    59  			continue
    60  		}
    61  		s := uint32(sum)
    62  		if odd {
    63  			s += uint32(v[0])
    64  			v = v[1:]
    65  		}
    66  		odd = len(v)&1 != 0
    67  		sum = calculateChecksum(v, s)
    68  	}
    69  	return sum
    70  }
    71  
    72  // ChecksumCombine combines the two uint16 to form their checksum. This is done
    73  // by adding them and the carry.
    74  //
    75  // Note that checksum a must have been computed on an even number of bytes.
    76  func ChecksumCombine(a, b uint16) uint16 {
    77  	v := uint32(a) + uint32(b)
    78  	return uint16(v + v>>16)
    79  }
    80  
    81  // PseudoHeaderChecksum calculates the pseudo-header checksum for the given
    82  // destination protocol and network address. Pseudo-headers are needed by
    83  // transport layers when calculating their own checksum.
    84  func PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, srcAddr tcpip.Address, dstAddr tcpip.Address, totalLen uint16) uint16 {
    85  	xsum := Checksum([]byte(srcAddr), 0)
    86  	xsum = Checksum([]byte(dstAddr), xsum)
    87  
    88  	// Add the length portion of the checksum to the pseudo-checksum.
    89  	tmp := make([]byte, 2)
    90  	binary.BigEndian.PutUint16(tmp, totalLen)
    91  	xsum = Checksum(tmp, xsum)
    92  
    93  	return Checksum([]byte{0, uint8(protocol)}, xsum)
    94  }