summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/.gitignore1
-rw-r--r--Kernel/ARPPacket.h52
-rw-r--r--Kernel/E1000NetworkAdapter.cpp52
-rw-r--r--Kernel/E1000NetworkAdapter.h2
-rw-r--r--Kernel/EtherType.h10
-rw-r--r--Kernel/EthernetFrameHeader.h4
-rw-r--r--Kernel/IPv4Address.h44
-rw-r--r--Kernel/NetworkAdapter.cpp7
-rw-r--r--Kernel/NetworkAdapter.h5
-rw-r--r--Kernel/NetworkTask.cpp87
-rw-r--r--Kernel/StdLib.h3
-rwxr-xr-xKernel/run2
12 files changed, 229 insertions, 40 deletions
diff --git a/Kernel/.gitignore b/Kernel/.gitignore
index 69c0ff7371..cef27ed586 100644
--- a/Kernel/.gitignore
+++ b/Kernel/.gitignore
@@ -6,3 +6,4 @@ kernel
kernel.map
_fs_contents
sync-local.sh
+*.pcap
diff --git a/Kernel/ARPPacket.h b/Kernel/ARPPacket.h
index f77f10b443..72cb75b625 100644
--- a/Kernel/ARPPacket.h
+++ b/Kernel/ARPPacket.h
@@ -1,14 +1,48 @@
#pragma once
+#include <Kernel/MACAddress.h>
+#include <Kernel/IPv4Address.h>
+#include <Kernel/EtherType.h>
+
class [[gnu::packed]] ARPPacket {
public:
- word hardware_type;
- word protocol_type;
- word hardware_address_length;
- word protocol_address_length;
- word operation;
- uint8_t sender_hardware_address[6]; // Sender hardware address.
- uint8_t sender_protocol_address[4]; // Sender protocol address.
- uint8_t target_hardware_address[6]; // target hardware address.
- uint8_t target_protocol_address[4]; // target protocol address.
+ 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
index b70bf79a0d..05e1c79253 100644
--- a/Kernel/E1000NetworkAdapter.cpp
+++ b/Kernel/E1000NetworkAdapter.cpp
@@ -230,7 +230,6 @@ void E1000NetworkAdapter::initialize_rx_descriptors()
out32(REG_RXDESCLEN, number_of_rx_descriptors * sizeof(e1000_rx_desc));
out32(REG_RXDESCHEAD, 0);
out32(REG_RXDESCTAIL, number_of_rx_descriptors - 1);
- m_rx_current = 0;
out32(REG_RCTRL, RCTL_EN| RCTL_SBP| RCTL_UPE | RCTL_MPE | RCTL_LBM_NONE | RTCL_RDMTS_HALF | RCTL_BAM | RCTL_SECRC | RCTL_BSIZE_8192);
}
@@ -244,7 +243,7 @@ void E1000NetworkAdapter::initialize_tx_descriptors()
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 = 0;
+ descriptor.addr = (qword)kmalloc_eternal(8192 + 16);
descriptor.cmd = 0;
}
@@ -252,10 +251,9 @@ void E1000NetworkAdapter::initialize_tx_descriptors()
out32(REG_TXDESCHI, 0);
out32(REG_TXDESCLEN, number_of_tx_descriptors * sizeof(e1000_tx_desc));
out32(REG_TXDESCHEAD, 0);
- out32(REG_TXDESCTAIL, number_of_tx_descriptors - 1);
- m_tx_current = 0;
+ out32(REG_TXDESCTAIL, 0);
- out32(REG_TCTRL, 0b0110000000000111111000011111010);
+ out32(REG_TCTRL, in32(REG_TCTRL) | TCTL_EN | TCTL_PSP);
out32(REG_TIPG, 0x0060200A);
}
@@ -312,29 +310,45 @@ dword E1000NetworkAdapter::in32(word 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);
- auto& descriptor = m_tx_descriptors[m_tx_current];
- descriptor.addr = (uint64_t)data;
+#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;
- m_tx_current = (m_tx_current + 1) % number_of_tx_descriptors;
- out32(REG_TXDESCTAIL, m_tx_current);
- while (!(descriptor.status & 0xff))
+#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)
;
- kprintf("E1000: Sent packet!\n");
+#ifdef E1000_DEBUG
+ kprintf("E1000: Sent packet, status is now %b!\n", descriptor.status);
+#endif
}
void E1000NetworkAdapter::receive()
{
- while (m_rx_descriptors[m_rx_current].status & 1) {
- auto* buffer = (byte*)m_rx_descriptors[m_rx_current].addr;
- word length = m_rx_descriptors[m_rx_current].length;
-
+ 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[m_rx_current].status = 0;
- auto old_current = m_rx_current;
- m_rx_current = (m_rx_current + 1) % number_of_rx_descriptors;
- out32(REG_RXDESCTAIL, old_current);
+ m_rx_descriptors[rx_current].status = 0;
+ out32(REG_RXDESCTAIL, rx_current);
}
}
diff --git a/Kernel/E1000NetworkAdapter.h b/Kernel/E1000NetworkAdapter.h
index 55390561ce..0bd47cda8b 100644
--- a/Kernel/E1000NetworkAdapter.h
+++ b/Kernel/E1000NetworkAdapter.h
@@ -71,6 +71,4 @@ private:
e1000_rx_desc* m_rx_descriptors;
e1000_tx_desc* m_tx_descriptors;
- word m_rx_current { 0 };
- word m_tx_current { 0 };
};
diff --git a/Kernel/EtherType.h b/Kernel/EtherType.h
new file mode 100644
index 0000000000..027967ff77
--- /dev/null
+++ b/Kernel/EtherType.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <AK/Types.h>
+
+struct EtherType {
+enum : word {
+ ARP = 0x0806,
+ IPv4 = 0x0800,
+};
+};
diff --git a/Kernel/EthernetFrameHeader.h b/Kernel/EthernetFrameHeader.h
index a90ca5503b..f6f74b42bb 100644
--- a/Kernel/EthernetFrameHeader.h
+++ b/Kernel/EthernetFrameHeader.h
@@ -13,8 +13,8 @@ public:
MACAddress source() const { return m_source; }
void set_source(const MACAddress& address) { m_source = address; }
- word ether_type() const { return (m_ether_type & 0xff) << 16 | ((m_ether_type >> 16) & 0xff); }
- void set_ether_type(word ether_type) { m_ether_type = (ether_type & 0xff) << 16 | ((ether_type >> 16) & 0xff); }
+ word ether_type() const { return ntohs(m_ether_type); }
+ void set_ether_type(word ether_type) { m_ether_type = htons(ether_type); }
const void* payload() const { return &m_payload[0]; }
void* payload() { return &m_payload[0]; }
diff --git a/Kernel/IPv4Address.h b/Kernel/IPv4Address.h
new file mode 100644
index 0000000000..d1f82c0114
--- /dev/null
+++ b/Kernel/IPv4Address.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <AK/Assertions.h>
+#include <AK/AKString.h>
+#include <AK/Types.h>
+#include <Kernel/StdLib.h>
+
+class [[gnu::packed]] IPv4Address {
+public:
+ IPv4Address() { }
+ IPv4Address(const byte data[4])
+ {
+ memcpy(m_data, data, 4);
+ }
+ 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;
+ }
+ ~IPv4Address() { }
+
+ 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; }
+
+private:
+ union {
+ byte m_data[4];
+ dword m_data_as_dword;
+ };
+};
+
+static_assert(sizeof(IPv4Address) == 4);
diff --git a/Kernel/NetworkAdapter.cpp b/Kernel/NetworkAdapter.cpp
index 6d46c5c660..b7e29967ae 100644
--- a/Kernel/NetworkAdapter.cpp
+++ b/Kernel/NetworkAdapter.cpp
@@ -2,6 +2,7 @@
#include <Kernel/StdLib.h>
#include <Kernel/EthernetFrameHeader.h>
#include <Kernel/kmalloc.h>
+#include <Kernel/EtherType.h>
NetworkAdapter::NetworkAdapter()
{
@@ -17,6 +18,7 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet
auto* eth = (EthernetFrameHeader*)kmalloc(size_in_bytes);
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);
kfree(eth);
@@ -35,3 +37,8 @@ ByteBuffer NetworkAdapter::dequeue_packet()
return { };
return m_packet_queue.take_first();
}
+
+void NetworkAdapter::set_ipv4_address(const IPv4Address& address)
+{
+ m_ipv4_address = address;
+}
diff --git a/Kernel/NetworkAdapter.h b/Kernel/NetworkAdapter.h
index 38ccb8ce10..01c69b9a25 100644
--- a/Kernel/NetworkAdapter.h
+++ b/Kernel/NetworkAdapter.h
@@ -4,6 +4,7 @@
#include <AK/SinglyLinkedList.h>
#include <AK/Types.h>
#include <Kernel/MACAddress.h>
+#include <Kernel/IPv4Address.h>
#include <Kernel/ARPPacket.h>
class NetworkAdapter {
@@ -12,6 +13,9 @@ public:
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&);
@@ -25,5 +29,6 @@ protected:
private:
MACAddress m_mac_address;
+ IPv4Address m_ipv4_address;
SinglyLinkedList<ByteBuffer> m_packet_queue;
};
diff --git a/Kernel/NetworkTask.cpp b/Kernel/NetworkTask.cpp
index 763331cc5f..1da5238a59 100644
--- a/Kernel/NetworkTask.cpp
+++ b/Kernel/NetworkTask.cpp
@@ -2,18 +2,24 @@
#include <Kernel/EthernetFrameHeader.h>
#include <Kernel/ARPPacket.h>
#include <Kernel/Process.h>
+#include <Kernel/EtherType.h>
+
+static void handle_arp(const EthernetFrameHeader&, int frame_size);
+static void handle_ipv4(const EthernetFrameHeader&, int frame_size);
void NetworkTask_main()
{
auto* e1000_ptr = E1000NetworkAdapter::the();
ASSERT(e1000_ptr);
auto& e1000 = *e1000_ptr;
+
+ e1000.set_ipv4_address(IPv4Address(192, 168, 5, 2));
ARPPacket arp;
- arp.hardware_type = 1; // Ethernet
- arp.hardware_address_length = 6; // MAC length
- arp.protocol_type = 0x0800; // IPv4
- arp.protocol_address_length = 4; // IP length
- arp.operation = 1; // 1 (request)
+ arp.set_hardware_type(1); // Ethernet
+ arp.set_hardware_address_length(sizeof(MACAddress));
+ arp.set_protocol_type(EtherType::IPv4);
+ arp.set_protocol_address_length(sizeof(IPv4Address));
+ arp.set_operation(1); // Request
e1000.send(MACAddress(), arp);
kprintf("NetworkTask: Enter main loop.\n");
@@ -27,7 +33,74 @@ void NetworkTask_main()
kprintf("NetworkTask: Packet is too small to be an Ethernet packet! (%d)\n", packet.size());
continue;
}
- auto* eth = (const EthernetFrameHeader*)packet.pointer();
- kprintf("NetworkTask: Handle packet from %s to %s\n", eth->source().to_string().characters(), eth->destination().to_string().characters());
+ auto& eth = *(const EthernetFrameHeader*)packet.pointer();
+ 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()
+ );
+
+ 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) + 4;
+ if (frame_size < minimum_arp_frame_size) {
+ kprintf("handle_arp: Frame too small (%d, need %d)\n", frame_size, minimum_arp_frame_size);
+ return;
+ }
+ const ARPPacket& incoming_packet = *static_cast<const ARPPacket*>(eth.payload());
+ if (incoming_packet.hardware_type() != 1 || incoming_packet.hardware_address_length() != sizeof(MACAddress)) {
+ kprintf("handle_arp: Hardware type not ethernet (%w, len=%u)\n", incoming_packet.hardware_type(), incoming_packet.hardware_address_length());
+ return;
+ }
+ if (incoming_packet.protocol_type() != EtherType::IPv4 || incoming_packet.protocol_address_length() != sizeof(IPv4Address)) {
+ kprintf("handle_arp: Protocol type not IPv4 (%w, len=%u)\n", incoming_packet.hardware_type(), incoming_packet.protocol_address_length());
+ return;
+ }
+
+#ifdef ARP_DEBUG
+ kprintf("handle_arp: operation=%w, sender=%s/%s, target=%s/%s\n",
+ incoming_packet.operation(),
+ incoming_packet.sender_hardware_address().to_string().characters(),
+ incoming_packet.sender_protocol_address().to_string().characters(),
+ incoming_packet.target_hardware_address().to_string().characters(),
+ incoming_packet.target_protocol_address().to_string().characters()
+ );
+#endif
+
+ // FIXME: Get the adapter through some kind of lookup by IPv4 address.
+ auto& e1000 = *E1000NetworkAdapter::the();
+
+ if (incoming_packet.operation() == 1) {
+ // Who has this IP address?
+ if (e1000.ipv4_address() == incoming_packet.target_protocol_address()) {
+ // We do!
+ kprintf("handle_arp: Responding to ARP request for my IPv4 address (%s)\n", e1000.ipv4_address().to_string().characters());
+ ARPPacket response;
+ response.set_operation(2); // Response
+
+ response.set_target_hardware_address(incoming_packet.sender_hardware_address());
+ response.set_target_protocol_address(incoming_packet.sender_protocol_address());
+ response.set_sender_hardware_address(e1000.mac_address());
+ response.set_sender_protocol_address(e1000.ipv4_address());
+
+ e1000.send(incoming_packet.sender_hardware_address(), response);
+ }
+ }
+}
+
+void handle_ipv4(const EthernetFrameHeader& eth, int frame_size)
+{
+
+}
diff --git a/Kernel/StdLib.h b/Kernel/StdLib.h
index 05525fb4a6..3af0ba98d7 100644
--- a/Kernel/StdLib.h
+++ b/Kernel/StdLib.h
@@ -16,4 +16,7 @@ char *strdup(const char*);
int memcmp(const void*, const void*, size_t);
char* strrchr(const char* str, int ch);
+inline word ntohs(word w) { return (w & 0xff) << 8 | ((w >> 8) & 0xff); }
+inline word htons(word w) { return (w & 0xff) << 8 | ((w >> 8) & 0xff); }
+
}
diff --git a/Kernel/run b/Kernel/run
index d4a8ed41b6..152539c1eb 100755
--- a/Kernel/run
+++ b/Kernel/run
@@ -9,6 +9,6 @@ elif [ "$1" = "qn" ]; then
else
echo run with net
# ./run: qemu with network
- sudo qemu-system-i386 -s -m 32 -netdev tap,id=br0 -device e1000,netdev=br0 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents #$
+ sudo qemu-system-i386 -s -m 32 -object filter-dump,id=hue,netdev=br0,file=e1000.pcap -netdev tap,ifname=tap0,id=br0 -device e1000,netdev=br0 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents
fi