www.pudn.com > IPsec_Src_Instal.rar > Miniport.c


/*++ 
 
  Copyright (c) 1992-2000  Microsoft Corporation 
   
--*/ 
#include "precomp.h" 
#include "PktHdr.h" 
#include "hmac.h" 
 
/* 
Miniport Initialize is Called as a result of the intermediate driver  
calling NdisIMInitializeDeviceInstance (in PPBindAdapter) to  
initialize  its miniport Operations  
*/ 
NDIS_STATUS MPInitialize(OUT PNDIS_STATUS OpenErrorStatus,  
						 OUT PUINT SelectedMediumIndex,  
						 IN PNDIS_MEDIUM MediumArray,  
						 IN UINT MediumArraySize,  
						 IN NDIS_HANDLE MiniportAdapterHandle,  
						 IN NDIS_HANDLE WrapperConfigurationContext) 
{ 
	UINT i; 
 
	PADAPT pAdapt; 
 
	NDIS_STATUS Status = NDIS_STATUS_FAILURE; 
 
	NDIS_MEDIUM Medium; 
 
	do 
	{ 
		// 
		//  Access the device context area allocate by PPBindAdapter 
		// 
		pAdapt = NdisIMGetDeviceContext(MiniportAdapterHandle); 
 
		// 
		//  MiniportAdapterHandle specifies a handle identifying the  
		//  miniport's NIC, which is assigned by the NDIS library.  
		//  Save this handle. 
		// 
		pAdapt->MiniportHandle = MiniportAdapterHandle; 
 
		// 
		//  Usually we export the medium type of the adapter below as  
		//  our virtual miniport's medium type. However if the adapter  
		//  below us is a WAN device, then we claim to be of medium  
		//  type 802.3. 
		// 
		Medium = pAdapt->Medium; 
 
		if (Medium == NdisMediumWan) 
		{ 
			Medium = NdisMedium802_3; 
		} 
		// 
		//  Making Sure that Selected Medium is the supported Medium 
		// 
		for (i = 0; i < MediumArraySize; i++) 
		{ 
			if (MediumArray[i] == Medium) 
			{ 
				*SelectedMediumIndex = i; 
 
				break; 
			} 
		} 
 
		if (i == MediumArraySize) 
		{ 
			Status = NDIS_STATUS_UNSUPPORTED_MEDIA; 
 
			break; 
		} 
 
		// 
		//  Informs the NDIS library about Virtual NIC 
		// 
		NdisMSetAttributesEx(MiniportAdapterHandle, 
			pAdapt, 
			0, 
			NDIS_ATTRIBUTE_DESERIALIZE | 
			NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER | 
			NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND | 
			NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT | 
			NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT, 
			0); 
 
		// 
		//  Initialize LastIndicatedStatus = NDIS_STATUS_MEDIA_CONNECT 
		// 
		pAdapt->LastIndicatedStatus = NDIS_STATUS_MEDIA_CONNECT; 
 
		// 
		//  Initializing Power Management State 
		//  NdisDeviceStateD0 - Full Powered State 
		// 
		pAdapt->MiniportDeviceState = NdisDeviceStateD0;   
		pAdapt->ProtocolDeviceState = NdisDeviceStateD0; 
 
		// 
		//  Add this adapter to the global pAdapt List 
		// 
		NdisAcquireSpinLock(&GlobalLock); 
 
		pAdapt->Next = pAdaptList; 
		pAdaptList = pAdapt; 
 
		NdisReleaseSpinLock(&GlobalLock); 
 
		Status = NDIS_STATUS_SUCCESS; 
	} 
	while (FALSE); 
 
	pAdapt->MiniportInitPending = FALSE; 
 
	NdisSetEvent(&pAdapt->MiniportInitEvent); 
 
	*OpenErrorStatus = Status; 
 
	return Status; 
} 
 
/* 
	 MPSendPackets transfers some number of packets specified as  
	 Array of packet Pointers , over the Network 
	 */ 
VOID MPSendPackets(IN NDIS_HANDLE MiniportAdapterContext,  
				   IN PPNDIS_PACKET PacketArray,  
				   IN UINT NumberOfPackets) 
{ 
	PADAPT pAdapt = (PADAPT) MiniportAdapterContext; 
	NDIS_STATUS Status;  
	UINT i; 
	PVOID MediaSpecificInfo = NULL; 
	UINT MediaSpecificInfoSize = 0; 
 
	DbgPrint("Send"); 
 
	for (i = 0; i < NumberOfPackets; i++) 
	{ 
		PNDIS_PACKET Packet; 
		PNDIS_PACKET MyPacket; 
 
 
		BOOLEAN bDecision; 
 
 
		PNDIS_BUFFER pNewNdisBfr; 
 
		ULONG OrigPayloadl; 
		ULONG NewPayloadl; 
 
		PUCHAR pNewPayload = NULL; 
 
#define 	  szPayloadCopy   ETH_MAX_PACKET_SIZE 
 
		char PayloadCopy[szPayloadCopy]; 
 
		// 
		//  Copying a Single packet from the packet Array 
		// 
		Packet = PacketArray[i]; 
 
		// 读取封包中的所有字符串 
		GetPktPayload(Packet, PayloadCopy, szPayloadCopy, &OrigPayloadl); 
 
		//---------------------------------------- 
 
		NdisAcquireSpinLock(&pAdapt->Lock); 
 
		// 
		// See if packet to be dropped. 
		// 判断封包是否要被丢弃 
		// 
		Status = FilterPacket(pAdapt, Packet, NULL, TRUE, &bDecision); 
 
		if (NDIS_STATUS_SUCCESS == Status && TRUE != bDecision) 
		{ 
			NdisReleaseSpinLock(&pAdapt->Lock); 
 
			goto Done; 
		} 
 
		NdisReleaseSpinLock(&pAdapt->Lock); 
		//------------------------------------------ 
		{ 
			pEthHdr pETH; 
			pIPHdr pIPH; 
 
			pAHHdr pAH; 
 
			UCHAR digest[16]; 
 
			NDIS_STATUS lclStatus; 
 
			USHORT IPHdrl, TCPHdrl, NewHdrsl; 
 
			int i; 
 
			// 获取IP指针 
			pIPH = (pIPHdr) (PayloadCopy + sizeof(EthHdr)); 
 
			// 获取IP包头长度 
			IPHdrl = pIPH->IPHdrLen * 4; 
 
			// OrigPayloadl为以太网帧的长度 
			// 相加后则为新的以太网帧的长度 
			NewPayloadl = OrigPayloadl + sizeof(AHHdr);  
 
			// 计算新IP包的总长(包括IP头) 
			pIPH->TotalLength = (USHORT) 
				RtlUlongByteSwap((NewPayloadl - sizeof(EthHdr)) << 
											16); 
			pIPH->Checksum = 0; 
 
			// 计算新IP包的校验和 
			pIPH->Checksum = GetIPChecksum((PUSHORT) pIPH, IPHdrl); 
 
			// 初始化新帧的内存空间 
			lclStatus = NdisAllocateMemoryWithTag(&pNewPayload, 
							NewPayloadl, 
							TAG); 
 
			if (NDIS_STATUS_SUCCESS != lclStatus) 
			{ 
				Status = lclStatus; 
 
				goto Done; 
			} 
 
			// 拷贝帧头及IP头到新的帧中 
			NdisMoveMemory(pNewPayload, PayloadCopy, sizeof(EthHdr) + IPHdrl); 
 
			// 获取AH头指针 
			pAH = (pAHHdr) (pNewPayload + sizeof(EthHdr) + IPHdrl); 
 
			// 初始化AH结构 
			pAH->NextHeader = 0; 
			pAH->PayloadLength = 5; 
			pAH->Reserved = 0; 
			pAH->SNF = 0; 
			pAH->SPI = 0; 
 
			for (i = 0; i < 16; i++) 
				pAH->Auth[i] = 0; 
 
			// 将原帧中IP头后的数据部份拷到新帧的AH头后面 
			NdisMoveMemory(pNewPayload + sizeof(EthHdr) + IPHdrl + sizeof(AHHdr), 
				PayloadCopy + sizeof(EthHdr) + IPHdrl, 
				OrigPayloadl - sizeof(EthHdr) - IPHdrl); 
			{ 
				PUCHAR pHmacPayload = NULL; 
 
				pIPHdr pHmacIPH; 
 
				UCHAR digest[16]; 
 
				UCHAR key[] = "Prakash"; 
 
				NdisZeroMemory(digest, 16); 
 
				Status = NdisAllocateMemoryWithTag(&pHmacPayload, 
							NewPayloadl - sizeof(EthHdr), 
							TAG); 
				if (NDIS_STATUS_SUCCESS != Status) 
				{ 
					goto Done; 
				} 
 
				// 将新帧的IP包拷到pHmacPayload中 
				NdisMoveMemory(pHmacPayload, 
					pNewPayload + sizeof(EthHdr), 
					NewPayloadl - sizeof(EthHdr)); 
 
				// 获取新IP包的头指针 
				pHmacIPH = (pIPHdr) pHmacPayload; 
 
				pHmacIPH->TTL = 0; 
				pHmacIPH->FragmentationSummary = 0; 
				pHmacIPH->Checksum = 0; 
 
				// 将新的IP包加密后保存在digest中 
				// 被加密的IP包结构如下: 
				// IP头 | AH头 | IP数据 
				hmac_md5(pHmacPayload, 
					NewPayloadl - sizeof(EthHdr), 
					key, 
					7, 
					digest); 
 
				NdisMoveMemory(pAH->Auth, digest, 16); 
				DbgPrint("Digest Send:"); 
 
				for (i = 0; i < 16 ; i++) 
				{ 
					DbgPrint("%x", digest[i]); 
				} 
			} 
		} 
 
		Done: 
		// 
		//  The driver should fail the send if the virtual miniport is in low  
		//  power state 
		// 
		if (pAdapt->MiniportDeviceState > NdisDeviceStateD0) 
		{ 
			NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt), 
				Packet, 
				NDIS_STATUS_FAILURE); 
 
			if (NULL != pNewPayload) 
			{ 
				// 
				//  Recycle memory. 
				// 
				NdisFreeMemory(pNewPayload, NewPayloadl, 0); 
 
				pNewPayload = NULL; 
			} 
 
			continue; 
		} 
 
		do 
		{ 
			NdisAcquireSpinLock(&pAdapt->Lock); 
 
			// 
			//  If the below miniport is going to low power state,  
			//  stop sending down any packet. 
			// 
			if (pAdapt->ProtocolDeviceState > NdisDeviceStateD0) 
			{ 
				NdisReleaseSpinLock(&pAdapt->Lock); 
 
				if (NULL != pNewPayload) 
				{ 
					NdisFreeMemory(pNewPayload, NewPayloadl, 0); 
 
					pNewPayload = NULL; 
				} 
 
				Status = NDIS_STATUS_FAILURE; 
 
				break; 
			} 
 
			pAdapt->OutstandingSends++; 
 
			NdisReleaseSpinLock(&pAdapt->Lock); 
 
			NdisAllocatePacket(&Status, 
				&MyPacket, 
				pAdapt->SendPacketPoolHandle); 
 
 
			if (Status == NDIS_STATUS_SUCCESS) 
			{ 
				PSEND_RSVD SendRsvd; 
 
				// 
				//  NIC drivers and intermediate drivers allocate 
				//  packet descriptors with, at least, 16 bytes of  
				//  ProtocolReserved space to be used by protocols  
				//  for receive indications.  
				// 
				SendRsvd = (PSEND_RSVD) (MyPacket->ProtocolReserved); 
 
				SendRsvd->OriginalPkt = Packet; 
 
				// 
				//  Found desired packet 
				// 
				if (NULL != pNewPayload) 
				{ 
					// 
					//  Build new buffer descriptor. 
					// 
					NdisAllocateBuffer(&Status, 
						&pNewNdisBfr, 
						pAdapt->hSendBufferPool, 
						pNewPayload, 
						NewPayloadl); 
 
					if (NDIS_STATUS_SUCCESS != Status) 
					{ 
						break; 
					} 
 
					// 
					//  Show new NDIS_BUFFER used. 
					// 
					SendRsvd->bNewBuffer = TRUE;	  
 
					// 
					//  Links a given buffer descriptor to the head of  
					//  the buffer-descriptor chain attached to a packet  
					//  descriptor. 
					// 
					NdisChainBufferAtFront(MyPacket, pNewNdisBfr); 
				} 
				else 
				{ 
					SendRsvd->bNewBuffer = FALSE;      // Original used. 
 
					MyPacket->Private.Head = Packet->Private.Head; 
					MyPacket->Private.Tail = Packet->Private.Tail; 
				} 
 
				MyPacket->Private.Flags = NdisGetPacketFlags(Packet); 
 
				// 
				//  Copy OOB Data to the New Packet 
				// 
				NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket), 
					NDIS_OOB_DATA_FROM_PACKET(Packet), 
					sizeof(NDIS_PACKET_OOB_DATA)); 
				// 
				//  Copy Media Specific Information 
				// 
				NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet, 
					&MediaSpecificInfo, 
					&MediaSpecificInfoSize); 
 
				if (MediaSpecificInfo || MediaSpecificInfoSize) 
				{ 
					NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket, 
						MediaSpecificInfo, 
						MediaSpecificInfoSize); 
				} 
 
				// 
				//  Send the packets to Miniport 
				// 
				NdisSend(&Status, pAdapt->BindingHandle, MyPacket); 
 
				if (Status != NDIS_STATUS_PENDING) 
				{ 
					if (NULL != pNewPayload) 
					{ 
						NdisFreeBuffer(pNewNdisBfr); 
 
						NdisFreeMemory(pNewPayload, NewPayloadl, 0); 
 
						pNewPayload = NULL; 
					} 
 
					NdisFreePacket(MyPacket); 
 
					ADAPT_DECR_PENDING_SENDS(pAdapt); 
				} 
			} 
			else 
			{ 
				// 
				//  The driver cannot allocate a packet. 
				//  
				ADAPT_DECR_PENDING_SENDS(pAdapt); 
 
				if (NULL != pNewPayload) 
				{ 
					NdisFreeMemory(pNewPayload, NewPayloadl, 0); 
 
					pNewPayload = NULL; 
				} 
			} 
		} 
		while (FALSE); 
 
 
		if (Status != NDIS_STATUS_PENDING) 
		{ 
			NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status); 
		} 
	} 
} 
 
 
 
 
/* 
Returns Information about capabilities and status of the driver 
*/ 
NDIS_STATUS MPQueryInformation(IN NDIS_HANDLE MiniportAdapterContext,  
							   IN NDIS_OID Oid,  
							   IN PVOID InformationBuffer,  
							   IN ULONG InformationBufferLength,  
							   OUT PULONG BytesWritten,  
							   OUT PULONG BytesNeeded) 
{ 
	PADAPT pAdapt = (PADAPT) MiniportAdapterContext; 
 
	NDIS_STATUS Status = NDIS_STATUS_FAILURE; 
 
	do 
	{ 
		// 
		//  An Intermediate Driver ,always return success for this OID 
		// 
		if (Oid == OID_PNP_QUERY_POWER) 
		{ 
			Status = NDIS_STATUS_SUCCESS; 
 
			break; 
		} 
 
		// 
		// If the miniport below is unbinding, just fail any request 
		// 
		if (Oid == OID_TCP_TASK_OFFLOAD) 
		{ 
			// 
			// Fail this -if- this driver performs data transformations 
			// that can interfere with a lower driver's ability to offload 
			// TCP tasks. 
			// 
			Status = NDIS_STATUS_NOT_SUPPORTED; 
 
			break; 
		} 
 
		// 
		//  OID_GEN_SUPPORTED_GUIDS - do not forward, otherwise we will show up 
		//  multiple instances of private GUIDs supported by the underlying miniport. 
		// 
		if (Oid == OID_GEN_SUPPORTED_GUIDS) 
		{ 
			Status = NDIS_STATUS_SUCCESS; 
 
			break; 
		} 
 
		NdisAcquireSpinLock(&pAdapt->Lock); 
 
		if (pAdapt->UnbindingInProcess == TRUE) 
		{ 
			NdisReleaseSpinLock(&pAdapt->Lock); 
 
			Status = NDIS_STATUS_FAILURE; 
 
			break; 
		} 
 
		NdisReleaseSpinLock(&pAdapt->Lock); 
 
		if (pAdapt->MiniportDeviceState > NdisDeviceStateD0) 
		{ 
			Status = NDIS_STATUS_FAILURE; 
 
			break; 
		} 
 
		// 
		//  Setting up request 
		// 
		pAdapt->Request.RequestType = NdisRequestQueryInformation; 
 
		pAdapt->Request.DATA.QUERY_INFORMATION.Oid = Oid; 
 
		pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; 
 
		pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength; 
 
		pAdapt->BytesReadOrWritten = BytesWritten; 
 
		pAdapt->BytesNeeded = BytesNeeded; 
 
		// 
		//  If the miniport below is binding, fail the request 
		// 
		NdisAcquireSpinLock(&pAdapt->Lock); 
 
		if (pAdapt->UnbindingInProcess == TRUE) 
		{ 
			NdisReleaseSpinLock(&pAdapt->Lock); 
 
			Status = NDIS_STATUS_FAILURE; 
 
			break; 
		} 
 
		// 
		//  If the Protocol device state is OFF, mark this request  
		//  as being pended. We queue this until the device state is  
		//  back to D0.  
		// 
		if (pAdapt->ProtocolDeviceState > NdisDeviceStateD0 && 
			pAdapt->StandingBy == FALSE) 
		{ 
			pAdapt->QueuedRequest = TRUE; 
 
			NdisReleaseSpinLock(&pAdapt->Lock); 
 
			Status = NDIS_STATUS_PENDING; 
 
			break; 
		} 
 
		// 
		//  This is in the process of powering down the system,  
		//  always fail the request 
		//  
		if (pAdapt->StandingBy == TRUE) 
		{ 
			NdisReleaseSpinLock(&pAdapt->Lock); 
 
			Status = NDIS_STATUS_FAILURE; 
 
			break; 
		} 
 
		pAdapt->OutstandingRequests = TRUE; 
 
		NdisReleaseSpinLock(&pAdapt->Lock); 
 
		// 
		//  Forwarding Request to Underlying Miniport 
		// 
		NdisRequest(&Status, pAdapt->BindingHandle, &pAdapt->Request); 
 
		if (Status != NDIS_STATUS_PENDING) 
		{ 
			PPRequestComplete(pAdapt, &pAdapt->Request, Status); 
 
			Status = NDIS_STATUS_PENDING; 
		} 
	} 
	while (FALSE); 
 
	return(Status); 
} 
 
 
/* 
Postprocess a request for OID_PNP_CAPABILITIES that was forwarded 
down to the underlying miniport, and has been completed by it. 
*/ 
VOID MPQueryPNPCapabilities(IN OUT PADAPT   	pAdapt,  
							OUT PNDIS_STATUS	   pStatus) 
{ 
	PNDIS_PNP_CAPABILITIES pPNPCapabilities; 
 
	PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct; 
 
 
 
	if (pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength >= 
		sizeof(NDIS_PNP_CAPABILITIES)) 
	{ 
		pPNPCapabilities = (PNDIS_PNP_CAPABILITIES) 
			(pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer); 
 
		// 
		//  The following fields must be overwritten by an IM driver. 
		// 
		pPMstruct = &pPNPCapabilities->WakeUpCapabilities; 
		pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified; 
		pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified; 
		pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified; 
 
		*pAdapt->BytesReadOrWritten = sizeof(NDIS_PNP_CAPABILITIES); 
		*pAdapt->BytesNeeded = 0; 
 
 
		// 
		//  Setting our internal flags 
		//  Default, device is ON 
		// 
		pAdapt->MiniportDeviceState = NdisDeviceStateD0; 
		pAdapt->ProtocolDeviceState = NdisDeviceStateD0; 
 
		*pStatus = NDIS_STATUS_SUCCESS; 
	} 
	else 
	{ 
		*pAdapt->BytesNeeded = sizeof(NDIS_PNP_CAPABILITIES); 
 
		*pStatus = NDIS_STATUS_RESOURCES; 
	} 
} 
 
 
 
/* 
Called by bound protocols/NDIS to request change of state 
 
*/  				 
NDIS_STATUS MPSetInformation(IN NDIS_HANDLE MiniportAdapterContext,  
							 IN NDIS_OID Oid,  
							 IN PVOID InformationBuffer,  
							 IN ULONG InformationBufferLength,  
							 OUT PULONG BytesRead,  
							 OUT PULONG BytesNeeded) 
{ 
	PADAPT pAdapt = (PADAPT) MiniportAdapterContext; 
 
	NDIS_STATUS Status = NDIS_STATUS_FAILURE; 
 
	do 
	{ 
		//Should not be propagated 
		if (Oid == OID_PNP_SET_POWER) 
		{ 
			MPProcessSetPowerOid(&Status, 
				pAdapt, 
				InformationBuffer, 
				InformationBufferLength, 
				BytesRead, 
				BytesNeeded); 
			break; 
		} 
		// 
		// If the miniport below is unbinding, fail the request 
		// 
		NdisAcquireSpinLock(&pAdapt->Lock);    
		if (pAdapt->UnbindingInProcess == TRUE) 
		{ 
			NdisReleaseSpinLock(&pAdapt->Lock); 
			Status = NDIS_STATUS_FAILURE; 
			break; 
		} 
		NdisReleaseSpinLock(&pAdapt->Lock); 
 
		// 
		//All Set Information Should fail - if Power is not on 
		// 
		if (pAdapt->MiniportDeviceState > NdisDeviceStateD0) 
		{ 
			Status = NDIS_STATUS_FAILURE; 
			break; 
		} 
 
		// 
		//Setting up request 
		// 
 
		pAdapt->Request.RequestType = NdisRequestSetInformation; 
		pAdapt->Request.DATA.QUERY_INFORMATION.Oid = Oid; 
		pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; 
		pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength; 
 
		pAdapt->BytesReadOrWritten = BytesRead; 
		pAdapt->BytesNeeded = BytesNeeded; 
 
		// 
		// If the miniport below is unbinding, fail the request 
		// 
		NdisAcquireSpinLock(&pAdapt->Lock);    
		if (pAdapt->UnbindingInProcess == TRUE) 
		{ 
			NdisReleaseSpinLock(&pAdapt->Lock); 
			Status = NDIS_STATUS_FAILURE; 
			break; 
		} 
 
		// 
		// If the device below is at a low power state, we cannot send it the 
		// request now, and must pend it. 
		// 
		if ((pAdapt->ProtocolDeviceState > NdisDeviceStateD0) && 
			(pAdapt->StandingBy == FALSE)) 
		{ 
			pAdapt->QueuedRequest = TRUE; 
			NdisReleaseSpinLock(&pAdapt->Lock); 
			Status = NDIS_STATUS_PENDING; 
			break; 
		} 
		// 
		// This is in the process of powering down the system, always fail the request 
		//  
		if (pAdapt->StandingBy == TRUE) 
		{ 
			NdisReleaseSpinLock(&pAdapt->Lock); 
			Status = NDIS_STATUS_FAILURE; 
			break; 
		} 
		pAdapt->OutstandingRequests = TRUE; 
 
		NdisReleaseSpinLock(&pAdapt->Lock); 
		// 
		// Forward the request to the device below. 
		// 
		NdisRequest(&Status, pAdapt->BindingHandle, &pAdapt->Request); 
 
		if (Status != NDIS_STATUS_PENDING) 
		{ 
			*BytesRead = pAdapt->Request.DATA.SET_INFORMATION.BytesRead; 
			*BytesNeeded = pAdapt->Request.DATA.SET_INFORMATION.BytesNeeded; 
			pAdapt->OutstandingRequests = FALSE; 
		} 
	} 
	while (FALSE); 
 
	return(Status); 
} 
 
VOID MPProcessSetPowerOid(IN OUT PNDIS_STATUS   pNdisStatus,  
						  IN	PADAPT  	 pAdapt,  
						  IN   PVOID		InformationBuffer,  
						  IN	ULONG   	 InformationBufferLength,  
						  OUT   PULONG  	 BytesRead,  
						  OUT   PULONG  	 BytesNeeded) 
{ 
	NDIS_DEVICE_POWER_STATE NewDeviceState; 
 
	*pNdisStatus = NDIS_STATUS_FAILURE; 
 
	do 
	{ 
		// 
		//  Check for invalid length 
		// 
		if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE)) 
		{ 
			*pNdisStatus = NDIS_STATUS_INVALID_LENGTH; 
 
			break; 
		} 
 
		NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE) InformationBuffer); 
 
		// 
		//  Check for invalid device state 
		// 
		if ((pAdapt->MiniportDeviceState > NdisDeviceStateD0) && 
			(NewDeviceState != NdisDeviceStateD0)) 
		{ 
			// 
			//  If the miniport is in a non-D0 state, the miniport can  
			//  only receive a Set Power to D0 
			// 
			*pNdisStatus = NDIS_STATUS_FAILURE; 
 
			break; 
		}     
 
		// 
		//  Is the miniport transitioning from an On (D0) state to an  
		//  Low Power State (>D0).If so, then set the StandingBy Flag - 
		//  (Block all incoming requests) 
		// 
		if (pAdapt->MiniportDeviceState == NdisDeviceStateD0 && 
			NewDeviceState > NdisDeviceStateD0) 
		{ 
			pAdapt->StandingBy = TRUE; 
		} 
 
		// 
		//  If the miniport is transitioning from a low power state  
		//  to ON (D0), then clear the StandingBy flag 
		//  All incoming requests will be pended until the physical  
		//  miniport turns ON. 
		// 
		if (pAdapt->MiniportDeviceState > NdisDeviceStateD0 && 
			NewDeviceState == NdisDeviceStateD0) 
		{ 
			pAdapt->StandingBy = FALSE; 
		} 
 
		// 
		//  Now update the state in the pAdapt structure; 
		// 
		pAdapt->MiniportDeviceState = NewDeviceState; 
 
		*pNdisStatus = NDIS_STATUS_SUCCESS; 
	} 
	while (FALSE);     
 
	if (*pNdisStatus == NDIS_STATUS_SUCCESS) 
	{ 
		// 
		//  The miniport resume from low power state 
		//  
		if (pAdapt->StandingBy == FALSE) 
		{ 
			// 
			//  If we need to indicate the media connect state 
			//  
			if (pAdapt->LastIndicatedStatus != pAdapt->LatestUnIndicateStatus) 
			{ 
				NdisMIndicateStatus(pAdapt->MiniportHandle, 
					pAdapt->LatestUnIndicateStatus, 
					(PVOID) NULL, 
					0); 
 
				NdisMIndicateStatusComplete(pAdapt->MiniportHandle); 
 
				pAdapt->LastIndicatedStatus = pAdapt->LatestUnIndicateStatus; 
			} 
		} 
		else 
		{ 
			// 
			//  Initialize LatestUnIndicatedStatus 
			// 
			pAdapt->LatestUnIndicateStatus = pAdapt->LastIndicatedStatus; 
		} 
 
		*BytesRead = sizeof(NDIS_DEVICE_POWER_STATE); 
 
		*BytesNeeded = 0; 
	} 
	else 
	{ 
		*BytesRead = 0; 
 
		*BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE); 
	} 
} 
 
 
 
 
/* 
Called whenever protocols are done with a packet that we had indicated up  
and they had queued up for returning later. 
 
  */				   
