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 + -
显示快捷键?