From 8d6ecc7134ef21f7eccc39cefd3abf9545e25194 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 20 Mar 2020 11:11:14 +0200 Subject: [PATCH] Add ARP stub --- etc/make/conf.mk | 5 ++++- include/net/arp.h | 21 +++++++++++++++++++ include/net/eth.h | 15 +++++++++++++ include/net/packet.h | 11 ++++++++++ include/net/util.h | 8 +++++++ net/arp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ net/eth.c | 28 +++++++++++++++++++++++++ net/net.c | 18 +++++++--------- net/util.c | 11 ++++++++++ 9 files changed, 155 insertions(+), 12 deletions(-) create mode 100644 include/net/arp.h create mode 100644 include/net/eth.h create mode 100644 include/net/packet.h create mode 100644 include/net/util.h create mode 100644 net/arp.c create mode 100644 net/eth.c create mode 100644 net/util.c diff --git a/etc/make/conf.mk b/etc/make/conf.mk index cdccd54..966535f 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -95,7 +95,10 @@ DIRS+=$(O)/drivers/pci \ OBJS+=$(O)/drivers/net/rtl8139.o DIRS+=$(O)/drivers/net -OBJS+=$(O)/net/net.o +OBJS+=$(O)/net/net.o \ + $(O)/net/eth.o \ + $(O)/net/arp.o \ + $(O)/net/util.o DIRS+=$(O)/net ifeq ($(DEBUG_COUNTERS),1) diff --git a/include/net/arp.h b/include/net/arp.h new file mode 100644 index 0000000..41b2988 --- /dev/null +++ b/include/net/arp.h @@ -0,0 +1,21 @@ +#pragma once +#include "sys/types.h" + +#define ARP_H_ETH 1 +#define ARP_P_IP 0x0800 + +struct arp_frame { + uint16_t htype; + uint16_t ptype; + uint8_t hlen; + uint8_t plen; + uint16_t oper; + // INET only + uint8_t sha[6]; + uint32_t spa; + uint8_t tha[6]; + uint32_t tpa; +} __attribute__((packed)); + +struct packet; +void arp_handle_frame(struct packet *packet, void *data, size_t len); diff --git a/include/net/eth.h b/include/net/eth.h new file mode 100644 index 0000000..69cdeb5 --- /dev/null +++ b/include/net/eth.h @@ -0,0 +1,15 @@ +#pragma once +#include "sys/types.h" + +#define ETH_T_IP 0x0800 +#define ETH_T_IPv6 0x86DD +#define ETH_T_ARP 0x0806 + +struct eth_frame { + uint8_t dst_hwaddr[6]; + uint8_t src_hwaddr[6]; + uint16_t ethertype; +} __attribute__((packed)); + +struct packet; +void eth_handle_frame(struct packet *p); diff --git a/include/net/packet.h b/include/net/packet.h new file mode 100644 index 0000000..3f82e4c --- /dev/null +++ b/include/net/packet.h @@ -0,0 +1,11 @@ +#pragma once +#include "sys/types.h" + +// Takes up a single page +#define PACKET_DATA_MAX (4064) +struct packet { + size_t size; + struct packet *prev, *next; + void *source_if; + char data[PACKET_DATA_MAX]; +}; diff --git a/include/net/util.h b/include/net/util.h new file mode 100644 index 0000000..a7e58ff --- /dev/null +++ b/include/net/util.h @@ -0,0 +1,8 @@ +#pragma once +#include "sys/types.h" + +void strmac(char *dst, const uint8_t *hw); + +static inline uint16_t ntohs(uint16_t w) { + return (w >> 8) | (w << 8); +} diff --git a/net/arp.c b/net/arp.c new file mode 100644 index 0000000..ccfcafd --- /dev/null +++ b/net/arp.c @@ -0,0 +1,50 @@ +#include "sys/debug.h" +#include "net/util.h" +#include "net/arp.h" + + +/* +?Do I have the hardware type in ar$hrd? +Yes: (almost definitely) + [optionally check the hardware length ar$hln] + ?Do I speak the protocol in ar$pro? + Yes: + [optionally check the protocol length ar$pln] + Merge_flag := false + If the pair is + already in my translation table, update the sender + hardware address field of the entry with the new + information in the packet and set Merge_flag to true. + ?Am I the target protocol address? + Yes: + If Merge_flag is false, add the triplet to + the translation table. + ?Is the opcode ares_op$REQUEST? (NOW look at the opcode!!) + Yes: + Swap hardware and protocol fields, putting the local + hardware and protocol addresses in the sender fields. + Set the ar$op field to ares_op$REPLY + Send the packet to the (new) target hardware address on + the same hardware on which the request was received. +*/ + + +void arp_handle_frame(struct packet *p, void *data, size_t len) { + if (len < sizeof(struct arp_frame)) { + kwarn("Dropping undersized frame: %u\n", len); + return; + } + + struct arp_frame *arp = data; + + if (ntohs(arp->htype) != ARP_H_ETH) { + kwarn("Dropping non-ethernet packet\n"); + return; + } + if (ntohs(arp->ptype) != ARP_P_IP) { + kwarn("Dropping non-IP packet\n"); + return; + } + +} diff --git a/net/eth.c b/net/eth.c new file mode 100644 index 0000000..2e27e8c --- /dev/null +++ b/net/eth.c @@ -0,0 +1,28 @@ +#include "net/packet.h" +#include "sys/debug.h" +#include "net/util.h" +#include "net/eth.h" + +#include "net/arp.h" + +void eth_handle_frame(struct packet *p) { + struct eth_frame *eth = (struct eth_frame *) p->data; + + if (p->size < sizeof(struct eth_frame)) { + kwarn("Dropping undersized packet: %u\n", p->size); + return; + } + + switch (ntohs(eth->ethertype)) { + case ETH_T_ARP: + arp_handle_frame(p, p->data + sizeof(struct eth_frame), p->size - sizeof(struct eth_frame)); + break; + case ETH_T_IP: + case ETH_T_IPv6: + // Silently drop + break; + default: + kwarn("Dropping unknown packet: %04x\n", ntohs(eth->ethertype)); + break; + } +} diff --git a/net/net.c b/net/net.c index 47f2407..b52b72e 100644 --- a/net/net.c +++ b/net/net.c @@ -8,14 +8,8 @@ #include "sys/debug.h" #include "sys/spin.h" -// Takes up a single page -#define PACKET_DATA_MAX (4064) -struct packet { - size_t size; - struct packet *prev, *next; - void *source_if; - char data[PACKET_DATA_MAX]; -}; +#include "net/packet.h" +#include "net/eth.h" static struct thread netd_thread = {0}; static spin_t g_rxq_lock = 0; @@ -24,9 +18,9 @@ static struct packet *g_rxq_head, *g_rxq_tail; static struct packet *packet_create(void); static void packet_free(struct packet *p); -static void net_handle_packet(struct packet *p) { - kdebug("Packet:\n"); - debug_dump(DEBUG_DEFAULT, p->data, p->size); +static inline void net_handle_packet(struct packet *p) { + // TODO: check if interface sends packet not in ethernet format + eth_handle_frame(p); } static void net_daemon(void) { @@ -80,6 +74,8 @@ int net_receive(/* TODO: replace with struct netdev * */ void *ctx, const void * } struct packet *p = packet_create(); + // TODO: maybe information like "Physical match", "Multicast" or "Broadcast" + // would be useful to store in packet memcpy(p->data, data, len); p->size = len; p->source_if = ctx; diff --git a/net/util.c b/net/util.c new file mode 100644 index 0000000..c51f701 --- /dev/null +++ b/net/util.c @@ -0,0 +1,11 @@ +#include "net/util.h" + +void strmac(char *dst, const uint8_t *hw) { + static const char hex_digits[] = "0123456789abcdef"; + // I don't have snprintf, lol + for (size_t i = 0; i < 6; ++i) { + dst[i * 3 + 0] = hex_digits[hw[i] >> 4]; + dst[i * 3 + 1] = hex_digits[hw[i] & 0xF]; + dst[i * 3 + 2] = i == 5 ? 0 : ':'; + } +}