
/***************************************************************/
/*Title:   scrc.c                                              */
/*Descr:   SCCP Routing Control Procedure                      */
/*Author:  Liang Hanxi                                         */
/*Create:  2002-2-19                                           */
/*Modify:  2003-5-9                                            */

/***************************************************************/
#include "./include/sccp.h"
#include "./include/sccp_pub.h"
#include "../../public/src/include/pub_netcap.h"

extern int sccp_send_netcap ;

/*===========export================*/
void scrc_timer (  );
int scrc_route ( Intra_Msg * pIntraMsg, BOOL ForceAnsi );
int scrc_mnp_route ( Intra_Msg * pIntraMsg, BOOL ForceAnsi );
int send_msg ( Intra_Msg * pIntraMsg, BYTE ansi_flag );
int scrc_rf ( Intra_Msg * pIntraMsg, BYTE AnsiFlag );
DWORD SelectIPOfSSN ( BYTE ssn, BYTE sls, BOOL from_mtp );

/*===========import================*/
extern int SegmentingMsg ( Intra_Msg * pIntraMsg );     //sclc.c
extern int build_msg ( BYTE * buf, Intra_Msg * intramsg, BYTE NetID, BYTE ansi_flag );
extern int parse_msg ( BYTE * buf, Intra_Msg * intramsg, int len, BYTE NetID, BYTE ansi_flag ); //sccpmsg.c
extern int scrc2scoc ( Intra_Msg * intramsg, BYTE AnsiFlag );
extern int scoc_store ( up_message * sccpmsg );
extern int Digits2Array ( BYTE * pArray, BYTE * pDigits, int DigitsLen );
extern u_short SelectRoute ( BYTE * pDigits, BYTE DigitsLen );
extern void TranslateGT ( SCCP_ADDR * addr, SCCP_ROUTE * pRoute );
extern int sclc2scmg ( Intra_Msg * intramsg );
extern BOOL CheckAvail ( SCCP_ADDR * addr );
extern int scrc2sclc ( Intra_Msg * pIntraMsg );
extern int sclc_rf ( Intra_Msg * pIntraMsg );
extern BOOL isco ( Intra_Msg * intramsg );
extern void snmpLogInfo ( char *logInfo );

/* by simon at 23/9/26 */
extern SCCP_CSTA SccpCsta[96];
extern DWORD SccpCstaInd;
extern LOCAL_SSN LocalSSN[256];
extern SCCP_SegMsgBuf sccp_segmsgbuf[MAX_SEGMSG_BUF];
extern struct sccp_msg_statistic
{
    DWORD msg_mtp_scoc;
    DWORD msg_scoc_up;
    DWORD mnp_send;
    DWORD mnp_route;
} sccpmsg_st;
extern struct _dpc2sls
{
    int dpc;
    u8 sls;
} dpc2sls[256]; // used for sequence control, add by Roy Jiang, 2007-09-17
extern SCCP_Capture_Buf SCCPCapBuf;
extern LOCAL_SSN LocalSSN[256];
extern int RelatedSSNNum;
extern RL_SSN RelatedSSN[SCCP_RLSSN_NUM];
extern SCOC_BUF ScocBuf;
extern SCCP_ROUTE RouteList[SCCP_ROUTE_NUM];
extern SCCP_OPT SCCP_Param;
extern u8 MNP_Flag[2];

/*===========private================*/
static int mtp2scrc ( up_message * pMsgFromMTP );
void sccp_put_capture_logs ( BYTE person, BYTE * pictures, int len );
int get_sls(int dpc);
/******************************************************************/

/*==================Interface function----->================*/

/******************************************************************/
void scrc_timer (  )            //called per 20ms
//read messge from mtp buffer
{
    up_message MsgFromMTP3;
    BYTE loop = 128;

    while ( loop-- > 0 )
    {
        if( sccp_GetMsg ( &MsgFromMTP3 ) > 0 )
            mtp2scrc ( &MsgFromMTP3 );
		else
			break;
    }
}

