📄 pppoe.cpp
字号:
//********************************************************************
// 日期: 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 + -