diff options
author | Anton Kling <anton@kling.gg> | 2023-10-26 22:35:58 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-10-30 21:49:48 +0100 |
commit | f8e15da04472f5ed6a26e588de4a23cb3e1ba20b (patch) | |
tree | 9e646d6ba72dcc8f2eb95d04bac2a8b4a91ad946 /network | |
parent | cf60045bdb969f6fe44fe7dc9bf7cec593a0b05c (diff) |
Kernel: Fixup rtl8139, add basic ARP and ethernet support
Currently the ARP appears to be able to respond to requests.
Diffstat (limited to 'network')
-rw-r--r-- | network/arp.c | 83 | ||||
-rw-r--r-- | network/arp.h | 3 | ||||
-rw-r--r-- | network/bytes.c | 10 | ||||
-rw-r--r-- | network/bytes.h | 5 | ||||
-rw-r--r-- | network/ethernet.c | 101 | ||||
-rw-r--r-- | network/ethernet.h | 5 |
6 files changed, 207 insertions, 0 deletions
diff --git a/network/arp.c b/network/arp.c new file mode 100644 index 0000000..eb8aca3 --- /dev/null +++ b/network/arp.c @@ -0,0 +1,83 @@ +#include <assert.h> +#include <drivers/rtl8139.h> +#include <network/arp.h> +#include <network/bytes.h> +#include <network/ethernet.h> +#include <stdio.h> +#include <string.h> + +struct ARP_DATA { + uint16_t htype; // Hardware type + uint16_t ptype; // Protocol type + uint8_t hlen; // Hardware address length (Ethernet = 6) + uint8_t plen; // Protocol address length (IPv4 = 4) + uint16_t opcode; // ARP Operation Code + uint8_t srchw[6]; // Source hardware address - hlen bytes (see above) + uint8_t srcpr[4]; // Source protocol address - plen bytes (see above). + // If IPv4 can just be a "u32" type. + uint8_t dsthw[6]; // Destination hardware address - hlen bytes (see above) + uint8_t dstpr[4]; // Destination protocol address - plen bytes (see + // above). If IPv4 can just be a "u32" type. +}; + +// FIXME: This is hardcoded, don't do this. +uint8_t ip_address[4] = {10, 0, 2, 15}; + +void print_mac(const char *str, uint8_t *mac) { + kprintf("%s: ", str); + for (int i = 0; i < 6; i++) { + kprintf("%x", mac[i]); + if (5 != i) + kprintf(":"); + } + kprintf("\n"); +} + +void print_ip(const char *str, uint8_t *ip) { + kprintf("%s: ", str); + for (int i = 0; i < 4; i++) { + kprintf("%d", ip[i]); + if (3 != i) + kprintf("."); + } + kprintf("\n"); +} + +void handle_arp(uint8_t *payload) { + struct ARP_DATA *data = (struct ARP_DATA *)payload; + + // Assert that communication is over ethernet + assert(1 == ntohs(data->htype)); + // Assert it is a request + assert(0x0001 == ntohs(data->opcode)); + // Assert that request uses IP + assert(0x0800 == ntohs(data->ptype)); + + assert(6 == data->hlen); + assert(4 == data->plen); + print_mac("srchw: ", data->srchw); + print_ip("srcpr: ", data->srcpr); + + print_mac("dsthw: ", data->dsthw); + print_ip("dstpr: ", data->dstpr); + + uint8_t mac[6]; + get_mac_address(mac); + print_mac("THIS DEVICE MAC: ", mac); + assert(0 == memcmp(data->dstpr, ip_address, sizeof(uint8_t[4]))); + + // Now we have to construct a ARP response + struct ARP_DATA response; + response.htype = htons(1); + response.ptype = htons(0x0800); + response.opcode = htons(0x00002); + response.hlen = 6; + response.plen = 4; + get_mac_address(response.srchw); + memcpy(response.srcpr, ip_address, sizeof(uint8_t[4])); + + memcpy(response.dsthw, data->srchw, sizeof(uint8_t[6])); + memcpy(response.dstpr, data->srcpr, sizeof(uint8_t[4])); + + send_ethernet_packet(data->srchw, 0x0806, (uint8_t*)&response, sizeof(response)); +} diff --git a/network/arp.h b/network/arp.h new file mode 100644 index 0000000..1e8df1b --- /dev/null +++ b/network/arp.h @@ -0,0 +1,3 @@ +#include <stdint.h> + +void handle_arp(uint8_t *payload); diff --git a/network/bytes.c b/network/bytes.c new file mode 100644 index 0000000..94afa73 --- /dev/null +++ b/network/bytes.c @@ -0,0 +1,10 @@ +#include <network/bytes.h> + +uint16_t ntohs(uint16_t net) { return (net >> 8) | (net << 8); } + +uint16_t htons(uint16_t net) { return (net >> 8) | (net << 8); } + +uint32_t htonl(uint32_t net) { + return (((net & 0x000000FF) << 24) | ((net & 0x0000FF00) << 8) | + ((net & 0x00FF0000) >> 8) | ((net & 0xFF000000) >> 24)); +} diff --git a/network/bytes.h b/network/bytes.h new file mode 100644 index 0000000..c291589 --- /dev/null +++ b/network/bytes.h @@ -0,0 +1,5 @@ +#include <stdint.h> + +uint16_t ntohs(uint16_t net); +uint16_t htons(uint16_t net); +uint32_t htonl(uint32_t net); diff --git a/network/ethernet.c b/network/ethernet.c new file mode 100644 index 0000000..ae8e814 --- /dev/null +++ b/network/ethernet.c @@ -0,0 +1,101 @@ +#include <assert.h> +#include <drivers/rtl8139.h> +#include <kmalloc.h> +#include <network/arp.h> +#include <network/bytes.h> +#include <network/ethernet.h> +#include <stdio.h> + +struct ETHERNET_HEADER { + uint8_t mac_dst[6]; + uint8_t mac_src[6]; + uint16_t type; +}; + +uint32_t crc32(const char *buf, size_t len) { + static uint32_t table[256]; + static int have_table = 0; + uint32_t rem; + uint8_t octet; + int i, j; + const char *p, *q; + + if (have_table == 0) { + for (i = 0; i < 256; i++) { + rem = i; + for (j = 0; j < 8; j++) { + if (rem & 1) { + rem >>= 1; + rem ^= 0xedb88320; + } else + rem >>= 1; + } + table[i] = rem; + } + have_table = 1; + } + + uint32_t crc = 0xFFFFFFFF; + q = buf + len; + for (p = buf; p < q; p++) { + octet = *p; + crc = (crc >> 8) ^ table[(crc & 0xff) ^ octet]; + } + return ~crc; +} + +void handle_ethernet(uint8_t *packet, uint64_t packet_length) { + struct ETHERNET_HEADER *eth_header = (struct ETHERNET_HEADER *)packet; + packet += sizeof(struct ETHERNET_HEADER); + uint8_t *payload = packet; + packet += packet_length - sizeof(struct ETHERNET_HEADER); + uint32_t crc = *((uint32_t *)packet - 1); + kprintf("PACKET crc: %x\n", crc); + kprintf("OUR OWN CALCULATED crc: %x\n", + crc32((const char *)eth_header, (packet_length - 4))); + + kprintf("mac dst: "); + for (int i = 0; i < 6; i++) + kprintf("%x", eth_header->mac_dst[i]); + kprintf("\n"); + kprintf("mac src: "); + for (int i = 0; i < 6; i++) + kprintf("%x", eth_header->mac_src[i]); + kprintf("\n"); + + uint16_t type = ntohs(eth_header->type); + kprintf("Etheretype: %x\n", type); + switch (type) { + case 0x0806: + handle_arp(payload); + break; + case 0x0800: + kprintf("IPV4 message\n"); + break; + default: + kprintf("Can't handle ethernet type\n"); + break; + } +} + +void send_ethernet_packet(uint8_t mac_dst[6], uint16_t type, uint8_t *payload, + uint64_t payload_length) { + // FIXME: Janky allocation, do this better + uint64_t buffer_size = + sizeof(struct ETHERNET_HEADER) + payload_length + sizeof(uint32_t); + uint8_t *buffer = kmalloc(buffer_size); + uint8_t *buffer_start = buffer; + struct ETHERNET_HEADER *eth_header = (struct ETHERNET_HEADER *)buffer; + buffer += sizeof(struct ETHERNET_HEADER); + memcpy(buffer, payload, payload_length); + buffer += payload_length; + + memcpy(eth_header->mac_dst, mac_dst, sizeof(uint8_t[6])); + get_mac_address(eth_header->mac_src); + eth_header->type = htons(type); + *(uint32_t *)(buffer) = + htonl(crc32((const char *)buffer_start, buffer_size - 4)); + + assert(rtl8139_send_data(buffer_start, buffer_size)); + kprintf("sent data\n"); +} diff --git a/network/ethernet.h b/network/ethernet.h new file mode 100644 index 0000000..88a4dc6 --- /dev/null +++ b/network/ethernet.h @@ -0,0 +1,5 @@ +#include <stdint.h> + +void handle_ethernet(uint8_t *packet, uint64_t packet_length); +void send_ethernet_packet(uint8_t mac_dst[6], uint16_t type, uint8_t *payload, + uint64_t payload_length); |