ARP query support.

Thanks to WaxDragon for encouragement and debugging.

svn path=/branches/ros-branch-0_3_1/; revision=24226
This commit is contained in:
Art Yerkes
2006-09-22 06:36:16 +00:00
parent 59c2e127cc
commit 50ee081131
10 changed files with 271 additions and 10 deletions
+30 -3
View File
@@ -40,7 +40,7 @@
#include "ifenum.h"
#include <assert.h>
#define NDEBUG
//#define NDEBUG
#include "debug.h"
/* Globals */
@@ -124,6 +124,7 @@ NTSTATUS tdiGetSetOfThings( HANDLE tcpFile,
DWORD toiType,
DWORD toiId,
DWORD teiEntity,
DWORD teiInstance,
DWORD fixedPart,
DWORD entrySize,
PVOID *tdiEntitySet,
@@ -148,6 +149,7 @@ NTSTATUS tdiGetSetOfThings( HANDLE tcpFile,
req.ID.toi_type = toiType;
req.ID.toi_id = toiId;
req.ID.toi_entity.tei_entity = teiEntity;
req.ID.toi_entity.tei_instance = teiInstance;
/* There's a subtle problem here...
* If an interface is added at this exact instant, (as if by a PCMCIA
@@ -168,7 +170,7 @@ NTSTATUS tdiGetSetOfThings( HANDLE tcpFile,
&allocationSizeForEntityArray,
NULL );
if(!status)
if(!NT_SUCCESS(status))
{
DPRINT("IOCTL Failed\n");
return STATUS_UNSUCCESSFUL;
@@ -285,6 +287,7 @@ NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile,
INFO_TYPE_PROVIDER,
ENTITY_LIST_ID,
GENERIC_ENTITY,
0,
0,
sizeof(TDIEntityID),
(PVOID *)entitySet,
@@ -303,7 +306,7 @@ NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile,
return status;
}
static BOOL isInterface( TDIEntityID *if_maybe ) {
BOOL isInterface( TDIEntityID *if_maybe ) {
return
if_maybe->tei_entity == IF_ENTITY;
}
@@ -348,6 +351,30 @@ NTSTATUS tdiGetEntityType( HANDLE tcpFile, TDIEntityID *ent, PULONG type ) {
return (status ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
BOOL hasArp( HANDLE tcpFile, TDIEntityID *arp_maybe ) {
TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
NTSTATUS status = STATUS_SUCCESS;
DWORD returnSize, type;
req.ID.toi_class = INFO_CLASS_GENERIC;
req.ID.toi_type = INFO_TYPE_PROVIDER;
req.ID.toi_id = ENTITY_TYPE_ID;
req.ID.toi_entity.tei_entity = AT_ENTITY;
req.ID.toi_entity.tei_instance = arp_maybe->tei_instance;
status = DeviceIoControl( tcpFile,
IOCTL_TCP_QUERY_INFORMATION_EX,
&req,
sizeof(req),
&type,
sizeof(type),
&returnSize,
NULL );
if( !NT_SUCCESS(status) ) return FALSE;
return type == AT_ENTITY;
}
static NTSTATUS getInterfaceInfoSet( HANDLE tcpFile,
IFInfo **infoSet,
PDWORD numInterfaces ) {
@@ -118,7 +118,8 @@ VOID closeTcpFile(HANDLE tcpFile);
NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile, TDIEntityID **entitySet,
PDWORD numEntities );
NTSTATUS tdiGetSetOfThings( HANDLE tcpFile, DWORD toiClass, DWORD toiType,
DWORD toiId, DWORD teiEntity, DWORD fixedPart,
DWORD toiId, DWORD teiEntity, DWORD teiInstance,
DWORD fixedPart,
DWORD entrySize, PVOID *tdiEntitySet,
PDWORD numEntries );
VOID tdiFreeThingSet( PVOID things );
@@ -134,6 +135,8 @@ PWCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n );
void ConsumeChildKeyName( PWCHAR Name );
PWCHAR QueryRegistryValueString( HANDLE RegHandle, PWCHAR ValueName );
void ConsumeRegValueString( PWCHAR NameServer );
BOOL isInterface( TDIEntityID *if_maybe );
BOOL hasArp( HANDLE tcpFile, TDIEntityID *arp_maybe );
#include <w32api.h>
/* This is here until we switch to version 2.5 of the mingw headers */
+98 -2
View File
@@ -183,6 +183,7 @@ NTSTATUS tdiGetRoutesForIpEntity
INFO_TYPE_PROVIDER,
IP_MIB_ROUTETABLE_ENTRY_ID,
ent->tei_entity,
0,
0,
sizeof(IPRouteEntry),
(PVOID *)routes,
@@ -203,6 +204,7 @@ NTSTATUS tdiGetIpAddrsForIpEntity
INFO_TYPE_PROVIDER,
IP_MIB_ADDRTABLE_ENTRY_ID,
ent->tei_entity,
0,
0,
sizeof(IPAddrEntry),
(PVOID *)addrs,
@@ -507,12 +509,106 @@ RouteTable *getRouteTable(void)
DWORD getNumArpEntries(void)
{
return getNumWithOneHeader("/proc/net/arp");
DWORD numEntities;
TDIEntityID *entitySet = NULL;
HANDLE tcpFile;
int i, totalNumber = 0;
NTSTATUS status;
PMIB_IPNETROW IpArpTable = NULL;
DWORD returnSize;
TRACE("called.\n");
status = openTcpFile( &tcpFile );
if( !NT_SUCCESS(status) ) {
TRACE("failure: %08x\n", (int)status );
return 0;
}
status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
for( i = 0; i < numEntities; i++ ) {
if( isInterface( &entitySet[i] ) &&
hasArp( tcpFile, &entitySet[i] ) ) {
status = tdiGetSetOfThings( tcpFile,
INFO_CLASS_PROTOCOL,
INFO_TYPE_PROVIDER,
IP_MIB_ARPTABLE_ENTRY_ID,
AT_ENTITY,
entitySet[i].tei_instance,
0,
sizeof(MIB_IPNETROW),
(PVOID *)&IpArpTable,
&returnSize );
if( status == STATUS_SUCCESS ) totalNumber += returnSize;
if( IpArpTable ) tdiFreeThingSet( IpArpTable );
}
}
closeTcpFile( tcpFile );
if( IpArpTable ) tdiFreeThingSet( IpArpTable );
if( entitySet ) tdiFreeThingSet( entitySet );
return totalNumber;
}
PMIB_IPNETTABLE getArpTable(void)
{
return 0;
DWORD numEntities, returnSize;
TDIEntityID *entitySet;
HANDLE tcpFile;
int i, row = 0, totalNumber;
NTSTATUS status;
PMIB_IPNETTABLE IpArpTable = NULL;
PMIB_IPNETROW AdapterArpTable = NULL;
TRACE("called.\n");
totalNumber = getNumArpEntries();
status = openTcpFile( &tcpFile );
if( !NT_SUCCESS(status) ) {
TRACE("failure: %08x\n", (int)status );
return 0;
}
IpArpTable = HeapAlloc
( GetProcessHeap(), 0,
sizeof(DWORD) + (sizeof(MIB_IPNETROW) * totalNumber) );
status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
for( i = 0; i < numEntities; i++ ) {
if( isIpEntity( tcpFile, &entitySet[i] ) &&
hasArp( tcpFile, &entitySet[i] ) ) {
status = tdiGetSetOfThings( tcpFile,
INFO_CLASS_PROTOCOL,
INFO_TYPE_PROVIDER,
IP_MIB_ARPTABLE_ENTRY_ID,
AT_ENTITY,
entitySet[i].tei_instance,
0,
sizeof(MIB_IPNETROW),
(PVOID *)&AdapterArpTable,
&returnSize );
if( status == STATUS_SUCCESS ) {
for( row = 0; row < returnSize; row++ )
IpArpTable->table[row] = AdapterArpTable[row];
}
if( AdapterArpTable ) tdiFreeThingSet( AdapterArpTable );
}
}
tdiFreeThingSet( entitySet );
IpArpTable->dwNumEntries = row;
return IpArpTable;
}
DWORD getNumUdpEntries(void)
@@ -46,6 +46,19 @@ typedef struct IPADDR_ENTRY {
USHORT Pad;
} IPADDR_ENTRY, *PIPADDR_ENTRY;
#define ARP_ENTRY_STATIC 4
#define ARP_ENTRY_DYNAMIC 3
#define ARP_ENTRY_INVALID 2
#define ARP_ENTRY_OTHER 1
typedef struct IPARP_ENTRY {
ULONG Index;
ULONG AddrSize;
UCHAR PhysAddr[8];
ULONG LogAddr;
ULONG Type;
} IPARP_ENTRY, *PIPARP_ENTRY;
typedef struct IPROUTE_ENTRY {
ULONG Dest;
ULONG Index; //matches if_index in IFEntry and iae_index in IPAddrEntry
@@ -96,6 +109,9 @@ typedef struct IFENTRY {
#ifndef IP_MIB_ADDRTABLE_ENTRY_ID
#define IP_MIB_ADDRTABLE_ENTRY_ID 0x102
#endif
#ifndef IP_MIB_ARPTABLE_ENTRY_ID
#define IP_MIB_ARPTABLE_ENTRY_ID 0x101
#endif
#ifndef MAX_PHYSADDR_SIZE
#define MAX_PHYSADDR_SIZE 8
#endif
@@ -107,6 +107,10 @@ BOOLEAN NBQueuePacket(
VOID NBRemoveNeighbor(
PNEIGHBOR_CACHE_ENTRY NCE);
DWORD NBCopyNeighbors(
PIP_INTERFACE Interface,
PIPARP_ENTRY ArpTable);
#endif /* __NEIGHBOR_H */
/* EOF */
@@ -14,6 +14,7 @@
#include <checksum.h>
#include <address.h>
#include <routines.h>
#include <info.h>
#include <neighbor.h>
#include <route.h>
#include <receive.h>
@@ -29,7 +30,6 @@
#include <tilists.h>
#include <dispatch.h>
#include <fileobjs.h>
#include <info.h>
#include <lock.h>
#include <wait.h>
#include <bug.h>
+48 -3
View File
@@ -78,6 +78,42 @@ TDI_STATUS InfoTdiQueryGetInterfaceMIB(TDIEntityID *ID,
return Status;
}
TDI_STATUS InfoTdiQueryGetArptableMIB(TDIEntityID *ID,
PIP_INTERFACE Interface,
PNDIS_BUFFER Buffer,
PUINT BufferSize) {
NTSTATUS Status;
DWORD NumNeighbors = NBCopyNeighbors( Interface, NULL );
DWORD MemSize = NumNeighbors * sizeof(IPARP_ENTRY);
PIPARP_ENTRY ArpEntries =
ExAllocatePoolWithTag
( NonPagedPool, MemSize, FOURCC('A','R','P','t') );
if( !ArpEntries ) return STATUS_NO_MEMORY;
NBCopyNeighbors( Interface, ArpEntries );
Status = InfoCopyOut( (PVOID)ArpEntries, MemSize, Buffer, BufferSize );
ExFreePool( ArpEntries );
return Status;
}
TDI_STATUS InfoTdiQueryGetArpCapability(TDIEntityID *ID,
PIP_INTERFACE Interface,
PNDIS_BUFFER Buffer,
PUINT BufferSize) {
NTSTATUS Status;
DWORD Capability = 0x280;
TI_DbgPrint(MID_TRACE,("Copying out %d bytes (AT_ENTITY capability)\n",
sizeof(Capability)));
Status = InfoCopyOut
( (PVOID)&Capability, sizeof(Capability), Buffer, BufferSize );
return Status;
}
TDI_STATUS InfoInterfaceTdiQueryEx( UINT InfoClass,
UINT InfoType,
UINT InfoId,
@@ -87,13 +123,22 @@ TDI_STATUS InfoInterfaceTdiQueryEx( UINT InfoClass,
PUINT BufferSize ) {
if( InfoClass == INFO_CLASS_GENERIC &&
InfoType == INFO_TYPE_PROVIDER &&
InfoId == ENTITY_TYPE_ID ) {
ULONG Temp = IF_MIB;
return InfoCopyOut( (PCHAR)&Temp, sizeof(Temp), Buffer, BufferSize );
InfoId == ENTITY_TYPE_ID &&
id->tei_entity == AT_ENTITY ) {
return InfoTdiQueryGetArpCapability( id, Context, Buffer, BufferSize );
} else if( InfoClass == INFO_CLASS_PROTOCOL &&
InfoType == INFO_TYPE_PROVIDER &&
InfoId == IF_MIB_STATS_ID ) {
return InfoTdiQueryGetInterfaceMIB( id, Context, Buffer, BufferSize );
} else if( InfoClass == INFO_CLASS_GENERIC &&
InfoType == INFO_TYPE_PROVIDER &&
InfoId == ENTITY_TYPE_ID ) {
ULONG Temp = IF_MIB;
return InfoCopyOut( (PCHAR)&Temp, sizeof(Temp), Buffer, BufferSize );
} else if( InfoClass == INFO_CLASS_PROTOCOL &&
InfoType == INFO_TYPE_PROVIDER &&
InfoId == IP_MIB_ARPTABLE_ENTRY_ID ) {
return InfoTdiQueryGetArptableMIB( id, Context, Buffer, BufferSize );
} else
return TDI_INVALID_REQUEST;
}
@@ -164,6 +164,35 @@ TDI_STATUS InfoTdiQueryInformationEx(
Status = TDI_INVALID_PARAMETER;
} else
Status = InfoTdiQueryListEntities(Buffer, BufferSize);
} else if (ID->toi_entity.tei_entity == AT_ENTITY) {
TcpipAcquireSpinLock( &EntityListLock, &OldIrql );
for( i = 0; i < EntityCount; i++ ) {
if( EntityList[i].tei_entity == IF_ENTITY &&
EntityList[i].tei_instance == ID->toi_entity.tei_instance ) {
InfoRequest = EntityList[i].info_req;
context = EntityList[i].context;
FoundEntity = TRUE;
break;
}
}
TcpipReleaseSpinLock( &EntityListLock, OldIrql );
if( FoundEntity ) {
TI_DbgPrint(DEBUG_INFO,
("Calling AT Entity %d (%04x:%d) InfoEx (%x,%x,%x)\n",
i, ID->toi_entity.tei_entity,
ID->toi_entity.tei_instance,
ID->toi_class, ID->toi_type, ID->toi_id));
Status = InfoRequest( ID->toi_class,
ID->toi_type,
ID->toi_id,
context,
&ID->toi_entity,
Buffer,
BufferSize );
}
} else {
TcpipAcquireSpinLock( &EntityListLock, &OldIrql );
+1
View File
@@ -45,6 +45,7 @@
#define IF_MIB_STATS_ID 1
#define IP_MIB_STATS_ID 1
#define IP_MIB_ARPTABLE_ENTRY_ID 0x101
#define IP_MIB_ADDRTABLE_ENTRY_ID 0x102
#define IP_INTFC_INFO_ID 0x103
#define MAX_PHYSADDR_SIZE 8
+40
View File
@@ -514,3 +514,43 @@ VOID NBRemoveNeighbor(
TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
}
ULONG NBCopyNeighbors
(PIP_INTERFACE Interface,
PIPARP_ENTRY ArpTable)
{
PNEIGHBOR_CACHE_ENTRY CurNCE;
KIRQL OldIrql;
UINT Size = 0, i;
for (i = 0; i <= NB_HASHMASK; i++) {
TcpipAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);
for( CurNCE = NeighborCache[i].Cache;
CurNCE;
CurNCE = CurNCE->Next ) {
if( CurNCE->Interface == Interface ) {
if( ArpTable ) {
ArpTable[Size].Index = Interface->Index;
ArpTable[Size].AddrSize = CurNCE->LinkAddressLength;
RtlCopyMemory
(ArpTable[Size].PhysAddr,
CurNCE->LinkAddress,
CurNCE->LinkAddressLength);
ArpTable[Size].LogAddr = CurNCE->Address.Address.IPv4Address;
if( CurNCE->State & NUD_PERMANENT )
ArpTable[Size].Type = ARP_ENTRY_STATIC;
else if( CurNCE->State & NUD_CONNECTED )
ArpTable[Size].Type = ARP_ENTRY_DYNAMIC;
else if( !(CurNCE->State & NUD_VALID) )
ArpTable[Size].Type = ARP_ENTRY_INVALID;
else
ArpTable[Size].Type = ARP_ENTRY_OTHER;
}
Size++;
}
}
TcpipReleaseSpinLock(&NeighborCache[i].Lock, OldIrql);
}
return Size;
}