📄 wdmvnicadap.cpp
字号:
// Complete the packet we just processed
SendComplete(pContext->type.m_Packet, NDIS_STATUS_SUCCESS);
// release all resources associated with this request
if ( pContext )
{
delete pContext;
}
// Free the IRP back to our pool
m_TxIrpPool.Free(pIrp);
// If any packets are in the queue, dequeue them, send them
KNdisPacket QueuePacket = m_TxQueue.RemoveHead();
while (QueuePacket.IsValid())
{
TRACE("Sending queued Tx packet\n");
// Attempt to put it onto the hardware
NDIS_STATUS Status = TxPacket(QueuePacket);
// If there were no resources for this packet, then we'll just have
// to try and send it later.
if (Status == NDIS_STATUS_RESOURCES)
{
// re-queue the packet
m_TxQueue.InsertHead(QueuePacket);
QueuePacket = NULL;
}
else
{
QueuePacket = m_TxQueue.RemoveHead();
}
}
// return indicates that system is to quit processing IRP completion
return STATUS_MORE_PROCESSING_REQUIRED;
}
////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::ReturnPacket
//
// This method is called when NDIS returns a packet previuosly
// indicated by IndicateReceive() back to the miniport
//
// Parameters:
// Packet
// Points to a packet descriptor specifying the packet
// IRQL:
// DISPATCH_LEVEL
// Return Mode:
// n/a
// NOTE:
// The packet returns to the "free list" in the Rx area.
// Reclaim() does the necessary reset of the chained buffer
// and OOB data if any.
VOID WdmVNICAdapter::ReturnPacket(IN PNDIS_PACKET Packet)
{
TRACE("WdmVNICAdapter::ReturnPacket() Entered Packet=%X\n", Packet);
// Allocate a work item off the heap. This will be used to submit our IRP to the
// driver managed queue for processing. This allows the calling thread to
// continue along merrily.
PNDIS_WORK_ITEM_CTX pWorkItemCtx = new NDIS_WORK_ITEM_CTX;
ASSERT(pWorkItemCtx);
if (pWorkItemCtx) {
pWorkItemCtx->m_pAdapter = this;
pWorkItemCtx->m_Packet = Packet;
NdisInitializeWorkItem(
&pWorkItemCtx->m_WorkItem,
OnReturnPacketX,
pWorkItemCtx
);
if (NDIS_STATUS_SUCCESS != NdisScheduleWorkItem(&pWorkItemCtx->m_WorkItem))
delete pWorkItemCtx;
}
}
////////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::OnReturnPacket
//
// Callback handler for the QueueReturnPacketWorkItem
//
// Input
// pItem Pointer to our work item
//
// Output
//
// Notes
//
VOID WdmVNICAdapter::OnReturnPacket(PNDIS_WORK_ITEM_CTX pCtx)
{
ASSERT(pCtx);
if (pCtx) {
KNdisPacket Packet(pCtx->m_Packet);
// Reclaim the packet back into our receive area
// Note: Can't hold spin lock while calling this method
m_pRxArea->Reclaim(Packet);
// Submit the IRP to the bus device
PHW_RFD pHwRfd = reinterpret_cast<PHW_RFD>(m_pRxArea->GetDescriptor(Packet));
m_BusDevice.Call(pHwRfd->m_pIrp);
delete pCtx;
}
}
VOID WdmVNICAdapter::StartReceiveUnit(void)
{
PHW_RFD pHwRfd = m_RxIrpList.Head();
while (pHwRfd)
{
// Increment the number of IRPs in play
++m_RxIrpsOutstanding;
m_BusDevice.Call(pHwRfd->m_pIrp);
pHwRfd = m_RxIrpList.Next(pHwRfd);
}
}
///////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::CompletionRxRoutine
//
// Parameters:
// pIrp - irp being completed
// Context - context passed when the irp had been submitted
// IRQL:
// IRQL DISPATCH_LEVEL
// Returns:
// Usually, STATUS_MORE_PROCESSING_REQUIRED
// NOTE:
// Processes asynchronous "receive" IRP completions: this is a "HandleInterrupt()"
// thing for NDIS WDM drivers. So, the logic is similar to HandleInterrupt():
// If a new received packet arrived indicate it to NDIS. Handle status indications, too.
// The important point is that if the the irps are be recycled back to the pools they
// came from, STATUS_MORE_PROCESSING_REQUIRED should be returned to the system.
// NOTE: Under Win9X, NDIS packet and status indications must NOT be made from
// the completion routine context. Instead, the NDIS WDM driver should schedule an
// NDIS timer callback that would post the indication to NDIS.
NTSTATUS WdmVNICAdapter::CompletionRxRoutine(PIRP pIrp, WdmVNICAdapter::IRP_CONTEXT* pContext)
{
TRACE("WdmVNICAdapter::RxPacketComplete() Entered\n");
// Figure from Context/pIrp what has completed: receive or status
// If the status of the IRP is not STATUS_SUCCESS or the m_HaltFlag is set
// do not process this IRP. Instead, decrement the m_RxIrpsOutstanding IRPs
// and signal the m_RxIdleEvent if the counter reaches zero.
KIrp I(pIrp);
if ( I.Status() != STATUS_SUCCESS || m_HaltFlag )
{
TRACE("IRP completion status = %08x, HaltFlag = %d\n", ULONG(I.Status()), ULONG(m_HaltFlag));
if(!--m_RxIrpsOutstanding)
{
m_RxIdleEvent.Set();
TRACE("Setting RxIdleEvent");
}
// return indicates that system is to quit processing IRP completion
return STATUS_MORE_PROCESSING_REQUIRED;
}
PHW_RFD pHwRfd = pContext->type.m_pHwRfd;
#if KNDIS_W9X_COMPATIBLE
// For Win9x, it is not safe to indicate the packet to NDIS from the context of a
// non-NDIS thread, so we must queue the packet, set an NDIS timer, and indicate the packet
// from the timer callback
m_RxIndicateQueue.InsertTail(pHwRfd);
m_Timer.Set(10);
#else // KNDIS_W9X_COMPATIBLE
CompleteHwRfd(pHwRfd);
#endif // KNDIS_W9X_COMPATIBLE
// return indicates that system is to quit processing IRP completion
return STATUS_MORE_PROCESSING_REQUIRED;
}
#if KNDIS_W9X_COMPATIBLE
////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::IndicateCallback
// Callback routine for the NDIS timer used to indicate packets
// in a Win9x compliant manner
// Parameters:
// none
// IRQL:
// IRQL DISPATCH_LEVEL
// Return Mode:
// Synchronous
// NOTE:
// This timer is an NDIS timer, and therefore operates in the context
// of an NDIS thread.
//
VOID WdmVNICAdapter::IndicateCallback(void)
{
PHW_RFD pHwRfd = m_RxIndicateQueue.RemoveHead();
while (pHwRfd)
{
CompleteHwRfd(pHwRfd);
pHwRfd = m_RxIndicateQueue.RemoveHead();
}
}
#endif // KNDIS_W9X_COMPATIBLE
////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::CompleteHwRfd
// Helper routine to complete the HW_RFD
// Parameters:
// PHW_RFD - pointer to the HW_RFD to be completed
// IRQL:
// IRQL DISPATCH_LEVEL
// Return Mode:
// Synchronous
// NOTE:
// This routine is simply common code shared between CompletionRxRoutine
// and IndicateCallback
//
VOID WdmVNICAdapter::CompleteHwRfd(PHW_RFD pHwRfd)
{
// Get the current packet based on the HW_RFD pointer stored in the context
KNdisPacket Packet(m_pRxArea->GetPacket(pHwRfd));
ASSERT( Packet.IsValid() );
// Get the current buffer
KNdisBuffer Buf = Packet.QueryFirstBuffer();
ASSERT( Buf.IsValid() );
// Check the Information field to see if the packet is valid. If so, indicate the packet, otherwise
// recycle the HW_RFD now.
//
// Determining if a completed IRP contains a valid packet is dependent on specifics of
// the lower device
KIrp I(pHwRfd->m_pIrp);
if (I.Information())
{
// The simulator saves the buffer length in the information field. Store
// this in the HW_RFD
pHwRfd->m_RfdActualCount = (ULONG)I.Information();
// Remove the RFD from the free list
m_pRxArea->Complete(pHwRfd);
// Get the packet length
ULONG FrameLength = pHwRfd->m_RfdActualCount;
ASSERT( FrameLength <= MAXIMUM_ETHERNET_PACKET_SIZE );
TRACE("Received packet length %d\n", FrameLength);
// Adjust the buffer length for this sw rfd
Buf.AdjustLength(FrameLength);
// Indicate the packet to NDIS
IndicateReceive(Packet);
}
else
{
// Reclaim the packet back into our receive area
m_pRxArea->Reclaim(Packet);
// Submit the IRP to the bus device
m_BusDevice.Call(pHwRfd->m_pIrp);
}
}
////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::CheckForHang
// Optional function that reports the state of the NIC or monitors
// the responsiveness of an underlying device driver.
// Parameters:
// none
// IRQL:
// IRQL DISPATCH_LEVEL
// Return Mode:
// Synchronous
// NOTE:
// By default, the NDIS library calls MiniportCheckForHang
// approximately every two seconds. If MiniportCheckForHang returns
// TRUE, NDIS then calls the driver's MiniportReset function.
BOOLEAN WdmVNICAdapter::CheckForHang()
{
// TODO: Check the h/w for hang
return FALSE;
}
VOID WdmVNICAdapter::DescriptorInitialize(
PHW_RFD pHwDesc, //The descriptor to initialize
PNDIS_PHYSICAL_ADDRESS pPhysAddr //Pointer to the physical address of the descriptor
)
{
TRACE("WdmVNICAdapter::DescriptorInitialize\n");
// Called from KNdisSharedReceiveArea ctor on initial descriptor chain setup
// for each hardware Receive Frame Descriptor (FRD)
// must initialize the hardware Receive Frame Descriptor
// Allocate an IRP for this descriptor
KIrp I = KIrp::Allocate(m_TopOfStackDeviceObject->StackSize);
if (I.IsNull())
{
ASSERT("No IRPs left in Rx Pool");
return;
}
pHwDesc->m_pIrp = I;
pHwDesc->m_IrpContext.Adapter = this;
pHwDesc->m_IrpContext.type.m_pHwRfd = pHwDesc; // back pointer to our HW_RFD
pHwDesc->m_RfdActualCount= 0;
pHwDesc->m_RfdSize = sizeof(ETH_RX_BUFFER_STRUC);
// Set the completion routine on the IRP and submit it to the bus device
I.SetCompletionRoutine(WdmCompletionRxRoutine(this), &pHwDesc->m_IrpContext);
// Allocate an NDIS_BUFFER describing the RfdBuffer in the HW_RFD structure. We will attach
// this MDL to the IRP.
//
// Note that the method in which data is attached to the IRP, and the format of that data
// is dependent on the particular system bus and device properties. In this case we are
// simply using the same buffer that the receive area will be using and assuming that the
// data will be in TCP/IP format, ready for indication by the miniport.
KNdisBuffer Buf = m_RxBufPool.Allocate(&pHwDesc->m_RfdBuffer ,pHwDesc->m_RfdSize);
if (!Buf.IsValid())
{
ASSERT("Cannot allocate memory for NDIS_BUFFER");
KIrp::Deallocate(I);
return;
}
I.Mdl() = (PNDIS_BUFFER) Buf;
// Add the IRP to the RxIrp list
m_RxIrpList.InsertTail(pHwDesc);
DumpHwRfd(pHwDesc);
}
VOID WdmVNICAdapter::DescriptorInvalidate(
PHW_RFD pHwDesc //The descriptor to inivalidate
)
{
// Free the MDL we associated with the IRP
KIrp I(pHwDesc->m_pIrp);
KNdisBuffer Buf((PNDIS_BUFFER)I.Mdl());
if (Buf.IsValid()) {
m_RxBufPool.Free(Buf);
}
I.Mdl() = NULL;
// Free the IRP
KIrp::Deallocate(I);
}
VOID WdmVNICAdapter::DescriptorComplete(
PHW_RFD pHwDesc, //The descriptor to initialize
PNDIS_PHYSICAL_ADDRESS pPhysAddr //Pointer to the physical address of the descriptor
)
{
TRACE("WdmVNICAdapter::DescriptorComplete\n");
DumpHwRfd(pHwDesc);
}
VOID WdmVNICAdapter::DescriptorReclaim(
PHW_RFD pHwDesc, //The descriptor to initialize
PNDIS_PHYSICAL_ADDRESS pPhysAddr //Pointer to the physical address of the descriptor
)
{
TRACE("WdmVNICAdapter::DescriptorReclaim\n");
// Called from KNdisSystemReceiveArea Reclaim method
// for each hardware Receive Frame Descriptor (HW_RFD) we
// must re-initialize
// We are done with this RFD so re-initialize it.
pHwDesc->m_RfdActualCount= 0;
// Reinitialize the IRP, saving the MDL so it can be reassociated with the IRP after
// the IRP has been reset
KIrp I(pHwDesc->m_pIrp);
KMemory mem(I.Mdl());
I.Reuse();
// Set the completion routine on the IRP and submit it to the bus device
I.SetCompletionRoutine(WdmCompletionRxRoutine(this), &pHwDesc->m_IrpContext);
I.Mdl() = mem;
DumpHwRfd(pHwDesc);
}
VOID WdmVNICAdapter::DumpHwRfd(PHW_RFD p)
{
// TRACE(" RFD_STRUC* p =%lx\n", p);
// TRACE(" p->m_pIrp=%lx\n", p->m_pIrp);
}
// end of file
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -