mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:38:11 +00:00
Kernel: Bring up enough networking code that we can respond to ARP requests.
This is all pretty rickety but we can now respond to "arping" from the host while running inside QEMU. Very cool. :^)
This commit is contained in:
parent
10dcd3a47f
commit
318b01e055
12 changed files with 229 additions and 40 deletions
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue