
/************************************************************/
/*Title:   scmg.c                                           */
/*Descr:   SCCP Management                                  */
/*Author:  Liang Hanxi                                      */
/*Create:  2002-2-19                                        */
/*Modify:  2002-5-7                                         */

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

#include "./include/sccp.h"

/*===========export================*/
void localssn_timer (  );
void sst_timer (  );
int sclc2scmg ( Intra_Msg * intramsg );
BOOL CheckAvail ( SCCP_ADDR * addr );

/*===========import================*/
extern int scrc_route ( Intra_Msg * pIntraMsg, BOOL ForceAnsi );
extern int send_msg ( Intra_Msg * pIntraMsg, BYTE ansi_flag );
extern void sccp_sethb (  );
extern int CollectLocalInfo (  );
extern int AddToIpList ( DWORD ip, BYTE ssn );
extern void snmpLogInfo ( char *logInfo );
extern void spLogDebug ( DWORD mask, const char *fmt, ... );
/*===========private================*/
static BYTE ssn_status ( int spc, BYTE ssn, BYTE NetID );
void spac ( int spc, BYTE NetID );
void sppc ( int spc, BYTE NetID );
void spcc ( int spc, BYTE NetID );
static void ssac ( int spc, BYTE ssn, BYTE NetID, BOOL relay );
static void sscc ( int spc, BYTE ssn, BYTE NetID );
static void sspc ( int spc, BYTE ssn, BYTE NetID, BOOL relay );
static void lcst ( int spc, BYTE ssn, BYTE ntype, BYTE NetID );
static void bcst ( BYTE ssn, BYTE ntype );
static void bcst_relay ( int spc, BYTE ssn, BYTE ntype, BYTE NetID );
static int build_scmgmsg ( BYTE * intramsg, BYTE type, int spc, BYTE ssn, BYTE NetID );
static int parse_scmgmsg ( BYTE * data, BYTE * type, int *spc, BYTE * ssn, BYTE NetID );

/* by simon at 23/9/25 */
extern DWORD ExistIP[64];
extern DWORD ExistIPNum;
extern SCOC_BUF ScocBuf;
extern LOCAL_SSN LocalSSN[256];
extern u8 ExistSSN[64];
extern u8 ExistSSNNum;
extern struct _dpc2sls
{
    int dpc;
    u8 sls;
} dpc2sls[256]; // used for sequence control, add by Roy Jiang, 2007-09-17
extern SCCP_OPT SCCP_Param;
extern u8 MNP_Flag[2];
extern SCCP_ROUTE RouteList[SCCP_ROUTE_NUM];
extern int RelatedSSNNum;
extern RL_SSN RelatedSSN[SCCP_RLSSN_NUM];
extern int RelatedSPCNum;
extern RL_SPC RelatedSPC[SCCP_RLSPC_NUM];
extern GTTATT_OMC GTTAttribute[SCCP_ROUTE_NUM];
extern SCCP_CSTA SccpCsta[96];
extern DWORD SccpCstaInd;
extern SCCP_Capture_Buf SCCPCapBuf;

void localssn_timer (  )        //called per 1s
{
    int i;
    LOCAL_SSN *pSSN;

    for ( i = 0; i < ExistSSNNum; i++ )
    {
        pSSN = &LocalSSN[ExistSSN[i]];
        if( pSSN->status[0] == ST_Enable && pSSN->local != 1 && pSSN->timeout[0]-- <= 0 )
            pSSN->status[0] = ST_Disable;
        if( pSSN->status[1] == ST_Enable && pSSN->local != 2 && pSSN->timeout[1]-- <= 0 )
            pSSN->status[1] = ST_Disable;
    }
}

int sclc2scmg ( Intra_Msg * intramsg )
{
    BYTE *pmsg;
    BYTE ntype, ssn;
    int spc;
    BOOL relay = 0;

    intramsg->msgsource = FROM_SCMG;
    pmsg = intramsg->data;
    parse_scmgmsg ( intramsg->data, &ntype, &spc, &ssn, intramsg->NetID );

    snmpLogInfo ( "sclc2scmg (): start..." );

    spLogDebug ( SCCPDB_SCMG, "Receive %s Message.ssn=%d,src_spc=%X", ntype == SSA_MSG ? "SSA" : ( ntype == SSP_MSG ? "SSP" : ( ntype == SST_MSG ? "SST" : "SCMG" ) ), ssn, spc );
    switch ( ntype )
    {
    case SSA_MSG:
        //to enable subsystem
        SccpCsta[SccpCstaInd].avail[11]++;
        if( intramsg->OPC != SCCP_Param.spc[intramsg->NetID] && intramsg->CGA.DPC != SCCP_Param.spc[intramsg->NetID] )
        {
            lcst ( spc, ssn, SSA_MSG, intramsg->NetID );
            if( spc == intramsg->CGA.DPC )
                relay = 1;
        }
        ssac ( spc, ssn, intramsg->NetID, relay );

        break;
    case SSC_MSG:
        SccpCsta[SccpCstaInd].avail[7]++;
        sscc ( spc, ssn, intramsg->NetID );
        break;
    case SSP_MSG:
        SccpCsta[SccpCstaInd].avail[10]++;
        if( intramsg->OPC != SCCP_Param.spc[intramsg->NetID] && intramsg->CGA.DPC != SCCP_Param.spc[intramsg->NetID] )
        {
            lcst ( spc, ssn, SSP_MSG, intramsg->NetID );
            if( spc == intramsg->CGA.DPC )
                relay = 1;
        }
        sspc ( spc, ssn, intramsg->NetID, relay );

        break;
    case SST_MSG:
        if( LocalSSN[ssn].status[0] == ST_Enable || LocalSSN[ssn].status[1] == ST_Enable )
            pmsg[0] = SSA_MSG;
        else
            return 1;

        memcpy ( &intramsg->CDA, &intramsg->CGA, sizeof ( SCCP_ADDR ) );
        intramsg->CGA.DPC = SCCP_Param.spc[intramsg->NetID];
        intramsg->CGA.GTI = 0;
        intramsg->CGA.SSN = 1;
        intramsg->CGA.RI = RI_SSN;
        intramsg->CGA.len = 0;

        spLogDebug ( SCCPDB_SCMG, "Send %s Message.ssn=%d,dst_spc=%X", ( pmsg[0] == SSA_MSG ) ? "SSA" : ( ( pmsg[0] == SSP_MSG ) ? "SSP" : "SSC" ), ssn, intramsg->CDA.DPC );
        send_msg ( intramsg, mtp3_ansiFlag ( intramsg->NetID ) );
        break;
    case SOR_MSG:
        //to send SOG
        pmsg[0] = SOG_MSG;      //to send SOG
        memcpy ( &intramsg->CDA, &intramsg->CGA, sizeof ( SCCP_ADDR ) );
        scrc_route ( intramsg, 0 );
        break;
    case SOG_MSG:
        //to disable local subsystem
        break;
    }
    snmpLogInfo ( "sclc2scmg (): end..." );
    return 1;
}

BOOL CheckAvail ( SCCP_ADDR * addr )
{
    BYTE status;

    status = ssn_status ( addr->DPC, addr->SSN, addr->NetID );
    if( status == ST_Disable )
    {
        spLogDebug ( SCCPDB_ERR, "<009>Subsystem Failure.NetID=%d,SPC=%x,SSN=%d", addr->NetID, addr->DPC, addr->SSN );
        SccpCsta[SccpCstaInd].error[4]++;
        return 0;
    }
    else if( status == ST_Congest )
    {
        spLogDebug ( SCCPDB_ERR, "<010>Subsystem Congest.NetID=%d,SPC=%x,SSN=%d", addr->NetID, addr->DPC, addr->SSN );
        SccpCsta[SccpCstaInd].error[5]++;
        return 0;
    }
    //else if(sccp_status(addr->DPC,addr->NetID)==ST_Disable)
    //      return 0;
    else
        return 1;
}

BYTE ssn_status ( int spc, BYTE ssn, BYTE NetID )
//related subsystem
{
    int i;

    for ( i = 0; i < RelatedSSNNum; i++ )
    {
        if( RelatedSSN[i].status == 0 )
            continue;
        if( RelatedSSN[i].DPC != spc || RelatedSSN[i].SSN != ssn || RelatedSSN[i].NetID != NetID )
            continue;

        return RelatedSSN[i].status;
    }
    return ST_Enable;
}

