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

📄 pppoefsm.cpp

📁 pppoe client
💻 CPP
📖 第 1 页 / 共 2 页
字号:

//********************************************************************
//	日期:	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<PCHANNEL>(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<PMINIPORT_RESERVED>(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<PUCHAR>(&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;

⌨️ 快捷键说明

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