mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 01:02:45 +00:00 
			
		
		
		
	Kernel+LibC: Add support for the IPv4 TOS field via the IP_TOS sockopt
This commit is contained in:
		
							parent
							
								
									20c7fcfedf
								
							
						
					
					
						commit
						adc9939a7b
					
				
					 9 changed files with 37 additions and 8 deletions
				
			
		|  | @ -22,6 +22,7 @@ typedef uint32_t in_addr_t; | ||||||
| 
 | 
 | ||||||
| #define IN_LOOPBACKNET 127 | #define IN_LOOPBACKNET 127 | ||||||
| 
 | 
 | ||||||
|  | #define IP_TOS 1 | ||||||
| #define IP_TTL 2 | #define IP_TTL 2 | ||||||
| #define IP_MULTICAST_LOOP 3 | #define IP_MULTICAST_LOOP 3 | ||||||
| #define IP_ADD_MEMBERSHIP 4 | #define IP_ADD_MEMBERSHIP 4 | ||||||
|  | @ -29,6 +30,10 @@ typedef uint32_t in_addr_t; | ||||||
| #define IP_MULTICAST_IF 6 | #define IP_MULTICAST_IF 6 | ||||||
| #define IP_MULTICAST_TTL 7 | #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 */ | /* Make sure these don't overlap with any other IPv4 and IPv6 options */ | ||||||
| #define MCAST_JOIN_SOURCE_GROUP 100 | #define MCAST_JOIN_SOURCE_GROUP 100 | ||||||
| #define MCAST_LEAVE_SOURCE_GROUP 101 | #define MCAST_LEAVE_SOURCE_GROUP 101 | ||||||
|  |  | ||||||
|  | @ -32,6 +32,9 @@ public: | ||||||
|     u8 version() const { return (m_version_and_ihl >> 4) & 0xf; } |     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); } |     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; } |     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); } |     void set_internet_header_length(u8 ihl) { m_version_and_ihl = (m_version_and_ihl & 0xf0) | (ihl & 0x0f); } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -229,7 +229,7 @@ KResultOr<size_t> IPv4Socket::sendto(OpenFileDescription&, const UserOrKernelBuf | ||||||
|         if (!packet) |         if (!packet) | ||||||
|             return set_so_error(ENOMEM); |             return set_so_error(ENOMEM); | ||||||
|         routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop, |         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()) { |         if (auto result = data.read(packet->buffer->data() + ipv4_payload_offset, data_length); result.is_error()) { | ||||||
|             routing_decision.adapter->release_packet_buffer(*packet); |             routing_decision.adapter->release_packet_buffer(*packet); | ||||||
|             return set_so_error(result); |             return set_so_error(result); | ||||||
|  | @ -504,6 +504,16 @@ KResult IPv4Socket::setsockopt(int level, int option, Userspace<const void*> use | ||||||
|         m_ttl = value; |         m_ttl = value; | ||||||
|         return KSuccess; |         return KSuccess; | ||||||
|     } |     } | ||||||
|  |     case IP_TOS: { | ||||||
|  |         if (user_value_size < sizeof(int)) | ||||||
|  |             return EINVAL; | ||||||
|  |         int value; | ||||||
|  |         TRY(copy_from_user(&value, static_ptr_cast<const int*>(user_value))); | ||||||
|  |         if (value < 0 || value > 255) | ||||||
|  |             return EINVAL; | ||||||
|  |         m_type_of_service = value; | ||||||
|  |         return KSuccess; | ||||||
|  |     } | ||||||
|     case IP_MULTICAST_LOOP: { |     case IP_MULTICAST_LOOP: { | ||||||
|         if (user_value_size != 1) |         if (user_value_size != 1) | ||||||
|             return EINVAL; |             return EINVAL; | ||||||
|  | @ -559,6 +569,14 @@ KResult IPv4Socket::getsockopt(OpenFileDescription& description, int level, int | ||||||
|         size = sizeof(int); |         size = sizeof(int); | ||||||
|         return copy_to_user(value_size, &size); |         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<int*>(value), (int*)&type_of_service)); | ||||||
|  |         size = sizeof(int); | ||||||
|  |         return copy_to_user(value_size, &size); | ||||||
|  |     } | ||||||
|     case IP_MULTICAST_LOOP: { |     case IP_MULTICAST_LOOP: { | ||||||
|         if (size < 1) |         if (size < 1) | ||||||
|             return EINVAL; |             return EINVAL; | ||||||
|  |  | ||||||
|  | @ -63,6 +63,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     String absolute_path(const OpenFileDescription& description) const override; |     String absolute_path(const OpenFileDescription& description) const override; | ||||||
| 
 | 
 | ||||||
|  |     u8 type_of_service() const { return m_type_of_service; } | ||||||
|     u8 ttl() const { return m_ttl; } |     u8 ttl() const { return m_ttl; } | ||||||
| 
 | 
 | ||||||
|     enum class BufferMode { |     enum class BufferMode { | ||||||
|  | @ -123,6 +124,7 @@ private: | ||||||
| 
 | 
 | ||||||
|     u32 m_bytes_received { 0 }; |     u32 m_bytes_received { 0 }; | ||||||
| 
 | 
 | ||||||
|  |     u8 m_type_of_service { IPTOS_LOWDELAY }; | ||||||
|     u8 m_ttl { 64 }; |     u8 m_ttl { 64 }; | ||||||
| 
 | 
 | ||||||
|     bool m_can_read { false }; |     bool m_can_read { false }; | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet | ||||||
|     send_packet({ (const u8*)eth, size_in_bytes }); |     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; |     size_t ipv4_packet_size = sizeof(IPv4Packet) + payload_size; | ||||||
|     VERIFY(ipv4_packet_size <= mtu()); |     VERIFY(ipv4_packet_size <= mtu()); | ||||||
|  | @ -62,6 +62,7 @@ void NetworkAdapter::fill_in_ipv4_header(PacketWithTimestamp& packet, IPv4Addres | ||||||
|     auto& ipv4 = *(IPv4Packet*)eth.payload(); |     auto& ipv4 = *(IPv4Packet*)eth.payload(); | ||||||
|     ipv4.set_version(4); |     ipv4.set_version(4); | ||||||
|     ipv4.set_internet_header_length(5); |     ipv4.set_internet_header_length(5); | ||||||
|  |     ipv4.set_dscp_and_ecn(type_of_service); | ||||||
|     ipv4.set_source(source_ipv4); |     ipv4.set_source(source_ipv4); | ||||||
|     ipv4.set_destination(destination_ipv4); |     ipv4.set_destination(destination_ipv4); | ||||||
|     ipv4.set_protocol((u8)protocol); |     ipv4.set_protocol((u8)protocol); | ||||||
|  |  | ||||||
|  | @ -69,7 +69,7 @@ public: | ||||||
|     void set_ipv4_gateway(const IPv4Address&); |     void set_ipv4_gateway(const IPv4Address&); | ||||||
| 
 | 
 | ||||||
|     void send(const MACAddress&, const ARPPacket&); |     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); |     size_t dequeue_packet(u8* buffer, size_t buffer_size, Time& packet_timestamp); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -258,7 +258,7 @@ void handle_icmp(EthernetFrameHeader const& eth, IPv4Packet const& ipv4_packet, | ||||||
|             dbgln("Could not allocate packet buffer while sending ICMP packet"); |             dbgln("Could not allocate packet buffer while sending ICMP packet"); | ||||||
|             return; |             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)); |         memset(packet->buffer->data() + ipv4_payload_offset, 0, sizeof(ICMPEchoPacket)); | ||||||
|         auto& response = *(ICMPEchoPacket*)(packet->buffer->data() + ipv4_payload_offset); |         auto& response = *(ICMPEchoPacket*)(packet->buffer->data() + ipv4_payload_offset); | ||||||
|         response.header.set_type(ICMPType::EchoReply); |         response.header.set_type(ICMPType::EchoReply); | ||||||
|  | @ -351,7 +351,7 @@ void send_tcp_rst(IPv4Packet const& ipv4_packet, TCPPacket const& tcp_packet, Re | ||||||
|         return; |         return; | ||||||
|     routing_decision.adapter->fill_in_ipv4_header(*packet, ipv4_packet.destination(), |     routing_decision.adapter->fill_in_ipv4_header(*packet, ipv4_packet.destination(), | ||||||
|         routing_decision.next_hop, ipv4_packet.source(), IPv4Protocol::TCP, |         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); |     auto& rst_packet = *(TCPPacket*)(packet->buffer->data() + ipv4_payload_offset); | ||||||
|     rst_packet = {}; |     rst_packet = {}; | ||||||
|  |  | ||||||
|  | @ -207,7 +207,7 @@ KResult TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload, | ||||||
|         return set_so_error(ENOMEM); |         return set_so_error(ENOMEM); | ||||||
|     routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), |     routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), | ||||||
|         routing_decision.next_hop, peer_address(), IPv4Protocol::TCP, |         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)); |     memset(packet->buffer->data() + ipv4_payload_offset, 0, sizeof(TCPPacket)); | ||||||
|     auto& tcp_packet = *(TCPPacket*)(packet->buffer->data() + ipv4_payload_offset); |     auto& tcp_packet = *(TCPPacket*)(packet->buffer->data() + ipv4_payload_offset); | ||||||
|     VERIFY(local_port()); |     VERIFY(local_port()); | ||||||
|  | @ -587,7 +587,7 @@ void TCPSocket::retransmit_packets() | ||||||
| 
 | 
 | ||||||
|             routing_decision.adapter->fill_in_ipv4_header(*packet.buffer, |             routing_decision.adapter->fill_in_ipv4_header(*packet.buffer, | ||||||
|                 local_address(), routing_decision.next_hop, peer_address(), |                 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); |             routing_decision.adapter->send_packet(packet_buffer); | ||||||
|             m_packets_out++; |             m_packets_out++; | ||||||
|             m_bytes_out += packet_buffer.size(); |             m_bytes_out += packet_buffer.size(); | ||||||
|  |  | ||||||
|  | @ -87,7 +87,7 @@ KResultOr<size_t> UDPSocket::protocol_send(const UserOrKernelBuffer& data, size_ | ||||||
|     udp_packet.set_length(udp_buffer_size); |     udp_packet.set_length(udp_buffer_size); | ||||||
|     SOCKET_TRY(data.read(udp_packet.payload(), data_length)); |     SOCKET_TRY(data.read(udp_packet.payload(), data_length)); | ||||||
|     routing_decision.adapter->fill_in_ipv4_header(*packet, local_address(), routing_decision.next_hop, |     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()); |     routing_decision.adapter->send_packet(packet->bytes()); | ||||||
|     return data_length; |     return data_length; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Idan Horowitz
						Idan Horowitz