diff options
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);  |