BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / 1628fcfdfdf2978ed9ccac96ee7d13bb3dc43a01 / net / arp.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 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;
	}
}