📄 receive.c
字号:
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Module Name:
RECV.C
Abstract:
This module contains miniport functions for handling Send & Receive
packets and other helper routines called by these miniport functions.
Author: Eliyas Yakub (Jan 11, 2003)
Revision History:
Notes:
--*/
#include "ndiswdm.h"
VOID
MPReturnPacket(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet)
/*++
Routine Description:
NDIS Miniport entry point called whenever protocols are done with
a packet that we had indicated up and they had queued up for returning
later.
Arguments:
MiniportAdapterContext - pointer to MP_ADAPTER structure
Packet - packet being returned.
Return Value:
None.
--*/
{
PRCB pRCB = NULL;
PMP_ADAPTER Adapter;
DEBUGP(MP_TRACE, ("---> MPReturnPacket\n"));
pRCB = *(PRCB *)Packet->MiniportReserved;
Adapter = pRCB->Adapter;
ASSERT(Adapter);
Adapter->nPacketsReturned++;
if(NdisInterlockedDecrement(&pRCB->Ref) == 0)
{
NICFreeRCB(pRCB);
}
DEBUGP(MP_TRACE, ("<--- MPReturnPacket\n"));
}
VOID
NICPostReadsWorkItemCallBack(
PNDIS_WORK_ITEM WorkItem,
PVOID Context
)
/*++
Routine Description:
Workitem to post all the free read requests to the target
driver. This workitme is scheduled from the MiniportInitialize
worker routine during start and also from the NICFreeRCB whenever
the outstanding read requests to the target driver goes below
the NIC_SEND_LOW_WATERMARK.
Arguments:
WorkItem - Pointer to workitem
Dummy - Unused
Return Value:
None.
--*/
{
PMP_ADAPTER Adapter = (PMP_ADAPTER)Context;
NTSTATUS ntStatus;
PRCB pRCB=NULL;
DEBUGP(MP_TRACE, ("--->NICPostReadsWorkItemCallBack\n"));
NdisAcquireSpinLock(&Adapter->RecvLock);
while(MP_IS_READY(Adapter) && !IsListEmpty(&Adapter->RecvFreeList))
{
pRCB = (PRCB) RemoveHeadList(&Adapter->RecvFreeList);
ASSERT(pRCB);// cannot be NULL
//
// Insert the RCB in the recv busy queue
//
NdisInterlockedIncrement(&Adapter->nBusyRecv);
ASSERT(Adapter->nBusyRecv <= NIC_MAX_BUSY_RECVS);
InsertTailList(&Adapter->RecvBusyList, &pRCB->List);
NdisReleaseSpinLock(&Adapter->RecvLock);
Adapter->nReadsPosted++;
ntStatus = NICPostReadRequest(Adapter, pRCB);
if (!NT_SUCCESS ( ntStatus ) ) {
DEBUGP (MP_ERROR, ( "NICPostReadRequest failed %x\n", ntStatus ));
break;
}
NdisAcquireSpinLock(&Adapter->RecvLock);
}
NdisReleaseSpinLock(&Adapter->RecvLock);
//
// Clear the flag to let the WorkItem structure be reused for
// scheduling another one.
//
InterlockedExchange(&Adapter->IsReadWorkItemQueued, FALSE);
MP_DEC_REF(Adapter);
DEBUGP(MP_TRACE, ("<---NICPostReadsWorkItemCallBack\n"));
}
NTSTATUS
NICPostReadRequest(
PMP_ADAPTER Adapter,
PRCB pRCB
)
/*++
Routine Description:
This routine sends a read IRP to the target device to get
the incoming network packet from the device.
Arguments:
Adapter - pointer to the MP_ADAPTER structure
pRCB - Pointer to the RCB block that contains the IRP.
Return Value:
NT status code
--*/
{
NTSTATUS status;
PIRP irp = pRCB->Irp;
PIO_STACK_LOCATION nextStack;
PDEVICE_OBJECT TargetDeviceObject = Adapter->TargetDeviceObject;
DEBUGP(MP_TRACE, ("--> NICPostReadRequest\n"));
//
// Obtain a pointer to the stack location of the first driver that will be
// invoked. This is where the function codes and the parameters are set.
//
nextStack = IoGetNextIrpStackLocation(irp);
nextStack->MajorFunction = IRP_MJ_READ;
nextStack->Parameters.Read.Length = NIC_BUFFER_SIZE;
nextStack->FileObject = Adapter->FileObject;
irp->MdlAddress = (PMDL) pRCB->Buffer;
pRCB->IrpLock = IRPLOCK_CANCELABLE;
pRCB->Ref = 1;
IoSetCompletionRoutine(irp,
NICReadRequestCompletion,
pRCB,
TRUE,
TRUE,
TRUE);
//
// We are making an asynchronous request, so we don't really care
// about the return status of IoCallDriver.
//
(void) IoCallDriver(TargetDeviceObject, irp);
DEBUGP(MP_TRACE, ("<-- NICPostReadRequest\n"));
return STATUS_SUCCESS;
}
NTSTATUS
NICReadRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Completion routine for the read request. This routine
indicates the received packet from the WDM driver to
NDIS. This routine also handles the case where another
thread has canceled the read request.
Arguments:
DeviceObject - not used. Should be NULL
Irp - Pointer to our read IRP
Context - pointer to our adapter context structure
Return Value:
STATUS_MORE_PROCESSING_REQUIRED - because this is an asynchronouse IRP
and we want to reuse it.
--*/
{
PRCB pRCB = (PRCB)Context;
PMP_ADAPTER Adapter = pRCB->Adapter;
ULONG bytesRead;
BOOLEAN bIndicateReceive = FALSE;
DEBUGP(MP_TRACE, ("--> NICReadRequestCompletion\n"));
if(!NT_SUCCESS(Irp->IoStatus.Status)) {
Adapter->nReadsCompletedWithError++;
DEBUGP (MP_LOUD, ("Read request failed %x\n", Irp->IoStatus.Status));
//
// Clear the flag to prevent any more reads from being
// posted to the target device.
//
MP_CLEAR_FLAG(Adapter, fMP_POST_READS);
} else {
Adapter->GoodReceives++;
bytesRead = (ULONG)Irp->IoStatus.Information;
DEBUGP (MP_VERY_LOUD, ("Read %d bytes\n", bytesRead));
Adapter->nBytesRead += bytesRead;
bIndicateReceive = TRUE;
}
if (InterlockedExchange((PVOID)&pRCB->IrpLock, IRPLOCK_COMPLETED)
== IRPLOCK_CANCEL_STARTED) {
//
// NICFreeBusyRecvPackets has got the control of the IRP. It will
// now take the responsibility of freeing the IRP.
// Therefore...
return STATUS_MORE_PROCESSING_REQUIRED;
}
if(bIndicateReceive) {
NICIndicateReceivedPacket(pRCB, bytesRead);
}
if(NdisInterlockedDecrement(&pRCB->Ref) == 0)
{
NICFreeRCB(pRCB);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
NICIndicateReceivedPacket(
IN PRCB pRCB,
IN ULONG BytesToIndicate
)
/*++
Routine Description:
Initialize the packet to describe the received data and
indicate to NDIS.
Arguments:
pRCB - pointer to the RCB block
BytesToIndicate - number of bytes to indicate
Return value:
VOID
--*/
{
ULONG PacketLength;
PNDIS_BUFFER CurrentBuffer = NULL;
PETH_HEADER pEthHeader = NULL;
PMP_ADAPTER Adapter = pRCB->Adapter;
PNDIS_PACKET Packet = pRCB->Packet;
KIRQL oldIrql;
NdisAdjustBufferLength(pRCB->Buffer, BytesToIndicate);
//
// Prepare the recv packet
//
NdisReinitializePacket(Packet);
*((PRCB *)Packet->MiniportReserved) = pRCB;
//
// Chain the TCB buffers to the packet
//
NdisChainBufferAtBack(Packet, pRCB->Buffer);
NdisQueryPacket(Packet, NULL, NULL, &CurrentBuffer,&PacketLength);
ASSERT(CurrentBuffer == pRCB->Buffer);
pEthHeader = (PETH_HEADER)pRCB->pData;
if(PacketLength >= sizeof(ETH_HEADER) &&
Adapter->PacketFilter &&
NICIsPacketAcceptable(Adapter, pEthHeader->DstAddr)){
DEBUGP(MP_LOUD, ("Src Address = %02x-%02x-%02x-%02x-%02x-%02x",
pEthHeader->SrcAddr[0],
pEthHeader->SrcAddr[1],
pEthHeader->SrcAddr[2],
pEthHeader->SrcAddr[3],
pEthHeader->SrcAddr[4],
pEthHeader->SrcAddr[5]));
DEBUGP(MP_LOUD, (" Dest Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
pEthHeader->DstAddr[0],
pEthHeader->DstAddr[1],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -