From 9251a3b7cce627a1625c13fd3a9f1fa6dce3a427 Mon Sep 17 00:00:00 2001 From: Ali Mashtizadeh Date: Wed, 28 Jan 2015 11:35:47 -0800 Subject: [PATCH] ethinject and plumbing for transmitting raw network packets. --- SConstruct | 2 ++ bin/ethdump/ethdump.c | 2 +- bin/ethinject/SConscript | 21 +++++++++++ bin/ethinject/ethinject.c | 73 +++++++++++++++++++++++++++++++++++++++ include/net/ethernet.h | 1 + include/stdio.h | 2 ++ release/bootdisk.manifest | 1 + sys/dev/e1000.c | 30 ++++++++++++++-- sys/kern/syscall.c | 26 ++++++++++++-- 9 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 bin/ethinject/SConscript create mode 100644 bin/ethinject/ethinject.c diff --git a/SConstruct b/SConstruct index abb9cfa..3058897 100644 --- a/SConstruct +++ b/SConstruct @@ -162,6 +162,7 @@ CopyTree('build/include/machine', 'sys/' + env['ARCH'] + '/include', env) SConscript('sys/SConscript', variant_dir='build/sys') SConscript('lib/libc/SConscript', variant_dir='build/lib/libc') SConscript('bin/ethdump/SConscript', variant_dir='build/bin/ethdump') +SConscript('bin/ethinject/SConscript', variant_dir='build/bin/ethinject') SConscript('bin/shell/SConscript', variant_dir='build/bin/shell') SConscript('sbin/ifconfig/SConscript', variant_dir='build/sbin/ifconfig') SConscript('sbin/init/SConscript', variant_dir='build/sbin/init') @@ -185,6 +186,7 @@ if env["BOOTDISK"] == "1": bootdisk = env.BuildImage('#build/bootdisk.img', '#release/bootdisk.manifest') Depends(bootdisk, "#build/tools/newfs_o2fs/newfs_o2fs") Depends(bootdisk, "#build/bin/ethdump/ethdump") + Depends(bootdisk, "#build/bin/ethinject/ethinject") Depends(bootdisk, "#build/bin/shell/shell") Depends(bootdisk, "#build/sbin/ifconfig/ifconfig") Depends(bootdisk, "#build/sbin/init/init") diff --git a/bin/ethdump/ethdump.c b/bin/ethdump/ethdump.c index b4443d7..7817da8 100644 --- a/bin/ethdump/ethdump.c +++ b/bin/ethdump/ethdump.c @@ -67,7 +67,7 @@ main(int argc, const char *argv[]) return 1; } - printf("Listening to nic%d\n", nic.nicNo); + printf("Listening to nic%d\n", (int)nic.nicNo); while (1) { readPacket(&nic); diff --git a/bin/ethinject/SConscript b/bin/ethinject/SConscript new file mode 100644 index 0000000..d94ae60 --- /dev/null +++ b/bin/ethinject/SConscript @@ -0,0 +1,21 @@ +import sys + +Import('env') + +ethinject_env = env.Clone() + +src = [ ] + +src_common = [ + "ethinject.c" +] + +src.append(src_common) + +ethinject_env.Append(LINKFLAGS = ['-nostdlib']) +ethinject_env.Append(CPPFLAGS = ['-nostdinc']) +ethinject_env.Append(CPPPATH = ['#build/include']) +ethinject_env.Append(LIBPATH = ['#build/lib/libc'], LIBS = ['c']) + +ethinject_env.Program("ethinject", src) + diff --git a/bin/ethinject/ethinject.c b/bin/ethinject/ethinject.c new file mode 100644 index 0000000..3e2f18f --- /dev/null +++ b/bin/ethinject/ethinject.c @@ -0,0 +1,73 @@ + +#include +#include +#include +#include + +#include + +static int nicNo = 1; +static char buf[4096]; +static MBuf mbuf; + +void +writePacket(NIC *nic) +{ + uint64_t status; + + mbuf.vaddr = (uint64_t)&buf; + mbuf.maddr = 0; + mbuf.len = 64; + mbuf.type = MBUF_TYPE_NULL; + mbuf.flags = 0; + mbuf.status = MBUF_STATUS_NULL; + + status = OSNICSend(nicNo, &mbuf); + if (status != 0) { + printf("OSNICSend failed!\n"); + return; + } + + if (mbuf.status == MBUF_STATUS_FAILED) { + printf("Failed to write packet!\n"); + return; + } +} + +int +main(int argc, const char *argv[]) +{ + uint64_t status; + NIC nic; + + printf("Ethernet Dump Tool\n"); + + status = OSNICStat(nicNo, &nic); + if (status == ENOENT) { + printf("nic%d not present\n", nicNo); + return 1; + } + + printf("Injecting packet on nic%d\n", (int)nic.nicNo); + + struct ether_header *hdr = (struct ether_header *)&buf; + hdr->ether_dhost[0] = 0xFF; + hdr->ether_dhost[1] = 0xFF; + hdr->ether_dhost[2] = 0xFF; + hdr->ether_dhost[3] = 0xFF; + hdr->ether_dhost[4] = 0xFF; + hdr->ether_dhost[5] = 0xFF; + + hdr->ether_shost[0] = 0x00; + hdr->ether_shost[1] = 0x11; + hdr->ether_shost[2] = 0x22; + hdr->ether_shost[3] = 0x33; + hdr->ether_shost[4] = 0x44; + hdr->ether_shost[5] = 0x55; + + while (1) { + writePacket(&nic); + sleep(5); + } +} + diff --git a/include/net/ethernet.h b/include/net/ethernet.h index 7f92db7..03f7df2 100644 --- a/include/net/ethernet.h +++ b/include/net/ethernet.h @@ -22,6 +22,7 @@ struct ether_addr { #define ETHERTYPE_IP 0x0800 /* IP */ #define ETHERTYPE_ARP 0x0806 /* ARP */ +#define ETHERTYPE_REVARP 0x8036 /* Reverse ARP */ #define ETHERTYPE_IPV6 0x86DD /* IPv6 */ #endif /* __NET_ETHERNET_H__ */ diff --git a/include/stdio.h b/include/stdio.h index 2b6a9b2..061639e 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -39,6 +39,8 @@ int puts(const char *str); int printf(const char *fmt, ...); int fprintf(FILE *stream, const char *fmt, ...); +int sprintf(char *str, const char *fmt, ...); +int snprintf(char *str, size_t size, const char *fmt, ...); #endif /* __STDIO_H__ */ diff --git a/release/bootdisk.manifest b/release/bootdisk.manifest index 6b3b04f..a8e687d 100644 --- a/release/bootdisk.manifest +++ b/release/bootdisk.manifest @@ -6,6 +6,7 @@ DIR / END DIR bin FILE ethdump build/bin/ethdump/ethdump + FILE ethinject build/bin/ethinject/ethinject FILE shell build/bin/shell/shell END DIR sbin diff --git a/sys/dev/e1000.c b/sys/dev/e1000.c index d4e2229..abeb009 100644 --- a/sys/dev/e1000.c +++ b/sys/dev/e1000.c @@ -58,6 +58,7 @@ void E1000_Configure(PCIDevice dev); #define E1000_REG_TDH 0x3810 #define E1000_REG_TDT 0x3818 #define E1000_REG_TIDV 0x3820 +#define E1000_REG_TADV 0x382C #define E1000_REG_MTABASE 0x5200 @@ -111,6 +112,11 @@ typedef struct PACKED E1000TXDesc { volatile uint16_t special; } E1000TXDesc; +#define TDESC_CMD_RS (1 << 3) /* Report Status */ +#define TDESC_CMD_IC (1 << 2) /* Insert Checksum */ +#define TDESC_CMD_IFCS (1 << 1) /* Insert Ethernet FCS/CRC */ +#define TDESC_CMD_EOP (1 << 0) /* End-of-Packet */ + /* * Driver Configuration and Structures */ @@ -220,6 +226,7 @@ void E1000_TXPoll(E1000Dev *dev) { // Free memory + kprintf("TXPOLL\n"); } void @@ -323,7 +330,7 @@ retry: //Debug_PrintHex(data, len, 0, len); // Use CB instead - memcpy(mbuf->vaddr, data, len); + memcpy((void *)mbuf->vaddr, data, len); dev->rxDesc[dev->rxTail].status = 0; dev->rxDesc[dev->rxTail].errors = 0; @@ -353,6 +360,18 @@ retry: int E1000_Enqueue(NIC *nic, MBuf *mbuf, NICCB cb, void *arg) { + E1000Dev *dev = (E1000Dev *)nic; + void *data = (void *)DMPA2VA(dev->txDesc[dev->txTail].addr); + + // Copy data + memcpy(data, (void *)mbuf->vaddr, mbuf->len); + dev->txDesc[dev->txTail].len = mbuf->len; + + dev->txDesc[dev->txTail].cmd = TDESC_CMD_EOP | TDESC_CMD_IFCS | TDESC_CMD_RS; + MMIO_Write32(dev, E1000_REG_TDT, dev->txTail); + dev->txTail = (dev->txTail + 1) % E1000_TX_QLEN; + + // Wait for transmit to complete } void @@ -392,7 +411,7 @@ E1000_TXInit(E1000Dev *dev) dev->txDesc = (E1000TXDesc *)E1000RXDesc_Alloc(); for (i = 0; i < E1000_TX_QLEN; i++) { - dev->txDesc[i].addr = 0; + dev->txDesc[i].addr = VA2PA((uintptr_t)PAlloc_AllocPage()); // LOOKUP IN PMAP dev->txDesc[i].cmd = 0; } @@ -406,6 +425,10 @@ E1000_TXInit(E1000Dev *dev) MMIO_Write32(dev, E1000_REG_TDT, 0); dev->txTail = 0; + // Interrupt Delay Timers + MMIO_Write32(dev, E1000_REG_TIDV, 1); + MMIO_Write32(dev, E1000_REG_TADV, 1); + MMIO_Write32(dev, E1000_REG_TCTL, TCTL_EN | TCTL_PSP); } @@ -415,6 +438,9 @@ E1000_Configure(PCIDevice dev) E1000Dev *ethDev = (E1000Dev *)PAlloc_AllocPage(); PCI_Configure(&dev); + // Ensure that the NIC structure is the first thing inside E1000Dev + ASSERT((void *)ethDev == (void *)ðDev->nic); + if (!runOnce) { runOnce = true; diff --git a/sys/kern/syscall.c b/sys/kern/syscall.c index d1444cf..4c3057e 100644 --- a/sys/kern/syscall.c +++ b/sys/kern/syscall.c @@ -410,9 +410,13 @@ Syscall_ThreadSleep(uint64_t time) // If the sleep time is zero just yield if (time != 0) { + Thread_Retain(cur); cur->timerEvt = KTimer_Create(time, ThreadWakeupHelper, cur); - if (cur->timerEvt == NULL) + if (cur->timerEvt == NULL) { + Thread_Release(cur); + Thread_Release(cur); return -ENOMEM; + } Sched_SetWaiting(cur); } @@ -472,7 +476,25 @@ Syscall_NICStat(uint64_t nicNo, uint64_t user_stat) uint64_t Syscall_NICSend(uint64_t nicNo, uint64_t user_mbuf) { - return SYSCALL_PACK(ENOSYS, 0); + int status; + NIC *nic; + MBuf mbuf; + + status = CopyIn(user_mbuf, &mbuf, sizeof(mbuf)); + if (status != 0) { + return SYSCALL_PACK(status, 0); + } + + nic = NIC_GetByID(nicNo); + if (nic == NULL) { + return SYSCALL_PACK(ENOENT, 0); + } + + // Pin Memory + (nic->tx)(nic, &mbuf, NULL, NULL); + // Unpin Memory + + return 0; } uint64_t