BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / e59e4fe0bbf5a3f56db0700ee49a81131b590f9c / net / ipv4.c

// Related

Orion

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