1095 lines
23 KiB
C
1095 lines
23 KiB
C
/*++
|
|
|
|
Copyright (c) 1992-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ioctl.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the code to implement the IOCTL interface to the atmarp server.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (jameelh@microsoft.com) July 1996
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include <precomp.h>
|
|
#define _FILENUM_ FILENUM_IOCTL
|
|
|
|
NTSTATUS
|
|
ArpSDispatch(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handler for the ioctl interface - not implemented yet.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject ARP Server device object
|
|
pIrp IRP
|
|
|
|
Return Value:
|
|
|
|
STATUS_NOT_IMPLEMENTED currently
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
NTSTATUS Status;
|
|
static ULONG OpenCount = 0;
|
|
|
|
ARPS_PAGED_CODE( );
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
switch (pIrpSp->MajorFunction)
|
|
{
|
|
case IRP_MJ_CREATE:
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSDispatch: Open Handle\n"));
|
|
|
|
InterlockedIncrement(&OpenCount);
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSDispatch: Close Handle\n"));
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
Status = ArpSHandleIoctlRequest(pIrp, pIrpSp);
|
|
break;
|
|
|
|
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case IRP_MJ_CLEANUP:
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSDispatch: Cleanup Handle\n"));
|
|
Status = STATUS_SUCCESS;
|
|
InterlockedDecrement(&OpenCount);
|
|
break;
|
|
|
|
case IRP_MJ_SHUTDOWN:
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSDispatch: Shutdown\n"));
|
|
ArpSShutDown();
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
if (Status != STATUS_PENDING)
|
|
{
|
|
pIrp->IoStatus.Status = Status;
|
|
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
|
|
}
|
|
else
|
|
{
|
|
IoMarkIrpPending(pIrp);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ArpSHandleIoctlRequest(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PUCHAR pBuf;
|
|
UINT BufLen;
|
|
PINTF pIntF = NULL;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
pBuf = pIrp->AssociatedIrp.SystemBuffer;
|
|
BufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
|
|
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case ARPS_IOCTL_FLUSH_ARPCACHE:
|
|
case ARPS_IOCTL_QUERY_ARPCACHE:
|
|
case ARPS_IOCTL_ADD_ARPENTRY:
|
|
case ARPS_IOCTL_QUERY_IP_FROM_ATM:
|
|
case ARPS_IOCTL_QUERY_ATM_FROM_IP:
|
|
case ARPS_IOCTL_QUERY_ARP_STATISTICS:
|
|
case ARPS_IOCTL_QUERY_MARSCACHE:
|
|
case ARPS_IOCTL_QUERY_MARS_STATISTICS:
|
|
case ARPS_IOCTL_RESET_STATISTICS:
|
|
{
|
|
INTERFACE_NAME RawName;
|
|
UINT Offset;
|
|
|
|
if (pIrpSp->Parameters.DeviceIoControl.IoControlCode == ARPS_IOCTL_QUERY_ARPCACHE)
|
|
{
|
|
Offset = FIELD_OFFSET(IOCTL_QUERY_CACHE, Name);
|
|
}
|
|
else if (pIrpSp->Parameters.DeviceIoControl.IoControlCode == ARPS_IOCTL_QUERY_MARSCACHE)
|
|
{
|
|
Offset = FIELD_OFFSET(IOCTL_QUERY_MARS_CACHE, Name);
|
|
}
|
|
else
|
|
{
|
|
Offset = 0;
|
|
}
|
|
|
|
if (BufLen < sizeof(INTERFACE_NAME) + Offset)
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
RawName = *(PINTERFACE_NAME)((PUCHAR)pBuf + Offset);
|
|
RawName.Buffer = (PWSTR)(pBuf + Offset + (ULONG_PTR)RawName.Buffer); // fixup ptr
|
|
|
|
//
|
|
// Probe away...
|
|
//
|
|
if ( (PUCHAR)RawName.Buffer < (pBuf+sizeof(INTERFACE_NAME))
|
|
|| (PUCHAR)RawName.Buffer >= (pBuf+BufLen)
|
|
|| ((PUCHAR)RawName.Buffer + RawName.Length) > (pBuf+BufLen))
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
pIntF = ArpSReferenceIntFByName(&RawName);
|
|
|
|
if (pIntF == NULL)
|
|
{
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case ARPS_IOCTL_QUERY_INTERFACES:
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: QUERY_INTERFACES\n"));
|
|
pIrp->IoStatus.Information = BufLen;
|
|
Status = ArpSEnumerateInterfaces(pBuf, &pIrp->IoStatus.Information);
|
|
break;
|
|
|
|
case ARPS_IOCTL_FLUSH_ARPCACHE:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: FLUSH_ARPCACHE on %Z\n",
|
|
&pIntF->FriendlyName));
|
|
Status = ArpSFlushArpCache(pIntF);
|
|
pIrp->IoStatus.Information = 0;
|
|
break;
|
|
|
|
case ARPS_IOCTL_QUERY_ARPCACHE:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: QUERY_ARPCACHE on %Z\n",
|
|
&pIntF->FriendlyName));
|
|
pIrp->IoStatus.Information = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
Status = ArpSQueryArpCache(pIntF, pBuf, &pIrp->IoStatus.Information);
|
|
break;
|
|
|
|
#if 0
|
|
//
|
|
// These need more work - commented out as they aren't critical.
|
|
//
|
|
case ARPS_IOCTL_ADD_ARPENTRY:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: QUERY_ADD_ARPENTRY on %Z\n",
|
|
&pIntF->FriendlyName));
|
|
|
|
Status = ArpSQueryOrAddArpEntry(pIntF, (PIOCTL_QA_ENTRY)pBuf, ADD_ARP_ENTRY);
|
|
break;
|
|
|
|
case ARPS_IOCTL_QUERY_IP_FROM_ATM:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: QUERY_IP_ADDR on %Z\n",
|
|
&pIntF->FriendlyName));
|
|
|
|
Status = ArpSQueryOrAddArpEntry(pIntF, (PIOCTL_QA_ENTRY)pBuf, QUERY_IP_FROM_ATM);
|
|
if (Status == STATUS_SUCCESS)
|
|
{
|
|
pIrp->IoStatus.Information = sizeof(IOCTL_QA_ENTRY);
|
|
}
|
|
break;
|
|
|
|
case ARPS_IOCTL_QUERY_ATM_FROM_IP:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: QUERY_ATM_ADDR on %Z\n",
|
|
pIntF->FriendlyName));
|
|
Status = ArpSQueryOrAddArpEntry( pIntF, (PIOCTL_QA_ENTRY)pBuf, QUERY_ATM_FROM_IP );
|
|
if (Status == STATUS_SUCCESS)
|
|
{
|
|
pIrp->IoStatus.Information = sizeof(IOCTL_QA_ENTRY);
|
|
}
|
|
break;
|
|
#endif // 0
|
|
|
|
case ARPS_IOCTL_QUERY_ARP_STATISTICS:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: QUERY_ARP_STATS on %Z\n",
|
|
pIntF->FriendlyName));
|
|
|
|
if (BufLen<sizeof(ARP_SERVER_STATISTICS))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Status = ArpSQueryArpStats( pIntF, (PARP_SERVER_STATISTICS)pBuf);
|
|
if (Status == STATUS_SUCCESS)
|
|
{
|
|
pIrp->IoStatus.Information = sizeof(ARP_SERVER_STATISTICS);
|
|
}
|
|
break;
|
|
|
|
case ARPS_IOCTL_QUERY_MARSCACHE:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: QUERY_MARSCACHE on %Z\n",
|
|
&pIntF->FriendlyName));
|
|
pIrp->IoStatus.Information = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
Status = ArpSQueryMarsCache(pIntF, pBuf, &pIrp->IoStatus.Information);
|
|
break;
|
|
|
|
case ARPS_IOCTL_QUERY_MARS_STATISTICS:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: QUERY_MARS_STATS on %Z\n",
|
|
pIntF->FriendlyName));
|
|
|
|
if (BufLen<sizeof(MARS_SERVER_STATISTICS))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Status = ArpSQueryMarsStats( pIntF, (PMARS_SERVER_STATISTICS)pBuf);
|
|
if (Status == STATUS_SUCCESS)
|
|
{
|
|
pIrp->IoStatus.Information = sizeof(MARS_SERVER_STATISTICS);
|
|
}
|
|
break;
|
|
|
|
case ARPS_IOCTL_RESET_STATISTICS:
|
|
ASSERT (pIntF);
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: RESET_STATISTICS on %Z\n",
|
|
pIntF->FriendlyName));
|
|
|
|
ArpSResetStats(pIntF);
|
|
pIrp->IoStatus.Information = 0;
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("ArpSHandleIoctlRequest: Unknown request %lx\n",
|
|
pIrpSp->Parameters.DeviceIoControl.IoControlCode));
|
|
break;
|
|
}
|
|
|
|
if (pIntF != NULL)
|
|
{
|
|
ArpSDereferenceIntF(pIntF);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ArpSEnumerateInterfaces(
|
|
IN PUCHAR pBuffer,
|
|
IN OUT PULONG_PTR pSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTERFACES pInterfaces = (PINTERFACES)pBuffer;
|
|
PINTERFACE_NAME pInterface;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PINTF pIntF;
|
|
KIRQL OldIrql;
|
|
UINT Size, Total, Remaining;
|
|
PUCHAR pBuf;
|
|
UINT InputSize = (UINT) *pSize;
|
|
ULONG IfIndex;
|
|
|
|
if (InputSize < sizeof(INTERFACES))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
pInterfaces->NumberOfInterfaces = 0;
|
|
pBuf = (PUCHAR)pInterfaces + InputSize;
|
|
|
|
ACQUIRE_SPIN_LOCK(&ArpSIfListLock, &OldIrql);
|
|
|
|
pInterface = &pInterfaces->Interfaces[0];
|
|
for (pIntF = ArpSIfList, Total = 0, Remaining = InputSize, IfIndex = 1;
|
|
pIntF != NULL;
|
|
pIntF = pIntF->Next, pInterface++, IfIndex++)
|
|
{
|
|
if (IfIndex > ArpSIfListSize)
|
|
{
|
|
DbgPrint("ATMARPS: EnumInt: IF list at %p not consistent with list size %d\n",
|
|
ArpSIfList, ArpSIfListSize);
|
|
DbgBreakPoint();
|
|
break;
|
|
}
|
|
|
|
Size = sizeof(INTERFACE_NAME) + pIntF->FriendlyName.Length;
|
|
if (Size > Remaining)
|
|
{
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
break;
|
|
}
|
|
pInterfaces->NumberOfInterfaces ++;
|
|
pInterface->MaximumLength = pInterface->Length = pIntF->FriendlyName.Length;
|
|
pInterface->Buffer = (PWSTR)(pBuf - pIntF->FriendlyName.Length);
|
|
COPY_MEM(pInterface->Buffer, pIntF->FriendlyName.Buffer, pIntF->FriendlyName.Length);
|
|
pBuf -= pIntF->FriendlyName.Length;
|
|
Total += Size;
|
|
Remaining -= Size;
|
|
|
|
//
|
|
// Convert the ptr now to an offset
|
|
//
|
|
pInterface->Buffer = (PWSTR)((ULONG_PTR)pInterface->Buffer - (ULONG_PTR)pInterface);
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ArpSIfListLock, OldIrql);
|
|
|
|
//
|
|
// Note: leave *pSize as is, because we write at the end of the
|
|
// passed-in buffer.
|
|
//
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ArpSFlushArpCache(
|
|
IN PINTF pIntF
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PARP_ENTRY ArpEntry, NextArpEntry;
|
|
KIRQL OldIrql;
|
|
UINT i;
|
|
|
|
//
|
|
// Acquire the ArpCache mutex now.
|
|
//
|
|
WAIT_FOR_OBJECT(Status, &pIntF->ArpCacheMutex, NULL);
|
|
ASSERT (Status == STATUS_SUCCESS);
|
|
|
|
for (i = 0; i < ARP_TABLE_SIZE; i++)
|
|
{
|
|
for (ArpEntry = pIntF->ArpCache[i];
|
|
ArpEntry != NULL;
|
|
ArpEntry = NextArpEntry)
|
|
{
|
|
NextArpEntry = ArpEntry->Next;
|
|
|
|
if (ArpEntry->Vc != NULL)
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
ArpEntry->Vc->ArpEntry = NULL;
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
}
|
|
|
|
if (ArpEntry->Next != NULL)
|
|
{
|
|
((PENTRY_HDR)(ArpEntry->Next))->Prev = ArpEntry->Prev;
|
|
}
|
|
*(ArpEntry->Prev) = ArpEntry->Next;
|
|
ArpSFreeBlock(ArpEntry);
|
|
pIntF->NumCacheEntries --;
|
|
}
|
|
}
|
|
|
|
RELEASE_MUTEX(&pIntF->ArpCacheMutex);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ArpSQueryOrAddArpEntry(
|
|
IN PINTF pIntF,
|
|
IN OUT PIOCTL_QA_ENTRY pQaBuf,
|
|
IN OPERATION Operation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PARP_ENTRY ArpEntry;
|
|
|
|
//
|
|
// Acquire the ArpCache mutex now.
|
|
//
|
|
WAIT_FOR_OBJECT(Status, &pIntF->ArpCacheMutex, NULL);
|
|
ASSERT (Status == STATUS_SUCCESS);
|
|
|
|
switch (Operation)
|
|
{
|
|
case QUERY_IP_FROM_ATM:
|
|
|
|
if ( !ArpSValidAtmAddress(&pQaBuf->ArpEntry.AtmAddress, 0) // TODO
|
|
|| !ArpSValidAtmAddress(&pQaBuf->ArpEntry.SubAddress, 0)) // TODO
|
|
{
|
|
DBGPRINT(DBG_LEVEL_ERROR,
|
|
("QueryIpAddress: Invalid address or subaddress\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("QueryIpAddress for "));
|
|
|
|
ArpSDumpAtmAddr(&pQaBuf->ArpEntry.AtmAddress, "");
|
|
if (pQaBuf->ArpEntry.SubAddress.NumberOfDigits != 0)
|
|
ArpSDumpAtmAddr(&pQaBuf->ArpEntry.SubAddress, "\tSub");
|
|
ArpEntry = ArpSLookupEntryByAtmAddr(pIntF,
|
|
&pQaBuf->ArpEntry.AtmAddress,
|
|
(pQaBuf->ArpEntry.SubAddress.NumberOfDigits != 0) ?
|
|
&pQaBuf->ArpEntry.SubAddress : NULL);
|
|
Status = STATUS_NOT_FOUND;
|
|
if (ArpEntry != NULL)
|
|
{
|
|
pQaBuf->ArpEntry.IpAddr = ArpEntry->IpAddr;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case QUERY_ATM_FROM_IP:
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("QueryAtmAddress for "));
|
|
ArpSDumpIpAddr(pQaBuf->ArpEntry.IpAddr, "");
|
|
ArpEntry = ArpSLookupEntryByIpAddr(pIntF, pQaBuf->ArpEntry.IpAddr);
|
|
Status = STATUS_NOT_FOUND;
|
|
if (ArpEntry != NULL)
|
|
{
|
|
COPY_ATM_ADDR(&pQaBuf->ArpEntry.AtmAddress, &ArpEntry->HwAddr.Address);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
#if 0
|
|
case ADD_ARP_ENTRY:
|
|
|
|
if ( !ArpSValidAtmAddress(&pQaBuf->ArpEntry.AtmAddress, 0) // TODO
|
|
|| !ArpSValidAtmAddress(&pQaBuf->ArpEntry.SubAddress, 0)) // TODO
|
|
{
|
|
DBGPRINT(DBG_LEVEL_ERROR,
|
|
("AddArpEntry: Invalid address or subaddress\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(DBG_LEVEL_NOTICE, ("AddArpEntry: IpAddr "));
|
|
ArpSDumpIpAddr(pQaBuf->ArpEntry.IpAddr, "");
|
|
ArpSDumpAtmAddr(&pQaBuf->ArpEntry.AtmAddress, "");
|
|
if (pQaBuf->ArpEntry.SubAddress.NumberOfDigits != 0)
|
|
ArpSDumpAtmAddr(&pQaBuf->ArpEntry.SubAddress, "\tSub");
|
|
ArpEntry = ArpSAddArpEntry(pIntF,
|
|
pQaBuf->ArpEntry.IpAddr,
|
|
&pQaBuf->ArpEntry.AtmAddress,
|
|
(pQaBuf->ArpEntry.SubAddress.NumberOfDigits != 0) ?
|
|
&pQaBuf->ArpEntry.SubAddress : NULL,
|
|
NULL);
|
|
#endif // 0
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
RELEASE_MUTEX(&pIntF->ArpCacheMutex);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ArpSQueryArpCache(
|
|
IN PINTF pIntF,
|
|
IN PUCHAR pBuf,
|
|
IN OUT PULONG_PTR pSize
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PIOCTL_QUERY_CACHE pQCache = (PIOCTL_QUERY_CACHE)pBuf;
|
|
PARP_ENTRY ArpEntry;
|
|
PARPENTRY Entry;
|
|
UINT i, Total, Remaining;
|
|
UINT InputSize = (UINT) *pSize;
|
|
UINT StartIndex;
|
|
|
|
#define HEADERSIZE (UINT)FIELD_OFFSET(IOCTL_QUERY_CACHE, Entries.Entries)
|
|
|
|
if (InputSize < HEADERSIZE)
|
|
{
|
|
//
|
|
// We don't even have enough space to store the
|
|
// IOCTL_QUERY_CACHE.Entries structure!
|
|
//
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
//
|
|
// Acquire the ArpCache mutex now.
|
|
//
|
|
WAIT_FOR_OBJECT(Status, &pIntF->ArpCacheMutex, NULL);
|
|
ASSERT (Status == STATUS_SUCCESS);
|
|
|
|
StartIndex = pQCache->StartEntryIndex;
|
|
pQCache->Entries.TotalNumberOfEntries = pIntF->NumCacheEntries;
|
|
pQCache->Entries.NumberOfEntriesInBuffer = 0;
|
|
Entry = &pQCache->Entries.Entries[0];
|
|
|
|
for (i = 0, Total = 0, Remaining = InputSize - HEADERSIZE;
|
|
i < ARP_TABLE_SIZE;
|
|
i++)
|
|
{
|
|
for (ArpEntry = pIntF->ArpCache[i];
|
|
ArpEntry != NULL;
|
|
ArpEntry = ArpEntry->Next)
|
|
{
|
|
//
|
|
// Skip entries until we reach entry # StartIndex
|
|
//
|
|
if (StartIndex != 0)
|
|
{
|
|
StartIndex--;
|
|
continue;
|
|
}
|
|
|
|
if (sizeof(*Entry) > Remaining)
|
|
{
|
|
break;
|
|
}
|
|
Remaining -= sizeof(ARPENTRY);
|
|
Entry->IpAddr = ArpEntry->IpAddr;
|
|
Entry->AtmAddress = ArpEntry->HwAddr.Address;
|
|
Entry->SubAddress.NumberOfDigits = 0;
|
|
if (ArpEntry->HwAddr.SubAddress != NULL)
|
|
Entry->SubAddress = *ArpEntry->HwAddr.SubAddress;
|
|
pQCache->Entries.NumberOfEntriesInBuffer ++;
|
|
Entry ++;
|
|
}
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
break;
|
|
}
|
|
|
|
RELEASE_MUTEX(&pIntF->ArpCacheMutex);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ArpSQueryMarsCache(
|
|
IN PINTF pIntF,
|
|
IN PUCHAR pBuf,
|
|
IN OUT PULONG_PTR pSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump the mars cache into pBuf. The structure is QUERY_MARS_CACHE.MarsCache.
|
|
The atm addresses are all placed together at the end of the supplied buffer,
|
|
so the full size, *pSize, is used.
|
|
|
|
Arguments:
|
|
|
|
pIntF - The interface on which the MARS_REQUEST arrived
|
|
Vc - The VC on which the packet arrived
|
|
Header - Points to the request packet
|
|
Packet - Packet where the incoming information is copied
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PMARS_ENTRY pMarsEntry;
|
|
PMARSENTRY pEntry;
|
|
UINT i, Total, Remaining;
|
|
KIRQL OldIrql;
|
|
ATM_ADDRESS *pAtmAddr;
|
|
UINT InputSize;
|
|
UINT StartIndex;
|
|
|
|
PIOCTL_QUERY_MARS_CACHE pQCache = (PIOCTL_QUERY_MARS_CACHE)pBuf;
|
|
|
|
#define MCHEADERSIZE \
|
|
((UINT)FIELD_OFFSET(IOCTL_QUERY_MARS_CACHE, MarsCache.Entries))
|
|
|
|
//
|
|
// Since we put stuff at the end of the buffer, let's force the
|
|
// size to be a multiple of ULONG_PTR size.
|
|
//
|
|
InputSize = (UINT)(*pSize) & ~ ((UINT) (sizeof(ULONG_PTR)-1));
|
|
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("QueryMarsCache: pBuf=0x%lx Size=%lu. pBuf+Size=0x%lx\n",
|
|
pBuf,
|
|
InputSize,
|
|
pBuf+InputSize
|
|
));
|
|
|
|
|
|
if (InputSize < MCHEADERSIZE)
|
|
{
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("QueryMarsCache: Size %lu too small. Want %lu\n",
|
|
InputSize,
|
|
MCHEADERSIZE
|
|
));
|
|
//
|
|
// We don't even have enough space to store the
|
|
// IOCTL_QUERY_CACHE.Entries structure!
|
|
//
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
StartIndex = pQCache->StartEntryIndex;
|
|
|
|
// Acquire the lock on the interface now
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
|
|
pQCache->MarsCache.TotalNumberOfEntries = 0;
|
|
pQCache->MarsCache.Sig = SIG_MARSENTRY;
|
|
pQCache->MarsCache.NumberOfEntriesInBuffer = 0;
|
|
pEntry = &pQCache->MarsCache.Entries[0];
|
|
|
|
//
|
|
// We'll go through the entire cache, but only pick up as many
|
|
// as we have space for. pAtmAddr contains the next location to
|
|
// put an atm address -- it starts out at the end of the buffer and
|
|
// works it's way backwards. Meanwhile, the mars entries are growing
|
|
// forward, starting with pQCache->MarseCache.Entries[1].
|
|
// Needless to say, we must keep track of how much space is left.
|
|
//
|
|
pAtmAddr = ((PATM_ADDRESS) (pBuf + InputSize));
|
|
|
|
|
|
for (i = 0, Total = 0, Remaining = InputSize-MCHEADERSIZE;
|
|
i < MARS_TABLE_SIZE && Status == STATUS_SUCCESS;
|
|
i++)
|
|
{
|
|
for (pMarsEntry = pIntF->MarsCache[i];
|
|
pMarsEntry != NULL && Status == STATUS_SUCCESS;
|
|
pMarsEntry = pMarsEntry->Next)
|
|
{
|
|
PGROUP_MEMBER pGroup;
|
|
UINT NumMembersPickedUp=0;
|
|
|
|
//
|
|
// Skip entries until we reach entry # StartIndex
|
|
//
|
|
if (StartIndex != 0)
|
|
{
|
|
StartIndex--;
|
|
continue;
|
|
}
|
|
|
|
if (sizeof(*pEntry) > Remaining)
|
|
{
|
|
DBGPRINT(
|
|
DBG_LEVEL_NOTICE,
|
|
("QueryMarsCache: \tOut of space. Remaining=%lu\n", Remaining));
|
|
break;
|
|
}
|
|
|
|
|
|
DBGPRINT(
|
|
DBG_LEVEL_NOTICE,
|
|
("QueryMarsCache: \tPicking up Group 0x%x. IP=0x%08lx NumAddr=%lu pE=0x%x Remaining=%lu\n",
|
|
pMarsEntry,
|
|
pMarsEntry->IPAddress,
|
|
pMarsEntry->NumMembers,
|
|
pEntry,
|
|
Remaining));
|
|
|
|
|
|
Remaining -= sizeof(*pEntry);
|
|
|
|
pQCache->MarsCache.NumberOfEntriesInBuffer ++;
|
|
GETULONG2ULONG(&(pEntry->IpAddr), &(pMarsEntry->IPAddress));
|
|
pEntry->Flags = 0;
|
|
pEntry->NumAtmAddresses = pMarsEntry->NumMembers;
|
|
pEntry->OffsetAtmAddresses = 0;
|
|
|
|
if (MarsIsAddressMcsServed(pIntF, pMarsEntry->IPAddress))
|
|
{
|
|
pEntry->Flags |= MARSENTRY_MCS_SERVED;
|
|
}
|
|
|
|
//
|
|
// Pick up the HW addresses of all the members of this group.
|
|
// (TODO: We don't pick up the subaddress).
|
|
//
|
|
for (
|
|
pGroup = pMarsEntry->pMembers, NumMembersPickedUp=0;
|
|
pGroup != NULL;
|
|
pGroup = pGroup->Next, NumMembersPickedUp++)
|
|
{
|
|
ARPS_ASSERT(pGroup != NULL_PGROUP_MEMBER);
|
|
|
|
//
|
|
// Check that we have enough space.
|
|
//
|
|
if (Remaining < sizeof(*pAtmAddr))
|
|
{
|
|
//
|
|
// If there is not enough space to store all atm addresses
|
|
// of a particular group, we return none, this is indicated
|
|
// by setting pEntry->OffsetAtmAdresses to 0.
|
|
//
|
|
DBGPRINT(
|
|
DBG_LEVEL_NOTICE,
|
|
("QueryMarsCache: \t\tOut of space adding addreses. Remaining=%lu\n", Remaining));
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
break;
|
|
}
|
|
ARPS_ASSERT( (PUCHAR)(pAtmAddr-1) >= (PUCHAR)(pEntry+1));
|
|
|
|
//
|
|
// Copy over the atm address
|
|
//
|
|
DBGPRINT(
|
|
DBG_LEVEL_NOTICE,
|
|
("QueryMarsCache: \t\tPicking up Addr. pDestAddr=%x. Remaining=%lu\n",
|
|
pAtmAddr-1,
|
|
Remaining));
|
|
*--pAtmAddr = pGroup->pClusterMember->HwAddr.Address;
|
|
Remaining -= sizeof(*pAtmAddr);
|
|
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS && NumMembersPickedUp)
|
|
{
|
|
//
|
|
// There are non-zero members of this entry and they were
|
|
// all copied successfully. Let's set the offset to these
|
|
// addresses.
|
|
//
|
|
pEntry->OffsetAtmAddresses =
|
|
(UINT) ((PUCHAR)pAtmAddr - (PUCHAR) pEntry);
|
|
|
|
//
|
|
// We expect NumMembersPickedUp to be equal to
|
|
// pMarsEntry->NumMembers.
|
|
//
|
|
ARPS_ASSERT(pMarsEntry->NumMembers == NumMembersPickedUp);
|
|
|
|
if (pMarsEntry->NumMembers != NumMembersPickedUp)
|
|
{
|
|
pEntry->NumAtmAddresses = NumMembersPickedUp;
|
|
}
|
|
|
|
DBGPRINT(
|
|
DBG_LEVEL_NOTICE,
|
|
("QueryMarsCache: \t Picked up all addresses. OffsetAtmAddresses = %lu\n",
|
|
pEntry->OffsetAtmAddresses));
|
|
|
|
pEntry++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
pQCache->MarsCache.TotalNumberOfEntries =
|
|
pQCache->MarsCache.NumberOfEntriesInBuffer; // TODO
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
return Status;
|
|
}
|
|
|
|
UINT
|
|
ArpSElapsedSeconds(
|
|
IN PLARGE_INTEGER pStatisticsStartTimeStamp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the elapsed time, in seconds, relative to *pStatisticsStartTimeStamp
|
|
|
|
Arguments:
|
|
|
|
pStatisticsStartTimeStamp ptr to the start time.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
UINT Ret;
|
|
LARGE_INTEGER Current;
|
|
NdisGetCurrentSystemTime(&Current);
|
|
|
|
//
|
|
// Current is in units of 100-nanoseconds so we must convert the difference
|
|
// to seconds. Note we use implicit large-arithmetic operators here.
|
|
//
|
|
Ret = (UINT) ((Current.QuadPart - pStatisticsStartTimeStamp->QuadPart)/10000000);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
extern
|
|
NTSTATUS
|
|
ArpSQueryArpStats(
|
|
IN PINTF pIntF,
|
|
OUT PARP_SERVER_STATISTICS pArpStats
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill in the current arp statistics. Also set the ElapsedSeconds field
|
|
to the time in seconds since statistics computation started.
|
|
|
|
Arguments:
|
|
|
|
pIntF - The interface applicable to the request
|
|
pArpStats - Arp statistics to fill out
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
*pArpStats = pIntF->ArpStats; // big structure copy.
|
|
|
|
pArpStats->ElapsedSeconds = ArpSElapsedSeconds(
|
|
&(pIntF->StatisticsStartTimeStamp)
|
|
);
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
extern
|
|
NTSTATUS
|
|
ArpSQueryMarsStats(
|
|
IN PINTF pIntF,
|
|
OUT PMARS_SERVER_STATISTICS pMarsStats
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill in the current mars statistics. Also set the ElapsedSeconds field
|
|
to the time in seconds since statistics computation started.
|
|
|
|
Arguments:
|
|
|
|
pIntF - The interface applicable to the request
|
|
pMarsStats - Mars statistics to fill out.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
*pMarsStats = pIntF->MarsStats; // big structure copy.
|
|
|
|
pMarsStats->ElapsedSeconds = ArpSElapsedSeconds(
|
|
&(pIntF->StatisticsStartTimeStamp)
|
|
);
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
extern
|
|
VOID
|
|
ArpSResetStats(
|
|
IN PINTF pIntF
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reset all arp and mars statistics. Update the statistics start timestamp.
|
|
|
|
Arguments:
|
|
|
|
pIntF - The interface on which the MARS_REQUEST arrived
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
ZERO_MEM(&(pIntF->ArpStats), sizeof(pIntF->ArpStats));
|
|
ZERO_MEM(&(pIntF->MarsStats), sizeof(pIntF->MarsStats));
|
|
|
|
NdisGetCurrentSystemTime(&(pIntF->StatisticsStartTimeStamp));
|
|
|
|
//
|
|
// Now recompute the "current" and "max" values...
|
|
//
|
|
|
|
//
|
|
// Arp cache entries
|
|
//
|
|
pIntF->ArpStats.CurrentArpEntries
|
|
= pIntF->ArpStats.MaxArpEntries
|
|
= pIntF->NumCacheEntries;
|
|
|
|
//
|
|
// Cluster member count
|
|
//
|
|
{
|
|
pIntF->MarsStats.CurrentClusterMembers
|
|
= pIntF->MarsStats.MaxClusterMembers
|
|
= pIntF->NumClusterMembers;
|
|
}
|
|
|
|
//
|
|
// MCast group count and max group-size - we have to go through the entire
|
|
// mars cache to get this information.
|
|
//
|
|
{
|
|
UINT u;
|
|
UINT MaxGroupSize;
|
|
UINT NumGroups;
|
|
|
|
for (u = 0, MaxGroupSize = 0, NumGroups = 0;
|
|
u < MARS_TABLE_SIZE;
|
|
u++)
|
|
{
|
|
PMARS_ENTRY pMarsEntry;
|
|
|
|
for (pMarsEntry = pIntF->MarsCache[u];
|
|
pMarsEntry != NULL;
|
|
pMarsEntry = pMarsEntry->Next)
|
|
{
|
|
if (MaxGroupSize < pMarsEntry->NumMembers)
|
|
{
|
|
MaxGroupSize = pMarsEntry->NumMembers;
|
|
}
|
|
NumGroups++;
|
|
}
|
|
}
|
|
|
|
pIntF->MarsStats.CurrentGroups
|
|
= pIntF->MarsStats.MaxGroups
|
|
= NumGroups;
|
|
|
|
pIntF->MarsStats.MaxAddressesPerGroup = MaxGroupSize;
|
|
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
}
|