
/**********************************************/
/*Title:    sccp.c                            */
/*Descr:    SCCP common procedure             */
/*Author:   Liang Hanxi                       */
/*Create:   2002-2-19                         */
/*Modify:   2002-7-18                         */

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

#include "./include/sccp.h"

// fix multiple definition====================================
SCCP_OPT SCCP_Param;
SCOC_BUF ScocBuf;
LOCAL_SSN LocalSSN[256];
u8 ExistSSN[64];
u8 ExistSSNNum;

u8 MNP_Flag[2];
SCCP_ROUTE RouteList[SCCP_ROUTE_NUM];
SCCP_ACN_VER_TABLE acn_ver_table[SCCP_ROUTE_NUM];
int RelatedSSNNum;
RL_SSN RelatedSSN[SCCP_RLSSN_NUM];
int RelatedSPCNum;
RL_SPC RelatedSPC[SCCP_RLSPC_NUM];
GTTATT_OMC GTTAttribute[SCCP_ROUTE_NUM];
SCCP_CSTA SccpCsta[96];
u_long SccpCstaInd;
sccp_msg_statistic sccpmsg_st;
sccp_msg_rv_snd_statistic sccpmsg_rs_st;
SCCP_Capture_Buf SCCPCapBuf;
_dpc2sls dpc2sls[256];	//used for sequence control, add by Roy Jiang, 2007-09-17
//

extern BYTE sccpDebugFull;

ull SCCPSerialNumber;

/*===========export================*/
void sccp_reset (  );

/*===========import================*/
extern void scrc_timer ( void );
extern void sclc_timer ( void );
extern void sccpmib_init ( void );      //sccpmib.c
extern void sccp_sethb ( void );        //sccpmib.c
extern void spLogDebug_setup ( void );  //sccpdebug.c
extern void spLogDebug_timer ( void );  //sccpdebug.c
extern void spLogDebug_csta ( BYTE npage, int instance );       //sccpdebug.c
extern void spLogDebug_local ( BYTE npage, BYTE nline );
extern void localssn_timer ( void );    //scmg.c
extern void sst_timer ( void ); //scmg.c
extern int sccp_loadparam ( void );     //sccpparam.c
extern int BuildRouteIndex ( void );
extern int GetMSISDNOfSSN(BYTE ssn, BYTE *msisdn);
extern int sccp_GetSSNType(BYTE ssn);
extern void coInit( );
extern void coFsm( );
extern void coTimerMng (  );
extern int checkSccpSaveFlag();
extern void sccpDisableSaveFlag();
extern void sccp_saveparam();

/*===========private================*/
int CollectLocalInfo (  );
extern u32 dAlterIpBackup;	//for protection
void sccp_init ( u32 sysID, u32 localIP, u32 alterIP )
{
    long l_time;
    struct tm *t;
    static BYTE initonce = 0;
    int i;
    BYTE version[3] = SCCP_VERSION;

    if( initonce == 1 )
        return;
    memcpy ( SCCP_Param.version, version, 3 );
    SCCPSerialNumber = 0;
    sccp_reset (  );

    /*initialize global parameter */
	memset(dpc2sls, 0xFF, sizeof(dpc2sls));

    LocalSSN[1].ip[0] = INADDR_NONE;
    LocalSSN[1].status[0] = ST_Enable;

    for ( i = 0; i < 256; i++ )
        LocalSSN[i].RegFlag = 0;

    l_time = time ( NULL );
    t = localtime ( (time_t *)&l_time );
    if( t == NULL )
    {
    	assert( 0 && "syscall: localtime fail ");
    	exit(0);
    }
    SccpCstaInd = t->tm_hour * 4 + t->tm_min / 15;
    SccpCsta[SccpCstaInd].timestamp = l_time;

    coInit ( sysID, localIP, alterIP );
	dAlterIpBackup = alterIP;
    sccpmib_init (  );

    spLogDebug_setup (  );
    spLogDebug_csta ( 1, SccpCstaInd );

    printf ( "%ld-%d-%d %d:%d:%d\n", l_time, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec );
    printf ( "SCCP Version V%d.%d.%02d ...... Finish initialization!\n", SCCP_Param.version[0], SCCP_Param.version[1], SCCP_Param.version[2] );
    initonce = 1;
}

void sccp_init_serial_number ( BYTE * Serial )
{
    SCCPSerialNumber = Str2Ull ( (char *)Serial );
}

void sccp_timer (  )            //called per 10ms
{
    static WORD m_state = 0, seconds10=0,ch = 0;
    struct tm *t;
    long l_time;

    //      BYTE                            flag;

    //      flag = inb(0x0378);
    //      outb((flag | 0x04), 0x0378);

    //20ms task===>
    sccpDebugFull = 0;
    sclc_timer (  );
    scrc_timer (  );

    coFsm (  );

    spLogDebug_timer (  );


    coTimerMng();

    if( SCCP_Param.T_reset > 0 )
        SCCP_Param.T_reset--;
    else if( SCCP_Param.T_reset == 0 )
    {
        spLogDebug_local ( 2, 1 );
        BuildRouteIndex (  );
        CollectLocalInfo (  );

        SCCP_Param.T_reset = -1;
    }
    //10s task===>
    switch ( ( m_state++ ) % 500 )
    {
    case 0:                    //switch csta buffer
        l_time = time ( NULL );
        t = localtime ( (time_t *)&l_time );
        if( t == NULL )
        {
    	   assert( 0 && "syscall: localtime fail ");
    	   exit(0);
        }
        if( ch == 0 && t->tm_min % 15 == 0 )
        {
            SccpCstaInd = t->tm_hour * 4 + t->tm_min / 15;

            memset ( &SccpCsta[SccpCstaInd], 0, sizeof ( SCCP_CSTA ) );
            SccpCsta[SccpCstaInd].timestamp = l_time;

            spLogDebug_csta ( 1, SccpCstaInd );
            ch = 1;
        }
        if( t->tm_min % 15 != 0 )
            ch = 0;
        break;
    case 100:                  //SST
        sst_timer (  );
        break;
    case 200:
        sccp_sethb (  );
        break;
    case 300:
        localssn_timer (  );
        break;
    case 400:
        break;
    }
	if(seconds10++>1000)
	{
		seconds10 = 0;
		if(checkSccpSaveFlag())
		{
			sccp_saveparam (  );
			sccpDisableSaveFlag();
		}
	}
    //      outb(flag & 0xFB,0x0378);
}

void sccp_reset (  )
{
    DWORD oid[20] = { 1, 3, 6, 1, 4, 1, 1373, 2, 3, 2, 2, 2, 2, 1, 0 };//MTP3_OID
    BYTE msg[64];
    BYTE spclen, temp;
    int i, len;

    //get parameter from mtp3
    SCCP_Param.status = 2;

    if( get_response ( 14, oid, msg, &temp ) < 0 )
    {
        SCCP_Param.status = 0;
        return;
    }
    spclen = msg[0];
    SCCP_Param.spclen[0] = ( spclen & 0x01 ) == 0x01 ? 3 : 2;
    SCCP_Param.spclen[1] = ( spclen & 0x02 ) == 0x02 ? 3 : 2;
    SCCP_Param.spclen[2] = ( spclen & 0x04 ) == 0x04 ? 3 : 2;
    SCCP_Param.spclen[3] = ( spclen & 0x08 ) == 0x08 ? 3 : 2;

    oid[12] = 3;

    for ( i = 0; i < 4; i++ )
    {
           oid[13] = 1;
           oid[12] = 2+i;        
        if( ( len = get_response ( 14, oid, msg, &temp ) ) < 0 )
        {
            SCCP_Param.status = 0;
            return;
        }
        SCCP_Param.spc[i] = decode_integer ( msg, len );
	oid[13] = 2;	
        if( ( len = get_response ( 14, oid, msg, &temp ) ) < 0 )
        {
            SCCP_Param.status = 0;
            return;
        }
	SCCP_Param.spclen[i] = msg[0] == 0x01 ? 3 : 2;;	
    }

    SCCP_Param.OMCIP[0] = 0;
    SCCP_Param.OMCIP[1] = 0;

    sccp_loadparam (  );

    CollectLocalInfo (  );

    spLogDebug_local ( 2, 1 );
    BuildRouteIndex (  );
    SCCP_Param.T_reset = -1;
}

int AddToIpList ( DWORD ip, BYTE ssn )
{
    int i;

    if( ip == SCCP_Param.ip && ssn != 4 )
        return 0;
    for ( i = 0; i < ExistIPNum; i++ )
    {
        if( ExistIP[i] == ip )
            return 0;
    }
    ExistIP[ExistIPNum] = ip;
    ExistIPNum = ( ExistIPNum + 1 ) % 64;
    return 1;
}

int CollectLocalInfo (  )
{
    int i;
    BYTE RegNum = 0;

    SCCP_Param.OMCIP[0] = 0;
    SCCP_Param.OMCIP[1] = 0;
    ExistSSNNum = 0;
    ExistIPNum = 0;

    for ( i = 2; i < 256; i++ )
    {
        if( i != 4 )
        {
            if( LocalSSN[i].status[0] )
                AddToIpList ( LocalSSN[i].ip[0], i );
            else if( LocalSSN[i].status[1] == 0 )
                continue;
            if( LocalSSN[i].status[1] )
                AddToIpList ( LocalSSN[i].ip[1], i );
        }

        if( LocalSSN[i].RegFlag && LocalSSN[i].local )
        {
            LocalSSN[i].status[( LocalSSN[i].local - 1 ) % 2] = 3;
            SCCP_Param.RegSSN[RegNum] = i;
            RegNum = ( RegNum + 1 ) % 32;
        }
        ExistSSN[ExistSSNNum++] = i;
    }

    SCCP_Param.RegNum = RegNum;
    return 1;
}

/*int LocalSSN_ANSIFlag(BYTE SSN)
   {
   return LocalSSN[SSN].ANSIFlag;
   } */

int sccp_mnp_register ( BYTE flag, BYTE routing_method, BYTE usertype )
{
    MNP_Flag[0] = flag % 3;
    MNP_Flag[1] = routing_method % 3;
    return 1;
}

///////////////////////////////////////////////////////////////////////////
//                                                                      ///
//  spSetGttAddr                                                        ///
//     uGtType : 0 Setting by SSN                                       ///
//               1 Setting by GtNum [MSISDN]                            ///
//               2 Setting by GtNum [IMSI  ]                            ///
//                                                                      ///
///////////////////////////////////////////////////////////////////////////

int spSetGttAddr ( u8 uGtType , u8 uSSN, u8 *uGtNum , struct SCCP_ADDRESS *pSpAddr )
{
    int nFlag;

    pSpAddr->SSN   = uSSN;
    pSpAddr->DPC   = 0;    // set SCCP address
    pSpAddr->NetID = 4;    // dedicate by GT table
    pSpAddr->RI    = RI_GT;    // Routing by GT
    if(uSSN == 247)
	pSpAddr->RI = RI_SSN; //For IN-MNP
    pSpAddr->NAI   = 4;    //
	pSpAddr->ip    = 0;
	
    nFlag = sccp_GetSSNType ( uSSN );     //0=ITU,1=ANSI
	pSpAddr->ip = 0;

    if( nFlag == 1 )            //ANSI SCCP
    {
        if( uGtType < 2 )
        {
            pSpAddr->NP  = 0;   // MSISDN
	    if(uSSN == 6)
			pSpAddr->TT  = 14;
            else
			pSpAddr->TT  = 10;
        }
        else
        {
        	pSpAddr->NP  = 6;   // IMSI
        	pSpAddr->TT  = 9;
        }
        pSpAddr->GTI = 0x02;
    }
    else if( nFlag == 0 )       //ITU SCCP
    {
        pSpAddr->TT  = 0;
        if( uGtType < 2 )
        {
            pSpAddr->NP  = 1;   // MSISDN
        }
        else
        {
        	pSpAddr->NP  = 6;   // IMSI
        }
        pSpAddr->GTI = 0x04;
    }

    
    if( 0 == uGtType )
    {
    	u8  aGTT[ISDN_LEN];
    	
        if( GetMSISDNOfSSN ( uSSN, aGTT )  )
        {
        	u8  aISDN[ISDN_LEN];
        	
            GttToIsdn ( aISDN, aGTT );
            pSpAddr->len = IsdnToGtai( pSpAddr->GTAI ,aISDN );
            return pSpAddr->len;
        }
    }
    else if( 1 == uGtType )
    {
    	pSpAddr->len = IsdnToGtai ( pSpAddr->GTAI, uGtNum );
    	return pSpAddr->len;
    }
    else if( 2 == uGtType )
    {
    	ImsiNtoA( pSpAddr->GTAI , uGtNum);
    	pSpAddr->len = IMSI_LEN;
    	return pSpAddr->len;
    }
    return 0;
}

