📄 nic_recv.c
字号:
pHwRfd->RfdCbHeader.CbStatus = 0;
pHwRfd->RfdActualCount = 0;
pHwRfd->RfdCbHeader.CbCommand = (RFD_EL_BIT);
pHwRfd->RfdCbHeader.CbLinkPointer = DRIVER_NULL;
// Append this RFD to the RFD chain
if (!IsListEmpty(&FdoData->RecvList))
{
pLastMpRfd = (PMP_RFD)GetListTailEntry(&FdoData->RecvList);
// Link it onto the end of the chain dynamically
pHwRfd = pLastMpRfd->HwRfd;
pHwRfd->RfdCbHeader.CbLinkPointer = pMpRfd->HwRfdPhys;
pHwRfd->RfdCbHeader.CbCommand = 0;
}
//
// HW_SPECIFIC_END
//
//
// The processing on this RFD is done, so put it back on the tail of
// our list
//
InsertTailList(&FdoData->RecvList, (PLIST_ENTRY)pMpRfd);
FdoData->nReadyRecv++;
ASSERT(FdoData->nReadyRecv <= FdoData->CurrNumRfd);
}
NTSTATUS
NICStartRecv(
IN PFDO_DATA FdoData
)
/*++
Routine Description:
Start the receive unit if it's not in a ready state
Assumption: Rcv spinlock has been acquired
Arguments:
FdoData Pointer to our FdoData
Return Value:
NT Status code
--*/
{
PMP_RFD pMpRfd;
NTSTATUS status;
DebugPrint(TRACE, DBG_READ, "---> NICStartRecv\n");
//
// If the receiver is ready, then don't try to restart.
//
if (NIC_IS_RECV_READY(FdoData))
{
DebugPrint(LOUD, DBG_READ, "Receive unit already active\n");
return STATUS_SUCCESS;
}
DebugPrint(LOUD, DBG_READ, "Re-start receive unit...\n");
ASSERT(!IsListEmpty(&FdoData->RecvList));
//
// Get the MP_RFD head
//
pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
//
// If more packets are received, clean up RFD chain again
//
if (NIC_RFD_GET_STATUS(pMpRfd->HwRfd))
{
NICHandleRecvInterrupt(FdoData);
ASSERT(!IsListEmpty(&FdoData->RecvList));
//
// Get the new MP_RFD head
//
pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
}
//
// Wait for the SCB to clear before we set the general pointer
//
if (!WaitScb(FdoData))
{
status = STATUS_DEVICE_DATA_ERROR;
goto exit;
}
if (FdoData->DevicePowerState > PowerDeviceD0)
{
status = STATUS_DEVICE_DATA_ERROR;
goto exit;
}
//
// Set the SCB General Pointer to point the current Rfd
//
FdoData->CSRAddress->ScbGeneralPointer = pMpRfd->HwRfdPhys;
//
// Issue the SCB RU start command
//
status = D100IssueScbCommand(FdoData, SCB_RUC_START, FALSE);
if (status == STATUS_SUCCESS)
{
// wait for the command to be accepted
if (!WaitScb(FdoData))
{
status = STATUS_DEVICE_DATA_ERROR;
}
}
exit:
DebugPrint(TRACE, DBG_READ, "<--- NICStartRecv, Status=%x\n", status);
return status;
}
VOID
NICResetRecv(
IN PFDO_DATA FdoData
)
/*++
Routine Description:
Reset the receive list
Assumption: Rcv spinlock has been acquired
Arguments:
FdoData Pointer to our FdoData
Return Value:
None
--*/
{
PMP_RFD pMpRfd;
PHW_RFD pHwRfd;
LONG RfdCount;
DebugPrint(TRACE, DBG_READ, "--> NICResetRecv\n");
ASSERT(!IsListEmpty(&FdoData->RecvList));
//
// Get the MP_RFD head
//
pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
for (RfdCount = 0; RfdCount < FdoData->nReadyRecv; RfdCount++)
{
pHwRfd = pMpRfd->HwRfd;
pHwRfd->RfdCbHeader.CbStatus = 0;
pMpRfd = (PMP_RFD)GetListFLink(&pMpRfd->List);
}
DebugPrint(TRACE, DBG_READ, "<-- NICResetRecv\n");
}
VOID
NICServiceReadIrps(
PFDO_DATA FdoData,
PMP_RFD *PacketArray,
ULONG PacketArrayCount
)
/*++
Routine Description:
Copy the data from the recv buffers to pending read IRP buffers
and complete the IRP. When used as network driver, copy operation
can be avoided by devising a private interface between us and the
NDIS-WDM filter and have the NDIS-WDM edge to indicate our buffers
directly to NDIS.
Arguments:
FdoData Pointer to our FdoData
Return Value:
None
--*/
{
PIRP irp;
PLIST_ENTRY listEntry;
PMP_RFD pMpRfd = NULL;
ULONG index, length;
NTSTATUS status;
PVOID buffer;
DebugPrint(TRACE, DBG_READ, "--> NICServiceReadIrps\n");
//
// We need to dequeue all the entries in the queue, reset the cancel
// routine for each of them and then process then:
// - if the device is active, we will send them down
// - else we will complete them with STATUS_NO_SUCH_DEVICE
//
for(index=0; index < PacketArrayCount; index++)
{
pMpRfd = PacketArray[index];
ASSERT(pMpRfd);
//
// Acquire the queue lock before manipulating the list entries.
//
KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock);
while(TRUE){
if(IsListEmpty(&FdoData->RecvQueueHead))
{
KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
break;
}
//
// Remove a request from the queue.
//
listEntry = RemoveHeadList(&FdoData->RecvQueueHead);
irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
//
// Set the cancel routine to NULL. This is an atomic operation.
//
if (IoSetCancelRoutine(irp, NULL))
{
//
// Cancel routine cannot run now and cannot have already
// started to run.
//
KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
//
// Copy data from the RFD buffer to the IRP and complete
// the IRP
//
buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
if(!buffer){
status = STATUS_INSUFFICIENT_RESOURCES;
length = 0;
} else {
length = min(MmGetMdlByteCount(irp->MdlAddress), pMpRfd->PacketSize);
RtlCopyMemory(buffer, pMpRfd->Buffer, length);
DebugPrintEx((LOUD, DBG_READ,
"Received Packet Data: %!HEXDUMP!\n",
log_xstr(buffer, (USHORT)length)));
status = STATUS_SUCCESS;
}
irp->IoStatus.Status = status;
irp->IoStatus.Information = length;
IoCompleteRequest(irp, IO_NO_INCREMENT);
PciDrvIoDecrement (FdoData);
break;
}
else
{
//
// Cancel rotuine is running. Leave the irp alone.
//
InitializeListHead(&irp->Tail.Overlay.ListEntry);
irp = NULL;
continue;
}
}
KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock);
//
// Decrement the number of outstanding Recvs
//
PciDrvIoDecrement (FdoData);
ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_PEND));
MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_PEND);
if (FdoData->RfdShrinkCount < NIC_RFD_SHRINK_THRESHOLD)
{
NICReturnRFD(FdoData, pMpRfd);
}
else
{
ASSERT(FdoData->CurrNumRfd > FdoData->NumRfd);
//
// Queue a passive level callback to free RFD memory.
// Increment the IO count to accout for the pending workitem. This
// will prevent us from freeing resources during stop/remove until
// the workitem callback is executed.
//
PciDrvIoIncrement (FdoData);
status = PciDrvQueuePassiveLevelCallback(FdoData,
NICFreeRfdWorkItem, (PVOID)pMpRfd,
NULL);
if(NT_SUCCESS(status)){
FdoData->RfdShrinkCount = 0;
FdoData->CurrNumRfd--;
DebugPrint(TRACE, DBG_READ, "Shrink... CurrNumRfd = %d\n",
FdoData->CurrNumRfd);
} else {
PciDrvIoDecrement (FdoData); // Free the reference
//
// We couldn't queue a workitem to free memory, so let us
// put that back in the main pool and try again next time.
//
NICReturnRFD(FdoData, pMpRfd);
}
}
KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
}// end of loop
DebugPrint(TRACE, DBG_READ, "<-- NICServiceReadIrps\n");
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -