call.cpp

来自「pppoe client」· C++ 代码 · 共 489 行

CPP
489
字号

//********************************************************************
//	日期:	2004/08/14 - 14:8:2004   5:03
//	名前:	tiamo
//	描述:	call
//*********************************************************************

#include "stdafx.h"

// dereference call
VOID ReferenceCall(PCALL_INFO pCall,BOOLEAN bAcquireSpinLock)
{
	if(bAcquireSpinLock)
		NdisAcquireSpinLock(&pCall->m_lockSelf);

	pCall->m_lRefCount ++;

	if(bAcquireSpinLock)
		NdisReleaseSpinLock(&pCall->m_lockSelf);
}

// dereference call
VOID DereferenceCall(PCALL_INFO pCall)
{
	NdisAcquireSpinLock(&pCall->m_lockSelf);

	LONG lCount = -- pCall->m_lRefCount;
	if(!lCount)
	{
		pCall->m_ulFlags &= ~(CALL_INITIALIZED | CALL_CLOSING);
		pCall->m_ulFlags |= CALL_FREEING;
	}

	NdisReleaseSpinLock(&pCall->m_lockSelf);

	// call close complete
	if(!lCount)
	{
		TspiCloseCallComplete(pCall);
	}
}

// close call complete
VOID TspiCloseCallComplete(PCALL_INFO pCall)
{
	if(pCall->m_ulFsmState == FSM_SESSION)
	{
		NDIS_MAC_LINE_DOWN lineDown;
		lineDown.NdisLinkContext = pCall->m_hLinkContext;

		NdisMIndicateStatus(g_pAdapter->m_hMiniportAdapter,NDIS_STATUS_WAN_LINE_DOWN,&lineDown,sizeof(lineDown));

		pCall->m_ulFsmState = FSM_DEAD;
	}

	if(pCall->m_ulFlags & CALL_CLOSE_RETURN_PENDING)
		NdisMSetInformationComplete(g_pAdapter->m_hMiniportAdapter,NDIS_STATUS_SUCCESS);

	PLINE_INFO pLine = pCall->m_pLine;

	CallCleanup(pCall);

	DereferenceLine(pLine);
}

VOID InitializeCall(PCALL_INFO pCall,PLINE_INFO pLine,HTAPI_CALL htCall,BOOLEAN bRunAsServer)
{
	// init it
	NdisZeroMemory(pCall,sizeof(CALL_INFO));

	NdisAllocateSpinLock(&pCall->m_lockSelf);

	pCall->m_bRunAsServer = bRunAsServer;

	pCall->m_pLine = pLine;

	pCall->m_htCall = htCall;

	pCall->m_ulSig = 'CALL';

	pCall->m_ulCallState = LINECALLSTATE_IDLE;

	pCall->m_ulFsmState = FSM_IDLE;

	pCall->m_ulFlags = CALL_INITIALIZED | CALL_CONNECTING;

	NdisInitializeListHead(&pCall->m_ltPendingPackets);
}

// clean up call
VOID CallCleanup(PCALL_INFO pCall)
{
	if(!pCall)
		return;

	if(pCall->m_pLastSendDiscoveryPacket)
		DereferencePacket(pCall->m_pLastSendDiscoveryPacket);

	for(;pCall->m_lPendingPacketsCount > 0 || !IsListEmpty(&pCall->m_ltPendingPackets);)
	{
		PLIST_ENTRY pEntry = RemoveHeadList(&pCall->m_ltPendingPackets);

		PPPPOE_PACKET pPacket = CONTAINING_RECORD(pEntry,PPPOE_PACKET,m_ltPackets);

		DereferencePacket(pPacket);

		pCall->m_lPendingPacketsCount--;
	}

	NdisFreeMemory(pCall,sizeof(CALL_INFO),0);
}

// add call to bind
VOID AddCall2Bind(PCALL_INFO pCall,PBIND_CONTEXT pBind)
{
	NdisAcquireSpinLock(&pCall->m_lockSelf);

	if(!(pCall->m_ulFlags & (CALL_CLOSING | CALL_DROPPING)))
	{
		NdisAcquireSpinLock(&pBind->m_lockSelf);
		if(pBind->m_ulBindState == BIND_LOWER_MINIPORT_OPENED)
		{
			ReferenceBind(pBind,FALSE);
			pCall->m_pBindContext = pBind;
	
			NdisMoveMemory(pCall->m_macSelf,pBind->m_macAddress,6);

			pCall->m_ulLinkSpeed = pBind->m_ulLinkSpeed;

			pCall->m_ulMaxFrameSize = pBind->m_ulMaxFrameSize - PPPOE_HEADER_LEN;
		}

		NdisReleaseSpinLock(&pBind->m_lockSelf);
	}

	NdisReleaseSpinLock(&pCall->m_lockSelf);
}

VOID RemoveCallFromBind(PCALL_INFO pCall,PBIND_CONTEXT pBind)
{
	NdisAcquireSpinLock(&pCall->m_lockSelf);

	pCall->m_pBindContext = NULL;
	pCall->m_ulLinkSpeed = 0;

	NdisReleaseSpinLock(&pCall->m_lockSelf);

	DereferenceBind(pBind);
}

// init handle table
VOID InitializeHandleTable(ULONG ulCount)
{
	NdisAllocateMemoryWithTag((PVOID *)&g_pAdapter->m_pCallHandleTable,sizeof(HANDLE_TABLE),'HDTB');

	NdisZeroMemory(g_pAdapter->m_pCallHandleTable,sizeof(HANDLE_TABLE));

	NdisAllocateMemoryWithTag((PVOID *)&g_pAdapter->m_pCallHandleTable->m_pTableEntry,sizeof(TABLE_ENTRY)*ulCount,'HDIT');

	NdisZeroMemory(g_pAdapter->m_pCallHandleTable->m_pTableEntry,sizeof(TABLE_ENTRY)*ulCount);

	g_pAdapter->m_pCallHandleTable->m_ulAllocatedSeq = 0;
	g_pAdapter->m_pCallHandleTable->m_ulTableSize = ulCount;
	g_pAdapter->m_pCallHandleTable->m_ulValid = 0;
}

// free handle table
VOID FreeHandleTable(PHANDLE_TABLE pTable)
{
	if(pTable)
	{
		if(pTable->m_pTableEntry)
			NdisFreeMemory(pTable->m_pTableEntry,sizeof(TABLE_ENTRY) * pTable->m_ulTableSize,0);

		NdisFreeMemory(pTable,sizeof(HANDLE_TABLE),0);
	}
}

// insert to table
HDRV_CALL InsertToHandleTable(PHANDLE_TABLE pTable,PCALL_INFO pCall,ULONG ulWhere)
{
	if(!pTable || !pCall)
		return NULL;

	HDRV_CALL hRet = NULL;
	if(ulWhere == -1)
	{
		// server handle will be put at bottom half
		ULONG ulEnd = pTable->m_ulTableSize / 2;
		ulWhere = 0;
		if(pCall->m_bRunAsServer)
		{
			ulWhere = pTable->m_ulTableSize / 2;
			ulEnd = pTable->m_ulTableSize;
		}

		for(;ulWhere < ulEnd; ulWhere ++)
		{
			PTABLE_ENTRY pEntry = pTable->m_pTableEntry + ulWhere;

			if(!pEntry->m_ulValid)
			{
				pTable->m_ulAllocatedSeq ++;
				pTable->m_ulAllocatedSeq = pTable->m_ulAllocatedSeq & 0xffff;

				if(!pTable->m_ulAllocatedSeq)
					pTable->m_ulAllocatedSeq ++;

				pEntry->m_hdCall = (ulWhere << 16) + pTable->m_ulAllocatedSeq;
				pEntry->m_pCall = pCall;
				pEntry->m_ulValid = TRUE;
				pTable->m_ulValid ++;

				hRet = pEntry->m_hdCall;
				break;
			}
		}
	}
	else
	{
		// server handle will be put at bottom half
		ULONG ulEnd = pTable->m_ulTableSize / 2;
		if(pCall->m_bRunAsServer)
		{
			ulEnd = pTable->m_ulTableSize;
		}

		if(ulWhere < ulEnd)
		{
			// get entry ptr
			PTABLE_ENTRY pEntry = pTable->m_pTableEntry + ulWhere;

			if(!pEntry->m_ulValid)
			{
				pTable->m_ulAllocatedSeq ++;
				pTable->m_ulAllocatedSeq = pTable->m_ulAllocatedSeq & 0xffff;

				if(!pTable->m_ulAllocatedSeq)
					pTable->m_ulAllocatedSeq ++;

				pEntry->m_hdCall = (ulWhere << 16) + pTable->m_ulAllocatedSeq;
				pEntry->m_pCall = pCall;
				pEntry->m_ulValid = TRUE;
				pTable->m_ulValid ++;

				hRet = pEntry->m_hdCall;
			}
		}
	}

	return hRet;
}

// remove
VOID RemoveFromHandleTable(PHANDLE_TABLE pCallHandle,HDRV_CALL hCall)
{
	if(!pCallHandle || !hCall)
		return;

	// we store index to hCall's high word,so get it
	HDRV_CALL ulIndex = hCall >> 16;

	if(ulIndex < pCallHandle->m_ulTableSize)
	{
		// get entry ptr
		PTABLE_ENTRY pEntry = pCallHandle->m_pTableEntry + ulIndex;

		if(pEntry->m_ulValid && pEntry->m_hdCall == hCall)
		{
			pEntry->m_hdCall = NULL;
			pEntry->m_pCall = NULL;
			pEntry->m_ulValid = FALSE;

			pCallHandle->m_ulValid --;
		}
	}
}

// get call info from call table
PCALL_INFO GetCallPtrFromCallHandle(PHANDLE_TABLE pCallHandle,HDRV_CALL hCall)
{
	PCALL_INFO pCall = NULL;

	// we store index to hCall's high word,so get it
	HDRV_CALL ulIndex = hCall >> 16;

	if(ulIndex < pCallHandle->m_ulTableSize)
	{
		// get entry ptr
		PTABLE_ENTRY pEntry = pCallHandle->m_pTableEntry + ulIndex;

		// check the entry
		if(pEntry->m_ulValid && pEntry->m_hdCall == hCall)
			pCall = pEntry->m_pCall;
	}

	return pCall;
}

// get call info from call table
PCALL_INFO GetCallPtrFromHandleTableIndex(PHANDLE_TABLE pCallHandle,USHORT usIndex)
{
	PCALL_INFO pCall = NULL;

	if(usIndex < pCallHandle->m_ulTableSize)
	{
		// get entry ptr
		PTABLE_ENTRY pEntry = pCallHandle->m_pTableEntry + usIndex;

		// check the entry
		if(pEntry->m_ulValid)
			pCall = pEntry->m_pCall;
	}

	return pCall;
}

// map session id to call
PCALL_INFO MapSeccesionIdToCall(PADAPTER pAdapter,PPPPOE_PACKET pPacket)
{
	PCALL_INFO pRet = NULL;

	NdisAcquireSpinLock(&pAdapter->m_lockSelf);

	// server use (index + 1) to generate session id
	USHORT usIndex = ntohs(pPacket->m_pFrame->m_pppFrame.m_usSession) - 1;
	ULONG ulSize = pAdapter->m_ulEndPoints * pAdapter->m_ulNumLineDevs;

	if(usIndex < ulSize && usIndex >= ulSize / 2)
	{
		PCALL_INFO pCall = GetCallPtrFromHandleTableIndex(pAdapter->m_pCallHandleTable,usIndex);

		if(pCall)
		{
			if(pCall->m_usSessionId == usIndex + 1)
			{
				if( RtlCompareMemory(pCall->m_macPeer,pPacket->m_pFrame->m_srcMac,6) == 6 && 
					RtlCompareMemory(pCall->m_macSelf,pPacket->m_pFrame->m_dstMac,6) == 6)
				{
					ReferenceCall(pCall,TRUE);
					pRet = pCall;
				}
			}
		}
	}
	
	if(!pRet)
	{
		// client need to loop check all the table entry
		for(usIndex = 0,ulSize /= 2;usIndex < ulSize;usIndex ++)
		{
			PCALL_INFO pCall = GetCallPtrFromHandleTableIndex(pAdapter->m_pCallHandleTable,usIndex);

			if(pCall)
			{
				if(pCall->m_usSessionId == ntohs(pPacket->m_pFrame->m_pppFrame.m_usSession))
				{
					if( RtlCompareMemory(pCall->m_macPeer,pPacket->m_pFrame->m_srcMac,6) == 6 && 
						RtlCompareMemory(pCall->m_macSelf,pPacket->m_pFrame->m_dstMac,6) == 6)
					{
						ReferenceCall(pCall,TRUE);
						pRet = pCall;
						break;
					}
				}
			}
		}
	}

	NdisReleaseSpinLock(&pAdapter->m_lockSelf);

	return pRet;
}

