#define VERSION VER2(0,10)
#include "ipstack.h"
#include "link.h"
-#include <tpl_drv_common.h>
-#include <tpl_drv_network.h>
+#include <api_drv_common.h>
+#include <api_drv_network.h>
// === CONSTANTS ===
//! Default timeout value, 30 seconds
tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
- int IPStack_AddInterface(const char *Device, const char *Name);
int IPStack_AddFile(tSocketFile *File);
+tInterface *IPStack_AddInterface(const char *Device, const char *Name);
tAdapter *IPStack_GetAdapter(const char *Path);
char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos);
// === GLOBALS ===
//! Loopback (127.0.0.0/8, ::1) Pseudo-Interface
tInterface gIP_LoopInterface = {
- Node: {
- ImplPtr: &gIP_LoopInterface,
- Flags: VFS_FFLAG_DIRECTORY,
- Size: -1,
- NumACLs: 1,
- ACLs: &gVFS_ACL_EveryoneRX,
- ReadDir: IPStack_Iface_ReadDir,
- FindDir: IPStack_Iface_FindDir,
- IOCtl: IPStack_Iface_IOCtl
+ .Node = {
+ .ImplPtr = &gIP_LoopInterface,
+ .Flags = VFS_FFLAG_DIRECTORY,
+ .Size = -1,
+ .NumACLs = 1,
+ .ACLs = &gVFS_ACL_EveryoneRX,
+ .ReadDir = IPStack_Iface_ReadDir,
+ .FindDir = IPStack_Iface_FindDir,
+ .IOCtl = IPStack_Iface_IOCtl
},
- Adapter: NULL,
- Type: 0
+ .Adapter = NULL,
+ .Type = 0
};
tShortSpinlock glIP_Interfaces;
tInterface *gIP_Interfaces = NULL;
tInterface *gIP_Interfaces_Last = NULL;
tSocketFile *gIP_FileTemplates;
+
+tAdapter gIP_LoopAdapter = {
+ .DeviceLen = 8,
+ .Device = "LOOPBACK"
+ };
tMutex glIP_Adapters;
tAdapter *gIP_Adapters = NULL;
int giIP_NextIfaceId = 1;
*/
tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name)
{
+ #if 0
int i, num;
+ #endif
tInterface *iface;
ENTER("pNode sName", Node, Name);
return &gIP_LoopInterface.Node;
}
- i = 0; num = 0;
- while('0' <= Name[i] && Name[i] <= '9')
- {
- num *= 10;
- num += Name[i] - '0';
- i ++;
- }
- if(Name[i] != '\0') {
- LEAVE('n');
- return NULL;
- }
-
for( iface = gIP_Interfaces; iface; iface = iface->Next )
{
- if( (int)iface->Node.ImplInt == num )
+ if( strcmp(iface->Name, Name) == 0 )
{
LEAVE('p', &iface->Node);
return &iface->Node;
}
}
+
LEAVE('p', NULL);
return NULL;
}
switch(ID)
{
// --- Standard IOCtls (0-3) ---
- case DRV_IOCTL_TYPE:
- LEAVE('i', DRV_TYPE_MISC);
- return DRV_TYPE_MISC;
-
- case DRV_IOCTL_IDENT:
- tmp = ModUtil_SetIdent(Data, "IPStack");
- LEAVE('i', 1);
- return 1;
-
- case DRV_IOCTL_VERSION:
- LEAVE('x', VERSION);
- return VERSION;
-
- case DRV_IOCTL_LOOKUP:
- tmp = ModUtil_LookupString( (char**)casIOCtls_Root, (char*)Data );
- LEAVE('i', tmp);
- return tmp;
+ BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Root)
- /*
- * add_interface
- * - Adds a new IP interface and binds it to a device
- */
+ /*
+ * 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);
{
char name[4] = "";
- tmp = IPStack_AddInterface(Data, name);
+ tInterface *iface = IPStack_AddInterface(Data, name);
+ if(iface == NULL) LEAVE_RET('i', -1);
+ tmp = iface->Node.ImplInt;
}
LEAVE_RET('i', tmp);
}
}
/**
- * \fn int IPStack_AddInterface(char *Device)
+ * \fn tInterface *IPStack_AddInterface(char *Device)
* \brief Adds an interface to the list
*/
-int IPStack_AddInterface(const char *Device, const char *Name)
+tInterface *IPStack_AddInterface(const char *Device, const char *Name)
{
tInterface *iface;
tAdapter *card;
+ int nameLen;
ENTER("sDevice", Device);
card = IPStack_GetAdapter(Device);
+ if( !card ) {
+ Log_Debug("IPStack", "Unable to open card '%s'", Device);
+ LEAVE('n');
+ return NULL; // ERR_YOURBAD
+ }
- iface = malloc(sizeof(tInterface) + strlen(Name));
+ nameLen = sprintf(NULL, "%i", giIP_NextIfaceId);
+
+ iface = malloc(
+ sizeof(tInterface)
+ + nameLen + 1
+ + IPStack_GetAddressSize(-1)*3 // Address, Route->Network, Route->NextHop
+ );
if(!iface) {
- LEAVE('i', -2);
- return -2; // Return ERR_MYBAD
+ Log_Warning("IPStack", "AddInterface - malloc() failed");
+ LEAVE('n');
+ return NULL; // Return ERR_MYBAD
}
iface->Next = NULL;
iface->Type = 0; // Unset type
+ iface->Address = iface->Name + nameLen + 1; // Address
+ iface->Route.Network = iface->Address + IPStack_GetAddressSize(-1);
+ iface->Route.NextHop = iface->Route.Network + IPStack_GetAddressSize(-1);
// Create Node
iface->Node.ImplPtr = iface;
iface->TimeoutDelay = DEFAULT_TIMEOUT;
// Get adapter handle
- iface->Adapter = IPStack_GetAdapter(Device);
- if( !iface->Adapter ) {
- free( iface );
- LEAVE('i', -1);
- return -1; // Return ERR_YOUFAIL
- }
+ iface->Adapter = card;
// Delay setting ImplInt until after the adapter is opened
// Keeps things simple
iface->Node.ImplInt = giIP_NextIfaceId++;
+ sprintf(iface->Name, "%i", (int)iface->Node.ImplInt);
// Append to list
SHORTLOCK( &glIP_Interfaces );
// gIP_DriverInfo.RootNode.Size ++;
// Success!
- LEAVE('i', iface->Node.ImplInt);
- return iface->Node.ImplInt;
+ LEAVE('p', iface);
+ return iface;
}
/**
"getset_type",
"get_address", "set_address",
"getset_subnet",
- "get_gateway", "set_gateway",
"get_device",
"ping",
NULL
*/
int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
{
- int tmp;
+ int tmp, size;
tInterface *iface = (tInterface*)Node->ImplPtr;
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:
- tmp = ModUtil_SetIdent(Data, STR(IDENT));
- LEAVE('i', 1);
- return 1;
-
- case DRV_IOCTL_VERSION:
- LEAVE('x', VERSION);
- return VERSION;
-
- case DRV_IOCTL_LOOKUP:
- tmp = ModUtil_LookupString( (char**)casIOCtls_Iface, (char*)Data );
- LEAVE('i', tmp);
- return tmp;
+ BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Iface)
/*
* getset_type
LEAVE('i', -1);
return -1;
}
- switch( *(int*)Data )
- {
- case 0: // Disable
+
+ // Set type
+ iface->Type = *(int*)Data;
+ size = IPStack_GetAddressSize(iface->Type);
+ // Check it's actually valid
+ if( iface->Type != 0 && size == 0 ) {
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;
}
+
+ // Clear address
+ memset(iface->Address, 0, size);
}
LEAVE('i', iface->Type);
return iface->Type;
* - 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);
+ size = IPStack_GetAddressSize(iface->Type);
+ if( !CheckMem( Data, size ) ) LEAVE_RET('i', -1);
+ memcpy( Data, iface->Address, size );
+ LEAVE('i', 1);
+ return 1;
/*
* set_address
- * - Get the interface's address
+ * - Set the interface's address
*/
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);
+
+ size = IPStack_GetAddressSize(iface->Type);
+ if( !CheckMem( Data, size ) ) LEAVE_RET('i', -1);
+ // TODO: Protect against trashing
+ memcpy( iface->Address, Data, size );
+ LEAVE('i', 1);
+ return 1;
/*
* 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;
-
- /*
- * 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)
+ // Do we want to set the value?
+ if( Data )
{
- 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);
+ // Are we root? (TODO: Check Owner/Group)
+ if( Threads_GetUID() != 0 ) LEAVE_RET('i', -1);
+ // Is the memory valid
+ if( !CheckMem(Data, sizeof(int)) ) LEAVE_RET('i', -1);
- case 6:
- LEAVE_RET('i', 1);
+ // Is the mask sane?
+ if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
+ LEAVE_RET('i', -1);
+
+ // Ok, set it
+ iface->SubnetBits = *(int*)Data;
}
- break;
+ LEAVE('i', iface->SubnetBits);
+ return iface->SubnetBits;
/*
* get_device
* - Gets the name of the attached device
*/
- case 10:
+ case 8:
+ if( iface->Adapter == NULL )
+ LEAVE_RET('i', 0);
if( Data == NULL )
LEAVE_RET('i', iface->Adapter->DeviceLen);
if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
* ping
* - Send an ICMP Echo
*/
- case 11:
+ case 9:
switch(iface->Type)
{
case 0:
ENTER("sPath", Path);
+ // Check for loopback
+ if( strcmp(Path, "LOOPBACK") == 0 )
+ {
+ // Initialise if required
+ if( gIP_LoopAdapter.DeviceFD == 0 )
+ {
+ dev = &gIP_LoopAdapter;
+
+ dev->NRef = 1;
+ dev->DeviceLen = 8;
+
+ dev->DeviceFD = VFS_Open( "/Devices/fifo/anon", VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
+ if( dev->DeviceFD == -1 ) {
+ Log_Warning("IPStack", "Unable to open FIFO '/Devices/fifo/anon' for loopback");
+ return NULL;
+ }
+
+ dev->MacAddr.B[0] = 'A';
+ dev->MacAddr.B[1] = 'c';
+ dev->MacAddr.B[2] = 'e';
+ dev->MacAddr.B[3] = 's';
+ dev->MacAddr.B[4] = 's';
+ dev->MacAddr.B[5] = '2';
+
+ // Start watcher
+ Link_WatchDevice( dev );
+ }
+ LEAVE('p', &gIP_LoopAdapter);
+ return &gIP_LoopAdapter;
+ }
+
Mutex_Acquire( &glIP_Adapters );
// Check if this adapter is already open
// Ok, so let's open it
dev = malloc( sizeof(tAdapter) + strlen(Path) + 1 );
if(!dev) {
+ Log_Warning("IPStack", "GetAdapter - malloc() failed");
Mutex_Release( &glIP_Adapters );
LEAVE('n');
return NULL;
tmp = VFS_IOCtl(dev->DeviceFD, 0, NULL);
LOG("Device type = %i", tmp);
if( tmp != DRV_TYPE_NETWORK ) {
- Warning("IPStack_GetAdapter: '%s' is not a network interface", dev->Device);
+ Log_Warning("IPStack", "IPStack_GetAdapter: '%s' is not a network interface", dev->Device);
VFS_Close( dev->DeviceFD );
free( dev );
Mutex_Release( &glIP_Adapters );