mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:28:12 +00:00
Kernel: Convert TCP pseudo-headers through a union
This keeps us from tripping strict aliasing, which previously made TCP connections inoperable when building without `-fsanitize=undefined` or `-fno-strict-aliasing`.
This commit is contained in:
parent
7cd99572be
commit
24f956c739
1 changed files with 14 additions and 10 deletions
|
@ -360,31 +360,35 @@ bool TCPSocket::should_delay_next_ack() const
|
||||||
|
|
||||||
NetworkOrdered<u16> TCPSocket::compute_tcp_checksum(IPv4Address const& source, IPv4Address const& destination, TCPPacket const& packet, u16 payload_size)
|
NetworkOrdered<u16> TCPSocket::compute_tcp_checksum(IPv4Address const& source, IPv4Address const& destination, TCPPacket const& packet, u16 payload_size)
|
||||||
{
|
{
|
||||||
struct [[gnu::packed]] PseudoHeader {
|
union PseudoHeader {
|
||||||
IPv4Address source;
|
struct [[gnu::packed]] {
|
||||||
IPv4Address destination;
|
IPv4Address source;
|
||||||
u8 zero;
|
IPv4Address destination;
|
||||||
u8 protocol;
|
u8 zero;
|
||||||
NetworkOrdered<u16> payload_size;
|
u8 protocol;
|
||||||
|
NetworkOrdered<u16> payload_size;
|
||||||
|
} header;
|
||||||
|
u16 raw[6];
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(PseudoHeader) == 12);
|
||||||
|
|
||||||
PseudoHeader pseudo_header { source, destination, 0, (u8)IPv4Protocol::TCP, packet.header_size() + payload_size };
|
PseudoHeader pseudo_header { .header = { source, destination, 0, (u8)IPv4Protocol::TCP, packet.header_size() + payload_size } };
|
||||||
|
|
||||||
u32 checksum = 0;
|
u32 checksum = 0;
|
||||||
auto raw_pseudo_header = bit_cast<u16*>(&pseudo_header);
|
auto* raw_pseudo_header = pseudo_header.raw;
|
||||||
for (size_t i = 0; i < sizeof(pseudo_header) / sizeof(u16); ++i) {
|
for (size_t i = 0; i < sizeof(pseudo_header) / sizeof(u16); ++i) {
|
||||||
checksum += AK::convert_between_host_and_network_endian(raw_pseudo_header[i]);
|
checksum += AK::convert_between_host_and_network_endian(raw_pseudo_header[i]);
|
||||||
if (checksum > 0xffff)
|
if (checksum > 0xffff)
|
||||||
checksum = (checksum >> 16) + (checksum & 0xffff);
|
checksum = (checksum >> 16) + (checksum & 0xffff);
|
||||||
}
|
}
|
||||||
auto raw_packet = bit_cast<u16*>(&packet);
|
auto* raw_packet = bit_cast<u16*>(&packet);
|
||||||
for (size_t i = 0; i < packet.header_size() / sizeof(u16); ++i) {
|
for (size_t i = 0; i < packet.header_size() / sizeof(u16); ++i) {
|
||||||
checksum += AK::convert_between_host_and_network_endian(raw_packet[i]);
|
checksum += AK::convert_between_host_and_network_endian(raw_packet[i]);
|
||||||
if (checksum > 0xffff)
|
if (checksum > 0xffff)
|
||||||
checksum = (checksum >> 16) + (checksum & 0xffff);
|
checksum = (checksum >> 16) + (checksum & 0xffff);
|
||||||
}
|
}
|
||||||
VERIFY(packet.data_offset() * 4 == packet.header_size());
|
VERIFY(packet.data_offset() * 4 == packet.header_size());
|
||||||
auto raw_payload = bit_cast<u16*>(packet.payload());
|
auto* raw_payload = bit_cast<u16*>(packet.payload());
|
||||||
for (size_t i = 0; i < payload_size / sizeof(u16); ++i) {
|
for (size_t i = 0; i < payload_size / sizeof(u16); ++i) {
|
||||||
checksum += AK::convert_between_host_and_network_endian(raw_payload[i]);
|
checksum += AK::convert_between_host_and_network_endian(raw_payload[i]);
|
||||||
if (checksum > 0xffff)
|
if (checksum > 0xffff)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue