feat: e100e Ethernet driver, ramdisk reorganization, shell rewrite, web server/client, and more

This commit is contained in:
2026-02-19 01:18:11 +01:00
parent 1a5d943649
commit d355d376f9
63 changed files with 5368 additions and 614 deletions
+9 -2
View File
@@ -10,6 +10,7 @@
#include <Net/Ipv4.hpp>
#include <Net/NetConfig.hpp>
#include <Drivers/Net/E1000.hpp>
#include <Drivers/Net/E1000E.hpp>
#include <Libraries/Memory.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
@@ -19,6 +20,12 @@ using namespace Kt;
namespace Net::Arp {
static const uint8_t* GetActiveNicMac() {
if (Drivers::Net::E1000::IsInitialized())
return Drivers::Net::E1000::GetMacAddress();
return Drivers::Net::E1000E::GetMacAddress();
}
// ARP cache entry
struct CacheEntry {
uint32_t Ip;
@@ -107,7 +114,7 @@ namespace Net::Arp {
reply.ProtocolAddrLen = 4;
reply.Operation = Htons(OP_REPLY);
memcpy(reply.SenderMac, Drivers::Net::E1000::GetMacAddress(), 6);
memcpy(reply.SenderMac, GetActiveNicMac(), 6);
reply.SenderIp = GetIpAddress();
memcpy(reply.TargetMac, pkt->SenderMac, 6);
reply.TargetIp = senderIp;
@@ -141,7 +148,7 @@ namespace Net::Arp {
req.ProtocolAddrLen = 4;
req.Operation = Htons(OP_REQUEST);
memcpy(req.SenderMac, Drivers::Net::E1000::GetMacAddress(), 6);
memcpy(req.SenderMac, GetActiveNicMac(), 6);
req.SenderIp = GetIpAddress();
memset(req.TargetMac, 0, 6);
req.TargetIp = targetIp;
+15 -2
View File
@@ -9,6 +9,7 @@
#include <Net/Arp.hpp>
#include <Net/Ipv4.hpp>
#include <Drivers/Net/E1000.hpp>
#include <Drivers/Net/E1000E.hpp>
#include <Libraries/Memory.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
@@ -17,6 +18,18 @@ using namespace Kt;
namespace Net::Ethernet {
static const uint8_t* GetActiveNicMac() {
if (Drivers::Net::E1000::IsInitialized())
return Drivers::Net::E1000::GetMacAddress();
return Drivers::Net::E1000E::GetMacAddress();
}
static bool ActiveNicSend(const uint8_t* data, uint16_t length) {
if (Drivers::Net::E1000::IsInitialized())
return Drivers::Net::E1000::SendPacket(data, length);
return Drivers::Net::E1000E::SendPacket(data, length);
}
void Initialize() {
KernelLogStream(OK, "Net") << "Ethernet layer initialized";
}
@@ -30,14 +43,14 @@ namespace Net::Ethernet {
Header* hdr = (Header*)frame;
memcpy(hdr->DestMac, destMac, 6);
memcpy(hdr->SrcMac, Drivers::Net::E1000::GetMacAddress(), 6);
memcpy(hdr->SrcMac, GetActiveNicMac(), 6);
hdr->EtherType = Htons(etherType);
memcpy(frame + HEADER_SIZE, payload, payloadLen);
uint16_t totalLen = HEADER_SIZE + payloadLen;
return Drivers::Net::E1000::SendPacket(frame, totalLen);
return ActiveNicSend(frame, totalLen);
}
void OnFrameReceived(const uint8_t* data, uint16_t length) {
+9 -4
View File
@@ -14,6 +14,7 @@
#include <Net/Socket.hpp>
#include <Net/NetConfig.hpp>
#include <Drivers/Net/E1000.hpp>
#include <Drivers/Net/E1000E.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
@@ -22,8 +23,8 @@ using namespace Kt;
namespace Net {
void Initialize() {
if (!Drivers::Net::E1000::IsInitialized()) {
KernelLogStream(WARNING, "Net") << "E1000 not initialized, skipping network stack";
if (!Drivers::Net::E1000::IsInitialized() && !Drivers::Net::E1000E::IsInitialized()) {
KernelLogStream(WARNING, "Net") << "No NIC initialized, skipping network stack";
return;
}
@@ -36,8 +37,12 @@ namespace Net {
Tcp::Initialize();
Socket::Initialize();
// Hook E1000 RX to our Ethernet dispatcher
Drivers::Net::E1000::SetRxCallback(Ethernet::OnFrameReceived);
// Hook the active NIC's RX to our Ethernet dispatcher
if (Drivers::Net::E1000::IsInitialized()) {
Drivers::Net::E1000::SetRxCallback(Ethernet::OnFrameReceived);
} else {
Drivers::Net::E1000E::SetRxCallback(Ethernet::OnFrameReceived);
}
// Send a gratuitous ARP to announce ourselves on the network
Arp::SendRequest(GetIpAddress());
+185 -2
View File
@@ -1,19 +1,42 @@
/*
* Socket.cpp
* Socket descriptor table wrapping kernel TCP layer
* Socket descriptor table wrapping kernel TCP and UDP layers
* Copyright (c) 2025 Daniel Hammer
*/
#include "Socket.hpp"
#include <Net/Tcp.hpp>
#include <Net/Udp.hpp>
#include <Net/NetConfig.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
#include <Libraries/Memory.hpp>
using namespace Kt;
namespace Net::Socket {
// ---- UDP socket state ----
static constexpr uint32_t UDP_RING_SIZE = 4096;
static constexpr int MAX_UDP_SOCKETS = 16;
struct UdpDgramHeader {
uint32_t SrcIp;
uint16_t SrcPort;
uint16_t DataLen;
};
struct UdpSocketState {
uint8_t Ring[UDP_RING_SIZE];
uint32_t Head;
uint32_t Tail;
uint32_t Count;
uint16_t LocalPort;
bool Active;
};
static UdpSocketState g_udpSockets[MAX_UDP_SOCKETS] = {};
static SocketEntry g_sockets[MAX_SOCKETS] = {};
static uint16_t g_nextEphemeralPort = 49152;
@@ -30,15 +53,78 @@ namespace Net::Socket {
return true;
}
static UdpSocketState* AllocUdpState() {
for (int i = 0; i < MAX_UDP_SOCKETS; i++) {
if (!g_udpSockets[i].Active) {
g_udpSockets[i].Active = true;
g_udpSockets[i].Head = 0;
g_udpSockets[i].Tail = 0;
g_udpSockets[i].Count = 0;
g_udpSockets[i].LocalPort = 0;
return &g_udpSockets[i];
}
}
return nullptr;
}
static void FreeUdpState(UdpSocketState* state) {
if (state) {
if (state->LocalPort != 0) {
Udp::Unbind(state->LocalPort);
}
state->Active = false;
}
}
static void UdpSocketDispatcher(uint32_t srcIp, uint16_t srcPort,
uint16_t dstPort,
const uint8_t* data, uint16_t length) {
for (int i = 0; i < MAX_UDP_SOCKETS; i++) {
if (g_udpSockets[i].Active && g_udpSockets[i].LocalPort == dstPort) {
UdpSocketState* st = &g_udpSockets[i];
uint32_t needed = sizeof(UdpDgramHeader) + length;
if (st->Count + needed > UDP_RING_SIZE) {
return; // drop if buffer full
}
// Enqueue header
UdpDgramHeader hdr;
hdr.SrcIp = srcIp;
hdr.SrcPort = srcPort;
hdr.DataLen = length;
const uint8_t* hdrBytes = (const uint8_t*)&hdr;
for (uint32_t j = 0; j < sizeof(UdpDgramHeader); j++) {
st->Ring[st->Tail] = hdrBytes[j];
st->Tail = (st->Tail + 1) % UDP_RING_SIZE;
}
// Enqueue payload
for (uint16_t j = 0; j < length; j++) {
st->Ring[st->Tail] = data[j];
st->Tail = (st->Tail + 1) % UDP_RING_SIZE;
}
st->Count += needed;
return;
}
}
}
// ---- Public API ----
void Initialize() {
for (int i = 0; i < MAX_SOCKETS; i++) {
g_sockets[i].Active = false;
}
for (int i = 0; i < MAX_UDP_SOCKETS; i++) {
g_udpSockets[i].Active = false;
}
KernelLogStream(OK, "Net") << "Socket table initialized";
}
int Create(int type, int pid) {
if (type != SOCK_TCP) return -1;
if (type != SOCK_TCP && type != SOCK_UDP) return -1;
for (int i = 0; i < MAX_SOCKETS; i++) {
if (!g_sockets[i].Active) {
@@ -46,7 +132,18 @@ namespace Net::Socket {
g_sockets[i].Type = type;
g_sockets[i].OwnerPid = pid;
g_sockets[i].TcpConn = nullptr;
g_sockets[i].UdpState = nullptr;
g_sockets[i].LocalPort = 0;
if (type == SOCK_UDP) {
UdpSocketState* us = AllocUdpState();
if (!us) {
g_sockets[i].Active = false;
return -1;
}
g_sockets[i].UdpState = us;
}
return i;
}
}
@@ -55,6 +152,7 @@ namespace Net::Socket {
int Connect(int fd, uint32_t ip, uint16_t port, int pid) {
if (!ValidFd(fd, pid)) return -1;
if (g_sockets[fd].Type != SOCK_TCP) return -1;
if (g_sockets[fd].TcpConn != nullptr) return -1;
uint16_t srcPort = AllocEphemeralPort();
@@ -70,11 +168,20 @@ namespace Net::Socket {
int Bind(int fd, uint16_t port, int pid) {
if (!ValidFd(fd, pid)) return -1;
g_sockets[fd].LocalPort = port;
if (g_sockets[fd].Type == SOCK_UDP) {
UdpSocketState* us = g_sockets[fd].UdpState;
if (!us) return -1;
us->LocalPort = port;
if (!Udp::Bind(port, UdpSocketDispatcher)) return -1;
}
return 0;
}
int Listen(int fd, int pid) {
if (!ValidFd(fd, pid)) return -1;
if (g_sockets[fd].Type != SOCK_TCP) return -1;
if (g_sockets[fd].LocalPort == 0) return -1;
if (g_sockets[fd].TcpConn != nullptr) return -1;
@@ -87,6 +194,7 @@ namespace Net::Socket {
int Accept(int fd, int pid) {
if (!ValidFd(fd, pid)) return -1;
if (g_sockets[fd].Type != SOCK_TCP) return -1;
if (g_sockets[fd].TcpConn == nullptr) return -1;
Tcp::Connection* clientConn = Tcp::Accept(g_sockets[fd].TcpConn);
@@ -99,6 +207,7 @@ namespace Net::Socket {
g_sockets[i].Type = SOCK_TCP;
g_sockets[i].OwnerPid = pid;
g_sockets[i].TcpConn = clientConn;
g_sockets[i].UdpState = nullptr;
g_sockets[i].LocalPort = g_sockets[fd].LocalPort;
return i;
}
@@ -111,22 +220,92 @@ namespace Net::Socket {
int Send(int fd, const uint8_t* data, uint32_t len, int pid) {
if (!ValidFd(fd, pid)) return -1;
if (g_sockets[fd].Type != SOCK_TCP) return -1;
if (g_sockets[fd].TcpConn == nullptr) return -1;
return Tcp::Send(g_sockets[fd].TcpConn, data, (uint16_t)len);
}
int Recv(int fd, uint8_t* buf, uint32_t maxLen, int pid) {
if (!ValidFd(fd, pid)) return -1;
if (g_sockets[fd].Type != SOCK_TCP) return -1;
if (g_sockets[fd].TcpConn == nullptr) return -1;
return Tcp::ReceiveNonBlocking(g_sockets[fd].TcpConn, buf, (uint16_t)maxLen);
}
int SendTo(int fd, const uint8_t* data, uint32_t len,
uint32_t destIp, uint16_t destPort, int pid) {
if (!ValidFd(fd, pid)) return -1;
if (g_sockets[fd].Type != SOCK_UDP) return -1;
UdpSocketState* us = g_sockets[fd].UdpState;
if (!us) return -1;
// Auto-bind ephemeral port if not already bound
if (us->LocalPort == 0) {
uint16_t ep = AllocEphemeralPort();
us->LocalPort = ep;
g_sockets[fd].LocalPort = ep;
if (!Udp::Bind(ep, UdpSocketDispatcher)) return -1;
}
if (!Udp::Send(destIp, us->LocalPort, destPort, data, (uint16_t)len)) {
return -1;
}
return (int)len;
}
int RecvFrom(int fd, uint8_t* buf, uint32_t maxLen,
uint32_t* srcIp, uint16_t* srcPort, int pid) {
if (!ValidFd(fd, pid)) return -1;
if (g_sockets[fd].Type != SOCK_UDP) return -1;
UdpSocketState* us = g_sockets[fd].UdpState;
if (!us) return -1;
if (us->Count < sizeof(UdpDgramHeader)) {
return -1; // no data available
}
// Dequeue header
UdpDgramHeader hdr;
uint8_t* hdrBytes = (uint8_t*)&hdr;
for (uint32_t j = 0; j < sizeof(UdpDgramHeader); j++) {
hdrBytes[j] = us->Ring[us->Head];
us->Head = (us->Head + 1) % UDP_RING_SIZE;
}
us->Count -= sizeof(UdpDgramHeader);
// Dequeue payload
uint16_t copyLen = hdr.DataLen;
if (copyLen > maxLen) copyLen = (uint16_t)maxLen;
for (uint16_t j = 0; j < copyLen; j++) {
buf[j] = us->Ring[us->Head];
us->Head = (us->Head + 1) % UDP_RING_SIZE;
}
// Skip remaining data if buffer was too small
for (uint16_t j = copyLen; j < hdr.DataLen; j++) {
us->Head = (us->Head + 1) % UDP_RING_SIZE;
}
us->Count -= hdr.DataLen;
if (srcIp) *srcIp = hdr.SrcIp;
if (srcPort) *srcPort = hdr.SrcPort;
return (int)copyLen;
}
void Close(int fd, int pid) {
if (!ValidFd(fd, pid)) return;
if (g_sockets[fd].TcpConn != nullptr) {
Tcp::Close(g_sockets[fd].TcpConn);
g_sockets[fd].TcpConn = nullptr;
}
if (g_sockets[fd].UdpState != nullptr) {
FreeUdpState(g_sockets[fd].UdpState);
g_sockets[fd].UdpState = nullptr;
}
g_sockets[fd].Active = false;
}
@@ -137,6 +316,10 @@ namespace Net::Socket {
Tcp::Close(g_sockets[i].TcpConn);
g_sockets[i].TcpConn = nullptr;
}
if (g_sockets[i].UdpState != nullptr) {
FreeUdpState(g_sockets[i].UdpState);
g_sockets[i].UdpState = nullptr;
}
g_sockets[i].Active = false;
}
}
+12 -1
View File
@@ -1,6 +1,6 @@
/*
* Socket.hpp
* Socket descriptor table for userspace TCP access
* Socket descriptor table for userspace TCP/UDP access
* Copyright (c) 2025 Daniel Hammer
*/
@@ -14,11 +14,14 @@ namespace Net::Socket {
static constexpr int SOCK_UDP = 2;
static constexpr int MAX_SOCKETS = 64;
struct UdpSocketState;
struct SocketEntry {
bool Active;
int Type;
int OwnerPid;
Tcp::Connection* TcpConn;
UdpSocketState* UdpState;
uint16_t LocalPort;
};
@@ -45,6 +48,14 @@ namespace Net::Socket {
// Receive data from a connected socket. Returns bytes received, 0 on close, or -1.
int Recv(int fd, uint8_t* buf, uint32_t maxLen, int pid);
// Send a UDP datagram to a specific destination. Returns bytes sent or -1.
int SendTo(int fd, const uint8_t* data, uint32_t len,
uint32_t destIp, uint16_t destPort, int pid);
// Receive a UDP datagram, returning source info. Returns bytes received or -1.
int RecvFrom(int fd, uint8_t* buf, uint32_t maxLen,
uint32_t* srcIp, uint16_t* srcPort, int pid);
// Close a socket.
void Close(int fd, int pid);
+1 -1
View File
@@ -61,7 +61,7 @@ namespace Net::Udp {
// Dispatch to bound callback
for (uint32_t i = 0; i < MAX_BINDINGS; i++) {
if (g_bindings[i].Active && g_bindings[i].Port == dstPort) {
g_bindings[i].Callback(srcIp, srcPort, payload, payloadLen);
g_bindings[i].Callback(srcIp, srcPort, dstPort, payload, payloadLen);
return;
}
}
+3 -1
View File
@@ -19,7 +19,9 @@ namespace Net::Udp {
} __attribute__((packed));
// Callback type for receiving UDP data
using RecvCallback = void(*)(uint32_t srcIp, uint16_t srcPort, const uint8_t* data, uint16_t length);
using RecvCallback = void(*)(uint32_t srcIp, uint16_t srcPort,
uint16_t dstPort,
const uint8_t* data, uint16_t length);
// Initialize the UDP subsystem
void Initialize();