VOID MPReturnPacket(IN NDIS_HANDLE MiniportAdapterContext,  
					IN PNDIS_PACKET Packet) 
{ 
	PADAPT pAdapt = (PADAPT) MiniportAdapterContext; 
 
	PNDIS_PACKET MyPacket; 
 
	PRECV_RSVD RecvRsvd; 
 
	// 
	//  This is a packet allocated from this IM's receive packet pool. 
	//  Reclaim our packet, and return the original to the driver below. 
	// 
	RecvRsvd = (PRECV_RSVD) (Packet->MiniportReserved); 
 
	MyPacket = RecvRsvd->OriginalPkt; 
 
 
	if (TRUE == RecvRsvd->bNewBuffer) 
	{ 
		PNDIS_BUFFER pNewNdisBfr;   	   
		PUCHAR VA; 
		UINT lVA; 
 
		NdisQueryPacket(Packet, NULL, NULL, &pNewNdisBfr, NULL); 
 
		NdisQueryBufferSafe(pNewNdisBfr, &VA,      // Payload address. 
 & lVA, 	 // Payload length. 
			  LowPagePriority); 
 
		NdisFreeBuffer(pNewNdisBfr); 
 
		NdisFreeMemory(VA, lVA, 0); 
	} 
 
	NdisFreePacket(Packet); 
 
	NdisReturnPackets(&MyPacket, 1); 
} 
 
 
/* 
MPTransferData is a required function if the NIC drivers  
that do not indicate multipacket receives and/or media-specific  
information with NdisMIndicateReceivePacket  
*/ 
 
