inet_checksum() accesses packet data as an array of uint16_t, but the
packet data can be for example of "anonymous struct pseudo" type from
route_ipv6_unreachable().
This type isn't a compatible type with uint16_t so a strict aliasing
violation occurs and causes the checksum to be computed incorrectly.
Fix this by using the memcpy() idiom to read the packet data as an array of
uint16_t in inet_checksum() (this should be understood by compilers and
optimized accordingly, so no actual copy occurs).
/* RFC 1071 */
static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
- uint16_t *p = data;
+ uint16_t word;
uint32_t checksum = prevsum ^ 0xFFFF;
while(len >= 2) {
- checksum += *p++;
+ memcpy(&word, data, sizeof(word));
+ checksum += word;
+ data += 2;
len -= 2;
}
if(len) {
- checksum += *(uint8_t *)p;
+ checksum += *(uint8_t *)data;
}
while(checksum >> 16) {