// map call info
PCALL_INFO MapWithoutSessionIdToCall(PADAPTER pAdapter,PPPPOE_PACKET pPacket)
{
	if(pPacket->m_usHostUnique != 8)
		return NULL;

	// we saved call handle as host unique lower part
	ULONG ulCallHandle = reinterpret_cast<PLARGE_INTEGER>(pPacket->m_pHostUnique)->LowPart;
	
	PCALL_INFO pRet = NULL;
	if(ulCallHandle)
	{
		NdisAcquireSpinLock(&pAdapter->m_lockSelf);

		// client mode only
		pRet = GetCallPtrFromCallHandle(pAdapter->m_pCallHandleTable,ulCallHandle);

		if(pRet)
			ReferenceCall(pRet,TRUE);

		NdisReleaseSpinLock(&pAdapter->m_lockSelf);
	}

	return pRet;
}

// return host order session id server mode only
USHORT GetSessionIdFromCallHandle(HDRV_CALL hdCall)
{
	return static_cast<USHORT>(hdCall >> 16) + 1;
}

// schedule a timer to indicate recved
VOID ScheduleIndicateRecvedPacketTimer(PCALL_INFO pCall)
{
	if(pCall->m_ulFlags & CALL_RECV_NEXT_TIMER_SCHEDULED)
		return;

	if(pCall->m_ulFsmState != FSM_SESSION)
		return;

	if(pCall->m_lPendingPacketsCount <= 0)
		return;

	pCall->m_ulFlags |= CALL_RECV_NEXT_TIMER_SCHEDULED;

	// init item
	NdisInitializeListHead(&pCall->m_timerRecvItem.m_ltItem);

	// schedule it
	ScheduleTimerItem(&g_timer,&pCall->m_timerRecvItem,1,IndicateRecvedPackets,pCall);

	// ref call
	ReferenceCall(pCall,FALSE);
}

// timer routine
VOID IndicateRecvedPackets(PPPPOE_TIMER_ITEM pItem,PVOID pContext,PVOID pCancelContext)
{
	PCALL_INFO pCall = static_cast<PCALL_INFO>(pContext);
	
	NdisAcquireSpinLock(&pCall->m_lockSelf);

	LONG lCount = 100;

	for(;pCall->m_lPendingPacketsCount > 0 && lCount > 0;lCount --)
	{
		PLIST_ENTRY pEntry = RemoveHeadList(&pCall->m_ltPendingPackets);

		PPPPOE_PACKET pPacket = CONTAINING_RECORD(pEntry,PPPOE_PACKET,m_ltPackets);

		pCall->m_lPendingPacketsCount --;

		NdisReleaseSpinLock(&pCall->m_lockSelf);

		NDIS_STATUS status;

		NdisMWanIndicateReceive(&status,g_pAdapter->m_hMiniportAdapter,pCall->m_hLinkContext,pPacket->m_pucDataBuffer,
								ntohs(pPacket->m_pFrame->m_pppFrame.m_usLen));

		// deref packet
		DereferencePacket(pPacket);

		NdisAcquireSpinLock(&pCall->m_lockSelf);
	}

	// schedule next call
	if(pCall->m_lPendingPacketsCount > 0 && pCall->m_ulFsmState == FSM_SESSION)
	{
		// init item
		NdisInitializeListHead(&pCall->m_timerRecvItem.m_ltItem);

		// schedule it
		ScheduleTimerItem(&g_timer,&pCall->m_timerRecvItem,1,IndicateRecvedPackets,pCall);

		NdisReleaseSpinLock(&pCall->m_lockSelf);
	}
	else
	{
		pCall->m_ulFlags &= ~CALL_RECV_NEXT_TIMER_SCHEDULED;

		NdisReleaseSpinLock(&pCall->m_lockSelf);

		DereferenceCall(pCall);
	}
}

// create unique value
VOID CreateUniqueValue(HDRV_CALL hCall,PLARGE_INTEGER pUnique,PUSHORT pusLen)
{
	static LONG _s_lUnique = 1;
	*pusLen = 8;
	pUnique->LowPart = (ULONG)hCall;
	pUnique->HighPart = NdisInterlockedIncrement(&_s_lUnique);
}

⌨️ 快捷键说明

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