www.pudn.com > PPPOE.rar > callmgr.cpp
//********************************************************************
// ÈÕÆÚ: 2004/08/25 - 25:8:2004 14:23
// Ãûǰ: tiamo
// ÃèÊö: call manager
//*********************************************************************
#include "stdafx.h"
// open af
NDIS_STATUS mcmOpenAf(PADAPTER pAdapter,PCO_ADDRESS_FAMILY pCoAf,NDIS_HANDLE hNdisAfHandle,PADAPTER *ppAdapter)
{
ASSERT(pAdapter && pAdapter->m_ulSig == ADAPTER_SIG && pAdapter->m_lRefCount > 0);
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
NdisAcquireSpinLock(&pAdapter->m_lockSelf);
if(pAdapter->m_hNdisAfHandle)
{
DebugError(("try to open AF again!\n"));
status = NDIS_STATUS_FAILURE;
}
else
{
// add a ref
ReferenceAdapter(pAdapter,FALSE);
// save
pAdapter->m_hNdisAfHandle = hNdisAfHandle;
DebugInfo(("AF = 0x%x,version = (%d,%d)\n",hNdisAfHandle,pCoAf->MajorVersion,pCoAf->MinorVersion));
*ppAdapter = pAdapter;
}
NdisReleaseSpinLock(&pAdapter->m_lockSelf);
return status;
}
// close af
NDIS_STATUS mcmCloseAf(PADAPTER pAdapter)
{
ASSERT(pAdapter && pAdapter->m_ulSig == ADAPTER_SIG && pAdapter->m_lRefCount > 0);
DebugInfo(("close AF = 0x%x\n",pAdapter->m_hNdisAfHandle));
NdisAcquireSpinLock(&pAdapter->m_lockSelf);
pAdapter->m_hNdisAfHandle = NULL;
NdisReleaseSpinLock(&pAdapter->m_lockSelf);
DereferenceAdapter(pAdapter);
return NDIS_STATUS_SUCCESS;
}
// register sap
NDIS_STATUS mcmRegisterSap(PADAPTER pAdapter,PCO_SAP pSap,NDIS_HANDLE hNdisSapHandle,PCHANNEL *ppChannel)
{
ASSERT(pAdapter && pAdapter->m_ulSig == ADAPTER_SIG && pAdapter->m_lRefCount > 0);
NDIS_STATUS status = NDIS_STATUS_INVALID_DATA;
PCO_AF_TAPI_SAP pTapiSap = reinterpret_cast(pSap->Sap);
PCHANNEL pChannel = NULL;
// get channel pointer
if(pTapiSap->ulLineID < pAdapter->m_ulNumChannels)
{
pChannel = pAdapter->m_ppChannels[pTapiSap->ulLineID];
ASSERT(pChannel && pChannel->m_lRefCount > 0);
NdisAcquireSpinLock(&pChannel->m_lockSelf);
if(pChannel->m_hNdisSapHandle)
{
DebugError(("channel %d try to register SAP again!\n",pTapiSap->ulLineID));
status = NDIS_STATUS_SAP_IN_USE;
}
else
{
pChannel->m_hNdisSapHandle = hNdisSapHandle;
pChannel->m_lSapRefCount = 1;
pChannel->m_lRefCount ++;
pChannel->m_coTapiSap = *pTapiSap;
DebugInfo(("channel %d reg SAP = 0x%x,addr id = 0x%x media mode = 0x%x\n",pTapiSap->ulLineID,hNdisSapHandle,
pTapiSap->ulAddressID,pTapiSap->ulMediaModes));
*ppChannel = pChannel;
status = NDIS_STATUS_SUCCESS;
}
NdisReleaseSpinLock(&pChannel->m_lockSelf);
}
return status;
}
// deregister sap
NDIS_STATUS mcmDeregisterSap(PCHANNEL pChannel)
{
ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG && pChannel->m_lRefCount > 0 && pChannel->m_lSapRefCount > 0);
DebugInfo(("channel %d dereg SAP = 0x%x,addr id = 0x%x media mode = 0x%x\n",
pChannel->m_coTapiSap.ulLineID,pChannel->m_hNdisSapHandle,
pChannel->m_coTapiSap.ulAddressID,pChannel->m_coTapiSap.ulMediaModes));
DereferenceSap(pChannel);
return NDIS_STATUS_PENDING;
}
// create vc
NDIS_STATUS mcmCreateVc(PADAPTER pAdapter,NDIS_HANDLE hNdisVcHandle,PCHANNEL *ppChannel)
{
ASSERT(pAdapter && pAdapter->m_ulSig == ADAPTER_SIG && pAdapter->m_lRefCount > 0);
NDIS_STATUS status = NDIS_STATUS_VC_NOT_AVAILABLE;
PCHANNEL pChannel = NULL;
NdisAcquireSpinLock(&pAdapter->m_lockSelf);
__try
{
// loop find
for(ULONG i = 0; i < pAdapter->m_ulNumChannels; i++)
{
pChannel = pAdapter->m_ppChannels[i];
ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG && pChannel->m_lRefCount > 0);
NdisAcquireSpinLock(&pChannel->m_lockSelf);
// check state
if(pChannel->m_ulState == CHANNEL_CLOSE)
{
pChannel->m_ulState = CHANNEL_OPEN;
pChannel->m_hNdisVcHandle = hNdisVcHandle;
ReferenceChannel(pChannel,FALSE);
NdisReleaseSpinLock(&pChannel->m_lockSelf);
DebugInfo(("found a free channel %d at 0x%x,NdisVcHandle = 0x%x\n",pChannel->m_ulLineId,pChannel,hNdisVcHandle));
status = NDIS_STATUS_SUCCESS;
break;
}
NdisReleaseSpinLock(&pChannel->m_lockSelf);
pChannel = NULL;
}
// found one
if(!pChannel)
{
DebugInfo(("there is no free channel,failed\n"));
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
NdisReleaseSpinLock(&pAdapter->m_lockSelf);
*ppChannel = pChannel;
return status;
}
// delete vc
NDIS_STATUS mcmDeleteVc(PCHANNEL pChannel)
{
ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG && pChannel->m_lRefCount > 0 && pChannel->m_hNdisVcHandle);
ASSERT(pChannel->m_ulState == CHANNEL_OPEN);
DebugInfo(("channel %d delete vc,NdisVcHandle = 0x%x\n",pChannel->m_ulLineId,pChannel->m_hNdisVcHandle));
NdisAcquireSpinLock(&pChannel->m_lockSelf);
pChannel->m_hNdisVcHandle = NULL;
pChannel->m_ulState = CHANNEL_CLOSE;
NdisReleaseSpinLock(&pChannel->m_lockSelf);
DereferenceChannel(pChannel);
return NDIS_STATUS_SUCCESS;
}
// activate vc complete
VOID mcmActivateVcComplete(NDIS_STATUS status,PCHANNEL pChannel,PCO_CALL_PARAMETERS pCallParams)
{
ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG && pChannel->m_lRefCount > 0 && pChannel->m_hNdisVcHandle);
ASSERT(pChannel->m_ulState == CHANNEL_ACTIVATING);
DebugInfo(("channel %d activate vc complete,NdisVcHandle = 0x%x,status = 0x%x\n",
pChannel->m_ulLineId,pChannel->m_hNdisVcHandle,status));
NdisAcquireSpinLock(&pChannel->m_lockSelf);
if(status == NDIS_STATUS_SUCCESS)
{
pChannel->m_ulState = CHANNEL_ACTIVATED;
ReferenceChannel(pChannel,FALSE);
}
NdisReleaseSpinLock(&pChannel->m_lockSelf);
}
// deactivate vc complete
VOID mcmDeactivateVcComplete(NDIS_STATUS status,PCHANNEL pChannel)
{
ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG && pChannel->m_lRefCount > 0 && pChannel->m_hNdisVcHandle);
ASSERT(pChannel->m_ulState == CHANNEL_DEACTIVATING);
DebugInfo(("channel %d deactivate vc complete,NdisVcHandle = 0x%x,status = 0x%x\n",
pChannel->m_ulLineId,pChannel->m_hNdisVcHandle,status));
NdisAcquireSpinLock(&pChannel->m_lockSelf);
if(status == NDIS_STATUS_SUCCESS)
{
pChannel->m_ulState = CHANNEL_OPEN;
}
NdisReleaseSpinLock(&pChannel->m_lockSelf);
if(status == NDIS_STATUS_SUCCESS)
{
DereferenceChannel(pChannel);
}
}
// make call
NDIS_STATUS mcmMakeCall(PCHANNEL pChannel,PCO_CALL_PARAMETERS pCallParams,NDIS_HANDLE hNdisPartyHandle,
PNDIS_HANDLE pCallMgrPartyContext)
{
ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG && pChannel->m_lRefCount > 0 && pChannel->m_hNdisVcHandle);
ASSERT(pChannel->m_ulState == CHANNEL_OPEN);
if(hNdisPartyHandle)
{
DebugError(("do not support party.\n"))
return NDIS_STATUS_NOT_SUPPORTED;
}
PCO_AF_TAPI_MAKE_CALL_PARAMETERS pTapiParam =
reinterpret_cast(pCallParams->MediaParameters->MediaSpecific.Parameters);
PLINE_CALL_PARAMS pLineParams = reinterpret_cast(
reinterpret_cast(&pTapiParam->LineCallParams) + pTapiParam->LineCallParams.Offset);
if(pLineParams->ulBearerMode & ~pChannel->m_ulBearerMode)
{
DebugError(("unsupported bearermode.(0x%x,0x%x)\n",pLineParams->ulBearerMode,pChannel->m_ulBearerMode));
return NDIS_STATUS_NOT_SUPPORTED;
}
if(pLineParams->ulMediaMode & ~pChannel->m_ulMediaMode)
{
DebugError(("unsupported mediamode.(0x%x,0x%x)\n",pLineParams->ulMediaMode,pChannel->m_ulMediaMode));
return NDIS_STATUS_NOT_SUPPORTED;
}
// irql is too high,use work item to do it
PWORK_ITEM pReBind = AllocateWorkItem(ExecReBindForMakeCall);
if(!pReBind)
{
DebugError(("unable to allocate workitem for rebind.\n"));
return NDIS_STATUS_RESOURCES;
}
PWORK_ITEM pMakeCall = AllocateWorkItem(ExecMakeCall);
if(!pMakeCall)
{
DebugError(("unable to allocate workitem for make call.\n"));
NdisFreeToNPagedLookasideList(&g_lookasideWorkItem,pReBind);
return NDIS_STATUS_RESOURCES;
}
pReBind->m_param.REBIND_FOR_MAKE_CALL.m_pMakeCall = pMakeCall;
pMakeCall->m_param.MAKE_CALL.m_pChannel = pChannel;
pChannel->m_pOutParam = pCallParams;
pChannel->m_ulState = CHANNEL_ACTIVATING;
ScheduleWorkItem(pReBind);
*pCallMgrPartyContext = NULL;
return NDIS_STATUS_PENDING;
}
// close call
NDIS_STATUS mcmCloseCall(PCHANNEL pChannel,NDIS_HANDLE PartyContext,PVOID pCloseData,UINT uSize)
{
ASSERT(pChannel && pChannel->m_ulSig == CHANNEL_SIG && pChannel->m_lRefCount > 0 && pChannel->m_hNdisVcHandle);
ASSERT(pChannel->m_ulState == CHANNEL_ACTIVATED);
// irql too high
PWORK_ITEM pCloseCall = AllocateWorkItem(ExecCloseCall);
if(!pCloseCall)
{
DebugError(("unable to allocate workitem for close call.\n"));
return NDIS_STATUS_RESOURCES;
}
pCloseCall->m_param.CLOSE_CALL.m_pChannel = pChannel;
ScheduleWorkItem(pCloseCall);
return NDIS_STATUS_PENDING;
}
// request
NDIS_STATUS mcmRequest(PADAPTER pAdapter,PCHANNEL pChannel,NDIS_HANDLE ProtocolPartyContext,PNDIS_REQUEST pNdisRequest)
{
return miniportCoRequest(pAdapter,pChannel,pNdisRequest);
}
// request complete
VOID mcmRequestComplete(NDIS_STATUS status,PADAPTER pAdapter,PCHANNEL pChannel,NDIS_HANDLE ProtocolPartyContext,PNDIS_REQUEST pNdisRequest)
{
}
// work item routine for make call reenumerate bind
VOID ExecReBindForMakeCall(PWORK_ITEM pItem,PWORK_ITEM_PARAM pParam)
{
NdisAcquireSpinLock(&g_lockBind);
g_bIsTimeToBind = TRUE;
NdisReleaseSpinLock(&g_lockBind);
NdisReEnumerateProtocolBindings(g_hNdisProtocolHandle);
ChangeLowerMiniportPacketFilter(TRUE);
ScheduleWorkItem(pParam->REBIND_FOR_MAKE_CALL.m_pMakeCall);
}
// for make call
VOID ExecMakeCall(PWORK_ITEM pItem,PWORK_ITEM_PARAM pParam)
{
PCHANNEL pChannel = pParam->MAKE_CALL.m_pChannel;
// tapi call param
PCO_AF_TAPI_MAKE_CALL_PARAMETERS pTapiParam =
reinterpret_cast(pChannel->m_pOutParam->MediaParameters->MediaSpecific.Parameters);
// line param
PLINE_CALL_PARAMS pLineParams = reinterpret_cast(
reinterpret_cast(&pTapiParam->LineCallParams) + pTapiParam->LineCallParams.Offset);
UNICODE_STRING strDestAddr;
strDestAddr.Buffer = reinterpret_cast(&pTapiParam->DestAddress) + pTapiParam->DestAddress.Offset;
strDestAddr.Length = strDestAddr.MaximumLength = pTapiParam->DestAddress.Length;
CHAR _s_tempAddr[256];
ANSI_STRING szDestAddr;
szDestAddr.Buffer = _s_tempAddr;
szDestAddr.Length = sizeof(_s_tempAddr);
szDestAddr.MaximumLength = sizeof(_s_tempAddr);
// this must passive level
NdisUnicodeStringToAnsiString(&szDestAddr,&strDestAddr);
DebugInfo(("dest addr %Z\n",&strDestAddr));
if(pChannel->m_ulState != CHANNEL_ACTIVATING)
return;
NdisAcquireSpinLock(&pChannel->m_lockSelf);
PUCHAR pDestAddr = reinterpret_cast(_s_tempAddr);
ULONG ulTotalLen = szDestAddr.Length;
// get ac name and serive name
ULONG ulACNameStart = 0;
ULONG ulACNameEnd = 0;
ULONG ulServiceNameStart = 0;
ULONG ulServiceNameEnd = 0;
ULONG i = 0;
/*
* format1 : " ac \ service "
* format2 : " ac \ "
* format3 : " service "
*/
while(i < ulTotalLen && pDestAddr[i])
{
// skip space
while(i < ulTotalLen && pDestAddr[i] && pDestAddr[i] == ' ')
i++;
// check len
if(i >= ulTotalLen || !pDestAddr[i])
break;
// ac name start
ulACNameStart = ulACNameEnd = i;
while(i < ulTotalLen)
{
if(pDestAddr[i] != ' ')
ulACNameEnd = i;
if(pDestAddr[i] == '\\' || !pDestAddr[i])
break;
i++;
}
// can't find a '\' total is service name
if(i == ulTotalLen || !pDestAddr[i])
{
ulServiceNameStart = ulACNameStart;
ulServiceNameEnd = ulACNameEnd;
ulACNameEnd = ulACNameStart = 0;
break;
}
++ i;
// got here found a '\' get service name
while(i < ulTotalLen && pDestAddr[i] && pDestAddr[i] == ' ')
i++;
ulServiceNameStart = ulServiceNameEnd = i;
while(i < ulTotalLen)
{
if(pDestAddr[i] != ' ')
ulServiceNameEnd = i;
if(!pDestAddr[i])
break;
i++;
}
}
// set ac name
ULONG ulLen = ulACNameEnd - ulACNameStart;
if(ulLen)
{
if(ulLen > 256)
ulLen = 256;
NdisMoveMemory(pChannel->m_ucAC,pDestAddr + ulACNameStart,ulLen);
pChannel->m_usACLen = static_cast(ulLen);
}
// set service name
ulLen = ulServiceNameEnd - ulServiceNameStart;
if(ulLen)
{
if(ulLen > 256)
ulLen = 256;
NdisMoveMemory(pChannel->m_ucService,pDestAddr + ulServiceNameStart,ulLen);
pChannel->m_usServiceLen = static_cast(ulLen);
}
pChannel->m_ulFsmState = FSM_CLIENT_SEND_PADI;
NdisReleaseSpinLock(&pChannel->m_lockSelf);
FsmRun(pChannel,NULL,NULL);
}
// close call
VOID ExecCloseCall(PWORK_ITEM pItem,PWORK_ITEM_PARAM pParam)
{
PCHANNEL pChannel = pParam->CLOSE_CALL.m_pChannel;
NdisAcquireSpinLock(&pChannel->m_lockSelf);
PPACKET pPacket = NULL;
if(pChannel->m_ulFsmState == FSM_SESSION && pChannel->m_pBindContext && pChannel->m_usSessionId)
{
DebugInfo(("need to send PADT,build it\n"));
pPacket = InitializePADTToSend(pChannel->m_macPeer,pChannel->m_macSelf,pChannel->m_usSessionId);
ReferencePacket(pPacket);
}
// set this state,lower protocol will not add recved packet to our list
pChannel->m_ulState = CHANNEL_DEACTIVATING;
NdisReleaseSpinLock(&pChannel->m_lockSelf);
// throw away pending packet
NdisAcquireSpinLock(&pChannel->m_lockSelf);
DebugInfo(("pending recved packets = %d,throw them away\n",pChannel->m_lPendingRecvedPackets));
while(pChannel->m_lPendingRecvedPackets > 0 && !IsListEmpty(&pChannel->m_ltRecvedPacketsHead))
{
PLIST_ENTRY pEntry = RemoveHeadList(&pChannel->m_ltRecvedPacketsHead);
PPACKET pPacket = CONTAINING_RECORD(pEntry,PACKET,m_ltPacketAnchor);
DereferencePacket(pPacket);
pChannel->m_lPendingRecvedPackets --;
}
if(pChannel->m_pLastPacket)
{
DereferencePacket(pChannel->m_pLastPacket);
pChannel->m_pLastPacket = NULL;
}
NdisReleaseSpinLock(&pChannel->m_lockSelf);
// cancel timer item
CancelTimerItem(&pChannel->m_timerItemDiscovery,(PVOID)1);
// send PADT
if(pPacket)
{
ReferenceBind(pChannel->m_pBindContext,TRUE);
SendPacket(pChannel->m_pBindContext,pPacket);
DereferencePacket(pPacket);
}
// this needed?
NdisMCoReceiveComplete(g_pAdapter->m_hNdisAdapter);
// wait for upper return packets
DebugInfo(("upper pending return packets = %d,wait them.\n",pChannel->m_lPendingReturnPackets));
while(pChannel->m_lPendingReturnPackets)
{
NdisMSleep(10000);
}
// wait for lower send complete
DebugInfo(("lower pending send complete packets = %d,wait them.\n",pChannel->m_lSendingPackets));
while(pChannel->m_lSendingPackets)
NdisMSleep(10000);
// remove from bind
if(pChannel->m_pBindContext)
RemoveChannelFromBind(pChannel,pChannel->m_pBindContext);
// deactivate vc
NDIS_STATUS status = NdisMCmDeactivateVc(pChannel->m_hNdisVcHandle);
if(status != NDIS_STATUS_PENDING)
mcmDeactivateVcComplete(status,pChannel);
// close complete
NdisMCmCloseCallComplete(status,pChannel->m_hNdisVcHandle,NULL);
}
// incoming call complete
VOID mcmIncomingCallComplete(NDIS_STATUS status,PCHANNEL pChannel,PCO_CALL_PARAMETERS pCallParams)
{
DebugError(("not implement!\n"));
}
// modify call qos
NDIS_STATUS mcmModifyCallQos(PCHANNEL pChannel,PCO_CALL_PARAMETERS pCallParams)
{
DebugError(("not implement!\n"));
return NDIS_STATUS_FAILURE;
}