Changes and Features to IPStack
authorJohn Hodge <tpg@prelude.(none)>
Mon, 18 Jan 2010 05:21:02 +0000 (13:21 +0800)
committerJohn Hodge <tpg@prelude.(none)>
Mon, 18 Jan 2010 05:21:02 +0000 (13:21 +0800)
- Added 'ping' ioctl and required calls, currently incomplete

Kernel/Makefile.BuildNum
Modules/IPStack/arp.c
Modules/IPStack/icmp.c
Modules/IPStack/icmp.h
Modules/IPStack/ipstack.h
Modules/IPStack/ipv4.c
Modules/IPStack/ipv4.h
Modules/IPStack/main.c

index b0b7558..fb94758 100644 (file)
@@ -1 +1 @@
-BUILD_NUM = 1368
+BUILD_NUM = 1369
index 2ee4fac..0ba0fd3 100644 (file)
@@ -7,6 +7,7 @@
 #include "link.h"
 
 #define        ARP_CACHE_SIZE  64
+#define        ARP_MAX_AGE             (60*60*1000)    // 1Hr
 
 // === IMPORTS ===
 extern tInterface      *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
@@ -23,8 +24,11 @@ struct sARP_Cache {
        tIPv4   IP4;
        tIPv6   IP6;
        Sint64  LastUpdate;
+       Sint64  LastUsed;
 }      *gaARP_Cache;
  int   giARP_CacheSpace;
+ int   giARP_LastUpdateID = 0;
+tSpinlock      glARP_Cache;
 
 // === CODE ===
 /**
@@ -41,6 +45,45 @@ int ARP_Initialise()
        return 1;
 }
 
+/**
+ * \brief Resolves a MAC address from an IPv4 address
+ */
+tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
+{
+        int    lastID;
+        int    i;
+       
+       LOCK( &glARP_Cache );
+       for( i = 0; i < giARP_CacheSpace; i++ )
+       {
+               if(gaARP_Cache[i].IP4.L != Address.L)   continue;
+               
+               // Check if the entry needs to be refreshed
+               if( now() - gaARP_Cache[i].LastUpdate > ARP_MAX_AGE )   break;
+               
+               RELEASE( &glARP_Cache );
+               return gaARP_Cache[i].MAC;
+       }
+       RELEASE( &glARP_Cache );
+       
+       lastID = giARP_LastUpdateID;
+       ARP_int_Resolve4(Interface, Address);
+       for(;;)
+       {
+               while(lastID == giARP_LastUpdateID)     Threads_Yield();
+               
+               LOCK( &glARP_Cache );
+               for( i = 0; i < giARP_CacheSpace; i++ )
+               {
+                       if(gaARP_Cache[i].IP4.L != Address.L)   continue;
+                       
+                       RELEASE( &glARP_Cache );
+                       return gaARP_Cache[i].MAC;
+               }
+               RELEASE( &glARP_Cache );
+       }
+}
+
 /**
  * \fn int ARP_int_Resolve4(tInterface *Interface, tIPv4 Address)
  * \brief Request the network to resolve an IPv4 Address
@@ -160,6 +203,7 @@ void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffe
        
        case 2: // Ooh! A response!
                // Find an entry for the MAC address in the cache
+               LOCK(&glARP_Cache);
                for( i = giARP_CacheSpace; i--; )
                {
                        if(gaARP_Cache[oldest].LastUpdate > gaARP_Cache[i].LastUpdate) {
@@ -190,10 +234,12 @@ void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffe
                        break;
                default:
                        Log("[ARP  ] Unknown Protocol Address size (%i)", req4->SWSize);
+                       RELEASE(&glARP_Cache);
                        return ;
                }
                
                gaARP_Cache[i].LastUpdate = now();
+               RELEASE(&glARP_Cache);
                break;
        }
 }
index 5d53cc6..3f82f87 100644 (file)
@@ -6,11 +6,18 @@
 #include "ipv4.h"
 #include "icmp.h"
 
+// === CONSTANTS ===
+#define PING_SLOTS     64
+
 // === PROTOTYPES ===
 void   ICMP_Initialise();
 void   ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
 
 // === GLOBALS ===
+struct {
+       tInterface      *Interface;
+        int    bArrived;
+}      gICMP_PingSlots[PING_SLOTS];
 
 // === CODE ===
 /**
@@ -35,4 +42,51 @@ void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buff
        Log("[ICMP ] hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
        Log("[ICMP ] hdr->ID = 0x%x", ntohs(hdr->ID));
        Log("[ICMP ] hdr->Sequence = 0x%x", ntohs(hdr->Sequence));
+       
+       switch(hdr->Type)
+       {
+       case ICMP_ECHOREPLY:
+               if(hdr->Code != 0) {
+                       Warning("[ICMP ] Code == %i for ICMP Echo Reply, should be 0", hdr->Code);
+                       return ;
+               }
+               if(hdr->ID != ~hdr->Sequence) {
+                       Warning("[ICMP ] ID and Sequence values do not match");
+                       return ;
+               }
+               gICMP_PingSlots[hdr->ID].bArrived = 1;
+               break;
+       }
+       
+}
+
+/**
+ * \brief Sends ICMP Echo and waits for the reply
+ * \note Times out after \a Interface->TimeoutDelay has elapsed
+ */
+int ICMP_Ping(tInterface *Interface, tIPv4 Addr)
+{
+       //Sint64        ts;
+       char    buf[32] = "\x8\0\0\0\0\0\0\0Acess2 I"
+                      "P/TCP Stack 1.0\0";
+       tICMPHeader     *hdr = (void*)buf;
+        int    i;
+       
+       for(;;)
+       {
+               for(i=0;i<PING_SLOTS;i++)
+               {
+                       if(gICMP_PingSlots[i].Interface == NULL)        break;
+               }
+               if(gICMP_PingSlots[i].Interface == NULL)        break;
+               Threads_Yield();
+       }
+       gICMP_PingSlots[i].Interface = Interface;
+       gICMP_PingSlots[i].bArrived = 0;
+       hdr->ID = i;
+       hdr->Sequence = ~i;
+       hdr->Checksum = htons( IPv4_Checksum(hdr, sizeof(buf)) );
+       IPv4_SendPacket(Interface, Addr, 1, i, 32, buf);
+       
+       return -1;
 }
index 73a641f..abd19cb 100644 (file)
@@ -18,4 +18,16 @@ struct sICMPHeader
        Uint16  Sequence;
 };
 
+// === CONSTANTS ===
+enum eICMPTypes
+{
+       ICMP_ECHOREPLY = 1,
+       ICMP_UNREACHABLE = 3,
+       ICMP_QUENCH = 4,
+       ICMP_REDIRECT = 5,
+       ICMP_ALTADDR = 6,
+       ICMP_ECHOREQ = 8,
+       ICMP_TRACE = 30 // Information Request
+};
+
 #endif
index 94fabbb..faf8cb8 100644 (file)
@@ -34,6 +34,7 @@ struct sInterface {
        struct sInterface       *Next;
        tVFS_Node       Node;
        tAdapter        *Adapter;
+        int    TimeoutDelay;   // Time in miliseconds before a connection times out
         int    Type;   // 0 for disabled, 4 for IPv4 and 6 for IPv6
        union {
                struct  {
index 7e7c585..282e71b 100644 (file)
@@ -6,10 +6,14 @@
 #include "link.h"
 #include "ipv4.h"
 
+#define DEFAULT_TTL    32
+
 // === IMPORTS ===
 extern tInterface      *gIP_Interfaces;
 extern void    ICMP_Initialise();
+extern  int    ICMP_Ping(tInterface *Interface, tIPv4 Addr);
 extern void    UDP_Initialise();
+extern tMacAddr        ARP_Resolve4(tInterface *Interface, tIPv4 Address);
 
 // === PROTOTYPES ===
  int   IPv4_Initialise();
@@ -17,6 +21,8 @@ extern void   UDP_Initialise();
 void   IPv4_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
 tInterface     *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
 Uint32 IPv4_Netmask(int FixedBits);
+Uint16 IPv4_Checksum(void *Buf, int Size);
+ int   IPv4_Ping(tInterface *Iface, tIPv4 Addr);
 
 // === GLOBALS ===
 tIPCallback    gaIPv4_Callbacks[256];
@@ -45,6 +51,33 @@ int IPv4_RegisterCallback(int ID, tIPCallback Callback)
        return 1;
 }
 
+/**
+ * \brief Creates and sends an IPv4 Packet
+ */
+int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, void *Data)
+{
+       tMacAddr        to = ARP_Resolve4(Iface, Address);
+        int    bufSize = sizeof(tIPv4Header) + Length;
+       char    buf[bufSize];
+       tIPv4Header     *hdr = (void*)buf;
+       
+       memcpy(&hdr->Options[0], Data, Length);
+       hdr->Version = 4;
+       hdr->HeaderLength = htons( sizeof(tIPv4Header) );
+       hdr->DiffServices = 0;  // TODO: Check
+       hdr->TotalLength = htons( bufSize );
+       hdr->Identifcation = htons( ID );       // TODO: Check
+       hdr->TTL = DEFAULT_TTL;
+       hdr->Protocol = Protocol;
+       hdr->HeaderChecksum = 0;        // Will be set later
+       hdr->Source = Iface->IP4.Address;
+       hdr->Destination = Address;
+       hdr->HeaderChecksum = htons( IPv4_Checksum(hdr, sizeof(tIPv4Header)) );
+       
+       Link_SendPacket(Iface->Adapter, IPV4_ETHERNET_ID, to, bufSize, buf);
+       return 1;
+}
+
 /**
  * \fn void IPv4_int_GetPacket(tInterface *Adapter, tMacAddr From, int Length, void *Buffer)
  * \brief Process an IPv4 Packet
@@ -156,3 +189,30 @@ Uint32 IPv4_Netmask(int FixedBits)
        // Returs a little endian netmask
        return ret;
 }
+
+/**
+ * \brief Calculate the IPv4 Checksum
+ */
+Uint16 IPv4_Checksum(void *Buf, int Size)
+{
+       Uint16  sum = 0;
+       Uint16  *arr = Buf;
+        int    i;
+       
+       Size = (Size + 1) >> 1;
+       for(i = 0; i < Size; i++ )
+       {
+               if((int)sum + arr[i] > 0xFFFF)
+                       sum ++; // Simulate 1's complement
+               sum += arr[i];
+       }
+       return ~sum;
+}
+
+/**
+ * \brief Sends an ICMP Echo and waits for a reply
+ */
+int IPv4_Ping(tInterface *Iface, tIPv4 Addr)
+{
+       return ICMP_Ping(Iface, Addr);
+}
index b092bec..e8c2bc3 100644 (file)
@@ -46,5 +46,7 @@ struct sIPv4Header
 
 // === FUNCTIONS ===
 extern int     IPv4_RegisterCallback(int ID, tIPCallback Callback);
+extern Uint16  IPv4_Checksum(void *Buf, int Size);
+extern int     IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, void *Data);
 
 #endif
