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

📄 wdmvnicadap.cpp

📁 WIN2000下基于虚拟设备的小端口网络驱动程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// WdmVNICAdap.cpp: implementation of the WdmVNICAdapter class.
//
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060  USA
//
// Copyright (c) 2001 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================
//////////////////////////////////////////////////////////////////////

#include <kndis.h>
#include <kndisvdw.h>		  // DriverWorks
#include <KIrpPool.h>
#include "Characteristics.h" 
#include "WdmVNICAdap.h"


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

WdmVNICAdapter::WdmVNICAdapter() :
	KNdisMiniAdapter(),
		m_HaltFlag(FALSE),
		m_RxIdleEvent(),
		m_RxIrpsOutstanding(),
#if KNDIS_W9X_COMPATIBLE
		m_RxIndicateQueue((ULONG)&((PHW_RFD)0)->m_LE),
#endif // KNDIS_W9X_COMPATIBLE
		m_RxIrpList()
{
	// TODO: initialize your private data members
	//       Do NOT call any NDIS functions in here. Defer to Initialize()

}

WdmVNICAdapter::~WdmVNICAdapter()
{
	// TODO: deallocate all the resources allocated in constructor/Initialize()

}

////////////////////////////////////////////////////////////////////
// NDIS callback handlers
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::Initialize
//
// MiniportInitialize is a required function that sets up a NIC (or 
// virtual NIC) for network I/O operations, claims all hardware resources
// necessary to the NIC in the registry, and allocates resources the driver
// needs to carry out network I/O operations
//
// Parameters:
//		Medium	
//			Reference to KNdisMedium object that we have to set the medium 
//			type our NIC supports
//		Config
//			Reference to KNdisConfig object that we use to query various
//			configuration parameters
// IRQL: 
//		PASSIVE_LEVEL
// Return Mode:
//		Synchronous
//
// TODO: 
// 1) Select supported medium in Medium object
// 2) Read config parameters if any using Config object
// 3) Allocate h/w resources, pools, etc.
// 4) Register with NDIS using SetAttributes()
// 5) Register Shutdown Handler
// 6) Initialize and enable the NIC.
// NOTE: Be ready to process INTs even before the function exits
//
NDIS_STATUS WdmVNICAdapter::Initialize
				(IN OUT KNdisMedium& Medium, IN KNdisConfig& Config)
{
	TRACE("WdmVNICAdapter::Initialize() Entered\n");

	// Select our the Medium:

	if (! Medium.Select(WDMVNIC_MEDIUM_TYPE) )
		KNDIS_RETURN_ERROR (NDIS_STATUS_UNSUPPORTED_MEDIA);

	// Get network address (if any) from the Registry. If specified
	// it will be used instead of burned permanent address:

	if (Config.ReadNetworkAddress(m_CurrentAddress) != NDIS_STATUS_SUCCESS)
		m_CurrentAddress.Invalidate();

	// Read some other config stuff from the Registry, e.g.

	ULONG	uMode;
	Config.Read(KNDIS_STRING_CONST("Mode"), &uMode);

	// Retrieve some initialization parameters from the Registry. Use defaults if none.
	UINT TxIrpPoolSize = Config.Read(KNDIS_STRING_CONST("TxIrpPoolSize"), 8);
	TRACE("WdmVNICAdapter::Initialize() TxIrpPoolSize %d\n", TxIrpPoolSize);
	UINT RxIrpPoolSize = Config.Read(KNDIS_STRING_CONST("RxIrpPoolSize"), 1);
	TRACE("WdmVNICAdapter::Initialize() RxIrpPoolSize %d\n", RxIrpPoolSize);
	UINT BusTimerIntervalMSecs = Config.Read(KNDIS_STRING_CONST("BusTimerIntervalMSecs"), 5000);
	TRACE("WdmVNICAdapter::Initialize() BusTimerIntervalMSecs %d\n", BusTimerIntervalMSecs);
	UINT RxPacketLength = Config.Read(KNDIS_STRING_CONST("RxPacketLength"), 1000);
	TRACE("WdmVNICAdapter::Initialize() RxPacketLength %d\n", RxPacketLength);
	UINT RxRandomize = Config.Read(KNDIS_STRING_CONST("RxRandomize"), (UINT)0);
	TRACE("WdmVNICAdapter::Initialize() RxRandomize %d\n", RxRandomize);
	UINT MaxRxBurstCount = Config.Read(KNDIS_STRING_CONST("MaxRxBurstCount"), 20);
	TRACE("WdmVNICAdapter::Initialize() MaxRxBurstCount %d\n", MaxRxBurstCount);

    // Now let NDIS know about the BUS the NIC is on. Here's where the NDIS/Adapter-instance
	// handshake takes place. This should happen *before* allocating the h/w resources:
	SetAttributesEx(NdisInterfaceInternal,
		NDIS_ATTRIBUTE_DESERIALIZE);

	// Get the physical and "TopOfStack" device objects from NDIS for our WDM
	// device.  The "TopOfStack" device object is the device to which we will
	// submit IRPs to talk to the bus driver for our device.  We will use the PDO, along
	// with the "TopOfStack" device object to initialize our lower device object using
	// the DriverWorks class KPnpLowerDevice (or in this case KUsbLowerDevice, which is
	// derived from KPnpLowerDevice).
	GetDeviceProperty(&m_PhysicalDeviceObject, NULL, &m_TopOfStackDeviceObject);

	// Initialize the IRP pools used to service the bus device for Send and Receive
	m_TxIrpPool.Initialize(m_TopOfStackDeviceObject, TxIrpPoolSize);

	// Initialize the context block heap. We'll need one block per irp.  We only
	// need the heap for Tx context blocks, since the Rx context blocks will be
	// allocated in the HW_RFD structures used by the receive area initialized below.
	m_ContextHeap.Initialize(static_cast<USHORT>(TxIrpPoolSize));

#if KNDIS_W9X_COMPATIBLE
	// Initialize a timer that will be used for indicating Rx packets in a Win9x compatible
	// manner.
	m_Timer.Initialize(this, KNDIS_MEMBER_CALLBACK(IndicateCallback));
#endif // KNDIS_W9X_COMPATIBLE

	m_RxBufPool.Initialize(RxIrpPoolSize);

	// This sets up the Receive Frame Area including:
	// Allocating internal software Receive Frame Descriptors
	// Allocating packet and buffer pools
	// Initializing and chaining packets, software RFD, buffers
	// Maintains list of software RFD descriptors
	//
	// This driver's requirement is to further initialize the hardware RFD's
	// see global template specialization DescriptorInitialize(..) which
	// is called for each descriptor
	m_pRxArea = new KNdisSystemReceiveArea< WdmVNICAdapter, HW_RFD >(
		*this,
		RxIrpPoolSize
		);

	// Initialize the bus based lower device object.  Since NDIS owns this device object, we
	// use the form of Initialize() on our KPnpLowerDevice derived class that takes the
	// "TopOfStackDevice" as the device to which calls to the lower device should be directed
	// in lieu of actually attaching to the device stack.
	m_BusDevice.Initialize(m_TopOfStackDeviceObject, m_PhysicalDeviceObject);

	m_BusDevice.SetAdapter(this);

	// Some initialization calls to our bus simulation device.
	m_BusDevice.SetTimerInterval(BusTimerIntervalMSecs);
	m_BusDevice.SetRxPacketLength(RxPacketLength);
	m_BusDevice.SetRxRandomize((RxRandomize != 0));
	m_BusDevice.SetMaxRxBurstCount(MaxRxBurstCount);

	// TODO: Read perm address from the card instead
	m_PermanentAddress = m_CurrentAddress;

	// Set default filter and MAC options. In principle, we should also
	// relay that to our card...
	m_uPacketFilter = NDIS_PACKET_TYPE_DIRECTED |
					  NDIS_PACKET_TYPE_MULTICAST |
					  NDIS_PACKET_TYPE_BROADCAST;

	m_uMacOptions = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND  |
				    NDIS_MAC_OPTION_RECEIVE_SERIALIZED  |
					NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
					NDIS_MAC_OPTION_NO_LOOPBACK;

	// Get the Receive IRPs going
	StartReceiveUnit();

	return NDIS_STATUS_SUCCESS;
}

////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::Halt
//
// MiniportHalt is a required function that deallocates resources when
// the NIC is removed and halts the NIC.
//
// Parameters:
//		None
// IRQL: 
//		PASSIVE_LEVEL
// Return Mode:
//		Synchronous
//
// NOTE: Miniports has no "unload" for the driver. The Halt() is the last
//       function called into a miniport, so everything should be stopped 
//		 and freed right here. The KNDIS framework takes care of destroying
//		 the adapter object itself, so this member function is merery required
//       to undo things done by the Initialize() above - in the inversed order.
//
//		 Alternatevely, the driver writer can move all the deallocations to the
//       destructor: the destructor will be called immediatelly after Halt() 
//		 returns. Our sample follows this practice.
//
VOID WdmVNICAdapter::Halt(VOID)
{
	TRACE("WdmVNICAdapter::Halt() Entered\n");

	// Set the halt flag
	m_HaltFlag = TRUE;

	// Cancel all of the IRPs in the Rx Irp list.
	PHW_RFD pHwRfd = m_RxIrpList.Head();
	while (pHwRfd)
	{
		IoCancelIrp(pHwRfd->m_pIrp);
		pHwRfd = m_RxIrpList.Next(pHwRfd);
	}

	// Wait for all of the Rx IRPs to be completed
	LARGE_INTEGER DueTime;
	DueTime.QuadPart = -(10000 * 20000);	// 20 seconds
	if ( m_RxIdleEvent.Wait() == FALSE )
	{
		ASSERT(!"All Rx IRPs were not accounted for");
	}

	// Wait for all of the Tx IRPs to be completed
	if ( m_TxIrpPool.Wait(1000) == STATUS_TIMEOUT )	// 20 seconds
	{
		ASSERT(!"All Tx IRPs were not accounted for");
	}

	// Deallocate our receive area.  This will cleanup all of the HW_RFD descriptors
	// and call the DescriptorInvalidate method, which will deallocate the IRP associated with
	// the descriptor in the DescriptorInitialize method.
	TRACE("WdmVNICAdapter::Halt() Deleting Receive Area\n");
	delete m_pRxArea;
	m_pRxArea = NULL;
}

