Цикл while переполнен. Тело случится только один раз.
while (checksum >> 16 != 0)
checksum = (checksum & 0xffff) + (checksum >> 16);
checksum = ~checksum;
return (uint16_t)checksum;
Вместо
checksum += checksum >> 16;
return (uint16_t)~checksum;
Это не нужно. len всегда 16-битный
temp.dword = htonl(len);
checksum += temp.word[0];
checksum += temp.word[1];
Это не нужно. Константа всегда 00 00 00 58, поэтому просто добавьте 58.
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];
Ваш алгоритм в целом выглядит правильно, за исключением того, как вы обрабатываете порядковый номер целых чисел и последний байт с нечетным байтом. Из того, как я прочитал протокол, байты должны быть суммированы в порядке с прямым порядком байтов, то есть байты 0xAB 0xCD должны интерпретироваться как 16-битный 0xABCD. Ваш код зависит от заказа вашей машины.
Порядок построения целых чисел будет влиять на количество переносов, которые вы правильно добавляете в контрольную сумму. Но если ваш код соответствует вашей целевой машине, то последний нечетный байт неверен. 0xAB приведет к 0xAB00, а не к 0x00AB, как написано.