u32 dAlterIpBackup;	//for protection
int mtp2scrc ( up_message * pMsgFromMTP )
{
    Intra_Msg msgin;
    BOOL ForceAnsi = 0;
    int mask;
    char *pStr;

    SccpCsta[SccpCstaInd].utilization[0]++;

    memset ( &msgin, 0, sizeof ( Intra_Msg ) );
    msgin.NetID = msgin.CGA.NetID = msgin.CDA.NetID = pMsgFromMTP->sio >> 6;
    msgin.DPC = pMsgFromMTP->dpc;
    msgin.OPC = pMsgFromMTP->opc;
    msgin.SLS = pMsgFromMTP->cic[0] & 0x0F;
    msgin.link = pMsgFromMTP->link;

    ForceAnsi = ( pMsgFromMTP->sio >> 4 ) & 1;
    parse_msg ( pMsgFromMTP->msgList, &msgin, pMsgFromMTP->len, msgin.NetID, ForceAnsi );

    if( msgin.CDA.len > ( MAX_DIGITS * 2 ) )
    {
        SCCPCapBuf.watch_dog[14]++;
        sccp_put_capture_logs ( 03, ( BYTE * ) pMsgFromMTP, sizeof ( up_message ) );
        spLogDebug ( SCCPDB_ERR, "SCCP RV Invalid Message from MTP3,CDA.len=%d, len is over range, the Message was captured", msgin.CDA.len );
    }

    msgin.msgsource = FROM_MTP;

    if( msgin.CGA.DPC == SCCP_Param.spc[msgin.NetID] )
        msgin.CGA.ip = pMsgFromMTP->dest_ip;
    else
        msgin.CGA.ip = INADDR_NONE;
    msgin.CDA.ip = INADDR_NONE;

    switch ( msgin.msgtype )
    {
    case UDT_MSG:
        SccpCsta[SccpCstaInd].quality[2]++;
        spShowMsg ( SCCPDB_MTP3, "SCCP <== MTP3. UDT Message", &msgin );
        return scrc_route ( &msgin, ForceAnsi );
    case UDTS_MSG:
        SccpCsta[SccpCstaInd].quality[3]++;
        spShowMsg ( SCCPDB_MTP3, "SCCP <== MTP3. UDTS Message", &msgin );
        return scrc_route ( &msgin, ForceAnsi );
    case XUDT_MSG:
        //SccpCsta[SccpCstaInd].quality[3]++;
        mask = 0;
        if( msgin.SegPresent == 1 )
        {
            mask |= SCCPDB_XUDT;
        }

        spShowMsg ( SCCPDB_MTP3 | mask, "SCCP_RegProc <== SCCP <== MTP3. XUDT Message", &msgin );
        return scrc_route ( &msgin, ForceAnsi );
    case XUDTS_MSG:
        //SccpCsta[SccpCstaInd].quality[3]++;
        spShowMsg ( SCCPDB_MTP3, "SCCP <== MTP3. XUDTS Message", &msgin );
        return scrc_route ( &msgin, ForceAnsi );
    case CR_MSG:
        SccpCsta[SccpCstaInd].quality[6]++;
        spShowMsg ( SCCPDB_AIF, "SCCP <== MTP3. CR Message", &msgin );
	    return scrc_route ( &msgin, ForceAnsi );
	case DT1_MSG:
	case CC_MSG:
    case DT2_MSG:
    case RLSD_MSG:
    case RLC_MSG:
    case CREF_MSG:
    case AK_MSG:
    case IT_MSG:
		//message redirect, add by Roy Jiang
		if (msgin.aDLR[0] != pSp->dSysID	//not local system
			&& msgin.aDLR[0] <= 2 && msgin.aDLR[0] != 0) //only system 1 & system 2
		{
			//dual server mode and the message is to the other server
			if(pSp->dAlterIP == 0)
			{
				if (dAlterIpBackup != 0){
					spLogDebug ( SCCPDB_ERR, "Fatal error, memory corrupted, pSp->dAlterIp = 0.");
					pSp->dAlterIP = dAlterIpBackup;
				}
				else
					return 0;
			}
			msgin.CDA.ip = pSp->dAlterIP;
			msgin.msgsource = FROM_MTP;
			msgin.redirectFlag = 1;
			//send_msg ( &msgin, 0 );	//uAnsiFlag = 0;
			pMsgFromMTP->dest_ip = pSp->dAlterIP;
			pMsgFromMTP->link = 0xff;
			sccp_redirect(pMsgFromMTP);
        	spGetMsgStr ( msgin.msgtype, pStr );
			spShowMsg(SCCPDB_MTP3, "Message redirected. SCCP ==> MTP3.", &msgin);
//			spLogDebug ( SCCPDB_AIF, "Message redirected. CO-%s, NetID=%d, msglen=%d", pStr, msgin.NetID, msgin.msglen );
			return 0;
		}
        if( msgin.msgtype == DT1_MSG )
            SccpCsta[SccpCstaInd].utilization[9 - 3]++;
        else if( msgin.msgtype == DT1_MSG )
            SccpCsta[SccpCstaInd].utilization[11 - 3]++;

        spGetMsgStr ( msgin.msgtype, pStr );
        spLogDebug ( SCCPDB_AIF, "SCCP <== MTP3. CO-%s, NetID=%d, msglen=%d ", pStr, msgin.NetID, msgin.msglen );

        {
            char digits1[24], digits2[24]; //, info[256];

            BcdToAscii ( digits1, msgin.aSLR, 6 );
            digits1[6] = 0;
            BcdToAscii ( digits2, msgin.aDLR, 6 );
            digits2[6] = 0;
            spLogDebug ( SCCPDB_AIF,"SLR = %s DLR = %s ", digits1, digits2 );
        }
        spShowBCD ( SCCPDB_AIF, ( BYTE * ) pMsgFromMTP, ( pMsgFromMTP->len + 17 ) % 256 );

#ifndef _WXC_TEST
/*
        if( SCCP_Param.CO_SSN <= 1 )
            return scrc_rf ( &msgin, ForceAnsi );

        msgin.CDA.ip = SelectIPOfSSN ( SCCP_Param.CO_SSN, msgin.SLS, 1 );

        if( msgin.CDA.ip == SCCP_Param.ip )
        {
            return scoc_store ( pMsgFromMTP );
        }
        else if( msgin.CDA.ip == 0 )
            return scrc_rf ( &msgin, ForceAnsi );
        else
            return send_msg ( &msgin, ForceAnsi );
*/
#endif
        //need to modify
        cr2co ( &msgin, ForceAnsi );
        return 1;
        //break;
    default:
        spLogDebug ( SCCPDB_ERR, "SCCP <== MTP3. Not support Message(type=%02x), NetID=%d, msglen=%d", msgin.msgtype, msgin.NetID, msgin.msglen );
        spShowBCD ( SCCPDB_ERR, ( BYTE * ) pMsgFromMTP, ( pMsgFromMTP->len + 17 ) % 256 );
        SCCPCapBuf.watch_dog[12]++;     //invalid message
        SCCPCapBuf.watch_dog[13] = msgin.msgtype;       //invalid message

    }
    return 0;
}

