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

📄 pppoe.cpp

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

//********************************************************************
//	日期:	2004/08/14 - 14:8:2004   4:46
//	名前:	tiamo
//	描述:	pppoe
//*********************************************************************

#include "stdafx.h"

NDIS_STATUS SendPPPOEPacket(PADAPTER pAdapter,PBIND_CONTEXT pBind,PPPPOE_PACKET pPacket)
{
	NDIS_STATUS status;
	pPacket->m_pBindContext = pBind;

	NdisSend(&status,pBind->m_pOpenBlock,pPacket->m_pNdisPacket);

	if(status != NDIS_STATUS_PENDING)
	{
		protocolSendComplete(pBind,pPacket->m_pNdisPacket,status);
	}

	return status;
}

// broadcast packet
BOOLEAN BroadcastPacket(PPPPOE_PACKET pPacket)
{
	BOOLEAN bRet = FALSE;

	NdisAcquireSpinLock(&g_lockBind);

	PLIST_ENTRY pEntry = g_ltBinds.Flink;
	for(; pEntry != &g_ltBinds;pEntry = pEntry->Flink)
	{
		bRet = TRUE;
		PBIND_CONTEXT pBind = CONTAINING_RECORD(pEntry,BIND_CONTEXT,m_ltBinds);

		PPPPOE_PACKET pPacketClone = ClonePacket(pPacket);
		if(pPacketClone)
		{
			NdisMoveMemory(pPacketClone->m_pFrame->m_srcMac,pBind->m_macAddress,6);

			PPPPOE_WORK_ITEM pWorkItem = AllocateWorkItem(&g_lookasideWorkItem,BroadcastExecWorkItem,NULL,NULL);
			if(pWorkItem)
			{
				pWorkItem->m_param.BroadcastFormat.m_pBind = pBind;
				pWorkItem->m_param.BroadcastFormat.m_pPacket = pPacketClone;

				ReferenceBind(pBind,TRUE);

				ReferencePacket(pPacketClone);

				ScheduleWorkItem(pWorkItem);
			}
		}
	}

	NdisReleaseSpinLock(&g_lockBind);

	return bRet;
}

// broadcast exec
VOID BroadcastExecWorkItem(PPPPOE_WORK_ITEM pItem,PPPPOE_WORK_ITEM_PARAM pParam,PVOID pAdditionalParam)
{
	SendPPPOEPacket(g_pAdapter,pParam->BroadcastFormat.m_pBind,pParam->BroadcastFormat.m_pPacket);
}

// process packet
VOID ProcessRecvPacket(PBIND_CONTEXT pBind,PPPPOE_PACKET pPacket)
{
	NdisAcquireSpinLock(&g_pAdapter->m_lockSelf);
	if(ADAPTER_IN_WRONG_STATE(g_pAdapter))
	{
		NdisReleaseSpinLock(&g_pAdapter->m_lockSelf);
		return;
	}

	if(PROVIDER_IN_WRONG_STATE(g_pAdapter))
	{
		NdisReleaseSpinLock(&g_pAdapter->m_lockSelf);
		return;
	}

	ReferenceTspiProvider(g_pAdapter,FALSE);

	NdisReleaseSpinLock(&g_pAdapter->m_lockSelf);

	if(pPacket->m_pFrame->m_pppFrame.m_ucCode)
	{
		ProcessCtrlPacket(pBind,pPacket);
	}
	else
	{
		// head add ref already
		PCALL_INFO pCall = MapSeccesionIdToCall(g_pAdapter,pPacket);

		if(pCall)
		{
			NdisAcquireSpinLock(&pCall->m_lockSelf);

			if(!(pCall->m_ulFlags & (CALL_FREEING | CALL_CLOSING | CALL_DROPPING)))
			{
				// check count
				if(pCall->m_lPendingPacketsCount < 100)
				{
					// ref the packet
					ReferencePacket(pPacket);

					// insert to list
					InsertHeadList(&pCall->m_ltPendingPackets,&pPacket->m_ltPackets);

					pCall->m_lPendingPacketsCount ++;

					// schedule timer to indicate recved packet
					ScheduleIndicateRecvedPacketTimer(pCall);
				}
			}

			NdisReleaseSpinLock(&pCall->m_lockSelf);

			// deref it
			DereferenceCall(pCall);
		}
	}

	DereferenceTspiProvider(g_pAdapter);
}

// ctrl packet
VOID ProcessCtrlPacket(PBIND_CONTEXT pBind,PPPPOE_PACKET pPacket)
{
	switch(pPacket->m_pFrame->m_pppFrame.m_ucCode)
	{
		// PADO
	case PPPOE_CODE_PADO:
		// client recv PADO
		{
			PCALL_INFO pCall = MapWithoutSessionIdToCall(g_pAdapter,pPacket);
			if(pCall)
			{
				// run the fsm
				FsmRun(pCall,pBind,pPacket);

				// deref the call
				DereferenceCall(pCall);
			}
		}
		break;

		// PADI
	case PPPOE_CODE_PADI:
		// server only
		{
			// check all mac address
			if(RtlCompareMemory(pPacket->m_pFrame->m_srcMac,pBind->m_macAddress,6) == 6)
				break;

			// check line
			if(g_pAdapter->m_ulTotalLines > 0)
			{
				// check service name
				if(VerifyServiceName(g_pAdapter,pPacket,TRUE))
				{
					// create a PADO packet
					PPPPOE_PACKET pSendPacket = InitializePADOToSend(pPacket,pBind->m_macAddress,
																	 g_pAdapter->m_ucServiceName,
																	 g_pAdapter->m_usServiceNameLen,
																	 g_pAdapter->m_ucACName,g_pAdapter->m_usACNameLen,TRUE);

					if(pSendPacket)
					{
						ReferencePacket(pSendPacket);

						ReferenceBind(pBind,TRUE);

						// send it
						SendPPPOEPacket(g_pAdapter,pBind,pSendPacket);

						DereferencePacket(pSendPacket);
					}
				}
			}
		}
		break;

		// PADR
	case PPPOE_CODE_PADR:
		// server only
		{
			USHORT usError = 0;

			// check service name
			if(VerifyServiceName(g_pAdapter,pPacket,TRUE))
			{
				// check cookie
				if(VerifyACCookie(pPacket))
				{
					// check connect quota
					if(CheckClientQuota(g_pAdapter,pPacket))
					{
					}
					else
						usError = PPPOE_TAG_AC_SYSTEM_ERROR;
				}
				else
					usError = PPPOE_TAG_AC_COOKIE_ERROR;
			}
			else
				usError = PPPOE_TAG_SERVICE_NAME_ERROR;
			
			// send error PADS
			if(usError)
				SendPADSWithError(usError,pBind,pPacket);
			// receive call
			else
				TspiReceiveCall(g_pAdapter,pBind,pPacket);
		}
		break;

		// PADS
	case PPPOE_CODE_PADS:
		// client only
		{
			// get call info
			PCALL_INFO pCall = MapWithoutSessionIdToCall(g_pAdapter,pPacket);
			if(pCall)
			{
				NdisAcquireSpinLock(&g_pAdapter->m_lockSelf);

				// check dup session id
				BOOLEAN bFoundDup = FALSE;

				ULONG ulTableSize = g_pAdapter->m_ulNumLineDevs * g_pAdapter->m_ulEndPoints;

				USHORT usIndex = 0;
				for(;usIndex < ulTableSize;usIndex ++)
				{
					PCALL_INFO pExistCall = GetCallPtrFromHandleTableIndex(g_pAdapter->m_pCallHandleTable,usIndex);
					if( pExistCall && pExistCall->m_usSessionId == ntohs(pPacket->m_pFrame->m_pppFrame.m_usSession) &&
						RtlCompareMemory(pExistCall->m_macPeer,pPacket->m_pFrame->m_srcMac,6) == 6 &&
						RtlCompareMemory(pExistCall->m_macSelf,pPacket->m_pFrame->m_dstMac,6) == 6)
					{
						bFoundDup = TRUE;
						break;
					}
				}

				NdisReleaseSpinLock(&g_pAdapter->m_lockSelf);

				if(!bFoundDup)
					FsmRun(pCall,pBind,pPacket);

				DereferenceCall(pCall);
			}
		}
		break;

		// PADT
	case PPPOE_CODE_PADT:
		{
			drvDbgPrint("recved a PADT\n");
			PCALL_INFO pCall = MapSeccesionIdToCall(g_pAdapter,pPacket);
			if(pCall)
			{
				// drop the call
				NDIS_TAPI_DROP drop;
				drop.hdCall = pCall->m_hdCall;
				TspiDrop(g_pAdapter,&drop,LINEDISCONNECTMODE_NORMAL);

				DereferenceCall(pCall);
			}
		}
		break;
	}
}

// fsm make call
VOID ExecFsmMakeCall(PPPPOE_WORK_ITEM pItem,PPPPOE_WORK_ITEM_PARAM pParam,PVOID pAdditionalParam)
{
	FsmMakeCall(pParam->FsmMakeFormat.m_pCall);

	DereferenceCall(pParam->FsmMakeFormat.m_pCall);
}

// fsm make call
VOID FsmMakeCall(PCALL_INFO pCall)
{
	TspiCallStateChange(pCall,LINECALLSTATE_DIALING,0);

	NdisAcquireSpinLock(&pCall->m_lockSelf);

	if(pCall->m_ulFlags & (CALL_DROPPING | CALL_CLOSING))
	{
		NdisReleaseSpinLock(&pCall->m_lockSelf);
		return;
	}

	pCall->m_ulFsmState = FSM_CLIENT_SEND_PADI;

	NdisReleaseSpinLock(&pCall->m_lockSelf);

	FsmRun(pCall,NULL,NULL);
}

// fsm receive call
VOID FsmReceiveCall(PCALL_INFO pCall,PBIND_CONTEXT pBind,PPPPOE_PACKET pPacket)
{
	NdisAcquireSpinLock(&pCall->m_lockSelf);

	if(pCall->m_ulFlags & (CALL_DROPPING | CALL_CLOSING))
	{
		NdisReleaseSpinLock(&pCall->m_lockSelf);
		return;
	}

	pCall->m_ulFsmState = FSM_SERVER_SEND_PADS;

	NdisReleaseSpinLock(&pCall->m_lockSelf);

	FsmRun(pCall,pBind,pPacket);
}

// answer call
NDIS_STATUS FsmAnswerCall(PCALL_INFO pCall)
{
	NdisAcquireSpinLock(&pCall->m_lockSelf);

	if((pCall->m_ulFlags & (CALL_DROPPING | CALL_CLOSING)) || pCall->m_ulFsmState != FSM_SERVER_WAIT_FOR_ANSWER)
	{
		NdisReleaseSpinLock(&pCall->m_lockSelf);
		return NDIS_STATUS_FAILURE;
	}

	pCall->m_ulFsmState = FSM_SERVER_ANSWER_OK;

	NdisReleaseSpinLock(&pCall->m_lockSelf);

	return FsmRun(pCall,NULL,NULL);
}

// fsm
NDIS_STATUS FsmRun(PCALL_INFO pCall,PBIND_CONTEXT pBind,PPPPOE_PACKET pPacket)
{
	NdisAcquireSpinLock(&pCall->m_lockSelf);

	if(pCall->m_ulFlags & (CALL_DROPPING | CALL_CLOSING))
	{
		NdisReleaseSpinLock(&pCall->m_lockSelf);
		return NDIS_STATUS_FAILURE;
	}

	NDIS_STATUS status = NDIS_STATUS_FAILURE;

	switch(pCall->m_ulFsmState)
	{
	case FSM_IDLE:
		break;

		// send PADI
	case FSM_CLIENT_SEND_PADI:
		ClientSendPADI(pCall,pBind,pPacket);
		break;

		// wait for PADO
	case FSM_CLIENT_WAIT_FOR_PADO:
		ClientWaitForPADO(pCall,pBind,pPacket);
		break;

		// send PADR
	case FSM_CLIENT_SEND_PADR:
		break;

		// wait for PADS
	case FSM_CLIENT_WAIT_FOR_PADS:
		ClientWaitForPADS(pCall,pBind,pPacket);
		break;

		// server receve new call
	case FSM_SERVER_SEND_PADS:
		ServerReceiveNewCall(pCall,pBind,pPacket);
		break;

	case FSM_SERVER_WAIT_FOR_ANSWER:
		break;

	case FSM_SERVER_ANSWER_OK:
		status = ServerAnswerCall(pCall,pBind,pPacket);
		break;
	}

	return status;
}

// client send PADI
VOID ClientSendPADI(PCALL_INFO pCall,PBIND_CONTEXT pBind,PPPPOE_PACKET pRecvedPacket)
{
	BOOLEAN bNeedDropCall = FALSE;
	BOOLEAN bNeedReleaseLock = TRUE;

	ULONG ulReportCallStateParam = 0;

	PPPPOE_PACKET pSendPacket = NULL;

	__try
	{
		if(pRecvedPacket)
			__leave;

		LARGE_INTEGER llHostUnique;
		USHORT usLen;

		CreateUniqueValue(pCall->m_hdCall,&llHostUnique,&usLen);

		bNeedDropCall = TRUE;
		ulReportCallStateParam = LINEDISCONNECTMODE_UNKNOWN;

		pSendPacket = InitializePADIToSend(pCall->m_ucServiceName,pCall->m_usServiceNameLen,
										   reinterpret_cast<PUCHAR>(&llHostUnique),usLen);

		ReferencePacket(pSendPacket);

		pCall->m_pLastSendDiscoveryPacket = pSendPacket;

		NdisInitializeListHead(&pCall->m_timerPPPOEItem.m_ltItem);

		pCall->m_usRetryCount = 0;
		ScheduleTimerItem(&g_timer,&pCall->m_timerPPPOEItem,g_pAdapter->m_ulSendTimeOut,FsmSendPADITimeOut,pCall);

		ReferenceCall(pCall,FALSE);

		pCall->m_ulFsmState = FSM_CLIENT_WAIT_FOR_PADO;

		NdisReleaseSpinLock(&pCall->m_lockSelf);

		bNeedReleaseLock = FALSE;

		ulReportCallStateParam = LINEDISCONNECTMODE_UNREACHABLE;
		bNeedDropCall = !BroadcastPacket(pSendPacket);
		
		DereferencePacket(pSendPacket);

		drvDbgPrint("client sending PADI...\n");
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
	}

	if(bNeedReleaseLock)
		NdisReleaseSpinLock(&pCall->m_lockSelf);

	if(bNeedDropCall)
	{
		NDIS_TAPI_DROP drop;
		drop.hdCall = pCall->m_hdCall;
		TspiDrop(g_pAdapter,&drop,ulReportCallStateParam);
	}
}

// client wait for PADO
VOID ClientWaitForPADO(PCALL_INFO pCall,PBIND_CONTEXT pBind,PPPPOE_PACKET pRecvedPacket)
{
	BOOLEAN bNeedDropCall = FALSE;
	ULONG ulReportCallStateParam = 0;

	BOOLEAN bNeedReleaseLock = TRUE;

	PPPPOE_PACKET 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)
		{
			drvDbgPrint("client recved PADO packet error ignore this packet...\n");
			__leave;
		}

		PPPPOE_PACKET pLastSendPacket = pCall->m_pLastSendDiscoveryPacket;

		// check host unique
		if( pLastSendPacket->m_usHostUnique != pRecvedPacket->m_usHostUnique || 
			RtlCompareMemory(pLastSendPacket->m_pHostUnique,pRecvedPacket->m_pHostUnique,pRecvedPacket->m_usHostUnique) != pRecvedPacket->m_usHostUnique)
		{
			drvDbgPrint("client recved PADO's host unique does not match ignore it...\n");
			__leave;
		}

		// check ac name
		if( pCall->m_bMustCheckACName && 
			(pCall->m_usACNameLen != pRecvedPacket->m_usACName || 
			RtlCompareMemory(pRecvedPacket->m_pACName,pCall->m_ucACName,pCall->m_usACNameLen) != pCall->m_usACNameLen))
		{
			drvDbgPrint("client recved PADO's ac name does not match ignore it...\n");
			__leave;
		}

		pCall->m_usACNameLen = pRecvedPacket->m_usACName;

		if(pCall->m_usACNameLen > sizeof(pCall->m_ucACName))
			pCall->m_usACNameLen = sizeof(pCall->m_ucACName);

		NdisMoveMemory(pCall->m_ucACName,pRecvedPacket->m_pACName,pCall->m_usACNameLen);

		// 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
		pCall->m_usServiceNameLen = usServiceNameLastSend;
		if(pCall->m_usServiceNameLen > sizeof(pCall->m_ucServiceName))
			pCall->m_usServiceNameLen = sizeof(pCall->m_ucServiceName);

		NdisMoveMemory(pCall->m_ucServiceName,pServiceNameLastSend,pCall->m_usServiceNameLen);

		// copy mac address
		NdisMoveMemory(pCall->m_macPeer,pRecvedPacket->m_pFrame->m_srcMac,6);

		pCall->m_pLastSendDiscoveryPacket = NULL;

⌨️ 快捷键说明

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