Add UDP reception support
This commit is contained in:
@@ -89,9 +89,16 @@ QEMU_DEV_HDA=-drive file=$(QEMU_HDA),format=raw,id=disk_hda
|
||||
QEMU_DEVS+=$(QEMU_DEV_HDA)
|
||||
endif
|
||||
|
||||
ifdef QEMU_NET_TAP
|
||||
QEMU_NETDEV=-netdev type=tap,id=net0
|
||||
else
|
||||
QEMU_NETDEV=-netdev type=user,hostfwd=tcp::5555-:22,hostfwd=udp::5555-:22,id=net0
|
||||
endif
|
||||
|
||||
ifdef QEMU_NET
|
||||
QEMU_DEV_NET=-device $(QEMU_NET),netdev=net0,mac=11:22:33:44:55:66 \
|
||||
-netdev type=user,hostfwd=tcp::5555-:22,hostfwd=udp::5555-:22,id=net0
|
||||
$(QEMU_NETDEV) \
|
||||
-object filter-dump,id=f1,netdev=net0,file=eth_dump.dat
|
||||
QEMU_DEVS+=$(QEMU_DEV_NET)
|
||||
endif
|
||||
|
||||
|
||||
+3
-1
@@ -61,7 +61,9 @@ OBJS+=$(O)/sys/debug.o \
|
||||
$(O)/sys/vfs/tar.o \
|
||||
$(O)/sys/blk/ram.o \
|
||||
$(O)/sys/ring.o \
|
||||
$(O)/sys/net/eth.o
|
||||
$(O)/sys/net/eth.o \
|
||||
$(O)/sys/net/arp.o \
|
||||
$(O)/sys/net/in.o
|
||||
DIRS+=$(O)/sys/vfs/ext2 \
|
||||
$(O)/sys/net \
|
||||
$(O)/sys/blk
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "sys/net/netdev.h"
|
||||
|
||||
struct arp_frame {
|
||||
uint16_t htype;
|
||||
uint16_t ptype;
|
||||
uint8_t hlen;
|
||||
uint8_t plen;
|
||||
uint16_t oper;
|
||||
uint8_t sha[6];
|
||||
uint32_t spa;
|
||||
uint8_t tha[6];
|
||||
uint32_t tpa;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct arp_route {
|
||||
struct netdev *dev;
|
||||
uint32_t addr_in;
|
||||
uint8_t hwaddr[6];
|
||||
struct arp_route *next;
|
||||
};
|
||||
|
||||
struct arp_route *arp_find_route_in(struct netdev *dev, uint32_t inaddr);
|
||||
void arp_handle_frame(struct netdev *dev, struct arp_frame *arp_frame);
|
||||
+15
-1
@@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
#include "sys/net/netdev.h"
|
||||
|
||||
#define ETHERTYPE_ARP 0x0806
|
||||
#define ETHERTYPE_IPV4 0x0800
|
||||
|
||||
struct eth_frame {
|
||||
uint8_t dst_mac[6];
|
||||
@@ -8,5 +12,15 @@ struct eth_frame {
|
||||
char payload[];
|
||||
} __attribute__((packed));
|
||||
|
||||
// Packet queue entry
|
||||
struct ethq {
|
||||
struct ethq *next;
|
||||
struct netdev *dev;
|
||||
char data[];
|
||||
};
|
||||
|
||||
// Ethernet queue stuff
|
||||
void ethq_handle(void);
|
||||
|
||||
// TODO: replace (void *) with (struct netdev *)
|
||||
void eth_handle_frame(void *dev, struct eth_frame *frame, size_t packet_size);
|
||||
void eth_handle_frame(struct netdev *dev, struct eth_frame *frame, size_t packet_size);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "sys/net/netdev.h"
|
||||
|
||||
#define INADDR_FMT "%u.%u.%u.%u"
|
||||
#define INADDR_VA(x) ((x) & 0xFF), (((x) >> 8) & 0xFF), \
|
||||
(((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
|
||||
|
||||
#define IN_PROTO_UDP 0x11
|
||||
|
||||
struct in_frame {
|
||||
uint8_t version;
|
||||
uint8_t dscp;
|
||||
uint16_t length;
|
||||
uint16_t id;
|
||||
uint16_t flag_frag_offset;
|
||||
uint8_t ttl;
|
||||
uint8_t protocol;
|
||||
uint16_t header_chksum;
|
||||
uint32_t src_inaddr;
|
||||
uint32_t dst_inaddr;
|
||||
char payload[];
|
||||
} __attribute__((packed));
|
||||
|
||||
void in_handle_frame(struct netdev *dev, struct in_frame *frame);
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
struct netdev;
|
||||
|
||||
typedef int (*netdev_tx_func_t) (struct netdev *, const void *, size_t);
|
||||
|
||||
struct netdev {
|
||||
uint8_t hwaddr[6];
|
||||
char name[32];
|
||||
netdev_tx_func_t tx;
|
||||
};
|
||||
+115
-9
@@ -3,8 +3,10 @@
|
||||
#include "sys/amd64/hw/irq.h"
|
||||
#include "sys/amd64/hw/io.h"
|
||||
#include "sys/net/eth.h"
|
||||
#include "sys/net/netdev.h"
|
||||
#include "sys/net/net.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/heap.h"
|
||||
#include "sys/attr.h"
|
||||
@@ -30,6 +32,8 @@
|
||||
#define RTL8139_CONFIG1 0x52
|
||||
#define RTL8139_MSR 0x58
|
||||
|
||||
#define RTL8139_TSD_OWN (1 << 13)
|
||||
|
||||
#define RTL8139_CR_RST (1 << 4)
|
||||
#define RTL8139_CR_RE (1 << 3)
|
||||
#define RTL8139_CR_TE (1 << 2)
|
||||
@@ -52,13 +56,23 @@
|
||||
#define RTL8139_IMR_ROK (1 << 0)
|
||||
|
||||
struct rtl8139 {
|
||||
struct netdev net;
|
||||
|
||||
uint32_t bar0;
|
||||
// Receive buffer: 3 pages
|
||||
uint32_t page0;
|
||||
uint32_t tx_pages[4];
|
||||
size_t tx_sizes[4];
|
||||
// Bits:
|
||||
// 0..3: TX_BUSY Set by _tx(), cleared by _handle_tx(), means that
|
||||
// the descriptor cannot be allocated
|
||||
uint32_t tx_flag;
|
||||
uint32_t cbr_prev;
|
||||
uint32_t tx_number;
|
||||
};
|
||||
|
||||
static void rtl8139_handle_recv(struct rtl8139 *rtl);
|
||||
static void rtl8139_handle_rx(struct rtl8139 *rtl);
|
||||
static void rtl8139_handle_tx(struct rtl8139 *rtl, int succ);
|
||||
|
||||
static uint32_t rtl8139_irq(void *ctx) {
|
||||
struct rtl8139 *rtl = ctx;
|
||||
@@ -67,7 +81,10 @@ static uint32_t rtl8139_irq(void *ctx) {
|
||||
if (isr) {
|
||||
if (isr & RTL8139_ISR_ROK) {
|
||||
// Got a packet
|
||||
rtl8139_handle_recv(rtl);
|
||||
rtl8139_handle_rx(rtl);
|
||||
}
|
||||
if (isr & (RTL8139_ISR_TOK | RTL8139_ISR_TER)) {
|
||||
rtl8139_handle_tx(rtl, isr & RTL8139_ISR_TOK);
|
||||
}
|
||||
|
||||
// Implementation of RTL8139 in qemu differs
|
||||
@@ -81,7 +98,7 @@ static uint32_t rtl8139_irq(void *ctx) {
|
||||
return IRQ_UNHANDLED;
|
||||
}
|
||||
|
||||
static void rtl8139_handle_recv(struct rtl8139 *rtl) {
|
||||
static void rtl8139_handle_rx(struct rtl8139 *rtl) {
|
||||
kdebug("Received a packet\n");
|
||||
uint16_t cbr = inw(rtl->bar0 + RTL8139_CBR);
|
||||
size_t packet_size;
|
||||
@@ -103,7 +120,81 @@ static void rtl8139_handle_recv(struct rtl8139 *rtl) {
|
||||
uint16_t recv_status = ((uint16_t *) pack)[0];
|
||||
uint16_t recv_length = ((uint16_t *) pack)[1];
|
||||
|
||||
eth_handle_frame(rtl, eth_frame, packet_size);
|
||||
kdebug("Recv status: %u\n", recv_status);
|
||||
|
||||
//kdebug("Recv length = %u\n", recv_length);
|
||||
//kdebug("Packet size = %u\n", packet_size);
|
||||
//_assert(recv_length == (packet_size - 4));
|
||||
|
||||
eth_handle_frame(&rtl->net, eth_frame, recv_length);
|
||||
}
|
||||
|
||||
static void rtl8139_cmd_tx(struct rtl8139 *rtl) {
|
||||
kdebug("HW TX %d\n", rtl->tx_number);
|
||||
|
||||
uint8_t n = rtl->tx_number;
|
||||
|
||||
++rtl->tx_number;
|
||||
if (rtl->tx_number == 4) {
|
||||
rtl->tx_number = 0;
|
||||
}
|
||||
|
||||
outl(rtl->bar0 + RTL8139_TSD(n), rtl->tx_sizes[n]);
|
||||
}
|
||||
|
||||
static void rtl8139_handle_tx(struct rtl8139 *rtl, int s) {
|
||||
uint8_t prev = 3;
|
||||
if (rtl->tx_number != 0) {
|
||||
prev = rtl->tx_number - 1;
|
||||
}
|
||||
|
||||
kdebug("%s Tx on %d\n", s ? "Successful" : "Failed", prev);
|
||||
kdebug("Clearing TxD%d\n", prev);
|
||||
rtl->tx_flag &= ~(1 << prev);
|
||||
rtl->tx_sizes[prev] = 0;
|
||||
|
||||
kdebug("TX Done!\n");
|
||||
|
||||
// If after transmission we reached a new entry and it's
|
||||
// awaiting transmission - emit a Tx command
|
||||
while (rtl->tx_flag & (1 << rtl->tx_number)) {
|
||||
rtl8139_cmd_tx(rtl);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t rtl8139_alloc_tx(struct rtl8139 *rtl) {
|
||||
for (uint8_t i = rtl->tx_number; i < 4; ++i) {
|
||||
if (!(rtl->tx_flag & (1 << i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for (uint8_t i = 0; i < rtl->tx_number; ++i) {
|
||||
if (!(rtl->tx_flag & (1 << i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
static int rtl8139_tx(struct netdev *net, const void *packet, size_t size) {
|
||||
kdebug("Requested Tx\n");
|
||||
struct rtl8139 *rtl = (struct rtl8139 *) net;
|
||||
|
||||
uint8_t index = rtl8139_alloc_tx(rtl);
|
||||
// TODO: transmit queue for this?
|
||||
assert(index != 0xFF, "No free TSADx\n");
|
||||
|
||||
void *page = (void *) MM_VIRTUALIZE(rtl->tx_pages[index]);
|
||||
memcpy(page, packet, size);
|
||||
|
||||
rtl->tx_sizes[index] = size;
|
||||
|
||||
if (index == rtl->tx_number) {
|
||||
// Can tx right now
|
||||
rtl8139_cmd_tx(rtl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pci_rtl8139_init(pci_addr_t addr) {
|
||||
@@ -138,6 +229,16 @@ void pci_rtl8139_init(pci_addr_t addr) {
|
||||
assert(rtl->page0 != MM_NADDR, "Failed to allocate RxBuf\n");
|
||||
outl(rtl->bar0 + RTL8139_RBSTART, rtl->page0);
|
||||
|
||||
// Initialize tx buffers
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
rtl->tx_pages[i] = amd64_phys_alloc_page();
|
||||
rtl->tx_sizes[i] = 0;
|
||||
assert(rtl->tx_pages[i] != MM_NADDR, "Failed to allocate TxBuf\n");
|
||||
outl(rtl->bar0 + RTL8139_TSAD(i), rtl->tx_pages[i]);
|
||||
}
|
||||
rtl->tx_flag = 0;
|
||||
rtl->tx_number = 0;
|
||||
|
||||
// Accept all
|
||||
outl(rtl->bar0 + RTL8139_RCR, RTL8139_RCR_APM | RTL8139_RCR_AB | RTL8139_RCR_WRAP);
|
||||
|
||||
@@ -151,16 +252,21 @@ void pci_rtl8139_init(pci_addr_t addr) {
|
||||
}
|
||||
|
||||
// Configure interrupt mask
|
||||
outw(rtl->bar0 + RTL8139_IMR, RTL8139_IMR_ROK | RTL8139_IMR_RER);
|
||||
outw(rtl->bar0 + RTL8139_IMR, RTL8139_IMR_ROK | RTL8139_IMR_RER |
|
||||
RTL8139_IMR_TOK | RTL8139_IMR_TER);
|
||||
// Clear ISR
|
||||
outw(rtl->bar0 + RTL8139_ISR, 0);
|
||||
|
||||
// Dump contents of MAC register
|
||||
uint8_t mac[6];
|
||||
// After the reset, controller uses Tx pair 0
|
||||
rtl->tx_number = 0;
|
||||
|
||||
// Setup a system network device
|
||||
for (size_t i = 0; i < 6; ++i) {
|
||||
mac[i] = inb(rtl->bar0 + RTL8139_IDR0 + i);
|
||||
rtl->net.hwaddr[i] = inb(rtl->bar0 + RTL8139_IDR0 + i);
|
||||
}
|
||||
kdebug("RTL8139 MAC: " MAC_FMT "\n", MAC_VA(mac));
|
||||
kdebug("RTL8139 MAC: " MAC_FMT "\n", MAC_VA(rtl->net.hwaddr));
|
||||
rtl->net.tx = rtl8139_tx;
|
||||
// TODO: call some kind of netdev_add to bind a name to the device
|
||||
}
|
||||
|
||||
static __init void pci_rtl8139_register(void) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "sys/amd64/mm/mm.h"
|
||||
#include "sys/amd64/mm/pool.h"
|
||||
#include "sys/amd64/cpu.h"
|
||||
#include "sys/net/eth.h"
|
||||
#include "sys/thread.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/heap.h"
|
||||
@@ -126,6 +127,10 @@ void init_func(void *arg) {
|
||||
|
||||
while (1) {
|
||||
asm volatile ("sti; hlt");
|
||||
|
||||
// I've decided not to create a separate thread for network handling yet,
|
||||
// so the code will be here
|
||||
ethq_handle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "sys/net/arp.h"
|
||||
#include "sys/net/eth.h"
|
||||
#include "sys/net/net.h"
|
||||
#include "sys/net/in.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/heap.h"
|
||||
|
||||
static struct arp_route *arp_routes_head = NULL;
|
||||
static struct arp_route *arp_routes_tail = NULL;
|
||||
|
||||
void arp_add_route_in(struct netdev *dev, uint32_t inaddr, uint8_t *hwaddr) {
|
||||
struct arp_route *rt = (struct arp_route *) kmalloc(sizeof(struct arp_route));
|
||||
_assert(rt);
|
||||
kdebug("Added ARP route: " INADDR_FMT " is " MAC_FMT "\n", INADDR_VA(inaddr), MAC_VA(hwaddr));
|
||||
|
||||
memcpy(rt->hwaddr, hwaddr, 6);
|
||||
rt->dev = dev;
|
||||
rt->addr_in = inaddr;
|
||||
rt->next = NULL;
|
||||
|
||||
if (arp_routes_tail) {
|
||||
arp_routes_tail->next = rt;
|
||||
} else {
|
||||
arp_routes_head = rt;
|
||||
}
|
||||
arp_routes_tail = rt;
|
||||
}
|
||||
|
||||
struct arp_route *arp_find_route_in(struct netdev *dev, uint32_t inaddr) {
|
||||
for (struct arp_route *rt = arp_routes_head; rt; rt = rt->next) {
|
||||
if (dev == rt->dev && rt->addr_in == inaddr) {
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void arp_handle_frame(struct netdev *dev, struct arp_frame *arp_frame) {
|
||||
uint16_t oper = htons(arp_frame->oper);
|
||||
|
||||
kdebug("ARP frame:\n");
|
||||
kdebug("\tOperation: %s\n", (oper == 1) ? "Request" : "Reply");
|
||||
kdebug("\tSHA: " MAC_FMT "\n", MAC_VA(arp_frame->sha));
|
||||
kdebug("\tTHA: " MAC_FMT "\n", MAC_VA(arp_frame->tha));
|
||||
kdebug("\tSPA: " INADDR_FMT "\n", INADDR_VA(arp_frame->spa));
|
||||
kdebug("\tTPA: " INADDR_FMT "\n", INADDR_VA(arp_frame->tpa));
|
||||
|
||||
struct arp_route *rt;
|
||||
if ((rt = arp_find_route_in(dev, arp_frame->spa))) {
|
||||
memcpy(rt->hwaddr, arp_frame->sha, 6);
|
||||
}
|
||||
|
||||
// TODO: check that TPA actually belongs to a netdev
|
||||
if (arp_frame->tpa == 0x0F02000A /* 10.0.2.15 */) {
|
||||
if (!rt) {
|
||||
arp_add_route_in(dev, arp_frame->spa, arp_frame->sha);
|
||||
}
|
||||
|
||||
if (oper == 1) {
|
||||
// Someone requested a MAC for IPv4
|
||||
char packet[sizeof(struct eth_frame) + sizeof(struct arp_frame)] = {0};
|
||||
struct eth_frame *r_eth_frame = (struct eth_frame *) packet;
|
||||
struct arp_frame *r_arp_frame = (struct arp_frame *) r_eth_frame->payload;
|
||||
|
||||
// ETH
|
||||
r_eth_frame->ethertype = htons(ETHERTYPE_ARP);
|
||||
memcpy(r_eth_frame->dst_mac, arp_frame->sha, 6);
|
||||
memcpy(r_eth_frame->src_mac, dev->hwaddr, 6);
|
||||
|
||||
// ARP
|
||||
r_arp_frame->htype = arp_frame->htype;
|
||||
r_arp_frame->ptype = arp_frame->ptype;
|
||||
r_arp_frame->hlen = arp_frame->hlen;
|
||||
r_arp_frame->plen = arp_frame->plen;
|
||||
r_arp_frame->oper = htons(2);
|
||||
memcpy(r_arp_frame->sha, dev->hwaddr, 6);
|
||||
r_arp_frame->spa = arp_frame->tpa;
|
||||
memcpy(r_arp_frame->tha, arp_frame->sha, 6);
|
||||
r_arp_frame->tpa = arp_frame->spa;
|
||||
|
||||
if (dev->tx) {
|
||||
dev->tx(dev, packet, sizeof(struct eth_frame) + sizeof(struct arp_frame));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
-35
@@ -1,52 +1,80 @@
|
||||
#include "sys/net/eth.h"
|
||||
#include "sys/net/net.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/heap.h"
|
||||
#include "sys/spin.h"
|
||||
|
||||
#define ETHERTYPE_ARP 0x0806
|
||||
#define ETHERTYPE_IPV4 0x0800
|
||||
#include "sys/net/arp.h"
|
||||
#include "sys/net/in.h"
|
||||
|
||||
#define INADDR_FMT "%u.%u.%u.%u"
|
||||
#define INADDR_VA(x) ((x) & 0xFF), (((x) >> 8) & 0xFF), \
|
||||
(((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
|
||||
static spin_t ethq_lock = 0;
|
||||
static int ethq_count = 0;
|
||||
static struct ethq *ethq_head = NULL, *ethq_tail = NULL;
|
||||
|
||||
struct arp_frame {
|
||||
uint16_t htype;
|
||||
uint16_t ptype;
|
||||
uint8_t hlen;
|
||||
uint8_t plen;
|
||||
uint16_t oper;
|
||||
uint8_t sha[6];
|
||||
uint32_t spa;
|
||||
uint8_t tha[6];
|
||||
uint32_t tpa;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Just for testing
|
||||
static void arp_handle_frame(void *dev, struct arp_frame *arp_frame) {
|
||||
kdebug("ARP frame:\n");
|
||||
kdebug("\tOperation: %s\n", (htons(arp_frame->oper) == 1) ? "Request" : "Reply");
|
||||
kdebug("\tSHA: " MAC_FMT "\n", MAC_VA(arp_frame->sha));
|
||||
kdebug("\tTHA: " MAC_FMT "\n", MAC_VA(arp_frame->tha));
|
||||
kdebug("\tSPA: " INADDR_FMT "\n", INADDR_VA(arp_frame->spa));
|
||||
kdebug("\tTPA: " INADDR_FMT "\n", INADDR_VA(arp_frame->tpa));
|
||||
static struct ethq *ethq_pop(void) {
|
||||
if (ethq_head) {
|
||||
struct ethq *head = ethq_head;
|
||||
if (!head->next) {
|
||||
ethq_tail = NULL;
|
||||
}
|
||||
ethq_head = head->next;
|
||||
return head;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void eth_handle_frame(void *dev, struct eth_frame *eth_frame, size_t packet_size) {
|
||||
debug_dump(DEBUG_DEFAULT, eth_frame, packet_size - 4);
|
||||
static void ethq_add(struct netdev *dev, struct eth_frame *eth_frame, size_t packet_size) {
|
||||
struct ethq *ent = (struct ethq *) kmalloc(packet_size + sizeof(struct ethq));
|
||||
ent->dev = dev;
|
||||
ent->next = NULL;
|
||||
memcpy(ent->data, eth_frame, packet_size);
|
||||
|
||||
if (eth_frame->ethertype >= 1536) {
|
||||
kdebug("DST: " MAC_FMT ", SRC: " MAC_FMT "\n",
|
||||
MAC_VA(eth_frame->dst_mac),
|
||||
MAC_VA(eth_frame->src_mac));
|
||||
spin_lock(ðq_lock);
|
||||
if (ethq_tail) {
|
||||
ethq_tail->next = ent;
|
||||
} else {
|
||||
ethq_head = ent;
|
||||
}
|
||||
ethq_tail = ent;
|
||||
++ethq_count;
|
||||
spin_release(ðq_lock);
|
||||
|
||||
kdebug("Added\n");
|
||||
}
|
||||
|
||||
// The function takes a single packet from the queue
|
||||
// and processes it
|
||||
void ethq_handle(void) {
|
||||
spin_lock(ðq_lock);
|
||||
struct ethq *ethq = ethq_pop();
|
||||
spin_release(ðq_lock);
|
||||
|
||||
if (ethq) {
|
||||
struct eth_frame *eth_frame = (struct eth_frame *) ethq->data;
|
||||
|
||||
// Ethernet II frame
|
||||
switch (eth_frame->ethertype) {
|
||||
case htons(ETHERTYPE_ARP):
|
||||
arp_handle_frame(dev, (struct arp_frame *) eth_frame->payload);
|
||||
arp_handle_frame(ethq->dev, (struct arp_frame *) eth_frame->payload);
|
||||
break;
|
||||
case htons(ETHERTYPE_IPV4):
|
||||
kdebug("IPv4 frame\n");
|
||||
case htons(ETHERTYPE_IPV4):
|
||||
in_handle_frame(ethq->dev, (struct in_frame *) eth_frame->payload);
|
||||
break;
|
||||
default:
|
||||
kdebug("Unsupported frame type: %04x\n", htons(eth_frame->ethertype));
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(ethq);
|
||||
}
|
||||
}
|
||||
|
||||
// Called from interrupt handler
|
||||
void eth_handle_frame(struct netdev *dev, struct eth_frame *eth_frame, size_t packet_size) {
|
||||
debug_dump(DEBUG_DEFAULT, eth_frame, packet_size);
|
||||
|
||||
if (htons(eth_frame->ethertype) >= 1536) {
|
||||
ethq_add(dev, eth_frame, packet_size);
|
||||
}
|
||||
// Ignore all other packets
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "sys/net/in.h"
|
||||
#include "sys/net/net.h"
|
||||
#include "sys/net/arp.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/debug.h"
|
||||
|
||||
struct udp_frame {
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
char payload[];
|
||||
};
|
||||
|
||||
static void udp_handle_frame(struct netdev *dev, int in6, void *frame, struct udp_frame *udp) {
|
||||
// in6 is required to be 0 now, I haven't yet implemented IPv6 support
|
||||
_assert(!in6);
|
||||
struct in_frame *in_frame = frame;
|
||||
|
||||
// Ignore UDP checksums
|
||||
kdebug("UDP packet\n");
|
||||
kdebug("\tsrcport: %u\n", htons(udp->src_port));
|
||||
kdebug("\tdstport: %u\n", htons(udp->dst_port));
|
||||
kdebug("\tLength: %u\n", htons(udp->length));
|
||||
|
||||
debug_dump(DEBUG_DEFAULT, udp->payload, htons(udp->length) - 8);
|
||||
}
|
||||
|
||||
void in_handle_frame(struct netdev *dev, struct in_frame *frame) {
|
||||
kdebug("INET frame\n");
|
||||
kdebug("\tTotal length: %u\n", htons(frame->length));
|
||||
kdebug("\tsrcaddr: " INADDR_FMT "\n", INADDR_VA(frame->src_inaddr));
|
||||
kdebug("\tdstaddr: " INADDR_FMT "\n", INADDR_VA(frame->dst_inaddr));
|
||||
|
||||
uint16_t checksum = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(struct in_frame) / 2; ++i) {
|
||||
checksum += ((uint16_t *) frame)[i];
|
||||
}
|
||||
kdebug("IP checksum = %04x\n", checksum);
|
||||
|
||||
//if (checksum != 0xFFFF) {
|
||||
// kwarn("Packet IP checksum mismatch\n");
|
||||
// // Drop packet
|
||||
// return;
|
||||
//}
|
||||
|
||||
switch (frame->protocol) {
|
||||
case IN_PROTO_UDP:
|
||||
udp_handle_frame(dev, 0, frame, (struct udp_frame *) frame->payload);
|
||||
break;
|
||||
default:
|
||||
kwarn("Unhandled IP protocol: %02x\n", frame->protocol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user