summaryrefslogtreecommitdiff
path: root/net/arp.c
diff options
context:
space:
mode:
authorMiguel <m.i@gmx.at>2018-09-25 12:43:03 +0200
committerMiguel <m.i@gmx.at>2018-09-25 12:43:03 +0200
commit112ca29a3bb2ab38693943ed33ee51f4fd7d2d81 (patch)
treec843051f9291ebe2de6e603c45d924d843d35ea4 /net/arp.c
parent2ba77c01a33c3454aeed42d5394dd5ccede10851 (diff)
arp replies working!
Diffstat (limited to 'net/arp.c')
-rw-r--r--net/arp.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/net/arp.c b/net/arp.c
new file mode 100644
index 0000000..501186f
--- /dev/null
+++ b/net/arp.c
@@ -0,0 +1,126 @@
+// https://github.com/saminiir/level-ip/blob/e9ceb08f01a5499b85f03e2d615309c655b97e8f/src/arp.c#L53
+// https://github.com/chobits/tapip
+// https://tools.ietf.org/html/rfc826
+
+#include "inet.h"
+#include "eth.h"
+#include "arp.h"
+#include "netdev.h"
+#include "log.h"
+
+#include "lib/string/string.h"
+
+/*
+ */
+/*
+static struct arp_cache_entry arp_cache[ARP_CACHE_LEN];
+
+static int insert_arp_translation_table(struct arp_hdr *hdr, struct arp_ipv4 *data)
+{
+ struct arp_cache_entry *entry;
+ for (int i = 0; i<ARP_CACHE_LEN; i++) {
+ entry = &arp_cache[i];
+
+ if (entry->state == ARP_FREE) {
+ entry->state = ARP_RESOLVED;
+
+ entry->hwtype = hdr->hwtype;
+ entry->sip = data->sip;
+ memcpy(entry->smac, data->smac, sizeof(entry->smac));
+
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int update_arp_translation_table(struct arp_hdr *hdr, struct arp_ipv4 *data)
+{
+ struct arp_cache_entry *entry;
+
+ for (int i = 0; i<ARP_CACHE_LEN; i++) {
+ entry = &arp_cache[i];
+
+ if (entry->state == ARP_FREE) continue;
+
+ if (entry->hwtype == hdr->hwtype && entry->sip == data->sip) {
+ memcpy(entry->smac, data->smac, 6);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void arp_init()
+{
+ memset(arp_cache, 0, ARP_CACHE_LEN * sizeof(struct arp_cache_entry));
+}
+*/
+
+void arp_reply(struct netdev *netdev, struct eth_hdr *hdr, struct arp_hdr *arphdr)
+{
+ struct arp_ipv4 *arpdata;
+ int len;
+
+ arpdata = (struct arp_ipv4 *) arphdr->data;
+
+ memcpy(arpdata->dmac, arpdata->smac, 6);
+ arpdata->dip = arpdata->sip;
+ memcpy(arpdata->smac, netdev->hwaddr, 6);
+ arpdata->sip = netdev->ip;
+
+ arphdr->opcode = ARP_REPLY;
+
+ arphdr->opcode = htons(arphdr->opcode);
+ arphdr->hwtype = htons(arphdr->hwtype);
+ arphdr->protype = htons(arphdr->protype);
+
+ len = sizeof(struct arp_hdr) + sizeof(struct arp_ipv4);
+ netdev_transmit(netdev, hdr, ETH_P_ARP, len, arpdata->dmac);
+}
+
+void arp_incoming(struct netdev *netdev, struct eth_hdr *hdr)
+{
+ struct arp_hdr *arphdr;
+ struct arp_ipv4 *arpdata;
+ int merge = 0;
+
+ arphdr = (struct arp_hdr *) hdr->payload;
+
+ arphdr->hwtype = ntohs(arphdr->hwtype);
+ arphdr->protype = ntohs(arphdr->protype);
+ arphdr->opcode = ntohs(arphdr->opcode);
+
+ if (arphdr->hwtype != ARP_ETHERNET) {
+ klog("Unsupported HW type\n");
+ return;
+ }
+
+ if (arphdr->protype != ARP_IPV4) {
+ klog("Unsupported protocol\n");
+ return;
+ }
+
+ arpdata = (struct arp_ipv4 *) arphdr->data;
+
+// merge = update_arp_translation_table(arphdr, arpdata);
+
+ if (netdev->ip != arpdata->dip) {
+ klog("ARP was not for us\n");
+ }
+
+// if (!merge && insert_arp_translation_table(arphdr, arpdata) != 0) {
+ // klog("ERR: No free space in ARP translation table\n");
+ // }
+
+ switch (arphdr->opcode) {
+ case ARP_REQUEST:
+ arp_reply(netdev, hdr, arphdr);
+ break;
+ default:
+ klog("Opcode not supported\n");
+ break;
+ }
+}