From 649c81a714e120a300439ca5d3fdd5e7f6f6b34d Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 2 Apr 2019 19:54:38 +0200 Subject: Kernel: Move networking related files into Kernel/Net/. --- Kernel/ARP.h | 61 ------- Kernel/E1000NetworkAdapter.cpp | 354 ------------------------------------- Kernel/E1000NetworkAdapter.h | 74 -------- Kernel/EtherType.h | 10 -- Kernel/EthernetFrameHeader.h | 31 ---- Kernel/ICMP.h | 45 ----- Kernel/IPv4.h | 135 -------------- Kernel/IPv4Socket.cpp | 236 ------------------------- Kernel/IPv4Socket.h | 98 ---------- Kernel/MACAddress.h | 47 ----- Kernel/Makefile | 12 +- Kernel/Net/ARP.h | 61 +++++++ Kernel/Net/E1000NetworkAdapter.cpp | 354 +++++++++++++++++++++++++++++++++++++ Kernel/Net/E1000NetworkAdapter.h | 74 ++++++++ Kernel/Net/EtherType.h | 10 ++ Kernel/Net/EthernetFrameHeader.h | 31 ++++ Kernel/Net/ICMP.h | 45 +++++ Kernel/Net/IPv4.h | 135 ++++++++++++++ Kernel/Net/IPv4Socket.cpp | 236 +++++++++++++++++++++++++ Kernel/Net/IPv4Socket.h | 98 ++++++++++ Kernel/Net/LoopbackAdapter.h | 2 +- Kernel/Net/MACAddress.h | 47 +++++ Kernel/Net/NetworkAdapter.cpp | 96 ++++++++++ Kernel/Net/NetworkAdapter.h | 54 ++++++ Kernel/Net/NetworkTask.cpp | 340 +++++++++++++++++++++++++++++++++++ Kernel/Net/NetworkTask.h | 3 + Kernel/Net/Routing.h | 2 +- Kernel/Net/TCP.h | 69 ++++++++ Kernel/Net/TCPSocket.cpp | 203 +++++++++++++++++++++ Kernel/Net/TCPSocket.h | 68 +++++++ Kernel/Net/UDP.h | 32 ++++ Kernel/Net/UDPSocket.cpp | 111 ++++++++++++ Kernel/Net/UDPSocket.h | 47 +++++ Kernel/NetworkAdapter.cpp | 96 ---------- Kernel/NetworkAdapter.h | 54 ------ Kernel/NetworkTask.cpp | 339 ----------------------------------- Kernel/NetworkTask.h | 3 - Kernel/Process.cpp | 3 - Kernel/Socket.cpp | 2 +- Kernel/TCP.h | 69 -------- Kernel/TCPSocket.cpp | 203 --------------------- Kernel/TCPSocket.h | 68 ------- Kernel/UDP.h | 32 ---- Kernel/UDPSocket.cpp | 111 ------------ Kernel/UDPSocket.h | 47 ----- Kernel/init.cpp | 4 +- 46 files changed, 2125 insertions(+), 2127 deletions(-) delete mode 100644 Kernel/ARP.h delete mode 100644 Kernel/E1000NetworkAdapter.cpp delete mode 100644 Kernel/E1000NetworkAdapter.h delete mode 100644 Kernel/EtherType.h delete mode 100644 Kernel/EthernetFrameHeader.h delete mode 100644 Kernel/ICMP.h delete mode 100644 Kernel/IPv4.h delete mode 100644 Kernel/IPv4Socket.cpp delete mode 100644 Kernel/IPv4Socket.h delete mode 100644 Kernel/MACAddress.h create mode 100644 Kernel/Net/ARP.h create mode 100644 Kernel/Net/E1000NetworkAdapter.cpp create mode 100644 Kernel/Net/E1000NetworkAdapter.h create mode 100644 Kernel/Net/EtherType.h create mode 100644 Kernel/Net/EthernetFrameHeader.h create mode 100644 Kernel/Net/ICMP.h create mode 100644 Kernel/Net/IPv4.h create mode 100644 Kernel/Net/IPv4Socket.cpp create mode 100644 Kernel/Net/IPv4Socket.h create mode 100644 Kernel/Net/MACAddress.h create mode 100644 Kernel/Net/NetworkAdapter.cpp create mode 100644 Kernel/Net/NetworkAdapter.h create mode 100644 Kernel/Net/NetworkTask.cpp create mode 100644 Kernel/Net/NetworkTask.h create mode 100644 Kernel/Net/TCP.h create mode 100644 Kernel/Net/TCPSocket.cpp create mode 100644 Kernel/Net/TCPSocket.h create mode 100644 Kernel/Net/UDP.h create mode 100644 Kernel/Net/UDPSocket.cpp create mode 100644 Kernel/Net/UDPSocket.h delete mode 100644 Kernel/NetworkAdapter.cpp delete mode 100644 Kernel/NetworkAdapter.h delete mode 100644 Kernel/NetworkTask.cpp delete mode 100644 Kernel/NetworkTask.h delete mode 100644 Kernel/TCP.h delete mode 100644 Kernel/TCPSocket.cpp delete mode 100644 Kernel/TCPSocket.h delete mode 100644 Kernel/UDP.h delete mode 100644 Kernel/UDPSocket.cpp delete mode 100644 Kernel/UDPSocket.h (limited to 'Kernel') diff --git a/Kernel/ARP.h b/Kernel/ARP.h deleted file mode 100644 index 934995d440..0000000000 --- a/Kernel/ARP.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include -#include -#include - -struct ARPOperation { -enum : word { - Request = 1, - Response = 2, -}; -}; - -struct ARPHardwareType { -enum : word { - Ethernet = 1, -}; -}; - -class [[gnu::packed]] ARPPacket { -public: - word hardware_type() const { return ntohs(m_hardware_type); } - void set_hardware_type(word w) { m_hardware_type = htons(w); } - - word protocol_type() const { return ntohs(m_protocol_type); } - void set_protocol_type(word w) { m_protocol_type = htons(w); } - - byte hardware_address_length() const { return m_hardware_address_length; } - void set_hardware_address_length(byte b) { m_hardware_address_length = b; } - - byte protocol_address_length() const { return m_protocol_address_length; } - void set_protocol_address_length(byte b) { m_protocol_address_length = b; } - - word operation() const { return ntohs(m_operation); } - void set_operation(word w) { m_operation = htons(w); } - - const MACAddress& sender_hardware_address() const { return m_sender_hardware_address; } - void set_sender_hardware_address(const MACAddress& address) { m_sender_hardware_address = address; } - - const IPv4Address& sender_protocol_address() const { return m_sender_protocol_address; } - void set_sender_protocol_address(const IPv4Address& address) { m_sender_protocol_address = address; } - - const MACAddress& target_hardware_address() const { return m_target_hardware_address; } - void set_target_hardware_address(const MACAddress& address) { m_target_hardware_address = address; } - - const IPv4Address& target_protocol_address() const { return m_target_protocol_address; } - void set_target_protocol_address(const IPv4Address& address) { m_target_protocol_address = address; } - -private: - word m_hardware_type { 0x0100 }; - word m_protocol_type { 0x0008 }; - byte m_hardware_address_length { sizeof(MACAddress) }; - byte m_protocol_address_length { sizeof(IPv4Address) }; - word m_operation { 0 }; - MACAddress m_sender_hardware_address; - IPv4Address m_sender_protocol_address; - MACAddress m_target_hardware_address; - IPv4Address m_target_protocol_address; -}; - -static_assert(sizeof(ARPPacket) == 28); diff --git a/Kernel/E1000NetworkAdapter.cpp b/Kernel/E1000NetworkAdapter.cpp deleted file mode 100644 index 05e1c79253..0000000000 --- a/Kernel/E1000NetworkAdapter.cpp +++ /dev/null @@ -1,354 +0,0 @@ -#include -#include -#include - -#define REG_CTRL 0x0000 -#define REG_STATUS 0x0008 -#define REG_EEPROM 0x0014 -#define REG_CTRL_EXT 0x0018 -#define REG_IMASK 0x00D0 -#define REG_RCTRL 0x0100 -#define REG_RXDESCLO 0x2800 -#define REG_RXDESCHI 0x2804 -#define REG_RXDESCLEN 0x2808 -#define REG_RXDESCHEAD 0x2810 -#define REG_RXDESCTAIL 0x2818 -#define REG_TCTRL 0x0400 -#define REG_TXDESCLO 0x3800 -#define REG_TXDESCHI 0x3804 -#define REG_TXDESCLEN 0x3808 -#define REG_TXDESCHEAD 0x3810 -#define REG_TXDESCTAIL 0x3818 -#define REG_RDTR 0x2820 // RX Delay Timer Register -#define REG_RXDCTL 0x3828 // RX Descriptor Control -#define REG_RADV 0x282C // RX Int. Absolute Delay Timer -#define REG_RSRPD 0x2C00 // RX Small Packet Detect Interrupt -#define REG_TIPG 0x0410 // Transmit Inter Packet Gap -#define ECTRL_SLU 0x40 //set link up -#define RCTL_EN (1 << 1) // Receiver Enable -#define RCTL_SBP (1 << 2) // Store Bad Packets -#define RCTL_UPE (1 << 3) // Unicast Promiscuous Enabled -#define RCTL_MPE (1 << 4) // Multicast Promiscuous Enabled -#define RCTL_LPE (1 << 5) // Long Packet Reception Enable -#define RCTL_LBM_NONE (0 << 6) // No Loopback -#define RCTL_LBM_PHY (3 << 6) // PHY or external SerDesc loopback -#define RTCL_RDMTS_HALF (0 << 8) // Free Buffer Threshold is 1/2 of RDLEN -#define RTCL_RDMTS_QUARTER (1 << 8) // Free Buffer Threshold is 1/4 of RDLEN -#define RTCL_RDMTS_EIGHTH (2 << 8) // Free Buffer Threshold is 1/8 of RDLEN -#define RCTL_MO_36 (0 << 12) // Multicast Offset - bits 47:36 -#define RCTL_MO_35 (1 << 12) // Multicast Offset - bits 46:35 -#define RCTL_MO_34 (2 << 12) // Multicast Offset - bits 45:34 -#define RCTL_MO_32 (3 << 12) // Multicast Offset - bits 43:32 -#define RCTL_BAM (1 << 15) // Broadcast Accept Mode -#define RCTL_VFE (1 << 18) // VLAN Filter Enable -#define RCTL_CFIEN (1 << 19) // Canonical Form Indicator Enable -#define RCTL_CFI (1 << 20) // Canonical Form Indicator Bit Value -#define RCTL_DPF (1 << 22) // Discard Pause Frames -#define RCTL_PMCF (1 << 23) // Pass MAC Control Frames -#define RCTL_SECRC (1 << 26) // Strip Ethernet CRC - -// Buffer Sizes -#define RCTL_BSIZE_256 (3 << 16) -#define RCTL_BSIZE_512 (2 << 16) -#define RCTL_BSIZE_1024 (1 << 16) -#define RCTL_BSIZE_2048 (0 << 16) -#define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25)) -#define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25)) -#define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25)) - -// Transmit Command - -#define CMD_EOP (1 << 0) // End of Packet -#define CMD_IFCS (1 << 1) // Insert FCS -#define CMD_IC (1 << 2) // Insert Checksum -#define CMD_RS (1 << 3) // Report Status -#define CMD_RPS (1 << 4) // Report Packet Sent -#define CMD_VLE (1 << 6) // VLAN Packet Enable -#define CMD_IDE (1 << 7) // Interrupt Delay Enable - -// TCTL Register - -#define TCTL_EN (1 << 1) // Transmit Enable -#define TCTL_PSP (1 << 3) // Pad Short Packets -#define TCTL_CT_SHIFT 4 // Collision Threshold -#define TCTL_COLD_SHIFT 12 // Collision Distance -#define TCTL_SWXOFF (1 << 22) // Software XOFF Transmission -#define TCTL_RTLC (1 << 24) // Re-transmit on Late Collision - -#define TSTA_DD (1 << 0) // Descriptor Done -#define TSTA_EC (1 << 1) // Excess Collisions -#define TSTA_LC (1 << 2) // Late Collision -#define LSTA_TU (1 << 3) // Transmit Underrun - -OwnPtr E1000NetworkAdapter::autodetect() -{ - static const PCI::ID qemu_bochs_vbox_id = { 0x8086, 0x100e }; - PCI::Address found_address; - PCI::enumerate_all([&] (const PCI::Address& address, PCI::ID id) { - if (id == qemu_bochs_vbox_id) { - found_address = address; - return; - } - }); - if (found_address.is_null()) - return nullptr; - byte irq = PCI::get_interrupt_line(found_address); - return make(found_address, irq); -} - -static E1000NetworkAdapter* s_the; -E1000NetworkAdapter* E1000NetworkAdapter::the() -{ - return s_the; -} - -E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address pci_address, byte irq) - : IRQHandler(irq) - , m_pci_address(pci_address) -{ - s_the = this; - kprintf("E1000: Found at PCI address %b:%b:%b\n", pci_address.bus(), pci_address.slot(), pci_address.function()); - - enable_bus_mastering(m_pci_address); - - m_mmio_base = PhysicalAddress(PCI::get_BAR0(m_pci_address)); - MM.map_for_kernel(LinearAddress(m_mmio_base.get()), m_mmio_base); - MM.map_for_kernel(LinearAddress(m_mmio_base.offset(4096).get()), m_mmio_base.offset(4096)); - MM.map_for_kernel(LinearAddress(m_mmio_base.offset(8192).get()), m_mmio_base.offset(8192)); - MM.map_for_kernel(LinearAddress(m_mmio_base.offset(12288).get()), m_mmio_base.offset(12288)); - MM.map_for_kernel(LinearAddress(m_mmio_base.offset(16384).get()), m_mmio_base.offset(16384)); - m_use_mmio = true; - m_io_base = PCI::get_BAR1(m_pci_address) & ~1; - m_interrupt_line = PCI::get_interrupt_line(m_pci_address); - kprintf("E1000: IO port base: %w\n", m_io_base); - kprintf("E1000: MMIO base: P%x\n", m_mmio_base); - kprintf("E1000: Interrupt line: %u\n", m_interrupt_line); - detect_eeprom(); - kprintf("E1000: Has EEPROM? %u\n", m_has_eeprom); - read_mac_address(); - const auto& mac = mac_address(); - kprintf("E1000: MAC address: %b:%b:%b:%b:%b:%b\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - - dword flags = in32(REG_CTRL); - out32(REG_CTRL, flags | ECTRL_SLU); - - initialize_rx_descriptors(); - initialize_tx_descriptors(); - - out32(REG_IMASK, 0x1f6dc); - out32(REG_IMASK, 0xff & ~4); - in32(0xc0); - - enable_irq(); -} - -E1000NetworkAdapter::~E1000NetworkAdapter() -{ -} - -void E1000NetworkAdapter::handle_irq() -{ - out32(REG_IMASK, 0x1); - - dword status = in32(0xc0); - if (status & 4) { - dword flags = in32(REG_CTRL); - out32(REG_CTRL, flags | ECTRL_SLU); - } - if (status & 0x10) { - // Threshold OK? - } - if (status & 0x80) { - receive(); - } -} - -void E1000NetworkAdapter::detect_eeprom() -{ - out32(REG_EEPROM, 0x1); - for (volatile int i = 0; i < 999; ++i) { - dword data = in32(REG_EEPROM); - if (data & 0x10) { - m_has_eeprom = true; - return; - } - } - m_has_eeprom = false; -} - -dword E1000NetworkAdapter::read_eeprom(byte address) -{ - word data = 0; - dword tmp = 0; - if (m_has_eeprom) { - out32(REG_EEPROM, ((dword)address << 8) | 1); - while (!((tmp = in32(REG_EEPROM)) & (1 << 4))) - ; - } else { - out32(REG_EEPROM, ((dword)address << 2) | 1); - while (!((tmp = in32(REG_EEPROM)) & (1 << 1))) - ; - } - data = (tmp >> 16) & 0xffff; - return data; -} - -void E1000NetworkAdapter::read_mac_address() -{ - if (m_has_eeprom) { - byte mac[6]; - dword tmp = read_eeprom(0); - mac[0] = tmp & 0xff; - mac[1] = tmp >> 8; - tmp = read_eeprom(1); - mac[2] = tmp & 0xff; - mac[3] = tmp >> 8; - tmp = read_eeprom(2); - mac[4] = tmp & 0xff; - mac[5] = tmp >> 8; - set_mac_address(mac); - } else { - ASSERT_NOT_REACHED(); - } -} - -void E1000NetworkAdapter::initialize_rx_descriptors() -{ - auto ptr = (dword)kmalloc_eternal(sizeof(e1000_rx_desc) * number_of_rx_descriptors + 16); - // Make sure it's 16-byte aligned. - if (ptr % 16) - ptr = (ptr + 16) - (ptr % 16); - m_rx_descriptors = (e1000_rx_desc*)ptr; - for (int i = 0; i < number_of_rx_descriptors; ++i) { - auto& descriptor = m_rx_descriptors[i]; - descriptor.addr = (qword)kmalloc_eternal(8192 + 16); - descriptor.status = 0; - } - - out32(REG_RXDESCLO, ptr); - out32(REG_RXDESCHI, 0); - out32(REG_RXDESCLEN, number_of_rx_descriptors * sizeof(e1000_rx_desc)); - out32(REG_RXDESCHEAD, 0); - out32(REG_RXDESCTAIL, number_of_rx_descriptors - 1); - - out32(REG_RCTRL, RCTL_EN| RCTL_SBP| RCTL_UPE | RCTL_MPE | RCTL_LBM_NONE | RTCL_RDMTS_HALF | RCTL_BAM | RCTL_SECRC | RCTL_BSIZE_8192); -} - -void E1000NetworkAdapter::initialize_tx_descriptors() -{ - auto ptr = (dword)kmalloc_eternal(sizeof(e1000_tx_desc) * number_of_tx_descriptors + 16); - // Make sure it's 16-byte aligned. - if (ptr % 16) - ptr = (ptr + 16) - (ptr % 16); - m_tx_descriptors = (e1000_tx_desc*)ptr; - for (int i = 0; i < number_of_tx_descriptors; ++i) { - auto& descriptor = m_tx_descriptors[i]; - descriptor.addr = (qword)kmalloc_eternal(8192 + 16); - descriptor.cmd = 0; - } - - out32(REG_TXDESCLO, ptr); - out32(REG_TXDESCHI, 0); - out32(REG_TXDESCLEN, number_of_tx_descriptors * sizeof(e1000_tx_desc)); - out32(REG_TXDESCHEAD, 0); - out32(REG_TXDESCTAIL, 0); - - out32(REG_TCTRL, in32(REG_TCTRL) | TCTL_EN | TCTL_PSP); - out32(REG_TIPG, 0x0060200A); -} - -void E1000NetworkAdapter::out8(word address, byte data) -{ - if (m_use_mmio) { - auto* ptr = (volatile byte*)(m_mmio_base.get() + address); - *ptr = data; - return; - } - IO::out8(m_io_base + address, data); -} - -void E1000NetworkAdapter::out16(word address, word data) -{ - if (m_use_mmio) { - auto* ptr = (volatile word*)(m_mmio_base.get() + address); - *ptr = data; - return; - } - IO::out16(m_io_base + address, data); -} - -void E1000NetworkAdapter::out32(word address, dword data) -{ - if (m_use_mmio) { - auto* ptr = (volatile dword*)(m_mmio_base.get() + address); - *ptr = data; - return; - } - IO::out32(m_io_base + address, data); -} - -byte E1000NetworkAdapter::in8(word address) -{ - if (m_use_mmio) - return *(volatile byte*)(m_mmio_base.get() + address); - return IO::in8(m_io_base + address); -} - -word E1000NetworkAdapter::in16(word address) -{ - if (m_use_mmio) - return *(volatile word*)(m_mmio_base.get() + address); - return IO::in16(m_io_base + address); -} - -dword E1000NetworkAdapter::in32(word address) -{ - if (m_use_mmio) - return *(volatile dword*)(m_mmio_base.get() + address); - return IO::in32(m_io_base + address); -} - -void E1000NetworkAdapter::send_raw(const byte* data, int length) -{ - dword tx_current = in32(REG_TXDESCTAIL); -#ifdef E1000_DEBUG - kprintf("E1000: Sending packet (%d bytes)\n", length); -#endif - auto& descriptor = m_tx_descriptors[tx_current]; - ASSERT(length <= 8192); - memcpy((void*)descriptor.addr, data, length); - descriptor.length = length; - descriptor.status = 0; - descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS; -#ifdef E1000_DEBUG - kprintf("E1000: Using tx descriptor %d (head is at %d)\n", tx_current, in32(REG_TXDESCHEAD)); -#endif - tx_current = (tx_current + 1) % number_of_tx_descriptors; - out32(REG_TXDESCTAIL, tx_current); - while (!descriptor.status) - ; -#ifdef E1000_DEBUG - kprintf("E1000: Sent packet, status is now %b!\n", descriptor.status); -#endif -} - -void E1000NetworkAdapter::receive() -{ - dword rx_current; - for (;;) { - rx_current = in32(REG_RXDESCTAIL); - if (rx_current == in32(REG_RXDESCHEAD)) - return; - rx_current = (rx_current + 1) % number_of_rx_descriptors; - if (!(m_rx_descriptors[rx_current].status & 1)) - break; - auto* buffer = (byte*)m_rx_descriptors[rx_current].addr; - word length = m_rx_descriptors[rx_current].length; -#ifdef E1000_DEBUG - kprintf("E1000: Received 1 packet @ %p (%u) bytes!\n", buffer, length); -#endif - did_receive(buffer, length); - m_rx_descriptors[rx_current].status = 0; - out32(REG_RXDESCTAIL, rx_current); - } -} diff --git a/Kernel/E1000NetworkAdapter.h b/Kernel/E1000NetworkAdapter.h deleted file mode 100644 index 0bd47cda8b..0000000000 --- a/Kernel/E1000NetworkAdapter.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -class E1000NetworkAdapter final : public NetworkAdapter, public IRQHandler { -public: - static E1000NetworkAdapter* the(); - - static OwnPtr autodetect(); - - E1000NetworkAdapter(PCI::Address, byte irq); - virtual ~E1000NetworkAdapter() override; - - virtual void send_raw(const byte*, int) override; - -private: - virtual void handle_irq() override; - virtual const char* class_name() const override { return "E1000NetworkAdapter"; } - - struct [[gnu::packed]] e1000_rx_desc { - volatile uint64_t addr { 0 }; - volatile uint16_t length { 0 }; - volatile uint16_t checksum { 0 }; - volatile uint8_t status { 0 }; - volatile uint8_t errors { 0 }; - volatile uint16_t special { 0 }; - }; - - struct [[gnu::packed]] e1000_tx_desc { - volatile uint64_t addr { 0 }; - volatile uint16_t length { 0 }; - volatile uint8_t cso { 0 }; - volatile uint8_t cmd { 0 }; - volatile uint8_t status { 0 }; - volatile uint8_t css { 0 }; - volatile uint16_t special { 0 }; - }; - - void detect_eeprom(); - dword read_eeprom(byte address); - void read_mac_address(); - - void write_command(word address, dword); - dword read_command(word address); - - void initialize_rx_descriptors(); - void initialize_tx_descriptors(); - - void out8(word address, byte); - void out16(word address, word); - void out32(word address, dword); - byte in8(word address); - word in16(word address); - dword in32(word address); - - void receive(); - - PCI::Address m_pci_address; - word m_io_base { 0 }; - PhysicalAddress m_mmio_base; - byte m_interrupt_line { 0 }; - bool m_has_eeprom { false }; - bool m_use_mmio { false }; - - static const int number_of_rx_descriptors = 32; - static const int number_of_tx_descriptors = 8; - - e1000_rx_desc* m_rx_descriptors; - e1000_tx_desc* m_tx_descriptors; -}; diff --git a/Kernel/EtherType.h b/Kernel/EtherType.h deleted file mode 100644 index 027967ff77..0000000000 --- a/Kernel/EtherType.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -struct EtherType { -enum : word { - ARP = 0x0806, - IPv4 = 0x0800, -}; -}; diff --git a/Kernel/EthernetFrameHeader.h b/Kernel/EthernetFrameHeader.h deleted file mode 100644 index af9713d30b..0000000000 --- a/Kernel/EthernetFrameHeader.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include - -class [[gnu::packed]] EthernetFrameHeader { -public: - EthernetFrameHeader() { } - ~EthernetFrameHeader() { } - - MACAddress destination() const { return m_destination; } - void set_destination(const MACAddress& address) { m_destination = address; } - - MACAddress source() const { return m_source; } - void set_source(const MACAddress& address) { m_source = address; } - - word ether_type() const { return m_ether_type; } - void set_ether_type(word ether_type) { m_ether_type = ether_type; } - - const void* payload() const { return &m_payload[0]; } - void* payload() { return &m_payload[0]; } - -private: - MACAddress m_destination; - MACAddress m_source; - NetworkOrdered m_ether_type; - dword m_payload[0]; -}; - -static_assert(sizeof(EthernetFrameHeader) == 14); - diff --git a/Kernel/ICMP.h b/Kernel/ICMP.h deleted file mode 100644 index c8dc818195..0000000000 --- a/Kernel/ICMP.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include -#include - -struct ICMPType { -enum { - EchoReply = 0, - EchoRequest = 8, -}; -}; - -class [[gnu::packed]] ICMPHeader { -public: - ICMPHeader() { } - ~ICMPHeader() { } - - byte type() const { return m_type; } - void set_type(byte b) { m_type = b; } - - byte code() const { return m_code; } - void set_code(byte b) { m_code = b; } - - word checksum() const { return m_checksum; } - void set_checksum(word w) { m_checksum = w; } - - const void* payload() const { return this + 1; } - void* payload() { return this + 1; } - -private: - byte m_type { 0 }; - byte m_code { 0 }; - NetworkOrdered m_checksum { 0 }; - // NOTE: The rest of the header is 4 bytes -}; - -static_assert(sizeof(ICMPHeader) == 4); - -struct [[gnu::packed]] ICMPEchoPacket { - ICMPHeader header; - NetworkOrdered identifier; - NetworkOrdered sequence_number; - void* payload() { return this + 1; } - const void* payload() const { return this + 1; } -}; diff --git a/Kernel/IPv4.h b/Kernel/IPv4.h deleted file mode 100644 index dc4e4dff3c..0000000000 --- a/Kernel/IPv4.h +++ /dev/null @@ -1,135 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -enum class IPv4Protocol : word { - ICMP = 1, - TCP = 6, - UDP = 17, -}; - -NetworkOrdered internet_checksum(const void*, size_t); - -class [[gnu::packed]] IPv4Address { -public: - IPv4Address() { } - IPv4Address(const byte data[4]) - { - m_data[0] = data[0]; - m_data[1] = data[1]; - m_data[2] = data[2]; - m_data[3] = data[3]; - } - IPv4Address(byte a, byte b, byte c, byte d) - { - m_data[0] = a; - m_data[1] = b; - m_data[2] = c; - m_data[3] = d; - } - - byte operator[](int i) const - { - ASSERT(i >= 0 && i < 4); - return m_data[i]; - } - - String to_string() const - { - return String::format("%u.%u.%u.%u", m_data[0], m_data[1], m_data[2], m_data[3]); - } - - bool operator==(const IPv4Address& other) const { return m_data_as_dword == other.m_data_as_dword; } - bool operator!=(const IPv4Address& other) const { return m_data_as_dword != other.m_data_as_dword; } - -private: - union { - byte m_data[4]; - dword m_data_as_dword; - }; -}; - -static_assert(sizeof(IPv4Address) == 4); - -namespace AK { - -template<> -struct Traits { - static unsigned hash(const IPv4Address& address) { return string_hash((const char*)&address, sizeof(address)); } - static void dump(const IPv4Address& address) { kprintf("%s", address.to_string().characters()); } -}; - -} - -class [[gnu::packed]] IPv4Packet { -public: - byte version() const { return (m_version_and_ihl >> 4) & 0xf; } - void set_version(byte version) { m_version_and_ihl = (m_version_and_ihl & 0x0f) | (version << 4); } - - byte internet_header_length() const { return m_version_and_ihl & 0xf; } - void set_internet_header_length(byte ihl) { m_version_and_ihl = (m_version_and_ihl & 0xf0) | (ihl & 0x0f); } - - word length() const { return m_length; } - void set_length(word length) { m_length = length; } - - word ident() const { return m_ident; } - void set_ident(word ident) { m_ident = ident; } - - byte ttl() const { return m_ttl; } - void set_ttl(byte ttl) { m_ttl = ttl; } - - byte protocol() const { return m_protocol; } - void set_protocol(byte protocol) { m_protocol = protocol; } - - word checksum() const { return m_checksum; } - void set_checksum(word checksum) { m_checksum = checksum; } - - const IPv4Address& source() const { return m_source; } - void set_source(const IPv4Address& address) { m_source = address; } - - const IPv4Address& destination() const { return m_destination; } - void set_destination(const IPv4Address& address) { m_destination = address; } - - void* payload() { return this + 1; } - const void* payload() const { return this + 1; } - - word payload_size() const { return m_length - sizeof(IPv4Packet); } - - NetworkOrdered compute_checksum() const - { - ASSERT(!m_checksum); - return internet_checksum(this, sizeof(IPv4Packet)); - } - -private: - byte m_version_and_ihl { 0 }; - byte m_dscp_and_ecn { 0 }; - NetworkOrdered m_length; - NetworkOrdered m_ident; - NetworkOrdered m_flags_and_fragment; - byte m_ttl { 0 }; - NetworkOrdered m_protocol; - NetworkOrdered m_checksum; - IPv4Address m_source; - IPv4Address m_destination; -}; - -static_assert(sizeof(IPv4Packet) == 20); - -inline NetworkOrdered internet_checksum(const void* ptr, size_t count) -{ - dword checksum = 0; - auto* w = (const word*)ptr; - while (count > 1) { - checksum += convert_between_host_and_network(*w++); - if (checksum & 0x80000000) - checksum = (checksum & 0xffff) | (checksum >> 16); - count -= 2; - } - while (checksum >> 16) - checksum = (checksum & 0xffff) + (checksum >> 16); - return ~checksum & 0xffff; -} diff --git a/Kernel/IPv4Socket.cpp b/Kernel/IPv4Socket.cpp deleted file mode 100644 index 3a327e1a4e..0000000000 --- a/Kernel/IPv4Socket.cpp +++ /dev/null @@ -1,236 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IPV4_SOCKET_DEBUG - -Lockable>& IPv4Socket::all_sockets() -{ - static Lockable>* s_table; - if (!s_table) - s_table = new Lockable>; - return *s_table; -} - -Retained IPv4Socket::create(int type, int protocol) -{ - if (type == SOCK_STREAM) - return TCPSocket::create(protocol); - if (type == SOCK_DGRAM) - return UDPSocket::create(protocol); - return adopt(*new IPv4Socket(type, protocol)); -} - -IPv4Socket::IPv4Socket(int type, int protocol) - : Socket(AF_INET, type, protocol) -{ - kprintf("%s(%u) IPv4Socket{%p} created with type=%u, protocol=%d\n", current->process().name().characters(), current->pid(), this, type, protocol); - LOCKER(all_sockets().lock()); - all_sockets().resource().set(this); -} - -IPv4Socket::~IPv4Socket() -{ - LOCKER(all_sockets().lock()); - all_sockets().resource().remove(this); -} - -bool IPv4Socket::get_address(sockaddr* address, socklen_t* address_size) -{ - // FIXME: Look into what fallback behavior we should have here. - if (*address_size != sizeof(sockaddr_in)) - return false; - memcpy(address, &m_destination_address, sizeof(sockaddr_in)); - *address_size = sizeof(sockaddr_in); - return true; -} - -KResult IPv4Socket::bind(const sockaddr* address, socklen_t address_size) -{ - ASSERT(!is_connected()); - if (address_size != sizeof(sockaddr_in)) - return KResult(-EINVAL); - if (address->sa_family != AF_INET) - return KResult(-EINVAL); - - ASSERT_NOT_REACHED(); -} - -KResult IPv4Socket::connect(const sockaddr* address, socklen_t address_size) -{ - ASSERT(!m_bound); - if (address_size != sizeof(sockaddr_in)) - return KResult(-EINVAL); - if (address->sa_family != AF_INET) - return KResult(-EINVAL); - - 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 protocol_connect(); -} - -void IPv4Socket::attach_fd(SocketRole) -{ - ++m_attached_fds; -} - -void IPv4Socket::detach_fd(SocketRole) -{ - --m_attached_fds; -} - -bool IPv4Socket::can_read(SocketRole) const -{ - if (protocol_is_disconnected()) - return true; - return m_can_read; -} - -ssize_t IPv4Socket::read(SocketRole, byte* buffer, ssize_t size) -{ - return recvfrom(buffer, size, 0, nullptr, 0); -} - -ssize_t IPv4Socket::write(SocketRole, const byte* data, ssize_t size) -{ - return sendto(data, size, 0, nullptr, 0); -} - -bool IPv4Socket::can_write(SocketRole) const -{ - return true; -} - -int IPv4Socket::allocate_source_port_if_needed() -{ - if (m_source_port) - return m_source_port; - int port = protocol_allocate_source_port(); - if (port < 0) - return port; - m_source_port = (word)port; - return port; -} - -ssize_t IPv4Socket::sendto(const void* data, size_t data_length, int flags, const sockaddr* addr, socklen_t addr_length) -{ - (void)flags; - if (addr && addr_length != sizeof(sockaddr_in)) - return -EINVAL; - - if (addr) { - if (addr->sa_family != AF_INET) { - kprintf("sendto: Bad address family: %u is not AF_INET!\n", addr->sa_family); - 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); - } - - auto* adapter = adapter_for_route_to(m_destination_address); - if (!adapter) - return -EHOSTUNREACH; - - int rc = allocate_source_port_if_needed(); - if (rc < 0) - return rc; - - kprintf("sendto: destination=%s:%u\n", m_destination_address.to_string().characters(), m_destination_port); - - if (type() == SOCK_RAW) { - adapter->send_ipv4(MACAddress(), m_destination_address, (IPv4Protocol)protocol(), ByteBuffer::copy(data, data_length)); - return data_length; - } - - return protocol_send(data, data_length); -} - -ssize_t IPv4Socket::recvfrom(void* buffer, size_t buffer_length, int flags, sockaddr* addr, socklen_t* addr_length) -{ - (void)flags; - if (addr_length && *addr_length < sizeof(sockaddr_in)) - return -EINVAL; - -#ifdef IPV4_SOCKET_DEBUG - kprintf("recvfrom: type=%d, source_port=%u\n", type(), source_port()); -#endif - - ByteBuffer packet_buffer; - { - LOCKER(lock()); - if (!m_receive_queue.is_empty()) { - packet_buffer = m_receive_queue.take_first(); - m_can_read = !m_receive_queue.is_empty(); -#ifdef IPV4_SOCKET_DEBUG - kprintf("IPv4Socket(%p): recvfrom without blocking %d bytes, packets in queue: %d\n", this, packet_buffer.size(), m_receive_queue.size_slow()); -#endif - } - } - if (packet_buffer.is_null()) { - if (protocol_is_disconnected()) { - kprintf("IPv4Socket{%p} is protocol-disconnected, returning 0 in recvfrom!\n", this); - return 0; - } - - current->set_blocked_socket(this); - load_receive_deadline(); - current->block(Thread::BlockedReceive); - - LOCKER(lock()); - if (!m_can_read) { - // Unblocked due to timeout. - return -EAGAIN; - } - ASSERT(m_can_read); - ASSERT(!m_receive_queue.is_empty()); - packet_buffer = m_receive_queue.take_first(); - m_can_read = !m_receive_queue.is_empty(); -#ifdef IPV4_SOCKET_DEBUG - kprintf("IPv4Socket(%p): recvfrom with blocking %d bytes, packets in queue: %d\n", this, packet_buffer.size(), m_receive_queue.size_slow()); -#endif - } - ASSERT(!packet_buffer.is_null()); - auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer()); - - if (addr) { - auto& ia = *(sockaddr_in*)addr; - memcpy(&ia.sin_addr, &m_destination_address, sizeof(IPv4Address)); - ia.sin_family = AF_INET; - ASSERT(addr_length); - *addr_length = sizeof(sockaddr_in); - } - - if (type() == SOCK_RAW) { - ASSERT(buffer_length >= ipv4_packet.payload_size()); - memcpy(buffer, ipv4_packet.payload(), ipv4_packet.payload_size()); - return ipv4_packet.payload_size(); - } - - return protocol_receive(packet_buffer, buffer, buffer_length, flags, addr, addr_length); -} - -void IPv4Socket::did_receive(ByteBuffer&& packet) -{ - LOCKER(lock()); - auto packet_size = packet.size(); - m_receive_queue.append(move(packet)); - m_can_read = true; - m_bytes_received += packet_size; -#ifdef IPV4_SOCKET_DEBUG - kprintf("IPv4Socket(%p): did_receive %d bytes, total_received=%u, packets in queue: %d\n", this, packet_size, m_bytes_received, m_receive_queue.size_slow()); -#endif -} diff --git a/Kernel/IPv4Socket.h b/Kernel/IPv4Socket.h deleted file mode 100644 index d4729dd7f0..0000000000 --- a/Kernel/IPv4Socket.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -class IPv4SocketHandle; -class TCPSocketHandle; -class NetworkAdapter; -class TCPPacket; -class TCPSocket; - -class IPv4Socket : public Socket { -public: - static Retained create(int type, int protocol); - virtual ~IPv4Socket() override; - - static Lockable>& all_sockets(); - - virtual KResult bind(const sockaddr*, socklen_t) override; - virtual KResult connect(const sockaddr*, socklen_t) override; - virtual bool get_address(sockaddr*, socklen_t*) override; - virtual void attach_fd(SocketRole) override; - virtual void detach_fd(SocketRole) override; - virtual bool can_read(SocketRole) const override; - virtual ssize_t read(SocketRole, byte*, ssize_t) override; - virtual ssize_t write(SocketRole, const byte*, ssize_t) override; - virtual bool can_write(SocketRole) const override; - virtual ssize_t sendto(const void*, size_t, int, const sockaddr*, socklen_t) override; - virtual ssize_t recvfrom(void*, size_t, int flags, sockaddr*, socklen_t*) override; - - void did_receive(ByteBuffer&&); - - const IPv4Address& source_address() const; - word source_port() const { return m_source_port; } - void set_source_port(word port) { m_source_port = port; } - - const IPv4Address& destination_address() const { return m_destination_address; } - word destination_port() const { return m_destination_port; } - void set_destination_port(word port) { m_destination_port = port; } - -protected: - IPv4Socket(int type, int protocol); - - int allocate_source_port_if_needed(); - - virtual int protocol_receive(const ByteBuffer&, void*, size_t, int, sockaddr*, socklen_t*) { return -ENOTIMPL; } - virtual int protocol_send(const void*, int) { return -ENOTIMPL; } - virtual KResult protocol_connect() { return KSuccess; } - virtual int protocol_allocate_source_port() { return 0; } - virtual bool protocol_is_disconnected() const { return false; } - -private: - virtual bool is_ipv4() const override { return true; } - - bool m_bound { false }; - int m_attached_fds { 0 }; - IPv4Address m_destination_address; - - DoubleBuffer m_for_client; - DoubleBuffer m_for_server; - - SinglyLinkedList m_receive_queue; - - word m_source_port { 0 }; - word m_destination_port { 0 }; - - dword m_bytes_received { 0 }; - - bool m_can_read { false }; -}; - -class IPv4SocketHandle : public SocketHandle { -public: - IPv4SocketHandle() { } - - IPv4SocketHandle(RetainPtr&& socket) - : SocketHandle(move(socket)) - { - } - - IPv4SocketHandle(IPv4SocketHandle&& other) - : SocketHandle(move(other)) - { - } - - IPv4SocketHandle(const IPv4SocketHandle&) = delete; - IPv4SocketHandle& operator=(const IPv4SocketHandle&) = delete; - - IPv4Socket* operator->() { return &socket(); } - const IPv4Socket* operator->() const { return &socket(); } - - IPv4Socket& socket() { return static_cast(SocketHandle::socket()); } - const IPv4Socket& socket() const { return static_cast(SocketHandle::socket()); } -}; diff --git a/Kernel/MACAddress.h b/Kernel/MACAddress.h deleted file mode 100644 index 0c2de93b27..0000000000 --- a/Kernel/MACAddress.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -class [[gnu::packed]] MACAddress { -public: - MACAddress() { } - MACAddress(const byte data[6]) - { - memcpy(m_data, data, 6); - } - ~MACAddress() { } - - byte operator[](int i) const - { - ASSERT(i >= 0 && i < 6); - return m_data[i]; - } - - bool operator==(const MACAddress& other) const - { - return !memcmp(m_data, other.m_data, sizeof(m_data)); - } - - String to_string() const - { - return String::format("%b:%b:%b:%b:%b:%b", m_data[0], m_data[1], m_data[2], m_data[3], m_data[4], m_data[5]); - } - -private: - byte m_data[6]; -}; - -static_assert(sizeof(MACAddress) == 6); - -namespace AK { - -template<> -struct Traits { - static unsigned hash(const MACAddress& address) { return string_hash((const char*)&address, sizeof(address)); } - static void dump(const MACAddress& address) { kprintf("%s", address.to_string().characters()); } -}; - -} diff --git a/Kernel/Makefile b/Kernel/Makefile index 11cc3a4142..85ef1c7e55 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -34,14 +34,14 @@ KERNEL_OBJS = \ PS2MouseDevice.o \ Socket.o \ LocalSocket.o \ - IPv4Socket.o \ - TCPSocket.o \ - UDPSocket.o \ - NetworkAdapter.o \ - E1000NetworkAdapter.o \ + Net/IPv4Socket.o \ + Net/TCPSocket.o \ + Net/UDPSocket.o \ + Net/NetworkAdapter.o \ + Net/E1000NetworkAdapter.o \ Net/LoopbackAdapter.o \ Net/Routing.o \ - NetworkTask.o + Net/NetworkTask.o VFS_OBJS = \ DiskDevice.o \ diff --git a/Kernel/Net/ARP.h b/Kernel/Net/ARP.h new file mode 100644 index 0000000000..ddfcd54f63 --- /dev/null +++ b/Kernel/Net/ARP.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +struct ARPOperation { +enum : word { + Request = 1, + Response = 2, +}; +}; + +struct ARPHardwareType { +enum : word { + Ethernet = 1, +}; +}; + +class [[gnu::packed]] ARPPacket { +public: + word hardware_type() const { return ntohs(m_hardware_type); } + void set_hardware_type(word w) { m_hardware_type = htons(w); } + + word protocol_type() const { return ntohs(m_protocol_type); } + void set_protocol_type(word w) { m_protocol_type = htons(w); } + + byte hardware_address_length() const { return m_hardware_address_length; } + void set_hardware_address_length(byte b) { m_hardware_address_length = b; } + + byte protocol_address_length() const { return m_protocol_address_length; } + void set_protocol_address_length(byte b) { m_protocol_address_length = b; } + + word operation() const { return ntohs(m_operation); } + void set_operation(word w) { m_operation = htons(w); } + + const MACAddress& sender_hardware_address() const { return m_sender_hardware_address; } + void set_sender_hardware_address(const MACAddress& address) { m_sender_hardware_address = address; } + + const IPv4Address& sender_protocol_address() const { return m_sender_protocol_address; } + void set_sender_protocol_address(const IPv4Address& address) { m_sender_protocol_address = address; } + + const MACAddress& target_hardware_address() const { return m_target_hardware_address; } + void set_target_hardware_address(const MACAddress& address) { m_target_hardware_address = address; } + + const IPv4Address& target_protocol_address() const { return m_target_protocol_address; } + void set_target_protocol_address(const IPv4Address& address) { m_target_protocol_address = address; } + +private: + word m_hardware_type { 0x0100 }; + word m_protocol_type { 0x0008 }; + byte m_hardware_address_length { sizeof(MACAddress) }; + byte m_protocol_address_length { sizeof(IPv4Address) }; + word m_operation { 0 }; + MACAddress m_sender_hardware_address; + IPv4Address m_sender_protocol_address; + MACAddress m_target_hardware_address; + IPv4Address m_target_protocol_address; +}; + +static_assert(sizeof(ARPPacket) == 28); diff --git a/Kernel/Net/E1000NetworkAdapter.cpp b/Kernel/Net/E1000NetworkAdapter.cpp new file mode 100644 index 0000000000..b73ddc70e2 --- /dev/null +++ b/Kernel/Net/E1000NetworkAdapter.cpp @@ -0,0 +1,354 @@ +#include +#include +#include + +#define REG_CTRL 0x0000 +#define REG_STATUS 0x0008 +#define REG_EEPROM 0x0014 +#define REG_CTRL_EXT 0x0018 +#define REG_IMASK 0x00D0 +#define REG_RCTRL 0x0100 +#define REG_RXDESCLO 0x2800 +#define REG_RXDESCHI 0x2804 +#define REG_RXDESCLEN 0x2808 +#define REG_RXDESCHEAD 0x2810 +#define REG_RXDESCTAIL 0x2818 +#define REG_TCTRL 0x0400 +#define REG_TXDESCLO 0x3800 +#define REG_TXDESCHI 0x3804 +#define REG_TXDESCLEN 0x3808 +#define REG_TXDESCHEAD 0x3810 +#define REG_TXDESCTAIL 0x3818 +#define REG_RDTR 0x2820 // RX Delay Timer Register +#define REG_RXDCTL 0x3828 // RX Descriptor Control +#define REG_RADV 0x282C // RX Int. Absolute Delay Timer +#define REG_RSRPD 0x2C00 // RX Small Packet Detect Interrupt +#define REG_TIPG 0x0410 // Transmit Inter Packet Gap +#define ECTRL_SLU 0x40 //set link up +#define RCTL_EN (1 << 1) // Receiver Enable +#define RCTL_SBP (1 << 2) // Store Bad Packets +#define RCTL_UPE (1 << 3) // Unicast Promiscuous Enabled +#define RCTL_MPE (1 << 4) // Multicast Promiscuous Enabled +#define RCTL_LPE (1 << 5) // Long Packet Reception Enable +#define RCTL_LBM_NONE (0 << 6) // No Loopback +#define RCTL_LBM_PHY (3 << 6) // PHY or external SerDesc loopback +#define RTCL_RDMTS_HALF (0 << 8) // Free Buffer Threshold is 1/2 of RDLEN +#define RTCL_RDMTS_QUARTER (1 << 8) // Free Buffer Threshold is 1/4 of RDLEN +#define RTCL_RDMTS_EIGHTH (2 << 8) // Free Buffer Threshold is 1/8 of RDLEN +#define RCTL_MO_36 (0 << 12) // Multicast Offset - bits 47:36 +#define RCTL_MO_35 (1 << 12) // Multicast Offset - bits 46:35 +#define RCTL_MO_34 (2 << 12) // Multicast Offset - bits 45:34 +#define RCTL_MO_32 (3 << 12) // Multicast Offset - bits 43:32 +#define RCTL_BAM (1 << 15) // Broadcast Accept Mode +#define RCTL_VFE (1 << 18) // VLAN Filter Enable +#define RCTL_CFIEN (1 << 19) // Canonical Form Indicator Enable +#define RCTL_CFI (1 << 20) // Canonical Form Indicator Bit Value +#define RCTL_DPF (1 << 22) // Discard Pause Frames +#define RCTL_PMCF (1 << 23) // Pass MAC Control Frames +#define RCTL_SECRC (1 << 26) // Strip Ethernet CRC + +// Buffer Sizes +#define RCTL_BSIZE_256 (3 << 16) +#define RCTL_BSIZE_512 (2 << 16) +#define RCTL_BSIZE_1024 (1 << 16) +#define RCTL_BSIZE_2048 (0 << 16) +#define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25)) +#define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25)) +#define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25)) + +// Transmit Command + +#define CMD_EOP (1 << 0) // End of Packet +#define CMD_IFCS (1 << 1) // Insert FCS +#define CMD_IC (1 << 2) // Insert Checksum +#define CMD_RS (1 << 3) // Report Status +#define CMD_RPS (1 << 4) // Report Packet Sent +#define CMD_VLE (1 << 6) // VLAN Packet Enable +#define CMD_IDE (1 << 7) // Interrupt Delay Enable + +// TCTL Register + +#define TCTL_EN (1 << 1) // Transmit Enable +#define TCTL_PSP (1 << 3) // Pad Short Packets +#define TCTL_CT_SHIFT 4 // Collision Threshold +#define TCTL_COLD_SHIFT 12 // Collision Distance +#define TCTL_SWXOFF (1 << 22) // Software XOFF Transmission +#define TCTL_RTLC (1 << 24) // Re-transmit on Late Collision + +#define TSTA_DD (1 << 0) // Descriptor Done +#define TSTA_EC (1 << 1) // Excess Collisions +#define TSTA_LC (1 << 2) // Late Collision +#define LSTA_TU (1 << 3) // Transmit Underrun + +OwnPtr E1000NetworkAdapter::autodetect() +{ + static const PCI::ID qemu_bochs_vbox_id = { 0x8086, 0x100e }; + PCI::Address found_address; + PCI::enumerate_all([&] (const PCI::Address& address, PCI::ID id) { + if (id == qemu_bochs_vbox_id) { + found_address = address; + return; + } + }); + if (found_address.is_null()) + return nullptr; + byte irq = PCI::get_interrupt_line(found_address); + return make(found_address, irq); +} + +static E1000NetworkAdapter* s_the; +E1000NetworkAdapter* E1000NetworkAdapter::the() +{ + return s_the; +} + +E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address pci_address, byte irq) + : IRQHandler(irq) + , m_pci_address(pci_address) +{ + s_the = this; + kprintf("E1000: Found at PCI address %b:%b:%b\n", pci_address.bus(), pci_address.slot(), pci_address.function()); + + enable_bus_mastering(m_pci_address); + + m_mmio_base = PhysicalAddress(PCI::get_BAR0(m_pci_address)); + MM.map_for_kernel(LinearAddress(m_mmio_base.get()), m_mmio_base); + MM.map_for_kernel(LinearAddress(m_mmio_base.offset(4096).get()), m_mmio_base.offset(4096)); + MM.map_for_kernel(LinearAddress(m_mmio_base.offset(8192).get()), m_mmio_base.offset(8192)); + MM.map_for_kernel(LinearAddress(m_mmio_base.offset(12288).get()), m_mmio_base.offset(12288)); + MM.map_for_kernel(LinearAddress(m_mmio_base.offset(16384).get()), m_mmio_base.offset(16384)); + m_use_mmio = true; + m_io_base = PCI::get_BAR1(m_pci_address) & ~1; + m_interrupt_line = PCI::get_interrupt_line(m_pci_address); + kprintf("E1000: IO port base: %w\n", m_io_base); + kprintf("E1000: MMIO base: P%x\n", m_mmio_base); + kprintf("E1000: Interrupt line: %u\n", m_interrupt_line); + detect_eeprom(); + kprintf("E1000: Has EEPROM? %u\n", m_has_eeprom); + read_mac_address(); + const auto& mac = mac_address(); + kprintf("E1000: MAC address: %b:%b:%b:%b:%b:%b\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + dword flags = in32(REG_CTRL); + out32(REG_CTRL, flags | ECTRL_SLU); + + initialize_rx_descriptors(); + initialize_tx_descriptors(); + + out32(REG_IMASK, 0x1f6dc); + out32(REG_IMASK, 0xff & ~4); + in32(0xc0); + + enable_irq(); +} + +E1000NetworkAdapter::~E1000NetworkAdapter() +{ +} + +void E1000NetworkAdapter::handle_irq() +{ + out32(REG_IMASK, 0x1); + + dword status = in32(0xc0); + if (status & 4) { + dword flags = in32(REG_CTRL); + out32(REG_CTRL, flags | ECTRL_SLU); + } + if (status & 0x10) { + // Threshold OK? + } + if (status & 0x80) { + receive(); + } +} + +void E1000NetworkAdapter::detect_eeprom() +{ + out32(REG_EEPROM, 0x1); + for (volatile int i = 0; i < 999; ++i) { + dword data = in32(REG_EEPROM); + if (data & 0x10) { + m_has_eeprom = true; + return; + } + } + m_has_eeprom = false; +} + +dword E1000NetworkAdapter::read_eeprom(byte address) +{ + word data = 0; + dword tmp = 0; + if (m_has_eeprom) { + out32(REG_EEPROM, ((dword)address << 8) | 1); + while (!((tmp = in32(REG_EEPROM)) & (1 << 4))) + ; + } else { + out32(REG_EEPROM, ((dword)address << 2) | 1); + while (!((tmp = in32(REG_EEPROM)) & (1 << 1))) + ; + } + data = (tmp >> 16) & 0xffff; + return data; +} + +void E1000NetworkAdapter::read_mac_address() +{ + if (m_has_eeprom) { + byte mac[6]; + dword tmp = read_eeprom(0); + mac[0] = tmp & 0xff; + mac[1] = tmp >> 8; + tmp = read_eeprom(1); + mac[2] = tmp & 0xff; + mac[3] = tmp >> 8; + tmp = read_eeprom(2); + mac[4] = tmp & 0xff; + mac[5] = tmp >> 8; + set_mac_address(mac); + } else { + ASSERT_NOT_REACHED(); + } +} + +void E1000NetworkAdapter::initialize_rx_descriptors() +{ + auto ptr = (dword)kmalloc_eternal(sizeof(e1000_rx_desc) * number_of_rx_descriptors + 16); + // Make sure it's 16-byte aligned. + if (ptr % 16) + ptr = (ptr + 16) - (ptr % 16); + m_rx_descriptors = (e1000_rx_desc*)ptr; + for (int i = 0; i < number_of_rx_descriptors; ++i) { + auto& descriptor = m_rx_descriptors[i]; + descriptor.addr = (qword)kmalloc_eternal(8192 + 16); + descriptor.status = 0; + } + + out32(REG_RXDESCLO, ptr); + out32(REG_RXDESCHI, 0); + out32(REG_RXDESCLEN, number_of_rx_descriptors * sizeof(e1000_rx_desc)); + out32(REG_RXDESCHEAD, 0); + out32(REG_RXDESCTAIL, number_of_rx_descriptors - 1); + + out32(REG_RCTRL, RCTL_EN| RCTL_SBP| RCTL_UPE | RCTL_MPE | RCTL_LBM_NONE | RTCL_RDMTS_HALF | RCTL_BAM | RCTL_SECRC | RCTL_BSIZE_8192); +} + +void E1000NetworkAdapter::initialize_tx_descriptors() +{ + auto ptr = (dword)kmalloc_eternal(sizeof(e1000_tx_desc) * number_of_tx_descriptors + 16); + // Make sure it's 16-byte aligned. + if (ptr % 16) + ptr = (ptr + 16) - (ptr % 16); + m_tx_descriptors = (e1000_tx_desc*)ptr; + for (int i = 0; i < number_of_tx_descriptors; ++i) { + auto& descriptor = m_tx_descriptors[i]; + descriptor.addr = (qword)kmalloc_eternal(8192 + 16); + descriptor.cmd = 0; + } + + out32(REG_TXDESCLO, ptr); + out32(REG_TXDESCHI, 0); + out32(REG_TXDESCLEN, number_of_tx_descriptors * sizeof(e1000_tx_desc)); + out32(REG_TXDESCHEAD, 0); + out32(REG_TXDESCTAIL, 0); + + out32(REG_TCTRL, in32(REG_TCTRL) | TCTL_EN | TCTL_PSP); + out32(REG_TIPG, 0x0060200A); +} + +void E1000NetworkAdapter::out8(word address, byte data) +{ + if (m_use_mmio) { + auto* ptr = (volatile byte*)(m_mmio_base.get() + address); + *ptr = data; + return; + } + IO::out8(m_io_base + address, data); +} + +void E1000NetworkAdapter::out16(word address, word data) +{ + if (m_use_mmio) { + auto* ptr = (volatile word*)(m_mmio_base.get() + address); + *ptr = data; + return; + } + IO::out16(m_io_base + address, data); +} + +void E1000NetworkAdapter::out32(word address, dword data) +{ + if (m_use_mmio) { + auto* ptr = (volatile dword*)(m_mmio_base.get() + address); + *ptr = data; + return; + } + IO::out32(m_io_base + address, data); +} + +byte E1000NetworkAdapter::in8(word address) +{ + if (m_use_mmio) + return *(volatile byte*)(m_mmio_base.get() + address); + return IO::in8(m_io_base + address); +} + +word E1000NetworkAdapter::in16(word address) +{ + if (m_use_mmio) + return *(volatile word*)(m_mmio_base.get() + address); + return IO::in16(m_io_base + address); +} + +dword E1000NetworkAdapter::in32(word address) +{ + if (m_use_mmio) + return *(volatile dword*)(m_mmio_base.get() + address); + return IO::in32(m_io_base + address); +} + +void E1000NetworkAdapter::send_raw(const byte* data, int length) +{ + dword tx_current = in32(REG_TXDESCTAIL); +#ifdef E1000_DEBUG + kprintf("E1000: Sending packet (%d bytes)\n", length); +#endif + auto& descriptor = m_tx_descriptors[tx_current]; + ASSERT(length <= 8192); + memcpy((void*)descriptor.addr, data, length); + descriptor.length = length; + descriptor.status = 0; + descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS; +#ifdef E1000_DEBUG + kprintf("E1000: Using tx descriptor %d (head is at %d)\n", tx_current, in32(REG_TXDESCHEAD)); +#endif + tx_current = (tx_current + 1) % number_of_tx_descriptors; + out32(REG_TXDESCTAIL, tx_current); + while (!descriptor.status) + ; +#ifdef E1000_DEBUG + kprintf("E1000: Sent packet, status is now %b!\n", descriptor.status); +#endif +} + +void E1000NetworkAdapter::receive() +{ + dword rx_current; + for (;;) { + rx_current = in32(REG_RXDESCTAIL); + if (rx_current == in32(REG_RXDESCHEAD)) + return; + rx_current = (rx_current + 1) % number_of_rx_descriptors; + if (!(m_rx_descriptors[rx_current].status & 1)) + break; + auto* buffer = (byte*)m_rx_descriptors[rx_current].addr; + word length = m_rx_descriptors[rx_current].length; +#ifdef E1000_DEBUG + kprintf("E1000: Received 1 packet @ %p (%u) bytes!\n", buffer, length); +#endif + did_receive(buffer, length); + m_rx_descriptors[rx_current].status = 0; + out32(REG_RXDESCTAIL, rx_current); + } +} diff --git a/Kernel/Net/E1000NetworkAdapter.h b/Kernel/Net/E1000NetworkAdapter.h new file mode 100644 index 0000000000..c0afa4cc26 --- /dev/null +++ b/Kernel/Net/E1000NetworkAdapter.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include +#include +#include + +class E1000NetworkAdapter final : public NetworkAdapter, public IRQHandler { +public: + static E1000NetworkAdapter* the(); + + static OwnPtr autodetect(); + + E1000NetworkAdapter(PCI::Address, byte irq); + virtual ~E1000NetworkAdapter() override; + + virtual void send_raw(const byte*, int) override; + +private: + virtual void handle_irq() override; + virtual const char* class_name() const override { return "E1000NetworkAdapter"; } + + struct [[gnu::packed]] e1000_rx_desc { + volatile uint64_t addr { 0 }; + volatile uint16_t length { 0 }; + volatile uint16_t checksum { 0 }; + volatile uint8_t status { 0 }; + volatile uint8_t errors { 0 }; + volatile uint16_t special { 0 }; + }; + + struct [[gnu::packed]] e1000_tx_desc { + volatile uint64_t addr { 0 }; + volatile uint16_t length { 0 }; + volatile uint8_t cso { 0 }; + volatile uint8_t cmd { 0 }; + volatile uint8_t status { 0 }; + volatile uint8_t css { 0 }; + volatile uint16_t special { 0 }; + }; + + void detect_eeprom(); + dword read_eeprom(byte address); + void read_mac_address(); + + void write_command(word address, dword); + dword read_command(word address); + + void initialize_rx_descriptors(); + void initialize_tx_descriptors(); + + void out8(word address, byte); + void out16(word address, word); + void out32(word address, dword); + byte in8(word address); + word in16(word address); + dword in32(word address); + + void receive(); + + PCI::Address m_pci_address; + word m_io_base { 0 }; + PhysicalAddress m_mmio_base; + byte m_interrupt_line { 0 }; + bool m_has_eeprom { false }; + bool m_use_mmio { false }; + + static const int number_of_rx_descriptors = 32; + static const int number_of_tx_descriptors = 8; + + e1000_rx_desc* m_rx_descriptors; + e1000_tx_desc* m_tx_descriptors; +}; diff --git a/Kernel/Net/EtherType.h b/Kernel/Net/EtherType.h new file mode 100644 index 0000000000..027967ff77 --- /dev/null +++ b/Kernel/Net/EtherType.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +struct EtherType { +enum : word { + ARP = 0x0806, + IPv4 = 0x0800, +}; +}; diff --git a/Kernel/Net/EthernetFrameHeader.h b/Kernel/Net/EthernetFrameHeader.h new file mode 100644 index 0000000000..2b549497d9 --- /dev/null +++ b/Kernel/Net/EthernetFrameHeader.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +class [[gnu::packed]] EthernetFrameHeader { +public: + EthernetFrameHeader() { } + ~EthernetFrameHeader() { } + + MACAddress destination() const { return m_destination; } + void set_destination(const MACAddress& address) { m_destination = address; } + + MACAddress source() const { return m_source; } + void set_source(const MACAddress& address) { m_source = address; } + + word ether_type() const { return m_ether_type; } + void set_ether_type(word ether_type) { m_ether_type = ether_type; } + + const void* payload() const { return &m_payload[0]; } + void* payload() { return &m_payload[0]; } + +private: + MACAddress m_destination; + MACAddress m_source; + NetworkOrdered m_ether_type; + dword m_payload[0]; +}; + +static_assert(sizeof(EthernetFrameHeader) == 14); + diff --git a/Kernel/Net/ICMP.h b/Kernel/Net/ICMP.h new file mode 100644 index 0000000000..efc6cf4ca6 --- /dev/null +++ b/Kernel/Net/ICMP.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +struct ICMPType { +enum { + EchoReply = 0, + EchoRequest = 8, +}; +}; + +class [[gnu::packed]] ICMPHeader { +public: + ICMPHeader() { } + ~ICMPHeader() { } + + byte type() const { return m_type; } + void set_type(byte b) { m_type = b; } + + byte code() const { return m_code; } + void set_code(byte b) { m_code = b; } + + word checksum() const { return m_checksum; } + void set_checksum(word w) { m_checksum = w; } + + const void* payload() const { return this + 1; } + void* payload() { return this + 1; } + +private: + byte m_type { 0 }; + byte m_code { 0 }; + NetworkOrdered m_checksum { 0 }; + // NOTE: The rest of the header is 4 bytes +}; + +static_assert(sizeof(ICMPHeader) == 4); + +struct [[gnu::packed]] ICMPEchoPacket { + ICMPHeader header; + NetworkOrdered identifier; + NetworkOrdered sequence_number; + void* payload() { return this + 1; } + const void* payload() const { return this + 1; } +}; diff --git a/Kernel/Net/IPv4.h b/Kernel/Net/IPv4.h new file mode 100644 index 0000000000..dc4e4dff3c --- /dev/null +++ b/Kernel/Net/IPv4.h @@ -0,0 +1,135 @@ +#pragma once + +#include +#include +#include +#include + +enum class IPv4Protocol : word { + ICMP = 1, + TCP = 6, + UDP = 17, +}; + +NetworkOrdered internet_checksum(const void*, size_t); + +class [[gnu::packed]] IPv4Address { +public: + IPv4Address() { } + IPv4Address(const byte data[4]) + { + m_data[0] = data[0]; + m_data[1] = data[1]; + m_data[2] = data[2]; + m_data[3] = data[3]; + } + IPv4Address(byte a, byte b, byte c, byte d) + { + m_data[0] = a; + m_data[1] = b; + m_data[2] = c; + m_data[3] = d; + } + + byte operator[](int i) const + { + ASSERT(i >= 0 && i < 4); + return m_data[i]; + } + + String to_string() const + { + return String::format("%u.%u.%u.%u", m_data[0], m_data[1], m_data[2], m_data[3]); + } + + bool operator==(const IPv4Address& other) const { return m_data_as_dword == other.m_data_as_dword; } + bool operator!=(const IPv4Address& other) const { return m_data_as_dword != other.m_data_as_dword; } + +private: + union { + byte m_data[4]; + dword m_data_as_dword; + }; +}; + +static_assert(sizeof(IPv4Address) == 4); + +namespace AK { + +template<> +struct Traits { + static unsigned hash(const IPv4Address& address) { return string_hash((const char*)&address, sizeof(address)); } + static void dump(const IPv4Address& address) { kprintf("%s", address.to_string().characters()); } +}; + +} + +class [[gnu::packed]] IPv4Packet { +public: + byte version() const { return (m_version_and_ihl >> 4) & 0xf; } + void set_version(byte version) { m_version_and_ihl = (m_version_and_ihl & 0x0f) | (version << 4); } + + byte internet_header_length() const { return m_version_and_ihl & 0xf; } + void set_internet_header_length(byte ihl) { m_version_and_ihl = (m_version_and_ihl & 0xf0) | (ihl & 0x0f); } + + word length() const { return m_length; } + void set_length(word length) { m_length = length; } + + word ident() const { return m_ident; } + void set_ident(word ident) { m_ident = ident; } + + byte ttl() const { return m_ttl; } + void set_ttl(byte ttl) { m_ttl = ttl; } + + byte protocol() const { return m_protocol; } + void set_protocol(byte protocol) { m_protocol = protocol; } + + word checksum() const { return m_checksum; } + void set_checksum(word checksum) { m_checksum = checksum; } + + const IPv4Address& source() const { return m_source; } + void set_source(const IPv4Address& address) { m_source = address; } + + const IPv4Address& destination() const { return m_destination; } + void set_destination(const IPv4Address& address) { m_destination = address; } + + void* payload() { return this + 1; } + const void* payload() const { return this + 1; } + + word payload_size() const { return m_length - sizeof(IPv4Packet); } + + NetworkOrdered compute_checksum() const + { + ASSERT(!m_checksum); + return internet_checksum(this, sizeof(IPv4Packet)); + } + +private: + byte m_version_and_ihl { 0 }; + byte m_dscp_and_ecn { 0 }; + NetworkOrdered m_length; + NetworkOrdered m_ident; + NetworkOrdered m_flags_and_fragment; + byte m_ttl { 0 }; + NetworkOrdered m_protocol; + NetworkOrdered m_checksum; + IPv4Address m_source; + IPv4Address m_destination; +}; + +static_assert(sizeof(IPv4Packet) == 20); + +inline NetworkOrdered internet_checksum(const void* ptr, size_t count) +{ + dword checksum = 0; + auto* w = (const word*)ptr; + while (count > 1) { + checksum += convert_between_host_and_network(*w++); + if (checksum & 0x80000000) + checksum = (checksum & 0xffff) | (checksum >> 16); + count -= 2; + } + while (checksum >> 16) + checksum = (checksum & 0xffff) + (checksum >> 16); + return ~checksum & 0xffff; +} diff --git a/Kernel/Net/IPv4Socket.cpp b/Kernel/Net/IPv4Socket.cpp new file mode 100644 index 0000000000..7c7b1fdb4f --- /dev/null +++ b/Kernel/Net/IPv4Socket.cpp @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPV4_SOCKET_DEBUG + +Lockable>& IPv4Socket::all_sockets() +{ + static Lockable>* s_table; + if (!s_table) + s_table = new Lockable>; + return *s_table; +} + +Retained IPv4Socket::create(int type, int protocol) +{ + if (type == SOCK_STREAM) + return TCPSocket::create(protocol); + if (type == SOCK_DGRAM) + return UDPSocket::create(protocol); + return adopt(*new IPv4Socket(type, protocol)); +} + +IPv4Socket::IPv4Socket(int type, int protocol) + : Socket(AF_INET, type, protocol) +{ + kprintf("%s(%u) IPv4Socket{%p} created with type=%u, protocol=%d\n", current->process().name().characters(), current->pid(), this, type, protocol); + LOCKER(all_sockets().lock()); + all_sockets().resource().set(this); +} + +IPv4Socket::~IPv4Socket() +{ + LOCKER(all_sockets().lock()); + all_sockets().resource().remove(this); +} + +bool IPv4Socket::get_address(sockaddr* address, socklen_t* address_size) +{ + // FIXME: Look into what fallback behavior we should have here. + if (*address_size != sizeof(sockaddr_in)) + return false; + memcpy(address, &m_destination_address, sizeof(sockaddr_in)); + *address_size = sizeof(sockaddr_in); + return true; +} + +KResult IPv4Socket::bind(const sockaddr* address, socklen_t address_size) +{ + ASSERT(!is_connected()); + if (address_size != sizeof(sockaddr_in)) + return KResult(-EINVAL); + if (address->sa_family != AF_INET) + return KResult(-EINVAL); + + ASSERT_NOT_REACHED(); +} + +KResult IPv4Socket::connect(const sockaddr* address, socklen_t address_size) +{ + ASSERT(!m_bound); + if (address_size != sizeof(sockaddr_in)) + return KResult(-EINVAL); + if (address->sa_family != AF_INET) + return KResult(-EINVAL); + + 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 protocol_connect(); +} + +void IPv4Socket::attach_fd(SocketRole) +{ + ++m_attached_fds; +} + +void IPv4Socket::detach_fd(SocketRole) +{ + --m_attached_fds; +} + +bool IPv4Socket::can_read(SocketRole) const +{ + if (protocol_is_disconnected()) + return true; + return m_can_read; +} + +ssize_t IPv4Socket::read(SocketRole, byte* buffer, ssize_t size) +{ + return recvfrom(buffer, size, 0, nullptr, 0); +} + +ssize_t IPv4Socket::write(SocketRole, const byte* data, ssize_t size) +{ + return sendto(data, size, 0, nullptr, 0); +} + +bool IPv4Socket::can_write(SocketRole) const +{ + return true; +} + +int IPv4Socket::allocate_source_port_if_needed() +{ + if (m_source_port) + return m_source_port; + int port = protocol_allocate_source_port(); + if (port < 0) + return port; + m_source_port = (word)port; + return port; +} + +ssize_t IPv4Socket::sendto(const void* data, size_t data_length, int flags, const sockaddr* addr, socklen_t addr_length) +{ + (void)flags; + if (addr && addr_length != sizeof(sockaddr_in)) + return -EINVAL; + + if (addr) { + if (addr->sa_family != AF_INET) { + kprintf("sendto: Bad address family: %u is not AF_INET!\n", addr->sa_family); + 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); + } + + auto* adapter = adapter_for_route_to(m_destination_address); + if (!adapter) + return -EHOSTUNREACH; + + int rc = allocate_source_port_if_needed(); + if (rc < 0) + return rc; + + kprintf("sendto: destination=%s:%u\n", m_destination_address.to_string().characters(), m_destination_port); + + if (type() == SOCK_RAW) { + adapter->send_ipv4(MACAddress(), m_destination_address, (IPv4Protocol)protocol(), ByteBuffer::copy(data, data_length)); + return data_length; + } + + return protocol_send(data, data_length); +} + +ssize_t IPv4Socket::recvfrom(void* buffer, size_t buffer_length, int flags, sockaddr* addr, socklen_t* addr_length) +{ + (void)flags; + if (addr_length && *addr_length < sizeof(sockaddr_in)) + return -EINVAL; + +#ifdef IPV4_SOCKET_DEBUG + kprintf("recvfrom: type=%d, source_port=%u\n", type(), source_port()); +#endif + + ByteBuffer packet_buffer; + { + LOCKER(lock()); + if (!m_receive_queue.is_empty()) { + packet_buffer = m_receive_queue.take_first(); + m_can_read = !m_receive_queue.is_empty(); +#ifdef IPV4_SOCKET_DEBUG + kprintf("IPv4Socket(%p): recvfrom without blocking %d bytes, packets in queue: %d\n", this, packet_buffer.size(), m_receive_queue.size_slow()); +#endif + } + } + if (packet_buffer.is_null()) { + if (protocol_is_disconnected()) { + kprintf("IPv4Socket{%p} is protocol-disconnected, returning 0 in recvfrom!\n", this); + return 0; + } + + current->set_blocked_socket(this); + load_receive_deadline(); + current->block(Thread::BlockedReceive); + + LOCKER(lock()); + if (!m_can_read) { + // Unblocked due to timeout. + return -EAGAIN; + } + ASSERT(m_can_read); + ASSERT(!m_receive_queue.is_empty()); + packet_buffer = m_receive_queue.take_first(); + m_can_read = !m_receive_queue.is_empty(); +#ifdef IPV4_SOCKET_DEBUG + kprintf("IPv4Socket(%p): recvfrom with blocking %d bytes, packets in queue: %d\n", this, packet_buffer.size(), m_receive_queue.size_slow()); +#endif + } + ASSERT(!packet_buffer.is_null()); + auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer()); + + if (addr) { + auto& ia = *(sockaddr_in*)addr; + memcpy(&ia.sin_addr, &m_destination_address, sizeof(IPv4Address)); + ia.sin_family = AF_INET; + ASSERT(addr_length); + *addr_length = sizeof(sockaddr_in); + } + + if (type() == SOCK_RAW) { + ASSERT(buffer_length >= ipv4_packet.payload_size()); + memcpy(buffer, ipv4_packet.payload(), ipv4_packet.payload_size()); + return ipv4_packet.payload_size(); + } + + return protocol_receive(packet_buffer, buffer, buffer_length, flags, addr, addr_length); +} + +void IPv4Socket::did_receive(ByteBuffer&& packet) +{ + LOCKER(lock()); + auto packet_size = packet.size(); + m_receive_queue.append(move(packet)); + m_can_read = true; + m_bytes_received += packet_size; +#ifdef IPV4_SOCKET_DEBUG + kprintf("IPv4Socket(%p): did_receive %d bytes, total_received=%u, packets in queue: %d\n", this, packet_size, m_bytes_received, m_receive_queue.size_slow()); +#endif +} diff --git a/Kernel/Net/IPv4Socket.h b/Kernel/Net/IPv4Socket.h new file mode 100644 index 0000000000..1cae3b17ed --- /dev/null +++ b/Kernel/Net/IPv4Socket.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +class IPv4SocketHandle; +class TCPSocketHandle; +class NetworkAdapter; +class TCPPacket; +class TCPSocket; + +class IPv4Socket : public Socket { +public: + static Retained create(int type, int protocol); + virtual ~IPv4Socket() override; + + static Lockable>& all_sockets(); + + virtual KResult bind(const sockaddr*, socklen_t) override; + virtual KResult connect(const sockaddr*, socklen_t) override; + virtual bool get_address(sockaddr*, socklen_t*) override; + virtual void attach_fd(SocketRole) override; + virtual void detach_fd(SocketRole) override; + virtual bool can_read(SocketRole) const override; + virtual ssize_t read(SocketRole, byte*, ssize_t) override; + virtual ssize_t write(SocketRole, const byte*, ssize_t) override; + virtual bool can_write(SocketRole) const override; + virtual ssize_t sendto(const void*, size_t, int, const sockaddr*, socklen_t) override; + virtual ssize_t recvfrom(void*, size_t, int flags, sockaddr*, socklen_t*) override; + + void did_receive(ByteBuffer&&); + + const IPv4Address& source_address() const; + word source_port() const { return m_source_port; } + void set_source_port(word port) { m_source_port = port; } + + const IPv4Address& destination_address() const { return m_destination_address; } + word destination_port() const { return m_destination_port; } + void set_destination_port(word port) { m_destination_port = port; } + +protected: + IPv4Socket(int type, int protocol); + + int allocate_source_port_if_needed(); + + virtual int protocol_receive(const ByteBuffer&, void*, size_t, int, sockaddr*, socklen_t*) { return -ENOTIMPL; } + virtual int protocol_send(const void*, int) { return -ENOTIMPL; } + virtual KResult protocol_connect() { return KSuccess; } + virtual int protocol_allocate_source_port() { return 0; } + virtual bool protocol_is_disconnected() const { return false; } + +private: + virtual bool is_ipv4() const override { return true; } + + bool m_bound { false }; + int m_attached_fds { 0 }; + IPv4Address m_destination_address; + + DoubleBuffer m_for_client; + DoubleBuffer m_for_server; + + SinglyLinkedList m_receive_queue; + + word m_source_port { 0 }; + word m_destination_port { 0 }; + + dword m_bytes_received { 0 }; + + bool m_can_read { false }; +}; + +class IPv4SocketHandle : public SocketHandle { +public: + IPv4SocketHandle() { } + + IPv4SocketHandle(RetainPtr&& socket) + : SocketHandle(move(socket)) + { + } + + IPv4SocketHandle(IPv4SocketHandle&& other) + : SocketHandle(move(other)) + { + } + + IPv4SocketHandle(const IPv4SocketHandle&) = delete; + IPv4SocketHandle& operator=(const IPv4SocketHandle&) = delete; + + IPv4Socket* operator->() { return &socket(); } + const IPv4Socket* operator->() const { return &socket(); } + + IPv4Socket& socket() { return static_cast(SocketHandle::socket()); } + const IPv4Socket& socket() const { return static_cast(SocketHandle::socket()); } +}; diff --git a/Kernel/Net/LoopbackAdapter.h b/Kernel/Net/LoopbackAdapter.h index 56cf6c4283..a852123733 100644 --- a/Kernel/Net/LoopbackAdapter.h +++ b/Kernel/Net/LoopbackAdapter.h @@ -1,6 +1,6 @@ #pragma once -#include +#include class LoopbackAdapter final : public NetworkAdapter { public: diff --git a/Kernel/Net/MACAddress.h b/Kernel/Net/MACAddress.h new file mode 100644 index 0000000000..0c2de93b27 --- /dev/null +++ b/Kernel/Net/MACAddress.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include + +class [[gnu::packed]] MACAddress { +public: + MACAddress() { } + MACAddress(const byte data[6]) + { + memcpy(m_data, data, 6); + } + ~MACAddress() { } + + byte operator[](int i) const + { + ASSERT(i >= 0 && i < 6); + return m_data[i]; + } + + bool operator==(const MACAddress& other) const + { + return !memcmp(m_data, other.m_data, sizeof(m_data)); + } + + String to_string() const + { + return String::format("%b:%b:%b:%b:%b:%b", m_data[0], m_data[1], m_data[2], m_data[3], m_data[4], m_data[5]); + } + +private: + byte m_data[6]; +}; + +static_assert(sizeof(MACAddress) == 6); + +namespace AK { + +template<> +struct Traits { + static unsigned hash(const MACAddress& address) { return string_hash((const char*)&address, sizeof(address)); } + static void dump(const MACAddress& address) { kprintf("%s", address.to_string().characters()); } +}; + +} diff --git a/Kernel/Net/NetworkAdapter.cpp b/Kernel/Net/NetworkAdapter.cpp new file mode 100644 index 0000000000..a1e5e31c9d --- /dev/null +++ b/Kernel/Net/NetworkAdapter.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include + +static Lockable>& all_adapters() +{ + static Lockable>* table; + if (!table) + table = new Lockable>; + return *table; +} + +NetworkAdapter* NetworkAdapter::from_ipv4_address(const IPv4Address& address) +{ + LOCKER(all_adapters().lock()); + for (auto* adapter : all_adapters().resource()) { + if (adapter->ipv4_address() == address) + return adapter; + } + return nullptr; +} + +NetworkAdapter::NetworkAdapter() + : m_packet_queue_alarm(*this) +{ + // FIXME: I wanna lock :( + all_adapters().resource().set(this); +} + +NetworkAdapter::~NetworkAdapter() +{ + // FIXME: I wanna lock :( + all_adapters().resource().remove(this); +} + +void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet) +{ + int size_in_bytes = sizeof(EthernetFrameHeader) + sizeof(ARPPacket); + auto buffer = ByteBuffer::create_zeroed(size_in_bytes); + auto* eth = (EthernetFrameHeader*)buffer.pointer(); + eth->set_source(mac_address()); + eth->set_destination(destination); + eth->set_ether_type(EtherType::ARP); + memcpy(eth->payload(), &packet, sizeof(ARPPacket)); + send_raw((byte*)eth, size_in_bytes); +} + +void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, ByteBuffer&& payload) +{ + size_t size_in_bytes = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload.size(); + auto buffer = ByteBuffer::create_zeroed(size_in_bytes); + auto& eth = *(EthernetFrameHeader*)buffer.pointer(); + eth.set_source(mac_address()); + eth.set_destination(destination_mac); + eth.set_ether_type(EtherType::IPv4); + auto& ipv4 = *(IPv4Packet*)eth.payload(); + ipv4.set_version(4); + ipv4.set_internet_header_length(5); + ipv4.set_source(ipv4_address()); + ipv4.set_destination(destination_ipv4); + ipv4.set_protocol((byte)protocol); + ipv4.set_length(sizeof(IPv4Packet) + payload.size()); + ipv4.set_ident(1); + ipv4.set_ttl(64); + ipv4.set_checksum(ipv4.compute_checksum()); + memcpy(ipv4.payload(), payload.pointer(), payload.size()); + send_raw((const byte*)ð, size_in_bytes); +} + +void NetworkAdapter::did_receive(const byte* data, int length) +{ + InterruptDisabler disabler; + m_packet_queue.append(ByteBuffer::copy(data, length)); +} + +ByteBuffer NetworkAdapter::dequeue_packet() +{ + InterruptDisabler disabler; + if (m_packet_queue.is_empty()) + return { }; + return m_packet_queue.take_first(); +} + +void NetworkAdapter::set_ipv4_address(const IPv4Address& address) +{ + m_ipv4_address = address; +} + +bool PacketQueueAlarm::is_ringing() const +{ + return m_adapter.has_queued_packets(); +} diff --git a/Kernel/Net/NetworkAdapter.h b/Kernel/Net/NetworkAdapter.h new file mode 100644 index 0000000000..3a7d0755c7 --- /dev/null +++ b/Kernel/Net/NetworkAdapter.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +class NetworkAdapter; + +class PacketQueueAlarm final : public Alarm { +public: + PacketQueueAlarm(NetworkAdapter& adapter) : m_adapter(adapter) { } + virtual ~PacketQueueAlarm() override { } + virtual bool is_ringing() const override; +private: + NetworkAdapter& m_adapter; +}; + +class NetworkAdapter { +public: + static NetworkAdapter* from_ipv4_address(const IPv4Address&); + virtual ~NetworkAdapter(); + + virtual const char* class_name() const = 0; + MACAddress mac_address() { return m_mac_address; } + IPv4Address ipv4_address() const { return m_ipv4_address; } + + void set_ipv4_address(const IPv4Address&); + + void send(const MACAddress&, const ARPPacket&); + void send_ipv4(const MACAddress&, const IPv4Address&, IPv4Protocol, ByteBuffer&& payload); + + ByteBuffer dequeue_packet(); + + Alarm& packet_queue_alarm() { return m_packet_queue_alarm; } + + bool has_queued_packets() const { return !m_packet_queue.is_empty(); } + +protected: + NetworkAdapter(); + void set_mac_address(const MACAddress& mac_address) { m_mac_address = mac_address; } + virtual void send_raw(const byte*, int) = 0; + void did_receive(const byte*, int); + +private: + MACAddress m_mac_address; + IPv4Address m_ipv4_address; + PacketQueueAlarm m_packet_queue_alarm; + SinglyLinkedList m_packet_queue; +}; diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp new file mode 100644 index 0000000000..fbd73671af --- /dev/null +++ b/Kernel/Net/NetworkTask.cpp @@ -0,0 +1,340 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//#define ETHERNET_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() +{ + static Lockable>* the; + if (!the) + the = new Lockable>; + return *the; +} + +void NetworkTask_main() +{ + LoopbackAdapter::the(); + + auto* adapter_ptr = E1000NetworkAdapter::the(); + ASSERT(adapter_ptr); + auto& adapter = *adapter_ptr; + adapter.set_ipv4_address(IPv4Address(192, 168, 5, 2)); + + auto dequeue_packet = [&] () -> ByteBuffer { + if (LoopbackAdapter::the().has_queued_packets()) + return LoopbackAdapter::the().dequeue_packet(); + if (adapter.has_queued_packets()) + return adapter.dequeue_packet(); + return { }; + }; + + kprintf("NetworkTask: Enter main loop.\n"); + for (;;) { + auto packet = dequeue_packet(); + if (packet.is_null()) { + // FIXME: Wake up when one of the adapters has packets. + current->sleep(1); + continue; + } + if (packet.size() < (int)(sizeof(EthernetFrameHeader))) { + kprintf("NetworkTask: Packet is too small to be an Ethernet packet! (%d)\n", packet.size()); + continue; + } + auto& eth = *(const EthernetFrameHeader*)packet.pointer(); +#ifdef ETHERNET_DEBUG + kprintf("NetworkTask: From %s to %s, ether_type=%w, packet_length=%u\n", + eth.source().to_string().characters(), + eth.destination().to_string().characters(), + eth.ether_type(), + packet.size() + ); +#endif + + switch (eth.ether_type()) { + case EtherType::ARP: + handle_arp(eth, packet.size()); + break; + case EtherType::IPv4: + handle_ipv4(eth, packet.size()); + break; + } + } +} + +void handle_arp(const EthernetFrameHeader& eth, int frame_size) +{ + constexpr int minimum_arp_frame_size = sizeof(EthernetFrameHeader) + sizeof(ARPPacket); + if (frame_size < minimum_arp_frame_size) { + kprintf("handle_arp: Frame too small (%d, need %d)\n", frame_size, minimum_arp_frame_size); + return; + } + auto& packet = *static_cast(eth.payload()); + if (packet.hardware_type() != 1 || packet.hardware_address_length() != sizeof(MACAddress)) { + kprintf("handle_arp: Hardware type not ethernet (%w, len=%u)\n", + packet.hardware_type(), + packet.hardware_address_length() + ); + return; + } + if (packet.protocol_type() != EtherType::IPv4 || packet.protocol_address_length() != sizeof(IPv4Address)) { + kprintf("handle_arp: Protocol type not IPv4 (%w, len=%u)\n", + packet.hardware_type(), + packet.protocol_address_length() + ); + return; + } + +#ifdef ARP_DEBUG + kprintf("handle_arp: operation=%w, sender=%s/%s, target=%s/%s\n", + packet.operation(), + packet.sender_hardware_address().to_string().characters(), + packet.sender_protocol_address().to_string().characters(), + packet.target_hardware_address().to_string().characters(), + packet.target_protocol_address().to_string().characters() + ); +#endif + + if (packet.operation() == ARPOperation::Request) { + // Who has this IP address? + if (auto* adapter = NetworkAdapter::from_ipv4_address(packet.target_protocol_address())) { + // We do! + kprintf("handle_arp: Responding to ARP request for my IPv4 address (%s)\n", + adapter->ipv4_address().to_string().characters()); + ARPPacket response; + response.set_operation(ARPOperation::Response); + response.set_target_hardware_address(packet.sender_hardware_address()); + response.set_target_protocol_address(packet.sender_protocol_address()); + response.set_sender_hardware_address(adapter->mac_address()); + response.set_sender_protocol_address(adapter->ipv4_address()); + + adapter->send(packet.sender_hardware_address(), response); + } + return; + } + + if (packet.operation() == ARPOperation::Response) { + // Someone has this IPv4 address. I guess we can try to remember that. + // FIXME: Protect against ARP spamming. + // FIXME: Support static ARP table entries. + LOCKER(arp_table().lock()); + arp_table().resource().set(packet.sender_protocol_address(), packet.sender_hardware_address()); + + kprintf("ARP table (%d entries):\n", arp_table().resource().size()); + for (auto& it : arp_table().resource()) { + kprintf("%s :: %s\n", it.value.to_string().characters(), it.key.to_string().characters()); + } + } +} + +void handle_ipv4(const EthernetFrameHeader& eth, int frame_size) +{ + constexpr int minimum_ipv4_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet); + if (frame_size < minimum_ipv4_frame_size) { + kprintf("handle_ipv4: Frame too small (%d, need %d)\n", frame_size, minimum_ipv4_frame_size); + return; + } + auto& packet = *static_cast(eth.payload()); + +#ifdef IPV4_DEBUG + kprintf("handle_ipv4: source=%s, target=%s\n", + packet.source().to_string().characters(), + packet.destination().to_string().characters() + ); +#endif + + switch ((IPv4Protocol)packet.protocol()) { + case IPv4Protocol::ICMP: + 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; + } +} + +void handle_icmp(const EthernetFrameHeader& eth, int frame_size) +{ + (void)frame_size; + auto& ipv4_packet = *static_cast(eth.payload()); + auto& icmp_header = *static_cast(ipv4_packet.payload()); +#ifdef ICMP_DEBUG + kprintf("handle_icmp: source=%s, destination=%s, type=%b, code=%b\n", + ipv4_packet.source().to_string().characters(), + ipv4_packet.destination().to_string().characters(), + icmp_header.type(), + icmp_header.code() + ); +#endif + + { + LOCKER(IPv4Socket::all_sockets().lock()); + for (RetainPtr socket : IPv4Socket::all_sockets().resource()) { + LOCKER(socket->lock()); + if (socket->protocol() != (unsigned)IPv4Protocol::ICMP) + continue; + socket->did_receive(ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())); + } + } + + auto* adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination()); + if (!adapter) + return; + + if (icmp_header.type() == ICMPType::EchoRequest) { + auto& request = reinterpret_cast(icmp_header); + kprintf("handle_icmp: EchoRequest from %s: id=%u, seq=%u\n", + ipv4_packet.source().to_string().characters(), + (word)request.identifier, + (word)request.sequence_number + ); + size_t icmp_packet_size = ipv4_packet.payload_size(); + auto buffer = ByteBuffer::create_zeroed(icmp_packet_size); + auto& response = *(ICMPEchoPacket*)buffer.pointer(); + response.header.set_type(ICMPType::EchoReply); + response.header.set_code(0); + response.identifier = request.identifier; + response.sequence_number = request.sequence_number; + if (size_t icmp_payload_size = icmp_packet_size - sizeof(ICMPEchoPacket)) + memcpy(response.payload(), request.payload(), icmp_payload_size); + response.header.set_checksum(internet_checksum(&response, icmp_packet_size)); + adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, move(buffer)); + } +} + +void handle_udp(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_udp: this packet is not for me, it's for %s\n", ipv4_packet.destination().to_string().characters()); + return; + } + + auto& udp_packet = *static_cast(ipv4_packet.payload()); +#ifdef UDP_DEBUG + kprintf("handle_udp: source=%s:%u, destination=%s:%u length=%u\n", + ipv4_packet.source().to_string().characters(), + udp_packet.source_port(), + ipv4_packet.destination().to_string().characters(), + udp_packet.destination_port(), + udp_packet.length() + ); +#endif + + auto socket = UDPSocket::from_port(udp_packet.destination_port()); + if (!socket) { + kprintf("handle_udp: No UDP socket for port %u\n", udp_packet.destination_port()); + return; + } + + ASSERT(socket->type() == SOCK_DGRAM); + ASSERT(socket->source_port() == udp_packet.destination_port()); + socket->did_receive(ByteBuffer::copy(&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()); + size_t payload_size = ipv4_packet.payload_size() - tcp_packet.header_size(); + +#ifdef TCP_DEBUG + kprintf("handle_tcp: source=%s:%u, destination=%s:%u seq_no=%u, ack_no=%u, flags=%w (%s %s), window_size=%u, payload_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.has_syn() ? "SYN" : "", + tcp_packet.has_ack() ? "ACK" : "", + tcp_packet.window_size(), + payload_size + ); +#endif + + auto socket = TCPSocket::from_port(tcp_packet.destination_port()); + if (!socket) { + kprintf("handle_tcp: No TCP socket for port %u\n", tcp_packet.destination_port()); + return; + } + + ASSERT(socket->type() == SOCK_STREAM); + ASSERT(socket->source_port() == tcp_packet.destination_port()); + + if (tcp_packet.ack_number() != socket->sequence_number()) { + kprintf("handle_tcp: ack/seq mismatch: got %u, wanted %u\n", tcp_packet.ack_number(), socket->sequence_number()); + return; + } + + if (tcp_packet.has_syn() && tcp_packet.has_ack()) { + socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1); + socket->send_tcp_packet(TCPFlags::ACK); + socket->set_connected(true); + kprintf("handle_tcp: Connection established!\n"); + socket->set_state(TCPSocket::State::Connected); + return; + } + + if (tcp_packet.has_fin()) { + kprintf("handle_tcp: Got FIN, payload_size=%u\n", payload_size); + + if (payload_size != 0) + socket->did_receive(ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())); + + socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1); + socket->send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK); + socket->set_state(TCPSocket::State::Disconnecting); + return; + } + + socket->set_ack_number(tcp_packet.sequence_number() + payload_size); + kprintf("Got packet with ack_no=%u, seq_no=%u, payload_size=%u, acking it with new ack_no=%u, seq_no=%u\n", + tcp_packet.ack_number(), + tcp_packet.sequence_number(), + payload_size, + socket->ack_number(), + socket->sequence_number() + ); + socket->send_tcp_packet(TCPFlags::ACK); + + if (payload_size != 0) + socket->did_receive(ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())); +} diff --git a/Kernel/Net/NetworkTask.h b/Kernel/Net/NetworkTask.h new file mode 100644 index 0000000000..16d8817309 --- /dev/null +++ b/Kernel/Net/NetworkTask.h @@ -0,0 +1,3 @@ +#pragma once + +void NetworkTask_main(); diff --git a/Kernel/Net/Routing.h b/Kernel/Net/Routing.h index 85eb72a116..48143520eb 100644 --- a/Kernel/Net/Routing.h +++ b/Kernel/Net/Routing.h @@ -1,5 +1,5 @@ #pragma once -#include +#include NetworkAdapter* adapter_for_route_to(const IPv4Address&); diff --git a/Kernel/Net/TCP.h b/Kernel/Net/TCP.h new file mode 100644 index 0000000000..e2eac61449 --- /dev/null +++ b/Kernel/Net/TCP.h @@ -0,0 +1,69 @@ +#pragma once + +#include + +struct TCPFlags { +enum : word { + FIN = 0x01, + SYN = 0x02, + RST = 0x04, + PUSH = 0x08, + ACK = 0x10, + URG = 0x20 +}; +}; + +class [[gnu::packed]] TCPPacket { +public: + TCPPacket() { } + ~TCPPacket() { } + + size_t header_size() const { return data_offset() * sizeof(dword); } + + 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_and_data_offset & 0x1ff; } + void set_flags(word flags) { m_flags_and_data_offset = (m_flags_and_data_offset & ~0x1ff) | (flags & 0x1ff); } + + bool has_syn() const { return flags() & TCPFlags::SYN; } + bool has_ack() const { return flags() & TCPFlags::ACK; } + bool has_fin() const { return flags() & TCPFlags::FIN; } + + byte data_offset() const { return (m_flags_and_data_offset & 0xf000) >> 12; } + void set_data_offset(word data_offset) { m_flags_and_data_offset = (m_flags_and_data_offset & ~0xf000) | data_offset << 12; } + + 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 ((const byte*)this) + header_size(); } + void* payload() { return ((byte*)this) + header_size(); } + +private: + NetworkOrdered m_source_port; + NetworkOrdered m_destination_port; + NetworkOrdered m_sequence_number; + NetworkOrdered m_ack_number; + + NetworkOrdered m_flags_and_data_offset; + NetworkOrdered m_window_size; + NetworkOrdered m_checksum; + NetworkOrdered m_urgent; +}; + +static_assert(sizeof(TCPPacket) == 20); diff --git a/Kernel/Net/TCPSocket.cpp b/Kernel/Net/TCPSocket.cpp new file mode 100644 index 0000000000..af37186395 --- /dev/null +++ b/Kernel/Net/TCPSocket.cpp @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include +#include + +Lockable>& TCPSocket::sockets_by_port() +{ + static Lockable>* s_map; + if (!s_map) + s_map = new Lockable>; + return *s_map; +} + +TCPSocketHandle TCPSocket::from_port(word port) +{ + RetainPtr socket; + { + LOCKER(sockets_by_port().lock()); + auto it = sockets_by_port().resource().find(port); + if (it == sockets_by_port().resource().end()) + return { }; + socket = (*it).value; + ASSERT(socket); + } + return { move(socket) }; +} + + +TCPSocket::TCPSocket(int protocol) + : IPv4Socket(SOCK_STREAM, protocol) +{ +} + +TCPSocket::~TCPSocket() +{ + LOCKER(sockets_by_port().lock()); + sockets_by_port().resource().remove(source_port()); +} + +Retained TCPSocket::create(int protocol) +{ + return adopt(*new TCPSocket(protocol)); +} + +int TCPSocket::protocol_receive(const ByteBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) +{ + (void)flags; + (void)addr_length; + ASSERT(!packet_buffer.is_null()); + auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer()); + auto& tcp_packet = *static_cast(ipv4_packet.payload()); + size_t payload_size = packet_buffer.size() - sizeof(IPv4Packet) - tcp_packet.header_size(); + kprintf("payload_size %u, will it fit in %u?\n", payload_size, buffer_size); + ASSERT(buffer_size >= payload_size); + if (addr) { + auto& ia = *(sockaddr_in*)addr; + ia.sin_port = htons(tcp_packet.destination_port()); + } + memcpy(buffer, tcp_packet.payload(), payload_size); + return payload_size; +} + +int TCPSocket::protocol_send(const void* data, int data_length) +{ + auto* adapter = adapter_for_route_to(destination_address()); + if (!adapter) + return -EHOSTUNREACH; + send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, data, data_length); + return data_length; +} + +void TCPSocket::send_tcp_packet(word flags, const void* payload, int payload_size) +{ + // FIXME: Maybe the socket should be bound to an adapter instead of looking it up every time? + auto* adapter = adapter_for_route_to(destination_address()); + ASSERT(adapter); + + auto buffer = ByteBuffer::create_zeroed(sizeof(TCPPacket) + payload_size); + auto& tcp_packet = *(TCPPacket*)(buffer.pointer()); + ASSERT(source_port()); + tcp_packet.set_source_port(source_port()); + tcp_packet.set_destination_port(destination_port()); + tcp_packet.set_window_size(1024); + tcp_packet.set_sequence_number(m_sequence_number); + tcp_packet.set_data_offset(sizeof(TCPPacket) / sizeof(dword)); + tcp_packet.set_flags(flags); + + if (flags & TCPFlags::ACK) + tcp_packet.set_ack_number(m_ack_number); + + if (flags == TCPFlags::SYN) { + ++m_sequence_number; + } else { + m_sequence_number += payload_size; + } + + memcpy(tcp_packet.payload(), payload, payload_size); + tcp_packet.set_checksum(compute_tcp_checksum(adapter->ipv4_address(), destination_address(), tcp_packet, payload_size)); + kprintf("sending tcp packet from %s:%u to %s:%u with (%s %s) seq_no=%u, ack_no=%u\n", + adapter->ipv4_address().to_string().characters(), + source_port(), + destination_address().to_string().characters(), + destination_port(), + tcp_packet.has_syn() ? "SYN" : "", + tcp_packet.has_ack() ? "ACK" : "", + tcp_packet.sequence_number(), + tcp_packet.ack_number() + ); + adapter->send_ipv4(MACAddress(), destination_address(), IPv4Protocol::TCP, move(buffer)); +} + +NetworkOrdered TCPSocket::compute_tcp_checksum(const IPv4Address& source, const IPv4Address& destination, const TCPPacket& packet, word payload_size) +{ + struct [[gnu::packed]] PseudoHeader { + IPv4Address source; + IPv4Address destination; + byte zero; + byte protocol; + NetworkOrdered payload_size; + }; + + PseudoHeader pseudo_header { source, destination, 0, (byte)IPv4Protocol::TCP, sizeof(TCPPacket) + payload_size }; + + dword checksum = 0; + auto* w = (const NetworkOrdered*)&pseudo_header; + for (size_t i = 0; i < sizeof(pseudo_header) / sizeof(word); ++i) { + checksum += w[i]; + if (checksum > 0xffff) + checksum = (checksum >> 16) + (checksum & 0xffff); + } + w = (const NetworkOrdered*)&packet; + for (size_t i = 0; i < sizeof(packet) / sizeof(word); ++i) { + checksum += w[i]; + if (checksum > 0xffff) + checksum = (checksum >> 16) + (checksum & 0xffff); + } + ASSERT(packet.data_offset() * 4 == sizeof(TCPPacket)); + w = (const NetworkOrdered*)packet.payload(); + for (size_t i = 0; i < payload_size / sizeof(word); ++i) { + checksum += w[i]; + if (checksum > 0xffff) + checksum = (checksum >> 16) + (checksum & 0xffff); + } + if (payload_size & 1) { + word expanded_byte = ((const byte*)packet.payload())[payload_size - 1] << 8; + checksum += expanded_byte; + if (checksum > 0xffff) + checksum = (checksum >> 16) + (checksum & 0xffff); + } + return ~(checksum & 0xffff); +} + +KResult TCPSocket::protocol_connect() +{ + auto* adapter = adapter_for_route_to(destination_address()); + if (!adapter) + return KResult(-EHOSTUNREACH); + + allocate_source_port_if_needed(); + + m_sequence_number = 0; + m_ack_number = 0; + + send_tcp_packet(TCPFlags::SYN); + m_state = State::Connecting; + + current->set_blocked_socket(this); + current->block(Thread::BlockedConnect); + + ASSERT(is_connected()); + return KSuccess; +} + +int TCPSocket::protocol_allocate_source_port() +{ + static const word first_ephemeral_port = 32768; + static const word last_ephemeral_port = 60999; + static const word ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port; + word first_scan_port = first_ephemeral_port + (word)(RandomDevice::random_percentage() * ephemeral_port_range_size); + + LOCKER(sockets_by_port().lock()); + for (word port = first_scan_port;;) { + auto it = sockets_by_port().resource().find(port); + if (it == sockets_by_port().resource().end()) { + set_source_port(port); + sockets_by_port().resource().set(port, this); + return port; + } + ++port; + if (port > last_ephemeral_port) + port = first_ephemeral_port; + if (port == first_scan_port) + break; + } + return -EADDRINUSE; +} + +bool TCPSocket::protocol_is_disconnected() const +{ + return m_state == State::Disconnecting || m_state == State::Disconnected; +} diff --git a/Kernel/Net/TCPSocket.h b/Kernel/Net/TCPSocket.h new file mode 100644 index 0000000000..5a1d88b2f7 --- /dev/null +++ b/Kernel/Net/TCPSocket.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +class TCPSocket final : public IPv4Socket { +public: + static Retained create(int protocol); + virtual ~TCPSocket() override; + + enum class State { + Disconnected, + Connecting, + Connected, + Disconnecting, + }; + + State state() const { return m_state; } + void set_state(State state) { m_state = state; } + + void set_ack_number(dword n) { m_ack_number = n; } + void set_sequence_number(dword n) { m_sequence_number = n; } + dword ack_number() const { return m_ack_number; } + dword sequence_number() const { return m_sequence_number; } + + void send_tcp_packet(word flags, const void* = nullptr, int = 0); + + static Lockable>& sockets_by_port(); + static TCPSocketHandle from_port(word); + +private: + explicit TCPSocket(int protocol); + + NetworkOrdered compute_tcp_checksum(const IPv4Address& source, const IPv4Address& destination, const TCPPacket&, word payload_size); + + virtual int protocol_receive(const ByteBuffer&, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) override; + virtual int protocol_send(const void*, int) override; + virtual KResult protocol_connect() override; + virtual int protocol_allocate_source_port() override; + virtual bool protocol_is_disconnected() const override; + + dword m_sequence_number { 0 }; + dword m_ack_number { 0 }; + State m_state { State::Disconnected }; +}; + +class TCPSocketHandle : public SocketHandle { +public: + TCPSocketHandle() { } + + TCPSocketHandle(RetainPtr&& socket) + : SocketHandle(move(socket)) + { + } + + TCPSocketHandle(TCPSocketHandle&& other) + : SocketHandle(move(other)) + { + } + + TCPSocketHandle(const TCPSocketHandle&) = delete; + TCPSocketHandle& operator=(const TCPSocketHandle&) = delete; + + TCPSocket* operator->() { return &socket(); } + const TCPSocket* operator->() const { return &socket(); } + + TCPSocket& socket() { return static_cast(SocketHandle::socket()); } + const TCPSocket& socket() const { return static_cast(SocketHandle::socket()); } +}; diff --git a/Kernel/Net/UDP.h b/Kernel/Net/UDP.h new file mode 100644 index 0000000000..ba6d02af37 --- /dev/null +++ b/Kernel/Net/UDP.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +class [[gnu::packed]] UDPPacket { +public: + UDPPacket() { } + ~UDPPacket() { } + + 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; } + + word length() const { return m_length; } + void set_length(word length) { m_length = length; } + + word checksum() const { return m_checksum; } + void set_checksum(word checksum) { m_checksum = checksum; } + + const void* payload() const { return this + 1; } + void* payload() { return this + 1; } + +private: + NetworkOrdered m_source_port; + NetworkOrdered m_destination_port; + NetworkOrdered m_length; + NetworkOrdered m_checksum; +}; + +static_assert(sizeof(UDPPacket) == 8); diff --git a/Kernel/Net/UDPSocket.cpp b/Kernel/Net/UDPSocket.cpp new file mode 100644 index 0000000000..ff8c2baa82 --- /dev/null +++ b/Kernel/Net/UDPSocket.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include + +Lockable>& UDPSocket::sockets_by_port() +{ + static Lockable>* s_map; + if (!s_map) + s_map = new Lockable>; + return *s_map; +} + +UDPSocketHandle UDPSocket::from_port(word port) +{ + RetainPtr socket; + { + LOCKER(sockets_by_port().lock()); + auto it = sockets_by_port().resource().find(port); + if (it == sockets_by_port().resource().end()) + return { }; + socket = (*it).value; + ASSERT(socket); + } + return { move(socket) }; +} + + +UDPSocket::UDPSocket(int protocol) + : IPv4Socket(SOCK_DGRAM, protocol) +{ +} + +UDPSocket::~UDPSocket() +{ + LOCKER(sockets_by_port().lock()); + sockets_by_port().resource().remove(source_port()); +} + +Retained UDPSocket::create(int protocol) +{ + return adopt(*new UDPSocket(protocol)); +} + +int UDPSocket::protocol_receive(const ByteBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) +{ + (void)flags; + (void)addr_length; + ASSERT(!packet_buffer.is_null()); + auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer()); + auto& udp_packet = *static_cast(ipv4_packet.payload()); + ASSERT(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier. + ASSERT(buffer_size >= (udp_packet.length() - sizeof(UDPPacket))); + if (addr) { + auto& ia = *(sockaddr_in*)addr; + ia.sin_port = htons(udp_packet.destination_port()); + } + memcpy(buffer, udp_packet.payload(), udp_packet.length() - sizeof(UDPPacket)); + return udp_packet.length() - sizeof(UDPPacket); +} + +int UDPSocket::protocol_send(const void* data, int data_length) +{ + auto* adapter = adapter_for_route_to(destination_address()); + if (!adapter) + return -EHOSTUNREACH; + auto buffer = ByteBuffer::create_zeroed(sizeof(UDPPacket) + data_length); + auto& udp_packet = *(UDPPacket*)(buffer.pointer()); + udp_packet.set_source_port(source_port()); + udp_packet.set_destination_port(destination_port()); + udp_packet.set_length(sizeof(UDPPacket) + data_length); + memcpy(udp_packet.payload(), data, data_length); + kprintf("sending as udp packet from %s:%u to %s:%u!\n", + adapter->ipv4_address().to_string().characters(), + source_port(), + destination_address().to_string().characters(), + destination_port()); + adapter->send_ipv4(MACAddress(), destination_address(), IPv4Protocol::UDP, move(buffer)); + return data_length; +} + +KResult UDPSocket::protocol_connect() +{ + return KSuccess; +} + +int UDPSocket::protocol_allocate_source_port() +{ + static const word first_ephemeral_port = 32768; + static const word last_ephemeral_port = 60999; + static const word ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port; + word first_scan_port = first_ephemeral_port + (word)(RandomDevice::random_percentage() * ephemeral_port_range_size); + + LOCKER(sockets_by_port().lock()); + for (word port = first_scan_port;;) { + auto it = sockets_by_port().resource().find(port); + if (it == sockets_by_port().resource().end()) { + set_source_port(port); + sockets_by_port().resource().set(port, this); + return port; + } + ++port; + if (port > last_ephemeral_port) + port = first_ephemeral_port; + if (port == first_scan_port) + break; + } + return -EADDRINUSE; +} diff --git a/Kernel/Net/UDPSocket.h b/Kernel/Net/UDPSocket.h new file mode 100644 index 0000000000..904243db34 --- /dev/null +++ b/Kernel/Net/UDPSocket.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +class UDPSocketHandle; + +class UDPSocket final : public IPv4Socket { +public: + static Retained create(int protocol); + virtual ~UDPSocket() override; + + static Lockable>& sockets_by_port(); + static UDPSocketHandle from_port(word); + +private: + explicit UDPSocket(int protocol); + + virtual int protocol_receive(const ByteBuffer&, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) override; + virtual int protocol_send(const void*, int) override; + virtual KResult protocol_connect() override; + virtual int protocol_allocate_source_port() override; +}; + +class UDPSocketHandle : public SocketHandle { +public: + UDPSocketHandle() { } + + UDPSocketHandle(RetainPtr&& socket) + : SocketHandle(move(socket)) + { + } + + UDPSocketHandle(UDPSocketHandle&& other) + : SocketHandle(move(other)) + { + } + + UDPSocketHandle(const UDPSocketHandle&) = delete; + UDPSocketHandle& operator=(const UDPSocketHandle&) = delete; + + UDPSocket* operator->() { return &socket(); } + const UDPSocket* operator->() const { return &socket(); } + + UDPSocket& socket() { return static_cast(SocketHandle::socket()); } + const UDPSocket& socket() const { return static_cast(SocketHandle::socket()); } +}; + diff --git a/Kernel/NetworkAdapter.cpp b/Kernel/NetworkAdapter.cpp deleted file mode 100644 index aa4d45b9b1..0000000000 --- a/Kernel/NetworkAdapter.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -static Lockable>& all_adapters() -{ - static Lockable>* table; - if (!table) - table = new Lockable>; - return *table; -} - -NetworkAdapter* NetworkAdapter::from_ipv4_address(const IPv4Address& address) -{ - LOCKER(all_adapters().lock()); - for (auto* adapter : all_adapters().resource()) { - if (adapter->ipv4_address() == address) - return adapter; - } - return nullptr; -} - -NetworkAdapter::NetworkAdapter() - : m_packet_queue_alarm(*this) -{ - // FIXME: I wanna lock :( - all_adapters().resource().set(this); -} - -NetworkAdapter::~NetworkAdapter() -{ - // FIXME: I wanna lock :( - all_adapters().resource().remove(this); -} - -void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet) -{ - int size_in_bytes = sizeof(EthernetFrameHeader) + sizeof(ARPPacket); - auto buffer = ByteBuffer::create_zeroed(size_in_bytes); - auto* eth = (EthernetFrameHeader*)buffer.pointer(); - eth->set_source(mac_address()); - eth->set_destination(destination); - eth->set_ether_type(EtherType::ARP); - memcpy(eth->payload(), &packet, sizeof(ARPPacket)); - send_raw((byte*)eth, size_in_bytes); -} - -void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, ByteBuffer&& payload) -{ - size_t size_in_bytes = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload.size(); - auto buffer = ByteBuffer::create_zeroed(size_in_bytes); - auto& eth = *(EthernetFrameHeader*)buffer.pointer(); - eth.set_source(mac_address()); - eth.set_destination(destination_mac); - eth.set_ether_type(EtherType::IPv4); - auto& ipv4 = *(IPv4Packet*)eth.payload(); - ipv4.set_version(4); - ipv4.set_internet_header_length(5); - ipv4.set_source(ipv4_address()); - ipv4.set_destination(destination_ipv4); - ipv4.set_protocol((byte)protocol); - ipv4.set_length(sizeof(IPv4Packet) + payload.size()); - ipv4.set_ident(1); - ipv4.set_ttl(64); - ipv4.set_checksum(ipv4.compute_checksum()); - memcpy(ipv4.payload(), payload.pointer(), payload.size()); - send_raw((const byte*)ð, size_in_bytes); -} - -void NetworkAdapter::did_receive(const byte* data, int length) -{ - InterruptDisabler disabler; - m_packet_queue.append(ByteBuffer::copy(data, length)); -} - -ByteBuffer NetworkAdapter::dequeue_packet() -{ - InterruptDisabler disabler; - if (m_packet_queue.is_empty()) - return { }; - return m_packet_queue.take_first(); -} - -void NetworkAdapter::set_ipv4_address(const IPv4Address& address) -{ - m_ipv4_address = address; -} - -bool PacketQueueAlarm::is_ringing() const -{ - return m_adapter.has_queued_packets(); -} diff --git a/Kernel/NetworkAdapter.h b/Kernel/NetworkAdapter.h deleted file mode 100644 index a040aaced2..0000000000 --- a/Kernel/NetworkAdapter.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -class NetworkAdapter; - -class PacketQueueAlarm final : public Alarm { -public: - PacketQueueAlarm(NetworkAdapter& adapter) : m_adapter(adapter) { } - virtual ~PacketQueueAlarm() override { } - virtual bool is_ringing() const override; -private: - NetworkAdapter& m_adapter; -}; - -class NetworkAdapter { -public: - static NetworkAdapter* from_ipv4_address(const IPv4Address&); - virtual ~NetworkAdapter(); - - virtual const char* class_name() const = 0; - MACAddress mac_address() { return m_mac_address; } - IPv4Address ipv4_address() const { return m_ipv4_address; } - - void set_ipv4_address(const IPv4Address&); - - void send(const MACAddress&, const ARPPacket&); - void send_ipv4(const MACAddress&, const IPv4Address&, IPv4Protocol, ByteBuffer&& payload); - - ByteBuffer dequeue_packet(); - - Alarm& packet_queue_alarm() { return m_packet_queue_alarm; } - - bool has_queued_packets() const { return !m_packet_queue.is_empty(); } - -protected: - NetworkAdapter(); - void set_mac_address(const MACAddress& mac_address) { m_mac_address = mac_address; } - virtual void send_raw(const byte*, int) = 0; - void did_receive(const byte*, int); - -private: - MACAddress m_mac_address; - IPv4Address m_ipv4_address; - PacketQueueAlarm m_packet_queue_alarm; - SinglyLinkedList m_packet_queue; -}; diff --git a/Kernel/NetworkTask.cpp b/Kernel/NetworkTask.cpp deleted file mode 100644 index 9132765dc3..0000000000 --- a/Kernel/NetworkTask.cpp +++ /dev/null @@ -1,339 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//#define ETHERNET_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() -{ - static Lockable>* the; - if (!the) - the = new Lockable>; - return *the; -} - -void NetworkTask_main() -{ - LoopbackAdapter::the(); - - auto* adapter_ptr = E1000NetworkAdapter::the(); - ASSERT(adapter_ptr); - auto& adapter = *adapter_ptr; - adapter.set_ipv4_address(IPv4Address(192, 168, 5, 2)); - - auto dequeue_packet = [&] () -> ByteBuffer { - if (LoopbackAdapter::the().has_queued_packets()) - return LoopbackAdapter::the().dequeue_packet(); - if (adapter.has_queued_packets()) - return adapter.dequeue_packet(); - return { }; - }; - - kprintf("NetworkTask: Enter main loop.\n"); - for (;;) { - auto packet = dequeue_packet(); - if (packet.is_null()) { - // FIXME: Wake up when one of the adapters has packets. - current->sleep(1); - continue; - } - if (packet.size() < (int)(sizeof(EthernetFrameHeader))) { - kprintf("NetworkTask: Packet is too small to be an Ethernet packet! (%d)\n", packet.size()); - continue; - } - auto& eth = *(const EthernetFrameHeader*)packet.pointer(); -#ifdef ETHERNET_DEBUG - kprintf("NetworkTask: From %s to %s, ether_type=%w, packet_length=%u\n", - eth.source().to_string().characters(), - eth.destination().to_string().characters(), - eth.ether_type(), - packet.size() - ); -#endif - - switch (eth.ether_type()) { - case EtherType::ARP: - handle_arp(eth, packet.size()); - break; - case EtherType::IPv4: - handle_ipv4(eth, packet.size()); - break; - } - } -} - -void handle_arp(const EthernetFrameHeader& eth, int frame_size) -{ - constexpr int minimum_arp_frame_size = sizeof(EthernetFrameHeader) + sizeof(ARPPacket); - if (frame_size < minimum_arp_frame_size) { - kprintf("handle_arp: Frame too small (%d, need %d)\n", frame_size, minimum_arp_frame_size); - return; - } - auto& packet = *static_cast(eth.payload()); - if (packet.hardware_type() != 1 || packet.hardware_address_length() != sizeof(MACAddress)) { - kprintf("handle_arp: Hardware type not ethernet (%w, len=%u)\n", - packet.hardware_type(), - packet.hardware_address_length() - ); - return; - } - if (packet.protocol_type() != EtherType::IPv4 || packet.protocol_address_length() != sizeof(IPv4Address)) { - kprintf("handle_arp: Protocol type not IPv4 (%w, len=%u)\n", - packet.hardware_type(), - packet.protocol_address_length() - ); - return; - } - -#ifdef ARP_DEBUG - kprintf("handle_arp: operation=%w, sender=%s/%s, target=%s/%s\n", - packet.operation(), - packet.sender_hardware_address().to_string().characters(), - packet.sender_protocol_address().to_string().characters(), - packet.target_hardware_address().to_string().characters(), - packet.target_protocol_address().to_string().characters() - ); -#endif - - if (packet.operation() == ARPOperation::Request) { - // Who has this IP address? - if (auto* adapter = NetworkAdapter::from_ipv4_address(packet.target_protocol_address())) { - // We do! - kprintf("handle_arp: Responding to ARP request for my IPv4 address (%s)\n", - adapter->ipv4_address().to_string().characters()); - ARPPacket response; - response.set_operation(ARPOperation::Response); - response.set_target_hardware_address(packet.sender_hardware_address()); - response.set_target_protocol_address(packet.sender_protocol_address()); - response.set_sender_hardware_address(adapter->mac_address()); - response.set_sender_protocol_address(adapter->ipv4_address()); - - adapter->send(packet.sender_hardware_address(), response); - } - return; - } - - if (packet.operation() == ARPOperation::Response) { - // Someone has this IPv4 address. I guess we can try to remember that. - // FIXME: Protect against ARP spamming. - // FIXME: Support static ARP table entries. - LOCKER(arp_table().lock()); - arp_table().resource().set(packet.sender_protocol_address(), packet.sender_hardware_address()); - - kprintf("ARP table (%d entries):\n", arp_table().resource().size()); - for (auto& it : arp_table().resource()) { - kprintf("%s :: %s\n", it.value.to_string().characters(), it.key.to_string().characters()); - } - } -} - -void handle_ipv4(const EthernetFrameHeader& eth, int frame_size) -{ - constexpr int minimum_ipv4_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet); - if (frame_size < minimum_ipv4_frame_size) { - kprintf("handle_ipv4: Frame too small (%d, need %d)\n", frame_size, minimum_ipv4_frame_size); - return; - } - auto& packet = *static_cast(eth.payload()); - -#ifdef IPV4_DEBUG - kprintf("handle_ipv4: source=%s, target=%s\n", - packet.source().to_string().characters(), - packet.destination().to_string().characters() - ); -#endif - - switch ((IPv4Protocol)packet.protocol()) { - case IPv4Protocol::ICMP: - 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; - } -} - -void handle_icmp(const EthernetFrameHeader& eth, int frame_size) -{ - (void)frame_size; - auto& ipv4_packet = *static_cast(eth.payload()); - auto& icmp_header = *static_cast(ipv4_packet.payload()); -#ifdef ICMP_DEBUG - kprintf("handle_icmp: source=%s, destination=%s, type=%b, code=%b\n", - ipv4_packet.source().to_string().characters(), - ipv4_packet.destination().to_string().characters(), - icmp_header.type(), - icmp_header.code() - ); -#endif - - { - LOCKER(IPv4Socket::all_sockets().lock()); - for (RetainPtr socket : IPv4Socket::all_sockets().resource()) { - LOCKER(socket->lock()); - if (socket->protocol() != (unsigned)IPv4Protocol::ICMP) - continue; - socket->did_receive(ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())); - } - } - - auto* adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination()); - if (!adapter) - return; - - if (icmp_header.type() == ICMPType::EchoRequest) { - auto& request = reinterpret_cast(icmp_header); - kprintf("handle_icmp: EchoRequest from %s: id=%u, seq=%u\n", - ipv4_packet.source().to_string().characters(), - (word)request.identifier, - (word)request.sequence_number - ); - size_t icmp_packet_size = ipv4_packet.payload_size(); - auto buffer = ByteBuffer::create_zeroed(icmp_packet_size); - auto& response = *(ICMPEchoPacket*)buffer.pointer(); - response.header.set_type(ICMPType::EchoReply); - response.header.set_code(0); - response.identifier = request.identifier; - response.sequence_number = request.sequence_number; - if (size_t icmp_payload_size = icmp_packet_size - sizeof(ICMPEchoPacket)) - memcpy(response.payload(), request.payload(), icmp_payload_size); - response.header.set_checksum(internet_checksum(&response, icmp_packet_size)); - adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, move(buffer)); - } -} - -void handle_udp(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_udp: this packet is not for me, it's for %s\n", ipv4_packet.destination().to_string().characters()); - return; - } - - auto& udp_packet = *static_cast(ipv4_packet.payload()); -#ifdef UDP_DEBUG - kprintf("handle_udp: source=%s:%u, destination=%s:%u length=%u\n", - ipv4_packet.source().to_string().characters(), - udp_packet.source_port(), - ipv4_packet.destination().to_string().characters(), - udp_packet.destination_port(), - udp_packet.length() - ); -#endif - - auto socket = UDPSocket::from_port(udp_packet.destination_port()); - if (!socket) { - kprintf("handle_udp: No UDP socket for port %u\n", udp_packet.destination_port()); - return; - } - - ASSERT(socket->type() == SOCK_DGRAM); - ASSERT(socket->source_port() == udp_packet.destination_port()); - socket->did_receive(ByteBuffer::copy(&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()); - size_t payload_size = ipv4_packet.payload_size() - tcp_packet.header_size(); - -#ifdef TCP_DEBUG - kprintf("handle_tcp: source=%s:%u, destination=%s:%u seq_no=%u, ack_no=%u, flags=%w (%s %s), window_size=%u, payload_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.has_syn() ? "SYN" : "", - tcp_packet.has_ack() ? "ACK" : "", - tcp_packet.window_size(), - payload_size - ); -#endif - - auto socket = TCPSocket::from_port(tcp_packet.destination_port()); - if (!socket) { - kprintf("handle_tcp: No TCP socket for port %u\n", tcp_packet.destination_port()); - return; - } - - ASSERT(socket->type() == SOCK_STREAM); - ASSERT(socket->source_port() == tcp_packet.destination_port()); - - if (tcp_packet.ack_number() != socket->sequence_number()) { - kprintf("handle_tcp: ack/seq mismatch: got %u, wanted %u\n", tcp_packet.ack_number(), socket->sequence_number()); - return; - } - - if (tcp_packet.has_syn() && tcp_packet.has_ack()) { - socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1); - socket->send_tcp_packet(TCPFlags::ACK); - socket->set_connected(true); - kprintf("handle_tcp: Connection established!\n"); - socket->set_state(TCPSocket::State::Connected); - return; - } - - if (tcp_packet.has_fin()) { - kprintf("handle_tcp: Got FIN, payload_size=%u\n", payload_size); - - if (payload_size != 0) - socket->did_receive(ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())); - - socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1); - socket->send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK); - socket->set_state(TCPSocket::State::Disconnecting); - return; - } - - socket->set_ack_number(tcp_packet.sequence_number() + payload_size); - kprintf("Got packet with ack_no=%u, seq_no=%u, payload_size=%u, acking it with new ack_no=%u, seq_no=%u\n", - tcp_packet.ack_number(), - tcp_packet.sequence_number(), - payload_size, - socket->ack_number(), - socket->sequence_number() - ); - socket->send_tcp_packet(TCPFlags::ACK); - - if (payload_size != 0) - socket->did_receive(ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())); -} diff --git a/Kernel/NetworkTask.h b/Kernel/NetworkTask.h deleted file mode 100644 index 16d8817309..0000000000 --- a/Kernel/NetworkTask.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void NetworkTask_main(); diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index e4445667bd..e8781ab047 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -22,9 +22,6 @@ #include "MasterPTY.h" #include "elf.h" #include -#include -#include -#include //#define DEBUG_IO //#define TASK_DEBUG diff --git a/Kernel/Socket.cpp b/Kernel/Socket.cpp index e6e26114b6..78adac287a 100644 --- a/Kernel/Socket.cpp +++ b/Kernel/Socket.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/Kernel/TCP.h b/Kernel/TCP.h deleted file mode 100644 index 989f7b3739..0000000000 --- a/Kernel/TCP.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include - -struct TCPFlags { -enum : word { - FIN = 0x01, - SYN = 0x02, - RST = 0x04, - PUSH = 0x08, - ACK = 0x10, - URG = 0x20 -}; -}; - -class [[gnu::packed]] TCPPacket { -public: - TCPPacket() { } - ~TCPPacket() { } - - size_t header_size() const { return data_offset() * sizeof(dword); } - - 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_and_data_offset & 0x1ff; } - void set_flags(word flags) { m_flags_and_data_offset = (m_flags_and_data_offset & ~0x1ff) | (flags & 0x1ff); } - - bool has_syn() const { return flags() & TCPFlags::SYN; } - bool has_ack() const { return flags() & TCPFlags::ACK; } - bool has_fin() const { return flags() & TCPFlags::FIN; } - - byte data_offset() const { return (m_flags_and_data_offset & 0xf000) >> 12; } - void set_data_offset(word data_offset) { m_flags_and_data_offset = (m_flags_and_data_offset & ~0xf000) | data_offset << 12; } - - 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 ((const byte*)this) + header_size(); } - void* payload() { return ((byte*)this) + header_size(); } - -private: - NetworkOrdered m_source_port; - NetworkOrdered m_destination_port; - NetworkOrdered m_sequence_number; - NetworkOrdered m_ack_number; - - NetworkOrdered m_flags_and_data_offset; - NetworkOrdered m_window_size; - NetworkOrdered m_checksum; - NetworkOrdered m_urgent; -}; - -static_assert(sizeof(TCPPacket) == 20); diff --git a/Kernel/TCPSocket.cpp b/Kernel/TCPSocket.cpp deleted file mode 100644 index dd856314e4..0000000000 --- a/Kernel/TCPSocket.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include -#include -#include -#include -#include -#include - -Lockable>& TCPSocket::sockets_by_port() -{ - static Lockable>* s_map; - if (!s_map) - s_map = new Lockable>; - return *s_map; -} - -TCPSocketHandle TCPSocket::from_port(word port) -{ - RetainPtr socket; - { - LOCKER(sockets_by_port().lock()); - auto it = sockets_by_port().resource().find(port); - if (it == sockets_by_port().resource().end()) - return { }; - socket = (*it).value; - ASSERT(socket); - } - return { move(socket) }; -} - - -TCPSocket::TCPSocket(int protocol) - : IPv4Socket(SOCK_STREAM, protocol) -{ -} - -TCPSocket::~TCPSocket() -{ - LOCKER(sockets_by_port().lock()); - sockets_by_port().resource().remove(source_port()); -} - -Retained TCPSocket::create(int protocol) -{ - return adopt(*new TCPSocket(protocol)); -} - -int TCPSocket::protocol_receive(const ByteBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) -{ - (void)flags; - (void)addr_length; - ASSERT(!packet_buffer.is_null()); - auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer()); - auto& tcp_packet = *static_cast(ipv4_packet.payload()); - size_t payload_size = packet_buffer.size() - sizeof(IPv4Packet) - tcp_packet.header_size(); - kprintf("payload_size %u, will it fit in %u?\n", payload_size, buffer_size); - ASSERT(buffer_size >= payload_size); - if (addr) { - auto& ia = *(sockaddr_in*)addr; - ia.sin_port = htons(tcp_packet.destination_port()); - } - memcpy(buffer, tcp_packet.payload(), payload_size); - return payload_size; -} - -int TCPSocket::protocol_send(const void* data, int data_length) -{ - auto* adapter = adapter_for_route_to(destination_address()); - if (!adapter) - return -EHOSTUNREACH; - send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, data, data_length); - return data_length; -} - -void TCPSocket::send_tcp_packet(word flags, const void* payload, int payload_size) -{ - // FIXME: Maybe the socket should be bound to an adapter instead of looking it up every time? - auto* adapter = adapter_for_route_to(destination_address()); - ASSERT(adapter); - - auto buffer = ByteBuffer::create_zeroed(sizeof(TCPPacket) + payload_size); - auto& tcp_packet = *(TCPPacket*)(buffer.pointer()); - ASSERT(source_port()); - tcp_packet.set_source_port(source_port()); - tcp_packet.set_destination_port(destination_port()); - tcp_packet.set_window_size(1024); - tcp_packet.set_sequence_number(m_sequence_number); - tcp_packet.set_data_offset(sizeof(TCPPacket) / sizeof(dword)); - tcp_packet.set_flags(flags); - - if (flags & TCPFlags::ACK) - tcp_packet.set_ack_number(m_ack_number); - - if (flags == TCPFlags::SYN) { - ++m_sequence_number; - } else { - m_sequence_number += payload_size; - } - - memcpy(tcp_packet.payload(), payload, payload_size); - tcp_packet.set_checksum(compute_tcp_checksum(adapter->ipv4_address(), destination_address(), tcp_packet, payload_size)); - kprintf("sending tcp packet from %s:%u to %s:%u with (%s %s) seq_no=%u, ack_no=%u\n", - adapter->ipv4_address().to_string().characters(), - source_port(), - destination_address().to_string().characters(), - destination_port(), - tcp_packet.has_syn() ? "SYN" : "", - tcp_packet.has_ack() ? "ACK" : "", - tcp_packet.sequence_number(), - tcp_packet.ack_number() - ); - adapter->send_ipv4(MACAddress(), destination_address(), IPv4Protocol::TCP, move(buffer)); -} - -NetworkOrdered TCPSocket::compute_tcp_checksum(const IPv4Address& source, const IPv4Address& destination, const TCPPacket& packet, word payload_size) -{ - struct [[gnu::packed]] PseudoHeader { - IPv4Address source; - IPv4Address destination; - byte zero; - byte protocol; - NetworkOrdered payload_size; - }; - - PseudoHeader pseudo_header { source, destination, 0, (byte)IPv4Protocol::TCP, sizeof(TCPPacket) + payload_size }; - - dword checksum = 0; - auto* w = (const NetworkOrdered*)&pseudo_header; - for (size_t i = 0; i < sizeof(pseudo_header) / sizeof(word); ++i) { - checksum += w[i]; - if (checksum > 0xffff) - checksum = (checksum >> 16) + (checksum & 0xffff); - } - w = (const NetworkOrdered*)&packet; - for (size_t i = 0; i < sizeof(packet) / sizeof(word); ++i) { - checksum += w[i]; - if (checksum > 0xffff) - checksum = (checksum >> 16) + (checksum & 0xffff); - } - ASSERT(packet.data_offset() * 4 == sizeof(TCPPacket)); - w = (const NetworkOrdered*)packet.payload(); - for (size_t i = 0; i < payload_size / sizeof(word); ++i) { - checksum += w[i]; - if (checksum > 0xffff) - checksum = (checksum >> 16) + (checksum & 0xffff); - } - if (payload_size & 1) { - word expanded_byte = ((const byte*)packet.payload())[payload_size - 1] << 8; - checksum += expanded_byte; - if (checksum > 0xffff) - checksum = (checksum >> 16) + (checksum & 0xffff); - } - return ~(checksum & 0xffff); -} - -KResult TCPSocket::protocol_connect() -{ - auto* adapter = adapter_for_route_to(destination_address()); - if (!adapter) - return KResult(-EHOSTUNREACH); - - allocate_source_port_if_needed(); - - m_sequence_number = 0; - m_ack_number = 0; - - send_tcp_packet(TCPFlags::SYN); - m_state = State::Connecting; - - current->set_blocked_socket(this); - current->block(Thread::BlockedConnect); - - ASSERT(is_connected()); - return KSuccess; -} - -int TCPSocket::protocol_allocate_source_port() -{ - static const word first_ephemeral_port = 32768; - static const word last_ephemeral_port = 60999; - static const word ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port; - word first_scan_port = first_ephemeral_port + (word)(RandomDevice::random_percentage() * ephemeral_port_range_size); - - LOCKER(sockets_by_port().lock()); - for (word port = first_scan_port;;) { - auto it = sockets_by_port().resource().find(port); - if (it == sockets_by_port().resource().end()) { - set_source_port(port); - sockets_by_port().resource().set(port, this); - return port; - } - ++port; - if (port > last_ephemeral_port) - port = first_ephemeral_port; - if (port == first_scan_port) - break; - } - return -EADDRINUSE; -} - -bool TCPSocket::protocol_is_disconnected() const -{ - return m_state == State::Disconnecting || m_state == State::Disconnected; -} diff --git a/Kernel/TCPSocket.h b/Kernel/TCPSocket.h deleted file mode 100644 index 1d59a41e83..0000000000 --- a/Kernel/TCPSocket.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include - -class TCPSocket final : public IPv4Socket { -public: - static Retained create(int protocol); - virtual ~TCPSocket() override; - - enum class State { - Disconnected, - Connecting, - Connected, - Disconnecting, - }; - - State state() const { return m_state; } - void set_state(State state) { m_state = state; } - - void set_ack_number(dword n) { m_ack_number = n; } - void set_sequence_number(dword n) { m_sequence_number = n; } - dword ack_number() const { return m_ack_number; } - dword sequence_number() const { return m_sequence_number; } - - void send_tcp_packet(word flags, const void* = nullptr, int = 0); - - static Lockable>& sockets_by_port(); - static TCPSocketHandle from_port(word); - -private: - explicit TCPSocket(int protocol); - - NetworkOrdered compute_tcp_checksum(const IPv4Address& source, const IPv4Address& destination, const TCPPacket&, word payload_size); - - virtual int protocol_receive(const ByteBuffer&, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) override; - virtual int protocol_send(const void*, int) override; - virtual KResult protocol_connect() override; - virtual int protocol_allocate_source_port() override; - virtual bool protocol_is_disconnected() const override; - - dword m_sequence_number { 0 }; - dword m_ack_number { 0 }; - State m_state { State::Disconnected }; -}; - -class TCPSocketHandle : public SocketHandle { -public: - TCPSocketHandle() { } - - TCPSocketHandle(RetainPtr&& socket) - : SocketHandle(move(socket)) - { - } - - TCPSocketHandle(TCPSocketHandle&& other) - : SocketHandle(move(other)) - { - } - - TCPSocketHandle(const TCPSocketHandle&) = delete; - TCPSocketHandle& operator=(const TCPSocketHandle&) = delete; - - TCPSocket* operator->() { return &socket(); } - const TCPSocket* operator->() const { return &socket(); } - - TCPSocket& socket() { return static_cast(SocketHandle::socket()); } - const TCPSocket& socket() const { return static_cast(SocketHandle::socket()); } -}; diff --git a/Kernel/UDP.h b/Kernel/UDP.h deleted file mode 100644 index c4da36b7a5..0000000000 --- a/Kernel/UDP.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -class [[gnu::packed]] UDPPacket { -public: - UDPPacket() { } - ~UDPPacket() { } - - 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; } - - word length() const { return m_length; } - void set_length(word length) { m_length = length; } - - word checksum() const { return m_checksum; } - void set_checksum(word checksum) { m_checksum = checksum; } - - const void* payload() const { return this + 1; } - void* payload() { return this + 1; } - -private: - NetworkOrdered m_source_port; - NetworkOrdered m_destination_port; - NetworkOrdered m_length; - NetworkOrdered m_checksum; -}; - -static_assert(sizeof(UDPPacket) == 8); diff --git a/Kernel/UDPSocket.cpp b/Kernel/UDPSocket.cpp deleted file mode 100644 index c54d94a16f..0000000000 --- a/Kernel/UDPSocket.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include -#include -#include -#include -#include -#include - -Lockable>& UDPSocket::sockets_by_port() -{ - static Lockable>* s_map; - if (!s_map) - s_map = new Lockable>; - return *s_map; -} - -UDPSocketHandle UDPSocket::from_port(word port) -{ - RetainPtr socket; - { - LOCKER(sockets_by_port().lock()); - auto it = sockets_by_port().resource().find(port); - if (it == sockets_by_port().resource().end()) - return { }; - socket = (*it).value; - ASSERT(socket); - } - return { move(socket) }; -} - - -UDPSocket::UDPSocket(int protocol) - : IPv4Socket(SOCK_DGRAM, protocol) -{ -} - -UDPSocket::~UDPSocket() -{ - LOCKER(sockets_by_port().lock()); - sockets_by_port().resource().remove(source_port()); -} - -Retained UDPSocket::create(int protocol) -{ - return adopt(*new UDPSocket(protocol)); -} - -int UDPSocket::protocol_receive(const ByteBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) -{ - (void)flags; - (void)addr_length; - ASSERT(!packet_buffer.is_null()); - auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer()); - auto& udp_packet = *static_cast(ipv4_packet.payload()); - ASSERT(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier. - ASSERT(buffer_size >= (udp_packet.length() - sizeof(UDPPacket))); - if (addr) { - auto& ia = *(sockaddr_in*)addr; - ia.sin_port = htons(udp_packet.destination_port()); - } - memcpy(buffer, udp_packet.payload(), udp_packet.length() - sizeof(UDPPacket)); - return udp_packet.length() - sizeof(UDPPacket); -} - -int UDPSocket::protocol_send(const void* data, int data_length) -{ - auto* adapter = adapter_for_route_to(destination_address()); - if (!adapter) - return -EHOSTUNREACH; - auto buffer = ByteBuffer::create_zeroed(sizeof(UDPPacket) + data_length); - auto& udp_packet = *(UDPPacket*)(buffer.pointer()); - udp_packet.set_source_port(source_port()); - udp_packet.set_destination_port(destination_port()); - udp_packet.set_length(sizeof(UDPPacket) + data_length); - memcpy(udp_packet.payload(), data, data_length); - kprintf("sending as udp packet from %s:%u to %s:%u!\n", - adapter->ipv4_address().to_string().characters(), - source_port(), - destination_address().to_string().characters(), - destination_port()); - adapter->send_ipv4(MACAddress(), destination_address(), IPv4Protocol::UDP, move(buffer)); - return data_length; -} - -KResult UDPSocket::protocol_connect() -{ - return KSuccess; -} - -int UDPSocket::protocol_allocate_source_port() -{ - static const word first_ephemeral_port = 32768; - static const word last_ephemeral_port = 60999; - static const word ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port; - word first_scan_port = first_ephemeral_port + (word)(RandomDevice::random_percentage() * ephemeral_port_range_size); - - LOCKER(sockets_by_port().lock()); - for (word port = first_scan_port;;) { - auto it = sockets_by_port().resource().find(port); - if (it == sockets_by_port().resource().end()) { - set_source_port(port); - sockets_by_port().resource().set(port, this); - return port; - } - ++port; - if (port > last_ephemeral_port) - port = first_ephemeral_port; - if (port == first_scan_port) - break; - } - return -EADDRINUSE; -} diff --git a/Kernel/UDPSocket.h b/Kernel/UDPSocket.h deleted file mode 100644 index 69c3a66a24..0000000000 --- a/Kernel/UDPSocket.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include - -class UDPSocketHandle; - -class UDPSocket final : public IPv4Socket { -public: - static Retained create(int protocol); - virtual ~UDPSocket() override; - - static Lockable>& sockets_by_port(); - static UDPSocketHandle from_port(word); - -private: - explicit UDPSocket(int protocol); - - virtual int protocol_receive(const ByteBuffer&, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) override; - virtual int protocol_send(const void*, int) override; - virtual KResult protocol_connect() override; - virtual int protocol_allocate_source_port() override; -}; - -class UDPSocketHandle : public SocketHandle { -public: - UDPSocketHandle() { } - - UDPSocketHandle(RetainPtr&& socket) - : SocketHandle(move(socket)) - { - } - - UDPSocketHandle(UDPSocketHandle&& other) - : SocketHandle(move(other)) - { - } - - UDPSocketHandle(const UDPSocketHandle&) = delete; - UDPSocketHandle& operator=(const UDPSocketHandle&) = delete; - - UDPSocket* operator->() { return &socket(); } - const UDPSocket* operator->() const { return &socket(); } - - UDPSocket& socket() { return static_cast(SocketHandle::socket()); } - const UDPSocket& socket() const { return static_cast(SocketHandle::socket()); } -}; - diff --git a/Kernel/init.cpp b/Kernel/init.cpp index d31ce1013a..e896dce1dc 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -23,8 +23,8 @@ #include "PTYMultiplexer.h" #include "DevPtsFS.h" #include "BXVGADevice.h" -#include "E1000NetworkAdapter.h" -#include +#include +#include #define SPAWN_LAUNCHER //#define SPAWN_GUITEST2 -- cgit v1.2.3