diff options
author | dzwdz | 2022-08-17 13:35:13 +0200 |
---|---|---|
committer | dzwdz | 2022-08-17 13:35:13 +0200 |
commit | 5eabc4872ecd883feb80b6517e0fd137fa702cc1 (patch) | |
tree | 608f453905c607c0a2a506a7e5090694eb33fc35 | |
parent | 2341a0705164e94d0874572505b60680fdbe631f (diff) |
user/ethdump: parse the Ethernet, IPv4, ICMP frames
-rw-r--r-- | src/user/app/ethdump/ethdump.c | 84 |
1 files changed, 82 insertions, 2 deletions
diff --git a/src/user/app/ethdump/ethdump.c b/src/user/app/ethdump/ethdump.c index 249ecd7..8ac1cbf 100644 --- a/src/user/app/ethdump/ethdump.c +++ b/src/user/app/ethdump/ethdump.c @@ -6,7 +6,7 @@ #define eprintf(fmt, ...) fprintf(stderr, "ethdump: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) -void hexdump(void *vbuf, size_t len) { +static void hexdump(void *vbuf, size_t len) { uint8_t *buf = vbuf; for (size_t i = 0; i < len; i += 16) { printf("%08x ", i); @@ -20,6 +20,84 @@ void hexdump(void *vbuf, size_t len) { } } +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; + } +} + +static void parse_ipv4(const uint8_t *buf, size_t len) { + uint8_t version, headerlen, proto; + uint16_t packetlen, id, fragoffset; + uint32_t dest, src; + + version = buf[0] >> 4; + if (version != 4) { + printf("bad IPv4 version %u\n", version); + return; + } + headerlen = (buf[0] & 0xf) * 4; + packetlen = (buf[2] << 8) | buf[3]; + id = (buf[4] << 8) | buf[5]; + 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); + + // TODO checksum + // TODO fragmentation + + printf("headerlen %u, packetlen %u (real %u), id %u\n", headerlen, packetlen, len, id); + printf("from %x to %x\n", src, dest); + printf("id %u\n", id); + if (packetlen < headerlen) { + printf("headerlen too big\n"); + return; + } + switch (proto) { + case 1: + printf("proto %u - icmp\n", proto); + parse_icmp(buf + headerlen, packetlen - headerlen); + break; + default: + printf("proto %u - unknown\n", proto); + break; + } +} + +static void parse_ethernet(const uint8_t *buf, size_t len) { + uint8_t dmac[6], smac[6]; + uint16_t ethertype; + + if (len < 60) return; + for (int i = 0; i < 6; i++) dmac[i] = buf[i]; + for (int i = 0; i < 6; i++) smac[i] = buf[i + 6]; + 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]); + + 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); + } +} + int main(void) { const char *path = "/kdev/eth"; handle_t h = _syscall_open(path, strlen(path), 0); @@ -33,7 +111,9 @@ int main(void) { for (;;) { long ret = _syscall_read(h, buf, buflen, -1); if (ret < 0) break; - printf("packet of length %u\n", ret); + printf("\npacket of length %u\n", ret); hexdump(buf, ret); + parse_ethernet((void*)buf, ret); } + return 0; } |