www.pudn.com > PPPOE.rar > pppoefsm.cpp


 
//******************************************************************** 
//	ÈÕÆÚ:	2004/08/25 - 25:8:2004   16:46 
//	Ãûǰ:	tiamo 
//	ÃèÊö:	pppoe fsm 
//********************************************************************* 
 
#include "stdafx.h" 
 
// create unique value 
VOID CreateUniqueValue(PCHANNEL pChannel,PLARGE_INTEGER pUnique,PUSHORT pusLen) 
{ 
	ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG); 
 
	static LONG _s_lUnique = 1; 
	*pusLen = sizeof(LARGE_INTEGER); 
	pUnique->LowPart = pChannel->m_ulLineId; 
	pUnique->HighPart = NdisInterlockedIncrement(&_s_lUnique); 
} 
 
// fsm run 
VOID FsmRun(PCHANNEL pChannel,PBIND_CONTEXT pBind,PPACKET pRecvedPacket) 
{ 
	ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG); 
 
	NdisAcquireSpinLock(&pChannel->m_lockSelf); 
 
	// must be set activating 
	if(pChannel->m_ulState != CHANNEL_ACTIVATING) 
	{ 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
		return; 
	} 
 
	switch(pChannel->m_ulFsmState) 
	{ 
	case FSM_IDLE: 
	case FSM_SERVER_SEND_PADS: 
	case FSM_SERVER_WAIT_FOR_ANSWER: 
	case FSM_SERVER_ANSWER_OK: 
	case FSM_CLIENT_SEND_PADR: 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
		break; 
 
		// send PADI 
	case FSM_CLIENT_SEND_PADI: 
		ClientSendPADI(pChannel,pBind,pRecvedPacket); 
		break; 
 
		// wait for PADO 
	case FSM_CLIENT_WAIT_FOR_PADO: 
		ClientWaitForPADO(pChannel,pBind,pRecvedPacket); 
		break; 
 
		// wait for PADS 
	case FSM_CLIENT_WAIT_FOR_PADS: 
		ClientWaitForPADS(pChannel,pBind,pRecvedPacket); 
		break; 
	} 
} 
 
// indicater recved packets 
VOID IndicateRecvedPackets(PTIMER_ITEM pItem,PVOID pContext,PVOID pCancelContext) 
{ 
	PCHANNEL pChannel = static_cast(pContext); 
 
	ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG); 
 
	ASSERT(DISPATCH_LEVEL == KeGetCurrentIrql()); 
 
	NdisDprAcquireSpinLock(&pChannel->m_lockSelf); 
 
	LONG lCount = 100; 
	for(; pChannel->m_lPendingRecvedPackets > 0 && lCount > 0; ++lCount) 
	{ 
		PLIST_ENTRY pEntry = RemoveHeadList(&pChannel->m_ltRecvedPacketsHead); 
 
		PPACKET pPacket = CONTAINING_RECORD(pEntry,PACKET,m_ltPacketAnchor); 
 
		pChannel->m_lPendingRecvedPackets --; 
 
		// unchain the header buffer 
		NdisUnchainBufferAtFront(pPacket->m_pNdisPacket,&pPacket->m_pNdisHeaderBuffer); 
 
		pPacket->m_ulFlags &= ~PPPOE_PACKET_HEADER_BUFFER_CHAINED; 
 
		// set pointer 
		PMINIPORT_RESERVED pResv = reinterpret_cast(pPacket->m_pNdisPacket->MiniportReservedEx); 
 
		pResv->m_pPacket = pPacket; 
		pResv->m_pChannel = pChannel; 
 
		pChannel->m_lPendingReturnPackets ++; 
 
		// call our return packet 
		NDIS_SET_PACKET_STATUS(pPacket->m_pNdisPacket,NDIS_STATUS_SUCCESS); 
 
		NdisMCoIndicateReceivePacket(pChannel->m_hNdisVcHandle,&pPacket->m_pNdisPacket,1); 
	} 
 
	NdisMCoReceiveComplete(g_pAdapter->m_hNdisAdapter); 
 
	// next call 
	if(pChannel->m_lPendingRecvedPackets > 0 && pChannel->m_ulFsmState == FSM_SESSION) 
	{ 
		InitializeTimerItem(&pChannel->m_timerItemSession); 
 
		ScheduleTimerItem(&pChannel->m_timerItemSession,IndicateRecvedPackets,1,pChannel); 
	} 
	else 
		pChannel->m_bRecvedTimerScheduled = FALSE; 
 
	NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
} 
 
// schedule timer 
VOID ScheduleIndicateRecvedPacketTimer(PCHANNEL pChannel) 
{ 
	ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG); 
 
	ASSERT(DISPATCH_LEVEL == KeGetCurrentIrql()); 
 
	if( pChannel->m_ulState != CHANNEL_ACTIVATED ||  
		pChannel->m_ulFsmState != FSM_SESSION ||  
		pChannel->m_lPendingRecvedPackets < 1 ||  
		pChannel->m_bRecvedTimerScheduled) 
		return; 
 
	pChannel->m_bRecvedTimerScheduled = TRUE; 
 
	InitializeTimerItem(&pChannel->m_timerItemSession); 
 
	ScheduleTimerItem(&pChannel->m_timerItemSession,IndicateRecvedPackets,1,pChannel); 
} 
 
// process recved packet  
VOID ProcessRecvedPacket(PBIND_CONTEXT pBind,PPACKET pPacket) 
{ 
	ASSERT(DISPATCH_LEVEL == KeGetCurrentIrql()); 
 
	// if is ctrl packet,then process it 
	if(pPacket->m_pFrame->m_pppFrame.m_ucCode) 
	{ 
		ProcessCtrlPacket(pBind,pPacket); 
	} 
	else 
	{ 
		// else found associate vc  
		PCHANNEL pChannel = MapSessionId2Channel(pPacket); 
 
		// insert the packet to vc's list 
		if(pChannel) 
		{ 
			ReferencePacket(pPacket); 
 
			InsertTailList(&pChannel->m_ltRecvedPacketsHead,&pPacket->m_ltPacketAnchor); 
 
			pChannel->m_lPendingRecvedPackets ++; 
 
			// then schedule the timer to indicate it up 
			ScheduleIndicateRecvedPacketTimer(pChannel); 
 
			NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
		}		 
	} 
} 
 
// process control packet 
VOID ProcessCtrlPacket(PBIND_CONTEXT pBind,PPACKET pPacket) 
{ 
	// according to the pppoe code we do some check then run the fsm 
	switch(pPacket->m_pFrame->m_pppFrame.m_ucCode) 
	{ 
		// PADO 
	case PPPOE_CODE_PADO: 
		// client recv PADO 
		{ 
			// get connect from host unique 
			PCHANNEL pChannel = MapWithoutSessionId2Channel(pPacket); 
			if(!pChannel) 
				break; 
 
			NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
 
			// run the fsm 
			FsmRun(pChannel,pBind,pPacket); 
		} 
		break; 
 
		// PADI 
	case PPPOE_CODE_PADI: 
		break; 
 
		// PADR 
	case PPPOE_CODE_PADR: 
		break; 
 
		// PADS 
	case PPPOE_CODE_PADS: 
		// client only 
		{ 
			// get channel from host unique 
			PCHANNEL pChannel = MapWithoutSessionId2Channel(pPacket); 
			if(!pChannel) 
				break; 
 
			NdisDprAcquireSpinLock(&g_pAdapter->m_lockSelf); 
 
			// check dup session id 
			BOOLEAN bFoundDup = FALSE; 
 
			ULONG ulTableSize = g_pAdapter->m_ulNumChannels; 
 
			USHORT usIndex = 0; 
			for(;usIndex < ulTableSize;usIndex ++) 
			{ 
				PCHANNEL pChannel = g_pAdapter->m_ppChannels[usIndex]; 
				if( pChannel->m_usSessionId == ntohs(pPacket->m_pFrame->m_pppFrame.m_usSession) && 
					RtlCompareMemory(pChannel->m_macPeer,pPacket->m_pFrame->m_srcMac,ETH_ADDR_LEN) == ETH_ADDR_LEN && 
					RtlCompareMemory(pChannel->m_macSelf,pPacket->m_pFrame->m_dstMac,ETH_ADDR_LEN) == ETH_ADDR_LEN) 
				{ 
					bFoundDup = TRUE; 
					break; 
				} 
			} 
 
			NdisDprReleaseSpinLock(&g_pAdapter->m_lockSelf); 
 
			NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
 
			if(!bFoundDup) 
				FsmRun(pChannel,pBind,pPacket); 
		} 
		break; 
 
		// PADT 
	case PPPOE_CODE_PADT: 
		{ 
			DebugInfo(("recved a PADT\n")); 
 
			PCHANNEL pChannel = MapSessionId2Channel(pPacket); 
			if(!pChannel) 
				break; 
 
			NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
 
			// close call 
			NdisMCmDispatchIncomingCloseCall(NDIS_STATUS_SUCCESS,pChannel->m_hNdisVcHandle,NULL,0); 
		} 
		break; 
	} 
} 
 
// client send PADI,build a PADI,and broadcast it,also set a timer to check time out  
VOID ClientSendPADI(PCHANNEL pChannel,PBIND_CONTEXT pBind,PPACKET pRecvedPacket) 
{ 
	BOOLEAN bNeedDropCall = FALSE; 
	BOOLEAN bNeedReleaseLock = TRUE; 
 
	PPACKET pSendPacket = NULL; 
 
	__try 
	{ 
		if(pRecvedPacket) 
			__leave; 
 
		LARGE_INTEGER llHostUnique; 
		USHORT usLen; 
 
		CreateUniqueValue(pChannel,&llHostUnique,&usLen); 
 
		bNeedDropCall = TRUE; 
 
		pSendPacket = InitializePADIToSend(pChannel->m_ucService,pChannel->m_usServiceLen, 
										   reinterpret_cast(&llHostUnique),usLen); 
 
		ReferencePacket(pSendPacket); 
 
		pChannel->m_pLastPacket = pSendPacket; 
 
		InitializeTimerItem(&pChannel->m_timerItemDiscovery); 
 
		pChannel->m_usRetryCounts = 0; 
 
		ScheduleTimerItem(&pChannel->m_timerItemDiscovery,FsmSendPADITimeOut,g_pAdapter->m_ulSendTimeOut,pChannel); 
 
		pChannel->m_ulFsmState = FSM_CLIENT_WAIT_FOR_PADO; 
 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
 
		bNeedReleaseLock = FALSE; 
 
		bNeedDropCall = !BroadcastPacket(pSendPacket); 
 
		DereferencePacket(pSendPacket); 
 
		DebugInfo(("client sending PADI...\n")); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
	} 
 
	if(bNeedReleaseLock) 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
 
	if(bNeedDropCall) 
	{ 
		NdisMCmMakeCallComplete(NDIS_STATUS_FAILURE,pChannel->m_hNdisVcHandle,NULL,NULL,pChannel->m_pOutParam); 
	} 
} 
 