/******************************************************************/

/*==========        Routing Control Procedure----->        ===========*/

/******************************************************************/
int scrc_route ( Intra_Msg * pIntraMsg, BOOL ForceAnsi )
{
    SCCP_ADDR *pAddr = NULL, DstAddr;
    SCCP_ROUTE *pRoute = NULL;
    int LocalSPC;
    u_short nRoute = 0xFFFF;
    BYTE Num[32], NumLen;
    BYTE routeAI;
    BYTE field = 0;

    SccpCsta[SccpCstaInd].utilization[0]++;
    pIntraMsg->msgMNP = 0;

    pAddr = &pIntraMsg->CDA;
    /* daniel */
    pAddr->AI = 1;              //default to include DPC
    pIntraMsg->CGA.AI = 1;      //default to include DPC
    /* daniel */
    memcpy ( &DstAddr, pAddr, sizeof ( SCCP_ADDR ) );

    if( pAddr->RI == RI_SSN && pAddr->DPC == 0 )
    {
        if( pAddr->NetID > 3 )
        {
            spLogDebug ( SCCPDB_ERR, "<011>SCCP Translation:SPC not available" );
            SccpCsta[SccpCstaInd].error[0]++;
            return -1;
        }
        DstAddr.DPC = SCCP_Param.spc[pAddr->NetID];
    }
    //Route On GT
    if( DstAddr.RI == RI_GT || DstAddr.DPC == 0 || DstAddr.SSN == 0 || DstAddr.NetID > 3 )
    {
        SccpCsta[SccpCstaInd].utilization[5 - 3]++;
        if( pIntraMsg->CDA.GTI == 0 )
        {
            pIntraMsg->cause = RT_NTFN;
            spLogDebug ( SCCPDB_ERR, "<011>SCCP Translation:GTI == 0 (4 is recommended)" );
            SccpCsta[SccpCstaInd].error[1]++;
            return -1;
        }
        /* if(pIntraMsg->CDA.TT != 0)
           {
           spLogDebug(SCCPDB_ERR, "<012>SCCP Translation:no translation for an address of such nature(TT=%d)", pIntraMsg->CDA.TT);
           pIntraMsg->cause = RT_NTFN;
           SccpCsta[SccpCstaInd].error[0] ++;
           return -1;
           } */

        if( pAddr->len > ( MAX_DIGITS * 2 ) )
        {
            SCCPCapBuf.watch_dog[0]++;
            sccp_put_capture_logs ( 01, ( BYTE * ) pIntraMsg, sizeof ( Intra_Msg ) );
            spLogDebug ( SCCPDB_ERR, "<014>SCCP Receive Invalid Message,GTT len=%d, the Message was discarded and captured", pAddr->len );
            return -2;
        }

        if( pAddr->NP > 0 )
            Num[field++] = pAddr->NP;
        else
            Num[field++] = NP_MSISDN;
        if( pAddr->TT > 0 )
        {
            Num[field++] = pAddr->TT / 100;
            Num[field++] = ( pAddr->TT / 10 ) % 10;
            Num[field++] = pAddr->TT % 10;
        }
        else
        {
            Num[field++] = TT_0;
            Num[field++] = TT_1;
            Num[field++] = TT_4;
        }
        NumLen = pAddr->len % ( MAX_DIGITS * 2 );
        Digits2Array ( Num + field, pAddr->GTAI, ( NumLen + 1 ) / 2 );
        nRoute = SelectRoute ( Num, NumLen + field );

        if( nRoute < SCCP_ROUTE_NUM )
        {
            pRoute = &RouteList[nRoute];

            if( DstAddr.NetID != pRoute->NetID )
                pIntraMsg->CGA.RI = RI_GT;
            /* daniel */
            else if( pIntraMsg->msgsource != FROM_MTP )
                pIntraMsg->CGA.RI = pRoute->RI;
            /* daniel */
            DstAddr.NetID = pRoute->NetID;

            if( pRoute->SSN > 0 )
                pAddr->SSN = DstAddr.SSN = pRoute->SSN;

            pAddr->RI = pRoute->RI;
            DstAddr.DPC = pRoute->DPC[0] * 0x10000 + pRoute->DPC[1] * 0x100 + pRoute->DPC[2];

		if(( pIntraMsg->CGA.SSN != 10 ) && ( DstAddr.SSN == 6 && DstAddr.NP == 1 && pIntraMsg->data[0] == 0x62 ) && (MNP_Flag[0] != 0))
			{//  MNP neednot convert GT
				if(!((pRoute->ReplaceStart == 1) && (pRoute->ReplaceEnd == pAddr->len)))
				{
					if( pRoute->convert )
			                {
				                DstAddr.RI = pAddr->RI;
				                TranslateGT ( &DstAddr, pRoute );
				                memcpy ( pAddr, &DstAddr, sizeof ( SCCP_ADDR ) );
					}
			         }
			}
		else if( pRoute->convert )
            {
                DstAddr.RI = pAddr->RI;
                TranslateGT ( &DstAddr, pRoute );
                memcpy ( pAddr, &DstAddr, sizeof ( SCCP_ADDR ) );
            }

            /* daniel */
            routeAI = pRoute->AI;
            //set calling address
            if( pIntraMsg->CGA.RI == 0 )        //route on GT
            {
                if( ( routeAI & 1 ) == 0 )      //point code no need
                    pIntraMsg->CGA.AI &= ~1;    //set dpc=0
            }
            else                //route on DPC+SSN
            {
                if( ( routeAI & 4 ) == 0 )      //GT no need
                    pIntraMsg->CGA.GTI = 0;     //set GT=0
            }

            //set called address
            if( pAddr->RI == 0 )        //route on GT
            {
                if( ( routeAI & 1 ) == 0 )      //point code no need
                    pAddr->AI &= ~1;    //set dpc=0
            }
            else                //route on DPC+SSN
            {
                if( ( routeAI & 4 ) == 0 )      //GT no need
                    pAddr->GTI = 0;     //set GTI=0
            }
            /* daniel */

        }
        else if( nRoute >= 1024 && nRoute < 1024 + 256 )        //local Node
        {
            pAddr->SSN = DstAddr.SSN = nRoute - 1024;
            if( DstAddr.NetID > 3 )
                DstAddr.NetID = LocalSSN[DstAddr.SSN].NetID;

            pAddr->RI = RI_SSN;
            DstAddr.DPC = SCCP_Param.spc[DstAddr.NetID & 3];
        }
        else
        {
            pIntraMsg->cause = RT_NTFA;
            SccpCsta[SccpCstaInd].avail[1]++;
            if( ForceAnsi )
                return scrc_rf ( pIntraMsg, 1 );
            else
                return scrc_rf ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
        }
    }
    if( !CheckAvail ( &DstAddr ) )
    {
        pIntraMsg->cause = RT_SF;
        if( ForceAnsi )
            return scrc_rf ( pIntraMsg, 1 );
        else
            return scrc_rf ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }

    pIntraMsg->NetID = DstAddr.NetID % 4;       //0~3
    pIntraMsg->DPC = pAddr->DPC = DstAddr.DPC;
    LocalSPC = SCCP_Param.spc[pIntraMsg->NetID];

	if (pIntraMsg->CGA.RI == RI_SSN)
	{
		if (pIntraMsg->CGA.DPC == 0)
		{
			pIntraMsg->CGA.DPC = pIntraMsg->OPC;
		}
	}

	if (pIntraMsg->CGA.RI == RI_SSN)
	{
		if (pIntraMsg->CGA.DPC == 0)
		{
			pIntraMsg->CGA.DPC = pIntraMsg->OPC;
		}
	}

    if( DstAddr.DPC != LocalSPC )
    {
        snmpLogInfo ( "scrc_route(): start.... 266" );

		if (pIntraMsg->sequenceFlag == 1 && pIntraMsg->msgtype == UDT_MSG){
			pIntraMsg->SLS = get_sls(pIntraMsg->DPC);	//in-sequence delivery, add by Roy Jiang, 07-09-26
			pIntraMsg->msgclass = 1;
		}
        if( ForceAnsi )
            return send_msg ( pIntraMsg, 1 );
        else
            return send_msg ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }
    else if( pIntraMsg->msgtype == UDTS_MSG && pIntraMsg->msgsource == FROM_MTP)   //discast UDTS message to local node
        return 1;

    if( DstAddr.SSN == 0 )
    {
        pIntraMsg->cause = RT_UU;
        spLogDebug ( SCCPDB_ERR, "<013>Invalid SSN(0)" );
        SccpCsta[SccpCstaInd].error[2]++;
        if( ForceAnsi )
            return scrc_rf ( pIntraMsg, 1 );
        else
            return scrc_rf ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }

    if( DstAddr.SSN == 1 )      //scmg message
        return sclc2scmg ( pIntraMsg );

#ifdef _WXC_SPTEST_TEMP
    //just for test , delete it for normal
    if( pAddr->ip == INADDR_NONE && pIntraMsg->msgsource == FROM_MTP )
    {
        if( ( pIntraMsg->msgtype >= CR_MSG && pIntraMsg->msgtype <= AK_MSG )  )
        {
            if( ForceAnsi )
                return cr2co ( pIntraMsg, 1 );
            else
                return cr2co ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
        }
        else
        {
            if( MNP_Flag[0] == 0 || pIntraMsg->msgsource != FROM_MTP )  /* MNP not supported */
                return scrc2sclc ( pIntraMsg );

            /* SCCP Steering Function */
            /* message received or sent */
            /* MNP supported */
            /* routing method */
            pIntraMsg->msgMNP = 0;

            if( DstAddr.SSN == 6 && DstAddr.NP == 1 && pIntraMsg->data[0] == 0x62 )
            {
                /* IN_Based and SRI for voice call */
                if( MNP_Flag[0] == 1 && DstAddr.TT != 0 )
                {
                    pIntraMsg->msgMNP = 0;
                }
                else if( pIntraMsg->CGA.SSN != 10 )
                {
                    pIntraMsg->msgMNP = 1;
                }
                return scrc2sclc ( pIntraMsg );
            }
            else
            {
                return scrc2sclc ( pIntraMsg );
            }
        }
    }
#endif

    pAddr->ip = SelectIPOfSSN ( DstAddr.SSN, pIntraMsg->SLS, ( pIntraMsg->msgsource == FROM_MTP ) );

    if( pAddr->ip == SCCP_Param.ip )    //local Node

    {
        if( ( pIntraMsg->msgtype >= CR_MSG && pIntraMsg->msgtype <= AK_MSG )  )
        {
            if( ForceAnsi )
                return cr2co ( pIntraMsg, 1 );
            else
                return cr2co ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
        }
        else
        {
             if( sccp_send_netcap)
             {
                int len;
                up_message            MsgToMTP;
                int ansi_flag ;
                if( ForceAnsi )
                    ansi_flag = 1;
                else
                    ansi_flag = mtp3_ansiFlag(DstAddr.NetID);

                len = build_msg ( MsgToMTP.msgList, pIntraMsg, pIntraMsg->NetID  ,ansi_flag );
                MsgToMTP.len = len%256;
                NcSccpSend( MsgToMTP.msgList ,  MsgToMTP.len , (u8 *)pIntraMsg , ansi_flag);
            }


            if( MNP_Flag[0] == 0 || pIntraMsg->msgsource != FROM_MTP )  /* MNP not supported */
                return scrc2sclc ( pIntraMsg );

            /* SCCP Steering Function */
            /* message received or sent */
            /* MNP supported */
            /* routing method */
            pIntraMsg->msgMNP = 0;

            if( DstAddr.SSN == 6 && DstAddr.NP == 1 && pIntraMsg->data[0] == 0x62 )
            {
                /* IN_Based and SRI for voice call */
                if( MNP_Flag[0] == 1 && DstAddr.TT != 0 )
                {
                    pIntraMsg->msgMNP = 0;
                }
                else if( pIntraMsg->CGA.SSN != 10 )
                {
                    pIntraMsg->msgMNP = 1;
                }
                return scrc2sclc ( pIntraMsg );
            }
            else
            {
                return scrc2sclc ( pIntraMsg );
            }
        }
    }
    else if( pAddr->ip == 0 )   //none subsystem is reachable
    {
        pIntraMsg->cause = RT_SF;
        SccpCsta[SccpCstaInd].error[3]++;
        if( ForceAnsi )
            return scrc_rf ( pIntraMsg, 1 );
        else
            return scrc_rf ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }
    else                        //relay to specify subsystem
    {
        snmpLogInfo ( "scrc_route(): start... 327" );
        if( ForceAnsi )
            return send_msg ( pIntraMsg, 1 );
        else
            return send_msg ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }
}

int scrc_mnp_route ( Intra_Msg * pIntraMsg, BOOL ForceAnsi )
{
    SCCP_ADDR *pAddr = NULL, DstAddr;
    SCCP_ROUTE *pRoute = NULL;
    int LocalSPC;
    u_short nRoute = 0xFFFF;
    BYTE Num[32], NumLen;
    BYTE routeAI;
    BYTE field = 0;

    SccpCsta[SccpCstaInd].utilization[0]++;

    pAddr = &pIntraMsg->CDA;
    /* daniel */
    pAddr->AI = 1;              //default to include DPC
    pIntraMsg->CGA.AI = 1;      //default to include DPC
    /* daniel */
    memcpy ( &DstAddr, pAddr, sizeof ( SCCP_ADDR ) );

	if( pAddr->RI == RI_SSN && pAddr->DPC == 0 )
    {
        if( pAddr->NetID > 3 )
        {
            spLogDebug ( SCCPDB_ERR, "<021>SCCP Translation:SPC not available" );
            SccpCsta[SccpCstaInd].error[0]++;
            return -1;
        }
        DstAddr.DPC = SCCP_Param.spc[pAddr->NetID];
    }
    //Route On GT
    if( DstAddr.RI == RI_GT || DstAddr.DPC == 0 || DstAddr.SSN == 0 || DstAddr.NetID > 3 )
    {
        SccpCsta[SccpCstaInd].utilization[5 - 3]++;
        if( pIntraMsg->CDA.GTI == 0 )
        {
            pIntraMsg->cause = RT_NTFN;
            spLogDebug ( SCCPDB_ERR, "<021>SCCP Translation:GTI == 0 (4 is recommended)" );
            SccpCsta[SccpCstaInd].error[1]++;
            return -1;
        }
        /* if(pIntraMsg->CDA.TT != 0)
           {
           spLogDebug(SCCPDB_ERR, "<012>SCCP Translation:no translation for an address of such nature(TT=%d)", pIntraMsg->CDA.TT);
           pIntraMsg->cause = RT_NTFN;
           SccpCsta[SccpCstaInd].error[0] ++;
           return -1;
           } */

        if( pAddr->len > ( MAX_DIGITS * 2 ) )
        {
            SCCPCapBuf.watch_dog[0]++;
            sccp_put_capture_logs ( 01, ( BYTE * ) pIntraMsg, sizeof ( Intra_Msg ) );
            spLogDebug ( SCCPDB_ERR, "<024>SCCP Receive Invalid Message,GTT len=%d, the Message was discarded and captured", pAddr->len );
            return -2;
        }

        if( pAddr->NP > 0 )
            Num[field++] = pAddr->NP;
        else
            Num[field++] = NP_MSISDN;
        if( pAddr->TT > 0 )
        {
            Num[field++] = pAddr->TT / 100;
            Num[field++] = ( pAddr->TT / 10 ) % 10;
            Num[field++] = pAddr->TT % 10;
        }
        else
        {
            Num[field++] = TT_0;
            Num[field++] = TT_1;
            Num[field++] = TT_4;
        }
        NumLen = pAddr->len % ( MAX_DIGITS * 2 );
        Digits2Array ( Num + field, pAddr->GTAI, ( NumLen + 1 ) / 2 );
        nRoute = SelectRoute ( Num, NumLen + field );

        if( nRoute < SCCP_ROUTE_NUM )
        {
            pRoute = &RouteList[nRoute];

            if( DstAddr.NetID != pRoute->NetID )
                pIntraMsg->CGA.RI = RI_GT;
            /* daniel */
            else if( pIntraMsg->msgsource != FROM_MTP )
                pIntraMsg->CGA.RI = pRoute->RI;
            /* daniel */
            DstAddr.NetID = pRoute->NetID;

            if( pRoute->SSN > 0 )
                pAddr->SSN = DstAddr.SSN = pRoute->SSN;

            pAddr->RI = pRoute->RI;
            DstAddr.DPC = pRoute->DPC[0] * 0x10000 + pRoute->DPC[1] * 0x100 + pRoute->DPC[2];

            if( pRoute->convert )
            {
                DstAddr.RI = pAddr->RI;
                TranslateGT ( &DstAddr, pRoute );
                memcpy ( pAddr, &DstAddr, sizeof ( SCCP_ADDR ) );
            }

            /* daniel */
            routeAI = pRoute->AI;
            //set calling address
            if( pIntraMsg->CGA.RI == 0 )        //route on GT
            {
                if( ( routeAI & 1 ) == 0 )      //point code no need
                    pIntraMsg->CGA.AI &= ~1;    //set dpc=0
            }
            else                //route on DPC+SSN
            {
                if( ( routeAI & 4 ) == 0 )      //GT no need
                    pIntraMsg->CGA.GTI = 0;     //set GT=0
            }

            //set called address
            if( pAddr->RI == 0 )        //route on GT
            {
                if( ( routeAI & 1 ) == 0 )      //point code no need
                    pAddr->AI &= ~1;    //set dpc=0
            }
            else                //route on DPC+SSN
            {
                if( ( routeAI & 4 ) == 0 )      //GT no need
                    pAddr->GTI = 0;     //set GTI=0
            }
            /* daniel */

        }
        else if( nRoute >= 1024 && nRoute < 1024 + 256 )        //local Node
        {
            pAddr->SSN = DstAddr.SSN = nRoute - 1024;
            if( DstAddr.NetID > 3 )
                DstAddr.NetID = LocalSSN[DstAddr.SSN].NetID;

            pAddr->RI = RI_SSN;
            DstAddr.DPC = SCCP_Param.spc[DstAddr.NetID & 3];
        }
        else
        {
            pIntraMsg->cause = RT_NTFA;
            SccpCsta[SccpCstaInd].avail[1]++;
            if( ForceAnsi )
                return scrc_rf ( pIntraMsg, 1 );
            else
                return scrc_rf ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
        }
    }
    if( !CheckAvail ( &DstAddr ) )
    {
        pIntraMsg->cause = RT_SF;
        if( ForceAnsi )
            return scrc_rf ( pIntraMsg, 1 );
        else
            return scrc_rf ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }

    pIntraMsg->NetID = DstAddr.NetID % 4;       //0~3
    pIntraMsg->DPC = pAddr->DPC = DstAddr.DPC;
    LocalSPC = SCCP_Param.spc[pIntraMsg->NetID];

    if( DstAddr.DPC != LocalSPC )
    {
        snmpLogInfo ( "mnp_scrc_route(): start... 471" );

		if (pIntraMsg->sequenceFlag == 1 && pIntraMsg->msgtype == UDT_MSG){
			pIntraMsg->SLS = get_sls(pIntraMsg->DPC);	//in-sequence delivery, add by Roy Jiang, 07-09-26
		}

        if( ForceAnsi )
            return send_msg ( pIntraMsg, 1 );
        else
            return send_msg ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
        //snmpLogInfo ( "mnp_scrc_route(): end... 471" );
    }
    else if( pIntraMsg->msgtype == UDTS_MSG )   //discast UDTS message to local node
        return 1;

    if( DstAddr.SSN == 0 )
    {
        pIntraMsg->cause = RT_UU;
        spLogDebug ( SCCPDB_ERR, "<023>Invalid SSN(0)" );
        SccpCsta[SccpCstaInd].error[2]++;
        if( ForceAnsi )
            return scrc_rf ( pIntraMsg, 1 );
        else
            return scrc_rf ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }

    if( DstAddr.SSN == 1 )      //scmg message
        return sclc2scmg ( pIntraMsg );

    pAddr->ip = SelectIPOfSSN ( DstAddr.SSN, pIntraMsg->SLS, ( pIntraMsg->msgsource == FROM_MTP ) );

    pIntraMsg->msgMNP = 0;
    if( pAddr->ip == 0 )        //none subsystem is reachable
    {
        pIntraMsg->cause = RT_SF;
        SccpCsta[SccpCstaInd].error[3]++;
        if( ForceAnsi )
            return scrc_rf ( pIntraMsg, 1 );
        else
            return scrc_rf ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }
    else if( pAddr->ip == SCCP_Param.ip )       //local Node
    {
        if( pIntraMsg->msgtype == CR_MSG || ( DstAddr.SSN == SCCP_Param.CO_SSN && SCCP_Param.CO_SSN > 1 ) )
        {
            if( ForceAnsi )
                return cr2co ( pIntraMsg, 1 );
            else
                return cr2co ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
        }
        else
            return scrc2sclc ( pIntraMsg );
    }
    else                        //relay to specify subsystem
    {
        snmpLogInfo ( "scrc_route(): start... 327" );
        if( ForceAnsi )
            return send_msg ( pIntraMsg, 1 );
        else
            return send_msg ( pIntraMsg, mtp3_ansiFlag ( DstAddr.NetID ) );
    }
}

int send_msg ( Intra_Msg * pIntraMsg, BYTE ansi_flag )
//pass message to mtp module
{
    int retval = 0;
    int len = 0;
    up_message MsgToMTP;

    pIntraMsg->DPC = pIntraMsg->CDA.DPC;

    if( pIntraMsg->msgsource != FROM_MTP && ( pIntraMsg->SLS & 0x80 ) == 0 )
    {
        if( pIntraMsg->NetID > 3 )
        {
            return 0;
        }
        pIntraMsg->CGA.DPC = SCCP_Param.spc[pIntraMsg->NetID];
        pIntraMsg->OPC = SCCP_Param.spc[pIntraMsg->NetID];
    }

    snmpLogInfo ( "send_msg(), build_msg: start..." );

    if( pIntraMsg->msglen > 256 )
        return 0;
    len = build_msg ( MsgToMTP.msgList, pIntraMsg, pIntraMsg->NetID, ansi_flag );

    /*
       MsgToMTP.len  = build_msg ( MsgToMTP.msgList, pIntraMsg, pIntraMsg->NetID );
       if( MsgToMTP.len > 256 ) MsgToMTP.len is a BYTE
       {
       return 0;               //added by Pierre, 01-19-05 for core at following line
       }

     */

    //add for UDT SegmentingMsg to XUDT
    if( len < 272 && ( len + 8 ) > 0xfd && pIntraMsg->msgtype == UDT_MSG && pIntraMsg->msgsource == FROM_SCLC
        && pIntraMsg->CDA.ip != 0 && pIntraMsg->CDA.ip != SCCP_Param.ip && pIntraMsg->CDA.ip != INADDR_NONE )
    {                           //relay to special system msg too long ,need cut to segment -- add by lw 2007/03/20
        spLogDebug ( SCCPDB_UDT, "UDT Message form upper layer is too long, [ %d Bytes(len=%d if include MTP3)]! " "Need to be segmented!\r\n ", pIntraMsg->msglen, len );
        retval = SegmentingMsg ( pIntraMsg );
        return retval;
    }

    if( len >= 256 )
    {
        spLogDebug ( SCCPDB_ERR, "Build SCCP Message too long! " );
        return 0;
    }
    MsgToMTP.len = len % 256;
    snmpLogInfo ( "send_msg(), type message: start..." );
    switch ( pIntraMsg->msgsource )
    {
    case FROM_MTP:
        spShowMsg ( SCCPDB_STP, "SCCP ==> MTP3: STP", pIntraMsg );
        break;
    case FROM_SCLC:
        switch ( pIntraMsg->msgtype )
        {
        case UDT_MSG:
            SccpCsta[SccpCstaInd].quality[0]++;
            spShowMsg ( SCCPDB_UDT, "SCCP ==> MTP3:", pIntraMsg );
            break;
        case UDTS_MSG:
            SccpCsta[SccpCstaInd].quality[1]++;
            spShowMsg ( SCCPDB_UDT, "SCCP ==> MTP3:", pIntraMsg );
            break;
        case XUDT_MSG:         //add for UDT SegmentingMsg to XUDT
            spShowMsg ( SCCPDB_XUDT, "SCCP ==> MTP3:", pIntraMsg );
            break;
        case XUDTS_MSG:        //add for UDT SegmentingMsg to XUDT
            spShowMsg ( SCCPDB_XUDT, "SCCP ==> MTP3:", pIntraMsg );
            break;
        }
        break;
    case FROM_SCOC:
        spShowMsg ( SCCPDB_AIF, "SCCP ==> MTP3: AIF", pIntraMsg );
        break;
    case FROM_SCMG:
        spShowMsg ( SCCPDB_SCMG, "SCCP ==> MTP3: SCMG", pIntraMsg );
        break;
    }

    MsgToMTP.dest_ip = pIntraMsg->CDA.ip;
    MsgToMTP.dpc = pIntraMsg->DPC;
    MsgToMTP.opc = pIntraMsg->OPC;
    MsgToMTP.sio = pIntraMsg->NetID * 0x40 + 3;
    MsgToMTP.cic[0] = pIntraMsg->SLS & 0x0F;
    MsgToMTP.link = 0xff;

	if(pIntraMsg->redirectFlag == 1 && pIntraMsg->CDA.ip != 0xFFFFFFFF)	//add by Roy to support sccp dual server message redirect, 07-09-12
		retval = sccp_redirect ( &MsgToMTP );
	else
	    retval = sccp_to_mtp3 ( &MsgToMTP );

    if( sccp_send_netcap)
    {
        NcSccpSend( MsgToMTP.msgList ,  MsgToMTP.len , (u8 *)pIntraMsg , ansi_flag );
    }

    return retval;
    //      return sccp_to_mtp3(&MsgToMTP);                 //depend on mtp module
}

int scrc_rf ( Intra_Msg * pIntraMsg, BYTE AnsiFlag )
{
#ifdef _WXC_TEST
    WxcAssert ( 0, "routing fail" );
#endif
    if( isco ( pIntraMsg ) )
    {

        pIntraMsg->msgtype = SP_MSG_RF;
        cr2co ( pIntraMsg, AnsiFlag );
        spShowMsg ( SCCPDB_ERR, "<006>Route Failure", pIntraMsg );
        return -1;
    }
    else
        return sclc_rf ( pIntraMsg );
}

DWORD SelectIPOfSSN ( BYTE ssn, BYTE sls, BOOL from_mtp )
{
    LOCAL_SSN *pssn = &LocalSSN[ssn];

    switch ( pssn->status[0] )
    {
    case ST_Enable:
        switch ( pssn->status[1] )
        {
        case ST_Enable:
            if( pssn->local == 0 )
                return pssn->ip[sls & 0x01];
            else if( from_mtp )
                return pssn->ip[( pssn->local - 1 ) & 0x01];
            else if( ( sls & 0x80 ) == 0x80 )
                return pssn->ip[pssn->local & 0x01];
            else
                return pssn->ip[sls & 0x01];
            //break;
        default:
            if( ( sls & 0x80 ) == 0x80 && pssn->local == 1 )
            {
                spLogDebug ( SCCPDB_ERR, "<014>Message was refused by subsystem_%d_0 and subsystem_%d_1 inaccessible", ssn, ssn );
                return 0;
            }
            else
                return pssn->ip[0];
            //break;
        }
        //break;
    default:
        switch ( pssn->status[1] )
        {
        case ST_Enable:
            if( ( sls & 0x80 ) == 0x80 && pssn->local == 2 )
            {
                spLogDebug ( SCCPDB_ERR, "<015>Message was refused by subsystem_%d_1 and subsystem_%d_0 inaccessible", ssn, ssn );
                return 0;
            }
            else
                return pssn->ip[1];
            //break;
        default:
            spLogDebug ( SCCPDB_ERR, "<016>Subsystem_%d is inaccessible", ssn );

        }
    }

    return 0;

}


//sequence control functions -- add by Roy Jiang 2007-09-17
int get_sls(int dpc)
{
	static int pos = 0;		//end position of dpc2sls array
	static u8 next_sls = 0;	//sls for new dpc
	int i;

	for(i=0; i<pos; i++){
		if (dpc2sls[i].dpc == dpc){
			assert(dpc2sls[i].sls != 0xFF);
			return dpc2sls[i].sls;
		}
	}

	//add dpc to dpc2sls array
	if (pos >= 256)
		return next_sls;

	dpc2sls[i].dpc = dpc;
	dpc2sls[i].sls = next_sls;
	next_sls = (next_sls + 1) & 0x0F;
	pos++;

	return dpc2sls[i].sls;
}
//end of sequence control functions -- add by Roy Jiang 2007-09-17

