windows-nt/Source/XPSP1/NT/net/atm/lane/sys/ioctl.c

1293 lines
27 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997 FORE Systems, Inc.
Copyright (c) 1997 Microsoft Corporation
Module Name:
ioctl.c
Abstract:
IOCTL Handler functions
Author:
Larry Cleeton, FORE Systems (v-lcleet@microsoft.com, lrc@fore.com)
Notes:
--*/
#include <precomp.h>
PATMLANE_ADAPTER
AtmLaneIoctlNameToAdapter(
IN PUNICODE_STRING pDeviceName
)
/*++
Routine Description:
Given the name of an adapter, return a pointer to the corresponding
adapter structure if one exists, else NULL.
This routine also references the adapter.
Arguments:
pDeviceName - Pointer to Device name we are searching for.
Return Value:
See above.
--*/
{
PLIST_ENTRY pListEntry;
PATMLANE_ADAPTER pAdapter;
PATMLANE_ADAPTER pAdapterToReturn = NULL_PATMLANE_ADAPTER;
BOOLEAN bReferenced = FALSE;
TRACEIN(IoctlNameToAdapter);
// fixup the Buffer pointer
pDeviceName->Buffer = (PWSTR)((PUCHAR)pDeviceName + sizeof(UNICODE_STRING));
// loop thru the adapters looking for the ELAN
ACQUIRE_GLOBAL_LOCK(pAtmLaneGlobalInfo);
for (pListEntry = pAtmLaneGlobalInfo->AdapterList.Flink;
pListEntry != &(pAtmLaneGlobalInfo->AdapterList);
pListEntry = pListEntry->Flink)
{
// get pointer to Adapter
pAdapter = CONTAINING_RECORD(pListEntry, ATMLANE_ADAPTER, Link);
STRUCT_ASSERT(pAdapter, atmlane_adapter);
// compare length first and then actual names
if ((pDeviceName->Length == pAdapter->DeviceName.Length) &&
(memcmp(pDeviceName->Buffer,
pAdapter->DeviceName.Buffer,
pDeviceName->Length) == 0))
{
// match - return this adapter
pAdapterToReturn = pAdapter;
ACQUIRE_ADAPTER_LOCK_DPC(pAdapter);
bReferenced = AtmLaneReferenceAdapter(pAdapter, "ioctl");
RELEASE_ADAPTER_LOCK_DPC(pAdapter);
break;
}
}
RELEASE_GLOBAL_LOCK(pAtmLaneGlobalInfo);
TRACEOUT(IoctlNameToAdapter);
return (bReferenced? pAdapterToReturn: NULL);
}
PATMLANE_ELAN
AtmLaneIoctlNameToElan(
IN PATMLANE_ADAPTER pAdapter,
IN PUNICODE_STRING pDeviceName
)
/*++
Routine Description:
Given a pointer to an adapter data structure and an
ELAN device name, return a pointer to the corresponding
ELAN structure if one exists, else NULL.
This also references the ELAN structure.
Arguments:
pAdapter - Pointer to Adapter data structure.
pDeviceName - Pointer to Device name we are searching for.
Return Value:
See above.
--*/
{
PLIST_ENTRY pListEntry;
PATMLANE_ELAN pElan;
PATMLANE_ELAN pElanToReturn = NULL_PATMLANE_ELAN;
TRACEIN(IoctlNameToElan);
STRUCT_ASSERT(pAdapter, atmlane_adapter);
// fixup the Buffer pointer
pDeviceName->Buffer = (PWSTR)((PUCHAR)pDeviceName + sizeof(UNICODE_STRING));
ACQUIRE_ADAPTER_LOCK(pAdapter);
// loop thru the ELANs looking for the given name
for (pListEntry = pAdapter->ElanList.Flink;
pListEntry != &(pAdapter->ElanList);
pListEntry = pListEntry->Flink)
{
// get pointer to ELAN
pElan = CONTAINING_RECORD(pListEntry, ATMLANE_ELAN, Link);
STRUCT_ASSERT(pElan, atmlane_elan);
// compare length first and then actual names
if ((pDeviceName->Length == pElan->CfgDeviceName.Length) &&
(memcmp(pDeviceName->Buffer,
pElan->CfgDeviceName.Buffer,
pDeviceName->Length) == 0))
{
// match - return this ELAN
pElanToReturn = pElan;
ACQUIRE_ELAN_LOCK(pElan);
AtmLaneReferenceElan(pElan, "iocnametoelan");
RELEASE_ELAN_LOCK(pElan);
break;
}
}
RELEASE_ADAPTER_LOCK(pAdapter);
TRACEOUT(IoctlNameToElan);
return (pElanToReturn);
}
NTSTATUS
AtmLaneIoctlGetInfoVersion (
IN PUCHAR pBuffer,
IN UINT InputBufferLength,
IN UINT OutputBufferLength,
IN OUT UINT_PTR * pBytesWritten
)
/*++
Routine Description:
Return the version number of the information exported by
these ioctl codes.
Arguments:
pBuffer - Space for input/output
InputBufferLength - Length of input parameters
OutputBufferLength - Space available for output
pBytesWritten - Where we return the amount we actually used up
Return Value:
Status code
--*/
{
NTSTATUS Status;
TRACEIN(IoctlGetInfoVersion);
// init
*pBytesWritten = 0;
Status = STATUS_SUCCESS;
do
{
// check for enough output space
if (OutputBufferLength < sizeof(ULONG))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// output the version
*((PULONG)pBuffer) = ATMLANE_INFO_VERSION;
*pBytesWritten = sizeof(ULONG);
}
while (FALSE);
TRACEOUT(IoctlGetInfoVersion);
return STATUS_SUCCESS;
}
NTSTATUS
AtmLaneIoctlEnumerateAdapters (
IN PUCHAR pBuffer,
IN UINT InputBufferLength,
IN UINT OutputBufferLength,
IN OUT UINT_PTR * pBytesWritten
)
/*++
Routine Description:
Return a list of adapters bound to the AtmLane protocol.
We go through the list of Adapter structures and concatenate the
device names stored in each into the output buffer.
Arguments:
pBuffer - Space for input/output
InputBufferLength - Length of input parameters
OutputBufferLength - Space available for output
pBytesWritten - Where we return the amount we actually used up
Return Value:
Status code
--*/
{
PATMLANE_ADAPTER pAdapter;
UINT Remaining;
PATMLANE_ADAPTER_LIST pAdapterList;
PUNICODE_STRING pAdapterName;
NTSTATUS Status;
PLIST_ENTRY pListEntry;
TRACEIN(IoctlEnumAdapters);
// init
*pBytesWritten = 0;
Status = STATUS_SUCCESS;
do
{
// check for minimal output space
Remaining = OutputBufferLength;
if (Remaining < sizeof(ATMLANE_ADAPTER_LIST))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
pAdapterList = (PATMLANE_ADAPTER_LIST)pBuffer;
// setup to return empty list
pAdapterList->AdapterCountReturned = 0;
*pBytesWritten = FIELD_OFFSET(ATMLANE_ADAPTER_LIST, AdapterList);
pAdapterName = &pAdapterList->AdapterList;
// adjust space for output
Remaining -= FIELD_OFFSET (ATMLANE_ADAPTER_LIST, AdapterList);
// loop thru the adapters
ACQUIRE_GLOBAL_LOCK(pAtmLaneGlobalInfo);
for (pListEntry = pAtmLaneGlobalInfo->AdapterList.Flink;
pListEntry != &(pAtmLaneGlobalInfo->AdapterList);
pListEntry = pListEntry->Flink)
{
// get pointer to adapter struct
pAdapter = CONTAINING_RECORD(pListEntry, ATMLANE_ADAPTER, Link);
STRUCT_ASSERT(pAdapter, atmlane_adapter);
// quit loop if no more space
if (Remaining < sizeof(NDIS_STRING) + pAdapter->DeviceName.Length)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// count and copy the adapter name
pAdapterList->AdapterCountReturned++;
pAdapterName->Buffer = (PWSTR)((PUCHAR)pAdapterName + sizeof(UNICODE_STRING));
memcpy(pAdapterName->Buffer, pAdapter->DeviceName.Buffer, pAdapter->DeviceName.Length);
pAdapterName->MaximumLength = pAdapterName->Length = pAdapter->DeviceName.Length;
// convert the Buffer pointer to an offset - caller expects it
pAdapterName->Buffer = (PWSTR)((PUCHAR)pAdapterName->Buffer - (PUCHAR)pAdapterList);
// move ptr past the name we just copied
pAdapterName = (PUNICODE_STRING)((PUCHAR)pAdapterName + sizeof(UNICODE_STRING)
+ pAdapter->DeviceName.Length);
// update bytes written and remaining space
*pBytesWritten += sizeof(UNICODE_STRING) + pAdapter->DeviceName.Length;
Remaining -= sizeof(UNICODE_STRING) + pAdapter->DeviceName.Length;
}
// check count available same as count returned
pAdapterList->AdapterCountAvailable = pAdapterList->AdapterCountReturned;
// count any remaining adapters that there wasn't space for
while (pListEntry != &(pAtmLaneGlobalInfo->AdapterList))
{
pAdapterList->AdapterCountAvailable++;
pListEntry = pListEntry->Flink;
}
RELEASE_GLOBAL_LOCK(pAtmLaneGlobalInfo);
} while (FALSE);
TRACEOUT(IoctlEnumerateAdapters);
return (Status);
}
NTSTATUS
AtmLaneIoctlEnumerateElans(
IN PUCHAR pBuffer,
IN UINT InputBufferLength,
IN UINT OutputBufferLength,
IN OUT UINT_PTR * pBytesWritten
)
/*++
Routine Description:
Return a list of adapters bound to the AtmLane protocol.
We go through the list of Adapter structures and concatenate the
device names stored in each into the output buffer.
Arguments:
pBuffer - Space for input/output
InputBufferLength - Length of input parameters
OutputBufferLength - Space available for output
pBytesWritten - Where we return the amount we actually used up
Return Value:
Status code
--*/
{
PATMLANE_ADAPTER pAdapter;
UINT Remaining;
PATMLANE_ELAN_LIST pElanList;
PUNICODE_STRING pElanName;
NTSTATUS Status;
PATMLANE_ELAN pElan;
PLIST_ENTRY pListEntry;
ULONG rc;
TRACEIN(IoctlEnumerateElans);
// init
*pBytesWritten = 0;
Status = STATUS_SUCCESS;
pAdapter = NULL;
do
{
// check if adapter string passed in
if (InputBufferLength < sizeof(UNICODE_STRING))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
if (InputBufferLength < sizeof(UNICODE_STRING) + ((PUNICODE_STRING)pBuffer)->MaximumLength)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// sanity check
if (((PUNICODE_STRING)pBuffer)->MaximumLength < ((PUNICODE_STRING)pBuffer)->Length)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// get the adapter struct from the name
pAdapter = AtmLaneIoctlNameToAdapter((PUNICODE_STRING)pBuffer);
if (pAdapter == NULL_PATMLANE_ADAPTER)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
// check for minimal output space
Remaining = OutputBufferLength;
if (Remaining < sizeof(ATMLANE_ELAN_LIST))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
pElanList = (PATMLANE_ELAN_LIST)pBuffer;
// setup to return empty list
pElanList->ElanCountReturned = 0;
*pBytesWritten = FIELD_OFFSET(ATMLANE_ELAN_LIST, ElanList);
Remaining -= FIELD_OFFSET(ATMLANE_ELAN_LIST, ElanList);
pElanName = &pElanList->ElanList;
// loop thru the Elans
ACQUIRE_ADAPTER_LOCK(pAdapter);
for (pListEntry = pAdapter->ElanList.Flink;
pListEntry != &(pAdapter->ElanList);
pListEntry = pListEntry->Flink)
{
// get pointer to adapter struct
pElan = CONTAINING_RECORD(pListEntry, ATMLANE_ELAN, Link);
STRUCT_ASSERT(pElan, atmlane_elan);
// quit loop if no more space
if (Remaining < sizeof(NDIS_STRING) + pElan->CfgDeviceName.Length)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// count and copy the adapter name
pElanList->ElanCountReturned++;
pElanName->Buffer = (PWSTR)((PUCHAR)pElanName + sizeof(UNICODE_STRING));
memcpy(pElanName->Buffer, pElan->CfgDeviceName.Buffer, pElan->CfgDeviceName.Length);
pElanName->MaximumLength = pElanName->Length = pElan->CfgDeviceName.Length;
// convert the Buffer pointer to an offset - caller expects it
pElanName->Buffer = (PWSTR)((PUCHAR)pElanName->Buffer - (PUCHAR)pElanList);
// move ptr past the name we just copied
pElanName = (PUNICODE_STRING)((PUCHAR)pElanName + sizeof(UNICODE_STRING)
+ pElan->CfgDeviceName.Length);
// update bytes written and remaining space
*pBytesWritten += (sizeof(UNICODE_STRING) + pElan->CfgDeviceName.Length);
Remaining -= sizeof(UNICODE_STRING) + pElan->CfgDeviceName.Length;
}
// set count available same as count returned
pElanList->ElanCountAvailable = pElanList->ElanCountReturned;
// count any remaining adapters that there wasn't space for
while (pListEntry != &(pAdapter->ElanList))
{
pElanList->ElanCountAvailable++;
pListEntry = pListEntry->Flink;
}
RELEASE_ADAPTER_LOCK(pAdapter);
} while (FALSE);
if (pAdapter != NULL)
{
ACQUIRE_ADAPTER_LOCK(pAdapter);
rc = AtmLaneDereferenceAdapter(pAdapter, "ioctl: enumelans");
if (rc != 0)
{
RELEASE_ADAPTER_LOCK(pAdapter);
}
}
TRACEOUT(IoctlEnumerateElans);
return (Status);
}
NTSTATUS
AtmLaneIoctlGetElanInfo(
IN PUCHAR pBuffer,
IN UINT InputBufferLength,
IN UINT OutputBufferLength,
OUT UINT_PTR * pBytesWritten
)
/*++
Routine Description:
Return the state information about a specific Elan.
Arguments:
pBuffer - Space for input/output
InputBufferLength - Length of input parameters
OutputBufferLength - Space available for output
pBytesWritten - Where we return the amount we actually used up
Return Value:
Status Code
--*/
{
PATMLANE_ADAPTER pAdapter;
PATMLANE_ELAN pElan;
PUNICODE_STRING pAdapterNameIn;
PUNICODE_STRING pElanNameIn;
PATMLANE_ELANINFO pElanInfo;
NTSTATUS Status;
ULONG rc;
TRACEIN(IoctlGetElanInfo);
// init
*pBytesWritten = 0;
Status = STATUS_SUCCESS;
pAdapter = NULL;
pElan = NULL;
do
{
// check if adapter string passed in
if (InputBufferLength < sizeof(UNICODE_STRING))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// check if elan string passed in
if (InputBufferLength < ((sizeof(UNICODE_STRING) * 2) +
((PUNICODE_STRING)pBuffer)->MaximumLength))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// sanity check
if (((PUNICODE_STRING)pBuffer)->MaximumLength < ((PUNICODE_STRING)pBuffer)->Length)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// check if minimal output space
if (OutputBufferLength < sizeof(ATMLANE_ELANINFO))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// setup ptrs to input names
pAdapterNameIn = (PUNICODE_STRING)pBuffer;
pElanNameIn = (PUNICODE_STRING)(pBuffer + sizeof(UNICODE_STRING) +
pAdapterNameIn->MaximumLength);
// find adapter struct
pAdapter = AtmLaneIoctlNameToAdapter(pAdapterNameIn);
if (pAdapter == NULL_PATMLANE_ADAPTER)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
// find elan struct - check the lengths passed in first.
InputBufferLength -= (sizeof(UNICODE_STRING) + pAdapterNameIn->MaximumLength);
if (InputBufferLength < sizeof(UNICODE_STRING))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
if (InputBufferLength < sizeof(UNICODE_STRING) + pElanNameIn->MaximumLength)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
if (pElanNameIn->MaximumLength < pElanNameIn->Length)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
pElan = AtmLaneIoctlNameToElan(pAdapter, pElanNameIn);
if (pElan == NULL_PATMLANE_ELAN)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
// setup to fill in ELAN info
pElanInfo = (PATMLANE_ELANINFO)pBuffer;
NdisZeroMemory(pElanInfo, sizeof(ATMLANE_ELANINFO));
ACQUIRE_ELAN_LOCK(pElan);
pElanInfo->ElanNumber = pElan->ElanNumber;
pElanInfo->ElanState = pElan->State;
NdisMoveMemory(
&pElanInfo->AtmAddress,
&pElan->AtmAddress.Address,
ATM_ADDRESS_LENGTH);
NdisMoveMemory(
&pElanInfo->LecsAddress,
&pElan->LecsAddress.Address,
ATM_ADDRESS_LENGTH);
NdisMoveMemory(
&pElanInfo->LesAddress,
&pElan->LesAddress.Address,
ATM_ADDRESS_LENGTH);
NdisMoveMemory(
&pElanInfo->BusAddress,
&pElan->BusAddress.Address,
ATM_ADDRESS_LENGTH);
pElanInfo->LanType = pElan->LanType;
pElanInfo->MaxFrameSizeCode = pElan->MaxFrameSizeCode;
pElanInfo->LecId = SWAPUSHORT(pElan->LecId);
NdisMoveMemory(
pElanInfo->ElanName,
pElan->ElanName,
pElan->ElanNameSize);
if (pElan->LanType == LANE_LANTYPE_TR)
{
NdisMoveMemory(
&pElanInfo->MacAddress,
&pElan->MacAddressTr,
sizeof(MAC_ADDRESS));
}
else
{
NdisMoveMemory(
&pElanInfo->MacAddress,
&pElan->MacAddressEth,
sizeof(MAC_ADDRESS));
}
pElanInfo->ControlTimeout = pElan->ControlTimeout;
pElanInfo->MaxUnkFrameCount = pElan->MaxUnkFrameCount;
pElanInfo->MaxUnkFrameTime = pElan->MaxUnkFrameTime;
pElanInfo->VccTimeout = pElan->VccTimeout;
pElanInfo->MaxRetryCount = pElan->MaxRetryCount;
pElanInfo->AgingTime = pElan->AgingTime;
pElanInfo->ForwardDelayTime = pElan->ForwardDelayTime;
pElanInfo->TopologyChange = pElan->TopologyChange;
pElanInfo->ArpResponseTime = pElan->ArpResponseTime;
pElanInfo->FlushTimeout = pElan->FlushTimeout;
pElanInfo->PathSwitchingDelay = pElan->PathSwitchingDelay;
pElanInfo->LocalSegmentId = pElan->LocalSegmentId;
pElanInfo->McastSendVcType = pElan->McastSendVcType;
pElanInfo->McastSendVcAvgRate = pElan->McastSendVcAvgRate;
pElanInfo->McastSendVcPeakRate = pElan->McastSendVcPeakRate;
pElanInfo->ConnComplTimer = pElan->ConnComplTimer;
RELEASE_ELAN_LOCK(pElan);
*pBytesWritten = sizeof(ATMLANE_ELANINFO);
} while (FALSE);
if (pElan != NULL)
{
ACQUIRE_ELAN_LOCK(pElan);
rc = AtmLaneDereferenceElan(pElan, "ioctl: getelaninfo");
if (rc != 0)
{
RELEASE_ELAN_LOCK(pElan);
}
}
if (pAdapter != NULL)
{
ACQUIRE_ADAPTER_LOCK(pAdapter);
rc = AtmLaneDereferenceAdapter(pAdapter, "ioctl: getelaninfo");
if (rc != 0)
{
RELEASE_ADAPTER_LOCK(pAdapter);
}
}
TRACEOUT(IoctlGetElanInfo);
return (Status);
}
NTSTATUS
AtmLaneIoctlGetElanArpTable(
IN PUCHAR pBuffer,
IN UINT InputBufferLength,
IN UINT OutputBufferLength,
OUT UINT_PTR * pBytesWritten
)
/*++
Routine Description:
Return the ARP table for the specified ELAN.
Arguments:
pBuffer - Space for input/output
InputBufferLength - Length of input parameters
OutputBufferLength - Space available for output
pBytesWritten - Where we return the amount we actually used up
Return Value:
Status code
--*/
{
PATMLANE_ADAPTER pAdapter;
PATMLANE_ELAN pElan;
PUNICODE_STRING pAdapterNameIn;
PUNICODE_STRING pElanNameIn;
PATMLANE_ARPTABLE pArpTable;
PATMLANE_ARPENTRY pArpEntry;
UINT Remaining;
PATMLANE_MAC_ENTRY pMacEntry;
NTSTATUS Status;
UINT i;
ULONG rc;
TRACEIN(IoctlGetElanArpTable);
// init
*pBytesWritten = 0;
Status = STATUS_SUCCESS;
pAdapter = NULL;
pElan = NULL;
do
{
// check if adapter string passed in
if (InputBufferLength < sizeof(UNICODE_STRING))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// sanity check the unicode string fields.
if (((PUNICODE_STRING)pBuffer)->MaximumLength < ((PUNICODE_STRING)pBuffer)->Length)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// check if elan string passed in
if (InputBufferLength < (((sizeof(UNICODE_STRING) * 2) +
((PUNICODE_STRING)pBuffer)->MaximumLength)))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// check if minimum output space
if (OutputBufferLength < sizeof(ATMLANE_ARPTABLE))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// setup ptrs to input names
pAdapterNameIn = (PUNICODE_STRING)pBuffer;
pElanNameIn = (PUNICODE_STRING)(pBuffer + sizeof(UNICODE_STRING) +
pAdapterNameIn->MaximumLength);
// find adapter struct
pAdapter = AtmLaneIoctlNameToAdapter(pAdapterNameIn);
if (pAdapter == NULL_PATMLANE_ADAPTER)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
// find elan struct
pElan = AtmLaneIoctlNameToElan(pAdapter, pElanNameIn);
if (pElan == NULL_PATMLANE_ELAN)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
// setup to return empty list
pArpTable = (PATMLANE_ARPTABLE)pBuffer;
pArpTable->ArpEntriesAvailable = pElan->NumMacEntries;
pArpTable->ArpEntriesReturned = 0;
*pBytesWritten = sizeof(ATMLANE_ARPTABLE);
Remaining = OutputBufferLength - sizeof(ATMLANE_ARPTABLE);
pArpEntry = (PATMLANE_ARPENTRY)(pBuffer + sizeof(ATMLANE_ARPTABLE));
ACQUIRE_ELAN_MAC_TABLE_LOCK(pElan);
// loop thru array of lists
for (i = 0; i < ATMLANE_MAC_TABLE_SIZE; i++)
{
pMacEntry = pElan->pMacTable[i];
while (pMacEntry != NULL_PATMLANE_MAC_ENTRY)
{
// check if enough space remaining
if (Remaining < sizeof(ATMLANE_ARPENTRY))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// output the entry
NdisZeroMemory(pArpEntry, sizeof(ATMLANE_ARPENTRY));
NdisMoveMemory(
pArpEntry->MacAddress,
&pMacEntry->MacAddress,
sizeof(MAC_ADDRESS));
if (pMacEntry->pAtmEntry != NULL_PATMLANE_ATM_ENTRY)
{
NdisMoveMemory(
pArpEntry->AtmAddress,
pMacEntry->pAtmEntry->AtmAddress.Address,
ATM_ADDRESS_LENGTH);
}
// update space used and space remaining
*pBytesWritten += sizeof(ATMLANE_ARPENTRY);
Remaining -= sizeof(ATMLANE_ARPENTRY);
// increment in and out pointers
pArpEntry++;
pMacEntry = pMacEntry->pNextEntry;
// add one to EntriesReturned
pArpTable->ArpEntriesReturned++;
}
}
RELEASE_ELAN_MAC_TABLE_LOCK(pElan);
} while (FALSE);
if (pElan != NULL)
{
ACQUIRE_ELAN_LOCK(pElan);
rc = AtmLaneDereferenceElan(pElan, "ioctl: getelanarp");
if (rc != 0)
{
RELEASE_ELAN_LOCK(pElan);
}
}
if (pAdapter != NULL)
{
ACQUIRE_ADAPTER_LOCK(pAdapter);
rc = AtmLaneDereferenceAdapter(pAdapter, "ioctl: getelanarp");
if (rc != 0)
{
RELEASE_ADAPTER_LOCK(pAdapter);
}
}
TRACEOUT(IoctlGetElanArpTable);
return (Status);
}
NTSTATUS
AtmLaneIoctlGetElanConnectTable(
IN PUCHAR pBuffer,
IN UINT InputBufferLength,
IN UINT OutputBufferLength,
OUT UINT_PTR * pBytesWritten
)
/*++
Routine Description:
Return the Connection table for the specified ELAN.
Arguments:
pBuffer - Space for input/output
InputBufferLength - Length of input parameters
OutputBufferLength - Space available for output
pBytesWritten - Where we return the amount we actually used up
Return Value:
Status code
--*/
{
PATMLANE_ADAPTER pAdapter;
PATMLANE_ELAN pElan;
PUNICODE_STRING pAdapterNameIn;
PUNICODE_STRING pElanNameIn;
PATMLANE_CONNECTTABLE pConnTable;
PATMLANE_CONNECTENTRY pConnEntry;
UINT Remaining;
PATMLANE_ATM_ENTRY pAtmEntry;
NTSTATUS Status;
ULONG rc;
TRACEIN(IoctlGetElanConnectTable);
// init
*pBytesWritten = 0;
Status = STATUS_SUCCESS;
pAdapter = NULL;
pElan = NULL;
do
{
// check if adapter string passed in
if (InputBufferLength < sizeof(UNICODE_STRING))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// check if elan string passed in
if (InputBufferLength < (((sizeof(UNICODE_STRING) * 2) +
((PUNICODE_STRING)pBuffer)->MaximumLength)))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// sanity check
if (((PUNICODE_STRING)pBuffer)->MaximumLength < ((PUNICODE_STRING)pBuffer)->Length)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// check if minimum output space
if (OutputBufferLength < sizeof(ATMLANE_CONNECTTABLE))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// setup ptrs to input names
pAdapterNameIn = (PUNICODE_STRING)pBuffer;
pElanNameIn = (PUNICODE_STRING)(pBuffer + sizeof(UNICODE_STRING) +
pAdapterNameIn->MaximumLength);
// How much of the input buffer do we have left?
InputBufferLength -= (sizeof(UNICODE_STRING) + pAdapterNameIn->MaximumLength);
// validate the ELAN name buffer
if (pElanNameIn->MaximumLength < pElanNameIn->Length)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
if (InputBufferLength < sizeof(UNICODE_STRING) + pElanNameIn->MaximumLength)
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// find adapter struct
pAdapter = AtmLaneIoctlNameToAdapter(pAdapterNameIn);
if (pAdapter == NULL_PATMLANE_ADAPTER)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
// find elan struct
pElan = AtmLaneIoctlNameToElan(pAdapter, pElanNameIn);
if (pElan == NULL_PATMLANE_ELAN)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
// setup to return empty list
pConnTable = (PATMLANE_CONNECTTABLE)pBuffer;
pConnTable->ConnectEntriesAvailable = pElan->NumAtmEntries;
pConnTable->ConnectEntriesReturned = 0;
*pBytesWritten = sizeof(ATMLANE_CONNECTTABLE);
Remaining = OutputBufferLength - sizeof(ATMLANE_CONNECTTABLE);
pConnEntry =
(PATMLANE_CONNECTENTRY)(pBuffer + sizeof(ATMLANE_CONNECTTABLE));
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
// loop thru the list
pAtmEntry = pElan->pAtmEntryList;
while (pAtmEntry != NULL_PATMLANE_ATM_ENTRY)
{
// check if enough space for another entry
if (Remaining < sizeof(ATMLANE_CONNECTENTRY))
{
Status = STATUS_BUFFER_OVERFLOW;
break;
}
// fill in entry
NdisMoveMemory(
pConnEntry->AtmAddress,
&pAtmEntry->AtmAddress.Address,
ATM_ADDRESS_LENGTH
);
pConnEntry->Type = pAtmEntry->Type;
pConnEntry->Vc = (pAtmEntry->pVcList!=NULL_PATMLANE_VC);
pConnEntry->VcIncoming = (pAtmEntry->pVcIncoming!=NULL_PATMLANE_VC);
// update space used and space remaining
*pBytesWritten += sizeof(ATMLANE_CONNECTENTRY);
Remaining -= sizeof(ATMLANE_CONNECTENTRY);
// increment in and out pointers
pConnEntry++;
pAtmEntry = pAtmEntry->pNext;
// add one to EntriesReturned
pConnTable->ConnectEntriesReturned++;
}
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
} while (FALSE);
if (pElan != NULL)
{
ACQUIRE_ELAN_LOCK(pElan);
rc = AtmLaneDereferenceElan(pElan, "ioctl: getelanconntab");
if (rc != 0)
{
RELEASE_ELAN_LOCK(pElan);
}
}
if (pAdapter != NULL)
{
ACQUIRE_ADAPTER_LOCK(pAdapter);
rc = AtmLaneDereferenceAdapter(pAdapter, "ioctl: getelanconntab");
if (rc != 0)
{
RELEASE_ADAPTER_LOCK(pAdapter);
}
}
TRACEOUT(IoctlGetElanConnectTable);
return (Status);
}
NTSTATUS
AtmLaneIoctlRequest(
IN PIRP pIrp
)
/*++
Routine Description:
Starting point for all IOCTL Requests.
Arguments:
pIrp : Pointer to the IRP
pHandled : If request handled TRUE otherwise FALSE
Return Value:
Status of the request
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PUCHAR pBuf;
UINT BufLen;
UINT OutBufLen;
UNICODE_STRING IfName;
PIO_STACK_LOCATION pIrpSp;
TRACEIN(IoctlRequest);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pBuf = pIrp->AssociatedIrp.SystemBuffer;
BufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
OutBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case ATMLANE_IOCTL_GET_INFO_VERSION:
DBGP((3, "IoctlRequest: Get Info Version\n"));
Status = AtmLaneIoctlGetInfoVersion(
pBuf,
BufLen,
OutBufLen,
&pIrp->IoStatus.Information
);
break;
case ATMLANE_IOCTL_ENUM_ADAPTERS:
DBGP((3, "IoctlRequest: Enum Adapters\n"));
Status = AtmLaneIoctlEnumerateAdapters(
pBuf,
BufLen,
OutBufLen,
&pIrp->IoStatus.Information
);
break;
case ATMLANE_IOCTL_ENUM_ELANS:
DBGP((3, "IoctlRequest: Enum ELANs\n"));
Status = AtmLaneIoctlEnumerateElans(
pBuf,
BufLen,
OutBufLen,
&pIrp->IoStatus.Information
);
break;
case ATMLANE_IOCTL_GET_ELAN_INFO:
DBGP((3, "IoctlRequest: Get ELAN Info\n"));
Status = AtmLaneIoctlGetElanInfo(
pBuf,
BufLen,
OutBufLen,
&pIrp->IoStatus.Information
);
break;
case ATMLANE_IOCTL_GET_ELAN_ARP_TABLE:
DBGP((3, "IoctlRequest: Getl ELAN ARP table\n"));
Status = AtmLaneIoctlGetElanArpTable(
pBuf,
BufLen,
OutBufLen,
&pIrp->IoStatus.Information
);
break;
case ATMLANE_IOCTL_GET_ELAN_CONNECT_TABLE:
DBGP((3, "IoctlRequest: Get ELAN Connection table\n"));
Status = AtmLaneIoctlGetElanConnectTable(
pBuf,
BufLen,
OutBufLen,
&pIrp->IoStatus.Information
);
break;
default:
DBGP((0, "IoctlRequest: Unknown control code %x\n",
pIrpSp->Parameters.DeviceIoControl.IoControlCode));
break;
}
TRACEOUT(IoctlRequest);
return (Status);
}