feat: e100e Ethernet driver, ramdisk reorganization, shell rewrite, web server/client, and more
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user