summaryrefslogtreecommitdiff
path: root/fw/test/rawether.c
blob: 540d0b6f5f0513822ca5e8e9eea6fe3daf268e28 (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
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * rawether - put one ethernet frame on the wire, addressed as told.
 *
 * A stack will only ever address a frame to the mac it resolved, so a
 * frame addressed to somebody else has to be forged.  That is the only
 * way to ask a firewall on a card whether it is looking at frames that
 * are not for it.
 *
 *	rawether /net/ether1 <dstmac> <srcip> <dstip>
 *
 * The payload is an icmp echo request, which is enough to be counted.
 */
#include <u.h>
#include <libc.h>
#include <ip.h>

enum { Ehdrlen = 14, Eminlen = 60, Etip4 = 0x0800 };

static ushort
csum(uchar *p, int n)
{
	ulong s;
	int i;

	s = 0;
	for(i = 0; i+1 < n; i += 2)
		s += (p[i]<<8) | p[i+1];
	if(i < n)
		s += p[i]<<8;
	while(s >> 16)
		s = (s & 0xFFFF) + (s >> 16);
	return ~s;
}

void
main(int argc, char **argv)
{
	uchar f[Eminlen], dst[6], src[6], sip[IPaddrlen], dip[IPaddrlen];
	char path[128], buf[64];
	int cfd, dfd, n, conn;

	if(argc != 5){
		fprint(2, "usage: rawether /net/etherN dstmac srcip dstip\n");
		exits("usage");
	}
	if(parseether(dst, argv[2]) < 0)
		sysfatal("%s: bad ethernet address", argv[2]);
	if(parseip(sip, argv[3]) == -1 || parseip(dip, argv[4]) == -1)
		sysfatal("bad ip address");

	snprint(path, sizeof path, "%s/clone", argv[1]);
	if((cfd = open(path, ORDWR)) < 0)
		sysfatal("open %s: %r", path);
	if((n = read(cfd, buf, sizeof buf - 1)) <= 0)
		sysfatal("read %s: %r", path);
	buf[n] = '\0';
	conn = atoi(buf);
	if(fprint(cfd, "connect -1") < 0)
		sysfatal("connect -1: %r");
	snprint(path, sizeof path, "%s/%d/data", argv[1], conn);
	if((dfd = open(path, ORDWR)) < 0)
		sysfatal("open %s: %r", path);
	snprint(path, sizeof path, "%s/addr", argv[1]);
	if((n = open(path, OREAD)) < 0)
		sysfatal("open addr: %r");
	if(read(n, buf, 12) != 12)
		sysfatal("read addr: %r");
	close(n);
	buf[12] = '\0';
	if(parseether(src, buf) < 0)
		sysfatal("unparseable card address %s", buf);

	memset(f, 0, sizeof f);
	memmove(f, dst, 6);
	memmove(f+6, src, 6);
	f[12] = Etip4 >> 8;
	f[13] = Etip4;

	f[14] = 0x45;			/* v4, 20 byte header */
	hnputs(f+16, 28);		/* total length */
	f[22] = 64;			/* ttl */
	f[23] = 1;			/* icmp */
	memmove(f+26, sip+IPv4off, 4);
	memmove(f+30, dip+IPv4off, 4);
	hnputs(f+24, csum(f+14, 20));

	f[34] = 8;			/* echo request */
	hnputs(f+38, 0x1234);		/* id */
	hnputs(f+40, 1);		/* seq */
	hnputs(f+36, csum(f+34, 8));

	if(write(dfd, f, sizeof f) != sizeof f)
		sysfatal("write: %r");
	fmtinstall('E', eipfmt);
	print("sent %d bytes to %E\n", (int)sizeof f, dst);
	exits(nil);
}