From 425dbdc114108f4b45d60cee4e6547187ef0f11e Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 20 Mar 2020 12:52:30 +0200 Subject: [PATCH] Add ARP tables and reply function --- drivers/net/rtl8139.c | 4 ++- include/net/arp.h | 3 ++ include/net/eth.h | 3 ++ include/net/if.h | 4 ++- include/net/util.h | 8 +++++ net/arp.c | 74 +++++++++++++++++++++++++++++++++++++++++++ net/eth.c | 13 ++++++++ net/if.c | 1 + 8 files changed, 108 insertions(+), 2 deletions(-) diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 103a651..53f5195 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -56,8 +56,10 @@ static void rtl8139_reset(struct rtl8139 *rtl) { while (inb(rtl->iobase + REG_CR) & CR_RST); } -static int rtl8139_netdev_send(struct netdev *net, const void *date, size_t len) { +static int rtl8139_netdev_send(struct netdev *net, const void *data, size_t len) { // TODO + kdebug("%s: send stub:\n", net->name); + debug_dump(DEBUG_DEFAULT, data, len); return -1; } diff --git a/include/net/arp.h b/include/net/arp.h index 41b2988..d950d03 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -4,6 +4,9 @@ #define ARP_H_ETH 1 #define ARP_P_IP 0x0800 +#define ARP_OP_REQUEST 1 +#define ARP_OP_REPLY 2 + struct arp_frame { uint16_t htype; uint16_t ptype; diff --git a/include/net/eth.h b/include/net/eth.h index 69cdeb5..dbbcf24 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -11,5 +11,8 @@ struct eth_frame { uint16_t ethertype; } __attribute__((packed)); +struct netdev; struct packet; void eth_handle_frame(struct packet *p); + +int eth_send_wrapped(struct netdev *src, const uint8_t *dst, uint16_t et, void *data, size_t len); diff --git a/include/net/if.h b/include/net/if.h index 15f0894..07b5f5a 100644 --- a/include/net/if.h +++ b/include/net/if.h @@ -6,6 +6,7 @@ #define IF_T_ETH 1 struct netdev; +struct arp_ent; typedef int (*netdev_send_func_t) (struct netdev *, const void *, size_t); @@ -17,7 +18,8 @@ struct netdev { uint32_t flags; int type; - // TODO: arp table here? + // ARP entry list + struct arp_ent *arp_ent_head; netdev_send_func_t send; diff --git a/include/net/util.h b/include/net/util.h index df0d0c3..e092ec3 100644 --- a/include/net/util.h +++ b/include/net/util.h @@ -9,6 +9,14 @@ void strmac(char *dst, const uint8_t *hw); +static inline uint32_t ntohl(uint32_t w) { + uint8_t *s = (uint8_t *)&w; + return (uint32_t) (s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); +} + static inline uint16_t ntohs(uint16_t w) { return (w >> 8) | (w << 8); } +static inline uint16_t htons(uint16_t w) { + return (w >> 8) | (w << 8); +} diff --git a/net/arp.c b/net/arp.c index b5f4410..66b1750 100644 --- a/net/arp.c +++ b/net/arp.c @@ -1,9 +1,45 @@ #include "net/packet.h" +#include "sys/assert.h" +#include "sys/string.h" #include "sys/debug.h" +#include "sys/heap.h" #include "net/util.h" #include "net/arp.h" +#include "net/eth.h" #include "net/if.h" +struct arp_ent { + uint32_t inaddr; + uint8_t hwaddr[6]; + int resolved; + struct arp_ent *prev, *next; +}; + +static struct arp_ent *arp_find_inaddr(struct netdev *dev, uint32_t inaddr) { + for (struct arp_ent *ent = dev->arp_ent_head; ent; ent = ent->next) { + if (ent->inaddr == inaddr) { + return ent; + } + } + return NULL; +} + +static void arp_add_entry(struct netdev *dev, uint32_t inaddr, const uint8_t *hw) { + struct arp_ent *ent = kmalloc(sizeof(struct arp_ent)); + _assert(ent); + + ent->inaddr = inaddr; + memcpy(ent->hwaddr, hw, 6); + ent->resolved = 1; + + ent->next = dev->arp_ent_head; + ent->prev = NULL; + dev->arp_ent_head = ent; + + char mac[24]; + strmac(mac, hw); + kdebug("%s: add arp entry: " FMT_INADDR " -> %s\n", dev->name, VA_INADDR(inaddr), mac); +} /* ?Do I have the hardware type in ar$hrd? @@ -31,6 +67,25 @@ Yes: (almost definitely) the same hardware on which the request was received. */ +static void arp_send_reply(struct netdev *src, struct arp_frame *req) { + char reply[sizeof(struct eth_frame) + sizeof(struct arp_frame)]; + struct arp_frame *arp = (struct arp_frame *) &reply[sizeof(struct eth_frame)]; + + memcpy(arp->tha, req->sha, 6); + memcpy(arp->sha, src->hwaddr, 6); + + arp->spa = req->tpa; + arp->tpa = req->spa; + + arp->hlen = req->hlen; + arp->plen = req->plen; + arp->htype = req->htype; + arp->ptype = req->ptype; + + arp->oper = htons(ARP_OP_REPLY); + + eth_send_wrapped(src, arp->tha, ETH_T_ARP, reply, sizeof(reply)); +} void arp_handle_frame(struct packet *p, void *data, size_t len) { if (len < sizeof(struct arp_frame)) { @@ -39,6 +94,9 @@ void arp_handle_frame(struct packet *p, void *data, size_t len) { } struct arp_frame *arp = data; + struct arp_ent *ent; + struct netdev *dev = p->dev; + int merge = 0; if (ntohs(arp->htype) != ARP_H_ETH) { kwarn("%s: dropping non-ethernet packet\n", p->dev->name); @@ -48,4 +106,20 @@ void arp_handle_frame(struct packet *p, void *data, size_t len) { kwarn("%s: dropping non-IP packet\n", p->dev->name); return; } + + if ((ent = arp_find_inaddr(dev, ntohl(arp->spa))) != NULL) { + merge = 1; + kinfo("Found source addr\n"); + } + + if ((dev->flags & IF_F_HASIP) && + dev->inaddr == ntohl(arp->tpa)) { + if (!merge) { + arp_add_entry(dev, ntohl(arp->spa), arp->sha); + } + + if (htons(arp->oper) == ARP_OP_REQUEST) { + arp_send_reply(dev, arp); + } + } } diff --git a/net/eth.c b/net/eth.c index 53fb255..6e2e2b0 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,4 +1,6 @@ #include "net/packet.h" +#include "sys/assert.h" +#include "sys/string.h" #include "sys/debug.h" #include "net/util.h" #include "net/eth.h" @@ -6,6 +8,17 @@ #include "net/arp.h" +int eth_send_wrapped(struct netdev *src, const uint8_t *hwaddr, uint16_t et, void *data, size_t len) { + struct eth_frame *eth = data; + + memcpy(eth->dst_hwaddr, hwaddr, 6); + memcpy(eth->src_hwaddr, src->hwaddr, 6); + eth->ethertype = htons(et); + + _assert(src->send); + return src->send(src, data, len); +} + void eth_handle_frame(struct packet *p) { if (p->size < sizeof(struct eth_frame)) { kwarn("%s: dropping undersized packet: %u\n", p->dev->name, p->size); diff --git a/net/if.c b/net/if.c index a8e9b8b..12b2b8e 100644 --- a/net/if.c +++ b/net/if.c @@ -17,6 +17,7 @@ struct netdev *netdev_create(int type) { net->inaddr = 0; net->flags = 0; net->type = type; + net->arp_ent_head = NULL; switch (type) { case IF_T_ETH: