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