mirror of
https://github.com/soypat/lneto.git
synced 2026-08-22 07:29:04 +00:00
Checksum simplification proposal (#29)
* Simplified checksum calculation and verification * Fixed tests * UDP: using NewBoundedFrame to create a Frame instance limited to the actual frame size. * Minor: renamed some functions * Commented and made more readable consecutive SetCRC calls. * Fixed icmp checksum calculation after rebase * Replaced NewBoundedFrame with explicit validation
This commit is contained in:
@@ -11,35 +11,25 @@ import (
|
||||
//
|
||||
// The zero value of CRC791 is ready to use.
|
||||
type CRC791 struct {
|
||||
sum uint32
|
||||
excedent uint8
|
||||
needPad bool
|
||||
sum uint32
|
||||
}
|
||||
|
||||
// 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
|
||||
func sum16(sum uint32) uint16 {
|
||||
sum = (sum & 0xffff) + sum>>16
|
||||
// the max value of sum at this point is 0x1fffe, so an additional round is enough
|
||||
return ^uint16(sum + sum>>16)
|
||||
}
|
||||
|
||||
func sumWriteEven(sum uint32, buff []byte) uint32 {
|
||||
for i := 0; i < len(buff); i += 2 {
|
||||
sum += uint32(binary.BigEndian.Uint16(buff[i:]))
|
||||
}
|
||||
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
|
||||
return sum
|
||||
}
|
||||
|
||||
// Write adds the bytes in p to the running checksum. The buffer size must be even or the function will panic.
|
||||
func (c *CRC791) WriteEven(buff []byte) {
|
||||
c.sum = sumWriteEven(c.sum, buff)
|
||||
}
|
||||
|
||||
// AddUint32 adds a 32 bit value to the running checksum interpreted as BigEndian (network order).
|
||||
@@ -50,55 +40,32 @@ func (c *CRC791) AddUint32(value uint32) {
|
||||
|
||||
// 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)
|
||||
c.sum += uint32(value)
|
||||
}
|
||||
|
||||
// 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
|
||||
return sum16(c.sum)
|
||||
}
|
||||
|
||||
// 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)
|
||||
// PayloadSum16 returns the checksum resulting by adding the bytes in p to the running checksum.
|
||||
func (c *CRC791) PayloadSum16(buff []byte) uint16 {
|
||||
odd := len(buff) & 1
|
||||
sum := sumWriteEven(c.sum, buff[:len(buff)-odd])
|
||||
if odd > 0 {
|
||||
sum += uint32(buff[len(buff)-1]) << 8
|
||||
}
|
||||
cc.AddUint16(expectedSum16)
|
||||
return cc.sum16() == 0
|
||||
return sum16(sum)
|
||||
}
|
||||
|
||||
// Reset zeros out the CRC791, resetting it to the initial state.
|
||||
func (c *CRC791) Reset() { *c = CRC791{} }
|
||||
|
||||
// NonZeroChecksum ensures that the given checksum is not zero, by returning 0xffff instead.
|
||||
func NeverZeroSum(sum16 uint16) uint16 {
|
||||
// 0x0000 and 0xffff are the same number in ones' complement math
|
||||
if sum16 == 0 {
|
||||
return 0xffff
|
||||
}
|
||||
return sum16
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user