arp: queue packets for sending while pending resolution
This commit is contained in:
@@ -23,4 +23,5 @@ struct arp_frame {
|
||||
struct packet;
|
||||
void arp_handle_frame(struct packet *packet, void *data, size_t len);
|
||||
|
||||
int arp_send(struct netdev *dev, uint32_t inaddr, uint16_t etype, void *data, size_t len);
|
||||
const uint8_t *arp_resolve(struct netdev *dev, uint32_t inaddr);
|
||||
|
||||
@@ -11,6 +11,8 @@ struct eth_frame {
|
||||
uint16_t ethertype;
|
||||
} __attribute__((packed));
|
||||
|
||||
static const uint8_t ETH_A_BROADCAST[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
struct netdev;
|
||||
struct packet;
|
||||
void eth_handle_frame(struct packet *p);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "arch/amd64/mm/phys.h"
|
||||
#include "net/packet.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/string.h"
|
||||
@@ -7,14 +8,27 @@
|
||||
#include "net/arp.h"
|
||||
#include "net/eth.h"
|
||||
#include "net/if.h"
|
||||
#include "sys/mm.h"
|
||||
|
||||
struct arp_hold;
|
||||
|
||||
struct arp_ent {
|
||||
uint32_t inaddr;
|
||||
uint8_t hwaddr[6];
|
||||
int resolved;
|
||||
struct arp_hold *hold;
|
||||
struct arp_ent *prev, *next;
|
||||
};
|
||||
|
||||
struct arp_hold {
|
||||
uint16_t ethertype;
|
||||
size_t len;
|
||||
struct arp_hold *next;
|
||||
char data[4096 - sizeof(uint16_t) - sizeof(struct arp_hold *) - sizeof(size_t)];
|
||||
} __attribute__((packed));
|
||||
|
||||
static void arp_send_request(struct netdev *dev, uint32_t inaddr);
|
||||
|
||||
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) {
|
||||
@@ -24,29 +38,106 @@ static struct arp_ent *arp_find_inaddr(struct netdev *dev, uint32_t inaddr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void arp_add_entry(struct netdev *dev, uint32_t inaddr, const uint8_t *hw) {
|
||||
static struct arp_ent *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;
|
||||
if (hw) {
|
||||
char mac[24];
|
||||
strmac(mac, hw);
|
||||
kdebug("%s: add arp entry: " FMT_INADDR " -> %s\n", dev->name, VA_INADDR(inaddr), mac);
|
||||
|
||||
memcpy(ent->hwaddr, hw, 6);
|
||||
ent->resolved = 1;
|
||||
} else {
|
||||
ent->resolved = 0;
|
||||
kdebug("%s: pending resolution: " FMT_INADDR "\n", dev->name, VA_INADDR(inaddr));
|
||||
}
|
||||
|
||||
ent->hold = NULL;
|
||||
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);
|
||||
return ent;
|
||||
}
|
||||
|
||||
const uint8_t *arp_resolve(struct netdev *dev, uint32_t inaddr) {
|
||||
struct arp_ent *ent = arp_find_inaddr(dev, inaddr);
|
||||
if (!ent || !ent->resolved) {
|
||||
return NULL;
|
||||
static struct arp_ent *arp_find_or_create(struct netdev *dev, uint32_t inaddr) {
|
||||
struct arp_ent *ent;
|
||||
if ((ent = arp_find_inaddr(dev, inaddr)) != NULL) {
|
||||
return ent;
|
||||
}
|
||||
return ent->hwaddr;
|
||||
|
||||
// Send a request for inaddr
|
||||
arp_send_request(dev, inaddr);
|
||||
|
||||
return arp_add_entry(dev, inaddr, NULL);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
int arp_send(struct netdev *src, uint32_t inaddr, uint16_t ethertype, void *data, size_t len) {
|
||||
struct arp_ent *ent = arp_find_or_create(src, inaddr);
|
||||
_assert(ent);
|
||||
|
||||
if (ent->resolved) {
|
||||
return eth_send_wrapped(src, ent->hwaddr, ethertype, data, len);
|
||||
} else {
|
||||
// TODO: better way?
|
||||
uintptr_t page = amd64_phys_alloc_page();
|
||||
_assert(page != MM_NADDR);
|
||||
struct arp_hold *hold = (struct arp_hold *) MM_VIRTUALIZE(page);
|
||||
|
||||
hold->ethertype = ethertype;
|
||||
hold->len = len;
|
||||
memcpy(hold->data, data, len);
|
||||
|
||||
hold->next = ent->hold;
|
||||
ent->hold = hold;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void arp_send_request(struct netdev *dev, uint32_t inaddr) {
|
||||
_assert(dev->flags & IF_F_HASIP);
|
||||
char packet[sizeof(struct eth_frame) + sizeof(struct arp_frame)];
|
||||
struct arp_frame *arp = (struct arp_frame *) &packet[sizeof(struct eth_frame)];
|
||||
|
||||
memcpy(arp->sha, dev->hwaddr, 6);
|
||||
memset(arp->tha, 0, 6);
|
||||
|
||||
arp->spa = htonl(dev->inaddr);
|
||||
arp->tpa = htonl(inaddr);
|
||||
|
||||
arp->hlen = 6;
|
||||
arp->plen = 4;
|
||||
arp->htype = htons(ARP_H_ETH);
|
||||
arp->ptype = htons(ARP_P_IP);
|
||||
|
||||
arp->oper = htons(ARP_OP_REQUEST);
|
||||
|
||||
kinfo("Send request for " FMT_INADDR "\n", VA_INADDR(inaddr));
|
||||
eth_send_wrapped(dev, ETH_A_BROADCAST, ETH_T_ARP, packet, sizeof(packet));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -75,26 +166,6 @@ 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)) {
|
||||
kwarn("%s: dropping undersized frame: %u\n", p->dev->name, len);
|
||||
@@ -117,7 +188,20 @@ void arp_handle_frame(struct packet *p, void *data, size_t len) {
|
||||
|
||||
if ((ent = arp_find_inaddr(dev, ntohl(arp->spa))) != NULL) {
|
||||
merge = 1;
|
||||
kinfo("Found source addr\n");
|
||||
|
||||
memcpy(ent->hwaddr, arp->sha, 6);
|
||||
|
||||
if (!ent->resolved) {
|
||||
ent->resolved = 1;
|
||||
struct arp_hold *hold;
|
||||
while ((hold = ent->hold)) {
|
||||
ent->hold = hold->next;
|
||||
|
||||
eth_send_wrapped(dev, ent->hwaddr, hold->ethertype, hold->data, hold->len);
|
||||
|
||||
amd64_phys_free(MM_PHYS(hold));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((dev->flags & IF_F_HASIP) &&
|
||||
|
||||
+1
-5
@@ -29,10 +29,6 @@ int inet_send_wrapped(struct netdev *src, uint32_t inaddr, uint8_t proto, void *
|
||||
}
|
||||
|
||||
struct inet_frame *ip = data + sizeof(struct eth_frame);
|
||||
const uint8_t *hwaddr = arp_resolve(src, inaddr);
|
||||
if (!hwaddr) {
|
||||
panic("TODO: handle this\n");
|
||||
}
|
||||
|
||||
ip->dst_inaddr = htonl(inaddr);
|
||||
ip->src_inaddr = htonl(src->inaddr);
|
||||
@@ -47,7 +43,7 @@ int inet_send_wrapped(struct netdev *src, uint32_t inaddr, uint8_t proto, void *
|
||||
|
||||
ip->checksum = inet_checksum(ip, sizeof(struct inet_frame));
|
||||
|
||||
return eth_send_wrapped(src, hwaddr, ETH_T_IP, data, len);
|
||||
return arp_send(src, inaddr, ETH_T_IP, data, len);
|
||||
}
|
||||
|
||||
void inet_handle_frame(struct packet *p, struct eth_frame *eth, void *data, size_t len) {
|
||||
|
||||
Reference in New Issue
Block a user