mirror of
https://github.com/soypat/lneto.git
synced 2026-08-13 03:13:43 +00:00
5e61b4600d
* Checksum 0x0000 is returned as 0xFFFF (mandatory for UDP, common for TCP) * Both checksum zero values (0x0000 and 0xFFFF) are accepted when receiving * Rename parameter in VerifySum16 to expectedSum16 --------- Co-authored-by: Pat Whittingslow <graded.sp@gmail.com>
105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package lneto
|
|
|
|
import (
|
|
"encoding/binary"
|
|
)
|
|
|
|
// CRC791 function as defined by RFC 791. The Checksum field for TCP+IP
|
|
// is the 16-bit ones' complement of the ones' complement sum of
|
|
// all 16-bit words in the header. In case of uneven number of octet the
|
|
// last word is LSB padded with zeros.
|
|
//
|
|
// The zero value of CRC791 is ready to use.
|
|
type CRC791 struct {
|
|
sum uint32
|
|
excedent uint8
|
|
needPad bool
|
|
}
|
|
|
|
// Write adds the bytes in p to the running checksum.
|
|
func (c *CRC791) Write(buff []byte) (n int, err error) {
|
|
if len(buff) == 0 {
|
|
return 0, nil
|
|
}
|
|
if c.needPad {
|
|
c.sum += uint32(c.excedent)<<8 + uint32(buff[0])
|
|
buff = buff[1:]
|
|
c.excedent = 0
|
|
c.needPad = false
|
|
if len(buff) == 0 {
|
|
return 1, nil
|
|
}
|
|
}
|
|
count := len(buff)
|
|
for count > 1 {
|
|
c.sum += uint32(binary.BigEndian.Uint16(buff[len(buff)-count:]))
|
|
count -= 2
|
|
}
|
|
if count != 0 {
|
|
c.excedent = buff[len(buff)-1]
|
|
c.needPad = true
|
|
}
|
|
return len(buff), nil
|
|
}
|
|
|
|
// AddUint32 adds a 32 bit value to the running checksum interpreted as BigEndian (network order).
|
|
func (c *CRC791) AddUint32(value uint32) {
|
|
c.AddUint16(uint16(value >> 16))
|
|
c.AddUint16(uint16(value))
|
|
}
|
|
|
|
// Add16 adds a 16 bit value to the running checksum interpreted as BigEndian (network order).
|
|
func (c *CRC791) AddUint16(value uint16) {
|
|
if c.needPad {
|
|
c.sum += uint32(c.excedent)<<8 | uint32(value>>8)
|
|
c.excedent = byte(value)
|
|
} else {
|
|
c.sum += uint32(value)
|
|
}
|
|
}
|
|
|
|
// Add16 adds value to the running checksum interpreted as BigEndian (network order).
|
|
func (c *CRC791) AddUint8(value uint8) {
|
|
if c.needPad {
|
|
c.sum += uint32(c.excedent)<<8 | uint32(value)
|
|
} else {
|
|
c.excedent = value
|
|
}
|
|
c.needPad = !c.needPad
|
|
}
|
|
|
|
func (c *CRC791) sum16() uint16 {
|
|
sum := c.sum
|
|
if c.needPad {
|
|
sum += uint32(c.excedent) << 8
|
|
}
|
|
for sum>>16 != 0 {
|
|
sum = (sum & 0xffff) + (sum >> 16)
|
|
}
|
|
return uint16(^sum)
|
|
}
|
|
|
|
// Sum16 calculates the checksum with the data written to c thus far.
|
|
func (c *CRC791) Sum16() uint16 {
|
|
sum16 := c.sum16()
|
|
if sum16 == 0 {
|
|
// The zero value is always transmitted as 0xFFFF, as required by UDP (RFC 768), and still valid for TCP and IP.
|
|
sum16 = 0xffff
|
|
}
|
|
return sum16
|
|
}
|
|
|
|
// VerifySum16 verifies that the given checksum matches the data written to c thus far.
|
|
func (c *CRC791) VerifySum16(expectedSum16 uint16) bool {
|
|
// as recommended by RFC 1624, this implementation supports both 0x0000 and 0xFFFF as zero value for the checksum
|
|
cc := *c
|
|
if cc.needPad {
|
|
cc.AddUint8(0)
|
|
}
|
|
cc.AddUint16(expectedSum16)
|
|
return cc.sum16() == 0
|
|
}
|
|
|
|
// Reset zeros out the CRC791, resetting it to the initial state.
|
|
func (c *CRC791) Reset() { *c = CRC791{} }
|