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