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{} }