// client wait for PADO,check the recved packet,and send a PADR,also set timeout timer 
VOID ClientWaitForPADO(PCHANNEL pChannel,PBIND_CONTEXT pBind,PPACKET pRecvedPacket) 
{ 
	BOOLEAN bNeedDropCall = FALSE; 
 
	BOOLEAN bNeedReleaseLock = TRUE; 
 
	PPACKET pSendPacket = NULL; 
 
	__try 
	{ 
		// check pointer 
		if( !pRecvedPacket ||  
			pRecvedPacket->m_pFrame->m_pppFrame.m_ucCode != PPPOE_CODE_PADO || 
			pRecvedPacket->m_ulFlags & PPPOE_PACKET_ERROR_TAG_RECV) 
		{ 
			DebugInfo(("client recved error packet(not a PADO or PADO with error tag) ignore this packet...\n")); 
			__leave; 
		} 
 
		PPACKET pLastSendPacket = pChannel->m_pLastPacket; 
 
		// check host unique 
		if( pLastSendPacket->m_usHostUnique != pRecvedPacket->m_usHostUnique ||  
			RtlCompareMemory(pLastSendPacket->m_pHostUnique,pRecvedPacket->m_pHostUnique,pRecvedPacket->m_usHostUnique) != pRecvedPacket->m_usHostUnique) 
		{ 
			DebugInfo(("client recved PADO's host unique does not match ignore it...\n")); 
			__leave; 
		} 
 
		// check ac name 
		if( pChannel->m_usACLen &&  
			(pChannel->m_usACLen != pRecvedPacket->m_usACName ||  
			RtlCompareMemory(pRecvedPacket->m_pACName,pChannel->m_ucAC,pChannel->m_usACLen) != pChannel->m_usACLen)) 
		{ 
			DebugInfo(("client recved PADO's ac name does not match ignore it...\n")); 
			__leave; 
		} 
 
		pChannel->m_usACLen = pRecvedPacket->m_usACName; 
 
		if(pChannel->m_usACLen > sizeof(pChannel->m_ucAC)) 
			pChannel->m_usACLen = sizeof(pChannel->m_ucAC); 
 
		NdisMoveMemory(pChannel->m_ucAC,pRecvedPacket->m_pACName,pChannel->m_usACLen); 
 
		// get service name 
		BOOLEAN bFoundService = FALSE; 
		PUCHAR pServiceNameLastSend; 
		USHORT usServiceNameLastSend; 
 
		// only one service 
		RetrieveTag(PPPOE_TAG_SERVICE,pLastSendPacket,&pServiceNameLastSend,&usServiceNameLastSend,FALSE); 
 
		// should not be null 
		if(!pServiceNameLastSend) 
			__leave; 
 
		PUCHAR pCurrentOffset = pRecvedPacket->m_pucDataBuffer; 
		USHORT usTotalLen = ntohs(pRecvedPacket->m_pFrame->m_pppFrame.m_usLen); 
 
		PUCHAR pServiceNameRecved = NULL; 
		USHORT usServiceNameRecved = 0; 
 
		// check service match 
		for(;;) 
		{ 
			RetrieveServiceName(pRecvedPacket,&pServiceNameRecved,&usServiceNameRecved,pCurrentOffset,usTotalLen); 
 
			if(!pServiceNameRecved) 
				break; 
 
			if( !usServiceNameLastSend ||  
				(usServiceNameLastSend == usServiceNameRecved &&  
				RtlCompareMemory(pServiceNameRecved,pServiceNameLastSend,usServiceNameRecved) == usServiceNameRecved)) 
			{ 
				bFoundService = TRUE; 
				break; 
			} 
 
			pCurrentOffset += usServiceNameRecved + sizeof(PPP_TAG); 
			usTotalLen -= (usServiceNameRecved + sizeof(PPP_TAG)); 
		} 
 
		if(!bFoundService) 
			__leave; 
 
		// copy service name 
		pChannel->m_usServiceLen = usServiceNameLastSend; 
		if(pChannel->m_usServiceLen > sizeof(pChannel->m_ucService)) 
			pChannel->m_usServiceLen = sizeof(pChannel->m_ucService); 
 
		NdisMoveMemory(pChannel->m_ucService,pServiceNameLastSend,pChannel->m_usServiceLen); 
 
		// copy mac address 
		NdisMoveMemory(pChannel->m_macPeer,pRecvedPacket->m_pFrame->m_srcMac,6); 
 
		pChannel->m_pLastPacket = NULL; 
 
		// set fsm state 
		pChannel->m_ulFsmState = FSM_CLIENT_SEND_PADR; 
 
		// deref original packet 
		DereferencePacket(pLastSendPacket); 
 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
 
		bNeedReleaseLock = FALSE; 
 
		// cancel timer 
		CancelTimerItem(&pChannel->m_timerItemDiscovery,(PVOID)1); 
 
		// add call to bind list 
		AddChannel2Bind(pChannel,pBind); 
 
		NdisAcquireSpinLock(&pChannel->m_lockSelf); 
 
		bNeedReleaseLock = TRUE; 
 
		// check fsm state 
		if(pChannel->m_ulFsmState != FSM_CLIENT_SEND_PADR) 
			__leave; 
 
		LARGE_INTEGER llHostUnique; 
		USHORT usLen; 
 
		// create unique host value 
		CreateUniqueValue(pChannel,&llHostUnique,&usLen); 
 
		// create packet 
		pSendPacket = InitializePADRToSend(pRecvedPacket,pChannel->m_ucService,pChannel->m_usServiceLen, 
										   reinterpret_cast(&llHostUnique),usLen); 
 
		ReferencePacket(pSendPacket); 
 
		// save the pointer 
		pChannel->m_pLastPacket = pSendPacket; 
 
		ReferenceBind(pBind,TRUE); 
 
		InitializeTimerItem(&pChannel->m_timerItemDiscovery); 
 
		// schedule timer 
		pChannel->m_usRetryCounts = 0; 
 
		ScheduleTimerItem(&pChannel->m_timerItemDiscovery,FsmSendPADRTimeOut,g_pAdapter->m_ulSendTimeOut,pChannel); 
 
		pChannel->m_ulFsmState = FSM_CLIENT_WAIT_FOR_PADS; 
 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
 
		bNeedReleaseLock = FALSE; 
 
		// send it 
		NDIS_STATUS status = SendPacket(pBind,pSendPacket); 
 
		if(status != NDIS_STATUS_SUCCESS && status != NDIS_STATUS_PENDING) 
		{ 
			bNeedDropCall = TRUE; 
		} 
 
		DebugInfo(("got an enough satisfied PADO so send a PADR...\n")); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
	} 
 
	if(bNeedReleaseLock) 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
 
	if(bNeedDropCall) 
	{ 
		NdisMCmMakeCallComplete(NDIS_STATUS_FAILURE,pChannel->m_hNdisVcHandle,NULL,NULL,pChannel->m_pOutParam); 
	} 
} 
 
