/*++ 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 sends the flag byte at the // end always. This means that 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 = AsyncInfo->ExtendedACCM[0] = 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); }