////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::Reset
//
// MiniportReset is a required function that issues a hardware reset
// to the NIC and/or resets the driver's software state.
//
// Parameters:
//		AddressingReset
//			Points to a variable that MiniportReset sets to TRUE if the
//			NDIS library should call MiniportSetInformation to restore
//			addressing information to the current values.
// IRQL: 
//		DISPATCH_LEVEL
// Return Mode:
//		Asynchronous
NDIS_STATUS WdmVNICAdapter::Reset
			(OUT PBOOLEAN AddressingReset)
{
	TRACE("WdmVNICAdapter::Reset() Entered\n");

	// TODO:	Reset the card

	return NDIS_STATUS_SUCCESS;
}
	
////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::Shutdown
//
// MiniportShutdown does nothing more than restore the NIC to its 
// initial state (before the miniport's DriverEntry function runs)
//
// Parameters:
//		None
// IRQL: 
//		If MiniportShutdown is called due to a user-initiated system shutdown,
//		it runs at IRQL PASSIVE_LEVEL in a system-thread context. If it is called
//		due to an unrecoverable error, MiniportShutdown runs at an arbitrary IRQL
//		and in the context of whatever component raised the error. 
// Return Mode:
//		Synchronous
VOID WdmVNICAdapter::Shutdown(VOID)
{
	TRACE("WdmVNICAdapter::Shutdown() Entered\n");

	// TODO:	Reset the card for good
}

////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::Send
//
// Transfers a protocol-supplied packet over the network
//
// Parameters:
//		Packet 
//			Points to a packet descriptor specifying the data to be transmitted. 
//		Flags 
//			Specifies the packet flags, if any, set by the protocol. 
// IRQL: 
//		DISPATCH_LEVEL
// Return Mode:
//		Asynchronous
// NOTE:
//		The return code determines the ownership of the packet and further
//		interaction between NDIS and our driver. Specifically,
//
//      NDIS_STATUS_SUCCESS - Done with.
//      NDIS_STATUS_PENDING - We keep it until further notice.
//      NDIS_STATUS_RESOURCES - We didn't have the resouces *now*, so, NDIS,
//                              please keep it until further notice.
//
// NOTE: Deserialized Miniports should never return NDIS_STATUS_RESOURCES to NDIS,
// and must instead queue it internally.
//
NDIS_STATUS WdmVNICAdapter::Send(
			IN	PNDIS_PACKET			Packet,
			IN	UINT					Flags
			)
{
	TRACE("WdmVNICAdapter::Send() Entered\n");

	if (TxPacket(Packet) == NDIS_STATUS_RESOURCES)
	{
		// We can never return NDIS_STATUS_RESOURCES to NDIS, and must
		// instead queue This packet for the Deserialized Miniport
		m_TxQueue.InsertTail(Packet);
		TRACE("!!!Queueing packet\n");
	}

	// Deserialized drivers always return pending.
	return NDIS_STATUS_PENDING;
}

///////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::TxPacket
//
// Parameters:
// 	PNDIS_PACKET		- Packet to be transmitted
// IRQL: 
//		IRQL DISPATCH_LEVEL
// Returns:
// 	NDIS_STATUS
NDIS_STATUS WdmVNICAdapter::TxPacket(
			IN	PNDIS_PACKET			Packet
			)
{
	NDIS_STATUS Status = NDIS_STATUS_PENDING;

	KIrp I = m_TxIrpPool.Allocate();

	if (I.IsNull())
	{
		Status = NDIS_STATUS_RESOURCES;
	}
	else
	{
		// allocate a new context structure
		IRP_CONTEXT* pContext = new (&m_ContextHeap) IRP_CONTEXT (this, Packet);

		// make sure it succeeded
		if ( pContext == NULL )
		{
			m_TxIrpPool.Free(I);
			Status = NDIS_STATUS_RESOURCES;
		}
		else
		{

			// TODO should transfer the packet information to the IRP.  This is highly dependent
			// on how the IRP should look to the lower device.

			I.SetCompletionRoutine(WdmCompletionTxRoutine(this), pContext);
			m_BusDevice.Call(I);
		}
	}
	
	return Status;
}

///////////////////////////////////////////////////////////////////////
// WdmVNICAdapter::CompletionTxRoutine
//
// 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 "send" IRP completions: this is a "HandleInterrupt()" 
//  thing for NDIS WDM drivers.So, the logic is similar to HandleInterrupt():
//  If a pended Tx packet gets completed, return the packet to NDIS. 
//  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.
NTSTATUS WdmVNICAdapter::CompletionTxRoutine(PIRP pIrp, WdmVNICAdapter::IRP_CONTEXT* pContext)
{
	TRACE("WdmVNICAdapter::TxPacketComplete() Entered\n");

	// Recycle the irp and the packet

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -