Tools/NetTest - Add a runner to test networking stack
authorJohn Hodge <[email protected]>
Sun, 16 Mar 2014 05:43:59 +0000 (13:43 +0800)
committerJohn Hodge <[email protected]>
Sun, 16 Mar 2014 05:43:59 +0000 (13:43 +0800)
34 files changed:
.gitignore
Tools/NetTest/Makefile
Tools/NetTest/include/nettest.h
Tools/NetTest/main.c
Tools/NetTest/mode_cmdline.c [new file with mode: 0644]
Tools/NetTest/nic.c
Tools/NetTest/tap.c
Tools/NetTest/vfs_shim.c
Tools/NetTest_Runner/Makefile [new file with mode: 0644]
Tools/NetTest_Runner/arp.c [new file with mode: 0644]
Tools/NetTest_Runner/include/arp.h [new file with mode: 0644]
Tools/NetTest_Runner/include/common.h [new file with mode: 0644]
Tools/NetTest_Runner/include/ip.h [new file with mode: 0644]
Tools/NetTest_Runner/include/link.h [new file with mode: 0644]
Tools/NetTest_Runner/include/net.h [new file with mode: 0644]
Tools/NetTest_Runner/include/stack.h [new file with mode: 0644]
Tools/NetTest_Runner/include/tcp.h [new file with mode: 0644]
Tools/NetTest_Runner/include/test.h [new file with mode: 0644]
Tools/NetTest_Runner/include/tests.h [new file with mode: 0644]
Tools/NetTest_Runner/ip.c [new file with mode: 0644]
Tools/NetTest_Runner/link.c [new file with mode: 0644]
Tools/NetTest_Runner/main.c [new file with mode: 0644]
Tools/NetTest_Runner/net.c [new file with mode: 0644]
Tools/NetTest_Runner/stack.c [new file with mode: 0644]
Tools/NetTest_Runner/tcp.c [new file with mode: 0644]
Tools/NetTest_Runner/test_arp.c [new file with mode: 0644]
Tools/NetTest_Runner/test_tcp.c [new file with mode: 0644]
Tools/nativelib/Makefile
Tools/nativelib/include/acess.h
Tools/nativelib/include/threads_int.h
Tools/nativelib/logging.c
Tools/nativelib/threads.c
Tools/nativelib/threads_int.c
Tools/nativelib/time.c

index a40bb69..d9d0812 100644 (file)
@@ -55,7 +55,10 @@ Tools/*/obj/
 Tools/*/Makefile.BuildNum
 Tools/disktool
 Tools/nettest
+Tools/nettest_runner
 Tools/img2sif
+Tools/stdout.txt
+Tools/stderr.txt
 
 *.udi
 UDI/drivers/*/bin
index 4473e73..c7118d2 100644 (file)
@@ -18,14 +18,14 @@ K_OBJ += vfs/acls.o vfs/io.o vfs/fs/devfs.o
 # Modules
 MODULES := IPStack
 # Local kernel soruces (same as above, but located in same directory as Makefile)
-L_OBJ = vfs_shim.o nic.o tcpclient.o tcpserver.o helpers.o
+L_OBJ = vfs_shim.o nic.o tcpclient.o tcpserver.o helpers.o mode_cmdline.o
 # Native Sources (compiled as usual)
 N_OBJ = main.o tap.o
 
 # Compilation Options
 CFLAGS := -Wall -std=gnu99 -g -Werror -O0 -pthread
 CPPFLAGS := -I include/ -I ../nativelib/include
-K_CPPFLAGS := -I $(KERNEL_SRC)include -I $(MODULE_SRC)
+K_CPPFLAGS := -I $(KERNEL_SRC)include -I $(MODULE_SRC) -I ../../Usermode/Libraries/ld-acess.so_src/include_exp/
 LDFLAGS += -Wl,--defsym,__buildnum=$(BUILD_NUM) -g -L .. -lpthread -lnativelib
 
 BUILDINFO_OBJ := obj/$(TARGET)/buildinfo.o
index 090f5d4..4705993 100644 (file)
@@ -15,12 +15,14 @@ extern int  NativeNic_AddDev(char *Desc);
 extern int     NetTest_AddAddress(const char *SetAddrString);
 
 extern void    *NetTest_OpenTap(const char *Name);
+extern void    *NetTest_OpenUnix(const char *Name);
 extern size_t  NetTest_WritePacket(void *Handle, size_t Size, const void *Data);
 extern size_t  NetTest_ReadPacket(void *Handle, size_t MaxSize, void *Data);
 
 extern size_t  NetTest_WriteStdout(const void *Data, size_t Size);
 
 extern void    NetTest_Suite_Netcat(const char *Addr, int Port);
+extern void    NetTest_Suite_Cmdline(void);
 
 extern int     Net_ParseAddress(const char *String, void *Addr);
 extern int     Net_OpenSocket_TCPC(int AddrType, void *Addr, int Port);
index 95e70ab..2aba060 100644 (file)
@@ -22,12 +22,16 @@ void PrintUsage(const char *ProgramName)
        fprintf(stderr, "\n");
        fprintf(stderr,
                "Options:\n"
-               "-dev <mac>:<tapdev>\n"
+               "-dev <mac>:<type>:<arg>\n"
                "-ip <dev>,<addr>/<mask>\n"
-               "-route <net>,<mask>,<nexthop>\n"
+               "-route <net>/<mask>,<nexthop>\n"
                "\n"
-               "Suites:\n"
+               "Commands:\n"
                "netcat <addr> <port>\n"
+               "\n"
+               "Device Types:\n"
+               "tun - Linux TUN/TAP device (takes an optional name)\n"
+               "unix - Unix named pipe (datagram)\n"
                );
 }
 
@@ -51,9 +55,10 @@ int main(int argc, char *argv[])
        
        for( int i = 1; i < argc; i ++ )
        {
-               if( argv[i][0] != '-' )
+               char *arg = argv[i];;
+               if( arg[0] != '-' )
                {
-                       if( strcmp(argv[i], "netcat") == 0 )
+                       if( strcmp(arg, "netcat") == 0 )
                        {
                                if( argc-i != 3 ) {
                                        Log_Error("NetTest", "'netcat' <addr> <port>");
@@ -64,34 +69,45 @@ int main(int argc, char *argv[])
                                NetTest_Suite_Netcat(argv[i+1], strtol(argv[i+2], NULL, 0));
                                i += 2;
                        }
+                       else if( strcmp(arg, "cmdline") == 0 )
+                       {
+                               NetTest_Suite_Cmdline();
+                       }
                        else
                        {
-                               Log_Error("NetTest", "Unknown suite name '%s'", argv[i]);
+                               Log_Error("NetTest", "Unknown suite name '%s'", arg);
                                PrintUsage(argv[0]);
                        }
                }
                else
                {
-                       if( strcmp(argv[i], "-dev") == 0 )
+                       if( strcmp(arg, "--help") == 0 )
+                       {
+                               PrintUsage(0);
+                               return 0;
+                       }
+                       else if( strcmp(arg, "-dev") == 0 )
                        {
-                               if( ++i == argc ) { PrintUsage(argv[0]); return 1; }
-                               rv = NativeNic_AddDev(argv[i]);
+                               if( i+1 == argc ) { PrintUsage(argv[0]); return 1; }
+                               rv = NativeNic_AddDev(argv[i+1]);
                                if( rv ) {
-                                       Log_Error("NetTest", "Failed to add device %s", argv[i]);
+                                       Log_Error("NetTest", "Failed to add device %s", argv[i+1]);
                                        return -1;
                                }
+                               i ++;
                        }
-                       else if( strcmp(argv[i], "-ip") == 0 )
+                       else if( strcmp(arg, "-ip") == 0 )
                        {
-                               if( ++i == argc ) { PrintUsage(argv[0]); return 1; }
-                               // TODO: parse argument and poke ipstack
-                               if( NetTest_AddAddress(argv[i]) ) {
+                               if( i+1 == argc ) { PrintUsage(argv[0]); return 1; }
+                               // Parse argument and poke ipstack
+                               if( NetTest_AddAddress(argv[i+1]) ) {
                                        return -1;
                                }
+                               i ++;
                        }
                        else
                        {
-                               Log_Error("NetTest", "Unknown argument '%s'", argv[i]);
+                               Log_Error("NetTest", "Unknown argument '%s'", arg);
                                PrintUsage(argv[0]);
                                return -1;
                        }
diff --git a/Tools/NetTest/mode_cmdline.c b/Tools/NetTest/mode_cmdline.c
new file mode 100644 (file)
index 0000000..5a17517
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ */
+#include <nettest.h>
+#include <stdio.h>
+#include <string.h>
+
+// === CODE ===
+void NetTest_Suite_Cmdline(void)
+{
+       char line[BUFSIZ];
+       while( fgets(line, sizeof(line)-1, stdin) )
+       {
+               const char *cmd = strtok(line, " ");
+               if(!cmd)
+                       continue;
+               if( strcmp(cmd, "exit") == 0 ) {
+                       return ;
+               }
+               else if( strcmp(cmd, "request") == 0 ) {
+                       //const char *addr = strtok(NULL, " ");
+                       
+               }
+               else {
+                       fprintf(stderr, "ERROR: Unknown command '%s'\n", cmd);
+               }
+       }
+}
index 4effc00..b8429fa 100644 (file)
@@ -20,8 +20,8 @@ tIPStackBuffer        *NativeNic_WaitForPacket(void *Ptr);
 // === GLOBALS ===
 tIPStack_AdapterType   gNativeNIC_AdapterType = {
        .Name = "NativeNIC",
-       .Type = 0,      // TODO: Differentiate differnet wire protos and speeds
-       .Flags = 0,     // TODO: IP checksum offloading, MAC checksum offloading etc
+       .Type = 0,
+       .Flags = 0,
        .SendPacket = NativeNic_SendPacket,
        .WaitForPacket = NativeNic_WaitForPacket
        };
@@ -30,12 +30,30 @@ tIPStack_AdapterType        gNativeNIC_AdapterType = {
 int NativeNic_AddDev(char *DevDesc)
 {
        Uint8   macaddr[6];
+       // Parse descriptor into mac address and path
+       // 123456789ABC:tun:ifname
+       // 123456789ABC:unix:/path
+       // 123456789ABC:file:/path
+       // 123456789ABC:tcp:host_desc
        char *colonpos = strchr(DevDesc, ':');
        if( !colonpos )
                return -1;
        if( UnHex(macaddr, 6, DevDesc) != 6 )
                return -1;
-       void *ptr = NetTest_OpenTap(colonpos+1);
+       
+       char *class = colonpos + 1;
+       colonpos = strchr(class, ':');
+       void *ptr;
+       if( strncmp(class, "tun:", 4) == 0 ) {
+               ptr = NetTest_OpenTap(colonpos+1);
+       }
+       else if( strncmp(class, "unix:", 5) == 0 ) {
+               ptr = NetTest_OpenUnix(colonpos+1);
+       }
+       else {
+               Log_Warning("NIC", "Unknown opener '%.*s'", colonpos-class, class);
+               ptr = NULL;
+       }
        if( !ptr )
                return 1;
        IPStack_Adapter_Add(&gNativeNIC_AdapterType, ptr, macaddr);
@@ -57,6 +75,9 @@ tIPStackBuffer *NativeNic_WaitForPacket(void *Ptr)
 
        tIPStackBuffer  *ret = IPStack_Buffer_CreateBuffer(1);
        IPStack_Buffer_AppendSubBuffer(ret, len, 0, buf, NativeNic_int_FreePacket, Ptr);
+       
+       Debug_HexDump("NativeNic: RX", buf, len);
+       
        return ret;
 }
 
@@ -71,6 +92,8 @@ int NativeNic_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
        // Serialise into stack
        char    buf[len];
        IPStack_Buffer_GetData(Buffer, buf, len);
+
+       Debug_HexDump("NativeNic: TX", buf, len);
        
        NetTest_WritePacket(Ptr, len, buf);
        return 0;
index ebacf16..1531619 100644 (file)
@@ -14,6 +14,8 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 
 // === CODE ===
 void *NetTest_OpenTap(const char *Name)
@@ -49,9 +51,39 @@ void *NetTest_OpenTap(const char *Name)
        return (void*)(intptr_t)fd;
 }
 
+void *NetTest_OpenUnix(const char *Path)
+{
+       int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+       struct sockaddr_un      sa = {AF_UNIX, ""};
+       struct sockaddr_un      sa_local = {AF_UNIX, ""};
+       strcpy(sa.sun_path, Path);
+       if( connect(fd, (struct sockaddr*)&sa, sizeof(sa)) ) {
+               perror("NetTest_OpenUnix - connect");
+               close(fd);
+               return NULL;
+       }
+       if( bind(fd, (struct sockaddr*)&sa_local, sizeof(sa)) ) {
+               perror("NetTest_OpenUnix - bind");
+               close(fd);
+               return NULL;
+       }
+       
+       {
+               char somenulls[] = { 0,0,0,0,0,0, 0,0,0,0,0, 0,0};
+               write(fd, somenulls, sizeof(somenulls));
+       }
+       
+       return (void*)(intptr_t)fd;
+}
+
 size_t NetTest_WritePacket(void *Handle, size_t Size, const void *Data)
 {
-       return write( (intptr_t)Handle, Data, Size);
+       int ret = write( (intptr_t)Handle, Data, Size);
+       if( ret < 0 ) {
+               perror("NetTest_WritePacket - write");
+               return 0;
+       }
+       return ret;
 }
 
 size_t NetTest_ReadPacket(void *Handle, size_t MaxSize, void *Data)
index 97ac4db..6d42064 100644 (file)
 #include <events.h>
 
 // === CODE ===
-int VFS_SelectNode(tVFS_Node *Node, int Type, tTime *Timeout, const char *Name)
-{
-       tThread *us = Proc_GetCurThread();
-
-        int    ret = 0;
-
-       Threads_ClearEvent(THREAD_EVENT_VFS);
-
-       if( Type & VFS_SELECT_READ ) {
-               Node->ReadThreads = (void*)us;
-               if(Node->DataAvaliable) ret |= VFS_SELECT_READ;
-       }
-       if( Type & VFS_SELECT_WRITE ) {
-               Node->WriteThreads = (void*)us;
-               if(!Node->BufferFull)   ret |= VFS_SELECT_WRITE;
-       }
-       if( Type & VFS_SELECT_ERROR ) {
-               Node->ErrorThreads = (void*)us;
-               if(Node->ErrorOccurred) ret |= VFS_SELECT_ERROR;
-       }
-       
-       if( !ret )
-       {
-               // TODO: Timeout
-               Threads_WaitEvents(THREAD_EVENT_VFS);
-       }
-
-       if( Type & VFS_SELECT_READ ) {
-               Node->ReadThreads = NULL;
-               if(Node->DataAvaliable) ret |= VFS_SELECT_READ;
-       }
-       if( Type & VFS_SELECT_WRITE ) {
-               Node->WriteThreads = NULL;
-               if(!Node->BufferFull)   ret |= VFS_SELECT_WRITE;
-       }
-       if( Type & VFS_SELECT_ERROR ) {
-               Node->ErrorThreads = NULL;
-               if(Node->ErrorOccurred) ret |= VFS_SELECT_ERROR;
-       }
-       return ret;
-}
-
-int VFS_MarkAvaliable(tVFS_Node *Node, BOOL bAvail)
-{
-       Node->DataAvaliable = bAvail;
-       if( Node->DataAvaliable && Node->ReadThreads )
-               Threads_PostEvent( (void*)Node->ReadThreads, THREAD_EVENT_VFS );
-       return 0;
-}
-
-int VFS_MarkError(tVFS_Node *Node, BOOL bError)
-{
-       Node->ErrorOccurred = bError;
-       if( Node->ErrorOccurred && Node->ErrorThreads )
-               Threads_PostEvent( (void*)Node->ErrorThreads, THREAD_EVENT_VFS );
-       return 0;
-}
-
-int VFS_MarkFull(tVFS_Node *Node, BOOL bError)
-{
-       Node->BufferFull = bError;
-       if( !Node->BufferFull && Node->WriteThreads )
-               Threads_PostEvent( (void*)Node->WriteThreads, THREAD_EVENT_VFS );
-       return 0;
-}
-
-
-#if 0
-int VFS_Open(const char *Path, Uint Flags)
-{
-       return -1;
-}
-
-void VFS_Close(int FD)
-{
-}
-#endif
-
 int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
 {
        const int maxfd = *Threads_GetMaxFD();
@@ -122,3 +44,18 @@ tVFS_Handle *VFS_GetHandle(int FD)
 
        return &handles[FD];
 }
+
+int VFS_SetHandle(int FD, tVFS_Node *Node, int Mode)
+{
+       const int maxfd = *Threads_GetMaxFD();
+       tVFS_Handle     *handles = *Threads_GetHandlesPtr();
+       if( !handles )
+               return -1;
+
+       if( FD < 0 || FD >= maxfd )
+               return -1;
+
+       handles[FD].Node = Node;
+       handles[FD].Mode = Mode;
+       return FD;
+}
diff --git a/Tools/NetTest_Runner/Makefile b/Tools/NetTest_Runner/Makefile
new file mode 100644 (file)
index 0000000..e957579
--- /dev/null
@@ -0,0 +1,32 @@
+
+OBJ := main.o net.o stack.o
+OBJ += tcp.o
+OBJ += ip.o arp.o
+OBJ += link.o
+OBJ += test_arp.o test_tcp.o
+BIN := ../nettest_runner
+
+CFLAGS := -Wall -std=c99
+CPPFLAGS := -Iinclude
+LIBS := 
+
+OBJ := $(OBJ:%=obj/%)
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+       $(RM) $(OBJ) $(BIN)
+
+$(BIN): $(OBJ)
+       @echo [CC] -o $@
+       @$(CC) $(LINKFLAGS) -o $@ $(OBJ) $(LIBS)
+
+obj/%.o: %.c
+       @mkdir -p $(dir $@)
+       @echo [CC] -c -o $@
+       @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< -MMD -MP
+
+-include $(OBJ:%.o=%.d)
+
diff --git a/Tools/NetTest_Runner/arp.c b/Tools/NetTest_Runner/arp.c
new file mode 100644 (file)
index 0000000..308f83e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ */
+#include "arp.h"
+#include "net.h"
+#include <stdint.h>
+#include <string.h>
+#include "test.h"
+#include "tests.h"
+
+// === CODE ===
+void ARP_SendRequest(int IfNum, const void *IPv4Addr)
+{
+       const uint8_t   *addr = IPv4Addr;
+       uint8_t pkt[] = {
+               // Ethernet
+               0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+               HOST_MAC,
+               0x08,0x06,
+               // ARP
+               0x00,0x01, 0x08,0x00,
+               6,4, 0,1,
+               HOST_MAC,
+               HOST_IP,
+               0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+               addr[0],addr[1],addr[2],addr[3],
+       };
+       Net_Send(IfNum, sizeof(pkt), pkt);
+}
+
+void ARP_SendResponse(int IfNum, const void *IPv4Addr, const void *MacAddr)
+{
+       
+}
+
+bool ARP_Pkt_IsResponse(size_t Len, const void *Packet, const void *ExpectedIP, const void *ExpectedMac)
+{
+       const uint8_t   *pkt8 = Packet;
+       if( Len < 2*6+2 ) {
+               TEST_WARN("Undersized");
+               return false;
+       }
+       // Ethernet ARP id
+       if( pkt8[12+0] != 0x08 || pkt8[12+1] != 0x06 ) {
+               TEST_WARN("Ethernet tag %02x %02x != 08 06", pkt8[12+0], pkt8[12+1]);
+               return false;
+       }
+       
+       // ARP HWtype/ProtoType
+       if( pkt8[14+0] != 0x00 || pkt8[14+1] != 0x01 || pkt8[14+2] != 0x08 || pkt8[14+3] != 0x00 ) {
+               TEST_WARN("ARP Types %02x %02x %02x %02x != 00 01 08 00",
+                       pkt8[14+0], pkt8[14+1], pkt8[14+2], pkt8[14+3]);
+               return false;
+       }
+       // ARP Sizes (HW/Proto) and operation (Response)
+       if( pkt8[14+4] != 6 || pkt8[14+5] != 4 || pkt8[14+6] != 0 || pkt8[14+7] != 2 ) {
+               TEST_WARN("Sizes+op %02x %02x %02x %02x != 06 04 00 02",
+                       pkt8[14+4], pkt8[14+5], pkt8[14+6], pkt8[14+7]);
+               return false;
+       }
+       
+       if( memcmp(pkt8+14+8, ExpectedMac, 6) != 0 )
+               return false;
+       if( memcmp(pkt8+14+14, ExpectedIP, 4) != 0 )
+               return false;
+       if( memcmp(pkt8+14+18, (char[]){HOST_MAC}, 6) != 0 )
+               return false;
+       if( memcmp(pkt8+14+24, (char[]){HOST_IP}, 4) != 0 )
+               return false;
+       
+       return true;
+}
+
+bool ARP_Pkt_IsRequest(size_t Len, const void *Packet, const void *ExpectedIP)
+{
+       return false;
+}
+
diff --git a/Tools/NetTest_Runner/include/arp.h b/Tools/NetTest_Runner/include/arp.h
new file mode 100644 (file)
index 0000000..e9a9bea
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ */
+#ifndef _ARP_H_
+#define _ARP_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+
+
+extern void ARP_SendRequest(int IfNum, const void *IPv4Addr);
+extern void ARP_SendResponse(int IfNum, const void *IPv4Addr, const void *MacAddr);
+extern bool ARP_Pkt_IsResponse(size_t Len, const void *Packet, const void *ExpectedIP, const void *ExpectedMac);
+extern bool ARP_Pkt_IsRequest(size_t Len, const void *Packet, const void *ExpectedIP);
+
+#endif
+
diff --git a/Tools/NetTest_Runner/include/common.h b/Tools/NetTest_Runner/include/common.h
new file mode 100644 (file)
index 0000000..6c10265
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <stdint.h>
+
+#define HOST_IP_STR    "10.1.1.2"
+#define HOST_IP        0x0A,0x01,0x01,0x02
+#define HOST_MAC       0x54,0x56,0x00,0x12,0x34,0x11
+
+#define TEST_IP        0x0A,0x01,0x01,0x01
+#define TEST_MAC       0x54,0x56,0x00,0x12,0x34,0x56
+
+#define BLOB(bytes)    (const char[]){bytes}
+
+#if BIG_ENDIAN
+# define htons(x)      ((uint16_t)(x))
+# define htonl(x)      ((uint32_t)(x))
+#else
+static inline uint16_t htons(uint16_t x) {
+       return (x >> 8) | (x << 8);
+}
+static inline uint32_t htonl(uint32_t x) {
+       return ((x >> 24) & 0xFF) <<  0
+             |((x >> 16) & 0xFF) <<  8
+             |((x >>  8) & 0xFF) << 16
+             |((x >>  0) & 0xFF) << 24;
+}
+#endif
+#define ntohs(x)       htons(x)
+#define ntohl(x)       htonl(x)
+
+
+#endif
+
diff --git a/Tools/NetTest_Runner/include/ip.h b/Tools/NetTest_Runner/include/ip.h
new file mode 100644 (file)
index 0000000..6f0eb15
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * ip.h
+ * - IP-layer Test Wrapper (v5/v6)
+ */
+#ifndef _IP_H_
+#define _IP_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#define IPPROTO_TCP    6
+
+#define IP_CHECKSUM_START      0xFFFF
+
+extern uint16_t        IP_Checksum(uint16_t Prev, size_t Length, const void *Data);
+
+extern void    IP_Send(int IfNum, int AF, const void *Src, const void *Dst, uint8_t proto,
+       int BufCount, size_t BufLens[], const void *Bufs[]);
+
+extern bool    IP_Pkt_Check(size_t len, const void *data, size_t *ofs, int AF, const void *Src, const void *Dst, uint8_t proto);
+
+#endif
+
diff --git a/Tools/NetTest_Runner/include/link.h b/Tools/NetTest_Runner/include/link.h
new file mode 100644 (file)
index 0000000..28efc50
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ */
+#ifndef _LINK_H_
+#define _LINK_H_
+
+#define ETHER_PROTO_IPV4       0x0800
+
+#include <stdint.h>
+#include <stdbool.h>
+
+extern void    Link_Send(int IfNum, const void *Src, const void *Dst, uint16_t Proto, int BufCount, size_t BufLens[], const void *Bufs[]);
+
+extern bool    Link_Pkt_Check(size_t len, const void *data, size_t *ofs, const void *Src, const void *Dst, uint16_t Proto);
+
+#endif
+
diff --git a/Tools/NetTest_Runner/include/net.h b/Tools/NetTest_Runner/include/net.h
new file mode 100644 (file)
index 0000000..e30ef93
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * net.h
+ * - Network interface IO
+ */
+#ifndef _NET_H_
+#define _NET_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#define MTU    1520
+
+extern int     Net_Open(int IfNum, const char *Path);
+extern void    Net_Close(int IfNum);
+
+
+extern size_t  Net_Receive(int IfNum, size_t MaxLen, void *DestBuf, unsigned int Timeout);
+extern void    Net_Send(int IfNum, size_t Length, const void *Buf);
+
+#endif
+
diff --git a/Tools/NetTest_Runner/include/stack.h b/Tools/NetTest_Runner/include/stack.h
new file mode 100644 (file)
index 0000000..40c92d6
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * stack.h
+ * - Functions for interacting with the IPStack program
+ */
+#ifndef _STACK_H_
+#define _STACK_H_
+
+#include <stdint.h>
+
+extern void    Stack_AddDevice(const char *Ident, const void *MacAddr);
+extern void    Stack_AddInterface(const char *Name, int AddrType, const void *Addr, int MaskBits);
+extern void    Stack_AddRoute(int Type, const void *Network, int MaskBits, const void *NextHop);
+
+extern void    Stack_AddArg(const char *Fmt, ...);
+extern int     Stack_Start(const char *Subcommand);
+extern void    Stack_Kill(void);
+
+extern int     Stack_SendCommand(const char *CommandString);
+
+#endif
+
diff --git a/Tools/NetTest_Runner/include/tcp.h b/Tools/NetTest_Runner/include/tcp.h
new file mode 100644 (file)
index 0000000..a96d921
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * tcp.h
+ * - TCP Test Wrapper
+ */
+#ifndef _TCP_H_
+#define _TCP_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#define TCP_FIN        0x01
+#define TCP_SYN        0x02
+#define TCP_RST        0x04
+
+extern void    TCP_Send(int IF, int AF, const void *IP, short sport, short dport, uint32_t seq, uint32_t ack, uint8_t flags, uint16_t window, size_t data_len, const void *data);
+extern bool    TCP_Pkt_Check(size_t len, const void *data, size_t *ofs, int AF, const void *IP, short sport, short dport, uint8_t flags);
+
+#endif
+
diff --git a/Tools/NetTest_Runner/include/test.h b/Tools/NetTest_Runner/include/test.h
new file mode 100644 (file)
index 0000000..7a32586
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ */
+#ifndef _TEST_H_
+#define _TEST_H_
+
+#define TEST_SETNAME(name)     test_setname(name)
+#define TEST_ASSERT(cnd)       do{if(!(cnd)) {test_assertion_fail(__FILE__,__LINE__,"%s",#cnd);return false;}}while(0)
+#define TEST_ASSERT_REL(a,r,b) do{long long a_val=(a),b_val=(b);if(!(a_val r b_val)) {test_assertion_fail(__FILE__,__LINE__,"%s(0x%llx)%s%s(%llx)",#a,a_val,#r,#b,b_val);return false;}}while(0)
+#define TEST_WARN(msg...)      test_message(__FILE__,__LINE__,msg)
+
+extern void    test_setname(const char *name);
+extern void    test_message(const char *filename, int line, const char *msg, ...);
+extern void    test_assertion_fail(const char *filename, int line, const char *test, ...);
+
+#endif
+
diff --git a/Tools/NetTest_Runner/include/tests.h b/Tools/NetTest_Runner/include/tests.h
new file mode 100644 (file)
index 0000000..bb16722
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * tests.h
+ * - List of tests used by main.c
+ */
+#ifndef _TESTS_H_
+#define _TESTS_H_
+
+#include "common.h"
+#include <stdbool.h>
+
+extern bool    Test_ARP_Basic(void);
+extern bool    Test_TCP_Basic(void);
+
+#endif
+
diff --git a/Tools/NetTest_Runner/ip.c b/Tools/NetTest_Runner/ip.c
new file mode 100644 (file)
index 0000000..bebcf73
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ */
+#include "common.h"
+#include "ip.h"
+#include "link.h"
+#include <assert.h>
+#include <string.h>
+#include "test.h"
+
+// === STRUCTURES ===
+typedef struct {
+       uint8_t         VerLen;
+       uint8_t         DiffServices;
+       uint16_t        TotalLength;
+       uint16_t        Identifcation;
+       uint16_t        FragmentInfo;   // rsvd:dont:more:[13]offset/8
+       uint8_t         TTL;
+       uint8_t         Protocol;
+       uint16_t        HeaderChecksum;
+       uint8_t         SrcAddr[4];
+       uint8_t         DstAddr[4];
+       uint8_t         Options[];
+} __attribute__((packed)) tIPv4Hdr;
+
+// === CODE ===
+uint16_t IP_Checksum(uint16_t Prev, size_t Length, const void *Data)
+{
+       const uint16_t  *words = Data;
+       uint32_t        ret = ~Prev;
+       for( int i = 0; i < Length/2; i ++ )
+       {
+               ret += ntohs(*words);
+               words ++;
+       }
+       if( Length & 1 )
+               ret += ntohs(*(uint8_t*)words);
+       
+       while( ret >> 16 )
+               ret = (ret & 0xFFFF) + (ret >> 16);
+       
+       return ~ret;
+}
+
+void IP_Send(int IfNum, int AF, const void *Src, const void *Dst, uint8_t proto,
+       int BufCount, size_t BufLens[], const void *Bufs[])
+{
+       size_t  total_length = 0;
+
+       size_t  out_buflens[BufCount+1];
+       const void *out_bufs[BufCount+1];
+       
+       for( int i = 0; i < BufCount; i ++ )
+       {
+               total_length += BufLens[i];
+               out_buflens[1+i] = BufLens[i];
+               out_bufs[1+i] = Bufs[i];
+       }
+
+       if( AF == 4 )
+       {
+               tIPv4Hdr        hdr;
+               hdr.VerLen = (4 << 4) | (sizeof(hdr)/4);
+               hdr.DiffServices = 0;
+               hdr.TotalLength = htons(sizeof(hdr) + total_length);
+               hdr.Identifcation = 0;  // TODO: WTF is this?
+               hdr.FragmentInfo = htons(0);
+               hdr.TTL = 18;   // TODO: Progammable TTL
+               hdr.Protocol = proto;
+               hdr.HeaderChecksum = 0;
+               memcpy(hdr.SrcAddr, Src, 4);
+               memcpy(hdr.DstAddr, Dst, 4);
+               
+               hdr.HeaderChecksum = htons( IP_Checksum(IP_CHECKSUM_START, sizeof(hdr), &hdr) );
+               
+               out_buflens[0] = sizeof(hdr);
+               out_bufs[0] = &hdr;
+               
+               // TODO: Don't hard-code MAC addresses
+               Link_Send(IfNum, BLOB(HOST_MAC), BLOB(TEST_MAC), ETHER_PROTO_IPV4,
+                       1+BufCount, out_buflens, out_bufs);
+       }
+       else {
+               TEST_WARN("Invalid AF(%i) in IP_Send", AF);
+       }
+}
+
+bool IP_Pkt_Check(size_t len, const void *data, size_t *ofs_out, int AF, const void *Src, const void *Dst, uint8_t proto)
+{
+       size_t  ofs;
+       if( AF == 4 ) {
+               if( !Link_Pkt_Check(len, data, &ofs, BLOB(TEST_MAC), BLOB(HOST_MAC), ETHER_PROTO_IPV4) )
+                       return false;
+       
+               tIPv4Hdr hdr;
+               memcpy(&hdr, (const uint8_t*)data + ofs, sizeof(hdr));
+               TEST_ASSERT_REL(hdr.VerLen >> 4, ==, 4);
+       
+               return false;
+       }
+       else {
+               TEST_WARN("Invalid AF(%i) in IP_Pkt_Check", AF);
+               return false;
+       }
+}
+
diff --git a/Tools/NetTest_Runner/link.c b/Tools/NetTest_Runner/link.c
new file mode 100644 (file)
index 0000000..53dfde5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ */
+#include "common.h"
+#include "net.h"
+#include "link.h"
+#include "test.h"
+#include <stdlib.h>
+#include <string.h>
+
+// === CODE ===
+void Link_Send(int IfNum, const void *Src, const void *Dst, uint16_t Proto,
+       int BufCount, size_t BufLens[], const void *Bufs[])
+{
+       size_t  total_len = 6+6+2;
+       for( int i = 0; i < BufCount; i ++ )
+               total_len += BufLens[i];
+       uint8_t *data = malloc(total_len);
+       
+       uint8_t *pos = data;
+       memcpy(pos, Dst, 6);    pos += 6;
+       memcpy(pos, Src, 6);    pos += 6;
+       *(uint16_t*)pos = htons(Proto); pos += 2;
+       
+       for( int i = 0; i < BufCount; i ++ )
+       {
+               memcpy(pos, Bufs[i], BufLens[i]);
+               pos += BufLens[i];
+       }
+       
+       Net_Send(IfNum, total_len, data);
+       
+       free(data);
+}
+
+bool Link_Pkt_Check(size_t len, const void *data, size_t *ofs_out,
+       const void *Src, const void *Dst, uint16_t Proto)
+{
+       const uint8_t   *data8 = data;
+       TEST_ASSERT_REL(len, >=, 6+6+2);
+
+       if(Src) TEST_ASSERT( memcmp(data8+0, Src, 6) == 0 );
+       if(Dst) TEST_ASSERT( memcmp(data8+6, Dst, 6) == 0 );
+       
+       TEST_ASSERT_REL( ntohs(*(uint16_t*)(data8+12)), ==, Proto );
+
+       *ofs_out = 6+6+2;
+       return true;
+}
+
diff --git a/Tools/NetTest_Runner/main.c b/Tools/NetTest_Runner/main.c
new file mode 100644 (file)
index 0000000..83ab653
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "net.h"
+#include "stack.h"
+#include "tests.h"
+#include "test.h"
+#include <stdarg.h>
+#include <unistd.h>
+
+// === PROTOTYPES ===
+ int   ParseCommandline(int argc, char *argv[]);
+
+// === GLOBALS ===
+const char *gsTestName;
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+       if( ParseCommandline(argc, argv) )
+               return 1;
+
+       typedef bool t_test(void);
+       t_test  *tests[] = {
+               Test_ARP_Basic,
+               Test_TCP_Basic,
+               NULL
+               };
+
+       // TODO: Move to stack.c
+       FILE    *fp;
+       fp = fopen("stdout.txt", "w");  fclose(fp);
+       fp = fopen("stderr.txt", "w");  fclose(fp);
+
+       for(int i = 0; tests[i]; i ++ )
+       {
+               Net_Open(0, "/tmp/acess2net");
+               
+               Stack_AddDevice("/tmp/acess2net", (char[]){TEST_MAC});
+               Stack_AddInterface("eth0", 4, (const char[]){TEST_IP}, 24);
+               Stack_AddRoute(4, "\0\0\0\0", 0, (const char[]){HOST_IP});
+               if( Stack_Start("cmdline") )
+                       goto teardown;
+               
+               if( Net_Receive(0, 1, &argc, 1000) == 0 )
+                       goto teardown;
+               
+               if( tests[i]() )
+                       printf("%s: PASS\n", gsTestName);
+               else
+                       printf("%s: FAIL\n", gsTestName);
+       
+       teardown:
+               Stack_Kill();
+               Net_Close(0);
+               unlink("/tmp/acess2net");
+       }
+
+       return 0;
+}
+
+void PrintUsage(const char *ProgName)
+{
+       fprintf(stderr, "Usage: %s\n", ProgName);
+}
+
+int ParseCommandline(int argc, char *argv[])
+{
+       const char      *progname = argv[0];
+       for( int i = 1; i < argc; i ++ )
+       {
+               const char      *arg = argv[i];
+               if( arg[0] != '-' ) {
+                       // bare args
+               }
+               else if( arg[1] != '-' ) {
+                       // short args
+               }
+               else {
+                       // long args
+                       if( strcmp(arg, "--help") == 0 ) {
+                               PrintUsage(progname);
+                               exit(0);
+                       }
+                       else {
+                               fprintf(stderr, "Unknown option: %s\n", arg);
+                               PrintUsage(progname);
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+void test_setname(const char *name)
+{
+       gsTestName = name;
+}
+
+void test_message(const char *filename, int line, const char *msg, ...)
+{
+       fprintf(stderr, "%s:%i [%s] - ", filename, line, gsTestName);
+       va_list args;
+       va_start(args, msg);
+       vfprintf(stderr, msg, args);
+       va_end(args);
+       fprintf(stderr, "\n");
+}
+
+void test_assertion_fail(const char *filename, int line, const char *fmt, ...)
+{
+       fprintf(stderr, "%s:%i [%s] - ASSERT FAIL ", filename, line, gsTestName);
+       va_list args;
+       va_start(args, fmt);
+       vfprintf(stderr, fmt, args);
+       va_end(args);
+       fprintf(stderr, "\n");
+}
+
diff --git a/Tools/NetTest_Runner/net.c b/Tools/NetTest_Runner/net.c
new file mode 100644 (file)
index 0000000..05c4ca4
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ */
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/select.h>
+#include "net.h"
+
+
+#define CONNECT_TIMEOUT        10*1000
+#define MAX_IFS        4
+
+typedef struct {
+       int     FD;
+       socklen_t       addrlen;
+       struct sockaddr_un      addr;
+} tIf;
+
+// === PROTOTYPES ===
+ int   Net_int_Open(const char *Path);
+
+// === GLOBALS ===
+tIf    gaInterfaces[MAX_IFS];
+
+// === CODE ===
+int Net_Open(int IfNum, const char *Path)
+{
+       if( IfNum >= MAX_IFS )
+               return 1;
+       
+       if(gaInterfaces[IfNum].FD != 0) return 1;
+       gaInterfaces[IfNum].addrlen = sizeof(gaInterfaces[IfNum].addr);
+       gaInterfaces[IfNum].FD = Net_int_Open(Path);
+       return 0;
+}
+
+int Net_int_Open(const char *Path)
+{
+       int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+       struct sockaddr_un      sa = {AF_UNIX, ""};
+       strcpy(sa.sun_path, Path);
+       unlink(Path);
+       if( bind(fd, (struct sockaddr*)&sa, sizeof(sa)) ) {
+               perror("NetTest_OpenUnix - bind");
+               close(fd);
+               return -1;
+       }
+       
+       return fd;
+}
+
+void Net_Close(int IfNum)
+{
+       assert(IfNum < MAX_IFS);
+       close(gaInterfaces[IfNum].FD);
+       gaInterfaces[IfNum].FD = 0;
+}
+
+bool WaitOnFD(int FD, bool Write, unsigned int Timeout)
+{
+       fd_set  fds;
+       FD_ZERO(&fds);
+       FD_SET(FD, &fds);
+       struct timeval  timeout;
+       timeout.tv_sec = Timeout/1000;
+       timeout.tv_usec = (Timeout%1000) * 1000;
+       
+       if( Write )
+               select(FD+1, NULL, &fds, NULL, &timeout);
+       else
+               select(FD+1, &fds, NULL, NULL, &timeout);
+       return FD_ISSET(FD, &fds);
+}
+
+bool Net_int_EnsureConnected(int IfNum)
+{
+       assert(IfNum < MAX_IFS);
+       #if 0
+       if( gaInterface_Clients[IfNum] == 0 )
+       {
+               //if( !WaitOnFD(gaInterface_Servers[IfNum], CONNECT_TIMEOUT) )
+               //{
+               //      fprintf(stderr, "ERROR: Client has not connected");
+               //      return false;
+               //}
+               gaInterface_Clients[IfNum] = accept(gaInterface_Servers[IfNum], NULL, NULL);
+               if( gaInterface_Clients[IfNum] < 0 ) {
+                       perror("Net_int_EnsureConnected - accept");
+                       return false;
+               }
+       }
+       #endif
+       return true;
+}
+
+size_t Net_Receive(int IfNum, size_t MaxLen, void *DestBuf, unsigned int Timeout)
+{
+       assert(IfNum < MAX_IFS);
+       tIf     *If = &gaInterfaces[IfNum];
+       
+       if( Net_int_EnsureConnected(IfNum) && WaitOnFD(If->FD, false, Timeout) )
+       {
+               return recvfrom(If->FD, DestBuf, MaxLen, 0, &If->addr, &If->addrlen);
+       }
+       return 0;
+}
+
+void Net_Send(int IfNum, size_t Length, const void *Buf)
+{
+       assert(IfNum < MAX_IFS);
+       tIf     *If = &gaInterfaces[IfNum];
+       
+       if( !WaitOnFD(If->FD, true, CONNECT_TIMEOUT) )
+               return ;
+       int rv = sendto(If->FD, Buf, Length, 0, &If->addr, If->addrlen);
+       if( rv < 0 )
+               perror("Net_Send - send");
+}
+
+
diff --git a/Tools/NetTest_Runner/stack.c b/Tools/NetTest_Runner/stack.c
new file mode 100644 (file)
index 0000000..c359d84
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ */
+#define _POSIX_C_SOURCE 200809L
+#include "stack.h"
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include <fcntl.h>
+#include <spawn.h>
+
+#define MAX_ARGS       16
+
+extern char **environ;
+
+// === GLOBALS ===
+pid_t  giStack_PID;
+ int   giStack_InFD = -1;
+ int   giNumStackArgs = 1;
+char   *gasStackArgs[MAX_ARGS] = {"nettest",NULL};
+
+// === CODE ===
+void Stack_AddDevice(const char *Ident, const void *MacAddr)
+{
+       Stack_AddArg("-dev");
+       Stack_AddArg("%02x%02x%02x%02x%02x%02x:unix:%s",
+               ((uint8_t*)MacAddr)[0],
+               ((uint8_t*)MacAddr)[1],
+               ((uint8_t*)MacAddr)[2],
+               ((uint8_t*)MacAddr)[3],
+               ((uint8_t*)MacAddr)[4],
+               ((uint8_t*)MacAddr)[5],
+               Ident);
+}
+
+void Stack_AddInterface(const char *Name, int AddrType, const void *Addr, int MaskBits)
+{
+       Stack_AddArg("-ip");
+       switch(AddrType)
+       {
+       case 4:
+               Stack_AddArg("%s,%i.%i.%i.%i/%i", Name,
+                       ((uint8_t*)Addr)[0],
+                       ((uint8_t*)Addr)[1],
+                       ((uint8_t*)Addr)[2],
+                       ((uint8_t*)Addr)[3],
+                       MaskBits
+                       );
+               break;
+       default:
+               assert(AddrType == 4);
+               exit(1);
+       }
+}
+
+void Stack_AddRoute(int Type, const void *Network, int MaskBits, const void *NextHop)
+{
+}
+
+void Stack_AddArg(const char *Fmt, ...)
+{
+       va_list args;
+       va_start(args, Fmt);
+       size_t len = vsnprintf(NULL, 0, Fmt, args);
+       va_end(args);
+       char *arg = malloc(len+1);
+       va_start(args, Fmt);
+       vsnprintf(arg, len+1, Fmt, args);
+       va_end(args);
+       gasStackArgs[giNumStackArgs++] = arg;
+}
+
+void sigchld_handler(int signum)
+{
+        int status;
+       wait(&status);
+       fprintf(stderr, "FAILURE: Child exited (%i)\n", status);
+}
+
+int Stack_Start(const char *Subcommand)
+{
+       Stack_AddArg(Subcommand);
+       
+       for( int i = 3; i < 16; i ++ )
+               fcntl(i, F_SETFD, FD_CLOEXEC);
+
+       //signal(SIGCHLD, sigchld_handler);
+
+        int    fds_in[2];
+       pipe(fds_in);
+       giStack_InFD = fds_in[1];
+       fcntl(giStack_InFD, F_SETFD, FD_CLOEXEC);
+
+       FILE    *fp;
+       fp = fopen("stdout.txt", "a"); fprintf(fp, "--- Startup\n"); fclose(fp);
+       fp = fopen("stderr.txt", "a"); fprintf(fp, "--- Startup\n"); fclose(fp);
+
+       posix_spawn_file_actions_t      fa;
+       posix_spawn_file_actions_init(&fa);
+       posix_spawn_file_actions_adddup2(&fa, fds_in[0], 0);
+       posix_spawn_file_actions_addopen(&fa, 1, "stdout.txt", O_CREAT|O_APPEND|O_WRONLY, 0644);
+       posix_spawn_file_actions_addopen(&fa, 2, "stderr.txt", O_CREAT|O_APPEND|O_WRONLY, 0644);
+
+       int rv = posix_spawn(&giStack_PID, "./nettest", &fa, NULL, gasStackArgs, environ);
+       if(rv) {
+               giStack_PID = 0;
+               fprintf(stderr, "posix_spawn failed: %s", strerror(rv));
+               return 1;
+       }
+
+       return 0;
+}
+void Stack_Kill(void)
+{
+       if( giStack_PID )
+       {
+               kill(giStack_PID, SIGTERM);
+               giStack_PID = 0;
+       }
+}
+
+int Stack_SendCommand(const char *CommandString)
+{
+       write(giStack_InFD, CommandString, strlen(CommandString));
+       write(giStack_InFD, "\n", 1);
+       return 0;
+}
+
diff --git a/Tools/NetTest_Runner/tcp.c b/Tools/NetTest_Runner/tcp.c
new file mode 100644 (file)
index 0000000..56c5571
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ */
+#include "common.h"
+#include "tcp.h"
+#include "ip.h"
+#include "test.h"      // TEST_ASSERT
+#include <string.h>
+
+typedef struct {
+       uint16_t        SPort;
+       uint16_t        DPort;
+       uint32_t        Seq;
+       uint32_t        Ack;
+       uint8_t         DataOfs;
+       uint8_t         Flags;
+       uint16_t        Window;
+       uint16_t        Checksum;
+       uint16_t        UrgPtr;
+} __attribute__((packed)) tTCPHeader;
+
+// === CODE ===
+void TCP_Send(int IF, int AF, const void *IP, short sport, short dport,
+       uint32_t seq, uint32_t ack, uint8_t flags, uint16_t window,
+       size_t data_len, const void *data
+       )
+{
+       tTCPHeader      hdr;
+       hdr.SPort = htons(sport);
+       hdr.DPort = htons(dport);
+       hdr.Seq = htonl(seq);
+       hdr.Ack = htonl(ack);
+       hdr.DataOfs = sizeof(hdr)/4;
+       hdr.Flags = flags;
+       hdr.Window = htons(window);
+       hdr.Checksum = htons(0);
+       hdr.UrgPtr = htons(0);
+
+       uint16_t        checksum = IP_CHECKSUM_START;
+       checksum = IP_Checksum(checksum, sizeof(hdr), &hdr);
+       checksum = IP_Checksum(checksum, data_len, data);
+       hdr.Checksum = htons( checksum );
+
+       size_t  buflens[] = {sizeof(hdr), data_len};
+       const void *bufs[] = {&hdr, data};
+       IP_Send(IF, AF, BLOB(HOST_IP), IP, IPPROTO_TCP, 2, buflens, bufs);
+}
+
+bool TCP_Pkt_Check(size_t len, const void *data, size_t *out_ofs, int AF, const void *IP, short sport, short dport,
+       uint8_t flags)
+{
+       size_t  ofs;
+       if( !IP_Pkt_Check(len, data, &ofs, AF, IP, BLOB(HOST_IP), IPPROTO_TCP) )
+               return false;
+       
+       tTCPHeader      hdr;
+       TEST_ASSERT_REL(len - ofs, >=, sizeof(hdr));    
+       memcpy(&hdr, (char*)data + ofs, sizeof(hdr));
+       
+       TEST_ASSERT_REL( ntohs(hdr.SPort), ==, sport );
+       TEST_ASSERT_REL( ntohs(hdr.DPort), ==, dport );
+       // TODO: Checks on Seq/Ack
+       TEST_ASSERT_REL( hdr.Flags, ==, flags);
+
+       uint16_t        real_cksum = htons(hdr.Checksum);
+       hdr.Checksum = 0;
+       uint16_t        calc_cksum = IP_CHECKSUM_START;
+       calc_cksum = IP_Checksum(calc_cksum, sizeof(hdr), &hdr);
+       calc_cksum = IP_Checksum(calc_cksum, len - ofs - sizeof(hdr), (char*)data+ofs+sizeof(hdr));
+       TEST_ASSERT_REL( real_cksum, ==, calc_cksum );
+       
+       *out_ofs = ofs + sizeof(hdr);
+       return true;
+}
+
diff --git a/Tools/NetTest_Runner/test_arp.c b/Tools/NetTest_Runner/test_arp.c
new file mode 100644 (file)
index 0000000..e97e2c3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ */
+#include "test.h"
+#include "tests.h"
+#include "net.h"
+#include "stack.h"
+#include "arp.h"
+
+bool Test_ARP_Basic(void)
+{
+       TEST_SETNAME(__func__);
+       size_t  rxlen;
+       char rxbuf[MTU];
+       
+       // Request test machine's IP
+       ARP_SendRequest(0, BLOB(TEST_IP));
+       TEST_ASSERT( rxlen = Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) );
+       TEST_ASSERT( ARP_Pkt_IsResponse(rxlen, rxbuf, BLOB(TEST_IP), BLOB(TEST_MAC)) );
+
+       // Request host machine's IP
+       ARP_SendRequest(0, HOST_IP_STR);
+       TEST_ASSERT( Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) == 0 );
+
+       #if 0   
+       // Ask test machine to request our IP
+       Stack_SendCommand("arprequest "HOST_IP_STR);
+       TEST_ASSERT( rxlen = Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) );
+       TEST_ASSERT( ARP_Pkt_IsRequest(rxlen, rxbuf, HOST_IP) );
+
+       // Respond
+       ARP_SendResponse(0, HOST_IP, HOST_MAC);
+       
+       // Ask test machine to request our IP again (expecting nothing)
+       Stack_SendCommand("arprequest "HOST_IP_STR);
+       TEST_ASSERT( !Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) );
+       #endif
+       
+       return true;
+}
diff --git a/Tools/NetTest_Runner/test_tcp.c b/Tools/NetTest_Runner/test_tcp.c
new file mode 100644 (file)
index 0000000..a19c85b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ */
+#include "test.h"
+#include "tests.h"
+#include "net.h"
+#include "stack.h"
+#include "arp.h"
+#include "tcp.h"
+
+bool Test_TCP_Basic(void)
+{
+       TEST_SETNAME(__func__);
+       size_t  rxlen, ofs;
+       char rxbuf[MTU];
+       
+       // 1. Test connection to closed port
+       uint32_t        seq_tx = 0x1000;
+       uint32_t        seq_exp = 0;
+       TCP_Send(0, 4, BLOB(TEST_IP), 1234, 80, seq_tx, seq_exp, TCP_SYN, 0x1000, 0, NULL);
+       
+       TEST_ASSERT( rxlen = Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) );
+       TEST_ASSERT( TCP_Pkt_Check(rxlen, rxbuf, &ofs, 4, BLOB(TEST_IP), 80, 1234, TCP_RST) );
+       TEST_ASSERT_REL(ofs, ==, rxlen);
+       
+       return true;
+}
index 7b78667..1a50d88 100644 (file)
@@ -7,11 +7,11 @@ LOBJ := threads.o time.o dummy_iocache.o
 # mutex.o rwlock.o semaphore.o
 
 KOBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o
-KOBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o vfs/select.o
+KOBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o vfs/select.o
 KOBJ += vfs/fs/root.o vfs/fs/devfs.o
 KOBJ += drv/proc.o
-KOBJ += mutex.o rwlock.o semaphore.o
-KOBJ += utf16.o
+KOBJ += mutex.o rwlock.o semaphore.o events.o
+KOBJ += utf16.o lib.o
 
 NOBJ := $(NOBJ:%.o=obj/%.o)
 LOBJ := $(LOBJ:%.o=obj/%.o)
index b8bd4df..f133788 100644 (file)
@@ -13,8 +13,6 @@
 #define STR(x) #x
 #define EXPAND_STR(x) STR(x)
 
-#define ASSERT(x)      do{}while(0)
-
 extern char    __buildnum[];
 #define BUILD_NUM      ((int)(Uint)&__buildnum)
 extern const char gsGitHash[];
@@ -25,6 +23,7 @@ extern const char gsBuildInfo[];
 #define BITS   32
 #define NULL   ((void*)0)
 #include <stdint.h>
+#include <stdbool.h>
 
 typedef uintptr_t      Uint;
 //typedef unsigned int size_t;
@@ -49,6 +48,7 @@ typedef uint32_t      tPAddr;
 typedef uint32_t       tUID;
 typedef uint32_t       tGID;
 typedef uint32_t       tTID;
+typedef uint32_t       tPGID;
 
 typedef int64_t        tTime;
 extern tTime   now(void);
@@ -71,7 +71,27 @@ extern void  free(void *buffer);
 extern char    *strdup(const char *str);
 
 #include <errno.h>
-#include <acess_logging.h>
+//#include <acess_logging.h>
+#include <logdebug.h>
+
+extern void    Debug_TraceEnter(const char *Function, const char *Format, ...);
+extern void    Debug_TraceLog(const char *Function, const char *Format, ...);
+extern void    Debug_TraceLeave(const char *Function, char Type, ...);
+#undef ENTER
+#undef LOG
+#undef LEAVE
+#undef LEAVE_RET
+#if DEBUG
+# define ENTER(str, v...)      Debug_TraceEnter(__func__, str, ##v)
+# define LOG(fmt, v...)        Debug_TraceLog(__func__, fmt, ##v)
+# define LEAVE(t, v...)        Debug_TraceLeave(__func__, t, ##v)
+# define LEAVE_RET(t,v)        do{LEAVE('-');return v;}while(0)
+#else
+# define ENTER(...)    do{}while(0)
+# define LOG(...)      do{}while(0)
+# define LEAVE(...)    do{}while(0)
+# define LEAVE_RET(t,v)        do{return v;}while(0)
+#endif
 
 // Threads
 extern void    **Threads_GetHandlesPtr(void);
index 1b4ddac..7bd91c1 100644 (file)
@@ -49,7 +49,7 @@ struct sThread
 
        tShortSpinlock  IsLocked;
 
-       uint32_t        PendingEvents;
+       uint32_t        EventState;
        uint32_t        WaitingEvents;
        tThreadIntSem   *WaitSemaphore; // pthreads
 
@@ -102,10 +102,13 @@ extern tShortSpinlock     glThreadListLock;
 extern int     Threads_int_CreateThread(struct sThread *Thread);
 extern int     Threads_int_ThreadingEnabled(void);
 
+
 extern tThread *Proc_GetCurThread(void);
 extern tThread *Threads_RemActive(void);
 extern void    Threads_AddActive(tThread *Thread);
 extern void    Threads_int_WaitForStatusEnd(enum eThreadStatus Status);
+extern int     Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock);
+extern void    Semaphore_ForceWake(tThread *Thread);
 
 extern tThreadIntMutex *Threads_int_MutexCreate(void);
 extern void    Threads_int_MutexDestroy(tThreadIntMutex *Mutex);
index 16e6f70..e9925ac 100644 (file)
@@ -19,16 +19,23 @@ extern int  Threads_GetTID();
 #define LOGHDR(col,type)       fprintf(stderr, "\e["col"m[%-8.8s]"type"%2i ", Ident, Threads_GetTID())
 #define LOGTAIL()      fprintf(stderr, "\e[0m\n")
 
-#define PUTERR(col,type)       {\
+#define        LOG_LOCK_ACQUIRE()      do{ \
        if(!gbThreadInLog)      SHORTLOCK(&glDebugLock); \
        gbThreadInLog ++; \
+}while(0)
+#define LOG_LOCK_RELEASE()     do {\
+       gbThreadInLog --; \
+       if(!gbThreadInLog)      SHORTREL(&glDebugLock); \
+} while(0)
+
+#define PUTERR(col,type)       {\
+       LOG_LOCK_ACQUIRE(); \
        LOGHDR(col,type);\
        va_list args; va_start(args, Message);\
        vfprintf(stderr, Message, args);\
        va_end(args);\
        LOGTAIL();\
-       gbThreadInLog --; \
-       if(!gbThreadInLog)      SHORTREL(&glDebugLock); \
+       LOG_LOCK_RELEASE(); \
 }
 
 // === GLOBALS ===
@@ -66,11 +73,16 @@ void Log(const char *Message, ...) {
        const char *Ident = "";
        PUTERR("37", "L")
 }
+void Debug(const char *Message, ...) {
+       const char *Ident = "";
+       PUTERR("38", "D")
+}
 
 void Debug_HexDump(const char *Prefix, const void *Data, size_t Length)
 {
        const uint8_t *data = Data;
        size_t  ofs;
+       LOG_LOCK_ACQUIRE();
        fprintf(stderr, "[HexDump ]d %s: %i bytes\n", Prefix, (int)Length);
        for( ofs = 0; ofs + 16 <= Length; ofs += 16 )
        {
@@ -91,6 +103,7 @@ void Debug_HexDump(const char *Prefix, const void *Data, size_t Length)
                fprintf(stderr, " %02x", data[ofs%16]);
        }
        fprintf(stderr, "\n");
+       LOG_LOCK_RELEASE();
 }
 
  int   giDebug_TraceLevel = 0;
@@ -98,6 +111,7 @@ void Debug_HexDump(const char *Prefix, const void *Data, size_t Length)
 void Debug_TraceEnter(const char *Function, const char *Format, ...)
 {
        const char *Ident = "Trace";
+       LOG_LOCK_ACQUIRE();
        LOGHDR("37","T");
        for( int i = 0; i < giDebug_TraceLevel; i ++ )
                fprintf(stderr, " ");
@@ -152,11 +166,13 @@ void Debug_TraceEnter(const char *Function, const char *Format, ...)
        fprintf(stderr, ")");
        LOGTAIL();
        giDebug_TraceLevel ++;
+       LOG_LOCK_RELEASE();
 }
 
 void Debug_TraceLog(const char *Function, const char *Format, ...)
 {
        const char *Ident = "Trace";
+       LOG_LOCK_ACQUIRE();
        LOGHDR("37","T");
        
        for( int i = 0; i < giDebug_TraceLevel; i ++ )
@@ -170,6 +186,7 @@ void Debug_TraceLog(const char *Function, const char *Format, ...)
        
        va_end(args);
        LOGTAIL();
+       LOG_LOCK_RELEASE();
 }
 
 void Debug_TraceLeave(const char *Function, char Type, ...)
@@ -179,6 +196,7 @@ void Debug_TraceLeave(const char *Function, char Type, ...)
        }
        
        const char *Ident = "Trace";
+       LOG_LOCK_ACQUIRE();
        LOGHDR("37","T");
        
        va_list args;
@@ -220,5 +238,6 @@ void Debug_TraceLeave(const char *Function, char Type, ...)
        
        va_end(args);
        LOGTAIL();
+       LOG_LOCK_RELEASE();
 }
 
index 9a4bfdf..cc508fb 100644 (file)
@@ -8,6 +8,7 @@
 #include <acess.h>
 #include <threads.h>
 #include <threads_int.h>
+#include <mutex.h>
 
 // === PROTOTYPES ===
 void   Threads_int_Init(void)  __attribute__((constructor(101)));
@@ -33,43 +34,6 @@ tThread *Proc_GetCurThread(void)
        return lpThreads_This;
 }
 
-void Threads_PostEvent(tThread *Thread, Uint32 Events)
-{
-       if( !Thread ) {
-               // nope.avi
-               return ;
-       }
-       SHORTLOCK( &Thread->IsLocked );
-       Thread->PendingEvents |= Events;
-       if( Thread->WaitingEvents & Events )
-               Threads_int_SemSignal(Thread->WaitSemaphore);
-       SHORTREL( &Thread->IsLocked );
-}
-
-Uint32 Threads_WaitEvents(Uint32 Events)
-{
-       if( !Threads_int_ThreadingEnabled() ) {
-               Log_Notice("Threads", "_WaitEvents: Threading disabled");
-               return 0;
-       }
-       lpThreads_This->WaitingEvents = Events;
-       Threads_int_SemWaitAll(lpThreads_This->WaitSemaphore);
-       lpThreads_This->WaitingEvents = 0;
-       Uint32  rv = lpThreads_This->PendingEvents;
-       return rv;
-}
-
-void Threads_ClearEvent(Uint32 Mask)
-{
-       if( !Threads_int_ThreadingEnabled() ) {
-               Log_Notice("Threads", "_ClearEvent: Threading disabled");
-               return ;
-       }
-       SHORTLOCK(&lpThreads_This->IsLocked);
-       lpThreads_This->PendingEvents &= ~Mask;
-       SHORTREL(&lpThreads_This->IsLocked);
-}
-
 tUID Threads_GetUID(void) { return 0; }
 tGID Threads_GetGID(void) { return 0; }
 
@@ -91,12 +55,6 @@ void Threads_Sleep(void)
        Log_Warning("Threads", "Threads_Sleep shouldn't be used");
 }
 
-void Threads_int_WaitForStatusEnd(enum eThreadStatus Status)
-{
-       while( lpThreads_This->Status != Status )
-               Threads_int_SemWaitAll(lpThreads_This->WaitSemaphore);
-}
-
 int Threads_SetName(const char *Name)
 {
        if( !lpThreads_This )
@@ -178,3 +136,53 @@ struct sThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
        }
 }
 
+void Threads_int_WaitForStatusEnd(enum eThreadStatus Status)
+{
+       tThread *us = Proc_GetCurThread();
+       assert(Status != THREAD_STAT_ACTIVE);
+       assert(Status != THREAD_STAT_DEAD);
+       LOG("%i(%s) - %i", us->TID, us->ThreadName, Status);
+       while( us->Status == Status )
+       {
+               Threads_int_SemWaitAll(us->WaitSemaphore);
+               if( us->Status == Status )
+                       Log_Warning("Threads", "Thread %p(%i %s) rescheduled while in %s state",
+                               us, us->TID, us->ThreadName, casTHREAD_STAT[Status]);
+       }
+}
+
+int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock)
+{
+       tThread *us = Proc_GetCurThread();
+       us->Next = NULL;
+       // - Mark as sleeping
+       us->Status = Status;
+       us->WaitPointer = Ptr;
+       us->RetStatus = Num;    // Use RetStatus as a temp variable
+               
+       // - Add to waiting
+       if( ListTail ) {
+               if(*ListTail) {
+                       (*ListTail)->Next = us;
+               }
+               else {
+                       *ListHead = us;
+               }
+               *ListTail = us;
+       }
+       else if(ListHead) {
+               us->Next = *ListHead;
+               *ListHead = us;
+       }
+       else {
+               // nothing
+       }
+       
+       if( Lock ) {
+               SHORTREL( Lock );
+       }
+       Threads_int_WaitForStatusEnd(Status);
+       us->WaitPointer = NULL;
+       return us->RetStatus;
+}
+
index b2ad9f6..8ab9b34 100644 (file)
@@ -4,6 +4,9 @@
  *
  * threads_int.c
  * - Internal threading functions
+ *
+ * POSIX Mutex/Semaphore management
+ * Wait state
  */
 #include <stddef.h>
 #include <stdlib.h>
@@ -28,7 +31,7 @@ int Threads_int_ThreadingEnabled(void)
 
 tThreadIntMutex *Threads_int_MutexCreate(void)
 {
-       if( pthread_mutex_init )
+       if( Threads_int_ThreadingEnabled() )
        {
                tThreadIntMutex *ret = malloc(sizeof(pthread_mutex_t));
                pthread_mutex_init( (void*)ret, NULL );
@@ -45,7 +48,7 @@ void Threads_int_MutexLock(tThreadIntMutex *Mutex)
        if( !Mutex ) {
                return ;
        }
-       if( pthread_mutex_lock )
+       if( Threads_int_ThreadingEnabled() )
        {
                pthread_mutex_lock( (void*)Mutex );
        }
@@ -63,7 +66,7 @@ void Threads_int_MutexRelease(tThreadIntMutex *Mutex)
                return ;
        }
 
-       if( pthread_mutex_unlock )
+       if( Threads_int_ThreadingEnabled() )
        {
                pthread_mutex_unlock( (void*)Mutex );
        }
@@ -77,7 +80,7 @@ void Threads_int_MutexRelease(tThreadIntMutex *Mutex)
 
 tThreadIntSem *Threads_int_SemCreate(void)
 {
-       if( sem_init )
+       if( Threads_int_ThreadingEnabled() )
        {
                tThreadIntSem *ret = malloc(sizeof(sem_t));
                sem_init( (void*)ret, 0, 0 );
@@ -91,7 +94,7 @@ tThreadIntSem *Threads_int_SemCreate(void)
 
 void Threads_int_SemSignal(tThreadIntSem *Sem)
 {
-       if( sem_post )
+       if( Threads_int_ThreadingEnabled() )
        {
                sem_post( (void*)Sem );
        }
@@ -103,7 +106,7 @@ void Threads_int_SemSignal(tThreadIntSem *Sem)
 
 void Threads_int_SemWaitAll(tThreadIntSem *Sem)
 {
-       if( sem_wait )
+       if( Threads_int_ThreadingEnabled() )
        {
                // TODO: Handle multiples
                sem_wait( (void*)Sem );
@@ -129,7 +132,7 @@ void *Threads_int_ThreadRoot(void *ThreadPtr)
 
 int Threads_int_CreateThread(tThread *Thread)
 {
-       if( pthread_create )
+       if( Threads_int_ThreadingEnabled() )
        {
                pthread_t *pthread = malloc(sizeof(pthread_t));
                Thread->ThreadHandle = pthread;
@@ -144,12 +147,7 @@ int Threads_int_CreateThread(tThread *Thread)
 
 void SHORTLOCK(tShortSpinlock *Lock)
 {
-       if( !pthread_mutex_init )
-       {
-               if(*Lock)       Log_KernelPanic("---", "Double short lock");
-               *Lock = (void*)1;
-       }
-       else
+       if( Threads_int_ThreadingEnabled() )
        {
                if( !*Lock ) {
                        *Lock = malloc(sizeof(pthread_mutex_t));
@@ -159,24 +157,36 @@ void SHORTLOCK(tShortSpinlock *Lock)
                pthread_mutex_lock(*Lock);
 //             printf("%p: SHORTLOCK held %p\n", lpThreads_This, __builtin_return_address(0));
        }
+       else
+       {
+               if(*Lock)       Log_KernelPanic("---", "Double short lock");
+               *Lock = (void*)1;
+       }
 }
 
 void SHORTREL(tShortSpinlock *Lock)
 {
-       if( !pthread_mutex_init )
+       if( Threads_int_ThreadingEnabled() )
        {
-               if(!*Lock)      Log_Notice("---", "Short release when not held");
-               *Lock = NULL;
+               pthread_mutex_unlock(*Lock);
+//             printf("%p: SHORTLOCK rel\n", lpThreads_This);
        }
        else
        {
-               pthread_mutex_unlock(*Lock);
-//             printf("%p: SHORTLOCK rel\n", lpThreads_This);
+               if(!*Lock)      Log_Notice("---", "Short release when not held");
+               *Lock = NULL;
        }
 }
 
 int CPU_HAS_LOCK(tShortSpinlock *Lock)
 {
-       return 0;
+       if( Threads_int_ThreadingEnabled() )
+       {
+               Log_KernelPanic("---", "TODO: CPU_HAS_LOCK with threading enabled");
+               return 0;
+       }
+       else
+       {
+               return 0;
+       }
 }
-
index f2f18d8..6f941f2 100644 (file)
@@ -7,6 +7,7 @@
  */
 #include <acess.h>
 #include <timers.h>
+#include <events.h>
 
 // === CODE ===
 tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument)
@@ -37,6 +38,17 @@ void Time_FreeTimer(tTimer *Timer)
        
 }
 
+void Time_ScheduleEvent(int Delay)
+{
+       Log_Warning("Time", "TODO: EVENT_TIMER in %ims", Delay);
+}
+
+void Time_Delay(int Delay)
+{
+       Time_ScheduleEvent(Delay);
+       Threads_WaitEvents(THREAD_EVENT_TIMER);
+}
+
 Sint64 now(void)
 {
        // TODO: Translate UNIX time into Acess time

UCC git Repository :: git.ucc.asn.au