summaryrefslogtreecommitdiff
path: root/src/user/app/ethdump/ether.c
blob: 32646e2cbc6fe08c37c92ea9930be680401767cd (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
#include <camellia/syscalls.h>
#include <stdlib.h>
#include <string.h>
#include "proto.h"
#include "util.h"

enum {
	DstMAC    =  0,
	SrcMAC    =  6,
	EtherType = 12,
	Payload   = 14,
};

void ether_parse(const uint8_t *buf, size_t len) {
	uint8_t dmac[6], smac[6];

	if (len < 60) return;
	for (int i = 0; i < 6; i++) dmac[i] = buf[i + DstMAC];
	for (int i = 0; i < 6; i++) smac[i] = buf[i + SrcMAC];
	printf("from %02x:%02x:%02x:%02x:%02x:%02x\n",
		smac[0], smac[1], smac[2], smac[3], smac[4], smac[5]);
	printf("to   %02x:%02x:%02x:%02x:%02x:%02x\n",
		dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]);

	uint16_t ethertype = nget16(buf + EtherType);
	printf("ethertype %u\n", ethertype);

	struct ethernet ether = (struct ethernet){
		.src = &smac,
		.dst = &dmac,
		.type = ethertype,
	};

	switch (ethertype) {
		case ET_IPv4:
			ipv4_parse(buf + Payload, len - Payload, ether);
			break;
		case ET_ARP:
			arp_parse(buf + Payload, len - Payload);
			break;
		default:
			printf("(unknown)\n");
			break;
	}
}

static const size_t fhoff = sizeof(size_t);
uint8_t *ether_start(size_t len, struct ethernet ether) {
	if (len < 60 - Payload) len = 60 - Payload;

	if (!ether.dst) eprintf("NULL ether.dst!"); // TODO arp? i guess?
	if (!ether.src) ether.src = &state.mac;

	uint8_t *buf = malloc(fhoff + Payload + len);
	memset(buf, 0, fhoff + Payload + len);
	*(size_t*)buf = len + Payload;
	memcpy(buf + fhoff + DstMAC, ether.dst, 6);
	memcpy(buf + fhoff + SrcMAC, ether.src, 6);
	nput16(buf + fhoff + EtherType, ether.type);
	return buf + fhoff + Payload;
}
void ether_finish(uint8_t *pkt) {
	uint8_t *buf = pkt - Payload - fhoff;
	size_t len = *(size_t*)buf;
	printf("sending:\n");
	hexdump(buf + fhoff, len);
	_syscall_write(state.raw_h, buf + fhoff, len, 0, 0);
	free(buf);
}