Kernel: Add a NetworkTask and a received network packet queue.

It will be easier to deal with incoming packets in a separate task.
This commit is contained in:
Andreas Kling 2019-03-11 12:43:45 +01:00
parent 47b096feb4
commit 35098cbde1
10 changed files with 90 additions and 11 deletions

View file

@ -1,6 +1,6 @@
#pragma once
#include <utility>
#include "StdLibExtras.h"
namespace AK {
@ -35,9 +35,19 @@ public:
T& last() { ASSERT(head()); return tail()->value; }
const T& last() const { ASSERT(head()); return tail()->value; }
T take_first()
{
ASSERT(head());
T value = first();
if (m_tail == m_head)
m_tail = nullptr;
m_head = m_head->next;
return value;
}
void append(T&& value)
{
auto* node = new Node(std::move(value));
auto* node = new Node(move(value));
if (!m_head) {
m_head = node;
m_tail = node;

View file

@ -148,7 +148,6 @@ E1000NetworkAdapter::~E1000NetworkAdapter()
void E1000NetworkAdapter::handle_irq()
{
kprintf("E1000: IRQ!\n");
out32(REG_IMASK, 0x1);
dword status = in32(0xc0);
@ -157,10 +156,9 @@ void E1000NetworkAdapter::handle_irq()
out32(REG_CTRL, flags | ECTRL_SLU);
}
if (status & 0x10) {
kprintf("E1000: threshold\n");
// Threshold OK?
}
if (status & 0x80) {
kprintf("E1000: receive...\n");
receive();
}
}
@ -318,8 +316,8 @@ void E1000NetworkAdapter::send_raw(const byte* data, int length)
auto& descriptor = m_tx_descriptors[m_tx_current];
descriptor.addr = (uint64_t)data;
descriptor.length = length;
descriptor.cmd = (1 << 3) | 3;
m_tx_current = m_tx_current + 1 % number_of_tx_descriptors;
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))
;
@ -333,7 +331,7 @@ void E1000NetworkAdapter::receive()
word length = m_rx_descriptors[m_rx_current].length;
kprintf("E1000: Received 1 packet @ %p (%u) bytes!\n", buffer, length);
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;

View file

@ -1,6 +1,7 @@
#pragma once
#include <AK/Assertions.h>
#include <AK/AKString.h>
#include <AK/Types.h>
#include <Kernel/StdLib.h>
@ -19,6 +20,11 @@ public:
return m_data[i];
}
String to_string() const
{
return String::format("%b:%b:%b:%b:%b:%b", m_data[0], m_data[1], m_data[2], m_data[3], m_data[4], m_data[5]);
}
private:
byte m_data[6];
};

View file

@ -35,7 +35,8 @@ KERNEL_OBJS = \
Socket.o \
LocalSocket.o \
NetworkAdapter.o \
E1000NetworkAdapter.o
E1000NetworkAdapter.o \
NetworkTask.o
VFS_OBJS = \
DiskDevice.o \

View file

@ -21,3 +21,17 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet
send_raw((byte*)eth, size_in_bytes);
kfree(eth);
}
void NetworkAdapter::did_receive(const byte* data, int length)
{
InterruptDisabler disabler;
m_packet_queue.append(ByteBuffer::copy(data, length));
}
ByteBuffer NetworkAdapter::dequeue_packet()
{
InterruptDisabler disabler;
if (m_packet_queue.is_empty())
return { };
return m_packet_queue.take_first();
}

View file

@ -1,5 +1,7 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/SinglyLinkedList.h>
#include <AK/Types.h>
#include <Kernel/MACAddress.h>
#include <Kernel/ARPPacket.h>
@ -13,11 +15,15 @@ public:
void send(const MACAddress&, const ARPPacket&);
ByteBuffer dequeue_packet();
protected:
NetworkAdapter();
void set_mac_address(const MACAddress& mac_address) { m_mac_address = mac_address; }
virtual void send_raw(const byte*, int) = 0;
void did_receive(const byte*, int);
private:
MACAddress m_mac_address;
SinglyLinkedList<ByteBuffer> m_packet_queue;
};

33
Kernel/NetworkTask.cpp Normal file
View file

@ -0,0 +1,33 @@
#include <Kernel/E1000NetworkAdapter.h>
#include <Kernel/EthernetFrameHeader.h>
#include <Kernel/ARPPacket.h>
#include <Kernel/Process.h>
void NetworkTask_main()
{
auto* e1000_ptr = E1000NetworkAdapter::the();
ASSERT(e1000_ptr);
auto& e1000 = *e1000_ptr;
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)
e1000.send(MACAddress(), arp);
kprintf("NetworkTask: Enter main loop.\n");
for (;;) {
auto packet = e1000.dequeue_packet();
if (packet.is_null()) {
sleep(100);
continue;
}
if (packet.size() < sizeof(EthernetFrameHeader) + 4) {
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());
}
}

3
Kernel/NetworkTask.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
void NetworkTask_main();

View file

@ -24,6 +24,7 @@
#include "DevPtsFS.h"
#include "BXVGADevice.h"
#include "E1000NetworkAdapter.h"
#include <Kernel/NetworkTask.h>
#define SPAWN_LAUNCHER
//#define SPAWN_GUITEST2
@ -186,6 +187,7 @@ VFS* vfs;
Scheduler::yield();
}
});
Process::create_kernel_process("NetworkTask", NetworkTask_main);
Scheduler::pick_next();

View file

@ -1,8 +1,14 @@
#!/bin/sh
if [ "$1" = "q" ]; then
if [ "$1" = "b" ]; then
# ./run b: bochs
bochs -q -f .bochsrc
elif [ "$1" = "qn" ]; then
# ./run qn: qemu without network
qemu-system-i386 -s -m 32 -device e1000 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents #$@
else
bochs -q -f .bochsrc
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 #$
fi