// client wait for PADS,check recved packet,get session id,complete the make call request 
VOID ClientWaitForPADS(PCHANNEL pChannel,PBIND_CONTEXT pBind,PPACKET pRecvedPacket) 
{ 
	BOOLEAN bNeedDropCall = FALSE; 
 
	BOOLEAN bNeedReleaseLock = TRUE; 
 
	PPACKET pSendPacket = NULL; 
	__try 
	{ 
		// check pointer 
		if( !pRecvedPacket ||  
			pRecvedPacket->m_pFrame->m_pppFrame.m_ucCode != PPPOE_CODE_PADS || 
			pRecvedPacket->m_ulFlags & PPPOE_PACKET_ERROR_TAG_RECV) 
		{ 
			DebugInfo(("recv packet is not a PADS or a PADS with error tag,ignore this packet...\n")); 
			__leave; 
		} 
 
		// last send packet 
		PPACKET pLastSendPacket = pChannel->m_pLastPacket; 
		if(!pLastSendPacket) 
		{ 
			bNeedDropCall = TRUE; 
			__leave; 
		} 
 
		// check host unique 
		if( pLastSendPacket->m_usHostUnique != pRecvedPacket->m_usHostUnique ||  
			RtlCompareMemory(pLastSendPacket->m_pHostUnique,pRecvedPacket->m_pHostUnique,pRecvedPacket->m_usHostUnique) != pRecvedPacket->m_usHostUnique) 
		{ 
			DebugInfo(("recved PADS's host unique not match ignore it...\n")); 
			__leave; 
		} 
 
		// get service name 
		PUCHAR pServiceNameRecved; 
		USHORT usServiceNameRecved; 
 
		RetrieveTag(PPPOE_TAG_SERVICE,pRecvedPacket,&pServiceNameRecved,&usServiceNameRecved,FALSE); 
 
		if(!pServiceNameRecved) 
			__leave; 
 
		PUCHAR pServiceNameLastSend; 
		USHORT usServiceNameLastSend; 
 
		// check service match 
		RetrieveTag(PPPOE_TAG_SERVICE,pLastSendPacket,&pServiceNameLastSend,&usServiceNameLastSend,FALSE); 
 
		if(!pServiceNameLastSend) 
			__leave; 
 
		if( usServiceNameLastSend!= usServiceNameRecved ||  
			RtlCompareMemory(pServiceNameRecved,pServiceNameLastSend,usServiceNameRecved) != usServiceNameRecved) 
		{ 
			__leave; 
		} 
 
		// save session id 
		pChannel->m_usSessionId = ntohs(pRecvedPacket->m_pFrame->m_pppFrame.m_usSession); 
 
		pChannel->m_pLastPacket = NULL; 
 
		pChannel->m_ulFsmState = FSM_SESSION; 
 
		DereferencePacket(pLastSendPacket); 
 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
 
		bNeedReleaseLock = FALSE; 
 
		// cancel timer 
		CancelTimerItem(&pChannel->m_timerItemDiscovery,(PVOID)1); 
 
		NDIS_STATUS status = NdisMCmActivateVc(pChannel->m_hNdisVcHandle,pChannel->m_pOutParam); 
 
		if(status != NDIS_STATUS_PENDING) 
			mcmActivateVcComplete(status,pChannel,pChannel->m_pOutParam); 
 
		NdisMCmMakeCallComplete(NDIS_STATUS_SUCCESS,pChannel->m_hNdisVcHandle,NULL,NULL,pChannel->m_pOutParam); 
 
		DebugInfo(("the PADS is ok,so go to session stage...\n")); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
	} 
 
	if(bNeedReleaseLock) 
		NdisReleaseSpinLock(&pChannel->m_lockSelf); 
 
	if(bNeedDropCall) 
	{ 
		NdisMCmMakeCallComplete(NDIS_STATUS_FAILURE,pChannel->m_hNdisVcHandle,NULL,NULL,pChannel->m_pOutParam); 
	} 
} 
 
// send PADI time out 
VOID FsmSendPADITimeOut(PTIMER_ITEM pItem,PVOID pContext,PVOID pCancelContext) 
{ 
	PCHANNEL pChannel = static_cast(pContext); 
 
	NdisDprAcquireSpinLock(&pChannel->m_lockSelf); 
 
	BOOLEAN bDropCall = FALSE; 
 
	BOOLEAN bNeedReleaseLock = TRUE; 
 
	if(pCancelContext) 
	{ 
		pChannel->m_usRetryCounts = 0; 
	} 
	else 
	{ 
		DebugInfo(("client sending PADI timeout %d...\n",pChannel->m_usRetryCounts + 1)); 
		__try 
		{ 
			if(pChannel->m_ulFsmState != FSM_CLIENT_WAIT_FOR_PADO) 
				__leave; 
 
			if(pChannel->m_usRetryCounts >= g_pAdapter->m_ulMaxRetryTimes) 
			{ 
				bDropCall = TRUE; 
				__leave; 
			} 
 
			if(!pChannel->m_pLastPacket) 
				__leave; 
 
			ReferencePacket(pChannel->m_pLastPacket); 
 
			InitializeTimerItem(&pChannel->m_timerItemDiscovery); 
 
			ScheduleTimerItem(&pChannel->m_timerItemDiscovery,FsmSendPADITimeOut,g_pAdapter->m_ulSendTimeOut,pChannel); 
 
			++pChannel->m_usRetryCounts; 
 
			NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
 
			bNeedReleaseLock = FALSE; 
 
			bDropCall = !BroadcastPacket(pChannel->m_pLastPacket); 
 
			DereferencePacket(pChannel->m_pLastPacket); 
		} 
		__except(EXCEPTION_EXECUTE_HANDLER) 
		{ 
		} 
	} 
 
	if(bNeedReleaseLock) 
		NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
 
	if(bDropCall) 
	{ 
		NdisMCmMakeCallComplete(NDIS_STATUS_FAILURE,pChannel->m_hNdisVcHandle,NULL,NULL,pChannel->m_pOutParam); 
	} 
} 
 
// send PADR time out DISPATCH_LEVEL 
VOID FsmSendPADRTimeOut(PTIMER_ITEM pItem,PVOID pContext,PVOID pCancelContext) 
{ 
	PCHANNEL pChannel = static_cast(pContext); 
 
	NdisDprAcquireSpinLock(&pChannel->m_lockSelf); 
 
	BOOLEAN bDropCall = FALSE; 
 
	BOOLEAN bNeedReleaseLock = TRUE; 
 
	if(pCancelContext) 
	{ 
		pChannel->m_usRetryCounts = 0; 
	} 
	else 
	{ 
		DebugInfo(("client sending PADR timeout %d...\n",pChannel->m_usRetryCounts + 1)); 
		__try 
		{ 
			if(pChannel->m_ulFsmState != FSM_CLIENT_WAIT_FOR_PADS) 
				__leave; 
 
			if(pChannel->m_usRetryCounts >= g_pAdapter->m_ulMaxRetryTimes) 
			{ 
				bDropCall = TRUE; 
				__leave; 
			} 
 
			if(!pChannel->m_pBindContext) 
			{ 
				bDropCall = TRUE; 
				__leave; 
			} 
 
			if(!pChannel->m_pLastPacket) 
				__leave; 
 
			ReferenceBind(pChannel->m_pBindContext,TRUE); 
 
			ReferencePacket(pChannel->m_pLastPacket); 
 
			InitializeTimerItem(&pChannel->m_timerItemDiscovery); 
 
			ScheduleTimerItem(&pChannel->m_timerItemDiscovery,FsmSendPADRTimeOut,g_pAdapter->m_ulSendTimeOut,pChannel); 
 
			++pChannel->m_usRetryCounts; 
 
			NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
 
			bNeedReleaseLock = FALSE; 
 
			NDIS_STATUS status = SendPacket(pChannel->m_pBindContext,pChannel->m_pLastPacket); 
 
			if(status != NDIS_STATUS_SUCCESS && status != NDIS_STATUS_PENDING) 
			{ 
				bDropCall = TRUE; 
				__leave; 
			} 
		} 
		__except(EXCEPTION_EXECUTE_HANDLER) 
		{ 
		} 
	} 
 
	if(bNeedReleaseLock) 
		NdisDprReleaseSpinLock(&pChannel->m_lockSelf); 
 
	if(bDropCall) 
	{ 
		NdisMCmMakeCallComplete(NDIS_STATUS_FAILURE,pChannel->m_hNdisVcHandle,NULL,NULL,pChannel->m_pOutParam); 
	} 
}