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; 
}