Orion
Barry Importing existing Orion kernel d41a53c (3 years, 3 months ago)
/*
* 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);
}