/* * 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 #include #include #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); }