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.
825 lines
28 KiB
825 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ioctl.c
|
|
|
|
Abstract:
|
|
|
|
This is the main file for handling DevIOCtl calls for AsyncMAC.
|
|
This driver conforms to the NDIS 3.0 interface.
|
|
|
|
Author:
|
|
|
|
Thomas J. Dimitri (TommyD) 08-May-1992
|
|
|
|
Environment:
|
|
|
|
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
#include "asyncall.h"
|
|
|
|
#ifdef NDIS_NT
|
|
#include <ntiologc.h>
|
|
#endif
|
|
|
|
#if DBG
|
|
|
|
#define __FILE_SIG__ 'tcoi'
|
|
|
|
#endif
|
|
|
|
|
|
// asyncmac.c will define the global parameters.
|
|
|
|
VOID
|
|
AsyncSendLineUp(
|
|
PASYNC_INFO pInfo
|
|
)
|
|
{
|
|
PASYNC_ADAPTER pAdapter = pInfo->Adapter;
|
|
NDIS_MAC_LINE_UP MacLineUp;
|
|
|
|
//
|
|
// divide the baud by 100 because NDIS wants it in 100s of bits per sec
|
|
//
|
|
|
|
MacLineUp.LinkSpeed = pInfo->LinkSpeed / 100;
|
|
MacLineUp.Quality = pInfo->QualOfConnect;
|
|
MacLineUp.SendWindow = ASYNC_WINDOW_SIZE;
|
|
|
|
MacLineUp.ConnectionWrapperID = pInfo;
|
|
MacLineUp.NdisLinkHandle = pInfo;
|
|
|
|
MacLineUp.NdisLinkContext = pInfo->NdisLinkContext;
|
|
|
|
//
|
|
// Tell the transport above (or really RasHub) that the connection
|
|
// is now up. We have a new link speed, frame size, quality of service
|
|
//
|
|
|
|
NdisMIndicateStatus(pAdapter->MiniportHandle,
|
|
NDIS_STATUS_WAN_LINE_UP, // General Status.
|
|
&MacLineUp, // (baud rate in 100 bps).
|
|
sizeof(NDIS_MAC_LINE_UP));
|
|
|
|
//
|
|
// Get the next binding (in case of multiple bindings like BloodHound)
|
|
//
|
|
|
|
pInfo->NdisLinkContext = MacLineUp.NdisLinkContext;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AsyncIOCtlRequest(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes an irp and checks to see if the IOCtl
|
|
is a valid one. If so, it performs the IOCtl and returns
|
|
any errors in the process.
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status of the IOCtl.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
ULONG funcCode;
|
|
PVOID pBufOut;
|
|
ULONG InBufLength, OutBufLength;
|
|
NDIS_HANDLE hNdisEndPoint;
|
|
PASYMAC_CLOSE pCloseStruct;
|
|
PASYMAC_OPEN pOpenStruct;
|
|
PASYMAC_DCDCHANGE pDCDStruct;
|
|
PASYNC_ADAPTER Adapter;
|
|
LARGE_INTEGER li ;
|
|
|
|
//
|
|
// Initialize locals.
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Initialize the I/O Status block
|
|
//
|
|
|
|
InBufLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
OutBufLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
funcCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
//
|
|
// Validate the function code
|
|
//
|
|
|
|
#ifdef MY_DEVICE_OBJECT
|
|
if ( (funcCode >> 16) != FILE_DEVICE_ASYMAC ) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
#else
|
|
if ( (funcCode >> 16) != FILE_DEVICE_NETWORK ) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
#endif
|
|
//
|
|
// Get a quick ptr to the IN/OUT SystemBuffer
|
|
//
|
|
|
|
pBufOut = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
switch ( funcCode ) {
|
|
|
|
case IOCTL_ASYMAC_OPEN:
|
|
|
|
DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_OPEN.\n"));
|
|
|
|
pIrp->IoStatus.Information = sizeof(ASYMAC_OPEN);
|
|
|
|
if (InBufLength >= sizeof(ASYMAC_OPEN) &&
|
|
OutBufLength >= sizeof(ASYMAC_OPEN)) {
|
|
|
|
pOpenStruct = pBufOut;
|
|
|
|
} else {
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_ASYMAC_CLOSE:
|
|
|
|
DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_CLOSE\n"));
|
|
|
|
if ( InBufLength >= sizeof(ASYMAC_CLOSE) ) {
|
|
|
|
pCloseStruct = pBufOut;
|
|
|
|
} else {
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_ASYMAC_TRACE:
|
|
|
|
#if DBG
|
|
DbgPrint("AsyncIOCtlRequest: IOCTL_ASYMAC_TRACE.\n");
|
|
|
|
if ( InBufLength >= sizeof(TraceLevel) ) {
|
|
|
|
CHAR *pTraceLevel=pBufOut;
|
|
TraceLevel=*pTraceLevel;
|
|
|
|
} else {
|
|
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
#endif
|
|
return status;
|
|
break;
|
|
|
|
|
|
case IOCTL_ASYMAC_DCDCHANGE:
|
|
|
|
DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_DCDCHANGE.\n"));
|
|
|
|
|
|
if ( InBufLength >= sizeof(ASYMAC_DCDCHANGE) ) {
|
|
|
|
pDCDStruct = pBufOut;
|
|
|
|
} else {
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
//
|
|
// Check if we already have an error (like STATUS_INFO_LENGTH_MISMATCH).
|
|
//
|
|
|
|
if ( status != STATUS_SUCCESS ) {
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Since most of IOCTL structs are similar
|
|
// we get the Adapter and hNdisEndPoint here using
|
|
// the StatsStruct (we could several of them)
|
|
//
|
|
|
|
pOpenStruct = pBufOut;
|
|
hNdisEndPoint = pOpenStruct->hNdisEndpoint;
|
|
|
|
//
|
|
// No error yet, let's go ahead and grab the global lock...
|
|
//
|
|
|
|
if ((Adapter = GlobalAdapter) == NULL ) {
|
|
|
|
return ASYNC_ERROR_NO_ADAPTER;
|
|
}
|
|
|
|
// there's a race condition right here that I am
|
|
// not bothering to get rid of because it would
|
|
// require the removal of this adapter in between
|
|
// here (which is, for all intensive purposes, impossible).
|
|
|
|
// Hmm... now that we have the lock we can do stuff
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
// Here we do the real work for the function call
|
|
|
|
switch ( funcCode ) {
|
|
|
|
case IOCTL_ASYMAC_OPEN:
|
|
{
|
|
PASYNC_INFO pNewInfo = NULL;
|
|
USHORT i;
|
|
PDEVICE_OBJECT deviceObject;
|
|
PFILE_OBJECT fileObject;
|
|
OBJECT_HANDLE_INFORMATION handleInformation;
|
|
|
|
//
|
|
// Get a new AsyncInfo
|
|
//
|
|
pNewInfo = (PASYNC_INFO)
|
|
ExAllocateFromNPagedLookasideList(&AsyncInfoList);
|
|
|
|
//
|
|
// Check if we could not find an open port
|
|
//
|
|
|
|
if ( pNewInfo == NULL ) {
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
return ASYNC_ERROR_NO_PORT_AVAILABLE;
|
|
}
|
|
|
|
RtlZeroMemory(pNewInfo, sizeof(ASYNC_INFO));
|
|
|
|
pNewInfo->Adapter = Adapter;
|
|
|
|
status =
|
|
AsyncGetFrameFromPool(pNewInfo, &pNewInfo->AsyncFrame);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS) {
|
|
ExFreeToNPagedLookasideList(&AsyncInfoList, pNewInfo);
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
return ASYNC_ERROR_NO_PORT_AVAILABLE;
|
|
}
|
|
|
|
KeInitializeEvent(&pNewInfo->DetectEvent,
|
|
SynchronizationEvent,
|
|
TRUE);
|
|
|
|
KeInitializeEvent(&pNewInfo->AsyncEvent,
|
|
SynchronizationEvent,
|
|
TRUE);
|
|
|
|
// increment the reference count (don't kill this adapter)
|
|
InterlockedIncrement(&Adapter->RefCount);
|
|
|
|
//
|
|
// Initialize the refcount on the new asyncinfo block.
|
|
//
|
|
pNewInfo->RefCount++;
|
|
|
|
#if DBG
|
|
InitializeListHead(&pNewInfo->lePendingRequests);
|
|
|
|
{
|
|
|
|
PENDING_REQUEST *_Request = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(PENDING_REQUEST),
|
|
'nepA');
|
|
if(NULL != _Request)
|
|
{
|
|
_Request->pvContext = pNewInfo;
|
|
_Request->Sig = __FILE_SIG__;
|
|
_Request->lineNum = __LINE__;
|
|
InsertTailList(&pNewInfo->lePendingRequests, &_Request->le);
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
pNewInfo->Flags |= ASYNC_FLAG_ASYNCMAC_OPEN;
|
|
|
|
//
|
|
// Set signalled state of event to not-signalled.
|
|
//
|
|
KeClearEvent(&pNewInfo->AsyncEvent);
|
|
|
|
// release spin lock so we can do some real work.
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Reference the file object so the target device can be found and
|
|
// the access rights mask can be used in the following checks for
|
|
// callers in user mode. Note that if the handle does not refer to
|
|
// a file object, then it will fail.
|
|
//
|
|
|
|
status = ObReferenceObjectByHandle(pOpenStruct->FileHandle,
|
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
|
*IoFileObjectType,
|
|
UserMode,
|
|
(PVOID) &fileObject,
|
|
&handleInformation);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
pNewInfo->PortState = PORT_CLOSED;
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
// RemoveEntryList(&pNewInfo->Linkage);
|
|
ExFreeToNPagedLookasideList(&Adapter->AsyncFrameList,
|
|
pNewInfo->AsyncFrame);
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
ExFreeToNPagedLookasideList(&AsyncInfoList,
|
|
pNewInfo);
|
|
|
|
return ASYNC_ERROR_NO_PORT_AVAILABLE;
|
|
}
|
|
|
|
//
|
|
// Init the portinfo block
|
|
//
|
|
InitializeListHead(&pNewInfo->DDCDQueue);
|
|
|
|
// Ok, we've gotten this far. We have a port.
|
|
// Own port, and check params...
|
|
// Nothing can be done to the port until it comes
|
|
// out of the PORT_OPENING state.
|
|
pNewInfo->PortState = PORT_OPENING;
|
|
|
|
NdisAllocateSpinLock(&pNewInfo->Lock);
|
|
|
|
//
|
|
// Get the address of the target device object. Note that this was already
|
|
// done for the no intermediate buffering case, but is done here again to
|
|
// speed up the turbo write path.
|
|
//
|
|
|
|
deviceObject = IoGetRelatedDeviceObject(fileObject);
|
|
|
|
ObReferenceObject(deviceObject);
|
|
|
|
// ok, we have a VALID handle of *something*
|
|
// we do NOT assume that the handle is anything
|
|
// in particular except a device which accepts
|
|
// non-buffered IO (no MDLs) Reads and Writes
|
|
|
|
// set new info...
|
|
|
|
pNewInfo->Handle = pOpenStruct->FileHandle;
|
|
|
|
//
|
|
// Tuck away link speed for line up
|
|
// and timeouts
|
|
//
|
|
pNewInfo->LinkSpeed = pOpenStruct->LinkSpeed;
|
|
|
|
//
|
|
// Return endpoint to RASMAN
|
|
//
|
|
pOpenStruct->hNdisEndpoint =
|
|
pNewInfo->hNdisEndPoint = pNewInfo;
|
|
|
|
// Get parameters set from Registry and return our capabilities
|
|
|
|
pNewInfo->QualOfConnect = pOpenStruct->QualOfConnect;
|
|
pNewInfo->PortState = PORT_FRAMING;
|
|
pNewInfo->FileObject = fileObject;
|
|
pNewInfo->DeviceObject = deviceObject;
|
|
pNewInfo->NdisLinkContext = NULL;
|
|
|
|
//
|
|
// Initialize the NDIS_WAN_GET_LINK_INFO structure.
|
|
//
|
|
|
|
pNewInfo->GetLinkInfo.MaxSendFrameSize = DEFAULT_PPP_MAX_FRAME_SIZE;
|
|
pNewInfo->GetLinkInfo.MaxRecvFrameSize = DEFAULT_PPP_MAX_FRAME_SIZE;
|
|
pNewInfo->GetLinkInfo.HeaderPadding = DEFAULT_PPP_MAX_FRAME_SIZE;
|
|
pNewInfo->GetLinkInfo.TailPadding = 4;
|
|
pNewInfo->GetLinkInfo.SendFramingBits = PPP_FRAMING;
|
|
pNewInfo->GetLinkInfo.RecvFramingBits = PPP_FRAMING;
|
|
pNewInfo->GetLinkInfo.SendCompressionBits = 0;
|
|
pNewInfo->GetLinkInfo.RecvCompressionBits = 0;
|
|
pNewInfo->GetLinkInfo.SendACCM = (ULONG) -1;
|
|
pNewInfo->GetLinkInfo.RecvACCM = (ULONG) -1;
|
|
|
|
//
|
|
// Initialize the Extended ACCM information so that we always
|
|
// escape 0x7D and 0x7E and we never escape 0x5E
|
|
//
|
|
pNewInfo->ExtendedACCM[0] = (ULONG) -1;
|
|
pNewInfo->ExtendedACCM[3] = (ULONG) 0x60000000;
|
|
|
|
|
|
ASYNC_ZERO_MEMORY(&(pNewInfo->SerialStats), sizeof(SERIAL_STATS));
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
InsertHeadList(&Adapter->ActivePorts, &pNewInfo->Linkage);
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
|
|
//
|
|
// Send a line up to the WAN wrapper.
|
|
//
|
|
AsyncSendLineUp(pNewInfo);
|
|
|
|
//
|
|
// We send a special IRP to the serial driver to set it in RAS friendly mode
|
|
// where it will not complete write requests until the packet has been transmitted
|
|
// on the wire. This is mostly important in case of intelligent controllers.
|
|
//
|
|
pNewInfo->WaitMaskToUse =
|
|
(SERIAL_EV_RXFLAG | SERIAL_EV_RLSD | SERIAL_EV_DSR |
|
|
SERIAL_EV_RX80FULL | SERIAL_EV_ERR) ;
|
|
|
|
{
|
|
NTSTATUS retStatus;
|
|
PASYNC_IO_CTX AsyncIoCtx;
|
|
PIRP irp;
|
|
|
|
irp =
|
|
IoAllocateIrp(pNewInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
|
|
|
|
if (irp != NULL) {
|
|
AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pNewInfo);
|
|
|
|
if (AsyncIoCtx == NULL) {
|
|
IoFreeIrp(irp);
|
|
irp = NULL;
|
|
}
|
|
}
|
|
|
|
if (irp != NULL) {
|
|
#define IOCTL_SERIAL_PRIVATE_RAS CTL_CODE(FILE_DEVICE_SERIAL_PORT,4000,METHOD_BUFFERED,FILE_ANY_ACCESS)
|
|
|
|
InitSerialIrp(irp,
|
|
pNewInfo,
|
|
IOCTL_SERIAL_PRIVATE_RAS,
|
|
sizeof(ULONG));
|
|
|
|
AsyncIoCtx->WriteBufferingEnabled =
|
|
Adapter->WriteBufferingEnabled;
|
|
|
|
irp->AssociatedIrp.SystemBuffer=
|
|
&AsyncIoCtx->WriteBufferingEnabled;
|
|
|
|
IoSetCompletionRoutine(irp, // irp to use
|
|
SerialIoSyncCompletionRoutine, // routine to call when irp is done
|
|
AsyncIoCtx, // context to pass routine
|
|
TRUE, // call on success
|
|
TRUE, // call on error
|
|
TRUE); // call on cancel
|
|
|
|
// Now simply invoke the driver at its dispatch entry with the IRP.
|
|
//
|
|
KeClearEvent(&AsyncIoCtx->Event);
|
|
retStatus = IoCallDriver(pNewInfo->DeviceObject, irp);
|
|
if (retStatus == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&AsyncIoCtx->Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
retStatus = AsyncIoCtx->IoStatus.Status;
|
|
}
|
|
|
|
IoFreeIrp(irp);
|
|
AsyncFreeIoCtx(AsyncIoCtx);
|
|
|
|
if (retStatus == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// this means that the driver below is DIGI. we should disable setting of the EV_ERR
|
|
// flags in this case.
|
|
//
|
|
|
|
pNewInfo->WaitMaskToUse &= ~SERIAL_EV_ERR;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Start the detect framing out with a 6 byte read to get the header
|
|
//
|
|
pNewInfo->BytesWanted=6;
|
|
pNewInfo->BytesRead=0;
|
|
|
|
//
|
|
// Start reading.
|
|
//
|
|
|
|
AsyncStartReads(pNewInfo);
|
|
|
|
if (NdisInterlockedIncrement(&glConnectionCount) == 1) {
|
|
ObReferenceObject(AsyncDeviceObject);
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IOCTL_ASYMAC_TRACE:
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IOCTL_ASYMAC_CLOSE:
|
|
case IOCTL_ASYMAC_DCDCHANGE:
|
|
{
|
|
PASYNC_INFO pNewInfo; // ptr to open port if found
|
|
USHORT i;
|
|
PLIST_ENTRY pListEntry;
|
|
BOOLEAN Valid = FALSE;
|
|
|
|
switch (funcCode) {
|
|
|
|
case IOCTL_ASYMAC_CLOSE:
|
|
{
|
|
NDIS_MAC_LINE_DOWN AsyncLineDown;
|
|
|
|
pNewInfo = (PASYNC_INFO)pCloseStruct->hNdisEndpoint;
|
|
|
|
// Verify that the pointer is a valid ASYNC_INFO
|
|
for (pListEntry=Adapter->ActivePorts.Flink;
|
|
pListEntry!=&Adapter->ActivePorts;
|
|
pListEntry=pListEntry->Flink)
|
|
{
|
|
if (&pNewInfo->Linkage==pListEntry)
|
|
{
|
|
Valid = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Valid) {
|
|
status=ASYNC_ERROR_PORT_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
// release spin lock so we can do some real work.
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisAcquireSpinLock(&pNewInfo->Lock);
|
|
|
|
// ASSERT(pNewInfo->PortState == PORT_FRAMING);
|
|
|
|
if(pNewInfo->PortState != PORT_FRAMING)
|
|
{
|
|
KdPrint(("AsyncIOCtlRequest: IOCTL_ASYMAC_CLOSE."));
|
|
KdPrint(("PortState = %d != PORT_FRAMING\n", pNewInfo->PortState));
|
|
|
|
NdisReleaseSpinLock(&pNewInfo->Lock);
|
|
return ASYNC_ERROR_PORT_BAD_STATE;
|
|
// break;
|
|
}
|
|
|
|
AsyncLineDown.NdisLinkContext = pNewInfo->NdisLinkContext;
|
|
|
|
// Signal that port is closing.
|
|
pNewInfo->PortState = PORT_CLOSING;
|
|
|
|
//Set MUTEX to wait on
|
|
KeInitializeEvent(&pNewInfo->ClosingEvent, // Event
|
|
SynchronizationEvent, // Event type
|
|
(BOOLEAN)FALSE); // Not signalled state
|
|
|
|
NdisReleaseSpinLock(&pNewInfo->Lock);
|
|
|
|
//
|
|
// If we have an outstanding Detect worker
|
|
// wait for it to complete!
|
|
//
|
|
KeWaitForSingleObject(&pNewInfo->DetectEvent,
|
|
UserRequest,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
//
|
|
// now we must send down an IRP do cancel
|
|
// any request pending in the serial driver
|
|
//
|
|
CancelSerialRequests(pNewInfo);
|
|
|
|
//
|
|
// Also, cancel any outstanding DDCD irps
|
|
//
|
|
|
|
AsyncCancelAllQueued(&pNewInfo->DDCDQueue);
|
|
|
|
// Synchronize closing with the read irp
|
|
|
|
li.QuadPart = Int32x32To64(10000, -10000); // wait for 10 secs
|
|
|
|
if (KeWaitForSingleObject (&pNewInfo->ClosingEvent,// PVOID Object,
|
|
UserRequest, // KWAIT_REASON WaitReason,
|
|
KernelMode, // KPROCESSOR_MODE WaitMode,
|
|
(BOOLEAN)FALSE, // BOOLEAN Alertable,
|
|
&li) == STATUS_TIMEOUT) {
|
|
|
|
// If the wait fails cause another flush
|
|
//
|
|
NTSTATUS retStatus;
|
|
PIRP irp;
|
|
PASYNC_IO_CTX AsyncIoCtx;
|
|
|
|
irp=
|
|
IoAllocateIrp(pNewInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
|
|
|
|
if (irp == NULL)
|
|
goto DEREF ;
|
|
|
|
|
|
AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pNewInfo);
|
|
|
|
if (AsyncIoCtx == NULL) {
|
|
IoFreeIrp(irp);
|
|
goto DEREF;
|
|
}
|
|
|
|
InitSerialIrp(irp,
|
|
pNewInfo,
|
|
IOCTL_SERIAL_PURGE,
|
|
sizeof(ULONG));
|
|
|
|
// kill all read and write threads.
|
|
AsyncIoCtx->SerialPurge =
|
|
SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT;
|
|
|
|
irp->AssociatedIrp.SystemBuffer=
|
|
&AsyncIoCtx->SerialPurge;
|
|
|
|
IoSetCompletionRoutine(irp, // irp to use
|
|
SerialIoSyncCompletionRoutine, // routine to call when irp is done
|
|
AsyncIoCtx, // context to pass routine
|
|
TRUE, // call on success
|
|
TRUE, // call on error
|
|
TRUE); // call on cancel
|
|
|
|
// Now simply invoke the driver at its dispatch entry with the IRP.
|
|
//
|
|
KeClearEvent(&AsyncIoCtx->Event);
|
|
retStatus = IoCallDriver(pNewInfo->DeviceObject, irp);
|
|
|
|
if (retStatus == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&AsyncIoCtx->Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
retStatus = AsyncIoCtx->IoStatus.Status;
|
|
}
|
|
|
|
IoFreeIrp(irp);
|
|
AsyncFreeIoCtx(AsyncIoCtx);
|
|
|
|
// if we do hit this code - wait for some time to let
|
|
// the read complete
|
|
//
|
|
KeDelayExecutionThread (KernelMode, FALSE, &li) ;
|
|
}
|
|
|
|
|
|
//
|
|
// Get rid of our reference to the serial port
|
|
//
|
|
DEREF:
|
|
ObDereferenceObject(pNewInfo->DeviceObject);
|
|
|
|
ObDereferenceObject(pNewInfo->FileObject);
|
|
|
|
NdisMIndicateStatus(Adapter->MiniportHandle,
|
|
NDIS_STATUS_WAN_LINE_DOWN, // General Status
|
|
&AsyncLineDown, // Specific Status
|
|
sizeof(NDIS_MAC_LINE_DOWN));
|
|
|
|
|
|
pNewInfo->Flags &= ~(ASYNC_FLAG_ASYNCMAC_OPEN);
|
|
//
|
|
// Deref the ref applied in IOCTL_ASYNCMAC_OPEN
|
|
//
|
|
DEREF_ASYNCINFO(pNewInfo, pNewInfo);
|
|
|
|
//
|
|
// Wait for ref on pNewInfo to go to 0
|
|
//
|
|
KeWaitForSingleObject(&pNewInfo->AsyncEvent,
|
|
UserRequest,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
// reacquire spin lock
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
RemoveEntryList(&pNewInfo->Linkage);
|
|
|
|
// decrement the reference count because we're done.
|
|
InterlockedDecrement(&Adapter->RefCount);
|
|
|
|
pNewInfo->PortState = PORT_CLOSED;
|
|
|
|
NdisFreeSpinLock(&pNewInfo->Lock);
|
|
|
|
ExFreeToNPagedLookasideList(&Adapter->AsyncFrameList,
|
|
pNewInfo->AsyncFrame);
|
|
|
|
ExFreeToNPagedLookasideList(&AsyncInfoList,
|
|
pNewInfo);
|
|
|
|
if (NdisInterlockedDecrement(&glConnectionCount) == 0) {
|
|
ObDereferenceObject(AsyncDeviceObject);
|
|
}
|
|
|
|
break; // get out of case statement
|
|
}
|
|
|
|
case IOCTL_ASYMAC_DCDCHANGE:
|
|
|
|
pNewInfo = (PASYNC_INFO)pDCDStruct->hNdisEndpoint;
|
|
|
|
// Verify that the pointer is a valid ASYNC_INFO
|
|
for (pListEntry=Adapter->ActivePorts.Flink;
|
|
pListEntry!=&Adapter->ActivePorts;
|
|
pListEntry=pListEntry->Flink)
|
|
{
|
|
if (&pNewInfo->Linkage==pListEntry)
|
|
{
|
|
Valid = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the port is already closed, we WILL complain
|
|
//
|
|
if (!Valid || pNewInfo->PortState == PORT_CLOSED) {
|
|
status=ASYNC_ERROR_PORT_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If any irps are pending, cancel all of them
|
|
// Only one irp can be outstanding at a time.
|
|
//
|
|
AsyncCancelAllQueued(&pNewInfo->DDCDQueue);
|
|
|
|
DbgTracef(0, ("ASYNC: Queueing up DDCD IRP\n"));
|
|
|
|
AsyncQueueIrp(&pNewInfo->DDCDQueue, pIrp);
|
|
|
|
//
|
|
// we'll have to wait for the SERIAL driver
|
|
// to flip DCD or DSR
|
|
//
|
|
status=STATUS_PENDING;
|
|
break;
|
|
|
|
} // end switch
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
return(status);
|
|
}
|
|
break;
|
|
|
|
} // end switch
|
|
|
|
return status;
|
|
}
|