index 448381d..1a58173 100644 (file)
 #include <tpl_drv_common.h>
 #include <tpl_drv_network.h>
 
+// === CONSTANTS ===
+//! Default timeout value, 30 seconds
+#define DEFAULT_TIMEOUT        (30*1000)
+
 // === IMPORTS ===
 extern int     ARP_Initialise();
 extern int     IPv4_Initialise();
+extern int     IPv4_Ping(tInterface *Iface, tIPv4 Addr);
 
 // === PROTOTYPES ===
  int   IPStack_Install(char **Arguments);
+ int   IPStack_IOCtlRoot(tVFS_Node *Node, int ID, void *Data);
 char   *IPStack_ReadDir(tVFS_Node *Node, int Pos);
 tVFS_Node      *IPStack_FindDir(tVFS_Node *Node, char *Name);
  int   IPStack_IOCtl(tVFS_Node *Node, int ID, void *Data);
@@ -34,7 +40,7 @@ tDevFS_Driver gIP_DriverInfo = {
        .Flags = VFS_FFLAG_DIRECTORY,
        .ReadDir = IPStack_ReadDir,
        .FindDir = IPStack_FindDir,
-       .IOCtl = IPStack_IOCtl
+       .IOCtl = IPStack_IOCtlRoot
        }
 };
 tSpinlock      glIP_Interfaces = 0;
@@ -158,20 +164,71 @@ tVFS_Node *IPStack_FindDir(tVFS_Node *Node, char *Name)
 }
 
 static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_interface", NULL };
