Orion
Barry Importing existing Orion kernel d41a53c (3 years, 2 months ago)
/*
* This file contains the implementation of ARP for the Network Stack. It
* handles converting IP addresses to MAC addresses, and sits between the
* Network layer and the Ethernet layer.
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "net.h"
#include "../mem/heap.h"
#include "../screen.h"
typedef struct ARPCacheEntry ARPCacheEntry;
/* Structure for an ARP Cache Entry */
struct ARPCacheEntry {
uint8_t mac[6], ip[4];
ARPCacheEntry *next;
};
/* Structure for an ARP Packet */
typedef struct Packet {
uint16_t hardwareType;
uint16_t protocolType;
uint8_t hardwareSize;
uint8_t protocolSize;
uint16_t opcode;
uint8_t srcMac[6], srcIp[4];
uint8_t dstMac[6], dstIp[4];
} __attribute__((packed)) Packet;
ARPCacheEntry *arpCache;
/* Request a MAC address from IP with ARP */
void
arp_request(NetIF *netif, uint8_t dstIp[4], uint8_t *res)
{
uint8_t dstMac[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
Packet packet = {
.hardwareType = htons(netif->type),
.protocolType = htons(0x0800), /* EtherType IPv4 */
.hardwareSize = 6,
.protocolSize = 4,
.opcode = htons(0x0001), /* ARP Request */
};
memcpy(packet.srcMac, netif->mac, 6);
memcpy(packet.srcIp, netif->ip, 4);
memcpy(packet.dstMac, dstMac, 6);
memcpy(packet.dstIp, dstIp, 4);
ethernet_send_frame(netif, dstMac, 0x0806, &packet, sizeof(Packet));
if (!res)
return;
/* Wait for result */
ARPCacheEntry *ce;
search:
for (ce = arpCache; ce; ce = ce->next)
if (!memcmp(ce->ip, dstIp, 4))
break;
if (!ce)
goto search;
memcpy(res, ce->mac, 6);
}
/* Reply to an ARP Request */
void
arp_reply(NetIF *netif, Packet *request)
{
Packet reply = {
.hardwareType = htons(netif->type),
.hardwareSize = request->hardwareSize,
.protocolType = htons(request->protocolType),
.protocolSize = request->protocolSize,
.opcode = htons(0x0002), /* ARP Reply */
};
memcpy(reply.srcMac, netif->mac, 6);
memcpy(reply.srcIp, netif->ip, 4);
memcpy(reply.dstMac, request->srcMac, 6);
memcpy(reply.dstIp, request->srcIp, 4);
ethernet_send_frame(netif, request->srcMac, 0x0806, &reply,
sizeof(Packet));
}
/* Handle an incoming ARP packet */
void
arp_receive_packet(NetIF *netif, void *data, size_t len)
{
Packet packet;
memcpy(&packet, data, sizeof(Packet));
packet.hardwareType = ntohs(packet.hardwareType);
packet.protocolType = ntohs(packet.protocolType);
packet.opcode = ntohs(packet.opcode);
switch (packet.opcode) {
case 0x0001: /* ARP Request */
if (!memcmp(packet.dstIp, netif->ip, 4))
arp_reply(netif, &packet);
/* FALLTHROUGH */
case 0x0002: /* ARP Reply */
ARPCacheEntry *ce;
for (ce = arpCache; ce; ce = ce->next)
if (!memcmp(ce->ip, packet.srcIp, 4))
break;
if (ce) {
memcpy(ce->mac, packet.srcMac, 6);
break;
}
ce = kmalloc(sizeof(ARPCacheEntry));
memcpy(ce->mac, packet.srcMac, 6);
memcpy(ce->ip, packet.srcIp, 4);
ce->next = arpCache;
arpCache = ce;
break;
}
}