Как проверить контрольную сумму ICMPv6? (Почему я продолжаю получать контрольную сумму 0x3fff?)

Я работаю над программой Linux userspace, которая получает рекламные пакеты IPv6 маршрутизатора. В рамках RFC4861 мне нужно проверить контрольную сумму ICMPv6. Основываясь на моих исследованиях, большинство из которых относится к контрольной сумме IP вообще, если вы вычислить те, которые дополняют контрольную сумму псевдозаголовка IPv6, а содержимое пакета, то результат должен быть 0xffff. Но я продолжаю получать контрольную сумму 0x3fff.

Что-то не так с моей реализацией контрольной суммы? Проверяет ли ядро Linux контрольную сумму ICMPv6 перед передачей пакетов в пользовательское пространство? Есть ли хороший справочный источник для проверки известных хороших пакетов ICMPv6?

uint16_t
checksum(const struct in6_addr *src, const struct in6_addr *dst, const void *data, size_t len) {
    uint32_t checksum = 0;
    union {
        uint32_t dword;
        uint16_t word[2];
        uint8_t byte[4];
    } temp;

    // IPv6 Pseudo header source address, destination address, length, zeros, next header
    checksum += src->s6_addr16[0];
    checksum += src->s6_addr16[1];
    checksum += src->s6_addr16[2];
    checksum += src->s6_addr16[3];
    checksum += src->s6_addr16[4];
    checksum += src->s6_addr16[5];
    checksum += src->s6_addr16[6];
    checksum += src->s6_addr16[7];

    checksum += dst->s6_addr16[0];
    checksum += dst->s6_addr16[1];
    checksum += dst->s6_addr16[2];
    checksum += dst->s6_addr16[3];
    checksum += dst->s6_addr16[4];
    checksum += dst->s6_addr16[5];
    checksum += dst->s6_addr16[6];
    checksum += dst->s6_addr16[7];

    temp.dword = htonl(len);
    checksum += temp.word[0];
    checksum += temp.word[1];

    temp.byte[0] = 0;
    temp.byte[1] = 0;
    temp.byte[2] = 0;
    temp.byte[3] = 58; // ICMPv6
    checksum += temp.word[0];
    checksum += temp.word[1];

    while (len > 1) {
        checksum += *((const uint16_t *)data);
        data = (const uint16_t *)data + 1;
        len -= 2;
    }

    if (len > 0)
        checksum += *((const uint8_t *)data);

    printf("Checksum %x\n", checksum);

    while (checksum >> 16 != 0)
        checksum = (checksum & 0xffff) + (checksum >> 16);

    checksum = ~checksum;

    return (uint16_t)checksum;
}
5
задан dlundquist 17 September 2011 в 21:17
поделиться