+/**
+ * \brief Handles IOCtls for the IPStack root
+ */
+int IPStack_IOCtlRoot(tVFS_Node *Node, int ID, void *Data)
+{
+        int    tmp;
+       ENTER("pNode iID pData", Node, ID, Data);
+       
+       switch(ID)
+       {
+       // --- Standard IOCtls (0-3) ---
+       case DRV_IOCTL_TYPE:
+               LEAVE('i', DRV_TYPE_MISC);
+               return DRV_TYPE_MISC;
+       
+       case DRV_IOCTL_IDENT:
+               if( !CheckMem( Data, 4 ) )      LEAVE_RET('i', -1);
+               memcpy(Data, "IP\0\0", 4);
+               LEAVE('i', 1);
+               return 1;
+       
+       case DRV_IOCTL_VERSION:
+               LEAVE('x', VERSION);
+               return VERSION;
+       
+       case DRV_IOCTL_LOOKUP:
+               if( !CheckString( Data ) )      LEAVE_RET('i', -1);
+               LOG("Lookup '%s'", Data);
+               if( Node == &gIP_DriverInfo.RootNode )
+                       tmp = LookupString( (char**)casIOCtls_Root, (char*)Data );
+               else
+                       tmp = LookupString( (char**)casIOCtls_Iface, (char*)Data );
+               LEAVE('i', tmp);
+               return tmp;
+               
+               /*
+                * add_interface
+                * - Adds a new IP interface and binds it to a device
+                */
+       case 4:
+               if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
+               if( !CheckString( Data ) )      LEAVE_RET('i', -1);
+               tmp = IPStack_AddInterface(Data);
+               LEAVE_RET('i', tmp);
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
 static const char *casIOCtls_Iface[] = {
        DRV_IOCTLNAMES,
        "getset_type",
        "get_address", "set_address",
        "getset_subnet",
        "get_gateway", "set_gateway",
+       "ping",
        NULL
        };
 /**
- * \brief Handles IOCtls for the IPStack root/interfaces
+ * \brief Handles IOCtls for the IPStack interfaces
  */
 int IPStack_IOCtl(tVFS_Node *Node, int ID, void *Data)
 {
         int    tmp;
+       tInterface      *iface = (tInterface*)Node->ImplPtr;
        ENTER("pNode iID pData", Node, ID, Data);
        
        switch(ID)
@@ -200,194 +257,192 @@ int IPStack_IOCtl(tVFS_Node *Node, int ID, void *Data)
                        tmp = LookupString( (char**)casIOCtls_Iface, (char*)Data );
                LEAVE('i', tmp);
                return tmp;
-       }
        
-       if(Node == &gIP_DriverInfo.RootNode)
-       {
-               switch(ID)
+       /*
+        * getset_type
+        * - Get/Set the interface type
+        */
+       case 4:
+               // Set Type?
+               if( Data )
                {
-               /*
-                * add_interface
-                * - Adds a new IP interface and binds it to a device
-                */
+                       // Ok, it's set type
+                       if( Threads_GetUID() != 0 ) {
+                               LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+                       if( !CheckMem( Data, sizeof(int) ) ) {
+                               LOG("Invalid pointer %p", Data);
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+                       switch( *(int*)Data )
+                       {
+                       case 0: // Disable
+                               iface->Type = 0;
+                               memset(&iface->IP6, 0, sizeof(tIPv6));  // Clear address
+                               break;
+                       case 4: // IPv4
+                               iface->Type = 4;
+                               memset(&iface->IP4, 0, sizeof(tIPv4));
+                               break;
+                       case 6: // IPv6
+                               iface->Type = 6;
+                               memset(&iface->IP6, 0, sizeof(tIPv6));
+                               break;
+                       default:
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+               }
+               LEAVE('i', iface->Type);
+               return iface->Type;
+       
+       /*
+        * get_address
+        * - Get the interface's address
+        */
+       case 5:
+               switch(iface->Type)
+               {
+               case 0: LEAVE_RET('i', 1);
                case 4:
-                       if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
-                       if( !CheckString( Data ) )      LEAVE_RET('i', -1);
-                       tmp = IPStack_AddInterface(Data);
-                       LEAVE_RET('i', tmp);
+                       if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
+                       memcpy( Data, &iface->IP4.Address, sizeof(tIPv4) );
+                       LEAVE_RET('i', 1);
+               case 6:
+                       if( !CheckMem( Data, sizeof(tIPv6) ) )  LEAVE_RET('i', -1);
+                       memcpy( Data, &iface->IP6.Address, sizeof(tIPv6) );
+                       LEAVE_RET('i', 1);
                }
-               LEAVE('i', 0);
-               return 0;       
-       }
-       else
-       {
-               tInterface      *iface = (tInterface*)Node->ImplPtr;
-               switch(ID)
+               LEAVE_RET('i', 0);
+       
+       /*
+        * set_address
+        * - Get the interface's address
+        */
+       case 6:
+               if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
+               switch(iface->Type)
                {
-               /*
-                * getset_type
-                * - Get/Set the interface type
-                */
+               case 0: LEAVE_RET('i', 1);
                case 4:
-                       // Set Type?
-                       if( Data )
+                       if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
+                       iface->Type = 0;        // One very hacky mutex/trash protector
+                       memcpy( &iface->IP4.Address, Data, sizeof(tIPv4) );
+                       iface->Type = 4;
+                       LEAVE_RET('i', 1);
+               case 6:
+                       if( !CheckMem( Data, sizeof(tIPv6) ) )  LEAVE_RET('i', -1);
+                       iface->Type = 0;
+                       memcpy( &iface->IP6.Address, Data, sizeof(tIPv6) );
+                       iface->Type = 6;
+                       LEAVE_RET('i', 1);
+               }
+               LEAVE_RET('i', 0);
+       
+       /*
+        * getset_subnet
+        * - Get/Set the bits in the address subnet
+        */
+       case 7:
+               // Get?
+               if( Data == NULL )
+               {
+                       switch( iface->Type )
                        {
-                               // Ok, it's set type
-                               if( Threads_GetUID() != 0 ) {
-                                       LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
-                                       LEAVE('i', -1);
-                                       return -1;
-                               }
-                               if( !CheckMem( Data, sizeof(int) ) ) {
-                                       LOG("Invalid pointer %p", Data);
-                                       LEAVE('i', -1);
-                                       return -1;
-                               }
-                               switch( *(int*)Data )
-                               {
-                               case 0: // Disable
-                                       iface->Type = 0;
-                                       memset(&iface->IP6, 0, sizeof(tIPv6));  // Clear address
-                                       break;
-                               case 4: // IPv4
-                                       iface->Type = 4;
-                                       memset(&iface->IP4, 0, sizeof(tIPv4));
-                                       break;
-                               case 6: // IPv6
-                                       iface->Type = 6;
-                                       memset(&iface->IP6, 0, sizeof(tIPv6));
-                                       break;
-                               default:
-                                       LEAVE('i', -1);
-                                       return -1;
-                               }
+                       case 4:         LEAVE_RET('i', iface->IP4.SubnetBits);
+                       case 6:         LEAVE_RET('i', iface->IP6.SubnetBits);
+                       default:        LEAVE_RET('i', 0);
                        }
-                       LEAVE('i', iface->Type);
-                       return iface->Type;
+               }
                
-               /*
-                * get_address
-                * - Get the interface's address
-                */
-               case 5:
-                       switch(iface->Type)
-                       {
-                       case 0: LEAVE_RET('i', 1);
-                       case 4:
-                               if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
-                               memcpy( Data, &iface->IP4.Address, sizeof(tIPv4) );
-                               LEAVE_RET('i', 1);
-                       case 6:
-                               if( !CheckMem( Data, sizeof(tIPv6) ) )  LEAVE_RET('i', -1);
-                               memcpy( Data, &iface->IP6.Address, sizeof(tIPv6) );
-                               LEAVE_RET('i', 1);
-                       }
-                       LEAVE_RET('i', 0);
+               // Ok, set.
+               if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
+               if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
                
-               /*
-                * set_address
-                * - Get the interface's address
-                */
+               // Check and set the subnet bits
+               switch( iface->Type )
+               {
+               case 4:
+                       if( *(int*)Data < 0 || *(int*)Data > 31 )       LEAVE_RET('i', -1);
+                       iface->IP4.SubnetBits = *(int*)Data;
+                       LEAVE_RET('i', iface->IP4.SubnetBits);
                case 6:
-                       if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
-                       switch(iface->Type)
-                       {
-                       case 0: LEAVE_RET('i', 1);
-                       case 4:
-                               if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
-                               iface->Type = 0;        // One very hacky mutex/trash protector
-                               memcpy( &iface->IP4.Address, Data, sizeof(tIPv4) );
-                               iface->Type = 4;
-                               LEAVE_RET('i', 1);
-                       case 6:
-                               if( !CheckMem( Data, sizeof(tIPv6) ) )  LEAVE_RET('i', -1);
-                               iface->Type = 0;
-                               memcpy( &iface->IP6.Address, Data, sizeof(tIPv6) );
-                               iface->Type = 6;
-                               LEAVE_RET('i', 1);
-                       }
-                       LEAVE_RET('i', 0);
+                       if( *(int*)Data < 0 || *(int*)Data > 127 )      LEAVE_RET('i', -1);
+                       iface->IP6.SubnetBits = *(int*)Data;
+                       LEAVE_RET('i', iface->IP6.SubnetBits);
+               default:
+                       break;
+               }
                
-               /*
-                * getset_subnet
-                * - Get/Set the bits in the address subnet
-                */
-               case 7:
-                       // Get?
-                       if( Data == NULL )
-                       {
-                               switch( iface->Type )
-                               {
-                               case 4:         LEAVE_RET('i', iface->IP4.SubnetBits);
-                               case 6:         LEAVE_RET('i', iface->IP6.SubnetBits);
-                               default:        LEAVE_RET('i', 0);
-                               }
-                       }
-                       
-                       // Ok, set.
-                       if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
-                       if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
-                       
-                       // Check and set the subnet bits
-                       switch( iface->Type )
-                       {
-                       case 4:
-                               if( *(int*)Data < 0 || *(int*)Data > 31 )       LEAVE_RET('i', -1);
-                               iface->IP4.SubnetBits = *(int*)Data;
-                               LEAVE_RET('i', iface->IP4.SubnetBits);
-                       case 6:
-                               if( *(int*)Data < 0 || *(int*)Data > 127 )      LEAVE_RET('i', -1);
-                               iface->IP6.SubnetBits = *(int*)Data;
-                               LEAVE_RET('i', iface->IP6.SubnetBits);
-                       default:
-                               break;
-                       }
-                       
-                       LEAVE('i', 0);
-                       return 0;
+               LEAVE('i', 0);
+               return 0;
+               
+       /*
+        * get_gateway
+        * - Get the interface's IPv4 gateway
+        */
+       case 8:
+               switch(iface->Type)
+               {
+               case 0:
+                       LEAVE_RET('i', 1);
+               case 4:
+                       if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
+                       memcpy( Data, &iface->IP4.Gateway, sizeof(tIPv4) );
+                       LEAVE_RET('i', 1);
+               case 6:
+                       LEAVE_RET('i', 1);
+               }
+               LEAVE('i', 0);
+               return 0;
+       
+       /*
+        * set_gateway
+        * - Get/Set the interface's IPv4 gateway
+        */
+       case 9:
+               if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
+               switch(iface->Type)
+               {
+               case 0:
+                       LEAVE_RET('i', 1);
+               
+               case 4:
+                       if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
+                       iface->Type = 0;        // One very hacky mutex/trash protector
+                       memcpy( &iface->IP4.Gateway, Data, sizeof(tIPv4) );
+                       iface->Type = 4;
+                       LEAVE_RET('i', 1);
                        
-               /*
-                * get_gateway
-                * - Get the interface's IPv4 gateway
-                */
-               case 8:
-                       switch(iface->Type)
-                       {
-                       case 0:
-                               LEAVE_RET('i', 1);
-                       case 4:
-                               if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
-                               memcpy( Data, &iface->IP4.Gateway, sizeof(tIPv4) );
-                               LEAVE_RET('i', 1);
-                       case 6:
-                               LEAVE_RET('i', 1);
-                       }
-                       LEAVE('i', 0);
-                       return 0;
+               case 6:
+                       LEAVE_RET('i', 1);
+               }
+               break;
+       
+       /*
+        * ping
+        * - Send an ICMP Echo
+        */
+       case 10:
+               switch(iface->Type)
+               {
+               case 0:
+                       LEAVE_RET('i', 1);
                
-               /*
-                * set_gateway
-                * - Get the interface's IPv4 gateway
-                */
-               case 9:
-                       if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
-                       switch(iface->Type)
-                       {
-                       case 0:
-                               LEAVE_RET('i', 1);
+               case 4:
+                       if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
+                       tmp = IPv4_Ping(iface, *(tIPv4*)Data);
+                       LEAVE('i', tmp);
+                       return tmp;
                        
-                       case 4:
-                               if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
-                               iface->Type = 0;        // One very hacky mutex/trash protector
-                               memcpy( &iface->IP4.Gateway, Data, sizeof(tIPv4) );
-                               iface->Type = 4;
-                               LEAVE_RET('i', 1);
-                               
-                       case 6:
-                               LEAVE_RET('i', 1);
-                       }
-                       LEAVE_RET('i', 0);
+               case 6:
+                       LEAVE_RET('i', 1);
                }
+               break;
+       
        }
        
        LEAVE('i', 0);
@@ -425,6 +480,9 @@ int IPStack_AddInterface(char *Device)
        iface->Node.FindDir = NULL;
        iface->Node.IOCtl = IPStack_IOCtl;
        
+       // Set Defaults
+       iface->TimeoutDelay = DEFAULT_TIMEOUT;
+       
        // Get adapter handle
        iface->Adapter = IPStack_GetAdapter(Device);
        if( !iface->Adapter ) {

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