⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wdmvnicadap.cpp

📁 WIN2000下基于虚拟设备的小端口网络驱动程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:

	// 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 + -