/////////////////////////
/*SPAC Module----------> */
/////////////////////////
void spac ( int spc, BYTE NetID )
{
    int i, j;

    for ( i = 0; i < RelatedSPCNum; i++ )
    {
        if( spc == RelatedSPC[i].DPC && NetID == RelatedSPC[i].NetID )
        {
            RelatedSPC[i].status = ST_Enable;
            for ( j = 0; j < RelatedSSNNum; j++ )
            {
                if( RelatedSSN[j].status == 0 )
                    continue;
                if( spc == RelatedSSN[j].DPC && NetID == RelatedSSN[j].NetID )
                {
                    if( RelatedSPC[i].status == ST_Disable )
                        RelatedSSN[j].SST = 1;
                    RelatedSSN[j].status = ST_Enable;
                }
            }
        }
    }

}

/////////////////////////
/*SPPC Module----------> */
/////////////////////////
void sppc ( int spc, BYTE NetID )
{
    int i, j;

    for ( i = 0; i < RelatedSPCNum; i++ )
    {
        if( spc == RelatedSPC[i].DPC && NetID == RelatedSPC[i].NetID )
        {
            RelatedSPC[i].status = ST_Disable;
            for ( j = 0; j < RelatedSSNNum; j++ )
            {
                if( RelatedSSN[j].status == 0 )
                    continue;
                if( spc == RelatedSSN[j].DPC && NetID == RelatedSSN[j].NetID )
                {
                    RelatedSSN[j].SST = 0;
                    RelatedSSN[j].status = ST_Disable;
                }
            }
        }
    }

}

/////////////////////////
/*SPCC Module----------> */
/////////////////////////
void spcc ( int spc, BYTE NetID )
{
    int i;

    for ( i = 0; i < RelatedSPCNum; i++ )
    {
        if( spc == RelatedSSN[i].DPC && NetID == RelatedSSN[i].NetID )
            RelatedSSN[i].status = ST_Congest;
    }
}

/////////////////////////
/*SSAC Module----------> */
/////////////////////////

int register_ssn ( BYTE ssn, BYTE usertype )    //enable local subsystem
{
    BYTE localindex = LocalSSN[ssn].local % 3;

    LocalSSN[ssn].RegFlag = 1;
    if( localindex > 0 )
    {
        CollectLocalInfo (  );
        LocalSSN[ssn].status[localindex - 1] = ST_Enable;
    }
    else
    {
        printf ( "Subsystem %d not equiped.check your GTT Table.\n", ssn );
        return 0;
    }

    if( usertype == 3 )
        SCCP_Param.CO_SSN = ssn;

    SccpCsta[SccpCstaInd].avail[8]++;
    LocalSSN[ssn].nbuf = usertype % 4;
    if( LocalSSN[ssn].nbuf == 3 )
        SCCP_Param.CO_SSN = ssn;
    bcst ( ssn, SSA_MSG );

    return 1;
}

void ssac ( int spc, BYTE ssn, BYTE NetID, BOOL relay ) //enable remote subsystem
{
    int i;

    for ( i = 0; i < RelatedSSNNum; i++ )
    {
        if( RelatedSSN[i].status == 0 )
            continue;
        if( RelatedSSN[i].DPC != spc || RelatedSSN[i].SSN != ssn || RelatedSSN[i].NetID != NetID )
            continue;

        if( RelatedSSN[i].status == ST_Disable && relay )       //Disable->Enable
            bcst_relay ( spc, ssn, SSA_MSG, NetID );
        RelatedSSN[i].SST = 0;
        RelatedSSN[i].status = ST_Enable;

    }
}

void sscc ( int spc, BYTE ssn, BYTE NetID )     //enable remote subsystem
{
    int i;

    for ( i = 0; i < RelatedSSNNum; i++ )
    {
        if( RelatedSSN[i].status == 0 )
            continue;
        if( RelatedSSN[i].DPC != spc || RelatedSSN[i].SSN != ssn || RelatedSSN[i].NetID != NetID )
            continue;

        RelatedSSN[i].status = ST_Congest;
    }
}

/////////////////////////
/*SSPC Module----------> */
/////////////////////////
int stop_ssn ( BYTE ssn )       //disable local subsystem
{
    BYTE localindex = LocalSSN[ssn].local % 3;
    int i;

    LocalSSN[ssn].RegFlag = 0;
    spLogDebug ( SCCPDB_SCMG, "Disable local subsystem. ssn=%d", ssn );

    if( localindex > 0 )
    {
        CollectLocalInfo (  );
        /* add by daniel on 2005-9-15 */
        for ( i = 0; i <= 1; i++ )
        {
            if( SCCP_Param.OMCIP[i] > 0 )
                AddToIpList ( SCCP_Param.OMCIP[i], ssn );
        }
        /* add by daniel on 2005-9-15 */
        LocalSSN[ssn].status[localindex - 1] = ST_Disable;
    }
    else
        return -1;

    sccp_sethb (  );
    SccpCsta[SccpCstaInd].avail[9]++;
    bcst ( ssn, SSP_MSG );
    return 1;
}

