1084 lines
25 KiB
C
1084 lines
25 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
ioctl.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains the ioctl interface to this driver
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Anil Francis Thomas (10/98)
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel
|
||
|
|
||
|
Revision History:
|
||
|
DChen 092499 Bug fixes
|
||
|
|
||
|
--*/
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
|
||
|
#define MODULE_ID MODULE_IOCTL
|
||
|
|
||
|
|
||
|
NTSTATUS AtmSmDispatch(
|
||
|
IN PDEVICE_OBJECT pDeviceObject,
|
||
|
IN PIRP pIrp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the common dispath routine for user Ioctls
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ULONG ulBytesWritten = 0;
|
||
|
PIO_STACK_LOCATION pIrpSp;
|
||
|
|
||
|
|
||
|
TraceIn(AtmSmDispatch);
|
||
|
|
||
|
//
|
||
|
// Get current Irp stack location
|
||
|
//
|
||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
|
|
||
|
pIrp->IoStatus.Information = 0;
|
||
|
|
||
|
switch(pIrpSp->MajorFunction)
|
||
|
{
|
||
|
|
||
|
case IRP_MJ_CREATE: {
|
||
|
|
||
|
DbgLoud(("IRP_MJ_CREATE\n"));
|
||
|
|
||
|
InterlockedIncrement(&AtmSmGlobal.ulNumCreates);
|
||
|
Status = STATUS_SUCCESS;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IRP_MJ_CLOSE: {
|
||
|
|
||
|
DbgLoud(("IRP_MJ_CLOSE\n"));
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IRP_MJ_CLEANUP: {
|
||
|
|
||
|
DbgLoud(("IRP_MJ_CLEANUP\n"));
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
|
||
|
InterlockedDecrement(&AtmSmGlobal.ulNumCreates);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IRP_MJ_DEVICE_CONTROL: {
|
||
|
|
||
|
ULONG ulControlCode;
|
||
|
ULONG ulControlFunc;
|
||
|
|
||
|
ulControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
|
||
|
ulControlFunc = IoGetFunctionCodeFromCtlCode(ulControlCode);
|
||
|
|
||
|
// verify the IOCTL codes
|
||
|
if(DEVICE_TYPE_FROM_CTL_CODE(ulControlCode) == FILE_DEVICE_ATMSM &&
|
||
|
ulControlFunc < ATMSM_NUM_IOCTLS &&
|
||
|
AtmSmIoctlTable[ulControlFunc] == ulControlCode)
|
||
|
{
|
||
|
// set the status to PENDING by default
|
||
|
pIrp->IoStatus.Status = STATUS_PENDING;
|
||
|
|
||
|
Status = (*AtmSmFuncProcessIoctl[ulControlFunc])(pIrp, pIrpSp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DbgErr(("Unknown IRP_MJ_DEVICE_CONTROL code - %x\n",
|
||
|
ulControlCode));
|
||
|
Status = STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default: {
|
||
|
|
||
|
DbgErr(("Unknown IRP_MJ_XX - %x\n",pIrpSp->MajorFunction));
|
||
|
|
||
|
Status = STATUS_INVALID_PARAMETER;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if(STATUS_PENDING != Status)
|
||
|
{
|
||
|
pIrp->IoStatus.Status = Status;
|
||
|
|
||
|
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
|
||
|
}
|
||
|
|
||
|
TraceOut(AtmSmDispatch);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS AtmSmIoctlEnumerateAdapters(
|
||
|
PIRP pIrp,
|
||
|
PIO_STACK_LOCATION pIrpSp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called to enumerate the adapters that we are bound to.
|
||
|
|
||
|
NOTE! This uses buffered I/O
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status - doesn't pend
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
ULONG ulNum, ulOutputBufLen, ulNeededSize;
|
||
|
PADAPTER_INFO pAdaptInfo = (PADAPTER_INFO)
|
||
|
pIrp->AssociatedIrp.SystemBuffer;
|
||
|
PATMSM_ADAPTER pAdapt;
|
||
|
|
||
|
|
||
|
TraceIn(AtmSmIoctlEnumerateAdapters);
|
||
|
|
||
|
ulOutputBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
|
||
|
|
||
|
ACQUIRE_GLOBAL_LOCK();
|
||
|
|
||
|
ulNeededSize = sizeof(ADAPTER_INFO) +
|
||
|
(sizeof(UCHAR) * NSAP_ADDRESS_LEN *
|
||
|
(AtmSmGlobal.ulAdapterCount - 1));
|
||
|
|
||
|
|
||
|
if(ulOutputBufLen < ulNeededSize)
|
||
|
{
|
||
|
|
||
|
DbgErr(("Output length is not sufficient\n"));
|
||
|
|
||
|
RELEASE_GLOBAL_LOCK();
|
||
|
|
||
|
TraceOut(AtmSmIoctlEnumerateAdapters);
|
||
|
return STATUS_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
pAdaptInfo->ulNumAdapters = 0;
|
||
|
|
||
|
ulNum = 0;
|
||
|
for(pAdapt = AtmSmGlobal.pAdapterList; pAdapt &&
|
||
|
ulNum < AtmSmGlobal.ulAdapterCount;
|
||
|
pAdapt = pAdapt->pAdapterNext)
|
||
|
{
|
||
|
|
||
|
if(AtmSmReferenceAdapter(pAdapt))
|
||
|
{
|
||
|
|
||
|
ACQUIRE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
if(0 == (pAdapt->ulFlags & ADAPT_ADDRESS_INVALID))
|
||
|
{
|
||
|
// this is a good adapter
|
||
|
|
||
|
RtlCopyMemory(pAdaptInfo->ucLocalATMAddr[ulNum],
|
||
|
pAdapt->ConfiguredAddress.Address,
|
||
|
(sizeof(UCHAR) * ATM_ADDRESS_LENGTH));
|
||
|
|
||
|
pAdaptInfo->ulNumAdapters++;
|
||
|
ulNum++;
|
||
|
}
|
||
|
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
AtmSmDereferenceAdapter(pAdapt);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
RELEASE_GLOBAL_LOCK();
|
||
|
|
||
|
pIrp->IoStatus.Information = ulOutputBufLen;
|
||
|
|
||
|
TraceOut(AtmSmIoctlEnumerateAdapters);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS AtmSmIoctlOpenForRecv(
|
||
|
PIRP pIrp,
|
||
|
PIO_STACK_LOCATION pIrpSp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is used to open an adapter for receiving all the packets that
|
||
|
come to our SAP. We allow only 1 user to open the adapter for recvs.
|
||
|
|
||
|
NOTE! This uses buffered I/O
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status - doesn't Pend
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
ULONG ulInputBufLen, ulOutputBufLen, ulCompareLength;
|
||
|
POPEN_FOR_RECV_INFO pOpenInfo = (POPEN_FOR_RECV_INFO)
|
||
|
pIrp->AssociatedIrp.SystemBuffer;
|
||
|
PATMSM_ADAPTER pAdapt;
|
||
|
|
||
|
#if DBG
|
||
|
ATM_ADDRESS AtmAddr;
|
||
|
#endif
|
||
|
|
||
|
TraceIn(AtmSmIoctlOpenForRecv);
|
||
|
|
||
|
ulInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
ulOutputBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
|
||
|
|
||
|
if(ulInputBufLen < sizeof(OPEN_FOR_RECV_INFO))
|
||
|
{
|
||
|
|
||
|
DbgErr(("Input length is invalid\n"));
|
||
|
TraceOut(AtmSmIoctlOpenForRecv);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if(ulOutputBufLen < sizeof(HANDLE))
|
||
|
{
|
||
|
|
||
|
DbgErr(("Output length is not sufficient\n"));
|
||
|
TraceOut(AtmSmIoctlOpenForRecv);
|
||
|
return STATUS_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
AtmAddr.AddressType = ATM_NSAP;
|
||
|
AtmAddr.NumberOfDigits = ATM_ADDRESS_LENGTH;
|
||
|
RtlCopyMemory(AtmAddr.Address, pOpenInfo->ucLocalATMAddr,
|
||
|
(sizeof(UCHAR) * ATM_ADDRESS_LENGTH));
|
||
|
|
||
|
DumpATMAddress(ATMSMD_INFO, "Recv Open - Local AtmAddress - ", &AtmAddr);
|
||
|
#endif
|
||
|
|
||
|
do
|
||
|
{ // break off loop
|
||
|
|
||
|
//
|
||
|
// grab the global lock and find out which adapter is being refered to.
|
||
|
//
|
||
|
ACQUIRE_GLOBAL_LOCK();
|
||
|
|
||
|
// we don't compare the selector byte
|
||
|
ulCompareLength = sizeof(UCHAR) * (ATM_ADDRESS_LENGTH - 1);
|
||
|
|
||
|
for(pAdapt = AtmSmGlobal.pAdapterList; pAdapt;
|
||
|
pAdapt = pAdapt->pAdapterNext)
|
||
|
{
|
||
|
|
||
|
if(ulCompareLength == RtlCompareMemory(
|
||
|
pOpenInfo->ucLocalATMAddr,
|
||
|
pAdapt->ConfiguredAddress.Address,
|
||
|
ulCompareLength))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(NULL == pAdapt)
|
||
|
{
|
||
|
RELEASE_GLOBAL_LOCK();
|
||
|
|
||
|
DbgErr(("Specified adapter address not found.\n"));
|
||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// we have found the adapter put a reference on it
|
||
|
if(!AtmSmReferenceAdapter(pAdapt))
|
||
|
{
|
||
|
RELEASE_GLOBAL_LOCK();
|
||
|
|
||
|
DbgErr(("Couldn't put a reference on the adapter.\n"));
|
||
|
Status = STATUS_UNSUCCESSFUL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
RELEASE_GLOBAL_LOCK();
|
||
|
|
||
|
// we have a reference on the adapter now
|
||
|
// check if it is already opened for recv's . We allow only
|
||
|
// one receiver.
|
||
|
ACQUIRE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
if(pAdapt->fAdapterOpenedForRecv)
|
||
|
{
|
||
|
// we already have an open for recv
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
AtmSmDereferenceAdapter(pAdapt);
|
||
|
|
||
|
DbgErr(("Already opened for recvs.\n"));
|
||
|
Status = STATUS_UNSUCCESSFUL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pAdapt->fAdapterOpenedForRecv = TRUE;
|
||
|
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
// now set the opencontext
|
||
|
*(PHANDLE)(pIrp->AssociatedIrp.SystemBuffer) = (HANDLE)pAdapt;
|
||
|
pIrp->IoStatus.Information = sizeof(HANDLE);
|
||
|
|
||
|
DbgInfo(("Success! Recv Open Context - 0x%x\n", pAdapt));
|
||
|
|
||
|
// remove the reference added when opening for recvs
|
||
|
AtmSmDereferenceAdapter(pAdapt);
|
||
|
|
||
|
} while(FALSE);
|
||
|
|
||
|
TraceOut(AtmSmIoctlOpenForRecv);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS AtmSmIoctlRecvData(
|
||
|
PIRP pIrp,
|
||
|
PIO_STACK_LOCATION pIrpSp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is used to transfer data from network packets into the user
|
||
|
buffers. If a packet is queued up, then we will immediately complete
|
||
|
this reuqest.
|
||
|
|
||
|
NOTE! This uses Direct I/O for buffer to recv data
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status - Success, Pending or error
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
ULONG ulInputBufLen, ulOutputBufLen;
|
||
|
PATMSM_ADAPTER pAdapt;
|
||
|
ULONG ulControlCode;
|
||
|
|
||
|
TraceIn(AtmSmIoctlRecvData);
|
||
|
|
||
|
ulControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
|
||
|
|
||
|
ASSERT(METHOD_OUT_DIRECT == (ulControlCode & 0x3));
|
||
|
|
||
|
ulInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
|
||
|
if(ulInputBufLen < sizeof(HANDLE))
|
||
|
{
|
||
|
|
||
|
DbgErr(("Input length is invalid\n"));
|
||
|
TraceOut(AtmSmIoctlRecvData);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
ulOutputBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
|
||
|
if(0 == ulOutputBufLen)
|
||
|
{
|
||
|
DbgErr(("Output buffer length is 0!\n"));
|
||
|
TraceOut(AtmSmIoctlRecvData);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
DbgLoud(("Recv - Output buffer length = %u\n", ulOutputBufLen));
|
||
|
|
||
|
pAdapt = (PATMSM_ADAPTER)(*(PHANDLE)(pIrp->AssociatedIrp.SystemBuffer));
|
||
|
|
||
|
DbgLoud(("Recv Context is 0x%x\n", pAdapt));
|
||
|
|
||
|
// Note - VerifyRecvOpenContext adds a reference to the adapter
|
||
|
// if successful, which we remove when we are done
|
||
|
|
||
|
if(STATUS_SUCCESS != (Status = VerifyRecvOpenContext(pAdapt)))
|
||
|
{
|
||
|
|
||
|
TraceOut(AtmSmIoctlRecvData);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// we have a valid RecvContext - check if a recv is already queued
|
||
|
do
|
||
|
{ // break off loop
|
||
|
|
||
|
ACQUIRE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
if(pAdapt->pRecvIrp)
|
||
|
{
|
||
|
|
||
|
// there is already an Irp pending
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
Status = STATUS_UNSUCCESSFUL;
|
||
|
DbgErr(("There is already a recv pending\n"));
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// No irps pending, check if a queued packets is there, if so copy
|
||
|
// else queue ourselves
|
||
|
if(pAdapt->pRecvPktNext)
|
||
|
{
|
||
|
|
||
|
PPROTO_RSVD pPRsvd;
|
||
|
PNDIS_PACKET pPkt;
|
||
|
|
||
|
pPkt = pAdapt->pRecvPktNext;
|
||
|
pPRsvd = GET_PROTO_RSVD(pPkt);
|
||
|
|
||
|
pAdapt->pRecvPktNext = pPRsvd->pPktNext;
|
||
|
|
||
|
if(pAdapt->pRecvLastPkt == pPkt)
|
||
|
pAdapt->pRecvLastPkt = NULL;
|
||
|
|
||
|
pAdapt->ulRecvPktsCount--;
|
||
|
|
||
|
// release the recv queue lock
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
// Copy the packet to the Irp buffer
|
||
|
// Note this may be partial if the Irp buffer is not large enough
|
||
|
pIrp->IoStatus.Information =
|
||
|
CopyPacketToIrp(pIrp, pPkt);
|
||
|
|
||
|
// return the packet to the miniport
|
||
|
NdisReturnPackets(&pPkt, 1);
|
||
|
|
||
|
// Status success
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// no packets available, queue this Irp
|
||
|
|
||
|
pAdapt->pRecvIrp = pIrp;
|
||
|
|
||
|
// release the recv queue lock
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
IoMarkIrpPending(pIrp);
|
||
|
|
||
|
Status = STATUS_PENDING;
|
||
|
}
|
||
|
|
||
|
|
||
|
}while(FALSE);
|
||
|
|
||
|
// remove the reference added while verifying
|
||
|
AtmSmDereferenceAdapter(pAdapt);
|
||
|
|
||
|
|
||
|
TraceOut(AtmSmIoctlRecvData);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS AtmSmIoctlCloseRecvHandle(
|
||
|
PIRP pIrp,
|
||
|
PIO_STACK_LOCATION pIrpSp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is used to close a handle that was obtained when the adapter
|
||
|
was opened for recvs.
|
||
|
|
||
|
NOTE! This uses buffered I/O
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status - doesn't pend
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
ULONG ulInputBufLen;
|
||
|
PATMSM_ADAPTER pAdapt;
|
||
|
|
||
|
TraceIn(AtmSmIoctlCloseRecvHandle);
|
||
|
|
||
|
ulInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
|
||
|
if(ulInputBufLen < sizeof(HANDLE))
|
||
|
{
|
||
|
|
||
|
DbgErr(("Input length is invalid\n"));
|
||
|
TraceOut(AtmSmIoctlCloseRecvHandle);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
|
||
|
pAdapt = (PATMSM_ADAPTER)(*(PHANDLE)(pIrp->AssociatedIrp.SystemBuffer));
|
||
|
|
||
|
DbgLoud(("Recv Context is 0x%x\n", pAdapt));
|
||
|
|
||
|
// Note - VerifyRecvOpenContext adds a reference to the adapter
|
||
|
// if successful, which we remove when we are done
|
||
|
|
||
|
if(STATUS_SUCCESS != (Status = VerifyRecvOpenContext(pAdapt)))
|
||
|
{
|
||
|
|
||
|
DbgInfo(("Couldn't put a reference on the adapter - pAdapt - 0x%x\n",
|
||
|
pAdapt));
|
||
|
TraceOut(AtmSmIoctlCloseRecvHandle);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// we have a valid RecvContext
|
||
|
|
||
|
ACQUIRE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
if(pAdapt->pRecvIrp)
|
||
|
{
|
||
|
|
||
|
PIRP pRecvIrp = pAdapt->pRecvIrp;
|
||
|
|
||
|
pAdapt->pRecvIrp = NULL;
|
||
|
|
||
|
// there is an Irp pending, complete it
|
||
|
pRecvIrp->IoStatus.Status = STATUS_CANCELLED;
|
||
|
pRecvIrp->Cancel = TRUE;
|
||
|
pRecvIrp->IoStatus.Information = 0;
|
||
|
IoCompleteRequest(pRecvIrp, IO_NETWORK_INCREMENT);
|
||
|
|
||
|
}
|
||
|
|
||
|
pAdapt->fAdapterOpenedForRecv = FALSE;
|
||
|
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
// remove the reference added while verifying
|
||
|
AtmSmDereferenceAdapter(pAdapt);
|
||
|
|
||
|
pIrp->IoStatus.Information = 0;
|
||
|
|
||
|
TraceOut(AtmSmIoctlCloseRecvHandle);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS AtmSmIoctlConnectToDsts(
|
||
|
PIRP pIrp,
|
||
|
PIO_STACK_LOCATION pIrpSp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
This routine is used to initiate a connection to 1 (P-P) or more (PMP)
|
||
|
destinations.
|
||
|
|
||
|
NOTE! This uses buffered I/O
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status - Pending or error
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
PCONNECT_INFO pConnectInfo = (PCONNECT_INFO)
|
||
|
pIrp->AssociatedIrp.SystemBuffer;
|
||
|
ULONG ul, ulInputBufLen, ulOutputBufLen, ulCompareLength;
|
||
|
PATMSM_ADAPTER pAdapt;
|
||
|
PATMSM_VC pVc;
|
||
|
|
||
|
#if DBG
|
||
|
ATM_ADDRESS AtmAddr;
|
||
|
#endif
|
||
|
|
||
|
TraceIn(AtmSmIoctlConnectToDsts);
|
||
|
|
||
|
ulInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
ulOutputBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
|
||
|
if(ulInputBufLen < sizeof(CONNECT_INFO))
|
||
|
{
|
||
|
DbgErr(("Input length < sizeof(CONNECT_INFO)\n"));
|
||
|
TraceOut(AtmSmIoctlConnectToDsts);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if(pConnectInfo->ulNumDsts == 0)
|
||
|
{
|
||
|
DbgErr(("Number of destinations is zero\n"));
|
||
|
TraceOut(AtmSmIoctlConnectToDsts);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if((ulInputBufLen - (sizeof(CONNECT_INFO))/(sizeof(UCHAR)*ATM_ADDRESS_LENGTH))
|
||
|
< pConnectInfo->ulNumDsts -1)
|
||
|
{
|
||
|
DbgErr(("Input length is invalid\n"));
|
||
|
TraceOut(AtmSmIoctlConnectToDsts);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if(ulOutputBufLen < sizeof(HANDLE))
|
||
|
{
|
||
|
DbgErr(("Output length is not sufficient\n"));
|
||
|
TraceOut(AtmSmIoctlConnectToDsts);
|
||
|
return STATUS_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
AtmAddr.AddressType = ATM_NSAP;
|
||
|
AtmAddr.NumberOfDigits = ATM_ADDRESS_LENGTH;
|
||
|
RtlCopyMemory(AtmAddr.Address, pConnectInfo->ucLocalATMAddr,
|
||
|
(sizeof(UCHAR) * ATM_ADDRESS_LENGTH));
|
||
|
|
||
|
DumpATMAddress(ATMSMD_INFO, "Connect to Dsts - Local AtmAddress - ",
|
||
|
&AtmAddr);
|
||
|
|
||
|
DbgInfo(("No of destinations - %u\n", pConnectInfo->ulNumDsts));
|
||
|
|
||
|
for(ul = 0; ul < pConnectInfo->ulNumDsts; ul++)
|
||
|
{
|
||
|
|
||
|
RtlCopyMemory(AtmAddr.Address, pConnectInfo->ucDstATMAddrs[ul],
|
||
|
(sizeof(UCHAR) * ATM_ADDRESS_LENGTH));
|
||
|
|
||
|
DumpATMAddress(ATMSMD_INFO, " Destination AtmAddress - ", &AtmAddr);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
do
|
||
|
{ // break off loop
|
||
|
|
||
|
// initialize
|
||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
||
|
|
||
|
//
|
||
|
// grab the global lock and find out which adapter is being refered to.
|
||
|
//
|
||
|
ACQUIRE_GLOBAL_LOCK();
|
||
|
|
||
|
// we don't compare the selector byte
|
||
|
ulCompareLength = sizeof(UCHAR) * (ATM_ADDRESS_LENGTH - 1);
|
||
|
|
||
|
for(pAdapt = AtmSmGlobal.pAdapterList; pAdapt;
|
||
|
pAdapt = pAdapt->pAdapterNext)
|
||
|
{
|
||
|
|
||
|
if(ulCompareLength == RtlCompareMemory(
|
||
|
pConnectInfo->ucLocalATMAddr,
|
||
|
pAdapt->ConfiguredAddress.Address,
|
||
|
ulCompareLength))
|
||
|
{
|
||
|
// create a VC structure
|
||
|
Status = AtmSmAllocVc(pAdapt,
|
||
|
&pVc,
|
||
|
(pConnectInfo->bPMP?
|
||
|
VC_TYPE_PMP_OUTGOING :
|
||
|
VC_TYPE_PP_OUTGOING),
|
||
|
NULL);
|
||
|
|
||
|
if(NDIS_STATUS_SUCCESS != Status)
|
||
|
{
|
||
|
|
||
|
DbgErr(("Failed to create ougoing VC. Status - 0x%X.\n", Status));
|
||
|
|
||
|
Status = STATUS_NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RELEASE_GLOBAL_LOCK();
|
||
|
|
||
|
if(Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// no need to add reference here since the allocation of VC
|
||
|
// will add a reference to the Adapter
|
||
|
|
||
|
ACQUIRE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
if(!pConnectInfo->bPMP)
|
||
|
{
|
||
|
|
||
|
// this is P-P
|
||
|
// copy the destination address
|
||
|
PATM_ADDRESS pAtmAddr = &pVc->HwAddr.Address;
|
||
|
|
||
|
pAtmAddr->AddressType = ATM_NSAP;
|
||
|
pAtmAddr->NumberOfDigits = ATM_ADDRESS_LENGTH;
|
||
|
RtlCopyMemory(pAtmAddr->Address, pConnectInfo->ucDstATMAddrs[0],
|
||
|
(sizeof(UCHAR) * ATM_ADDRESS_LENGTH));
|
||
|
// Note: we don't get the correct selector byte from user mode
|
||
|
// we assume the selector byte used by the destination is
|
||
|
// the same.
|
||
|
pAtmAddr->Address[ATM_ADDRESS_LENGTH-1] = pAdapt->SelByte;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
for(ul = 0; ul < pConnectInfo->ulNumDsts; ul++)
|
||
|
{
|
||
|
|
||
|
PATMSM_PMP_MEMBER pMember;
|
||
|
PATM_ADDRESS pAtmAddr;
|
||
|
|
||
|
AtmSmAllocMem(&pMember, PATMSM_PMP_MEMBER,
|
||
|
sizeof(ATMSM_PMP_MEMBER));
|
||
|
|
||
|
if(NULL == pMember)
|
||
|
{
|
||
|
|
||
|
|
||
|
DbgErr(("Failed to allocate member. No resources\n"));
|
||
|
|
||
|
// cleanup the members and VC
|
||
|
while(NULL != (pMember = pVc->pPMPMembers))
|
||
|
{
|
||
|
AtmSmFreeMem(pMember);
|
||
|
pVc->ulRefCount--;
|
||
|
}
|
||
|
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
AtmSmDereferenceVc(pVc);
|
||
|
|
||
|
Status = STATUS_NO_MEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
NdisZeroMemory(pMember, sizeof(ATMSM_PMP_MEMBER));
|
||
|
|
||
|
pMember->ulSignature = atmsm_member_signature;
|
||
|
pMember->pVc = pVc;
|
||
|
ATMSM_SET_MEMBER_STATE(pMember, ATMSM_MEMBER_IDLE);
|
||
|
pAtmAddr = &pMember->HwAddr.Address;
|
||
|
|
||
|
pAtmAddr->AddressType = ATM_NSAP;
|
||
|
pAtmAddr->NumberOfDigits = ATM_ADDRESS_LENGTH;
|
||
|
RtlCopyMemory(pAtmAddr->Address,
|
||
|
pConnectInfo->ucDstATMAddrs[ul],
|
||
|
(sizeof(UCHAR) * ATM_ADDRESS_LENGTH));
|
||
|
|
||
|
// Note: we don't get the correct selector byte from user mode
|
||
|
// we assume the selector byte used by the destination is
|
||
|
// the same.
|
||
|
pAtmAddr->Address[ATM_ADDRESS_LENGTH-1] = pAdapt->SelByte;
|
||
|
|
||
|
pMember->pNext = pVc->pPMPMembers;
|
||
|
pVc->pPMPMembers = pMember;
|
||
|
pVc->ulNumTotalMembers++;
|
||
|
|
||
|
// Also add a reference for each members
|
||
|
pVc->ulRefCount++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
pVc->pConnectIrp = pIrp;
|
||
|
|
||
|
IoMarkIrpPending(pIrp);
|
||
|
|
||
|
// we will return pending
|
||
|
Status = STATUS_PENDING;
|
||
|
|
||
|
RELEASE_ADAPTER_GEN_LOCK(pAdapt);
|
||
|
|
||
|
DbgInfo(("Initiated a VC connection - Adapter 0x%x VC - 0x%x\n",
|
||
|
pAdapt, pVc));
|
||
|
if(!pConnectInfo->bPMP)
|
||
|
{
|
||
|
|
||
|
AtmSmConnectPPVC(pVc);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
AtmSmConnectToPMPDestinations(pVc);
|
||
|
}
|
||
|
|
||
|
|
||
|
} while(FALSE);
|
||
|
|
||
|
|
||
|
TraceOut(AtmSmIoctlConnectToDsts);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS AtmSmIoctlSendToDsts(
|
||
|
PIRP pIrp,
|
||
|
PIO_STACK_LOCATION pIrpSp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
This routine is used to send a packet to destination(s) for which we
|
||
|
already have a connection.
|
||
|
|
||
|
NOTE! This uses Direct I/O for buffer to send data
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status - Pending or error
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
ULONG ulInputBufLen, ulOutputBufLen;
|
||
|
PATMSM_VC pVc;
|
||
|
ULONG ulControlCode;
|
||
|
|
||
|
TraceIn(AtmSmIoctlSendToDsts);
|
||
|
|
||
|
ulControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
|
||
|
|
||
|
ASSERT(METHOD_IN_DIRECT == (ulControlCode & 0x3));
|
||
|
|
||
|
ulInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
|
||
|
if(sizeof(HANDLE) != ulInputBufLen)
|
||
|
{
|
||
|
DbgErr(("Input buffer length is invalid!\n"));
|
||
|
ASSERT(FALSE);
|
||
|
TraceOut(AtmSmIoctlSendToDsts);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
ulOutputBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
|
||
|
if(0 == ulOutputBufLen)
|
||
|
{
|
||
|
DbgErr(("Output buffer length is 0!\n"));
|
||
|
ASSERT(FALSE);
|
||
|
TraceOut(AtmSmIoctlRecvData);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
DbgLoud(("Send - Output buffer length = %u\n", ulOutputBufLen));
|
||
|
|
||
|
pVc = (PATMSM_VC)(*(PHANDLE)(pIrp->AssociatedIrp.SystemBuffer));
|
||
|
|
||
|
DbgLoud(("Connect Context is 0x%x\n", pVc));
|
||
|
|
||
|
// Note - VerifyConnectContext adds a reference to the VC
|
||
|
// if successful, which we remove when we are done
|
||
|
|
||
|
if(STATUS_SUCCESS != (Status = VerifyConnectContext(pVc)))
|
||
|
{
|
||
|
|
||
|
TraceOut(AtmSmIoctlSendToDsts);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// we have a valid ConnectContext
|
||
|
do
|
||
|
{ // break off loop
|
||
|
|
||
|
PNDIS_PACKET pPacket;
|
||
|
PATMSM_ADAPTER pAdapt = pVc->pAdapt;
|
||
|
//
|
||
|
// Try to get a packet
|
||
|
//
|
||
|
|
||
|
NdisAllocatePacket(
|
||
|
&Status,
|
||
|
&pPacket,
|
||
|
pAdapt->PacketPoolHandle
|
||
|
);
|
||
|
|
||
|
if(NDIS_STATUS_SUCCESS != Status)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// No free packets
|
||
|
//
|
||
|
Status = STATUS_UNSUCCESSFUL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
(GET_PROTO_RSVD(pPacket))->pSendIrp=pIrp;
|
||
|
|
||
|
#ifdef BUG_IN_NEW_DMA
|
||
|
|
||
|
{
|
||
|
PNDIS_BUFFER pBuffer;
|
||
|
PVOID pSrcVA =
|
||
|
MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
|
||
|
UINT uiBufSize =
|
||
|
MmGetMdlByteCount(pIrp->MdlAddress);
|
||
|
|
||
|
if (pSrcVA == NULL)
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// allocate the Buffer Descriptor
|
||
|
NdisAllocateBuffer(&Status,
|
||
|
&pBuffer,
|
||
|
pAdapt->BufferPoolHandle,
|
||
|
pSrcVA,
|
||
|
uiBufSize);
|
||
|
|
||
|
if(NDIS_STATUS_SUCCESS != Status)
|
||
|
{
|
||
|
NdisFreePacket(pPacket);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// add the buffer to the packet
|
||
|
NdisChainBufferAtFront(pPacket,
|
||
|
pBuffer);
|
||
|
|
||
|
}
|
||
|
|
||
|
#else // BUG_IN_NEW_DMA
|
||
|
|
||
|
//
|
||
|
// Attach the send buffer to the packet
|
||
|
//
|
||
|
NdisChainBufferAtFront(pPacket, pIrp->MdlAddress);
|
||
|
|
||
|
#endif // BUG_IN_NEW_DMA
|
||
|
|
||
|
IoMarkIrpPending(pIrp);
|
||
|
|
||
|
Status = STATUS_PENDING;
|
||
|
|
||
|
// send the packet on the VC
|
||
|
AtmSmSendPacketOnVc(pVc, pPacket);
|
||
|
|
||
|
}while(FALSE);
|
||
|
|
||
|
// remove the reference added to the VC while verifying
|
||
|
AtmSmDereferenceVc(pVc);
|
||
|
|
||
|
TraceOut(AtmSmIoctlSendToDsts);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS AtmSmIoctlCloseSendHandle(
|
||
|
PIRP pIrp,
|
||
|
PIO_STACK_LOCATION pIrpSp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is used to close a handle that was obtained when we established
|
||
|
a connection to destinations.
|
||
|
|
||
|
NOTE! This uses buffered I/O
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status - doesn't pend
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
ULONG ulInputBufLen;
|
||
|
PATMSM_VC pVc;
|
||
|
|
||
|
TraceIn(AtmSmIoctlCloseSendHandle);
|
||
|
|
||
|
ulInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
|
||
|
if(ulInputBufLen < sizeof(HANDLE))
|
||
|
{
|
||
|
|
||
|
DbgErr(("Input length is invalid\n"));
|
||
|
TraceOut(AtmSmIoctlCloseSendHandle);
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
pVc = (PATMSM_VC)(*(PHANDLE)(pIrp->AssociatedIrp.SystemBuffer));
|
||
|
|
||
|
DbgLoud(("Connect Context is 0x%x\n", pVc));
|
||
|
|
||
|
// Note - VerifyConnectContext adds a reference to the VC
|
||
|
// if successful, which we remove when we are done
|
||
|
|
||
|
if(STATUS_SUCCESS != (Status = VerifyConnectContext(pVc)))
|
||
|
{
|
||
|
|
||
|
TraceOut(AtmSmIoctlCloseSendHandle);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// we have a valid Connect Context - disconnect it
|
||
|
AtmSmDisconnectVc(pVc);
|
||
|
|
||
|
// remove the reference added to the VC while verifying
|
||
|
AtmSmDereferenceVc(pVc);
|
||
|
|
||
|
TraceOut(AtmSmIoctlCloseSendHandle);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|