From 150303b2b88fff33dba96d6fabaf517bec3fb9ec Mon Sep 17 00:00:00 2001 From: dzwdz Date: Mon, 22 Aug 2022 17:13:43 +0200 Subject: user/netstack: ARP cache --- src/user/app/netstack/arp.c | 56 ++++++++++++++++++++++++++++++++++++++++++- src/user/app/netstack/fs.c | 13 +++++++++- src/user/app/netstack/proto.h | 1 + 3 files changed, 68 insertions(+), 2 deletions(-) (limited to 'src/user') diff --git a/src/user/app/netstack/arp.c b/src/user/app/netstack/arp.c index 9eab8e3..b43b7e8 100644 --- a/src/user/app/netstack/arp.c +++ b/src/user/app/netstack/arp.c @@ -1,5 +1,7 @@ #include "proto.h" #include "util.h" +#include +#include #include enum { @@ -13,8 +15,16 @@ enum { OpReply = 2, }; +struct arpc { + struct arpc *next; + uint32_t ip; + mac_t mac; +}; +static struct arpc *arpcache; +static void arpcache_put(uint32_t ip, mac_t mac); + void arp_parse(const uint8_t *buf, size_t len) { - // TODO no bound checks + if (len < Operation + 2) return; uint16_t htype = nget16(buf + HdrType); uint16_t ptype = nget16(buf + ProtoType); uint16_t op = nget16(buf + Operation); @@ -26,6 +36,8 @@ void arp_parse(const uint8_t *buf, size_t len) { DstMAC = 18, DstIP = 24, }; + if (len < DstIP + 4) return; + arpcache_put(nget32(buf + SrcIP), *(mac_t*)buf + SrcMAC); if (op == OpReq) { uint32_t daddr = nget32(buf + DstIP); @@ -46,3 +58,45 @@ void arp_parse(const uint8_t *buf, size_t len) { } } } + +static void arpcache_put(uint32_t ip, mac_t mac) { + for (struct arpc *iter = arpcache; iter; iter = iter->next) { + if (memcmp(iter->mac, mac, 6) == 0) { + if (iter->ip == ip) return; /* cache entry correct */ + else break; /* cache entry needs updating */ + } + } + struct arpc *e = malloc(sizeof *e); + e->next = arpcache; + e->ip = ip; + memcpy(e->mac, mac, 6); + arpcache = e; +} + +void arp_fsread(handle_t h, long offset) { + const char *fmt = "%08x\t%02x:%02x:%02x:%02x:%02x:%02x\n"; + long linelen = snprintf(NULL, 0, fmt, 0, 1, 2, 3, 4, 5, 6) + 1; + char buf[28]; + assert(linelen <= (long)sizeof(buf)); + if (offset < 0) goto err; + + struct arpc *cur = arpcache; + if (!cur) goto err; + for (; linelen <= offset; offset -= linelen) { + cur = cur->next; + if (!cur) goto err; + } + assert(0 <= offset && offset < linelen); + + snprintf(buf, sizeof buf, fmt, cur->ip, + cur->mac[0], + cur->mac[1], + cur->mac[2], + cur->mac[3], + cur->mac[4], + cur->mac[5]); + _syscall_fs_respond(h, buf + offset, linelen - offset, 0); + return; +err: + _syscall_fs_respond(h, NULL, -1, 0); +} diff --git a/src/user/app/netstack/fs.c b/src/user/app/netstack/fs.c index 52d6038..dc6db04 100644 --- a/src/user/app/netstack/fs.c +++ b/src/user/app/netstack/fs.c @@ -2,6 +2,8 @@ * path format: * /net/raw * raw ethernet frames (read-write) + * /net/arp + * ARP cache (currently read-only) * /net/0.0.0.0/connect/1.2.3.4/udp/53 * connect from 0.0.0.0 (any ip) to 1.2.3.4 on udp port 53 * /net/0.0.0.0/listen/udp/53 @@ -9,6 +11,7 @@ * open() returns once a connection to ip 0.0.0.0 on udp port 53 is received */ #include "proto.h" +#include "util.h" #include #include #include @@ -17,6 +20,7 @@ enum handle_type { H_ETHER, H_UDP, + H_ARP, }; struct strqueue { @@ -79,7 +83,7 @@ static void udp_recv_enqueue(struct handle *h, handle_t reqh) { } static void fs_open(handle_t reqh, char *path) { -#define respond(buf, val) do{ _syscall_fs_respond(reqh, NULL, -1, 0); return; }while(0) +#define respond(buf, val) do{ _syscall_fs_respond(reqh, buf, val, 0); return; }while(0) struct handle *h; if (*path != '/') respond(NULL, -1); path++; @@ -88,6 +92,10 @@ static void fs_open(handle_t reqh, char *path) { h = malloc(sizeof *h); h->type = H_ETHER; respond(h, 0); + } else if (strcmp(path, "arp") == 0) { + h = malloc(sizeof *h); + h->type = H_ARP; + respond(h, 0); } char *save; @@ -147,6 +155,9 @@ void fs_thread(void *arg) { (void)arg; case H_UDP: udp_recv_enqueue(h, reqh); break; + case H_ARP: + arp_fsread(reqh, res.offset); + break; default: _syscall_fs_respond(reqh, NULL, -1, 0); } diff --git a/src/user/app/netstack/proto.h b/src/user/app/netstack/proto.h index 106f286..864f1c1 100644 --- a/src/user/app/netstack/proto.h +++ b/src/user/app/netstack/proto.h @@ -46,6 +46,7 @@ struct ethq { extern struct ethq *ether_queue; void arp_parse(const uint8_t *buf, size_t len); +void arp_fsread(handle_t h, long offset); void icmp_parse(const uint8_t *buf, size_t len, struct ipv4 ip); void icmp_send(const void *payload, size_t len, struct icmp i); -- cgit v1.2.3