void sspc ( int spc, BYTE ssn, BYTE NetID, BOOL relay ) //disable remote subsystem
{
    int i;

    for ( i = 0; i < RelatedSSNNum; i++ )
    {
        if( RelatedSSN[i].status == 0 )
            continue;
        if( RelatedSSN[i].DPC != spc || RelatedSSN[i].SSN != ssn || RelatedSSN[i].NetID != NetID )
            continue;

        if( RelatedSSN[i].status == ST_Enable ) //Enable->Disable
        {
            RelatedSSN[i].timeout = T_sst;
            RelatedSSN[i].SST = 1;
            if( relay )
                bcst_relay ( spc, ssn, SSP_MSG, NetID );
        }

        RelatedSSN[i].status = ST_Disable;
    }
}

/////////////////////////
/*SSTC Module----------> */
/////////////////////////
void sst_timer (  )
{
    Intra_Msg outmsg;
    RL_SSN *pSSN;
    int i;

    for ( i = 0; i < RelatedSSNNum; i++ )
    {
        pSSN = &RelatedSSN[i];
        if( !pSSN->SST )
            continue;
        if( pSSN->timeout-- > 0 )
            continue;
        if( pSSN->DPC == SCCP_Param.spc[pSSN->NetID] )
            continue;

        outmsg.msgtype = UDT_MSG;
        outmsg.msgsource = FROM_SCMG;

        outmsg.CGA.DPC = SCCP_Param.spc[pSSN->NetID];
        outmsg.CGA.SSN = 1;
        outmsg.CGA.GTI = 0;
        outmsg.CGA.RI = RI_SSN;
        outmsg.CGA.len = 0;

        outmsg.CDA.DPC = pSSN->DPC;
        outmsg.CDA.SSN = 1;     //SCMG
        outmsg.CDA.GTI = 0;     //No GT
        outmsg.CDA.RI = 1;
        outmsg.CDA.len = 0;

        outmsg.NetID = pSSN->NetID;

        outmsg.CDA.ip = INADDR_NONE;

        outmsg.msglen = build_scmgmsg ( outmsg.data, SST_MSG, pSSN->DPC, pSSN->SSN, pSSN->NetID );
        spLogDebug ( SCCPDB_SCMG, "SST spc=%X,ssn=%d", pSSN->DPC, pSSN->SSN );
        send_msg ( &outmsg, mtp3_ansiFlag ( pSSN->NetID ) );
        pSSN->timeout = T_sst;
    }
}

/////////////////////////
/*LCST Module----------> */
/////////////////////////

void lcst ( int spc, BYTE ssn, BYTE ntype, BYTE NetID )
{
    Intra_Msg outmsg;
    int i;

    spLogDebug ( SCCPDB_SCMG, "Start Local Broatcast.spc=%X,ssn=%d,ntype=%d", spc, ssn, ntype );
    outmsg.msgtype = UDT_MSG;
    outmsg.msgsource = FROM_SCMG;
    outmsg.CGA.SSN = 1;
    outmsg.CGA.GTI = 0;
    outmsg.CGA.len = 0;
    outmsg.CGA.RI = 1;
    outmsg.CGA.DPC = SCCP_Param.spc[NetID];
    outmsg.CDA.GTI = 0;
    outmsg.NetID = outmsg.CDA.NetID = outmsg.CGA.NetID = NetID;

    outmsg.CDA.DPC = SCCP_Param.spc[NetID];
    outmsg.CDA.SSN = 1;
    outmsg.CDA.RI = 1;
    outmsg.CDA.len = 0;

    outmsg.msglen = build_scmgmsg ( outmsg.data, ntype, spc, ssn, NetID );

    for ( i = 2; i < 256; i++ )
    {
        if( LocalSSN[i].status[0] > 0 && LocalSSN[i].local != 1 )
        {
            outmsg.CDA.ip = LocalSSN[i].ip[0];
            send_msg ( &outmsg, mtp3_ansiFlag ( NetID ) );
        }
        if( LocalSSN[i].status[1] > 0 && LocalSSN[i].local != 2 )
        {
            outmsg.CDA.ip = LocalSSN[i].ip[1];
            send_msg ( &outmsg, mtp3_ansiFlag ( NetID ) );
        }
    }
}

