Merge remote-tracking branch 'Kernel/master'

This commit is contained in:
EnderIce2
2024-11-20 05:00:33 +02:00
468 changed files with 112800 additions and 1 deletions

245
Kernel/network/arp.cpp Normal file
View File

@ -0,0 +1,245 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/arp.hpp>
#include <debug.h>
#include "../kernel.h"
/* conversion from 'uint48_t' {aka 'long unsigned int'} to 'long unsigned int:48' may change value */
#pragma GCC diagnostic ignored "-Wconversion"
namespace NetworkARP
{
DiscoveredAddress *ARP::ManageDiscoveredAddresses(DAType Type, InternetProtocol IP, MediaAccessControl MAC)
{
switch (Type)
{
case DA_ADD:
{
DiscoveredAddress *tmp = new DiscoveredAddress;
tmp->IP = IP;
tmp->MAC = MAC;
DiscoveredAddresses.push_back(tmp);
netdbg("Added %s to discovered addresses", IP.v4.ToStringLittleEndian());
return tmp;
}
case DA_DEL:
{
forItr(itr, DiscoveredAddresses)
{
if ((*itr)->IP.v4 == IP.v4)
{
DiscoveredAddress *tmp = *itr;
netdbg("Removed %s from discovered addresses", IP.v4.ToStringLittleEndian());
delete tmp, tmp = nullptr;
DiscoveredAddresses.erase(itr);
break;
}
}
return nullptr;
}
case DA_SEARCH:
{
for (size_t i = 0; i < DiscoveredAddresses.size(); i++)
{
if (DiscoveredAddresses[i]->IP.v4 == IP.v4)
{
netdbg("Found %s in discovered addresses", IP.v4.ToStringLittleEndian());
return DiscoveredAddresses[i];
}
}
return nullptr;
}
case DA_UPDATE:
{
for (size_t i = 0; i < DiscoveredAddresses.size(); i++)
{
if (DiscoveredAddresses[i]->IP.v4 == IP.v4)
{
DiscoveredAddresses[i]->MAC = MAC;
netdbg("Updated %s in discovered addresses", IP.v4.ToStringLittleEndian());
return DiscoveredAddresses[i];
}
}
return nullptr;
}
default:
{
return nullptr;
}
}
return nullptr;
}
ARP::ARP(NetworkEthernet::Ethernet *Ethernet) : NetworkEthernet::EthernetEvents(NetworkEthernet::TYPE_ARP)
{
debug("ARP interface %#lx created.", this);
this->Ethernet = Ethernet;
}
ARP::~ARP()
{
debug("ARP interface %#lx destroyed.", this);
}
MediaAccessControl InvalidMAC;
InternetProtocol InvalidIP;
DiscoveredAddress InvalidRet = {.MAC = InvalidMAC, .IP = InvalidIP};
DiscoveredAddress *ARP::Search(InternetProtocol TargetIP)
{
DiscoveredAddress *ret = ManageDiscoveredAddresses(DA_SEARCH, TargetIP, MediaAccessControl());
if (ret)
return ret;
warn("No address found for %s", TargetIP.v4.ToStringLittleEndian());
return &InvalidRet;
}
DiscoveredAddress *ARP::Update(InternetProtocol TargetIP, MediaAccessControl TargetMAC)
{
DiscoveredAddress *ret = ManageDiscoveredAddresses(DA_UPDATE, TargetIP, TargetMAC);
if (ret)
return ret;
warn("No address found for %s", TargetIP.v4.ToStringLittleEndian());
return &InvalidRet;
}
uint48_t ARP::Resolve(InternetProtocol IP)
{
netdbg("Resolving %s", IP.v4.ToStringLittleEndian());
if (IP.v4 == 0xFFFFFFFF)
return 0xFFFFFFFFFFFF;
/* If we can't find the MAC, return the default value which is 0xFFFFFFFFFFFF. */
uint48_t ret = this->Search(IP)->MAC.ToHex();
netdbg("Resolved %s to %lx", IP.v4.ToStringLittleEndian(), ret);
if (ret == 0xFFFFFFFFFFFF)
{
netdbg("Sending request");
/* If we can't find the MAC, send a request.
Because we are going to send this over the network, we need to byteswap first.
This is actually very confusing for me. */
ARPHeader *Header = new ARPHeader;
Header->HardwareType = b16(ARPHardwareType::HTYPE_ETHERNET);
Header->ProtocolType = b16(NetworkEthernet::FrameType::TYPE_IPV4);
Header->HardwareSize = b8(6);
Header->ProtocolSize = b8(4);
Header->Operation = b16(ARPOperation::REQUEST);
Header->SenderMAC = b48(Ethernet->GetInterface()->MAC.ToHex());
Header->SenderIP = b32(Ethernet->GetInterface()->IP.v4.ToHex());
Header->TargetMAC = b48(0xFFFFFFFFFFFF);
Header->TargetIP = b32(IP.v4.ToHex());
netdbg("SIP: %s; TIP: %s", InternetProtocol().v4.FromHex(Header->SenderIP).ToStringLittleEndian(),
InternetProtocol().v4.FromHex(Header->TargetIP).ToStringLittleEndian());
/* Send the request to the broadcast MAC address. */
Ethernet->Send({.Address = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}, NetworkEthernet::FrameType::TYPE_ARP, (uint8_t *)Header, sizeof(ARPHeader));
delete Header, Header = nullptr;
}
int RequestTimeout = 20;
debug("Waiting for response");
while (ret == 0xFFFFFFFFFFFF)
{
ret = this->Search(IP)->MAC.ToHex();
if (--RequestTimeout == 0)
{
warn("Request timeout.");
return 0;
}
netdbg("Still waiting...");
TaskManager->Sleep(1000);
}
return ret;
}
void ARP::Broadcast(InternetProtocol IP)
{
netdbg("Sending broadcast");
uint48_t ResolvedMAC = this->Resolve(IP);
ARPHeader *Header = new ARPHeader;
Header->HardwareType = b16(ARPHardwareType::HTYPE_ETHERNET);
Header->ProtocolType = b16(NetworkEthernet::FrameType::TYPE_IPV4);
Header->HardwareSize = b8(0x6);
Header->ProtocolSize = b8(0x4);
Header->Operation = b16(ARPOperation::REQUEST);
Header->SenderMAC = b48(Ethernet->GetInterface()->MAC.ToHex());
Header->SenderIP = b32(Ethernet->GetInterface()->IP.v4.ToHex());
Header->TargetMAC = b48(ResolvedMAC);
Header->TargetIP = b32(IP.v4.ToHex());
Ethernet->Send(MediaAccessControl().FromHex(ResolvedMAC), NetworkEthernet::FrameType::TYPE_ARP, (uint8_t *)Header, sizeof(ARPHeader));
delete Header, Header = nullptr;
}
bool ARP::OnEthernetPacketReceived(uint8_t *Data, size_t Length)
{
UNUSED(Length);
netdbg("Received packet");
ARPHeader *Header = (ARPHeader *)Data;
InternetProtocol SenderIPv4;
SenderIPv4.v4 = SenderIPv4.v4.FromHex(b32(Header->SenderIP));
/* We only support Ethernet and IPv4. */
if (b16(Header->HardwareType) != ARPHardwareType::HTYPE_ETHERNET || b16(Header->ProtocolType) != NetworkEthernet::FrameType::TYPE_IPV4)
{
warn("Invalid hardware/protocol type (%d/%d)", b16(Header->HardwareType), b16(Header->ProtocolType));
return false;
}
InternetProtocol TmpIPStruct;
InternetProtocol().v4.FromHex(b32(Header->SenderIP));
if (ManageDiscoveredAddresses(DA_SEARCH, TmpIPStruct, MediaAccessControl().FromHex(b48(Header->SenderMAC))) == nullptr)
{
netdbg("Discovered new address %s", SenderIPv4.v4.ToStringLittleEndian());
TmpIPStruct.v4.FromHex(b32(Header->SenderIP));
ManageDiscoveredAddresses(DA_ADD, TmpIPStruct, MediaAccessControl().FromHex(b48(Header->SenderMAC)));
}
else
{
netdbg("Updated address %s", SenderIPv4.v4.ToStringLittleEndian());
TmpIPStruct.v4.FromHex(b32(Header->SenderIP));
ManageDiscoveredAddresses(DA_UPDATE, TmpIPStruct, MediaAccessControl().FromHex(b48(Header->SenderMAC)));
}
switch (b16(Header->Operation))
{
case ARPOperation::REQUEST:
netdbg("Received request from %s", SenderIPv4.v4.ToStringLittleEndian());
/* We need to byteswap before we send it back. */
Header->TargetMAC = b48(Header->SenderMAC);
Header->TargetIP = b32(Header->SenderIP);
Header->SenderMAC = b48(Ethernet->GetInterface()->MAC.ToHex());
Header->SenderIP = b32(Ethernet->GetInterface()->IP.v4.ToHex());
Header->Operation = b16(ARPOperation::REPLY);
Ethernet->Send(MediaAccessControl().FromHex(Header->TargetMAC), NetworkEthernet::FrameType::TYPE_ARP, (uint8_t *)Header, sizeof(ARPHeader));
netdbg("Sent request for %s", SenderIPv4.v4.ToStringLittleEndian());
break;
case ARPOperation::REPLY:
fixme("Received reply from %s", SenderIPv4.v4.ToStringLittleEndian());
break;
default:
warn("Invalid operation (%d)", b16(Header->Operation));
break;
}
return false;
}
}

View File

@ -0,0 +1,31 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/net.hpp>
uint16_t CalculateChecksum(uint16_t *Data, size_t Length)
{
uint16_t *Data16 = (uint16_t *)Data;
uint64_t Checksum = 0;
for (uint64_t i = 0; i < Length / 2; i++)
Checksum += ((Data16[i] & 0xFF00) >> 8) | ((Data16[i] & 0x00FF) << 8);
if (Length % 2)
Checksum += ((uint16_t)((char *)Data16)[Length - 1]) << 8;
while (Checksum & 0xFFFF0000)
Checksum = (Checksum & 0xFFFF) + (Checksum >> 16);
return (uint16_t)(((~Checksum & 0xFF00) >> 8) | ((~Checksum & 0x00FF) << 8));
}

186
Kernel/network/dhcp.cpp Normal file
View File

@ -0,0 +1,186 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/dhcp.hpp>
#include <debug.h>
#include "../kernel.h"
namespace NetworkDHCP
{
DHCP::DHCP(NetworkUDP::Socket *Socket, NetworkInterfaceManager::DeviceInterface *Interface)
{
debug("DHCP interface %#lx created.", this);
this->UDPSocket = Socket;
this->Interface = Interface;
Socket->LocalPort = b16(68);
InternetProtocol::Version4 DefaultIPv4 = {.Address = {0x0, 0x0, 0x0, 0x0}};
InternetProtocol::Version6 DefaultIPv6 = {.Address = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
this->IP.v4 = DefaultIPv4;
this->IP.v6 = DefaultIPv6;
this->Gateway.v4 = DefaultIPv4;
this->Gateway.v6 = DefaultIPv6;
this->SubNetworkMask.v4 = DefaultIPv4;
this->SubNetworkMask.v6 = DefaultIPv6;
this->DomainNameSystem.v4 = DefaultIPv4;
this->DomainNameSystem.v6 = DefaultIPv6;
}
DHCP::~DHCP()
{
debug("DHCP interface %#lx destroyed.", this);
}
__no_sanitize("alignment") void DHCP::CreatePacket(DHCPHeader *Packet, uint8_t MessageType, uint32_t RequestIP)
{
Packet->Opcode = b8(DHCP_OP_BOOTREQUEST);
Packet->HardwareType = b8(1);
Packet->HardwareAddressLength = b8(6);
Packet->Hops = b8(0);
Packet->TransactionID = b32(DHCP_TRANSACTION_ID);
Packet->Flags = b16(0x40);
uint48_t InterfaceMAC = b48(Interface->MAC.ToHex());
memcpy(Packet->ClientHardwareAddress, &InterfaceMAC, sizeof(InterfaceMAC));
uint8_t *Ptr = Packet->Options;
*((uint32_t *)(Ptr)) = b32(0x63825363); // Magic Cookie
Ptr += 4;
*(Ptr++) = DHCP_OPTION_MESSAGE_TYPE;
*(Ptr++) = DHCP_MESSAGE_TYPE_DISCOVER;
*(Ptr++) = MessageType;
*(Ptr++) = DHCP_OPTION_CLIENT_IDENTIFIER;
*(Ptr++) = 0x07;
*(Ptr++) = 0x01;
memcpy(Ptr, &InterfaceMAC, sizeof(InterfaceMAC));
Ptr += 6;
*(Ptr++) = DHCP_OPTION_REQUESTED_IP;
*(Ptr++) = 0x04;
*((uint32_t *)(Ptr)) = b32(0x0a00020e);
memcpy((uint32_t *)(Ptr), &RequestIP, 4);
Ptr += 4;
*(Ptr++) = DHCP_OPTION_HOST_NAME;
char *HostName = (char *)KERNEL_NAME;
*(Ptr++) = s_cst(uint8_t, 1 + strlen(HostName));
memcpy(Ptr, HostName, strlen(HostName));
Ptr += strlen(HostName);
*(Ptr++) = DHCP_OPTION_PAD;
*(Ptr++) = DHCP_OPTION_PARAMETER_REQUEST_LIST;
*(Ptr++) = DHCP_OPTION_COOKIE_SERVER;
*(Ptr++) = DHCP_OPTION_SUBNETMASK;
*(Ptr++) = DHCP_OPTION_ROUTER;
*(Ptr++) = DHCP_OPTION_DOMAIN_NAME_SERVER;
*(Ptr++) = DHCP_OPTION_DOMAIN_NAME;
*(Ptr++) = DHCP_OPTION_NETBIOS_NAME_SERVERS;
*(Ptr++) = DHCP_OPTION_NETBIOS_NODE_TYPE;
*(Ptr++) = DHCP_OPTION_NETBIOS_SCOPE;
*(Ptr++) = DHCP_OPTION_MAX_MESSAGE_SIZE;
*(Ptr++) = DHCP_OPTION_END;
}
void DHCP::Request()
{
netdbg("Requesting IP address");
DHCPHeader packet;
memset(&packet, 0, sizeof(DHCPHeader));
CreatePacket(&packet, DHCP_MESSAGE_TYPE_DISCOVER, 0x00000000);
this->UDPSocket->SocketUDP->Send(this->UDPSocket, (uint8_t *)&packet, sizeof(DHCPHeader));
debug("Waiting for response...");
int RequestTimeout = 20;
while (!Received)
{
if (--RequestTimeout == 0)
{
warn("Request timeout.");
break;
}
netdbg("Still waiting...");
TaskManager->Sleep(1000);
}
}
void DHCP::Request(InternetProtocol IP)
{
netdbg("Requesting IP address %s", IP.v4.ToStringLittleEndian());
DHCPHeader packet;
memset(&packet, 0, sizeof(DHCPHeader));
/* CreatePacket() accepts IP as MSB */
CreatePacket(&packet, DHCP_MESSAGE_TYPE_REQUEST, b32(IP.v4.ToHex()));
UDPSocket->SocketUDP->Send(UDPSocket, (uint8_t *)&packet, sizeof(DHCPHeader));
}
void *DHCP::GetOption(DHCPHeader *Packet, uint8_t Type)
{
uint8_t *Option = Packet->Options + 4;
uint8_t Current = *Option;
while (Current != 0xFF)
{
uint8_t OptionLength = *(Option + 1);
if (Current == Type)
return Option + 2;
Option += (2 + OptionLength);
Current = *Option;
}
warn("Option %#x not found", Type);
return nullptr;
}
__no_sanitize("alignment") void DHCP::OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length)
{
UNUSED(Socket);
UNUSED(Length);
DHCPHeader *Packet = (DHCPHeader *)Data;
uint8_t *MessageType = (uint8_t *)GetOption(Packet, DHCP_OPTION_MESSAGE_TYPE);
switch (*MessageType)
{
case DHCP_OPTION_TIME_OFFSET:
{
InternetProtocol ReqIP;
ReqIP.v4.FromHex(b32(Packet->YourIP));
netdbg("Received DHCP offer for IP %s", ReqIP.v4.ToStringLittleEndian());
this->Request(ReqIP);
break;
}
case DHCP_OPTION_NAME_SERVER:
this->IP.v4.FromHex(b32(Packet->YourIP));
this->Gateway.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_ROUTER))));
this->DomainNameSystem.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_DOMAIN_NAME_SERVER))));
this->SubNetworkMask.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_SUBNETMASK))));
this->Received = true;
netdbg("Received DHCP ACK for IP %s", this->IP.v4.ToStringLittleEndian());
break;
default:
warn("Received unknown message type %#x", *MessageType);
break;
}
}
}

35
Kernel/network/dns.cpp Normal file
View File

@ -0,0 +1,35 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/dns.hpp>
#include <debug.h>
#include "../kernel.h"
namespace NetworkDNS
{
DNS::DNS(NetworkUDP::Socket *Socket) : NetworkUDP::UDPEvents()
{
debug("DNS interface %#lx created.", this);
this->UDPSocket = Socket;
}
DNS::~DNS()
{
debug("DNS interface %#lx destroyed.", this);
}
}

152
Kernel/network/eth.cpp Normal file
View File

@ -0,0 +1,152 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/eth.hpp>
#include <debug.h>
#include "../kernel.h"
/* conversion from 'uint48_t' {aka 'long unsigned int'} to 'long unsigned int:48' may change value */
#pragma GCC diagnostic ignored "-Wconversion"
namespace NetworkEthernet
{
struct EthernetEventHelperStruct
{
EthernetEvents *Ptr;
uint16_t Type;
};
std::vector<EthernetEventHelperStruct> RegisteredEvents;
Ethernet::Ethernet(NetworkInterfaceManager::DeviceInterface *Interface) : NetworkInterfaceManager::Events(Interface)
{
debug("Ethernet interface %#lx created.", this);
this->Interface = Interface;
}
Ethernet::~Ethernet()
{
debug("Ethernet interface %#lx destroyed.", this);
}
void Ethernet::Send(MediaAccessControl MAC, FrameType Type, uint8_t *Data, size_t Length)
{
netdbg("Sending frame type %#x to %s", Type, MAC.ToString());
size_t PacketLength = sizeof(EthernetHeader) + Length;
EthernetPacket *Packet = (EthernetPacket *)kmalloc(PacketLength);
Packet->Header.DestinationMAC = b48(MAC.ToHex());
Packet->Header.SourceMAC = b48(this->Interface->MAC.ToHex());
Packet->Header.Type = b16(Type);
memcpy(Packet->Data, Data, Length);
/* Network Interface Manager takes care of physical allocation.
So basically, we allocate here and then it allocates again but 1:1 mapped. */
// NIManager->Send(Interface, (uint8_t *)Packet, PacketLength);
assert(!"Function not implemented");
kfree(Packet);
}
void Ethernet::Receive(uint8_t *Data, size_t Length)
{
EthernetPacket *Packet = (EthernetPacket *)Data;
size_t PacketLength = Length - sizeof(EthernetHeader);
/* TODO: I have to do checks here to be sure that PacketLength is right */
UNUSED(PacketLength);
MediaAccessControl SourceMAC;
SourceMAC.FromHex(b48(Packet->Header.SourceMAC));
MediaAccessControl DestinationMAC;
DestinationMAC.FromHex(b48(Packet->Header.DestinationMAC));
netdbg("Received frame type %#x from %s to %s", b16(Packet->Header.Type), SourceMAC.ToString(), DestinationMAC.ToString());
/* Byte-swapped little-endian */
if (b48(Packet->Header.DestinationMAC) == 0xFFFFFFFFFFFF ||
/* Byte-swapped Driver interface has little-endian order */
b48(Packet->Header.DestinationMAC) == this->Interface->MAC.ToHex())
/* This is true only if the packet is for us (Interface MAC or broadcast) */
{
netdbg("Received data from %s [Type %#x]", SourceMAC.ToString(), b16(Packet->Header.Type));
bool Reply = false;
switch (b16(Packet->Header.Type))
{
case TYPE_IPV4:
foreach (auto e in RegisteredEvents)
if (e.Type == TYPE_IPV4)
Reply = e.Ptr->OnEthernetPacketReceived((uint8_t *)Packet->Data, Length);
break;
case TYPE_ARP:
foreach (auto e in RegisteredEvents)
if (e.Type == TYPE_ARP)
Reply = e.Ptr->OnEthernetPacketReceived((uint8_t *)Packet->Data, Length);
break;
case TYPE_RARP:
foreach (auto e in RegisteredEvents)
if (e.Type == TYPE_RARP)
Reply = e.Ptr->OnEthernetPacketReceived((uint8_t *)Packet->Data, Length);
break;
case TYPE_IPV6:
foreach (auto e in RegisteredEvents)
if (e.Type == TYPE_IPV6)
Reply = e.Ptr->OnEthernetPacketReceived((uint8_t *)Packet->Data, Length);
break;
default:
warn("Unknown packet type %#lx", Packet->Header.Type);
break;
}
if (Reply)
{
/* FIXME: I should reply, right? I have to do more research here... */
// Packet->Header.DestinationMAC = Packet->Header.SourceMAC;
// Packet->Header.SourceMAC = b48(this->Interface->MAC.ToHex());
fixme("Replying to %s [%s]=>[%s]", SourceMAC.ToString(),
this->Interface->MAC.ToString(), DestinationMAC.ToString());
}
}
else
{
netdbg("Packet not for us [%s]=>[%s]", this->Interface->MAC.ToString(), DestinationMAC.ToString());
}
}
void Ethernet::OnInterfaceReceived(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length)
{
if (Interface == this->Interface)
this->Receive(Data, Length);
}
EthernetEvents::EthernetEvents(FrameType Type)
{
this->FType = Type;
RegisteredEvents.push_back({.Ptr = this, .Type = (uint16_t)Type});
}
EthernetEvents::~EthernetEvents()
{
forItr(itr, RegisteredEvents)
{
if (itr->Ptr == this)
{
RegisteredEvents.erase(itr);
return;
}
}
}
}

78
Kernel/network/icmp.cpp Normal file
View File

@ -0,0 +1,78 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/icmpv4.hpp>
#include <net/icmpv6.hpp>
#include <debug.h>
#include "../kernel.h"
namespace NetworkICMPv4
{
ICMPv4::ICMPv4(NetworkInterfaceManager::DeviceInterface *Interface)
{
debug("ICMPv4 interface %#lx created.", this);
this->Interface = Interface;
}
ICMPv4::~ICMPv4()
{
debug("ICMPv4 interface %#lx destroyed.", this);
}
void ICMPv4::Send(/* ???? */)
{
fixme("Unimplemented");
}
void ICMPv4::Receive(ICMPPacket *Packet)
{
if (Packet->Header.Type == ICMPv4Type::TYPE_ECHO)
{
// TODO: This probably doesn't work
netdbg("Echo Request");
Packet->Header.Type = ICMPv4Type::TYPE_ECHO_REPLY;
Packet->Header.Code = 0x0;
Packet->Header.Checksum = CalculateChecksum((uint16_t *)Packet, sizeof(ICMPHeader));
// NIManager->Send(this->Interface, (uint8_t *)Packet, sizeof(ICMPHeader) + 0);
assert(!"Function not implemented");
}
else
{
netdbg("Unknown type %d", Packet->Header.Type);
}
}
}
namespace NetworkICMPv6
{
ICMPv6::ICMPv6(NetworkInterfaceManager::DeviceInterface *Interface) { this->Interface = Interface; }
ICMPv6::~ICMPv6() {}
void ICMPv6::Send(uint8_t *Data, size_t Length)
{
UNUSED(Data);
UNUSED(Length);
fixme("Unimplemented");
}
void ICMPv6::Receive(uint8_t *Data)
{
UNUSED(Data);
fixme("Unimplemented");
}
}

145
Kernel/network/ip.cpp Normal file
View File

@ -0,0 +1,145 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/ipv4.hpp>
#include <debug.h>
#include "../kernel.h"
namespace NetworkIPv4
{
IPv4::IPv4(NetworkARP::ARP *ARP, NetworkEthernet::Ethernet *Ethernet) : NetworkEthernet::EthernetEvents(NetworkEthernet::TYPE_IPV4)
{
debug("IPv4 interface %#lx created.", this);
this->ARP = ARP;
this->Ethernet = Ethernet;
}
IPv4::~IPv4()
{
debug("IPv4 interface %#lx destroyed.", this);
}
void IPv4::Send(uint8_t *Data, size_t Length, uint8_t Protocol, InternetProtocol DestinationIP)
{
netdbg("Sending %ld bytes to %s", Length, DestinationIP.v4.ToStringLittleEndian());
IPv4Packet *Packet = (IPv4Packet *)kmalloc(Length + sizeof(IPv4Header));
/* This part is the most confusing one for me. */
Packet->Header.Version = b8(4);
Packet->Header.IHL = b8(sizeof(IPv4Header) / 4);
Packet->Header.TypeOfService = b8(0);
/* We don't byteswap. */
Packet->Header.TotalLength = s_cst(uint16_t, Length + sizeof(IPv4Header));
Packet->Header.TotalLength = s_cst(uint16_t, ((Packet->Header.TotalLength & 0xFF00) >> 8) | ((Packet->Header.TotalLength & 0x00FF) << 8));
Packet->Header.Identification = b16(0x0000);
Packet->Header.Flags = b8(0x0);
Packet->Header.FragmentOffset = b8(0x0);
Packet->Header.TimeToLive = b8(64);
Packet->Header.Protocol = b8(Protocol);
Packet->Header.DestinationIP = b32(DestinationIP.v4.ToHex());
Packet->Header.SourceIP = b32(Ethernet->GetInterface()->IP.v4.ToHex());
Packet->Header.HeaderChecksum = b16(0x0);
Packet->Header.HeaderChecksum = CalculateChecksum((uint16_t *)Packet, sizeof(IPv4Header));
memcpy(Packet->Data, Data, Length);
InternetProtocol DestinationRoute = DestinationIP;
if ((DestinationIP.v4.ToHex() & SubNetworkMaskIP.v4.ToHex()) != (b32(Packet->Header.SourceIP) & SubNetworkMaskIP.v4.ToHex()))
DestinationRoute = SubNetworkMaskIP;
Ethernet->Send(MediaAccessControl().FromHex(ARP->Resolve(DestinationRoute)), this->GetFrameType(), (uint8_t *)Packet, Length + sizeof(IPv4Header));
kfree(Packet);
}
std::vector<IPv4Events *> RegisteredEvents;
__no_sanitize("alignment") bool IPv4::OnEthernetPacketReceived(uint8_t *Data, size_t Length)
{
IPv4Packet *Packet = (IPv4Packet *)Data;
netdbg("Received %d bytes [Protocol %ld]", Length, Packet->Header.Protocol);
if (Length < sizeof(IPv4Header))
{
warn("Packet too short");
return false;
}
bool Reply = false;
if (b32(Packet->Header.DestinationIP) == Ethernet->GetInterface()->IP.v4.ToHex() || b32(Packet->Header.DestinationIP) == 0xFFFFFFFF || Ethernet->GetInterface()->IP.v4.ToHex() == 0)
{
size_t TotalLength = Packet->Header.TotalLength;
if (TotalLength > Length)
TotalLength = Length;
foreach (auto Event in RegisteredEvents)
if (Packet->Header.Protocol == Event->GetProtocol())
{
InternetProtocol SourceIP;
InternetProtocol DestinationIP;
SourceIP.v4 = SourceIP.v4.FromHex(b32(Packet->Header.SourceIP));
DestinationIP.v4 = DestinationIP.v4.FromHex(b32(Packet->Header.DestinationIP));
if (Event->OnIPv4PacketReceived(SourceIP, DestinationIP, (uint8_t *)((uint64_t)Data + 4 * Packet->Header.IHL), TotalLength - 4 * Packet->Header.IHL))
Reply = true;
}
}
else
{
netdbg("Not for us. We are %s but this is for %s",
Ethernet->GetInterface()->IP.v4.ToHex(),
Packet->Header.DestinationIP);
}
if (Reply)
{
uint32_t SwapIP = Packet->Header.DestinationIP;
Packet->Header.DestinationIP = Packet->Header.SourceIP;
Packet->Header.SourceIP = SwapIP;
Packet->Header.TimeToLive = 0x40;
Packet->Header.HeaderChecksum = 0x0;
Packet->Header.HeaderChecksum = CalculateChecksum((uint16_t *)Data, 4 * Packet->Header.TotalLength);
// NIManager->Send(Ethernet->GetInterface(), (uint8_t *)Data, Length);
assert(!"Function not implemented");
}
return Reply;
}
IPv4Events::IPv4Events(IPv4Protocols Protocol)
{
this->Protocol = (uint8_t)Protocol;
RegisteredEvents.push_back(this);
}
IPv4Events::~IPv4Events()
{
forItr(itr, RegisteredEvents)
{
if (*itr == this)
{
RegisteredEvents.erase(itr);
break;
}
}
}
}
namespace NetworkIPv6
{
}

100
Kernel/network/net_dbg.cpp Normal file
View File

@ -0,0 +1,100 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/nc.hpp>
/*
TODO: This code is a mess. It needs to be cleaned up.
*/
#ifdef DEBUG_NETWORK
#include <uart.hpp>
#include <printf.h>
#include <lock.hpp>
using namespace UniversalAsynchronousReceiverTransmitter;
NewLock(netdbg_lock);
namespace NetDbg
{
class NETWORK_DEBUG : public NetworkInterfaceManager::Events
{
public:
static inline void print_wrapper(char c, void *unused) { UART(COM1).Write(c); }
int vprintf(const char *format, va_list list) { return vfctprintf(print_wrapper, NULL, format, list); }
void WriteRaw(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
void DumpData(const char *Description, void *Address, unsigned long Length)
{
SmartLock(netdbg_lock);
WriteRaw("-------------------------------------------------------------------------\n");
unsigned char *AddressChar = (unsigned char *)Address;
unsigned char Buffer[17];
unsigned long Iterate;
if (Description != nullptr)
WriteRaw("%s:\n", Description);
for (Iterate = 0; Iterate < Length; Iterate++)
{
if ((Iterate % 16) == 0)
{
if (Iterate != 0)
WriteRaw(" %s\n", Buffer);
WriteRaw(" %04x ", Iterate);
}
WriteRaw(" %02x", AddressChar[Iterate]);
if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7e))
Buffer[Iterate % 16] = '.';
else
Buffer[Iterate % 16] = AddressChar[Iterate];
Buffer[(Iterate % 16) + 1] = '\0';
}
while ((Iterate % 16) != 0)
{
WriteRaw(" ");
Iterate++;
}
WriteRaw(" %s\n", Buffer);
WriteRaw("-------------------------------------------------------------------------\n");
}
NETWORK_DEBUG() : NetworkInterfaceManager::Events(nullptr) { netdbg("NetworkDebugger initialized."); }
~NETWORK_DEBUG() { netdbg("NetworkDebugger destroyed."); }
void OnInterfaceReceived(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length) { DumpData("Received", Data, Length); }
void OnInterfaceSent(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length) { DumpData("Sent", Data, Length); }
};
}
NetDbg::NETWORK_DEBUG *N;
void DbgNetwork() { N = new NetDbg::NETWORK_DEBUG; }
void DbgDumpData(const char *Description, void *Address, unsigned long Length) { N->DumpData(Description, Address, Length); }
#endif

View File

@ -0,0 +1,240 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/nc.hpp>
#include <net/ipv4.hpp>
#include <net/dhcp.hpp>
#include <net/eth.hpp>
#include <net/arp.hpp>
#include <net/ntp.hpp>
#include <net/dns.hpp>
#include <net/udp.hpp>
#include <debug.h>
#include "../kernel.h"
/* FIXME: The functions MUST have little endian parameters and return values. */
namespace NetworkInterfaceManager
{
std::vector<Events *> RegisteredEvents;
NetworkInterface::NetworkInterface()
{
this->vma = new Memory::VirtualMemoryArea(nullptr);
/* KernelCallback */
// if (DriverManager->GetModules().size() > 0)
// {
// foreach (auto Driver in DriverManager->GetModules())
// if (((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Network)
// this->FetchNetworkCards(Driver.modUniqueID);
// }
// else
// KPrint("\eE85230No network drivers found! Cannot fetch network cards!");
DbgNetwork();
}
NetworkInterface::~NetworkInterface()
{
debug("Destructor called");
// Stop the network stack
this->StopNetworkStack();
// Unregister all events
RegisteredEvents.clear();
forItr(itr, Interfaces) delete *itr;
Interfaces.clear();
// Delete all interfaces and their callbacks and free the memory
delete this->vma, this->vma = nullptr;
}
void NetworkInterface::FetchNetworkCards(unsigned long modUniqueID)
{
// KernelCallback cb{};
// cb.Reason = QueryReason;
// DriverManager->IOCB(modUniqueID, &cb);
/* KernelCallback */
DeviceInterface *Iface = (DeviceInterface *)vma->RequestPages(TO_PAGES(sizeof(DeviceInterface) + 1));
// strcpy(Iface->Name, cb.NetworkCallback.Fetch.Name);
Iface->ID = this->CardIDs++;
// Iface->MAC.FromHex(cb.NetworkCallback.Fetch.MAC);
Iface->DriverID = modUniqueID;
Interfaces.push_back(Iface);
foreach (auto var in RegisteredEvents)
var->OnInterfaceAdded(Iface);
debug("Network Card: %s; MAC: %#lx", Iface->Name, Iface->MAC.ToHex());
}
#ifdef DEBUG_NETWORK
#define DbgWriteScreen(x, ...) KPrint(x, ##__VA_ARGS__)
#else
#define DbgWriteScreen(x, ...) debug(x, ##__VA_ARGS__)
#endif
void NetworkInterface::StartNetworkStack()
{
thisThread->SetPriority(Tasking::TaskPriority::Critical);
DeviceInterface *DefaultDevice = nullptr;
foreach (auto inf in Interfaces)
{
if (inf)
{
DefaultDevice = inf;
break;
}
}
if (!DefaultDevice)
{
error("No network device found!");
KPrint("\eE85230No network device found!");
thisThread->SetPriority(Tasking::TaskPriority::Idle);
CPU::Halt(true);
}
KPrint("Using %s (%s) as the default network device",
DefaultDevice->Name, DefaultDevice->MAC.ToString());
NetworkEthernet::Ethernet *eth = new NetworkEthernet::Ethernet(DefaultDevice); // Use the first device found as the ethernet device
NetworkARP::ARP *arp = new NetworkARP::ARP(eth);
NetworkIPv4::IPv4 *ipv4 = new NetworkIPv4::IPv4(arp, eth);
NetworkUDP::UDP *udp = new NetworkUDP::UDP(ipv4, DefaultDevice);
NetworkUDP::Socket *DHCP_Socket = udp->Connect(InternetProtocol() /* Default value is 255.255.255.255 */, 67);
NetworkDHCP::DHCP *dhcp = new NetworkDHCP::DHCP(DHCP_Socket, DefaultDevice);
debug("eth: %p; arp: %p; ipv4: %p; udp: %p; dhcp: %p",
eth, arp, ipv4, udp, dhcp);
udp->Bind(DHCP_Socket, dhcp);
dhcp->Request();
DefaultDevice->IP.v4.FromHex(dhcp->IP.v4.ToHex());
ipv4->SubNetworkMaskIP = dhcp->SubNetworkMask;
ipv4->GatewayIP = dhcp->Gateway;
arp->Broadcast(dhcp->Gateway);
TaskManager->Sleep(200);
DbgWriteScreen("IP: %s", dhcp->IP.v4.ToStringLittleEndian());
DbgWriteScreen("SubNetwork Mask: %s", dhcp->SubNetworkMask.v4.ToStringLittleEndian());
DbgWriteScreen("Gateway: %s", dhcp->Gateway.v4.ToStringLittleEndian());
DbgWriteScreen("DNS: %s", dhcp->DomainNameSystem.v4.ToStringLittleEndian());
TaskManager->Sleep(200);
/* TODO: This is a quick workaround we need DNS resolver asap.
https://tf.nist.gov/tf-cgi/servers.cgi
https://www.ntppool.org
- 0.ro.pool.ntp.org ( {86, 127, 71, 168} )
- time-a-g.nist.gov ( {129, 6, 15, 28} )
*/
// InternetProtocol ip = {.v4 = {.Address = {129, 6, 15, 28}},
// .v6 = {.Address = {}}};
// NetworkUDP::Socket *NTP_Socket = udp->Connect(ip, 123);
// NetworkNTP::NTP *ntp = new NetworkNTP::NTP(NTP_Socket);
// udp->Bind(NTP_Socket, ntp);
// int UnixTimestamp = ntp->ReadTime();
// Time::Clock time = Time::ConvertFromUnix(UnixTimestamp);
// DbgWriteScreen("NTP: %d - %d.%d.%d %d:%d:%d", time.Counter,
// time.Day, time.Month, time.Year,
// time.Hour, time.Minute, time.Second);
TaskManager->Sleep(200);
/* TODO: Store everything in an vector and initialize all network cards */
thisThread->SetPriority(Tasking::TaskPriority::Idle);
CPU::Halt(true);
}
void NetworkInterface::StopNetworkStack()
{
fixme("Stop network stack");
}
void CallStartNetworkStackWrapper()
{
// NIManager->StartNetworkStack();
assert(!"Function not implemented");
}
void NetworkInterface::StartService()
{
this->NetSvcThread = TaskManager->CreateThread(thisProcess, Tasking::IP(CallStartNetworkStackWrapper));
this->NetSvcThread->Rename("Network Service");
}
void NetworkInterface::DrvSend(unsigned int DriverID, unsigned char *Data, unsigned short Size)
{
// foreach (auto inf in this->Interfaces)
// if (inf->DriverID == DriverID)
// NIManager->Send(inf, Data, Size);
assert(!"Function not implemented");
}
void NetworkInterface::DrvReceive(unsigned int DriverID, unsigned char *Data, unsigned short Size)
{
// foreach (auto inf in this->Interfaces)
// if (inf->DriverID == DriverID)
// NIManager->Receive(inf, Data, Size);
assert(!"Function not implemented");
}
void NetworkInterface::Send(DeviceInterface *Interface, uint8_t *Data, size_t Length)
{
void *DataToBeSent = vma->RequestPages(TO_PAGES(Length + 1));
memcpy(DataToBeSent, Data, Length);
/* KernelCallback */
// KernelCallback cb{};
// cb.Reason = SendReason;
// cb.NetworkCallback.Send.Data = (uint8_t *)DataToBeSent;
// cb.NetworkCallback.Send.Length = Length;
// DriverManager->IOCB(Interface->DriverID, &cb);
vma->FreePages(DataToBeSent, TO_PAGES(Length + 1));
foreach (auto ev in RegisteredEvents)
ev->OnInterfaceSent(Interface, Data, Length);
}
void NetworkInterface::Receive(DeviceInterface *Interface, uint8_t *Data, size_t Length)
{
foreach (auto re in RegisteredEvents)
re->OnInterfaceReceived(Interface, Data, Length);
}
Events::Events(DeviceInterface *Interface)
{
UNUSED(Interface);
RegisteredEvents.push_back(this);
}
Events::~Events()
{
forItr(itr, RegisteredEvents)
{
if (*itr == this)
{
RegisteredEvents.erase(itr);
break;
}
}
}
}

75
Kernel/network/ntp.cpp Normal file
View File

@ -0,0 +1,75 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/ntp.hpp>
#include <debug.h>
#include "../kernel.h"
namespace NetworkNTP
{
void NTP::OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length)
{
UNUSED(Socket);
UNUSED(Length);
this->NTPPacket = *(NTPHeader *)Data;
this->TimeReceived = true;
netdbg("Received UDP packet for NTP.");
}
NTP::NTP(NetworkUDP::Socket *Socket) : NetworkUDP::UDPEvents()
{
debug("NTP interface %#lx created.", this);
this->UDPSocket = Socket;
}
NTP::~NTP()
{
debug("NTP interface %#lx destroyed.", this);
}
int NTP::ReadTime()
{
netdbg("Requesting time");
this->TimeReceived = false;
NTPHeader ReqPacket; // This may require physical memory allocation but Ethernet already has this job.
memset(&ReqPacket, 0, sizeof(NTPHeader)); // Zero out the packet
*((char *)&ReqPacket) = 0x1b; // byteswap nightmare, this is the code below but in little endian
// ReqPacket.LeapIndicator = 0;
// ReqPacket.VersionNumber = 3;
// ReqPacket.Mode = 3;
UDPSocket->SocketUDP->Send(UDPSocket, (uint8_t *)&ReqPacket, sizeof(NTPHeader));
debug("Waiting for response...");
int RequestTimeout = 20;
while (!this->TimeReceived)
{
if (--RequestTimeout == 0)
{
warn("Request timeout.");
return 0;
}
netdbg("Still waiting...");
TaskManager->Sleep(1000);
}
uint64_t UnixTimestamp = (b32(this->NTPPacket.TransmitTimestamp[0])) - 2208988800;
debug("Unix time: %d", UnixTimestamp);
return s_cst(int, UnixTimestamp);
}
}

