diff --git a/kernel/include/kernel/Networking/IPv4Layer.h b/kernel/include/kernel/Networking/IPv4Layer.h index 7bafddf3..40e9e412 100644 --- a/kernel/include/kernel/Networking/IPv4Layer.h +++ b/kernel/include/kernel/Networking/IPv4Layer.h @@ -41,7 +41,7 @@ namespace Kernel ARPTable& arp_table() { return *m_arp_table; } - BAN::ErrorOr handle_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan); + BAN::ErrorOr handle_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan, uint32_t validated_cksums); virtual void unbind_socket(uint16_t port) override; virtual BAN::ErrorOr bind_socket_with_target(BAN::RefPtr, const sockaddr* target_address, socklen_t target_address_len) override; diff --git a/kernel/include/kernel/Networking/NetworkInterface.h b/kernel/include/kernel/Networking/NetworkInterface.h index 2c6c12eb..708b1bdb 100644 --- a/kernel/include/kernel/Networking/NetworkInterface.h +++ b/kernel/include/kernel/Networking/NetworkInterface.h @@ -23,6 +23,13 @@ namespace Kernel ARP = 0x0806, }; + enum NetworkChecksum : uint32_t + { + CKSUM_IPV4 = 1 << 0, + CKSUM_TCP = 1 << 1, + CKSUM_UDP = 1 << 2, + }; + class NetworkInterface : public CharacterDevice { BAN_NON_COPYABLE(NetworkInterface); diff --git a/kernel/include/kernel/Networking/NetworkManager.h b/kernel/include/kernel/Networking/NetworkManager.h index 779f8ada..70f1fed1 100644 --- a/kernel/include/kernel/Networking/NetworkManager.h +++ b/kernel/include/kernel/Networking/NetworkManager.h @@ -27,7 +27,7 @@ namespace Kernel BAN::ErrorOr> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t); BAN::ErrorOr connect_sockets(Socket::Domain, BAN::RefPtr, BAN::RefPtr); - void on_receive(NetworkInterface&, BAN::ConstByteSpan); + void on_receive(NetworkInterface&, BAN::ConstByteSpan, uint32_t validated_cksums); private: NetworkManager() {} diff --git a/kernel/include/kernel/Networking/NetworkSocket.h b/kernel/include/kernel/Networking/NetworkSocket.h index 19fd42eb..107e6ce2 100644 --- a/kernel/include/kernel/Networking/NetworkSocket.h +++ b/kernel/include/kernel/Networking/NetworkSocket.h @@ -35,7 +35,7 @@ namespace Kernel virtual void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) = 0; virtual NetworkProtocol protocol() const = 0; - virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0; + virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums) = 0; bool is_bound() const { return m_address_len >= static_cast(sizeof(sa_family_t)) && m_address.ss_family != AF_UNSPEC; } in_port_t bound_port() const diff --git a/kernel/include/kernel/Networking/TCPSocket.h b/kernel/include/kernel/Networking/TCPSocket.h index 46952dc2..36ce26b4 100644 --- a/kernel/include/kernel/Networking/TCPSocket.h +++ b/kernel/include/kernel/Networking/TCPSocket.h @@ -68,7 +68,7 @@ namespace Kernel BAN::ErrorOr ioctl_impl(int, void*) override; - void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override; + void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums) override; bool can_read_impl() const override; bool can_write_impl() const override; diff --git a/kernel/include/kernel/Networking/UDPSocket.h b/kernel/include/kernel/Networking/UDPSocket.h index f2e8360c..3ca63d09 100644 --- a/kernel/include/kernel/Networking/UDPSocket.h +++ b/kernel/include/kernel/Networking/UDPSocket.h @@ -31,7 +31,7 @@ namespace Kernel void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) override; protected: - void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override; + void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums) override; BAN::ErrorOr connect_impl(const sockaddr*, socklen_t) override; BAN::ErrorOr bind_impl(const sockaddr* address, socklen_t address_len) override; diff --git a/kernel/kernel/Networking/E1000/E1000.cpp b/kernel/kernel/Networking/E1000/E1000.cpp index 0179e640..636387ed 100644 --- a/kernel/kernel/Networking/E1000/E1000.cpp +++ b/kernel/kernel/Networking/E1000/E1000.cpp @@ -341,7 +341,7 @@ namespace Kernel NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { reinterpret_cast(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE), descriptor.length - }); + }, 0); m_rx_lock.lock(); diff --git a/kernel/kernel/Networking/IPv4Layer.cpp b/kernel/kernel/Networking/IPv4Layer.cpp index e181aac4..dd5dfb81 100644 --- a/kernel/kernel/Networking/IPv4Layer.cpp +++ b/kernel/kernel/Networking/IPv4Layer.cpp @@ -238,7 +238,7 @@ namespace Kernel return {}; } - BAN::ErrorOr IPv4Layer::handle_ipv4_packet(NetworkInterface& interface, BAN::ConstByteSpan packet) + BAN::ErrorOr IPv4Layer::handle_ipv4_packet(NetworkInterface& interface, BAN::ConstByteSpan packet, uint32_t validated_cksums) { if (packet.size() < sizeof(IPv4Header)) { @@ -247,7 +247,7 @@ namespace Kernel } auto& ipv4_header = packet.as(); - if (calculate_internet_checksum(BAN::ConstByteSpan::from(ipv4_header)) != 0) + if (!(validated_cksums & CKSUM_IPV4) && calculate_internet_checksum(BAN::ConstByteSpan::from(ipv4_header)) != 0) { dwarnln_if(DEBUG_IPV4, "IPv4 packet checksum failed"); return {}; @@ -386,7 +386,7 @@ namespace Kernel sender.sin_family = AF_INET; sender.sin_port = BAN::host_to_network_endian(src_port); sender.sin_addr.s_addr = src_ipv4.raw; - bound_socket->receive_packet(ipv4_data, reinterpret_cast(&sender), sizeof(sender)); + bound_socket->receive_packet(ipv4_data, reinterpret_cast(&sender), sizeof(sender), validated_cksums); return {}; } diff --git a/kernel/kernel/Networking/Loopback.cpp b/kernel/kernel/Networking/Loopback.cpp index c76f8a11..37c1bce0 100644 --- a/kernel/kernel/Networking/Loopback.cpp +++ b/kernel/kernel/Networking/Loopback.cpp @@ -109,10 +109,7 @@ namespace Kernel m_buffer_lock.unlock(InterruptState::Enabled); - NetworkManager::get().on_receive(*this, { - descriptor.addr, - descriptor.size, - }); + NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { descriptor.addr, descriptor.size }, 0); m_buffer_lock.lock(); diff --git a/kernel/kernel/Networking/NetworkManager.cpp b/kernel/kernel/Networking/NetworkManager.cpp index 6cc88b99..1439e98c 100644 --- a/kernel/kernel/Networking/NetworkManager.cpp +++ b/kernel/kernel/Networking/NetworkManager.cpp @@ -148,7 +148,7 @@ namespace Kernel return {}; } - void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet) + void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet, uint32_t validated_cksums) { if (packet.size() < sizeof(EthernetHeader)) return; @@ -163,7 +163,7 @@ namespace Kernel dwarnln("ARP: {}", ret.error()); break; case EtherType::IPv4: - if (auto ret = m_ipv4_layer->handle_ipv4_packet(interface, packet_data); ret.is_error()) + if (auto ret = m_ipv4_layer->handle_ipv4_packet(interface, packet_data, validated_cksums); ret.is_error()) dwarnln("IPv4; {}", ret.error()); break; default: diff --git a/kernel/kernel/Networking/RTL8169/RTL8169.cpp b/kernel/kernel/Networking/RTL8169/RTL8169.cpp index f5dc6908..8c625c8b 100644 --- a/kernel/kernel/Networking/RTL8169/RTL8169.cpp +++ b/kernel/kernel/Networking/RTL8169/RTL8169.cpp @@ -272,10 +272,8 @@ namespace Kernel { m_rx_lock.unlock(InterruptState::Enabled); - NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { - reinterpret_cast(m_rx_buffer_region->vaddr() + m_rx_head * s_buffer_size), - packet_length - }); + const uint8_t* packet_data = reinterpret_cast(m_rx_buffer_region->vaddr() + m_rx_head * s_buffer_size); + NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { packet_data, packet_length }, 0); m_rx_lock.lock(); } diff --git a/kernel/kernel/Networking/TCPSocket.cpp b/kernel/kernel/Networking/TCPSocket.cpp index a537b708..a8519800 100644 --- a/kernel/kernel/Networking/TCPSocket.cpp +++ b/kernel/kernel/Networking/TCPSocket.cpp @@ -572,7 +572,7 @@ namespace Kernel dprintln_if(DEBUG_TCP, " seq {}", (uint32_t)header.seq_number); } - void TCPSocket::receive_packet(BAN::ConstByteSpan buffer, const sockaddr* sender, socklen_t sender_len) + void TCPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums) { if (m_state == State::Listen) { @@ -585,9 +585,10 @@ namespace Kernel }(); if (socket) - return socket->receive_packet(buffer, sender, sender_len); + return socket->receive_packet(packet, sender, sender_len, validated_cksums); } + if (!(validated_cksums & CKSUM_TCP)) { uint16_t checksum = 0; @@ -603,23 +604,23 @@ namespace Kernel .src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr), .dst_ipv4 = interface->get_ipv4_address(), .protocol = NetworkProtocol::TCP, - .length = buffer.size(), + .length = packet.size(), }; const BAN::ConstByteSpan buffers[] { BAN::ConstByteSpan::from(pseudo_header), - buffer + packet }; checksum = calculate_internet_checksum({ buffers, sizeof(buffers) / sizeof(*buffers) }); } else { - dwarnln("No tcp checksum validation for socket family {}", sender->sa_family); + dwarnln("no TCP checksum validation for socket family {}", sender->sa_family); return; } if (checksum != 0) { - dprintln("Checksum does not match"); + dwarnln("checksum does not match"); return; } } @@ -628,7 +629,7 @@ namespace Kernel const bool hungup_before = has_hungup_impl(); - auto& header = buffer.as(); + const auto& header = packet.as(); dprintln_if(DEBUG_TCP, "receiving {} {8b}", (uint8_t)m_state, header.flags); dprintln_if(DEBUG_TCP, " ack {}", (uint32_t)header.ack_number); @@ -768,7 +769,7 @@ namespace Kernel if (header.ack_number > m_send_window.current_ack) m_send_window.current_ack = header.ack_number; - auto payload = buffer.slice(header.data_offset * sizeof(uint32_t)); + auto payload = packet.slice(header.data_offset * sizeof(uint32_t)); if (header.seq_number < expected_seq) { diff --git a/kernel/kernel/Networking/UDPSocket.cpp b/kernel/kernel/Networking/UDPSocket.cpp index 25fb402a..b5275146 100644 --- a/kernel/kernel/Networking/UDPSocket.cpp +++ b/kernel/kernel/Networking/UDPSocket.cpp @@ -57,21 +57,69 @@ namespace Kernel header.checksum = 0xFFFF; } - void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len) + void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len, uint32_t validated_cksums) { - auto payload = packet.slice(sizeof(UDPHeader)); + const auto header = packet.as(); + + if (!(validated_cksums & CKSUM_UDP) && header.checksum) + { + uint16_t checksum = 0; + + if (sender->sa_family == AF_INET) + { + auto interface_or_error = interface(sender, sender_len); + if (interface_or_error.is_error()) + return; + auto interface = interface_or_error.release_value(); + + auto& addr_in = *reinterpret_cast(sender); + const PseudoHeader pseudo_header { + .src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr), + .dst_ipv4 = interface->get_ipv4_address(), + .protocol = NetworkProtocol::UDP, + .length = packet.size(), + }; + const UDPHeader udp_header { + .src_port = header.src_port, + .dst_port = header.dst_port, + .length = header.length, + .checksum = 0, + }; + const BAN::ConstByteSpan buffers[] { + BAN::ConstByteSpan::from(pseudo_header), + BAN::ConstByteSpan::from(udp_header), + packet.slice(sizeof(UDPHeader)) + }; + checksum = calculate_internet_checksum({ buffers, sizeof(buffers) / sizeof(*buffers) }); + } + else + { + dwarnln("no UDP checksum validation for socket family {}", sender->sa_family); + return; + } + + const bool checksum_valid1 = (header.checksum == checksum); + const bool checksum_valid2 = (header.checksum == 0xFFFF && checksum == 0); + if (!checksum_valid1 && !checksum_valid2) + { + dwarnln("checksum does not match {4h}", checksum); + return; + } + } SpinLockGuard _(m_packet_lock); if (m_packets.full()) { - dprintln("Packet buffer full, dropping packet"); + dwarnln("Packet buffer full, dropping packet"); return; } + const auto payload = packet.slice(sizeof(UDPHeader)); + if (m_packet_total_size + payload.size() > m_packet_buffer->size()) { - dprintln("Packet buffer full, dropping packet"); + dwarnln("Packet buffer full, dropping packet"); return; }