summaryrefslogtreecommitdiff
path: root/fw/test/rawether.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/test/rawether.c')
-rw-r--r--fw/test/rawether.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/fw/test/rawether.c b/fw/test/rawether.c
new file mode 100644
index 0000000..540d0b6
--- /dev/null
+++ b/fw/test/rawether.c
@@ -0,0 +1,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);
+}