25
Kernel/network/tcp.cpp Normal file
View File

@ -0,0 +1,25 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/tcp.hpp>
#include <debug.h>
#include "../kernel.h"
namespace NetworkTCP
{
}

145
Kernel/network/udp.cpp Normal file
View File

@ -0,0 +1,145 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <net/udp.hpp>
#include <debug.h>
#include "../kernel.h"
namespace NetworkUDP
{
struct EventInfo
{
Socket *UDPSocket;
uint16_t Port;
};
std::vector<EventInfo> RegisteredEvents;
UDPEvents::UDPEvents() {}
UDPEvents::~UDPEvents() {}
/* -------------------------------------------------------------------------------------------------------------------------------- */
UDP::UDP(NetworkIPv4::IPv4 *ipv4, NetworkInterfaceManager::DeviceInterface *Interface) : NetworkIPv4::IPv4Events(NetworkIPv4::PROTOCOL_UDP)
{
debug("UDP interface %#lx created.", this);
this->ipv4 = ipv4;
this->Interface = Interface;
}
UDP::~UDP()
{
debug("UDP interface %#lx destroyed.", this);
}
uint16_t UsablePort = 0x200;
Socket *UDP::Connect(InternetProtocol IP, uint16_t Port)
{
netdbg("Connecting to %s", IP.v4.ToStringLittleEndian(), Port);
Socket *socket = new Socket(this);
socket->RemoteIP = IP;
socket->RemotePort = Port;
socket->LocalPort = UsablePort++; // TODO: track ports
socket->LocalIP = Interface->IP;
socket->LocalPort = b16(socket->LocalPort);
socket->RemotePort = b16(socket->RemotePort);
RegisteredEvents.push_back({.UDPSocket = socket, .Port = socket->LocalPort});
return socket;
}
Socket *UDP::Listen(uint16_t Port)
{
UNUSED(Port);
fixme("Not implemented");
return nullptr;
}
void UDP::Disconnect(Socket *Socket)
{
UNUSED(Socket);
fixme("Not implemented");
}
void UDP::Send(Socket *Socket, uint8_t *Data, size_t Length)
{
netdbg("Sending %d bytes to %s", Length, Socket->RemoteIP.v4.ToStringLittleEndian(), Socket->RemotePort);
uint16_t TotalLength = s_cst(uint16_t, Length + sizeof(UDPHeader));
UDPPacket *packet = (UDPPacket *)kmalloc(TotalLength);
packet->Header.SourcePort = Socket->LocalPort;
packet->Header.DestinationPort = Socket->RemotePort;
packet->Header.Length = b16(TotalLength);
memcpy(packet->Data, Data, Length);
packet->Header.Checksum = 0; // I totally should do this. Some devices may require it.
// packet->Header.Checksum = CalculateChecksum((uint16_t *)packet, TotalLength);
this->ipv4->Send((uint8_t *)packet, TotalLength, 0x11, Socket->RemoteIP);
kfree(packet);
}
void UDP::Bind(Socket *Socket, UDPEvents *EventHandler)
{
netdbg("Binding socket to %s", Socket->LocalIP.v4.ToStringLittleEndian(), Socket->LocalPort);
Socket->EventHandler = EventHandler;
}
bool UDP::OnIPv4PacketReceived(InternetProtocol SourceIP, InternetProtocol DestinationIP, uint8_t *Data, size_t Length)
{
netdbg("Received %d bytes from %s", Length, SourceIP.v4.ToStringLittleEndian());
if (Length < sizeof(UDPHeader))
return false;
UDPHeader *udp = (UDPHeader *)Data;
netdbg("SP:%d | DP:%d | L:%d | CHK:%#x", b16(udp->SourcePort), b16(udp->DestinationPort), b16(udp->Length), b16(udp->Checksum));
Socket *GoodSocket = nullptr;
foreach (auto &var in RegisteredEvents)
{
netdbg("UDP->SKT[]: LP:%d | LIP:%s | RP:%d | RIP:%s | LST:%d",
b16(var.UDPSocket->LocalPort),
var.UDPSocket->LocalIP.v4.ToStringLittleEndian(),
b16(var.UDPSocket->RemotePort),
var.UDPSocket->RemoteIP.v4.ToStringLittleEndian(),
b16(var.UDPSocket->Listening));
if (var.UDPSocket->LocalPort == udp->DestinationPort &&
var.UDPSocket->LocalIP.v4 == DestinationIP.v4 &&
var.UDPSocket->Listening == true)
{
var.UDPSocket->Listening = false;
var.UDPSocket->RemotePort = b16(udp->SourcePort);
var.UDPSocket->RemoteIP = SourceIP;
netdbg("E1");
return true;
}
GoodSocket = var.UDPSocket;
}
if (GoodSocket)
GoodSocket->EventHandler->OnUDPPacketReceived(GoodSocket, ((UDPPacket *)Data)->Data, Length);
netdbg("E0 (Success)");
return false;
}
/* -------------------------------------------------------------------------------------------------------------------------------- */
Socket::Socket(UDP *_UDP) { this->SocketUDP = _UDP; }
Socket::~Socket() {}
}