diff --git a/Kernel/IPv4Socket.cpp b/Kernel/IPv4Socket.cpp index 60f4d949a8..9e427fd969 100644 --- a/Kernel/IPv4Socket.cpp +++ b/Kernel/IPv4Socket.cpp @@ -93,7 +93,11 @@ KResult IPv4Socket::connect(const sockaddr* address, socklen_t address_size) if (address->sa_family != AF_INET) return KResult(-EINVAL); - ASSERT_NOT_REACHED(); + auto& ia = *(const sockaddr_in*)address; + m_destination_address = IPv4Address((const byte*)&ia.sin_addr.s_addr); + m_destination_port = ntohs(ia.sin_port); + + return KSuccess; } void IPv4Socket::attach_fd(SocketRole) @@ -177,9 +181,11 @@ ssize_t IPv4Socket::sendto(const void* data, size_t data_length, int flags, cons return -EAFNOSUPPORT; } - auto& ia = *(const sockaddr_in*)addr; - m_destination_address = IPv4Address((const byte*)&ia.sin_addr.s_addr); - m_destination_port = ntohs(ia.sin_port); + if (addr) { + auto& ia = *(const sockaddr_in*)addr; + m_destination_address = IPv4Address((const byte*)&ia.sin_addr.s_addr); + m_destination_port = ntohs(ia.sin_port); + } allocate_source_port_if_needed(); diff --git a/Kernel/NetworkTask.cpp b/Kernel/NetworkTask.cpp index c96e17b721..8382fd8ca8 100644 --- a/Kernel/NetworkTask.cpp +++ b/Kernel/NetworkTask.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -10,14 +11,16 @@ #include //#define ETHERNET_DEBUG -//#define IPV4_DEBUG +#define IPV4_DEBUG //#define ICMP_DEBUG #define UDP_DEBUG +#define TCP_DEBUG static void handle_arp(const EthernetFrameHeader&, int frame_size); static void handle_ipv4(const EthernetFrameHeader&, int frame_size); static void handle_icmp(const EthernetFrameHeader&, int frame_size); static void handle_udp(const EthernetFrameHeader&, int frame_size); +static void handle_tcp(const EthernetFrameHeader&, int frame_size); Lockable>& arp_table() { @@ -152,6 +155,8 @@ void handle_ipv4(const EthernetFrameHeader& eth, int frame_size) return handle_icmp(eth, frame_size); case IPv4Protocol::UDP: return handle_udp(eth, frame_size); + case IPv4Protocol::TCP: + return handle_tcp(eth, frame_size); default: kprintf("handle_ipv4: Unhandled protocol %u\n", packet.protocol()); break; @@ -244,3 +249,44 @@ void handle_udp(const EthernetFrameHeader& eth, int frame_size) ASSERT(socket->source_port() == udp_packet.destination_port()); socket->did_receive(ByteBuffer::copy((const byte*)&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())); } + +void handle_tcp(const EthernetFrameHeader& eth, int frame_size) +{ + (void)frame_size; + auto& ipv4_packet = *static_cast(eth.payload()); + + auto* adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination()); + if (!adapter) { + kprintf("handle_tcp: this packet is not for me, it's for %s\n", ipv4_packet.destination().to_string().characters()); + return; + } + + auto& tcp_packet = *static_cast(ipv4_packet.payload()); +#ifdef TCP_DEBUG + kprintf("handle_tcp: source=%s:%u, destination=%s:%u seq=%u, ack=%u, flags=%w, window_size=%u\n", + ipv4_packet.source().to_string().characters(), + tcp_packet.source_port(), + ipv4_packet.destination().to_string().characters(), + tcp_packet.destination_port(), + tcp_packet.sequence_number(), + tcp_packet.ack_number(), + tcp_packet.flags(), + tcp_packet.window_size() + ); +#endif + + RetainPtr socket; + { + LOCKER(IPv4Socket::sockets_by_tcp_port().lock()); + auto it = IPv4Socket::sockets_by_tcp_port().resource().find(tcp_packet.destination_port()); + if (it == IPv4Socket::sockets_by_tcp_port().resource().end()) + return; + ASSERT((*it).value); + socket = *(*it).value; + } + + LOCKER(socket->lock()); + ASSERT(socket->type() == SOCK_STREAM); + ASSERT(socket->source_port() == tcp_packet.destination_port()); + socket->did_receive(ByteBuffer::copy((const byte*)&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())); +} diff --git a/Kernel/TCP.h b/Kernel/TCP.h new file mode 100644 index 0000000000..7bc0a6dd26 --- /dev/null +++ b/Kernel/TCP.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +class [[gnu::packed]] TCPPacket { +public: + TCPPacket() { } + ~TCPPacket() { } + + word source_port() const { return m_source_port; } + void set_source_port(word port) { m_source_port = port; } + + word destination_port() const { return m_destination_port; } + void set_destination_port(word port) { m_destination_port = port; } + + dword sequence_number() const { return m_sequence_number; } + void set_sequence_number(dword number) { m_sequence_number = number; } + + dword ack_number() const { return m_ack_number; } + void set_ack_number(dword number) { m_ack_number = number; } + + word flags() const { return m_flags; } + void set_flags(word flags) { m_flags = flags; } + + word window_size() const { return m_window_size; } + void set_window_size(word window_size) { m_window_size = window_size; } + + word checksum() const { return m_checksum; } + void set_checksum(word checksum) { m_checksum = checksum; } + + word urgent() const { return m_urgent; } + void set_urgent(word urgent) { m_urgent = urgent; } + + const void* payload() const { return this + 1; } + void* payload() { return this + 1; } + +private: + NetworkOrdered m_source_port; + NetworkOrdered m_destination_port; + NetworkOrdered m_sequence_number; + NetworkOrdered m_ack_number; + + NetworkOrdered m_flags; + NetworkOrdered m_window_size; + NetworkOrdered m_checksum; + NetworkOrdered m_urgent; +}; + +static_assert(sizeof(UDPPacket) == 8); diff --git a/Kernel/run b/Kernel/run index a3b56265be..5d562bdcc0 100755 --- a/Kernel/run +++ b/Kernel/run @@ -11,6 +11,11 @@ elif [ "$1" = "qtap" ]; then sudo qemu-system-i386 -s -m 32 -object filter-dump,id=hue,netdev=br0,file=e1000.pcap -netdev tap,ifname=tap0,id=br0 -device e1000,netdev=br0 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents else # ./run: qemu with user networking - qemu-system-i386 -s -m 32 -object filter-dump,id=hue,netdev=breh,file=e1000.pcap -netdev user,id=breh -device e1000,netdev=breh -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents + qemu-system-i386 -s -m 32 \ + -object filter-dump,id=hue,netdev=breh,file=e1000.pcap \ + -netdev user,id=breh,hostfwd=tcp:127.0.0.1:8888-192.168.5.2:8888 \ + -device e1000,netdev=breh \ + -drive format=raw,file=.floppy-image,if=floppy \ + -drive format=raw,file=_fs_contents fi