📄 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<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 + -