mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-22 17:31:58 -05:00
2a0af461b2
Up until now, the internet_checksum function lived in IPv4.h. Due to its use in IPv6, a better place for it nowadays would be in IP.h. Due to how it gets used in IPv6 scenarios, it makes sense to extend it to run over multiple smaller structs instead of one big continous chunk of memory. This change converts internet_checksum into a class with methods "add" and "finish", which process data and return the final result, respectively. This commit also fixes proper hash computation for payloads that have an odd length. Furthermore, the function was refactored to use a ReadonlyBytes object instead of separate data and size. Co-Authored-By: Wanda <wanda@phinode.net>
53 lines
1.4 KiB
C++
53 lines
1.4 KiB
C++
/*
|
|
* Copyright (c) 2024, kleines Filmröllchen <filmroellchen@serenityos.org>
|
|
* Copyright (c) 2024, sdomi <ja@sdomi.pl>
|
|
* Copyright (c) 2024, Wanda <wanda@phinode.net>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Types.h>
|
|
|
|
namespace Kernel {
|
|
|
|
// IPv4 "Protocol" field or IPv6 "Next Header" field.
|
|
// Included in this enum are only transport layer protocols, not IPv6 extended headers.
|
|
// https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
|
enum class TransportProtocol : u8 {
|
|
ICMP = 1,
|
|
TCP = 6,
|
|
UDP = 17,
|
|
ICMPv6 = 58,
|
|
};
|
|
|
|
class InternetChecksum {
|
|
public:
|
|
void add(ReadonlyBytes bytes)
|
|
{
|
|
VERIFY(!m_uneven_payload);
|
|
Span<u16 const> words { bit_cast<u16 const*>(bytes.data()), bytes.size() / 2 };
|
|
for (u16 w : words) {
|
|
m_checksum += AK::convert_between_host_and_network_endian(w);
|
|
if (m_checksum & 0x80000000)
|
|
m_checksum = (m_checksum & 0xffff) | (m_checksum >> 16);
|
|
}
|
|
if (bytes.size() % 2 == 1) {
|
|
m_checksum += (bytes.last()) << 8;
|
|
m_uneven_payload = true;
|
|
}
|
|
}
|
|
NetworkOrdered<u16> finish()
|
|
{
|
|
while (m_checksum >> 16)
|
|
m_checksum = (m_checksum & 0xffff) + (m_checksum >> 16);
|
|
return ~m_checksum & 0xffff;
|
|
}
|
|
|
|
private:
|
|
u32 m_checksum { 0 };
|
|
bool m_uneven_payload { false };
|
|
};
|
|
|
|
}
|