diff --git a/Kernel/API/POSIX/netinet/in.h b/Kernel/API/POSIX/netinet/in.h index 9d4d54bf22..272f1ab44e 100644 --- a/Kernel/API/POSIX/netinet/in.h +++ b/Kernel/API/POSIX/netinet/in.h @@ -22,6 +22,7 @@ typedef uint32_t in_addr_t; #define IN_LOOPBACKNET 127 +#define IP_TOS 1 #define IP_TTL 2 #define IP_MULTICAST_LOOP 3 #define IP_ADD_MEMBERSHIP 4 @@ -29,6 +30,10 @@ typedef uint32_t in_addr_t; #define IP_MULTICAST_IF 6 #define IP_MULTICAST_TTL 7 +#define IPTOS_LOWDELAY 16 +#define IPTOS_THROUGHPUT 8 +#define IPTOS_RELIABILITY 4 + /* Make sure these don't overlap with any other IPv4 and IPv6 options */ #define MCAST_JOIN_SOURCE_GROUP 100 #define MCAST_LEAVE_SOURCE_GROUP 101 diff --git a/Kernel/Net/IPv4.h b/Kernel/Net/IPv4.h index 704ef1754f..9eb069d985 100644 --- a/Kernel/Net/IPv4.h +++ b/Kernel/Net/IPv4.h @@ -32,6 +32,9 @@ public: u8 version() const { return (m_version_and_ihl >> 4) & 0xf; } void set_version(u8 version) { m_version_and_ihl = (m_version_and_ihl & 0x0f) | (version << 4); } + u8 dscp_and_ecn() const { return m_dscp_and_ecn; } + void set_dscp_and_ecn(u8 dscp_and_ecn) { m_dscp_and_ecn = dscp_and_ecn; } + u8 internet_header_length() const { return m_version_and_ihl & 0xf; } void set_internet_header_length(u8 ihl) { m_version_and_ihl = (m_version_and_ihl & 0xf0) | (ihl & 0x0f); } diff --git a/Kernel/Net/IPv4Socket.cpp b/Kernel/Net/IPv4Socket.cpp index 7d64a68f32..326c2452e4 100644 --- a/Kernel/Net/IPv4Socket.cpp +++ b/Kernel/Net/IPv4Socket.cpp @@ -229,7 +229,7 @@ KResultOr IPv4Socket::sendto(OpenFileDescription&, const UserOrKernelBuf if (!packet) return set_so_error(ENOMEM); routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop, - m_peer_address, (IPv4Protocol)protocol(), data_length, m_ttl); + m_peer_address, (IPv4Protocol)protocol(), data_length, m_type_of_service, m_ttl); if (auto result = data.read(packet->buffer->data() + ipv4_payload_offset, data_length); result.is_error()) { routing_decision.adapter->release_packet_buffer(*packet); return set_so_error(result); @@ -504,6 +504,16 @@ KResult IPv4Socket::setsockopt(int level, int option, Userspace use m_ttl = value; return KSuccess; } + case IP_TOS: { + if (user_value_size < sizeof(int)) + return EINVAL; + int value; + TRY(copy_from_user(&value, static_ptr_cast(user_value))); + if (value < 0 || value > 255) + return EINVAL; + m_type_of_service = value; + return KSuccess; + } case IP_MULTICAST_LOOP: { if (user_value_size != 1) return EINVAL; @@ -559,6 +569,14 @@ KResult IPv4Socket::getsockopt(OpenFileDescription& description, int level, int size = sizeof(int); return copy_to_user(value_size, &size); } + case IP_TOS: { + if (size < sizeof(int)) + return EINVAL; + int type_of_service = m_type_of_service; + TRY(copy_to_user(static_ptr_cast(value), (int*)&type_of_service)); + size = sizeof(int); + return copy_to_user(value_size, &size); + } case IP_MULTICAST_LOOP: { if (size < 1) return EINVAL; diff --git a/Kernel/Net/IPv4Socket.h b/Kernel/Net/IPv4Socket.h index cbea9aad24..2cd90350e9 100644 --- a/Kernel/Net/IPv4Socket.h +++ b/Kernel/Net/IPv4Socket.h @@ -63,6 +63,7 @@ public: String absolute_path(const OpenFileDescription& description) const override; + u8 type_of_service() const { return m_type_of_service; } u8 ttl() const { return m_ttl; } enum class BufferMode { @@ -123,6 +124,7 @@ private: u32 m_bytes_received { 0 }; + u8 m_type_of_service { IPTOS_LOWDELAY }; u8 m_ttl { 64 }; bool m_can_read { false }; diff --git a/Kernel/Net/NetworkAdapter.cpp b/Kernel/Net/NetworkAdapter.cpp index 3b82ef1598..faac7af431 100644 --- a/Kernel/Net/NetworkAdapter.cpp +++ b/Kernel/Net/NetworkAdapter.cpp @@ -47,7 +47,7 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet send_packet({ (const u8*)eth, size_in_bytes }); } -void NetworkAdapter::fill_in_ipv4_header(PacketWithTimestamp& packet, IPv4Address const& source_ipv4, MACAddress const& destination_mac, IPv4Address const& destination_ipv4, IPv4Protocol protocol, size_t payload_size, u8 ttl) +void NetworkAdapter::fill_in_ipv4_header(PacketWithTimestamp& packet, IPv4Address const& source_ipv4, MACAddress const& destination_mac, IPv4Address const& destination_ipv4, IPv4Protocol protocol, size_t payload_size, u8 type_of_service, u8 ttl) { size_t ipv4_packet_size = sizeof(IPv4Packet) + payload_size; VERIFY(ipv4_packet_size <= mtu()); @@ -62,6 +62,7 @@ void NetworkAdapter::fill_in_ipv4_header(PacketWithTimestamp& packet, IPv4Addres auto& ipv4 = *(IPv4Packet*)eth.payload(); ipv4.set_version(4); ipv4.set_internet_header_length(5); + ipv4.set_dscp_and_ecn(type_of_service); ipv4.set_source(source_ipv4); ipv4.set_destination(destination_ipv4); ipv4.set_protocol((u8)protocol); diff --git a/Kernel/Net/NetworkAdapter.h b/Kernel/Net/NetworkAdapter.h index b793ef2cd8..0c69b6230f 100644 --- a/Kernel/Net/NetworkAdapter.h +++ b/Kernel/Net/NetworkAdapter.h @@ -69,7 +69,7 @@ public: void set_ipv4_gateway(const IPv4Address&); void send(const MACAddress&, const ARPPacket&); - void fill_in_ipv4_header(PacketWithTimestamp&, IPv4Address const&, MACAddress const&, IPv4Address const&, IPv4Protocol, size_t, u8); + void fill_in_ipv4_header(PacketWithTimestamp&, IPv4Address const&, MACAddress const&, IPv4Address const&, IPv4Protocol, size_t, u8 type_of_service, u8 ttl); size_t dequeue_packet(u8* buffer, size_t buffer_size, Time& packet_timestamp); diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp index e49f6f530a..c24f14f1c7 100644 --- a/Kernel/Net/NetworkTask.cpp +++ b/Kernel/Net/NetworkTask.cpp @@ -258,7 +258,7 @@ void handle_icmp(EthernetFrameHeader const& eth, IPv4Packet const& ipv4_packet, dbgln("Could not allocate packet buffer while sending ICMP packet"); return; } - adapter->fill_in_ipv4_header(*packet, adapter->ipv4_address(), eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, icmp_packet_size, 64); + adapter->fill_in_ipv4_header(*packet, adapter->ipv4_address(), eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, icmp_packet_size, 0, 64); memset(packet->buffer->data() + ipv4_payload_offset, 0, sizeof(ICMPEchoPacket)); auto& response = *(ICMPEchoPacket*)(packet->buffer->data() + ipv4_payload_offset); response.header.set_type(ICMPType::EchoReply); @@ -351,7 +351,7 @@ void send_tcp_rst(IPv4Packet const& ipv4_packet, TCPPacket const& tcp_packet, Re return; routing_decision.adapter->fill_in_ipv4_header(*packet, ipv4_packet.destination(), routing_decision.next_hop, ipv4_packet.source(), IPv4Protocol::TCP, - buffer_size - ipv4_payload_offset, 64); + buffer_size - ipv4_payload_offset, 0, 64); auto& rst_packet = *(TCPPacket*)(packet->buffer->data() + ipv4_payload_offset); rst_packet = {}; diff --git a/Kernel/Net/TCPSocket.cpp b/Kernel/Net/TCPSocket.cpp index 555b606045..24f078cdc3 100644 --- a/Kernel/Net/TCPSocket.cpp +++ b/Kernel/Net/TCPSocket.cpp @@ -207,7 +207,7 @@ KResult TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload, return set_so_error(ENOMEM); routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop, peer_address(), IPv4Protocol::TCP, - buffer_size - ipv4_payload_offset, ttl()); + buffer_size - ipv4_payload_offset, type_of_service(), ttl()); memset(packet->buffer->data() + ipv4_payload_offset, 0, sizeof(TCPPacket)); auto& tcp_packet = *(TCPPacket*)(packet->buffer->data() + ipv4_payload_offset); VERIFY(local_port()); @@ -587,7 +587,7 @@ void TCPSocket::retransmit_packets() routing_decision.adapter->fill_in_ipv4_header(*packet.buffer, local_address(), routing_decision.next_hop, peer_address(), - IPv4Protocol::TCP, packet_buffer.size() - ipv4_payload_offset, ttl()); + IPv4Protocol::TCP, packet_buffer.size() - ipv4_payload_offset, type_of_service(), ttl()); routing_decision.adapter->send_packet(packet_buffer); m_packets_out++; m_bytes_out += packet_buffer.size(); diff --git a/Kernel/Net/UDPSocket.cpp b/Kernel/Net/UDPSocket.cpp index 36cdc92bab..51847893c7 100644 --- a/Kernel/Net/UDPSocket.cpp +++ b/Kernel/Net/UDPSocket.cpp @@ -87,7 +87,7 @@ KResultOr UDPSocket::protocol_send(const UserOrKernelBuffer& data, size_ udp_packet.set_length(udp_buffer_size); SOCKET_TRY(data.read(udp_packet.payload(), data_length)); routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop, - peer_address(), IPv4Protocol::UDP, udp_buffer_size, ttl()); + peer_address(), IPv4Protocol::UDP, udp_buffer_size, type_of_service(), ttl()); routing_decision.adapter->send_packet(packet->bytes()); return data_length; }