?? tdiclient.c
字號:
IN PVOID Options,
IN ULONG ReceiveDatagramFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
IN PVOID Tsdu,
OUT PIRP *IoRequestPacket
)
/*++
Routine Description:
TDI_EVENT_RECEIVE_DATAGRAM handle.
When a UDP packet from particular address and port arrive, this callback function will be called.
Usually BytesIndicated is less than or equal to BytesAvailable. If less, a Irp should be buildt
for the remainder data. This irp has be pre-allocated by TDIBuildRecvContext.
Note:
Don't forget to call IoSetNextIrpStackLocation to handle the IoRequestPacket.
Because the stack locations of this irp between this function and underlying transport are identical.
Pls refer to Windows DDK documentation chapter relevant to this handle.
--*/
{
LONG i;
PUCHAR p;
PIRP pIrp;
NTSTATUS status;
ULONG BytesToCopy;
ULONG stageSize;
PDEVICE_EXTENSION deviceExtension;
deviceExtension = (PDEVICE_EXTENSION)TdiEventContext;
DebugPrint(("SourceAddress: "));
p = (PUCHAR)SourceAddress;
for( i = 0; i < SourceAddressLength; i++)
{
DbgPrint("%2x ", p[ i ] );
}
DbgPrint(("\n"));
DebugPrint(("ReceiveDatagramFlags: %x\n", ReceiveDatagramFlags ));
DebugPrint(("BytesIndicated: %d\n", BytesIndicated ));
DebugPrint(("BytesAvailable: %d\n", BytesAvailable ));
*BytesTaken = BytesIndicated;
CopyToRingBuffer( deviceExtension, (PUCHAR)Tsdu, BytesIndicated );
*IoRequestPacket = NULL;
status = STATUS_SUCCESS;
if ( BytesIndicated < BytesAvailable )
{
if ( deviceExtension->recvContext.pIrp )
{
pIrp = deviceExtension->recvContext.pIrp;
DebugPrint(("EventRecvDatagram: pIrp = %x\n", deviceExtension->recvContext.pIrp ));
TdiBuildReceiveDatagram( pIrp,
deviceExtension->TDILowerDeviceObject,
deviceExtension->lpTransAddrFileObject,
TDIRecvRemainderCompRoutine,
deviceExtension,
deviceExtension->recvContext.pMdl,
0,
&(deviceExtension->recvContext.ReceiveDatagramInfo),
&(deviceExtension->recvContext.ReturnInfo),
TDI_RECEIVE_NORMAL);
IoSetNextIrpStackLocation ( pIrp );
*IoRequestPacket = pIrp;
status = STATUS_MORE_PROCESSING_REQUIRED;
}
}
return status;
}
VOID CopyToRingBuffer(
PDEVICE_EXTENSION deviceExtension,
PUCHAR LinearBuffer,
ULONG BytesIndicated )
/*++
Routine Description:
This function is called by TDIEventRecvDatagram and TDIRecvRemainderCompRoutine.
It copies linear buffer containing network packet to ring buffer. If source buffer length
is more than the length of ReceiveBuffer, the last part of LinearBuffer will be copied
to destination buffer.
If there is WaitOnMaskIrp in deviceExtension and the WaitMask meets SERIAL_EV_RXCHAR || SERIAL_EV_RLSD,
it will complete the WaitOnMaskIrp to indicate the application that there are some data arrive.
The destination ringbuffer, deviceExtension->RxBuffer, is shared with IRP_MJ_READ.
So the access to the ringbuffer must be synchronous.
Arguments:
deviceExtension - pointer to device object extension
LinearBuffer - Tsdu containing network packets.
BytesIndicated - the length of LinearBuffer
Return Value:
NT status code.
--*/
{
ULONG stageSize;
KIRQL oldIrql;
ULONG BytesToCopy;
PUCHAR lpSrc;
BytesToCopy = BytesIndicated;
lpSrc = LinearBuffer;
if ( BytesIndicated > RINGBUFFER_SIZE )
{
lpSrc = (PUCHAR)LinearBuffer + BytesIndicated - RINGBUFFER_SIZE;
BytesToCopy = RINGBUFFER_SIZE;
}
KeAcquireSpinLock(&deviceExtension->ThreadSpinLock, &oldIrql);
stageSize = deviceExtension->RxBuffer + RINGBUFFER_SIZE - deviceExtension->lpRx;
if( BytesToCopy <= stageSize )
RtlCopyMemory ( deviceExtension->lpRx, lpSrc, BytesToCopy );
else
{
RtlCopyMemory ( deviceExtension->lpRx, lpSrc, stageSize );
RtlCopyMemory ( deviceExtension->RxBuffer, lpSrc + stageSize, ( BytesToCopy - stageSize ) );
}
deviceExtension->lpRx = deviceExtension->RxBuffer + ( ( RINGBUFFER_SIZE - stageSize + BytesToCopy ) % RINGBUFFER_SIZE );
deviceExtension->SerialStatus.AmountInInQueue += BytesToCopy;
if ( deviceExtension->SerialStatus.AmountInInQueue > RINGBUFFER_SIZE )
{
deviceExtension->lpRead = deviceExtension->lpRx;
deviceExtension->SerialStatus.AmountInInQueue = RINGBUFFER_SIZE;
}
if( ( deviceExtension->WaitOnMaskIrp ) &&
( ( deviceExtension->WaitMask & SERIAL_EV_RXCHAR ) || ( deviceExtension->WaitMask & SERIAL_EV_RLSD ) ) )
{
DebugPrint(("ClientEventRecv: Complete WaitOnMaskIrp\n"));
deviceExtension->SerialStatus.EofReceived = TRUE;
*(PULONG)deviceExtension->WaitOnMaskIrp->AssociatedIrp.SystemBuffer = ( SERIAL_EV_RXCHAR | SERIAL_EV_RLSD );
CompleteRequest( deviceExtension->WaitOnMaskIrp, STATUS_SUCCESS, sizeof( ULONG ) );
deviceExtension->WaitOnMaskIrp = NULL;
SampleIoDecrement( deviceExtension );
}
KeReleaseSpinLock( &deviceExtension->ThreadSpinLock, oldIrql );
}
NTSTATUS TDIBuildRecvContext( PRECV_CONTEXT lpContext)
/*++
Routine Description:
This function is called by InitializeConnection.
It builds RecvContext, including pIrp, pMdl, and locks the Mdl.
Arguments:
lpContext - pointer to deviceExtension->recvContext
Return Value:
NT status code.
--*/
{
PIRP pIrp;
PMDL pMdl;
PDEVICE_EXTENSION deviceExtension;
EXCEPTION_POINTERS * pExceptionInfo;
ULONG lclExceptionCode;
PVOID lclExceptionAddr;
PIO_STACK_LOCATION ioStack;
if( lpContext->pIrp || lpContext->pMdl || ( lpContext->RemainderBuffer == NULL ) )
return STATUS_UNSUCCESSFUL;
deviceExtension = CONTAINING_RECORD( lpContext, DEVICE_EXTENSION, recvContext );
pIrp = IoAllocateIrp ( deviceExtension->TDILowerDeviceObject->StackSize + 2, FALSE );
/*
Because the irp will be used for many times, TdiBuildInternalDeviceControlIrp is not best.
*/
/* pIrp = TdiBuildInternalDeviceControlIrp(
TDI_RECEIVE_DATAGRAM,
deviceExtension->TDILowerDeviceObject,
deviceExtension->lpTransAddrFileObject,
&lpContext->Event,
&lpContext->IoStatus
);
*/
if (NULL == pIrp)
{
DebugPrint(("TdiBuildInternalIrp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}else
{
DebugPrint(("TDIBuildRecvContext: pIrp = %x\n", pIrp ));
}
pMdl = IoAllocateMdl ( lpContext->RemainderBuffer,
RECVREMAINDER_BUFFER_SIZE, FALSE, FALSE, NULL );
if (NULL==pMdl)
{
goto Error_Exit;
}
_try
{
// lockpage the Mdl, even though it is allocated based on NonPagesPool
MmProbeAndLockPages(pMdl, // (Try to) fix buffer.
KernelMode,
IoModifyAccess
);
lpContext->bLocked = TRUE;
DebugPrint(("RemainderBuffer: 0x%x, pMdl: 0x%x\n", lpContext->RemainderBuffer, pMdl ));
}
_except(
pExceptionInfo = GetExceptionInformation(),
lclExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode,
lclExceptionAddr = pExceptionInfo->ExceptionRecord->ExceptionAddress,
EXCEPTION_EXECUTE_HANDLER
)
{
DebugPrint((".TDIClnRecv: MmProbeAndLockPages() failed. Error = 0x%08x at 0x%08x\n",
lclExceptionCode, lclExceptionAddr));
goto Error_Exit;
}
lpContext->pIrp = pIrp;
lpContext->pMdl = pMdl;
return STATUS_SUCCESS;
Error_Exit:
if ( pMdl )
IoFreeMdl ( pMdl );
if ( pIrp )
IoFreeIrp ( pIrp );
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
TDIRecvRemainderCompRoutine(
PDEVICE_OBJECT DeviceObject, // TDI driver's device object.
PIRP pIrp, // Address of completed Irp.
PVOID pCtx // Pointer to context.
)
/*++
Routine Description:
Completion routine of IoRequestPacket in TDIEventRecvDatagram.
It copies receiving data in recvContext.RemainderBuffer to RxBuffer.
The length of receining data is indicated by pIrp->IoStatus.Information.
Arguments:
DeviceObject - pointer to the device object
pIrp - pointer to completed Irp, which is recvContext->pIrp
pCtx - pointer to context, which is deviceExtension
Return Value:
NT status code.
--*/
{
PDEVICE_EXTENSION deviceExtension;
PRECV_CONTEXT lpContext;
ULONG RecvDataLength;
PUCHAR lpSrc;
DebugPrint(("TDIRecvRemainderCompRoutine...\n"));
RecvDataLength = pIrp->IoStatus.Information;
deviceExtension = (PDEVICE_EXTENSION)pCtx;
DebugPrint(("Remainder length: %d\n", RecvDataLength ));
CopyToRingBuffer ( deviceExtension,
(PUCHAR)deviceExtension->recvContext.RemainderBuffer,
RecvDataLength );
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS TDIFreeRecvContext( PRECV_CONTEXT lpContext )
/*++
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -