Orion
Barry Importing existing Orion kernel d41a53c (3 years, 1 month 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