Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1105 lines
24 KiB

/*++
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 ([email protected]) 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;
default:
break; // FALL THROUGH
}
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case ARPS_IOCTL_QUERY_INTERFACES:
DBGPRINT(DBG_LEVEL_NOTICE,
("ArpSHandleIoctlRequest: QUERY_INTERFACES\n"));
BufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
Status = ArpSEnumerateInterfaces(pBuf, &BufLen);
if (NT_SUCCESS(Status))
{
pIrp->IoStatus.Information = BufLen;
}
else
{
pIrp->IoStatus.Information = 0;
}
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 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);
}