BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / net

// Related

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;
+	}
+}
diff --git a/net/ethernet.c b/net/ethernet.c
new file mode 100644
index 0000000..98d6692
--- /dev/null
+++ b/net/ethernet.c
@@ -0,0 +1,63 @@
+/*
+ * This file implements the Ethernet layer of the Network Stack.  It wraps any
+ * packet sent to it with the Ethernet Header.  Equally, it unwraps any packets
+ * before passing them to the next layer, determined by the EtherType in the
+ * header.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include "net.h"
+#include "../mem/heap.h"
+#include "../screen.h"
+
+/* Structure for an Ethernet Header */
+typedef struct Header {
+	uint8_t dst[6];
+	uint8_t src[6];
+	uint16_t ethertype;
+} __attribute__((packed)) Header;
+
+/* Receive a frame of data */
+void
+ethernet_receive_frame(NetIF *netif, void *data, size_t len)
+{
+	Header header;
+	memcpy(&header, data, sizeof(Header));
+	header.ethertype = ntohs(header.ethertype);
+
+	/* Handle appropriately */
+	switch (header.ethertype) {
+	case 0x0800: /* IPv4 */
+		ipv4_receive_packet(netif, data + sizeof(Header),
+		                    len - sizeof(Header));
+		break;
+	case 0x0806: /* ARP */
+		arp_receive_packet(netif, data + sizeof(Header),
+		                   len - sizeof(Header));
+		break;
+//	default:
+//		kprintf("Unhandled type (%04x)", header.ethertype);
+	}
+}
+
+/* Send a frame of data */
+void
+ethernet_send_frame(NetIF *netif, uint8_t dst[6], uint16_t type,
+                    void *data, size_t len)
+{
+	Header header;
+	header.ethertype = htons(type);
+	memcpy(header.src, netif->mac, 6);
+	memcpy(header.dst, dst, 6);
+	size_t frameLen = sizeof(Header) + len;
+	if (frameLen < 64)
+		frameLen = 64;
+
+	char *frame = kmalloc(frameLen);
+	memcpy(frame, &header, sizeof(Header));
+	memcpy(frame + sizeof(Header), data, len);
+	netif->transmit(frame, frameLen);
+	kfree(frame);
+}
diff --git a/net/ipv4.c b/net/ipv4.c
new file mode 100644
index 0000000..ce27ba7
--- /dev/null
+++ b/net/ipv4.c
@@ -0,0 +1,97 @@
+/*
+ * This file contains the IPv4 implementation in the Network Stack.  It sits
+ * above the Ethernet layer, but makes heavy use of the Address Resolution
+ * Protocol.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include "net.h"
+#include "../mem/heap.h"
+#include "../screen.h"
+
+/* Structure for an IPv4 Packet Header */
+typedef struct Header {
+	/* ihl and version are swapped to work with network byte order */
+	uint8_t ihl : 4;
+	uint8_t version : 4;
+	uint8_t service;
+	uint16_t len;
+	uint16_t id;
+	uint16_t flags;
+	uint8_t ttl;
+	uint8_t proto;
+	uint16_t checksum;
+	uint32_t src, dst;
+} __attribute__((packed)) Header;
+
+uint16_t ipid = 1;
+
+/* Calculate an IPv4 checksum */
+static uint16_t
+ipv4_checksum(void *addr, size_t len)
+{
+	register uint32_t sum = 0;
+	while (len > 1) {
+		sum += *(uint16_t *) addr++;
+		len -= 2;
+	}
+	if (len > 0)
+		sum += *(uint8_t *) addr;
+
+	while (sum >> 16)
+		sum = (sum & 0xFFFF) + (sum >> 16);
+
+	return ~sum;
+}
+
+/* Receive an IPv4 Packet */
+void
+ipv4_receive_packet(NetIF *netif, void *data, size_t len)
+{
+	Header header;
+	memcpy(&header, data, sizeof(Header));
+
+	uint8_t src[4];
+	memcpy(src, &header.src, 4);
+	kprintf("Received IPv4 Packet from %d.%d.%d.%d",
+	        src[0], src[1], src[2], src[3]);
+
+	/* Handle packet */
+	switch (header.proto) {
+//	case 0x01: /* ICMP */
+//		break;
+//	case 0x02: /* IGMP */
+//	case 0x06: /* TCP */
+//	case 0x11: /* UDP */
+	default:
+		kprintf("Unhandled IP packet (proto %d)", header.proto);
+	}
+}
+
+/* Transmit an IPv4 Packet */
+void
+ipv4_send_packet(NetIF *netif, uint8_t dst[4], uint8_t proto, uint16_t flags,
+                 void *data, size_t len)
+{
+	Header header;
+	header.ihl = 5;
+	header.version = 4;
+	header.service = 0;
+	header.len = htons(len + sizeof(Header));
+	header.id = htons(ipid++);
+	header.flags = htons(flags);
+	header.ttl = 255;
+	header.proto = proto;
+	memcpy(&header.src, netif->ip, 4);
+	memcpy(&header.dst, dst, 4);
+	header.checksum = ipv4_checksum(&header, sizeof(Header));
+
+	char *packet = kmalloc(len + sizeof(Header));
+	memcpy(packet, &header, sizeof(Header));
+	memcpy(packet + sizeof(Header), data, len);
+	ethernet_send_frame(netif, netif->gatewayMac,
+	                    0x800, packet, len + sizeof(Header));
+	kfree(packet);
+}
diff --git a/net/net.c b/net/net.c
new file mode 100644
index 0000000..5c963dc
--- /dev/null
+++ b/net/net.c
@@ -0,0 +1,90 @@
+/*
+ * This file represents the core of the Kernel Networking System.  It contains
+ * the outwards facing interface, as well as the internal interface for the
+ * lower levels to make use of.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "net.h"
+#include "../mem/heap.h"
+
+NetIF *netifs;
+
+/* Switch the endian of integers */
+static uint16_t
+switch_endian16(uint16_t nb)
+{
+	return (nb>>8) | (nb<<8);
+}
+static uint32_t
+switch_endian32(uint32_t nb)
+{
+	return ((nb>>24)&0xff)      |
+	       ((nb<<8)&0xff0000)   |
+	       ((nb>>8)&0xff00)     |
+	       ((nb<<24)&0xff000000);
+}
+
+/* Host to Network byte order */
+uint16_t
+htons(uint16_t hostshort)
+{
+	return switch_endian16(hostshort);
+}
+uint32_t
+htonl(uint32_t hostlong)
+{
+	return switch_endian32(hostlong);
+}
+
+/* Network to Host byte order */
+uint16_t
+ntohs(uint16_t netshort)
+{
+	return switch_endian16(netshort);
+}
+uint32_t
+ntohl(uint32_t netlong)
+{
+	return switch_endian32(netlong);
+}
+
+/* Intialise Networking */
+void
+init_net(void)
+{
+	char ip[] = {10,0,2,2};
+	memcpy(netifs->gatewayIp, ip, 4);
+	arp_request(netifs, ip, netifs->gatewayMac);
+
+	/* Send ICMP ECHO */
+	char icmp[12] = {
+		8, 0,
+		0xF7, 0xFE,
+		0x00, 0x01,
+		0, 0
+	};
+	char pip[] = {1,1,1,1};
+	ipv4_send_packet(netifs, pip, 1, 0, icmp, 12);
+}
+
+/* Register a Network Driver */
+NetIF *
+net_create_interface(uint16_t type, void (*transmit)(void *, size_t),
+                     void (*get_mac)(char *buf))
+{
+	NetIF *netif = kmalloc(sizeof(NetIF));
+	netif->type = type;
+	netif->transmit = transmit;
+	netif->get_mac = get_mac;
+	netif->get_mac(netif->mac);
+	netif->ip[0] = 10;
+	netif->ip[1] =  0;
+	netif->ip[2] =  2;
+	netif->ip[3] = 15;
+
+	/* Link into list */
+	netif->next = netifs;
+	netifs = netif;
+}
diff --git a/net/net.h b/net/net.h
new file mode 100644
index 0000000..3fd113b
--- /dev/null
+++ b/net/net.h
@@ -0,0 +1,40 @@
+#ifndef KERNEL_NET_H
+#define KERNEL_NET_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct NetIF NetIF;
+
+/* Structure for a Network Interface */
+struct NetIF {
+	uint16_t type;
+	void (*transmit)(void *, size_t);
+	void (*get_mac)(char *);
+
+	uint8_t ip[4], mac[6];
+	uint8_t gatewayIp[4], gatewayMac[6];
+	uint8_t dnsIp[4], dnsMac[6];
+	NetIF *next;
+};
+
+uint16_t htons(uint16_t hostshort);
+uint32_t htonl(uint32_t hostlong);
+uint16_t ntohs(uint16_t hostshort);
+uint32_t ntohl(uint32_t hostlong);
+void init_net(void);
+NetIF *net_create_interface(uint16_t type, void (*transmit)(void *, size_t),
+                            void (*get_mac)(char *buf));
+
+void ethernet_receive_frame(NetIF *netif, void *data, size_t len);
+void ethernet_send_frame(NetIF *netif, uint8_t dst[6], uint16_t type,
+                         void *data, size_t len);
+
+void arp_receive_packet(NetIF *netif, void *data, size_t len);
+void arp_request(NetIF *netif, uint8_t dstIp[4], uint8_t *res);
+
+void ipv4_receive_packet(NetIF *netif, void *data, size_t len);
+void ipv4_send_packet(NetIF *netif, uint8_t dst[4], uint8_t proto,
+                      uint16_t flags, void *data, size_t len);
+
+#endif