362 lines
9.7 KiB
C
362 lines
9.7 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1992 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
detect.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
|
||
|
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"
|
||
|
|
||
|
VOID
|
||
|
SerialFlushReads(
|
||
|
PASYNC_INFO pInfo);
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
AsyncDetectCompletionRoutine(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp,
|
||
|
IN PASYNC_INFO pInfo)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
This is the IO Completion routine for ReadFrame.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
PASYNC_FRAME pFrame;
|
||
|
PUCHAR frameStart;
|
||
|
|
||
|
DbgTracef(-1,("Entering AsyncDetectCompletionRoutine\n"));
|
||
|
|
||
|
status = Irp->IoStatus.Status;
|
||
|
|
||
|
pInfo->BytesRead = (ULONG)Irp->IoStatus.Information;
|
||
|
|
||
|
IoFreeIrp(Irp);
|
||
|
|
||
|
pFrame=pInfo->AsyncFrame;
|
||
|
|
||
|
DbgTracef(2,("DET PortState = %u for Info 0x%.8x\n", pInfo->PortState, pInfo));
|
||
|
|
||
|
//
|
||
|
// check if this port is closing down or already closed
|
||
|
//
|
||
|
if (pInfo->PortState == PORT_CLOSING ||
|
||
|
pInfo->PortState == PORT_CLOSED) {
|
||
|
|
||
|
if (pInfo->PortState == PORT_CLOSED) {
|
||
|
DbgTracef(-2,("ASYNC: Port closed - but still reading on it!\n"));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Acknowledge that the port is closed
|
||
|
//
|
||
|
KeSetEvent(
|
||
|
&pInfo->ClosingEvent, // Event
|
||
|
1, // Priority
|
||
|
(BOOLEAN)FALSE); // Wait (does not follow)
|
||
|
|
||
|
//
|
||
|
// Ok, if this happens, we are shutting down. Stop
|
||
|
// posting reads. Don't make it try to deallocate the irp!
|
||
|
//
|
||
|
return(STATUS_MORE_PROCESSING_REQUIRED);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the port is close and we are still posting reads, something
|
||
|
// is seriously wrong here!
|
||
|
//
|
||
|
|
||
|
if (pInfo->PortState == PORT_CLOSED) {
|
||
|
DbgTracef(-2, ("ASYNC: !!Whoa, I'm reading bytes on a dead port!!\n"));
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Send off a irp to check comm status
|
||
|
//
|
||
|
|
||
|
AsyncCheckCommStatus(pInfo);
|
||
|
|
||
|
switch (status) {
|
||
|
|
||
|
case STATUS_SUCCESS:
|
||
|
|
||
|
//
|
||
|
// Look at the first byte and see if we can
|
||
|
// detect the framing.
|
||
|
//
|
||
|
frameStart=pFrame->Frame + PPP_PADDING;
|
||
|
|
||
|
//
|
||
|
// NOTE: New RAS framing clients come in with 0x02 not 0x01
|
||
|
//
|
||
|
if (frameStart[0] == SYN && (frameStart[1]==0x01 || frameStart[1] == 0x02)) {
|
||
|
ULONG bytesWanted;
|
||
|
PUCHAR frameStart2;
|
||
|
|
||
|
pInfo->SetLinkInfo.SendFramingBits =
|
||
|
pInfo->SetLinkInfo.RecvFramingBits = RAS_FRAMING;
|
||
|
|
||
|
DbgTracef(-1,("ASYNC: RAS framing detected\n"));
|
||
|
|
||
|
frameStart2=pFrame->Frame+10;
|
||
|
|
||
|
//
|
||
|
// Adjust buffer for old RAS read
|
||
|
//
|
||
|
ASYNC_MOVE_MEMORY(
|
||
|
frameStart2,
|
||
|
frameStart,
|
||
|
6);
|
||
|
|
||
|
frameStart=frameStart2;
|
||
|
|
||
|
bytesWanted=(frameStart[2]*256)+(frameStart[3]);
|
||
|
|
||
|
if (bytesWanted > (ULONG)(max( pInfo->Adapter->MaxFrameSize, DEFAULT_EXPANDED_PPP_MAX_FRAME_SIZE ))) {
|
||
|
|
||
|
DbgTracef(-1,("---ASYNC: Frame too large -- size: %d!\n", bytesWanted));
|
||
|
//
|
||
|
// set frame start to non-SYN character
|
||
|
//
|
||
|
*frameStart = 0;
|
||
|
pInfo->BytesRead=0;
|
||
|
pInfo->BytesWanted=6;
|
||
|
|
||
|
//
|
||
|
// break added to fix problem where frame has length
|
||
|
// greater than max frame size. This will send us back
|
||
|
// to detect the next frame! Added 10/31/95 by TonyBe.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// if this is the first we posted, post another to get
|
||
|
// rest of frame.
|
||
|
if (pInfo->BytesRead == 6) {
|
||
|
|
||
|
pInfo->BytesRead=6;
|
||
|
pInfo->BytesWanted=bytesWanted +
|
||
|
// SYN+SOH+LEN+ETX+CRC
|
||
|
1 + 1 + 2 + 1 + 2 -
|
||
|
6;
|
||
|
|
||
|
DbgTracef(2,("---Posting second read for %d bytes\n",pInfo->BytesWanted));
|
||
|
}
|
||
|
|
||
|
} else
|
||
|
|
||
|
//
|
||
|
// It turns out that NetManage send the flag byte at the
|
||
|
// end always. This means taht their first frame is wrong.
|
||
|
// Anyway, this throws off the detect routine. So, we
|
||
|
// will be robust and accept frames without the FLAG_BYTE.
|
||
|
//
|
||
|
|
||
|
if ((frameStart[0] == PPP_FLAG_BYTE && frameStart[1]==0xFF) ||
|
||
|
(frameStart[0] == 0xFF && frameStart[1]==PPP_ESC_BYTE)) {
|
||
|
|
||
|
pInfo->SetLinkInfo.SendFramingBits =
|
||
|
pInfo->SetLinkInfo.RecvFramingBits = PPP_FRAMING;
|
||
|
pInfo->SetLinkInfo.SendACCM=0xFFFFFFFF;
|
||
|
|
||
|
DbgTracef(-1,("ASYNC: PPP framing detected\n"));
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
//
|
||
|
// Read again!
|
||
|
//
|
||
|
|
||
|
DbgTracef(-1,("ASYNC: No framing detected yet\n"));
|
||
|
DbgTracef(-1,("ASYNC: Got %.2x %.2x %.2x %.2x %.2x %.2x\n",
|
||
|
frameStart[0],
|
||
|
frameStart[1],
|
||
|
frameStart[2],
|
||
|
frameStart[3],
|
||
|
frameStart[4],
|
||
|
frameStart[5]));
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// set framing mode active
|
||
|
//
|
||
|
pInfo->PortState = PORT_FRAMING;
|
||
|
|
||
|
//
|
||
|
// Send off the worker thread to start reading frames
|
||
|
// off this port - we want to be at passive level otherwise
|
||
|
// it don't work.
|
||
|
//
|
||
|
|
||
|
ExInitializeWorkItem(&(pInfo->WorkItem),
|
||
|
(PWORKER_THREAD_ROUTINE)AsyncStartReads,
|
||
|
pInfo);
|
||
|
|
||
|
ExQueueWorkItem(&(pInfo->WorkItem), DelayedWorkQueue);
|
||
|
|
||
|
return(STATUS_MORE_PROCESSING_REQUIRED);
|
||
|
|
||
|
case STATUS_TIMEOUT:
|
||
|
DbgTracef(-1,("---ASYNC: detect Status %x%0.8x on read\n", status));
|
||
|
break;
|
||
|
|
||
|
case STATUS_CANCELLED:
|
||
|
case STATUS_PORT_DISCONNECTED:
|
||
|
default:
|
||
|
return(STATUS_MORE_PROCESSING_REQUIRED);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Wipe out rest of this buffer
|
||
|
//
|
||
|
SerialFlushReads(pInfo);
|
||
|
|
||
|
KeClearEvent(&pInfo->DetectEvent);
|
||
|
|
||
|
//
|
||
|
// Here we are at the end of processing this IRP so we go
|
||
|
// ahead and post another read from the serial port.
|
||
|
//
|
||
|
// this is done on a worker since we run out of stack otherwise
|
||
|
//
|
||
|
ExInitializeWorkItem(&(pInfo->WorkItem),
|
||
|
(PWORKER_THREAD_ROUTINE) AsyncDetectRead,
|
||
|
pInfo);
|
||
|
|
||
|
ExQueueWorkItem(&(pInfo->WorkItem), DelayedWorkQueue);
|
||
|
|
||
|
// We return STATUS_MORE_PROCESSING_REQUIRED so that the
|
||
|
// IoCompletionRoutine will stop working on the IRP.
|
||
|
//
|
||
|
return(STATUS_MORE_PROCESSING_REQUIRED);
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
AsyncDetectRead(
|
||
|
IN PASYNC_INFO pInfo)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
PIRP irp;
|
||
|
PDEVICE_OBJECT deviceObject=pInfo->DeviceObject;
|
||
|
PFILE_OBJECT fileObject=pInfo->FileObject;
|
||
|
PIO_STACK_LOCATION irpSp;
|
||
|
PASYNC_FRAME pFrame;
|
||
|
PASYNC_ADAPTER pAdapter=pInfo->Adapter;
|
||
|
|
||
|
DbgTracef(-1,("Entering AsyncDetectRead\n"));
|
||
|
|
||
|
do {
|
||
|
|
||
|
if (pInfo->PortState == PORT_CLOSING ||
|
||
|
pInfo->PortState == PORT_CLOSED) {
|
||
|
|
||
|
status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// get ptr to first frame in list...
|
||
|
pFrame=pInfo->AsyncFrame;
|
||
|
|
||
|
irp =
|
||
|
IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
|
||
|
|
||
|
// Setup this irp with defaults
|
||
|
AsyncSetupIrp(pFrame, irp);
|
||
|
|
||
|
irp->AssociatedIrp.SystemBuffer =
|
||
|
irp->UserBuffer =
|
||
|
pFrame->Frame + PPP_PADDING;
|
||
|
|
||
|
//
|
||
|
// Get a pointer to the stack location for the first driver. This will be
|
||
|
// used to pass the original function codes and parameters.
|
||
|
//
|
||
|
|
||
|
irpSp = IoGetNextIrpStackLocation(irp);
|
||
|
irpSp->MajorFunction = IRP_MJ_READ;
|
||
|
irpSp->FileObject = fileObject;
|
||
|
if (fileObject->Flags & FO_WRITE_THROUGH) {
|
||
|
irpSp->Flags = SL_WRITE_THROUGH;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If this write operation is to be performed without any caching, set the
|
||
|
// appropriate flag in the IRP so no caching is performed.
|
||
|
//
|
||
|
|
||
|
irp->Flags |= IRP_READ_OPERATION;
|
||
|
|
||
|
if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
|
||
|
irp->Flags |= IRP_NOCACHE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Copy the caller's parameters to the service-specific portion of the
|
||
|
// IRP.
|
||
|
//
|
||
|
|
||
|
irpSp->Parameters.Read.Length = 6; // from frame...
|
||
|
irpSp->Parameters.Read.Key = 0; // we don't use a key
|
||
|
irpSp->Parameters.Read.ByteOffset = fileObject->CurrentByteOffset;
|
||
|
|
||
|
IoSetCompletionRoutine(
|
||
|
irp, // irp to use
|
||
|
AsyncDetectCompletionRoutine, // routine to call when irp is done
|
||
|
pInfo, // context to pass routine
|
||
|
TRUE, // call on success
|
||
|
TRUE, // call on error
|
||
|
TRUE); // call on cancel
|
||
|
|
||
|
//
|
||
|
// We DO NOT insert the packet at the head of the IRP list for the thread.
|
||
|
// because we do NOT really have an IoCompletionRoutine that does
|
||
|
// anything with the thread.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Now simply invoke the driver at its dispatch entry with the IRP.
|
||
|
//
|
||
|
|
||
|
status = IoCallDriver(deviceObject, irp);
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
KeSetEvent(&pInfo->DetectEvent,
|
||
|
1,
|
||
|
FALSE);
|
||
|
|
||
|
return(status);
|
||
|
}
|