summaryrefslogtreecommitdiff
path: root/network/arp.c
blob: f86c7325c2238c82c59b1a2dc072b650849956d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#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(const 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));
}