/////////////////////////
/*BCST Module----------> */
/////////////////////////
void bcst ( BYTE ssn, BYTE ntype )
{
    Intra_Msg outmsg;
    int i;

    spLogDebug ( SCCPDB_SCMG, "Start Remote Broadcase ssn=%d,ntype=%d", ssn, ntype );
    outmsg.msgtype = UDT_MSG;
    outmsg.msgsource = FROM_SCMG;
    outmsg.CDA.GTI = 0;
    for ( i = 0; i < RelatedSPCNum; i++ )
    {
        if( RelatedSPC[i].status != ST_Enable )
            continue;
        outmsg.CGA.SSN = 1;
        outmsg.CGA.GTI = 0;
        outmsg.CGA.len = 0;
        outmsg.CGA.RI = 1;
        outmsg.CGA.DPC = SCCP_Param.spc[RelatedSPC[i].NetID];
        outmsg.CDA.ip = INADDR_NONE;
        outmsg.CDA.DPC = RelatedSPC[i].DPC;
        outmsg.CDA.SSN = 1;
        outmsg.CDA.RI = 1;
        outmsg.CDA.len = 0;
        outmsg.NetID = outmsg.CDA.NetID = outmsg.CGA.NetID = RelatedSPC[i].NetID;

        outmsg.msglen = build_scmgmsg ( outmsg.data, ntype, SCCP_Param.spc[outmsg.NetID], ssn, outmsg.NetID );
        send_msg ( &outmsg, mtp3_ansiFlag ( outmsg.NetID ) );
    }
}

void bcst_relay ( int spc, BYTE ssn, BYTE ntype, BYTE NetID )
{
    Intra_Msg outmsg;
    int i;

    spLogDebug ( SCCPDB_SCMG, "relay Broadcase spc:%X,ssn%d,ntype:%d", spc, ssn, ntype );
    outmsg.msgtype = UDT_MSG;
    outmsg.msgsource = FROM_SCMG;
    outmsg.CDA.GTI = 0;
    outmsg.CGA.SSN = 1;
    outmsg.CGA.GTI = 0;
    outmsg.CGA.len = 0;
    outmsg.CGA.RI = 1;
    outmsg.NetID = outmsg.CGA.NetID = outmsg.CDA.NetID = NetID;
    for ( i = 0; i < RelatedSPCNum; i++ )
    {
        if( NetID != RelatedSPC[i].NetID )
            return;
        if( RelatedSPC[i].status == ST_Disable || spc == RelatedSPC[i].DPC )
            continue;

        outmsg.CGA.DPC = SCCP_Param.spc[RelatedSPC[i].NetID];
        outmsg.CDA.ip = INADDR_NONE;
        outmsg.CDA.DPC = RelatedSPC[i].DPC;
        outmsg.CDA.SSN = 1;
        outmsg.CDA.RI = 1;
        outmsg.CDA.len = 0;

        outmsg.msglen = build_scmgmsg ( outmsg.data, ntype, spc, ssn, NetID );
        send_msg ( &outmsg, mtp3_ansiFlag ( NetID ) );
    }
}

int build_scmgmsg ( BYTE * data, BYTE type, int spc, BYTE ssn, BYTE NetID )
{
    int pos = 0;

    data[pos++] = type;
    data[pos++] = ssn;
    memcpy ( data + pos, ( BYTE * ) & spc, SCCP_Param.spclen[NetID] );
    pos += SCCP_Param.spclen[NetID];
    data[pos++] = 0;
    if( type == SSC_MSG )
        data[pos++] = 0;
    return pos;
}

int parse_scmgmsg ( BYTE * data, BYTE * type, int *spc, BYTE * ssn, BYTE NetID )
{
    int pos = 0;

    *type = data[pos++];
    *ssn = data[pos++];
    *spc = 0;
    memcpy ( ( BYTE * ) spc, data + pos, SCCP_Param.spclen[NetID] );
    pos += SCCP_Param.spclen[NetID];
    return 1;
}
