summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel/arch/amd64/driver/rtl8139.c6
-rw-r--r--src/kernel/arch/amd64/pci.c2
-rw-r--r--src/user/app/ethdump/ethdump.c172
3 files changed, 114 insertions, 66 deletions
diff --git a/src/kernel/arch/amd64/driver/rtl8139.c b/src/kernel/arch/amd64/driver/rtl8139.c
index 5b09027..428d675 100644
--- a/src/kernel/arch/amd64/driver/rtl8139.c
+++ b/src/kernel/arch/amd64/driver/rtl8139.c
@@ -39,7 +39,7 @@ static size_t rxpos;
static char txbuf[4][txbuf_len];
static void rx_irq_enable(bool v) {
- uint16_t mask = 1 | 4; /* rx/tx ok */
+ uint16_t mask = 1; /* rx ok */
port_out16(iobase + INTRMASK, v ? mask : 0);
}
@@ -85,11 +85,11 @@ void rtl8139_init(uint32_t bdf) {
void rtl8139_irq(void) {
uint16_t status = port_in16(iobase + INTRSTATUS);
- if (status != 1) {
+ if (!(status & 1)) {
kprintf("bad rtl8139 status 0x%x\n", status);
panic_unimplemented();
}
- // TODO don't assume this is an rx irq
+ status &= 1;
do {
if (blocked_on) {
diff --git a/src/kernel/arch/amd64/pci.c b/src/kernel/arch/amd64/pci.c
index 93fffec..92e2697 100644
--- a/src/kernel/arch/amd64/pci.c
+++ b/src/kernel/arch/amd64/pci.c
@@ -60,9 +60,7 @@ static void scan_bus(uint32_t bus) {
}
if (id == 0x813910ec) {
- kprintf("rtl irq %u\n", pcicfg_r8(bdf, 0x3C));
pcicfg_w32(bdf, 0x3C, IRQ_RTL8139);
- kprintf("rtl irq %u\n", pcicfg_r8(bdf, 0x3C));
rtl8139_init(bdf);
}
}
diff --git a/src/user/app/ethdump/ethdump.c b/src/user/app/ethdump/ethdump.c
index adcb95e..8d5be34 100644
--- a/src/user/app/ethdump/ethdump.c
+++ b/src/user/app/ethdump/ethdump.c
@@ -1,4 +1,5 @@
#include <camellia/syscalls.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -6,8 +7,14 @@
#define eprintf(fmt, ...) fprintf(stderr, "ethdump: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-static void hexdump(void *vbuf, size_t len) {
- uint8_t *buf = vbuf;
+handle_t eth_h;
+
+// TODO dynamically get mac
+uint8_t my_mac[] = {0x52, 0x54, 0x00, 0xCA, 0x77, 0x1A};
+uint32_t my_ip = (192 << 24) + (168 << 16) + 11;
+
+static void hexdump(const void *vbuf, size_t len) {
+ const uint8_t *buf = vbuf;
for (size_t i = 0; i < len; i += 16) {
printf("%08x ", i);
@@ -20,19 +27,42 @@ static void hexdump(void *vbuf, size_t len) {
}
}
+static void nput16(void *vbuf, uint16_t n) {
+ uint8_t *b = vbuf;
+ b[0] = n >> 8;
+ b[1] = n >> 0;
+}
+
+static void nput32(void *vbuf, uint32_t n) {
+ uint8_t *b = vbuf;
+ b[0] = n >> 24;
+ b[1] = n >> 16;
+ b[2] = n >> 8;
+ b[3] = n >> 0;
+}
+
+static uint16_t nget16(const void *vbuf) {
+ const uint8_t *b = vbuf;
+ return (b[0] << 8)
+ | (b[1] << 0);
+}
+
+static uint32_t nget32(const void *vbuf) {
+ const uint8_t *b = vbuf;
+ return (b[0] << 24)
+ | (b[1] << 16)
+ | (b[2] << 8)
+ | (b[3] << 0);
+}
+
+
static void parse_icmp(const uint8_t *buf, size_t len) {
if (len < 4) return;
uint8_t type = buf[0];
- switch (type) {
- case 8:
- printf("icmp type %u - echo request\n", type);
- break;
- default:
- printf("icmp type %u - unknown\n", type);
- break;
- }
+ printf("ICMP type %u\n", type);
}
+
static void parse_ipv4(const uint8_t *buf, size_t len) {
uint8_t version, headerlen, proto;
uint16_t packetlen, id, fragoffset;
@@ -44,17 +74,11 @@ static void parse_ipv4(const uint8_t *buf, size_t len) {
return;
}
headerlen = (buf[0] & 0xf) * 4;
- packetlen = (buf[2] << 8) | buf[3];
- id = (buf[4] << 8) | buf[5];
+ packetlen = nget16(buf + 2);
+ id = nget16(buf + 4);
proto = buf[9];
- src = (buf[12] << 24)
- | (buf[13] << 16)
- | (buf[14] << 8)
- | (buf[15] << 0);
- dest = (buf[16] << 24)
- | (buf[17] << 16)
- | (buf[18] << 8)
- | (buf[19] << 0);
+ src = nget32(buf + 12);
+ dest = nget32(buf + 16);
// TODO checksum
// TODO fragmentation
@@ -77,11 +101,53 @@ static void parse_ipv4(const uint8_t *buf, size_t len) {
}
}
+static void parse_arp(const uint8_t *buf, size_t len) {
+ // TODO no bound checks
+ uint16_t htype = nget16(buf + 0);
+ uint16_t ptype = nget16(buf + 2);
+ uint16_t op = nget16(buf + 6);
+
+ const char *ops = "bad operation";
+ if (op == 1) ops = "request";
+ if (op == 2) ops = "reply";
+
+ printf("ARP htype 0x%x, ptype 0x%x, %s\n", htype, ptype, ops);
+
+ if (!(htype == 1 && ptype == 0x800)) return;
+ /* IPv4 over Ethernet */
+
+ if (op != 1) return;
+ /* a request */
+
+ uint32_t daddr = nget32(buf + 24);
+ printf("IPv4 request for %08x\n", daddr);
+
+ if (daddr == my_ip) {/* send a response */
+ char res[64];
+ memset(res, 0, 64);
+ /* Ethernet */
+ memcpy(res + 0, buf + 8, 6); /* from ARP sender MAC */
+ memcpy(res + 6, my_mac, 6);
+ nput16(res + 12, 0x0806); /* ethertype == ARP */
+
+ /* ARP */
+ nput16(res + 14, 1); /* Ethernet */
+ nput16(res + 16, 0x800); /* IPv4 */
+ res[18] = 6; res[19] = 4; /* address lengths */
+ nput16(res + 20, 2); /* operation == reply */
+ memcpy(res + 22, my_mac, 6);
+ nput32(res + 28, my_ip);
+ memcpy(res + 32, buf + 8, 10); /* sender's MAC and IP */
+ printf("sending ARP response:\n");
+ hexdump(res, sizeof res);
+ _syscall_write(eth_h, res, sizeof res, 0, 0);
+ }
+}
+
/* https://www.w3.org/TR/PNG/#D-CRCAppendix */
uint32_t crc_table[256];
static uint32_t crc32(const uint8_t *buf, size_t len) {
if (!crc_table[1]) {
- eprintf("building crc cache");
for (int i = 0; i < 256; i++) {
uint32_t c = i;
for (int j = 0; j < 8; j++)
@@ -107,63 +173,47 @@ static void parse_ethernet(const uint8_t *buf, size_t len) {
printf("to %02x:%02x:%02x:%02x:%02x:%02x\n",
dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]);
- /* byte order switched on purpose */
- uint32_t crc = (buf[len - 1] << 24)
- | (buf[len - 2] << 16)
- | (buf[len - 3] << 8)
- | (buf[len - 4] << 0);
- printf("fcf %x, crc %x\n", crc, crc32(buf, len - 4));
-
- uint16_t ethertype = (buf[12] << 8) | buf[13];
- if (ethertype == 0x800) {
- printf("ethertype %u - IPv4\n", ethertype);
- parse_ipv4(buf + 14, len - 14);
- } else {
- printf("ethertype %u - unknown\n", ethertype);
+ if (false) {
+ /* byte order switched on purpose */
+ uint32_t crc = (buf[len - 1] << 24)
+ | (buf[len - 2] << 16)
+ | (buf[len - 3] << 8)
+ | (buf[len - 4] << 0);
+ printf("fcf %x, crc %x\n", crc, crc32(buf, len - 4));
}
-}
-static void dummy_packet(handle_t h) {
- const uint8_t packet[] = {
- /* raw dump of a ICMP broadcast ping */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x52, 0x54,
- 0x00, 0x12, 0x34, 0x56, 0x08, 0x00, 0x45, 0x00,
- 0x00, 0x54, 0x06, 0xa6, 0x40, 0x00, 0x40, 0x01,
- 0x73, 0x5a, 0xc0, 0xa8, 0x00, 0x01, 0xff, 0xff,
- 0xff, 0xff, 0x08, 0x00, 0x82, 0x62, 0xef, 0x07,
- 0x00, 0xcb, 0x3b, 0x83, 0x4a, 0x47, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- /* 0x20, 0xcf, 0x98, 0x7f, */ /* crc */
- };
- _syscall_write(h, packet, sizeof packet, 0, 0);
+ uint16_t ethertype = nget16(buf + 12);
+ printf("ethertype %u\n", ethertype);
+ switch (ethertype) {
+ case 0x800:
+ parse_ipv4(buf + 14, len - 14);
+ break;
+ case 0x806:
+ parse_arp(buf + 14, len - 14);
+ break;
+ default:
+ printf("(unknown)\n");
+ break;
+ }
}
int main(void) {
const char *path = "/kdev/eth";
- handle_t h = _syscall_open(path, strlen(path), 0);
- if (h < 0) {
+ eth_h = _syscall_open(path, strlen(path), 0);
+ if (eth_h < 0) {
eprintf("couldn't open %s", path);
return 1;
}
- for (int i = 0; i < 20; i++)
- dummy_packet(h);
- return 0;
-
const size_t buflen = 4096;
char *buf = malloc(buflen);
for (;;) {
- long ret = _syscall_read(h, buf, buflen, -1);
+ long ret = _syscall_read(eth_h, buf, buflen, -1);
if (ret < 0) break;
printf("\npacket of length %u\n", ret);
hexdump(buf, ret);
parse_ethernet((void*)buf, ret);
}
+ free(buf);
return 0;
}