NDIS_STATUS MPTransferData(OUT PNDIS_PACKET Packet,  
						   OUT PUINT	 BytesTransferred,  
						   IN  NDIS_HANDLE   MiniportAdapterContext,  
						   IN  NDIS_HANDLE   MiniportReceiveContext,  
						   IN  UINT 	 ByteOffset,  
						   IN  UINT 	 BytesToTransfer) 
{ 
	PADAPT pAdapt = (PADAPT) MiniportAdapterContext; 
 
	NDIS_STATUS Status; 
 
	// 
	// Return, if the device is OFF 
	// 
	if (IsIMDeviceStateOn(pAdapt) == FALSE) 
	{ 
		return NDIS_STATUS_FAILURE; 
	} 
 
	// 
	//  Forwards a request to copy data received on the underlying NIC  
	//  into a protocol-supplied packet.  
	// 
	NdisTransferData(&Status, 
		pAdapt->BindingHandle, 
		MiniportReceiveContext, 
		ByteOffset, 
		BytesToTransfer, 
		Packet, 
		BytesTransferred); 
 
	return(Status); 
} 
 
 
VOID MPHalt(IN NDIS_HANDLE MiniportAdapterContext) 
{ 
	PADAPT pAdapt = (PADAPT) MiniportAdapterContext; 
	NDIS_STATUS Status; 
	PADAPT* ppCursor; 
 
	// 
	//  Remove this adapter from the global list 
	// 
	NdisAcquireSpinLock(&GlobalLock); 
 
	for (ppCursor = &pAdaptList; 
		*ppCursor != NULL; 
		ppCursor = &(*ppCursor)->Next) 
	{ 
		if (*ppCursor == pAdapt) 
		{ 
			*ppCursor = pAdapt->Next; 
 
			break; 
		} 
	} 
 
	NdisReleaseSpinLock(&GlobalLock); 
 
	if (pAdapt->BindingHandle != NULL) 
	{ 
		// 
		// Close the binding below. and wait for it to complete 
		// 
		NdisResetEvent(&pAdapt->Event); 
 
		NdisCloseAdapter(&Status, pAdapt->BindingHandle); 
 
		if (Status == NDIS_STATUS_PENDING) 
		{ 
			NdisWaitEvent(&pAdapt->Event, 0); 
 
			Status = pAdapt->Status; 
		} 
 
		pAdapt->BindingHandle = NULL; 
	} 
 
	// 
	//  Free all resources on this adapter structure. 
	// 
	MPFreeAllPacketPools(pAdapt); 
 
	NdisFreeMemory(pAdapt, 0, 0); 
} 
 
 
/* 
Free all packet pools on the specified adapter. 
*/ 
 
VOID MPFreeAllPacketPools(IN PADAPT  pAdapt) 
{ 
	if (pAdapt->RecvPacketPoolHandle != NULL) 
	{ 
		NdisFreePacketPool(pAdapt->RecvPacketPoolHandle); 
 
		pAdapt->RecvPacketPoolHandle = NULL; 
	} 
 
	if (pAdapt->SendPacketPoolHandle != NULL) 
	{ 
		NdisFreePacketPool(pAdapt->SendPacketPoolHandle); 
 
		pAdapt->SendPacketPoolHandle = NULL; 
	} 
}