
/*
*********************************************************************************
*                                                                               *
* NOTICE:                                                                 *
*                                                                               *
*********************************************************************************
*  
*                                      
*    
*       mgcSap <---------mgcPhyPorts --------> mgcMgInfo
*                                            |
*                                            |
*                                            |
*                                       mgcChnls <-----------mgcConnections
*/
 
    
/*********************************************************************************
 *                              <mgc.c>                                                              
 *     This file contain APIs which is provided to uplayer to implement media control between sessions 
 * by using MGCP protocol   	
 *
 *
 *    Author                         Date
 *    ------                        ------
 *    Sam Yao                     Aug 2008                                                                                              
 *********************************************************************************/



#define MGC_AAS_ITL_PORT_NO 255

/*-----------------------------------------------------------------------*/
/*                        INCLUDE HEADER FILES                           */
/*-----------------------------------------------------------------------*/
#include "./include/mgc_struct.h"
#include "./include/mgc_debug.h"
#include "./include/mgc_chnl_info.h"
#include "./include/mgc_mg_info.h"
#include "./include/mgc_port_info.h"
#include "./include/mgc_conn_info.h"
#include "./include/mgc_ctl.h"
#include "./include/mgc_8ecp.h"
#include "./include/mgc_phy_port.h"
#include "./include/mgc_mgcp.h"
#include "./include/mgc_internal.h"
#include "./include/mgc_snmp.h"
#include "./include/mgc_tandem_info.h"
#include "./include/mgc_sur_info.h"
#ifdef MGC_PORT_LIST_EN
#include "./include/mgc_port_list.h"
#endif

static MGC_SAP mgcSap[MGC_MAX_NUM_OF_SAP];


/*-----------------------------------------------------------------------*/
/*                           MODULE FUNCTIONS                            */
/*-----------------------------------------------------------------------*/
static int mgc_get_snmp_msg(void);


/*-----------------------------------------------------------------------
              MGC - SAP      M A N A G E R
 ------------------------------------------------------------------------*/	  


char *mgc_print_failure_reason(int ret)
{
    if(ret >= 0)
	    return "MGC_RESULT_OK";	

     switch(ret)
     {
	     case MGC_RESULT_FAILURE:
	 	    return "MGC_RESULT_FAILURE";
	     case MGC_RESULT_INPUT_ILLEGAL:
	 	    return "MGC_RESULT_INPUT_ILLEGAL";
	     case MGC_RESULT_NO_RES:
	 	    return "MGC_RESULT_NO_RES";
	     case MGC_RESULT_LACK_PARA:
		 	return "MGC_RESULT_LACK_PARA";
		 default:
		 	break;
     }

     return "MGC_RESULT_UNKNOW_REASON";
}


/***************************************************************************
 * mgc_sap_init
 * ------------------------------------------------------------------------
 * General: init MGC_SAP structure object , and set the id of this MGC_SAP object. 
 * Return Value:  void.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	pMgcSap - pointer of the MGC_SAP object which want to be init
 *	       id - the id of this MGC_SAP object should be, this id can't be set out of MGC module
 ***************************************************************************/
static void mgc_sap_init(MGC_SAP *pMgcSap , int id)
{
    if(pMgcSap == NULL)
        return ;
	
    pMgcSap->id = id;
    memset(pMgcSap->usrName , 0 , MGC_MAX_USER_NAME_LEN);
	pMgcSap->usrType = MGC_USER_TYPE_UNDEF;
	pMgcSap->cnf_func = NULL;
	pMgcSap->ind_func = NULL;
	return;
}

static void mgc_sap_setup(void)
{
    int i;
	MGC_SAP *pMgcSap = NULL;
	
    for(i=0 ; i<MGC_MAX_NUM_OF_SAP ; i++)
    {
        pMgcSap = &mgcSap[i];
		mgc_sap_init(pMgcSap , i);
    }
    return;
}

/***************************************************************************
 * mgc_sap_get_index_sap
 * ------------------------------------------------------------------------
 * General: get the pointer of the MGC_SAP object. 
 * Return Value:  if failed return NULL , else return a pointer.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	index - the index of MGC_SAP object
 *	    
 ***************************************************************************/
MGC_SAP *mgc_sap_get_index_sap(int index)
{
    if((index < 0)||(index>= MGC_MAX_NUM_OF_SAP))
        return NULL;

    return &(mgcSap[index]);	
}


/***************************************************************************
 * mgc_sap_get_idle_sap
 * ------------------------------------------------------------------------
 * General: get an pointer of the MGC_SAP object which is not used. 
 * Return Value:  if failed return NULL , else return a pointer.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	void
 *	    
 ***************************************************************************/
static MGC_SAP *mgc_sap_get_idle_sap(void)
{
    int i;
    MGC_SAP *pSap = NULL;

    for(i=0 ; i< MGC_MAX_NUM_OF_SAP ; i++)
    {
        pSap = &mgcSap[i];
		if((pSap->usrType == MGC_USER_TYPE_UNDEF)&&(pSap->ind_func == NULL) && (pSap->cnf_func == NULL))
		    return pSap;	
    }

    return NULL;	
}

/***************************************************************************
 * mgc_sap_is_already_bind
 * ------------------------------------------------------------------------
 * General: check if the MGC_SAP object is already exist. 
 * Return Value:  if not exist return NULL , else return a pointer.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	pSap- the pointer 
 *	    
 ***************************************************************************/
static MGC_SAP *mgc_sap_is_already_bind(MGC_SAP *pSap)
{
    int i;
    MGC_SAP *pSapTmp = NULL;    

    if(pSap == NULL)
        return NULL;

    for(i=0 ; i<MGC_MAX_NUM_OF_SAP ; i++)
    {
        pSapTmp = &mgcSap[i];

		if(pSapTmp->usrType == MGC_USER_TYPE_UNDEF)
		    continue;

		if(strcmp(pSapTmp->usrName , pSap->usrName) != 0)
		    continue;

		return pSapTmp;
    }

    return NULL;	
}


/*-----------------------------------------------------------------------
              MGC - INTERFACE      M A N A G E R
 ------------------------------------------------------------------------*/	  


/***************************************************************************
 * mgc_init
 * ------------------------------------------------------------------------
 * General: init mgc module, which is used by up-layer 
 * Return Value:  void.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: systemId - the ID of the MGC
 *           localIp - the IP of the MGC
 *	       peerIp -  the IP of the peer object
 *
 *  Notice :  the input arguments is not actually useful, just for keep interface unchange
 ***************************************************************************/	
void mgc_init(DWORD systemId, DWORD localIp, DWORD peerIp)
{
    mgc_debug_set();	
    MGC_DEBUG("MGC %ld init start!!" , systemId);
	
    if(mgc_bind_8ecp_setup() < 0)
        return;
	
	if(mgc_bind_mgcp_setup() < 0)
		return;

	mgc_sap_setup();
	mgc_phy_port_setup();
    mgc_mg_info_setup();
	mgc_chnl_info_setup();
	mgc_connect_setup();
	mgc_port_info_setup();
    mgc_tandem_info_setup();
	mgc_sur_info_setup();
    mgc_ctl_num_init(systemId , localIp , peerIp);

#ifdef MGC_PORT_LIST_EN
    mgc_port_list_setup();
#endif
	/*create internal mg, need to be done*/

    if(mgc_internal_sap_bind() == FALSE)
    {
        MGC_ERROR("bind internal sap failed");
		return;
    }

    if(mgc_internal_mg_create() == FALSE)
    {
        MGC_ERROR("create internal mg failed!");
        return;
    }

	MGC_DEBUG("mgc module init over");
	return;
}


/***************************************************************************
 * mgc_bind
 * ------------------------------------------------------------------------
 * General: bind up-layer user info to MGC_SAP object 
 * Return Value:  if failed return -1 ,  else return the id of the MGC_SAP object.
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pSap - pointer to the up-layer info
 *
 ***************************************************************************/	
int mgc_bind(MGC_SAP *pSap)
{
    MGC_SAP *pSapIdle = NULL;
 
#ifndef MGC_TEST_ENABLE 
    if (wxc2_get_license(LIC_MGC) <= 0)
    {
	    MGC_ERROR("mgc_bind:	mgc module is not presented!");
	    return MGC_RESULT_INPUT_ILLEGAL;
    }
#endif
    if(pSap == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;

    switch(pSap->usrType)
    {
        case MGC_USER_TYPE_MG:
			 if(pSap->ind_func == NULL)
			     return MGC_RESULT_LACK_PARA;	
			 break;
        case MGC_USER_TYPE_MGC:
             if(pSap->cnf_func == NULL)
			      return MGC_RESULT_LACK_PARA;	
			 break;		
		default:
			 return MGC_RESULT_INPUT_ILLEGAL;
    }

    pSapIdle = mgc_sap_is_already_bind(pSap);
	if(pSapIdle != NULL)
	{
	    MGC_WARN("mgcSap[%d] already bind" , pSap->id);
	    return pSapIdle->id;
	}

    pSapIdle = mgc_sap_get_idle_sap();
    if(pSapIdle == NULL)
        return MGC_RESULT_NO_RES;		

    sprintf(pSapIdle->usrName , "%s" , pSap->usrName);
	pSapIdle->usrType = pSap->usrType;
	pSapIdle->ind_func = pSap->ind_func;
	pSapIdle->cnf_func = pSap->cnf_func;

    MGC_DEBUG("mgcSap[%d] %s bind !" , pSapIdle->id , pSapIdle->usrName);
	return pSapIdle->id;
}


/***************************************************************************
 * mgc_unbind
 * ------------------------------------------------------------------------
 * General: remove the up-layer info from MGC_SAP objects 
 * Return Value:  if failed return -1 ,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: pSap - pointer to the up-layer info which want to be remove
 *          sapIndex - the MGC_SAP object id which is returned when use mgc_bind
 ***************************************************************************/
int mgc_unbind(MGC_SAP *pSap, BYTE sapIndex)
{
    MGC_SAP *pDestSap = NULL;
	
    if(pSap == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;

    pDestSap = mgc_sap_get_index_sap(sapIndex);
    if(pDestSap == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;

    if((pSap->usrType != pDestSap->usrType)||(strcmp(pSap->usrName , pDestSap->usrName)))	
    {
        MGC_WARN("unbind mgc sap not matched!");
    }

    MGC_DEBUG("mgcSap[%d] %s unbind !" ,pDestSap->id,pDestSap->usrName);
	mgc_sap_init(pDestSap , pDestSap->id);
	return MGC_RESULT_OK;
}


/***************************************************************************
 * mgc_misc_timer
 * ------------------------------------------------------------------------
 * General: handle snmp msg and debug msg reciving
 * Return Value:  void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  void
 ***************************************************************************/
static void mgc_misc_timer(void)
{
    static DWORD cntT50ms;

    if(cntT50ms++ >= MGC_MGCF_TIMER_50MS)
    {		
        cntT50ms = 0;
        mgc_get_snmp_msg();
    }

	mgc_mon();
}

/***************************************************************************
 * mgc_timer
 * ------------------------------------------------------------------------
 * General: mgc Module polling
 * Return Value:  void
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  void
 ***************************************************************************/
void mgc_timer(void)
{
#ifndef MGC_PORT_LIST_EN
    PORT_INFO *pPortInfo = NULL;
#endif
	MG_INFO *pMgInfo = NULL;
    int i;

#ifndef MGC_PORT_LIST_EN
    for(i=0 ; i<MGC_MAX_NUM_OF_PORT ; i++)
    {
        pPortInfo = mgc_port_info_find_port_by_id(i);
		mgc_port_info_fsm(pPortInfo);
    }
#else
    mgc_port_active_list_proc();
#endif

    for(i=0 ; i<MGC_MAX_NUM_OF_MG ; i++)
    {
        pMgInfo = mgc_mg_info_get_index_mg(i);
        mgc_mg_info_state_check(pMgInfo);
    }

	mgc_misc_timer();
}


/***************************************************************************
 * mgc_create_MG
 * ------------------------------------------------------------------------
 * General: inferace for up-layer create mg
 * Return Value:  if failure return -1,  else return the id of the MG_INFO object
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  sapIndex - the id of the MGC_SAP object which is provided by mgc_bind 
 *            pMgAttr -  the pointer of the MG attribute
 ***************************************************************************/
int mgc_create_MG(BYTE sapIndex, MG_ATTR *pMgAttr)
{
    MGC_SAP *pMgcSap = NULL;
	MG_INFO *pMgInfo = NULL;
    int i;
	BOOL tag;
    PHY_PORT_INFO *pPhyPort;
	MGC_PHY_PORT_TYPE portType = MGC_PHY_PORT_TYPE_UNDEF;
    if(pMgAttr == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;

	if(mgc_ctl_is_mg_full())
        return MGC_RESULT_NO_RES;
		
    pMgcSap = mgc_sap_get_index_sap(sapIndex);
    if(pMgcSap == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;

	if(pMgAttr->mgType == MGC_MG_TYPE_ANN)
	{
		portType = MGC_PHY_VIRTUAL_TYPE_ANN;				
	}
	else if(pMgAttr->mgType == MGC_MG_TYPE_TANDEM)
	{
		 portType = MGC_PHY_VIRTUAL_TYPE_TANDEM; 
	}

    pMgInfo = mgc_mg_info_check_mg_is_exsit(pMgAttr);
	if(pMgInfo != NULL)
	{
	    /*check if the same sapIndex already create MGC_MG_TYPE_ANN*/
        if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_ANN)
        {
            tag = FALSE;

            for(i=0 ; i<MGC_MAX_PHY_PORT_PER_MG ; i++)
            {
                pPhyPort = pMgInfo->pPhyPort[i];

				if(pPhyPort == NULL)
				    continue;

				if(pPhyPort->pMgcSap != pMgcSap)
				    continue;

				tag = TRUE;  // the same user already create MGC_MG_TYPE_ANN 
            }

			if(tag == FALSE)   //new user create MGC_MG_TYPE_ANN 
			{
		        pPhyPort = mgc_phy_port_get_unused_phy();
		        /*only add one phyPort for rtp_proxy*/
			    
                if(mgc_add_port(sapIndex, pMgInfo->id, MGC_AAS_ITL_PORT_NO,portType) < 0)
                {
                    mgc_delete_MG(sapIndex, pMgInfo->id); 
			        return MGC_RESULT_FAILURE ;
                }       
			}			
        }

	    return pMgInfo->id;
	}

    pMgInfo = mgc_mg_info_get_unused_mg();
    if(pMgInfo == NULL)
        return MGC_RESULT_NO_RES;

    if(mgc_mg_info_assign_attr(pMgInfo ,pMgAttr) == FALSE)
    {
        mgc_mg_info_init(pMgInfo, pMgInfo->id);
        return MGC_RESULT_FAILURE ;
    }

    mgc_ctl_mg_add_one();


    if(pMgAttr->mgType == MGC_MG_TYPE_ANN)
    {
		pPhyPort = mgc_phy_port_get_unused_phy();
		/*only add one phyPort for rtp_proxy*/
        MGC_DEBUG("add phyPort[%d] to aas" , pPhyPort->id);
        if(mgc_add_port(sapIndex, pMgInfo->id, MGC_AAS_ITL_PORT_NO,portType) < 0)
        {
            mgc_delete_MG(sapIndex, pMgInfo->id); 
			return MGC_RESULT_FAILURE ;
        }   		
    }

    if(pMgAttr->mgType == MGC_MG_TYPE_TANDEM)
    {
        if(mgc_tandem_info_add_tandem_res(sapIndex , pMgInfo->id) == FALSE)
        {
            mgc_delete_MG(sapIndex, pMgInfo->id); 
			return MGC_RESULT_FAILURE ;
        }   			

        if(mgc_sur_info_add_survillance_res(sapIndex, pMgInfo->id) == FALSE)
        {
            MGC_ERROR("add survilliance res failed!");			
            mgc_delete_MG(sapIndex, pMgInfo->id); 
		    return MGC_RESULT_FAILURE ;
        }				
    }
	
	MGC_DEBUG("create mg[%d] %s success" , pMgInfo->id , pMgInfo->mgAttr.domain);
    return pMgInfo->id;
}

/***************************************************************************
 * mgc_delete_MG
 * ------------------------------------------------------------------------
 * General: inferace for up-layer delete mg
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  sapIndex - the id of the MGC_SAP object which is provided by mgc_bind 
 *            mgNo - the id of which MG_INFO need to be removed
 ***************************************************************************/
int mgc_delete_MG(BYTE sapIndex, WORD mgNo)
{
    MG_INFO *pMgInfo = NULL;
    MGC_SAP *pMgcSap = NULL;
	
    pMgInfo = mgc_mg_info_get_index_mg(mgNo);
	pMgcSap = mgc_sap_get_index_sap(sapIndex);

    if((pMgInfo == NULL)||(pMgcSap) == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;
    
    if(pMgInfo->created == FALSE)
    {
        MGC_WARN("mg[%d] is not created, could not delete" , pMgInfo->id);
        return MGC_RESULT_INPUT_ILLEGAL;	    
    }
	
    switch(pMgInfo->mgAttr.ctrlType)
    {
        case MGC_MG_CTRL_TYPE_8ECP:
			mgc_8ecp_delete(pMgInfo);
		    break;	
	    case MGC_MG_CTRL_TYPE_MGCP:            
			break;
        default:
			MGC_WARN("mg[%d] unsupport ctrlType %d" , pMgInfo->id , pMgInfo->mgAttr.ctrlType);			
			break;
	}

	mgc_mg_info_clear(pMgInfo);
	MGC_DEBUG("remove mg[%d] success" , pMgInfo->id);
    mgc_ctl_mg_remove_one();	
	return MGC_RESULT_OK;
}


/***************************************************************************
 * mgc_modify_MG
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to modify mg
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  sapIndex - the id of the MGC_SAP object which is provided by mgc_bind 
 *            mgNo - the id of which MG_INFO need to be modified
 *            pMgAttr - pointer of the new mg attribute
 ***************************************************************************/
int mgc_modify_MG(BYTE sapIndex, WORD mgNo, MG_ATTR *pMgAttr)
{
    MG_INFO *pMgInfo = NULL;
    MGC_SAP *pMgcSap = NULL;
	
    pMgInfo = mgc_mg_info_get_index_mg(mgNo);
	pMgcSap = mgc_sap_get_index_sap(sapIndex);

    if((pMgInfo == NULL)||(pMgcSap) == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;
    
    if(pMgInfo->created == FALSE)
    {
        MGC_ERROR("mg[%d] is not created, could not modify" , pMgInfo->id);
        return MGC_RESULT_INPUT_ILLEGAL;	    
    }

    if(pMgInfo->mgAttr.ctrlType != pMgAttr->ctrlType)
    {
        MGC_ERROR("do not support different ctltype modify");
        return MGC_RESULT_INPUT_ILLEGAL;
    }

    switch(pMgAttr->ctrlType)
    {
	    case MGC_MG_CTRL_TYPE_8ECP:
            mgc_8ecp_create(pMgInfo, pMgAttr);
		    break;	
	    case MGC_MG_CTRL_TYPE_MGCP:
            mgc_mg_info_assign_attr(pMgInfo , pMgAttr);
		    break;
	    default:
		    MGC_WARN("mg[%d] unsupport ctrlType %d" , pMgInfo->id , pMgInfo->mgAttr.ctrlType);
			return MGC_RESULT_INPUT_ILLEGAL;
    }

	MGC_DEBUG("modify mg[%d] %s success" , pMgInfo->id , pMgInfo->mgAttr.domain);
    return MGC_RESULT_OK;
}


static char *mgc_print_user_type(MGC_USER_TYPE userType)
{
    switch(userType)
    {
        case MGC_USER_TYPE_MG:
			 return "MGC_USER_TYPE_MG";
		case MGC_USER_TYPE_MGC:
			 return "MGC_USER_TYPE_MGC";
		default:
			 return "MGC_USER_TYPE_UNDKNOWN";
    }
	return "MGC_USER_TYPE_UNDKNOWN";	
}


/***************************************************************************
 * mgc_add_port
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to add phyPort 
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  sapIndex - the id of the MGC_SAP object which is provided by mgc_bind 
 *            mgNo - the id of which MG_INFO need to attach to
 *            portNo - the id of the phyPort in the up-layer, this is used for up-layer find phyPort in the MGC
 *            portType - the phyPort type to be created
 ***************************************************************************/
int mgc_add_port(BYTE sapIndex, WORD mgNo, BYTE portNo, MGC_PHY_PORT_TYPE portType)
{
    MG_INFO *pMgInfo = NULL;
    MGC_SAP *pMgcSap = NULL;
    PHY_PORT_INFO *pPhyPort = NULL;
	
    pMgInfo = mgc_mg_info_get_index_mg(mgNo);
	pMgcSap = mgc_sap_get_index_sap(sapIndex);

    if((pMgInfo == NULL)||(pMgcSap) == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->created == FALSE)
    {
	    MGC_ERROR("mg[%d] is not created, could not add port" , pMgInfo->id);
	    return MGC_RESULT_INPUT_ILLEGAL;		
    }

    if((ITL_OPERA_PORT_NO == portNo)&&(sapIndex != mgc_internal_get_sap_index()))
    {
        MGC_ERROR("portNo %d is internal used! " , portNo);
        return MGC_RESULT_INPUT_ILLEGAL;
    }

    if(mgc_mg_info_is_port_already_exist(pMgInfo , portNo , pMgcSap) == TRUE)
	    return MGC_RESULT_OK;	

    pPhyPort = mgc_phy_port_get_unused_phy();
    if(pPhyPort == NULL)
        return MGC_RESULT_NO_RES;		

    pPhyPort->portType = portType;
	pPhyPort->portNo = portNo;
	pPhyPort->pMgcSap = pMgcSap;
	pPhyPort->pMgInfo = pMgInfo;
	
    switch(pMgInfo->mgAttr.ctrlType)
    {
        case MGC_MG_CTRL_TYPE_8ECP:
			/*do nothing ?*/
			mgc_phy_port_set_chnl_num(pPhyPort , MGC_PHY_PORT_TYPE_E1);
		    return MGC_RESULT_8ECP_OK;	
		case MGC_MG_CTRL_TYPE_MGCP:
            mgc_phy_port_set_chnl_num(pPhyPort , pPhyPort->portType);
			break;
		default:
			mgc_phy_port_clear(pPhyPort);
			MGC_ERROR("mgcMgInfo[%d] unsupport ctrl type %d" , pMgInfo->id , pMgInfo->mgAttr.ctrlType);
			return MGC_RESULT_INPUT_ILLEGAL;
    }
	
    if(mgc_phy_port_attach_chnl(pPhyPort) == FALSE)
    {
        mgc_phy_port_clear(pPhyPort);
		return MGC_RESULT_FAILURE;
    }

    if(mgc_mg_info_attach_phy_port(pMgInfo , pPhyPort , pMgcSap)== FALSE)
    {
        mgc_phy_port_clear(pPhyPort);
		return MGC_RESULT_FAILURE;    
    }

	if(sapIndex != mgc_internal_get_sap_index())
	{
        MGC_INFO("phyPort[%d] is add to mgInfo[%d] %s , as portNo %d, userType %s" 
		       , pPhyPort->id , pMgInfo->id , pMgInfo->mgAttr.domain, pPhyPort->portNo , mgc_print_user_type(pPhyPort->pMgcSap->usrType));	
	}
	return MGC_RESULT_OK;
}


/***************************************************************************
 * mgc_delete_port
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to delete phyPort 
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  sapIndex - the id of the MGC_SAP object which is provided by mgc_bind 
 *            mgNo - the id of which MG_INFO need to attach to
 *            portNo - the id of the phyPort in the up-layer, this is used for up-layer find phyPort in the MGC
 ***************************************************************************/
int mgc_delete_port(BYTE sapIndex, WORD mgNo, BYTE portNo)
{
    MG_INFO *pMgInfo = NULL;
    MGC_SAP *pMgcSap = NULL;
    PHY_PORT_INFO *pPhyPort = NULL;
	
    pMgInfo = mgc_mg_info_get_index_mg(mgNo);
	pMgcSap = mgc_sap_get_index_sap(sapIndex);

    if((pMgInfo == NULL)||(pMgcSap) == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;
	
    pPhyPort = mgc_phy_port_find_port_of_mg(pMgInfo , portNo);
    if(pPhyPort == NULL)
    {
        if(sapIndex != mgc_internal_get_sap_index()) 
        {
        MGC_ERROR("mg[%d] %s do not have port[%d]" , pMgInfo->id , pMgInfo->mgAttr.domain , portNo);
        }
        return MGC_RESULT_INPUT_ILLEGAL;
    }

    if(pPhyPort->pMgcSap != pMgcSap)
    {
        MGC_ERROR("Port[%d] is not belong to mgcSap[%d] %s" , pPhyPort->portNo, pMgcSap->id , pMgcSap->usrName);
		return MGC_RESULT_INPUT_ILLEGAL;
    }


	if(sapIndex != mgc_internal_get_sap_index())
	{
        MGC_INFO("phyPort[%d] is remove from mgInfo[%d] %s , as portNo %d, userType %s" 
		       , pPhyPort->id , pMgInfo->id , pMgInfo->mgAttr.domain, pPhyPort->portNo , mgc_print_user_type(pPhyPort->pMgcSap->usrType));	
	}

	mgc_mg_info_dettach_phy_port(pMgInfo , pPhyPort);
    mgc_phy_port_clear(pPhyPort);    
	return MGC_RESULT_OK;
}


/***************************************************************************
 * mgc_auep_chnl
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to send auep 
 * Return Value :  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  usrPort - up-layer parameter to identify
 *            chnl - the chnl need to send auep
 ***************************************************************************/
int mgc_auep_chnl(WORD usrPort, CHNL chnl)
{
    MG_INFO *pMgInfo = NULL;
    CHNL_INFO *pChnlInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;

    pMgInfo = mgc_mg_info_get_index_mg(chnl.mgNo);
    pChnlInfo = mgc_chnl_info_get_chnl(chnl);
    if((pMgInfo == NULL)||(pChnlInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.ctrlType == MGC_MG_CTRL_TYPE_8ECP)
	    return MGC_RESULT_8ECP_OK;	

    pConnect = mgc_chnl_info_assign_connect(pChnlInfo, chnl.connectNo);
	pPortInfo = mgc_port_info_get_unused_port();
    if((pPortInfo == NULL)||(pConnect == NULL))
    {
		return MGC_RESULT_NO_RES;		
    }
  
    mgc_connect_add_auep(pConnect , pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_AUEP);
    pPortInfo->usrPort = usrPort;

	return MGC_RESULT_OK;	
}



/***************************************************************************
 * mgc_crcx_chnl
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to send crcx, on the specific chnl
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  usrPort - up-layer parameter to identify
 *            chnl - the chnl need to send crcx
 ***************************************************************************/
int mgc_crcx_chnl(WORD usrPort, CHNL chnl)
{
    MG_INFO *pMgInfo = NULL;
    CHNL_INFO *pChnlInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
    CONNECT_INFO *pConnectTmp = NULL;
    PORT_INFO *pPortInfo = NULL;

    MGC_DEBUG("func %s " , __FUNCTION__);
    pMgInfo = mgc_mg_info_get_index_mg(chnl.mgNo);
	pChnlInfo = mgc_chnl_info_get_chnl(chnl);
    pConnect = mgc_chnl_info_assign_connect(pChnlInfo, chnl.connectNo);
	pPortInfo = mgc_port_info_get_unused_port();	
    if((pMgInfo == NULL)||(pChnlInfo == NULL)||(pPortInfo == NULL)||(pConnect == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.ctrlType == MGC_MG_CTRL_TYPE_8ECP)
        return MGC_RESULT_8ECP_OK;	

    if(pMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP)
        return MGC_RESULT_INPUT_ILLEGAL;

    MGC_DEBUG("mg[%d]port[%d]chnl[%d]conNo[%d]  ==> conn[%d]" , chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo , pConnect->id);	

    if(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_IDLE)
    {
        MGC_WARN("conn[%d] should be idle" , pConnect->id);
	pConnectTmp = mgc_connect_dup_attr(pConnect);
	mgc_connect_add_dlcx(pConnectTmp, pPortInfo);
	mgc_connect_set_status(pConnect,MGC_CONNECT_STATUS_IDLE);
	mgc_connect_codec_list_init(&pConnect->codecList);
	memset(&pConnect->mediaAttr , 0 , sizeof(MEDIA_ATTR));
    }
	
    mgc_connect_add_crcx(pConnect , pPortInfo);    
    mgc_connect_add_nop(pConnect,pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
	mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_CRCX);
	pPortInfo->usrPort = usrPort;
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo, 
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));	
    return MGC_RESULT_OK;	
}




int mgc_rqnt_chnl(WORD usrPort, CHNL chnl, PKG_EVENT *pPkgEvent, PKG_SIGNAL *pPkgSig)
{
    CHNL_INFO *pChnlInfo = NULL;
	MG_INFO *pMgInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;

    pMgInfo = mgc_mg_info_get_index_mg(chnl.mgNo);
    pChnlInfo = mgc_chnl_info_get_chnl(chnl);
	pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo,chnl.connectNo);
	pPortInfo = mgc_port_info_get_unused_port();
    MGC_DEBUG("func %s " , __FUNCTION__);

    if((pChnlInfo == NULL)||(pConnect== NULL)||(pPortInfo == NULL)||(pMgInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.ctrlType == MGC_MG_CTRL_TYPE_8ECP)
	    return MGC_RESULT_8ECP_OK;	

    mgc_connect_add_rqnt(pConnect, pPkgEvent, pPkgSig, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
	mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_RQNT);
	pPortInfo->usrPort = usrPort;
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo, 
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));		
    return MGC_RESULT_OK;		
}



int mgc_mdcx_chnl(WORD usrPort, CHNL chnl, MEDIA_PARA *pMediaPara)
{
    MG_INFO *pMgInfo = NULL;
    CHNL_INFO *pChnlInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;
    MGC_DEBUG("func %s " , __FUNCTION__);

	pPortInfo = mgc_port_info_get_unused_port();	
    pMgInfo = mgc_mg_info_get_index_mg(chnl.mgNo);
    pChnlInfo = mgc_chnl_info_get_chnl(chnl);
    if((pMgInfo == NULL)||(pChnlInfo == NULL)||(pPortInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP)
	    return MGC_RESULT_INPUT_ILLEGAL;

    pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo, chnl.connectNo);
    if(pConnect == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;
	

    if(pMediaPara)
    {
        if((pMediaPara->flag & MGC_MEDIA_PARA_FLAG_EC) == MGC_MEDIA_PARA_FLAG_EC)
        {
            pConnect->mediaAttr.ecDisable = pMediaPara->ecDisable;
        }

		if((pMediaPara->flag & MGC_MEDIA_PARA_FLAG_SS) == MGC_MEDIA_PARA_FLAG_SS)
		{
		    pConnect->mediaAttr.ssDisable = pMediaPara->ssDisable;
		}

		if((pMediaPara->flag & MGC_MEDIA_PARA_FLAG_CM) == MGC_MEDIA_PARA_FLAG_CM)
		{
		    pConnect->mediaAttr.conMode = mgc_mgcp_convert_to_mgc_mode(pMediaPara->conMode);
		}

		if((pMediaPara->flag & MGC_MEDIA_PARA_FLAG_PT) == MGC_MEDIA_PARA_FLAG_PT)
		{
		    pConnect->mediaAttr.ptime = pMediaPara->ptime;
		}

		if((pMediaPara->flag & MGC_MEDIA_PARA_FLAG_VT) == MGC_MEDIA_PARA_FLAG_VT)
		{
		    mgc_mgcp_match_codec_list(&pConnect->codecList , &pMediaPara->vocoderType , &pConnect->codecList);
		}
    }

	mgc_tandem_info_mdcx(pConnect, pPortInfo);
    mgc_connect_add_nop(pConnect, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_MDCX);
    pPortInfo->usrPort = usrPort;
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo, 
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));		
	return MGC_RESULT_OK;
}




/***************************************************************************
 * mgc_connect_chnl
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to connect orgChnl to the destChnl
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  usrPort - up-layer parameter to identify
 *            orgChnl - the chnl need to send connect info
 *            destChnl - the peer chnl to be connected
 *            flag - reserved 
 *-------------------------------------------------------------------------
 *Note: if connection of the chnl is not created send crcx first, then send mdcx
 ***************************************************************************/
int mgc_connect_chnl(WORD usrPort, CHNL orgChnl, CHNL destChnl, BYTE flag)
{
    MG_INFO *pOrgMgInfo = NULL;
	MG_INFO *pDestMgInfo = NULL;
    CHNL_INFO *pOrgChnlInfo = NULL;
    CHNL_INFO *pDestChnlInfo = NULL;	
    CONNECT_INFO *pOrgConnect = NULL;
	CONNECT_INFO *pDestConnect = NULL;		
	CONNECT_INFO *pPeerConnect = NULL;	
	CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;

    pOrgMgInfo = mgc_mg_info_get_index_mg(orgChnl.mgNo);
	pOrgChnlInfo = mgc_chnl_info_get_chnl(orgChnl);
    pDestMgInfo = mgc_mg_info_get_index_mg(destChnl.mgNo);
	pDestChnlInfo = mgc_chnl_info_get_chnl(destChnl);

	if((pOrgMgInfo == NULL)||(pOrgChnlInfo == NULL)||(pDestMgInfo == NULL) || (pDestChnlInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

    if((pOrgMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP)||(pDestMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP) )
        return -MGC_RESULT_INPUT_ILLEGAL;

    if(pOrgMgInfo->mgAttr.ctrlType == MGC_MG_CTRL_TYPE_8ECP)
    {
       mgc_8ecp_connect_chnl(orgChnl, destChnl, flag);
       return MGC_RESULT_OK ;
    }
	
    MGC_DEBUG("func %s " , __FUNCTION__);
    pOrgConnect = mgc_chnl_info_assign_connect(pOrgChnlInfo,orgChnl.connectNo);
    pDestConnect= mgc_chnl_info_assign_connect(pDestChnlInfo, destChnl.connectNo);
    pPortInfo = mgc_port_info_get_unused_port();
	if((pPortInfo == NULL)||(pOrgConnect == NULL)||(pDestConnect == NULL))
	{
	    return MGC_RESULT_NO_RES;
	}

    MGC_DEBUG("Org mg[%d]port[%d]chnl[%d]conNo[%d]  ==> conn[%d]" ,
		orgChnl.mgNo, orgChnl.portNo, orgChnl.chlNo,orgChnl.connectNo , pOrgConnect->id);	

    MGC_DEBUG("Dest mg[%d]port[%d]chnl[%d]conNo[%d]  ==> conn[%d]" ,
		destChnl.mgNo, destChnl.portNo, destChnl.chlNo,destChnl.connectNo , pDestConnect->id);	

    pConnect = pOrgConnect;
    pPeerConnect = pDestConnect;
/*
    if((pConnect->pOperStep != NULL)&&(pConnect->pOperStep->stepInfo.delay != 0))
    {
        pConnect->pOperStep->stepInfo.delay = 0;
		MGC_DEBUG("conn[%d] set clear delay" , pConnect->id);
    }

    if(pPeerConnect->pOperStep != NULL)
    {
        pPeerConnect->pOperStep->stepInfo.delay = 0;
		MGC_DEBUG("conn[%d] set clear delay" , pPeerConnect->id);    
    }
 */
    if(pConnect->pOperStep != NULL)
	    mgc_port_info_mv_step_into_new_port(pPortInfo, pConnect->pOperStep);

    if(pPeerConnect->pOperStep != NULL)
	    mgc_port_info_mv_step_into_new_port(pPortInfo, pPeerConnect->pOperStep);
      
    //if any connection is a target, create the tandem if neccessary	
    mgc_connect_add_crcx(pConnect,pPortInfo);
	
	mgc_connect_add_crcx(pPeerConnect,pPortInfo);    

	//if any connecion is aor, stop related tandem and dettach from the tandem
    if(mgc_tandem_info_get_conn_pos(pPeerConnect->pTandem, pPeerConnect) == MGC_TANDEM_CONN_POS_AOR)
    {
        if((mgc_tandem_info_get_conn_pos(pConnect->pTandem , pConnect) == MGC_TANDEM_CONN_POS_TAR)
			&&(pConnect->pTandem == pPeerConnect->pTandem))
        {
            MGC_DEBUG("PeerConn[%d] and Conn[%d] is in tandem[%d]" , pPeerConnect->id , pConnect->id , pConnect->pTandem->id);
        }
		else
		{
			mgc_tandem_info_dettach_aor_related_tandem(pConnect , pPeerConnect, pPortInfo);
		}
    }

    if(mgc_tandem_info_get_conn_pos(pConnect->pTandem, pConnect) == MGC_TANDEM_CONN_POS_AOR)
    {
        if((mgc_tandem_info_get_conn_pos(pPeerConnect->pTandem , pPeerConnect) == MGC_TANDEM_CONN_POS_TAR)
			&&(pPeerConnect->pTandem == pConnect->pTandem))
		{
            MGC_DEBUG("Conn[%d] and PeerConn[%d] is in tandem[%d]" , pConnect->id , pPeerConnect->id , pConnect->pTandem->id);		
		}
		else
		{
		    mgc_tandem_info_dettach_aor_related_tandem(pPeerConnect , pConnect, pPortInfo);
		}
    }    	

    //connect to peer connection
    if(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATED)
    {
        mgc_tandem_info_connect(pConnect,pPeerConnect, MGC_CON_MODE_OWN, pPortInfo);    
    }

    mgc_tandem_info_connect(pPeerConnect, pConnect,MGC_CON_MODE_SENDRECV,pPortInfo);

    if((pOrgMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)&&(pDestMgInfo->mgAttr.mgType != MGC_MG_TYPE_INTERNAL))	
        mgc_connect_add_nop(pPeerConnect, pPortInfo);        
	
    if((flag & MGCP_PARA_FLAG_TFO) == MGCP_PARA_FLAG_TFO)
    {
        pDestConnect->flag |= MGCP_PARA_FLAG_TFO;
		pOrgConnect->flag |= MGCP_PARA_FLAG_TFO;
    }

    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_CONNECT_CHNL);
    pPortInfo->usrPort = usrPort;

    memset(&pOrgConnect->operRec , 0 , sizeof(OPER_REC));
	pOrgConnect->operRec.operaId = MGC_OPER_ID_CONNECT_CHNL;	
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] and mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     orgChnl.mgNo,orgChnl.portNo,orgChnl.chlNo,orgChnl.connectNo, 
		     destChnl.mgNo,destChnl.portNo,destChnl.chlNo,destChnl.connectNo, 		     
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));		
	return MGC_RESULT_OK;         	
}




/***************************************************************************
 * mgc_dlcx_chnl
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to send dlcx to the specific chnl
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  usrPort - up-layer parameter to identify
 *            chnl - the chnl need to send dlcx
 ***************************************************************************/
int mgc_dlcx_chnl(WORD usrPort, CHNL chnl)
{
    MG_INFO *pMgInfo = NULL;
    CHNL_INFO *pChnlInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;	

    MGC_DEBUG("func %s " , __FUNCTION__);
    pMgInfo = mgc_mg_info_get_index_mg(chnl.mgNo);
	pChnlInfo = mgc_chnl_info_get_chnl(chnl);	
	pPortInfo = mgc_port_info_get_unused_port();
    if((pMgInfo == NULL)||(pChnlInfo == NULL)||(pPortInfo == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.ctrlType == MGC_MG_CTRL_TYPE_8ECP)
    {    
		mgc_8ecp_dlcx_chnl(chnl);
        return MGC_RESULT_OK;
    }	
    
    pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo, chnl.connectNo);
	if(pConnect == NULL)
	{
	    MGC_ERROR("lost connect in dlcx");
	    return MGC_RESULT_INPUT_ILLEGAL;
	}

/*
    if((pConnect->pOperStep != NULL)&&(pConnect->pOperStep->stepInfo.delay != 0))
    {
        pConnect->pOperStep->stepInfo.delay = 0;
		MGC_DEBUG("conn[%d] set clear delay" , pConnect->id);
    }
*/
    if(pConnect->pOperStep != NULL)
	    mgc_port_info_mv_step_into_new_port(pPortInfo, pConnect->pOperStep);

	
    MGC_DEBUG("mg[%d]port[%d]chnl[%d]conNo[%d]  ==> conn[%d]" , chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo , pConnect->id);
    if(mgc_tandem_info_get_conn_pos(pConnect->pTandem, pConnect) == MGC_TANDEM_CONN_POS_AOR)	
	    mgc_tandem_info_remove_connection_from_tandem(pConnect, pPortInfo);
	
    mgc_connect_add_dlcx(pConnect, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_DLCX);
    pPortInfo->usrPort = usrPort;
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo, 
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));		
    return MGC_RESULT_OK;
}


int mgc_recvonly_chnl(WORD usrPort, CHNL orgChnl, CHNL destChnl)
{
    MG_INFO *pOrgMgInfo = NULL;
	MG_INFO *pDestMgInfo = NULL;
    CHNL_INFO *pOrgChnlInfo = NULL;
    CHNL_INFO *pDestChnlInfo = NULL;	
    CONNECT_INFO *pOrgConnect = NULL;
	CONNECT_INFO *pDestConnect = NULL;		
	CONNECT_INFO *pPeerConnect = NULL;
	CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;

    MGC_DEBUG("func %s " , __FUNCTION__);
    pOrgMgInfo = mgc_mg_info_get_index_mg(orgChnl.mgNo);
	pOrgChnlInfo = mgc_chnl_info_get_chnl(orgChnl);
    pDestMgInfo = mgc_mg_info_get_index_mg(destChnl.mgNo);
	pDestChnlInfo = mgc_chnl_info_get_chnl(destChnl);

	if((pOrgMgInfo == NULL)||(pOrgChnlInfo == NULL)||(pDestMgInfo == NULL) || (pDestChnlInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;
    if((pOrgMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP)||(pDestMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP))
        return MGC_RESULT_INPUT_ILLEGAL;
	
    pOrgConnect = mgc_connect_find_connect_of_chnl(pOrgChnlInfo,orgChnl.connectNo);
    pDestConnect= mgc_connect_find_connect_of_chnl(pDestChnlInfo, destChnl.connectNo);
    pPortInfo = mgc_port_info_get_unused_port();
	if((pPortInfo == NULL)||(pOrgConnect == NULL)||(pDestConnect == NULL))
	    return MGC_RESULT_NO_RES;

    pConnect = pOrgConnect;
    pPeerConnect = pDestConnect;	

	//if any connecion is aor, stop related tandem and dettach from the tandem
	mgc_tandem_info_dettach_aor_related_tandem(pConnect , pPeerConnect, pPortInfo);
	mgc_tandem_info_connect(pConnect, pPeerConnect,MGC_CON_MODE_RECVONLY, pPortInfo);
    memset(&pOrgConnect->operRec , 0 , sizeof(OPER_REC));
	pOrgConnect->operRec.operaId = MGC_OPER_ID_MDCX;
    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_MDCX);
    pPortInfo->usrPort = usrPort;
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] and mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     orgChnl.mgNo,orgChnl.portNo,orgChnl.chlNo,orgChnl.connectNo, 
		     destChnl.mgNo,destChnl.portNo,destChnl.chlNo,destChnl.connectNo, 		     
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));				
	return MGC_RESULT_OK;         	
}



/***************************************************************************
 * mgc_connect_dtmf
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to send dtmf to the specific chnl
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  usrPort - up-layer parameter to identify
 *            chnl - the chnl need to send dtmf
 *            dtmfNo - the dtmf  need to be sent
 ***************************************************************************/
int mgc_connect_dtmf(WORD usrPort, CHNL chnl,CHNL dstChnl, BYTE dtmfNo)
{
    CHNL_INFO *pChnlInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
    MG_INFO *pMgInfo = NULL;
    PORT_INFO *pPortInfo = NULL;

    MGC_DEBUG("func %s " , __FUNCTION__);
    pMgInfo = mgc_mg_info_get_index_mg(chnl.mgNo);
	pChnlInfo = mgc_chnl_info_get_chnl(chnl);	
	pPortInfo = mgc_port_info_get_unused_port();
    if((pMgInfo == NULL)||(pChnlInfo == NULL)||(pPortInfo == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.ctrlType == MGC_MG_CTRL_TYPE_8ECP)
    {       
	    mgc_8ecp_connect_dtmf(chnl, dstChnl, dtmfNo);       
        return MGC_RESULT_OK;
    }	

    pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo, chnl.connectNo);
	if(pConnect == NULL)
	{
	    MGC_WARN("lost connect in dtmf");
	    return MGC_RESULT_INPUT_ILLEGAL;
	}

    mgc_connect_set_dtmf(pConnect, dtmfNo);
    mgc_connect_add_rqnt(pConnect, NULL , &pConnect->mediaAttr.pkgSignal,pPortInfo);   
    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_CONNECT_DTMF);
    pPortInfo->usrPort = usrPort;	
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] and mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo, 
		     dstChnl.mgNo,dstChnl.portNo,dstChnl.chlNo,dstChnl.connectNo, 		     
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));			
    return MGC_RESULT_OK;
}


/***************************************************************************
 * mgc_connect_AAS
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to make the specific orgChnl to connect to specific toneNo chnl on the AAS
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  usrPort - up-layer parameter to identify
 *            orgChnl - the chnl need to send tone
 *            destChnl - the peer endpoint of the orgChnl
 *            toneNo - the tone identify on the AAS
 *            duration - the time need to be played
 *            times - reserved
 ***************************************************************************/
int mgc_connect_AAS(WORD usrPort, CHNL orgChnl, CHNL destChnl, BYTE toneNo, WORD duration, WORD times)
{
    MG_INFO *pOrgMgInfo = NULL;
	MG_INFO *pDestMgInfo = NULL;
	MG_INFO *pAasMgInfo = NULL;
    CHNL_INFO *pOrgChnlInfo = NULL;
    CHNL_INFO *pDestChnlInfo = NULL;	
    CONNECT_INFO *pOrgConnect = NULL;
	CONNECT_INFO *pDestConnect = NULL;	
	CONNECT_INFO *pAasConnect = NULL;
	CONNECT_INFO *pPeerConnect = NULL;	
	CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;	
    PORT_INFO *pPortInfoTmp = NULL;	
	
	DWORD delay;
	BYTE tone;

    MGC_DEBUG("func %s  toneNo[%d] times[%d] duration[%d]" , __FUNCTION__ , toneNo , times , duration);
    pOrgMgInfo = mgc_mg_info_get_index_mg(orgChnl.mgNo);
	pOrgChnlInfo = mgc_chnl_info_get_chnl(orgChnl);
    pDestMgInfo = mgc_mg_info_get_index_mg(destChnl.mgNo);
	pDestChnlInfo = mgc_chnl_info_get_chnl(destChnl);
	tone = toneNo;
	
	if((pOrgMgInfo == NULL)||(pOrgChnlInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

    if(pOrgMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP)
        return MGC_RESULT_INPUT_ILLEGAL;
	
    toneNo = times * 10 + (toneNo - 7);
    pAasConnect = mgc_mg_info_assign_aas_tone_connection(toneNo);
    pOrgConnect = mgc_connect_find_connect_of_chnl(pOrgChnlInfo,orgChnl.connectNo);
    pDestConnect= mgc_connect_find_connect_of_chnl(pDestChnlInfo, destChnl.connectNo);
    pPortInfoTmp = mgc_port_info_get_unused_port();
	if((pPortInfoTmp == NULL)||(pOrgConnect == NULL)||(pAasConnect == NULL))
	    return MGC_RESULT_NO_RES;	    

    MGC_DEBUG("Org mg[%d]port[%d]chnl[%d]conNo[%d]  ==> conn[%d]" ,
		orgChnl.mgNo, orgChnl.portNo, orgChnl.chlNo,orgChnl.connectNo , pOrgConnect->id);	

    pAasMgInfo = mgc_connect_get_own_mg_info(pAasConnect);
    if((mgc_connect_get_status(pAasConnect) != MGC_CONNECT_STATUS_IDLE)||(pAasMgInfo == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;

    if((mgc_connect_get_status(pOrgConnect) == MGC_CONNECT_STATUS_IDLE)||
		(mgc_connect_get_status(pDestConnect) == MGC_CONNECT_STATUS_IDLE))
    {
        MGC_ERROR("conn[%d] and conn[%d] is not created" , pOrgConnect->id , pDestConnect->id);
        return MGC_RESULT_INPUT_ILLEGAL;
    }

    pConnect = pOrgConnect;
	pPeerConnect = pDestConnect;

    //stop stream sending
    if(mgc_connect_get_status(pPeerConnect) == MGC_CONNECT_STATUS_CREATED)
    {
        if(mgc_tandem_info_get_conn_pos(pPeerConnect->pTandem, pPeerConnect) != MGC_TANDEM_CONN_POS_UNDEF)
        {
             mgc_tandem_info_connect(pPeerConnect, pConnect,MGC_CON_MODE_RECVONLY, pPortInfoTmp);    
        }
	    else
	    {
	         mgc_connect_add_mdcx(pPeerConnect, pConnect, MGC_CON_MODE_RECVONLY, pPortInfoTmp);
	    }    
	    mgc_connect_add_nop(pPeerConnect, pPortInfoTmp);
        mgc_port_info_set_step_to_start(pPortInfoTmp);
        mgc_port_info_set_oper_id(pPortInfoTmp , MGC_OPER_ID_MDCX);
        pPortInfoTmp->usrPort = usrPort;			        
    }
	
    pPortInfo = mgc_port_info_get_unused_port();
    if(pPortInfo == NULL)
	    return MGC_RESULT_NO_RES;
		
    delay = duration * MGC_MGCF_TIMER_1S;
    if(delay == 0)
	    delay = MGC_MGCF_TIMER_1H;	

    /*copy dest connection sdp and made codec negotiate*/
    pConnect = pAasConnect;
	pPeerConnect = pOrgConnect;
    if(pPeerConnect->pOperStep != NULL)
	    mgc_port_info_mv_step_into_new_port(pPortInfo, pPeerConnect->pOperStep);	
	MGC_DEBUG("conn[%d] send crcx to aas with %ld delay" , pConnect->id , delay);
	mgc_tandem_info_add_crcx_aas(pConnect, pPeerConnect, pPortInfo);	
	mgc_tandem_info_add_mdcx_aas(pPeerConnect, pConnect, pPortInfo);
	mgc_connect_add_nop_with_delay(pPeerConnect, delay , pPortInfo);
	/*remove aas connection*/
	MGC_DEBUG("conn[%d] send dlcx to delete aas" , pConnect->id);
	mgc_connect_add_dlcx(pConnect, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_CONNECT_AAS);
    pPortInfo->usrPort = usrPort;
    pPortInfo->cause = tone;
	
    memset(&pOrgConnect->operRec , 0 , sizeof(OPER_REC));
	pOrgConnect->operRec.operaId = MGC_OPER_ID_CONNECT_AAS;
    pOrgConnect->operRec.duration = duration;
	pOrgConnect->operRec.times = times;
	pOrgConnect->operRec.tone = tone;

    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     orgChnl.mgNo,orgChnl.portNo,orgChnl.chlNo,orgChnl.connectNo, 
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));			
    return MGC_RESULT_OK;    
}



/***************************************************************************
 * mgc_connect_tone
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to make the specific orgChnl to connect to specific toneNo chnl on the AAS
 * Return Value:  if failure return -1,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  usrPort - up-layer parameter to identify
 *            orgChnl - the chnl need to send tone
 *            destChnl - the peer endpoint of the orgChnl
 *            toneNo - the tone identify on the AAS
 *            duration - the time need to be played
 ***************************************************************************/
int mgc_connect_tone(WORD usrPort, CHNL orgChnl, CHNL destChnl, BYTE toneNo, WORD duration)
{
    MG_INFO *pOrgMgInfo = NULL;
	MG_INFO *pDestMgInfo = NULL;
	MG_INFO *pAasMgInfo = NULL;
    CHNL_INFO *pOrgChnlInfo = NULL;
    CHNL_INFO *pDestChnlInfo = NULL;	
    CONNECT_INFO *pOrgConnect = NULL;
	CONNECT_INFO *pDestConnect = NULL;	
	CONNECT_INFO *pAasConnect = NULL;
	CONNECT_INFO *pPeerConnect = NULL;	
	CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;	
    PORT_INFO *pPortInfoTmp = NULL;		
	DWORD delay;
	BYTE tone , toneTmp;

    MGC_DEBUG("func %s " , __FUNCTION__);
    pOrgMgInfo = mgc_mg_info_get_index_mg(orgChnl.mgNo);
	pOrgChnlInfo = mgc_chnl_info_get_chnl(orgChnl);
    pDestMgInfo = mgc_mg_info_get_index_mg(destChnl.mgNo);
	pDestChnlInfo = mgc_chnl_info_get_chnl(destChnl);

    MGC_DEBUG("Org mg[%d]port[%d]chnl[%d]conNo[%d]" ,
		orgChnl.mgNo, orgChnl.portNo, orgChnl.chlNo,orgChnl.connectNo);	

    MGC_DEBUG("Dest mg[%d]port[%d]chnl[%d]conNo[%d]" ,
		destChnl.mgNo, destChnl.portNo, destChnl.chlNo,destChnl.connectNo);		
	if((pOrgMgInfo == NULL)||(pOrgChnlInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

    if(pOrgMgInfo->mgAttr.ctrlType == MGC_MG_CTRL_TYPE_8ECP)
    {        
		mgc_8ecp_connect_tone(orgChnl, destChnl, toneNo , duration);
        return MGC_RESULT_OK;
    }

    if((pOrgMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP) )
        return MGC_RESULT_INPUT_ILLEGAL;
	
    tone = toneNo;
	toneTmp = toneNo-7;
    pAasConnect = mgc_mg_info_assign_aas_tone_connection(toneTmp);	
    pOrgConnect = mgc_connect_find_connect_of_chnl(pOrgChnlInfo,orgChnl.connectNo);
    pDestConnect= mgc_connect_find_connect_of_chnl(pDestChnlInfo, destChnl.connectNo);
    pPortInfoTmp = mgc_port_info_get_unused_port();
	if((pPortInfoTmp == NULL)||(pOrgConnect == NULL)||(pAasConnect == NULL))
	    return MGC_RESULT_NO_RES;

    MGC_DEBUG("Org mg[%d]port[%d]chnl[%d]conNo[%d]  ==> conn[%d]" ,
		orgChnl.mgNo, orgChnl.portNo, orgChnl.chlNo,orgChnl.connectNo , pOrgConnect->id);	

    pAasMgInfo = mgc_connect_get_own_mg_info(pAasConnect);
    if((mgc_connect_get_status(pAasConnect) != MGC_CONNECT_STATUS_IDLE)||(pAasMgInfo == NULL))
         return MGC_RESULT_INPUT_ILLEGAL;
	
    pConnect = pOrgConnect;
	pPeerConnect = pDestConnect;

    // stop dest send stream to org
    if(mgc_connect_get_status(pPeerConnect) == MGC_CONNECT_STATUS_CREATED)
    {
        if(mgc_tandem_info_get_conn_pos(pPeerConnect->pTandem, pPeerConnect) != MGC_TANDEM_CONN_POS_UNDEF)
        {
             mgc_tandem_info_connect(pPeerConnect, pConnect,MGC_CON_MODE_RECVONLY, pPortInfoTmp);    
        }
	    else
	    {
	         mgc_connect_add_mdcx(pPeerConnect, pConnect, MGC_CON_MODE_RECVONLY, pPortInfoTmp);
	    }    
	    mgc_connect_add_nop(pPeerConnect, pPortInfoTmp);
        mgc_port_info_set_step_to_start(pPortInfoTmp);
        mgc_port_info_set_oper_id(pPortInfoTmp , MGC_OPER_ID_MDCX);
        pPortInfoTmp->usrPort = usrPort;			        
    }

    pPortInfo = mgc_port_info_get_unused_port();
    if(pPortInfo == NULL)
	    return MGC_RESULT_NO_RES;

    //if org is not created create first
    if(mgc_connect_get_status(pOrgConnect) == MGC_CONNECT_STATUS_IDLE)
    {
        mgc_connect_add_crcx(pOrgConnect , pPortInfo);    
    }

    if(pOrgConnect->pOperStep != NULL)
	    mgc_port_info_mv_step_into_new_port(pPortInfo, pOrgConnect->pOperStep);

    delay = duration * MGC_MGCF_TIMER_1S;
    if(delay == 0)
	    delay = MGC_MGCF_TIMER_1H;	

    if(pOrgMgInfo->mgAttr.toneCap == 1)
    {        
		mgc_connect_set_tone(pConnect , toneNo);
	    mgc_connect_add_rqnt_with_delay(pConnect, delay, NULL ,&pOrgConnect->mediaAttr.pkgSignal,pPortInfo);
		mgc_connect_clear_tone(pConnect);
		mgc_connect_add_rqnt(pConnect,NULL,&pOrgConnect->mediaAttr.pkgSignal,pPortInfo);
    }
	else
	{	
		pConnect = pAasConnect;
	    pPeerConnect = pOrgConnect;		
		mgc_tandem_info_add_crcx_aas(pConnect, pPeerConnect, pPortInfo);	
		mgc_tandem_info_add_mdcx_aas(pPeerConnect, pConnect, pPortInfo);
		mgc_connect_add_nop_with_delay(pPeerConnect, delay, pPortInfo);
        mgc_connect_add_dlcx(pConnect, pPortInfo);
	}
    mgc_port_info_set_step_to_start(pPortInfo);
	mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_CONNECT_TONE);
	pPortInfo->usrPort = usrPort;	
    memset(&pOrgConnect->operRec , 0 , sizeof(OPER_REC));
	pOrgConnect->operRec.operaId = MGC_OPER_ID_CONNECT_TONE;
    pOrgConnect->operRec.duration = duration;
	pOrgConnect->operRec.tone = tone;	

    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] ==> %s", 
		     __FUNCTION__ , 
		     orgChnl.mgNo,orgChnl.portNo,orgChnl.chlNo,orgChnl.connectNo, 
		     mgc_port_info_print_opera_id(pPortInfo->mgcfOperId));			
    return MGC_RESULT_OK; 
}



/***************************************************************************
 * mgc_query_mg_status
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to query the specific mg status
 * Return Value:  if  mg not created return -1,  
 *                       else return the status of the mg, 1 stand for enable, 0 stand for disable
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  mgNo - the mg  id, return by mgc_create_MG
 ***************************************************************************/
int mgc_query_mg_status(WORD mgNo)
{
    MG_INFO *pMgInfo = NULL;

	pMgInfo = mgc_mg_info_get_index_mg(mgNo);
	if(pMgInfo == NULL)
	   return -1;	
	MGC_INFO("%s mg[%d] %s" , __FUNCTION__ , pMgInfo->id , pMgInfo->enable?"ENABLE":"DISABLE");
	return pMgInfo->enable;
}


/***************************************************************************
 * mgc_query_port_status
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to query the specific port
 * Return Value:  if  port not created return -1,  
 *                       else return the status of the port, 1 stand for enable, 0 stand for disable
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  mgNo - the mg  id, return by mgc_create_MG
 *            portNo - used in the mgc_add_port
 ***************************************************************************/
int mgc_query_port_status(WORD mgNo, BYTE portNo)
{
    MG_INFO *pMgInfo = NULL;
    PHY_PORT_INFO *pPhyPort = NULL;

    pMgInfo = mgc_mg_info_get_index_mg(mgNo);
    if(pMgInfo == NULL)
       return -1;

    pPhyPort = mgc_phy_port_find_port_of_mg(pMgInfo, portNo);
	if(pPhyPort == NULL)
	   return -1;

    return pPhyPort->status;
}


/***************************************************************************
 * mgc_query_channel_status
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to query the specific chnl
 * Return Value:  if  port not created return -1,  
 *                       else return the status of the chnl, 1 stand for enable, 0 stand for disable
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  chnl - the chnl need to query
 ***************************************************************************/
int mgc_query_channel_status(CHNL chnl)
{
    CHNL_INFO *pChnlInfo = NULL;

    pChnlInfo = mgc_chnl_info_get_chnl(chnl);
    if(pChnlInfo == NULL)
	    return -1;	

	return pChnlInfo->status;
}



/***************************************************************************
 * mgc_create_virtual_chnl
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to create virtual chnl 
 * Return Value:  if failure return -1, else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  pChnl - the address of the chnl to be filled
 *            usrPort - reserved
 ***************************************************************************/
int mgc_create_virtual_chnl(WORD usrPort, CHNL *pChnl)
{
    MG_INFO *pMgInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
    CHNL_INFO *pChnlInfo = NULL;
    PHY_PORT_INFO *pPhyPort = NULL;
	PORT_INFO *pPortInfo = NULL;	

	pPortInfo = mgc_port_info_get_unused_port();

    if((pChnl == NULL)||(pPortInfo == NULL))
	    return MGC_RESULT_NO_RES;	

    MGC_DEBUG("func %s " , __FUNCTION__);
    pMgInfo = mgc_mg_info_find_available_mg(MGC_MG_TYPE_INTERNAL);
	if(pMgInfo == NULL)
	    return MGC_RESULT_NO_RES;

    pConnect = mgc_mg_info_assign_idle_connection(pMgInfo);
	if(pConnect == NULL)
	    return MGC_RESULT_NO_RES;	

    pChnlInfo = mgc_connect_get_own_chnl_info(pConnect);
	if(pChnlInfo == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;

    pPhyPort = mgc_connect_get_own_phy_port_info(pConnect);
	if(pPhyPort == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;	

    pChnl->mgNo = pMgInfo->id;
	pChnl->portNo = pPhyPort->portNo;
	pChnl->chlNo = mgc_chnl_info_get_chnl_no_of_phy(pChnlInfo, pPhyPort);
	pChnl->connectNo = mgc_connect_get_connNo_of_chnl_info(pConnect, pChnlInfo);
	mgc_connect_set_status(pConnect,MGC_CONNECT_STATUS_CREATING);
	mgc_connect_add_nop(pConnect, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_CREATE_VIRTUAL_CHNL);
    pPortInfo->usrPort = usrPort;	
	MGC_INFO("create virtual mg[%d]port[%d]chnl[%d]connNo[%d]" , pChnl->mgNo , pChnl->portNo , pChnl->chlNo , pChnl->connectNo);
	return MGC_RESULT_OK;
}


/***************************************************************************
 * mgc_release_virtual_chnl
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to release virtual chnl 
 * Return Value:  if failure return -1, else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  pChnl - the address of the chnl to be filled
 *            usrPort - reserved
 ***************************************************************************/
int mgc_release_virtual_chnl(WORD usrPort, CHNL chnl)
{
    CHNL_INFO *pChnlInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
    PORT_INFO *pPortInfo = NULL;    

    MGC_DEBUG("func %s " , __FUNCTION__);
	pPortInfo = mgc_port_info_get_unused_port();
    pChnlInfo = mgc_chnl_info_get_chnl(chnl);
    if((pChnlInfo ==  NULL)||(pPortInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;	

    pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo, chnl.connectNo);
	if(pConnect == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;	

    if(mgc_tandem_info_get_conn_pos(pConnect->pTandem, pConnect) == MGC_TANDEM_CONN_POS_AOR)
	    mgc_tandem_info_remove_connection_from_tandem(pConnect, pPortInfo);
	
    mgc_connect_add_dlcx(pConnect, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_RELEASE_VIRTUAL_CHNL);
    pPortInfo->usrPort = usrPort;	
    MGC_INFO("release virtual mg[%d]port[%d]chnl[%d]connNo[%d]" , chnl.mgNo , chnl.portNo , chnl.chlNo , chnl.connectNo);	
	return MGC_RESULT_OK;
}


/***************************************************************************
 * mgc_license_ctrl
 * ------------------------------------------------------------------------
 * General: inferace for up-layer to make license control
 * Return Value:  if failure return -1, else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input:  maxMgNum - the maxMgNum could be created
 *            maxChnlNum - the maxChnlNum could be created
 ***************************************************************************/
int mgc_license_ctrl(WORD maxMgNum, WORD maxChnlNum)
{    
    if(mgc_ctl_set_mg_max_num(maxMgNum) != maxMgNum)
	   return MGC_RESULT_FAILURE;
	
    if(mgc_ctl_set_chnl_max_num(maxChnlNum) != maxChnlNum)
	   return MGC_RESULT_FAILURE;
	
	return MGC_RESULT_OK;
}


/***************************************************************************
 * mgc_rsp
 * ------------------------------------------------------------------------
 * General:  interface for up-layer to send rsp msg to the incoming ind
 * Return Value:  if failure return -1, else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	cmd - mgcp ind command
 *            usrPort - up-layer  parameter for identify
 *            port - the mgcPort id , get from ind callback function
 *            retCode - the respond code
 *            pMediaAttr - media info get from up-layer
 ***************************************************************************/
int mgc_rsp(BYTE cmd, WORD usrPort, WORD port, WORD retCode, MEDIA_ATTR *pMediaAttr)
{
    PORT_INFO *pPortInfo = NULL;
	MGCF_OPER_STEP *pCurrentStep = NULL;
	CONNECT_INFO *pConnect = NULL;

	MGC_DEBUG("mgc rsp to mgcPort[%d]" , port);
    pPortInfo = mgc_port_info_find_port_by_id(port);
	if(pPortInfo == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;

    pCurrentStep = pPortInfo->pMgcOperCurrent;
	if(pCurrentStep == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;	
	
    if(pCurrentStep->status != MGCP_OPER_STEP_IND_SENT)
    {
        MGC_WARN("mgcPort[%d]step[%d] error status" , port , pCurrentStep->id);
		return MGC_RESULT_INPUT_ILLEGAL;
    }	

	pConnect = pCurrentStep->pConnect;
	if(pConnect == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;	

    if(pMediaAttr != NULL)
	    memcpy(&(pConnect->mediaAttr) , pMediaAttr, sizeof(MEDIA_ATTR));
	pCurrentStep->llCmd = retCode;
	pCurrentStep->stepInfo.pPeerConn = pConnect;
	pCurrentStep->status = MGCP_OPER_STEP_RESPONSE;	
	return MGC_RESULT_OK;
}



/***************************************************************************
 * mgc_chnl_codec_update
 * ------------------------------------------------------------------------
 * General:  interface for up-layer to update codecList on the specific chnl
 * Return Value:  if failure return -1, else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	chnl -  the chnl to be update
 *           codecList - the codecList from the up-layer
 ***************************************************************************/
int mgc_chnl_codec_update(CHNL chnl , MGC_CODEC_LIST codecList)
{
    int i ,j;
	BYTE codec;
    MG_INFO *pMgInfo = NULL;
    CHNL_INFO *pChnlInfo = NULL;
	CONNECT_INFO *pConnect = NULL;
    MGC_CODEC_LIST codecListResult, codecListMg;
	
    pChnlInfo = mgc_chnl_info_get_chnl(chnl);
    if(pChnlInfo == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;
	
    MGC_DEBUG("func %s " , __FUNCTION__);

    pConnect = mgc_chnl_info_assign_connect(pChnlInfo , chnl.connectNo);
    if(pConnect == NULL)
	    return MGC_RESULT_NO_RES;

    pMgInfo = mgc_connect_get_own_mg_info(pConnect);
	if(pMgInfo == NULL)
	    return MGC_RESULT_FAILURE;

    mgc_connect_codec_list_init(&codecListResult);
    memcpy(&codecListMg , &pMgInfo->mgAttr.codecList , sizeof(MGC_CODEC_LIST));
    codecListMg.priority = codecList.priority+1;


    for(i=0 ; i<codecListMg.num ; i++)
    {
        codec = codecListMg.codec[i];	
	    for(j=0 ; j<codecList.num ; j++)
		{
		    switch(codec)
		    {
		       case MGC_VCTYPE_AMR_12_2: 
		       case MGC_VCTYPE_AMR_10_2:
			   	    if(codecList.codec[j] == MGC_VCTYPE_AMR_12_2)
			   	    {
			   	        codecListResult.codec[codecListResult.num] = codec;
						codecListResult.num++;
			   	    }
			        break; 	
		       case MGC_VCTYPE_AMR_7_95:
		       case MGC_VCTYPE_AMR_7_4:
		       case MGC_VCTYPE_AMR_6_7:
		       case MGC_VCTYPE_AMR_5_15:
		       case MGC_VCTYPE_AMR_5_9:
		       case MGC_VCTYPE_AMR_4_75:	
			   	    if((codecList.codec[j] == MGC_VCTYPE_AMR_12_2)||(codecList.codec[j] == MGC_VCTYPE_AMR_7_95))
			   	    {
	    	   	        codecListResult.codec[codecListResult.num] = codec;
						codecListResult.num++;
			   	    }				   	
			        break;	
				default:
					if(codecList.codec[j] == codec)
					{
			   	        codecListResult.codec[codecListResult.num] = codec;
						codecListResult.num++;						    
					}
					break;			 
		    }				    
		}
    }

    if(codecListResult.num == 0)
	    return MGC_RESULT_FAILURE;

	if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_IPBSS)
        memcpy(&pConnect->codecList , &codecListResult , sizeof(MGC_CODEC_LIST));


    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] sucess", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo);	   		
    switch(codecListResult.codec[0])
    {
	    case MGC_VCTYPE_AMR_12_2: 
	    case MGC_VCTYPE_AMR_10_2:
		     return MGC_VCTYPE_AMR_12_2;
	    case MGC_VCTYPE_AMR_7_95:
	    case MGC_VCTYPE_AMR_7_4:
	    case MGC_VCTYPE_AMR_6_7:
	    case MGC_VCTYPE_AMR_5_15:
	    case MGC_VCTYPE_AMR_5_9:
	    case MGC_VCTYPE_AMR_4_75:
		     return MGC_VCTYPE_AMR_7_95;
	    default :
		     return codecListResult.codec[0];
    }
 

   return MGC_RESULT_FAILURE;	
}


/***************************************************************************
 * mgc_query_chnl_oper_rec
 * ------------------------------------------------------------------------
 * General:  interface for up-layer to query last time operation 
 * Return Value:  if failure return NULL, else return pointer of the record
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	chnl -  the chnl to be query
 ***************************************************************************/
OPER_REC *mgc_query_chnl_oper_rec(CHNL chnl)
{
    CHNL_INFO *pChnlInfo = NULL;
	CONNECT_INFO *pConnect = NULL;

	pChnlInfo = mgc_chnl_info_get_chnl(chnl);
	if(pChnlInfo == NULL)
        return NULL;

    pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo, chnl.connectNo);
    if(pConnect == NULL)
	    return NULL;

    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] sucess", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo);	   

    return &(pConnect->operRec);	
}


/***************************************************************************
 * mgc_query_chnl_media
 * ------------------------------------------------------------------------
 * General:  interface for up-layer to query chnl media info
 * Return Value:  if failure return -1, else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	chnl -  the chnl to be query
 ***************************************************************************/
int mgc_query_chnl_media(WORD usrPort, CHNL chnl, PUB_SDP_MSG **ppMediaInfo, BYTE *pMgPayloads, BYTE *pMgPlNum)
{
    CHNL_INFO *pChnlInfo = NULL;
	CONNECT_INFO *pConnect = NULL;
	MGC_TANDEM_INFO *pTandem = NULL;
    int i;	

    if((ppMediaInfo == NULL)||(pMgPayloads == NULL)||(pMgPlNum == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;		

	pChnlInfo = mgc_chnl_info_get_chnl(chnl);
	if(pChnlInfo == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;

    pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo, chnl.connectNo);	
    if(pConnect == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;	

    pTandem = pConnect->pTandem;
    if(mgc_tandem_info_get_conn_pos(pTandem, pConnect) == MGC_TANDEM_CONN_POS_TAR)
    {
        pConnect= pTandem->pRxconn;
    }
	else if(mgc_tandem_info_get_conn_pos(pTandem, pConnect) == MGC_TANDEM_CONN_POS_AOR)
	{
		pConnect = pConnect;
	}
	else if((mgc_tandem_info_get_conn_pos(pTandem, pConnect) != MGC_TANDEM_CONN_POS_UNDEF)&&
		    (mgc_tandem_info_get_conn_pos(pTandem, pConnect) != MGC_TANDEM_CONN_POS_SUR))
	{
	    MGC_ERROR("conn[%d] in illegal tandem" , pConnect->id);
		return MGC_RESULT_INPUT_ILLEGAL;
	}

    if((mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATED)&&(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATE))
	    return MGC_RESULT_INPUT_ILLEGAL;	
		
    *ppMediaInfo = &(pConnect->mediaAttr.sdp);

    for(i=0 ; i< pConnect->codecList.num ; i++)
    {
        pMgPayloads[i] = mgc_mgcp_print_vc_num(pConnect->codecList.codec[i]);
    }

    *pMgPlNum = pConnect->codecList.num;

    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] sucess", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo);	   

    return MGC_RESULT_OK;	
}


static int mgc_payload_to_codec(WORD payload, PUB_SDP_ATTRS attrs)
{
    BYTE    i = 0;

    if (attrs.num > 0)
    {
        for (i = 0; i < attrs.num; i++)
        {
            if (attrs.attrs[i].aType != PUB_SDP_ATTR_TYPE_RTPMAP)
            {
                continue;
            }

            if (strtol(attrs.attrs[i].aValue, NULL, 10) == payload)
            {
                if (strstr(attrs.attrs[i].aValue, " GSM/") != NULL)
                    return MGC_VCTYPE_GSM;
                else if (strstr(attrs.attrs[i].aValue, "GSM-EFR") != NULL)
                    return MGC_VCTYPE_GSM_EFR;
                else if (strstr(attrs.attrs[i].aValue, "AMR") != NULL)
                    return MGC_VCTYPE_AMR_12_2;
                else if (strstr(attrs.attrs[i].aValue, "G729B") != NULL)
                    return MGC_VCTYPE_G729B;
                else if (strstr(attrs.attrs[i].aValue, "PCMU") != NULL)
                    return MGC_VCTYPE_PCMU;
				else if (strstr(attrs.attrs[i].aValue, "AMR_12_2") != NULL)
					return MGC_VCTYPE_AMR_12_2;
				else if (strstr(attrs.attrs[i].aValue, "AMR_10_2") != NULL)
					return MGC_VCTYPE_AMR_10_2;
				else if (strstr(attrs.attrs[i].aValue, "AMR_7_95") != NULL)
					return MGC_VCTYPE_AMR_7_95;
				else if (strstr(attrs.attrs[i].aValue, "AMR_7_4") != NULL)
					return MGC_VCTYPE_AMR_7_4;
				else if (strstr(attrs.attrs[i].aValue, "AMR_6_7") != NULL)
					return MGC_VCTYPE_AMR_6_7;
				else if (strstr(attrs.attrs[i].aValue, "AMR_5_15") != NULL)
					return MGC_VCTYPE_AMR_5_15;
				else if (strstr(attrs.attrs[i].aValue, "AMR_5_9") != NULL)
					return MGC_VCTYPE_AMR_5_9;
				else if (strstr(attrs.attrs[i].aValue, "AMR_4_75") != NULL)
					return MGC_VCTYPE_AMR_4_75;				
                else
                    return MGC_VCTYPE_PCMA;
            }
        }
    }
    
    if (i == attrs.num)
    {
        if (payload == 3)
            return MGC_VCTYPE_GSM;
        else if (payload == 84)
            return MGC_VCTYPE_GSM_EFR;
        else if (payload == 118)
            return MGC_VCTYPE_G729B;
        else if (payload == 0)
            return MGC_VCTYPE_PCMU;
        else if (payload == 71)
            return MGC_VCTYPE_AMR_12_2;
        else if (payload == 70)
            return MGC_VCTYPE_AMR_10_2;
        else if (payload == 69)
            return MGC_VCTYPE_AMR_7_95;
        else if (payload == 68)
            return MGC_VCTYPE_AMR_7_4;
        else if (payload == 67)
            return MGC_VCTYPE_AMR_6_7;
        else if (payload == 65)
            return MGC_VCTYPE_AMR_5_15;
        else if (payload == 66)
            return MGC_VCTYPE_AMR_5_9;
        else if (payload == 64)
            return MGC_VCTYPE_AMR_4_75;		
    }
    
    return MGC_VCTYPE_PCMA;
}


/***************************************************************************
 * mgc_update_chnl_media
 * ------------------------------------------------------------------------
 * General:  interface for up-layer to update chnl media info
 * Return Value:  if failure return -1, else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: 	chnl - the chnl to be update
 ***************************************************************************/
int mgc_update_chnl_media(WORD usrPort, CHNL chnl, PUB_SDP_MSG *pMediaInfo)
{
    CHNL_INFO *pChnlInfo = NULL;
	CONNECT_INFO *pConnect = NULL;
	MG_INFO *pMgInfo = NULL;
    PUB_SDP_A *pSdpA = NULL;	
	PORT_INFO *pPortInfo = NULL;		
    BYTE ptime;	
    int i;	

    pPortInfo = mgc_port_info_get_unused_port();
    if((pMediaInfo == NULL)||(pPortInfo == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;		

    pChnlInfo = mgc_chnl_info_get_chnl(chnl);
    if(pChnlInfo == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;

    pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo, chnl.connectNo);
    if(pConnect == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;		

    pMgInfo = mgc_connect_get_own_mg_info(pConnect);
    if(pMgInfo == NULL)
        return MGC_RESULT_INPUT_ILLEGAL;		

    memcpy(&pConnect->mediaAttr.sdp , pMediaInfo , sizeof(PUB_SDP_MSG));

    pConnect->codecList.num = pMediaInfo->medias.medias[0].m.plNum;

    for(i=0 ; i<pConnect->codecList.num ; i++)
    {
        pConnect->codecList.codec[i] = mgc_payload_to_codec(pMediaInfo->medias.medias[0].m.payloads[i], pMediaInfo->medias.medias[0].attrs);
    }

    pConnect->codecList.priority = 255;

    for (i = 0; i < pMediaInfo->medias.medias[0].attrs.num; i++)
    {
        pSdpA = &pMediaInfo->medias.medias[0].attrs.attrs[i];
        if (pSdpA->aType == PUB_SDP_ATTR_TYPE_PTIME)
        {
            ptime = atoi(pSdpA->aValue);
			continue;
        }

		if(strcmp(pSdpA->aValue , "inactive") == 0)
		{
		    mgc_connect_set_conn_mode(pConnect, MGC_CON_MODE_INACTIVE);
		}
		else if(strcmp(pSdpA->aValue , "sendonly") == 0)
		{
		    mgc_connect_set_conn_mode(pConnect, MGC_CON_MODE_SENDONLY);
		}		
		else if(strcmp(pSdpA->aValue , "recvonly") == 0)
		{
		    mgc_connect_set_conn_mode(pConnect, MGC_CON_MODE_RECVONLY);
		}		
		else if(strcmp(pSdpA->aValue , "sendrecv") == 0)
		{
		    mgc_connect_set_conn_mode(pConnect, MGC_CON_MODE_SENDRECV);
		}		
    }

    if (i == pMediaInfo->medias.medias[0].attrs.num)
        ptime = 20;   

    pConnect->mediaAttr.ptime = ptime;

    MGC_DEBUG("conn[%d] , %s " , pConnect->id ,__FUNCTION__);
    if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_INTERNAL)	
    {
		mgc_connect_add_crcx(pConnect, pPortInfo);
    }
    mgc_connect_add_nop(pConnect, pPortInfo);
    mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_UPDATE_CHNL_MEDIA);	
    mgc_port_info_set_step_to_start(pPortInfo);
    pPortInfo->usrPort = usrPort;		
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] sucess", 
		     __FUNCTION__ , 
		     chnl.mgNo,chnl.portNo,chnl.chlNo,chnl.connectNo);	   	
    return MGC_RESULT_OK;	
}


/*-----------------------------------------------------------------------
             SNMP      M A N A G E R
 ------------------------------------------------------------------------*/	


/***************************************************************************
 * mgc_get_snmp_msg
 * ------------------------------------------------------------------------
 * General: check trunk state by snmp info msg 
 * Return Value:  if failed return -1 ,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: void
 ***************************************************************************/
static int mgc_get_snmp_msg(void)
{
    struct snmp_pdu     mgcSnmpPdu;
    struct snmp_addr    mgcSnmpAddr;
    struct var_list     *mgcVarList;
    BYTE                i, trkNo;
    WORD                mgNo;
    MG_INFO             *pMgInfo = NULL;
	PHY_PORT_INFO       *pPhyPort = NULL;
    
    mgcSnmpAddr.local_port = 4968;
    if (!snmp_receive(&mgcSnmpPdu, &mgcSnmpAddr))
        return 0;
    
    if (mgcSnmpPdu.error_index != 0)
        return -1;
    
    mgNo = mgcSnmpPdu.request_id >> 16;
    pMgInfo = mgc_mg_info_get_index_mg(mgNo);
	if(pMgInfo == NULL)
	    return -1;
	
    if ((mgcSnmpPdu.request_id & 0xFFFF) != pMgInfo->requestId)
        return -1;
    
    if (mgcSnmpPdu.var_num > MGC_MAX_PHY_PORT_PER_MG)
        return -1;
    
    mgcVarList = &mgcSnmpPdu.var[0];
    
    for (i = 0; i < mgcSnmpPdu.var_num; i++)
    {
        trkNo = mgcVarList[i].oid[MGC_AC_LINE_STATUS_IDLEN - 1];
        pPhyPort = mgc_phy_port_find_port_of_mg(pMgInfo, trkNo);
        if(pPhyPort == NULL)
		    return -1;

		if(mgcVarList[i].msg[0] == 1)
		{
		    pPhyPort->status = MGC_PHY_PORT_STATUS_ON_LINE;
		}
		else
		{
		    pPhyPort->status = MGC_PHY_PORT_STATUS_OFF_LINE;
		}
		
    }
    
    return 1;
}


/***************************************************************************
 * mgc_get_non_virtual_trk_status
 * ------------------------------------------------------------------------
 * General: send snmp msg to check mg status
 * Return Value:  if failed return -1 ,  else return 0
 * ------------------------------------------------------------------------
 * Arguments:
 * Input: void
 ***************************************************************************/
int mgc_get_non_virtual_trk_status(MG_INFO *pMgInfo)
{
    struct snmp_pdu     mgcSnmpPdu;
    struct snmp_addr    mgcSnmpAddr;
    struct var_list     *mgcVarList;
    BYTE                i, j = 0;
    PHY_PORT_INFO *pPhyPort;

    if(pMgInfo == NULL)
	    return MGC_RESULT_FAILURE;	

    mgcVarList = &mgcSnmpPdu.var[0];
    mgcSnmpPdu.var_num = 0;             //val list number

    if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_AudioCoder)
    {
        for(i=0 ; i< MGC_MAX_PHY_PORT_PER_MG ; i++)
        {
            pPhyPort = mgc_phy_port_find_port_of_mg_by_index(pMgInfo, i);

			if(pPhyPort == NULL)
			    continue;

		    mgcVarList[j].oidlen = MGC_AC_LINE_STATUS_IDLEN;
			MGC_AC_LINE_STATUS_OID[MGC_AC_LINE_STATUS_IDLEN - 1] = pPhyPort->portNo;
		    memcpy(&mgcVarList[mgcSnmpPdu.var_num].oid[0], MGC_AC_LINE_STATUS_OID, MGC_AC_LINE_STATUS_IDLEN*4);	
            mgcVarList[mgcSnmpPdu.var_num].vartype = 0x04;//octet string
            mgcVarList[mgcSnmpPdu.var_num].msglen = 0;
            mgcSnmpPdu.var_num++;
            j++;			
        }
    }
	
    
    if(pMgInfo->mgAttr.mgType == MGC_MG_TYPE_LGC_MG)
    {
        for(i=0 ; i< MGC_MAX_PHY_PORT_PER_MG ; i++)
        {
            pPhyPort = mgc_phy_port_find_port_of_mg_by_index(pMgInfo, i);

			if(pPhyPort == NULL)
			    continue;

		    mgcVarList[j].oidlen = MGC_AC_LINE_STATUS_IDLEN;
			MGC_AC_LINE_STATUS_OID[MGC_AC_LINE_STATUS_IDLEN - 1] = i;
		    memcpy(&mgcVarList[mgcSnmpPdu.var_num].oid[0], MGC_AC_LINE_STATUS_OID, MGC_LGC_MG_STATUS_IDLEN*4);	
            mgcVarList[mgcSnmpPdu.var_num].vartype = 0x04;//octet string
            mgcVarList[mgcSnmpPdu.var_num].msglen = 0;
            mgcSnmpPdu.var_num++;
            j++;			
        }    
    }
    
    pMgInfo->requestId = (++pMgInfo->requestId) & 0xFFFF;
    if (pMgInfo->requestId == 0)
        pMgInfo->requestId = 1;
    
    mgcSnmpPdu.pdu_type = 0x00; //get
    mgcSnmpPdu.request_id = (pMgInfo->id<< 16) | pMgInfo->requestId;
    
    mgcSnmpAddr.local_port = 4968;
    mgcSnmpAddr.remote_port = 161;
    mgcSnmpAddr.broadcast = 0;  //Not broadcast
    mgcSnmpAddr.remote_ip = pMgInfo->mgAttr.ip;
    
    if (mgcSnmpPdu.var_num)
        snmp_send(&mgcSnmpPdu,&mgcSnmpAddr);
    
    return MGC_RESULT_OK;
}


int mgc_get_idle_tandem_id(void)
{
    MGC_TANDEM_INFO *pTandem = NULL;
	
    pTandem = mgc_tandem_info_get_idle_tandem();
	if(pTandem == NULL)
	    return MGC_RESULT_NO_RES;

    MGC_INFO("%s tandem[%d]" , __FUNCTION__ , pTandem->id);
	return pTandem->id;
}


int mgc_create_tandem(WORD usrPort , DWORD tandId)
{
	MGC_TANDEM_INFO *pTandem = NULL;
    PORT_INFO *pPortInfo = NULL;

    MGC_DEBUG("func %s " , __FUNCTION__);
    pTandem = mgc_tandem_info_get_tandem_by_id(tandId);
	pPortInfo = mgc_port_info_get_unused_port();

    if((pTandem == NULL)||(pPortInfo == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;	

    mgc_tandem_info_create_tandem(pTandem, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
	mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_TANDEM_CREATE);	
	pPortInfo->usrPort = usrPort;
    MGC_INFO("%s tandem[%d]" , __FUNCTION__ , pTandem->id);
	return MGC_RESULT_OK;
}

int mgc_bind_chnl_to_tandem(WORD usrPort , CHNL tarChnl , DWORD tandId)
{
    MG_INFO *pMgInfo = NULL;
    CHNL_INFO *pChnlInfo = NULL;
	CONNECT_INFO *pConnect = NULL;
	MGC_TANDEM_INFO *pTandem = NULL;
    PORT_INFO *pPortInfo = NULL;	

    MGC_DEBUG("func %s " , __FUNCTION__);
    pMgInfo = mgc_mg_info_get_index_mg(tarChnl.mgNo);
	pChnlInfo = mgc_chnl_info_get_chnl(tarChnl);
    pTandem = mgc_tandem_info_get_tandem_by_id(tandId);
	pPortInfo = mgc_port_info_get_unused_port();
    if((pMgInfo == NULL)||(pChnlInfo == NULL)||(pTandem == NULL)||(pPortInfo == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP)
        return -MGC_RESULT_INPUT_ILLEGAL;

    MGC_DEBUG("mg[%d]port[%d]chnl[%d]connNo[%d]" , tarChnl.mgNo,tarChnl.portNo,tarChnl.chlNo,tarChnl.connectNo);
    pConnect = mgc_chnl_info_assign_connect(pChnlInfo, tarChnl.connectNo);	
	if(pConnect == NULL)
	    return MGC_RESULT_NO_RES;	
	
    if(mgc_tandem_info_get_conn_pos(pTandem , pTandem->pTconn) != MGC_TANDEM_CONN_POS_UNDEF)
    {
        MGC_ERROR("tandem[%d] is in use" ,pTandem->id);
        return MGC_RESULT_FAILURE;	
    }

    if(mgc_tandem_info_get_conn_pos(pConnect->pTandem, pConnect) != MGC_TANDEM_CONN_POS_UNDEF)
    {
        MGC_WARN("conn[%d] already bind to tandem[%d]" , pConnect->id , pConnect->pTandem->id);
		mgc_tandem_info_remove_connection_from_tandem(pConnect, pPortInfo);
    }
	
	if(mgc_tandem_info_set_conn(pTandem,pConnect, MGC_TANDEM_CONN_POS_TAR) == FALSE)
	    return MGC_RESULT_FAILURE;
	
    mgc_tandem_info_create_tar_tandem(pConnect, pPortInfo);
	mgc_connect_add_nop(pConnect, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
	mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_TANDEM_SET_TAR);
    MGC_DEBUG("%s tandem[%ld] conn[%d]" , __FUNCTION__, tandId , pConnect->id);
	MGC_DEBUG("tandem[%d] rxConn[%d] txConn[%d]" , pTandem->id , pTandem->pRxconn->id , pTandem->pTxconn->id);
	pPortInfo->usrPort = usrPort;
    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] bind tandem[%d] success" , __FUNCTION__ , 
		      tarChnl.mgNo , tarChnl.portNo , tarChnl.chlNo , tarChnl.connectNo ,pTandem->id);	
	return MGC_RESULT_OK;
}


int mgc_unbind_chnl_from_tandem(WORD usrPort , CHNL tarChnl , DWORD tandId)
{
    MG_INFO *pMgInfo = NULL;
    CHNL_INFO *pChnlInfo = NULL;
	CONNECT_INFO *pConnect = NULL;
	MGC_TANDEM_INFO *pTandem = NULL;
    PORT_INFO *pPortInfo = NULL;	

    MGC_DEBUG("func %s " , __FUNCTION__);
    pMgInfo = mgc_mg_info_get_index_mg(tarChnl.mgNo);
	pChnlInfo = mgc_chnl_info_get_chnl(tarChnl);
    pTandem = mgc_tandem_info_get_tandem_by_id(tandId);
	pPortInfo = mgc_port_info_get_unused_port();
    if((pMgInfo == NULL)||(pChnlInfo == NULL)||(pTandem == NULL)||(pPortInfo == NULL))
        return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.ctrlType != MGC_MG_CTRL_TYPE_MGCP)
        return -MGC_RESULT_INPUT_ILLEGAL;

    MGC_DEBUG("mg[%d]port[%d]chnl[%d]connNo[%d]" , tarChnl.mgNo,tarChnl.portNo,tarChnl.chlNo,tarChnl.connectNo);
    pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo, tarChnl.connectNo);	
	if(pConnect == NULL)
	    return MGC_RESULT_NO_RES;	

    if(mgc_tandem_info_get_conn_pos(pTandem, pConnect) != MGC_TANDEM_CONN_POS_TAR)
	    return MGC_RESULT_FAILURE;

	mgc_tandem_info_remove_connection_from_tandem(pConnect, pPortInfo);    	
    mgc_port_info_set_step_to_start(pPortInfo);
	mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_TANDEM_UNSET_TAR);
	pPortInfo->usrPort = usrPort;

    MGC_INFO("%s mg[%d]port[%d]chnl[%d]conNo[%d] unbind tandem[%d] success" , __FUNCTION__ , 
		      tarChnl.mgNo , tarChnl.portNo , tarChnl.chlNo , tarChnl.connectNo ,pTandem->id);	
	return MGC_RESULT_OK;
}


int mgc_get_tandem_near_end(DWORD tandem_id, CHNL *pChnl)
{
	MGC_TANDEM_INFO *pTandem = NULL;
    CONNECT_INFO *pConnect = NULL;
    MG_INFO *pMgInfo = NULL;
	PHY_PORT_INFO *pPhyPort = NULL;
    CHNL_INFO *pChnlInfo = NULL;
	
    if(pChnl == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;
    MGC_DEBUG("func %s " , __FUNCTION__);
    pTandem = mgc_tandem_info_get_tandem_by_id(tandem_id);
	if(pTandem == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;

    if(mgc_tandem_info_get_conn_pos(pTandem, pTandem->pTxconn) != MGC_TANDEM_CONN_POS_TX)
    {
        MGC_ERROR("tandem[%d] lost TxConn" , pTandem->id);
		return MGC_RESULT_INPUT_ILLEGAL;
    }

    pConnect = pTandem->pTxconn;
    pMgInfo = mgc_connect_get_own_mg_info(pConnect);
    pPhyPort = mgc_connect_get_own_phy_port_info(pConnect);
	pChnlInfo = mgc_connect_get_own_chnl_info(pConnect);
	if((pConnect == NULL)||(pMgInfo == NULL)||(pPhyPort == NULL)||(pChnlInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

	pChnl->mgNo = pMgInfo->id;
	pChnl->portNo = pPhyPort->portNo;
	pChnl->chlNo = mgc_chnl_info_get_chnl_no_of_phy(pChnlInfo, pPhyPort);
	pChnl->connectNo = mgc_connect_get_connNo_of_chnl_info(pConnect, pChnlInfo);
    MGC_INFO("%s success" , __FUNCTION__);	
	return MGC_RESULT_OK;
}


int mgc_get_tandem_far_end(DWORD tandem_id, CHNL *pChnl)
{
	MGC_TANDEM_INFO *pTandem = NULL;
    CONNECT_INFO *pConnect = NULL;
    MG_INFO *pMgInfo = NULL;
	PHY_PORT_INFO *pPhyPort = NULL;
    CHNL_INFO *pChnlInfo = NULL;
	
    if(pChnl == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;
	
    MGC_DEBUG("func %s " , __FUNCTION__);

    pTandem = mgc_tandem_info_get_tandem_by_id(tandem_id);
	if(pTandem == NULL)
	    return MGC_RESULT_INPUT_ILLEGAL;

    if(mgc_tandem_info_get_conn_pos(pTandem, pTandem->pRxconn) != MGC_TANDEM_CONN_POS_RX)
    {
        MGC_ERROR("tandem[%d] lost RxConn" , pTandem->id);
		return MGC_RESULT_INPUT_ILLEGAL;
    }
	
    pConnect = pTandem->pRxconn;
    pMgInfo = mgc_connect_get_own_mg_info(pConnect);
    pPhyPort = mgc_connect_get_own_phy_port_info(pConnect);
	pChnlInfo = mgc_connect_get_own_chnl_info(pConnect);
	if((pConnect == NULL)||(pMgInfo == NULL)||(pPhyPort == NULL)||(pChnlInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

	pChnl->mgNo = pMgInfo->id;
	pChnl->portNo = pPhyPort->portNo;
	pChnl->chlNo = mgc_chnl_info_get_chnl_no_of_phy(pChnlInfo, pPhyPort);
	pChnl->connectNo = mgc_connect_get_connNo_of_chnl_info(pConnect, pChnlInfo);
    MGC_INFO("%s success" , __FUNCTION__);	
	return MGC_RESULT_OK;
}


int mgc_fork_chnl(WORD usrPort , CHNL parent, CHNL *pChild)
{
    MG_INFO *pMgInfo = NULL;
    CHNL_INFO *pChnlInfo = NULL;
	CONNECT_INFO *pConnect = NULL;	
	MGC_TANDEM_INFO *pTandem = NULL;
	CONNECT_INFO *pSurConnect = NULL;	
	PHY_PORT_INFO *pSurPhyPort = NULL;
    CHNL_INFO *pSurChnlInfo = NULL;	
    PORT_INFO *pPortInfo = NULL;	

    pMgInfo = mgc_mg_info_get_index_mg(parent.mgNo);
	pChnlInfo = mgc_chnl_info_get_chnl(parent);
	pConnect = mgc_connect_find_connect_of_chnl(pChnlInfo,parent.connectNo);
	pPortInfo = mgc_port_info_get_unused_port();	
    MGC_DEBUG("func %s " , __FUNCTION__);

    if((pMgInfo == NULL)||(pChnlInfo == NULL)||(pConnect == NULL)||(pPortInfo == NULL)||(pChild == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

    if(pMgInfo->mgAttr.mgType != MGC_MG_TYPE_TANDEM)
    {
        MGC_ERROR("mg[%d] is not tandem type!" , pMgInfo->id);
	    return MGC_RESULT_INPUT_ILLEGAL;	    
    }

    if((mgc_tandem_info_get_conn_pos(pConnect->pTandem,pConnect) != MGC_TANDEM_CONN_POS_RX)&&
		(mgc_tandem_info_get_conn_pos(pConnect->pTandem,pConnect) != MGC_TANDEM_CONN_POS_TX))
    {
        MGC_ERROR("conn[%d] is not a connection on tandem" , pConnect->id);
        return MGC_RESULT_FAILURE;
    }

    if((mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATED)&&(mgc_connect_get_status(pConnect) != MGC_CONNECT_STATUS_CREATE))
    {
        MGC_ERROR("conn[%d] of tandem[%d] is not created, can't fork!" , pConnect->id , pConnect->pTandem->id);
        return MGC_RESULT_FAILURE;
    }

    pTandem = pConnect->pTandem;
	pSurConnect = mgc_sur_info_find_sur_conn_in_mg(pMgInfo);
	pSurPhyPort = mgc_connect_get_own_phy_port_info(pSurConnect);
	pSurChnlInfo = mgc_connect_get_own_chnl_info(pSurConnect);
    if((pSurConnect == NULL)||(pSurChnlInfo == NULL)||(pSurPhyPort == NULL))
	    return MGC_RESULT_NO_RES;		    

    if(mgc_tandem_info_set_conn(pTandem, pSurConnect,MGC_TANDEM_CONN_POS_SUR) == FALSE)
	    return MGC_RESULT_FAILURE;

    pChild->mgNo = pMgInfo->id;
	pChild->portNo = pSurPhyPort->portNo;
	pChild->chlNo = mgc_chnl_info_get_chnl_no_of_phy(pSurChnlInfo, pSurPhyPort);
	pChild->connectNo = mgc_connect_get_connNo_of_chnl_info(pSurConnect, pSurChnlInfo);

    sprintf(pSurConnect->mediaAttr.callId, "%s" , pConnect->mediaAttr.callId);  
	memcpy(&pSurConnect->codecList, &pConnect->codecList , sizeof(MGC_CODEC_LIST));
    mgc_connect_add_crcx_with_mode(pSurConnect, MGC_CON_MODE_SENDONLY , pPortInfo);
	mgc_connect_add_nop(pConnect, pPortInfo);   //report to the parant chnl
    mgc_port_info_set_step_to_start(pPortInfo);
	mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_TANDEM_FORK_CHNL);
	pPortInfo->usrPort = usrPort;	
	MGC_DEBUG("conn[%d] fork conn[%d] callid :%s , on tandem[%d]" , pConnect->id , pSurConnect->id , pSurConnect->mediaAttr.callId, pTandem->id);
    MGC_DEBUG("fork mg[%d]port[%d]chnl[%d]connNo[%d]" , pChild->mgNo , pChild->portNo , pChild->chlNo, pChild->connectNo);	
    MGC_INFO("%s success" , __FUNCTION__);		
	return MGC_RESULT_OK;
}

int mgc_delete_tandem(WORD usrPort , DWORD tandemId)
{
    MGC_TANDEM_INFO *pTandem = NULL;
	PORT_INFO *pPortInfo = NULL;
    CONNECT_INFO *pConnect = NULL;
	
    pTandem = mgc_tandem_info_get_tandem_by_id(tandemId);
	pPortInfo = mgc_port_info_get_unused_port();
    MGC_DEBUG("func %s " , __FUNCTION__);

    if((pTandem == NULL)||(pPortInfo == NULL))
	    return MGC_RESULT_INPUT_ILLEGAL;

    pConnect = pTandem->pTxconn;
	mgc_tandem_info_unset_conn(pTandem, pTandem->pTconn);
	mgc_tandem_info_unset_conn(pTandem, pTandem->pAconn);
	mgc_tandem_info_clear(pTandem, pPortInfo);
    mgc_port_info_set_step_to_start(pPortInfo);
	mgc_port_info_set_oper_id(pPortInfo , MGC_OPER_ID_TANDEM_CLEAR);
	pPortInfo->usrPort = usrPort;	
    MGC_INFO("%s  tandem[%d] success" , __FUNCTION__ , pTandem->id);	
	return MGC_RESULT_OK;    	
}

int mgc_update_phy_port_status(CHNL chnl, BOOL status)
{
    MG_INFO *pMgInfo = NULL;
	PHY_PORT_INFO *pPhyPort = NULL;

    pMgInfo = mgc_mg_info_get_index_mg(chnl.mgNo);
    pPhyPort = mgc_phy_port_find_port_of_mg(pMgInfo, chnl.portNo);

    MGC_DEBUG("func %s " , __FUNCTION__);

    if((pMgInfo == NULL)||(pPhyPort == NULL))
    {
        MGC_ERROR("update phyport failed! ,lost phyport");
        return MGC_RESULT_INPUT_ILLEGAL;
    }

    if(status == TRUE)
    {
        pPhyPort->status = MGC_PHY_PORT_STATUS_ON_LINE;
    }
	else
	{
	    pPhyPort->status = MGC_PHY_PORT_STATUS_OFF_LINE;
	}
	
    return MGC_RESULT_OK;
}

