Orion
Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)diff --git a/net/arp.c b/net/arp.c new file mode 100644 index 0000000..8906abb --- /dev/null +++ b/net/arp.c @@ -0,0 +1,118 @@ +/* + * 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; + } +}