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

/*****************************************/
#include "./include/sccp.h"
/* =========== export ================ */
int build_msg ( BYTE * buf, Intra_Msg * intramsg, BYTE NetID, BYTE ansi_flag );
int parse_msg ( BYTE * buf, Intra_Msg * intramsg, int len, BYTE NetID, BYTE ansi_flag );

/* =========== private ================ */
static int parse_oparam ( BYTE * buf, int len, Intra_Msg * intramsg, BYTE NetID, BYTE ansi_flag );
static int encode_addr ( BYTE * buf, SCCP_ADDR * addr, BYTE NetID );
static int decode_addr ( BYTE * buf, SCCP_ADDR * addr, BYTE NetID );

/* ansi */
static int encode_addr_Ansi ( BYTE * buf, SCCP_ADDR * addr );
static int decode_addr_Ansi ( BYTE * buf, SCCP_ADDR * addr );

/* ansi */
//static int encode_int ( BYTE * buf, unsigned int val, BYTE len );
//static unsigned int decode_int ( BYTE * buf, BYTE len );

extern void spLogDebug ( DWORD mask, const char *fmt, ... );

/* by simon at 23/9/26 */
extern SCCP_Capture_Buf SCCPCapBuf;
extern DWORD SccpCstaInd;
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;

////////////////////////////////////////////////////////////

int build_msg ( BYTE * buf, Intra_Msg * intramsg, BYTE NetID, BYTE ansi_flag )
{
    int msglen = 0, vnum = 0, vlen = 0;

    buf[msglen++] = intramsg->msgtype;

    if( intramsg->msglen > 256 )
    {
        intramsg->msglen = 256;
    }

    switch ( intramsg->msgtype )
    {
    case CR_MSG:
        vnum = 1 + 1;
        memcpy ( buf + msglen, &intramsg->aSLR, 3 );    //SLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aSLR, 3 );       //SLR
        buf[msglen++] = intramsg->msgclass;     //protocol class
        /*Mandatory variable part */
        buf[msglen++] = vnum--; //pointer of CDA
        if( !ansi_flag )
            vlen += encode_addr ( buf + msglen + vnum + vlen, &( intramsg->CDA ), NetID );
        else
            vlen += encode_addr_Ansi ( buf + msglen + vnum + vlen, &( intramsg->CDA ) );

        buf[msglen++] = ( vnum-- ) + vlen;      //Pointer of optional part
        msglen += vlen;
        /*optional part */
        /*
           buf[msglen++] = P_CGA;                               //codes of CGA
           msglen += encode_addr(buf + msglen, &(intramsg->CGA), NetID); 
         */
        buf[msglen++] = P_Data;
        if( intramsg->msglen > 0 )
        {
            buf[msglen++] = intramsg->msglen;
            memcpy ( buf + msglen, intramsg->data, intramsg->msglen );
            msglen += intramsg->msglen;
        }
        buf[msglen++] = P_EOP;
        break;
    case CC_MSG:
        memcpy ( buf + msglen, &intramsg->aDLR, 3 );    //DLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aDLR, 3 );
        memcpy ( buf + msglen, &intramsg->aSLR, 3 );    //SLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aSLR, 3 );
        buf[msglen++] = intramsg->msgclass;
        buf[msglen++] = 1; // pointer ot end of optional
        buf[msglen++] = 0; // end of optional
        break;
    case CREF_MSG:
        memcpy ( buf + msglen, &intramsg->aDLR, 3 );    //DLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aDLR, 3 );
        buf[msglen++] = intramsg->cause;
        buf[msglen++] = 1; // pointer ot end of optional
        buf[msglen++] = 0; // end of optional
        break;
    case UDT_MSG:
        vnum = 3;
        buf[msglen++] = intramsg->msgclass;
        /*mandatory variable part */
        buf[msglen++] = vnum--; //pointer of CDA
        if( !ansi_flag )
            vlen += ( encode_addr ( buf + msglen + vnum + vlen, &( intramsg->CDA ), NetID ) % 64 );
        else
            vlen += ( encode_addr_Ansi ( buf + msglen + vnum + vlen, &( intramsg->CDA ) ) % 64 );

        buf[msglen++] = ( vnum-- ) + vlen;      //Pointer of CGA
        if( !ansi_flag )
            vlen += ( encode_addr ( buf + msglen + vnum + vlen, &( intramsg->CGA ), NetID ) % 64 );
        else
            vlen += ( encode_addr_Ansi ( buf + msglen + vnum + vlen, &( intramsg->CGA ) ) % 64 );

        buf[msglen++] = ( vnum-- ) + vlen;      //Pointer of Data
        buf[msglen + vnum + vlen] = intramsg->msglen;   //Length of Data
        memcpy ( buf + msglen + vnum + vlen + 1, intramsg->data, intramsg->msglen );
        vlen = vlen + intramsg->msglen + 1;

        msglen += vlen;
        break;
    case UDTS_MSG:
        vnum = 3;
        buf[msglen++] = intramsg->cause;
        /*mandatory variable part */
        buf[msglen++] = vnum--; //pointer of CDA
        if( !ansi_flag )
            vlen += ( encode_addr ( buf + msglen + vnum + vlen, &( intramsg->CDA ), NetID ) % 64 );
        else
            vlen += ( encode_addr_Ansi ( buf + msglen + vnum + vlen, &( intramsg->CDA ) ) % 64 );

        buf[msglen++] = ( vnum-- ) + vlen;      //Pointer of CGA
        if( !ansi_flag )
            vlen += ( encode_addr ( buf + msglen + vnum + vlen, &( intramsg->CGA ), NetID ) % 64 );
        else
            vlen += ( encode_addr_Ansi ( buf + msglen + vnum + vlen, &( intramsg->CGA ) ) % 64 );

        buf[msglen++] = ( vnum-- ) + vlen;      //Pointer of Data
        buf[msglen + vnum + vlen] = intramsg->msglen;   //Length of Data
        memcpy ( buf + msglen + vnum + vlen + 1, intramsg->data, intramsg->msglen );
        vlen = vlen + intramsg->msglen + 1;

        msglen += vlen;
        break;
    case XUDT_MSG:
        vnum = intramsg->SegPresent ? 4 : 3;
        buf[msglen++] = intramsg->msgclass;
        buf[msglen++] = intramsg->Hop;
        /*mandatory variable part */
        buf[msglen++] = vnum--; //pointer of CDA
        vlen += ( encode_addr ( buf + msglen + vnum + vlen, &( intramsg->CDA ), NetID ) % 64 );

        buf[msglen++] = ( vnum-- ) + vlen;      //Pointer of CGA
        vlen += ( encode_addr ( buf + msglen + vnum + vlen, &( intramsg->CGA ), NetID ) % 64 );

        buf[msglen++] = ( vnum-- ) + vlen;      //Pointer of Data
        buf[msglen + vnum + vlen] = intramsg->msglen;   //Length of Data
        memcpy ( buf + msglen + vnum + vlen + 1, intramsg->data, intramsg->msglen );
        vlen = vlen + intramsg->msglen + 1;

        if( intramsg->SegPresent )
        {
            buf[msglen++] = ( vnum-- ) + vlen;  //Pointer to Segmentation
            buf[msglen + vnum + vlen] = P_SEG;  //Segmentation tag
            buf[msglen + vnum + vlen + 1] = 4;  //Segmentation len
            memcpy ( buf + msglen + vnum + vlen + 2, &intramsg->Segmnt, 4 );
            msglen += 6;
        }
        msglen += vlen;
        break;
    case DT1_MSG:
        memcpy ( buf + msglen, &intramsg->aDLR, 3 );    //DLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aDLR, 3 );
        buf[msglen++] = intramsg->EOD;

        buf[msglen++] = 1;      //Pointer of Data
        buf[msglen++] = intramsg->msglen;       //Length of Data
        memcpy ( buf + msglen, intramsg->data, intramsg->msglen );
        msglen += intramsg->msglen;
        break;
    case DT2_MSG:
        memcpy ( buf + msglen, &intramsg->aDLR, 3 );    //DLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aDLR, 3 );
        buf[msglen++] = 2 * intramsg->PS;
        buf[msglen++] = 2 * intramsg->PR + intramsg->EOD;

        buf[msglen++] = 1;      //Pointer of Data
        buf[msglen++] = intramsg->msglen;       //Length of Data
        memcpy ( buf + msglen, intramsg->data, intramsg->msglen );
        msglen += intramsg->msglen;
        break;
    case RLSD_MSG:
        memcpy ( buf + msglen, &intramsg->aDLR, 3 );    //DLR
        msglen += 3;
        memcpy ( buf + msglen, &intramsg->aSLR, 3 );    //SLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aDLR, 3 );
        //msglen += encode_int ( buf + msglen, intramsg->aSLR, 3 );
        buf[msglen++] = intramsg->cause;
        buf[msglen++] = 1; // pointer ot end of optional
        buf[msglen++] = 0; // end of optional
        break;
    case RLC_MSG:
        memcpy ( buf + msglen, &intramsg->aDLR, 3 );    //DLR
        msglen += 3;
        memcpy ( buf + msglen, &intramsg->aSLR, 3 );    //SLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aDLR, 3 );
        //msglen += encode_int ( buf + msglen, intramsg->aSLR, 3 );
        break;
    case IT_MSG:
        memcpy ( buf + msglen, &intramsg->aDLR, 3 );    //DLR
        msglen += 3;
        memcpy ( buf + msglen, &intramsg->aSLR, 3 );    //SLR
        msglen += 3;
        //msglen += encode_int ( buf + msglen, intramsg->aDLR, 3 );
        //msglen += encode_int ( buf + msglen, intramsg->aSLR, 3 );
        buf[msglen++] = 2;	//class = 2
		buf[msglen++] = 0;	//Sequencing/segmenting octet 0
		buf[msglen++] = 0;	//Sequencing/segmenting	octet 1
		buf[msglen++] = 0;	//Credit
        break;
    }
    //buf[0] = msglen-1; 
    return msglen;
}

int parse_msg ( BYTE * buf, Intra_Msg * intramsg, int len, BYTE NetID, BYTE ansi_flag )
{
    int pos = 0;
    BYTE ptv, vlen;

    intramsg->msgtype = buf[pos++];
    switch ( intramsg->msgtype )
    {
    case CR_MSG:
        if( len < 4 )
            SCCPCapBuf.watch_dog[2]++;  //invalid CR message 

        memcpy ( &intramsg->aSLR, buf + pos, 3 );       //SLR
        pos += 3;
        //intramsg->aSLR = decode_int ( buf + pos, 3 );
        intramsg->msgclass = buf[pos++];

        ptv = pos + buf[pos];
        pos++;
        if( !ansi_flag )
            vlen = decode_addr ( buf + ptv, &( intramsg->CDA ), NetID );
        else
            vlen = decode_addr_Ansi ( buf + ptv, &( intramsg->CDA ) );

        if( vlen + ptv >= len )
            return 1;
        ptv = pos + buf[pos];
        pos++;
        parse_oparam ( buf + ptv, len - ptv, intramsg, NetID, ansi_flag );
        break;
    case CC_MSG:
        if( len < 8 )
            SCCPCapBuf.watch_dog[3]++;  //invalid CC message 

        memcpy ( &intramsg->aDLR, buf + pos, 3 );       //DLR
        pos += 3;
        memcpy ( &intramsg->aSLR, buf + pos, 3 );       //SLR
        pos += 3;
        //intramsg->aDLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        //intramsg->aSLR = decode_int ( buf + pos, 3 );
        //pos += 3;
		intramsg->msgclass = buf[pos++];
		
		ptv = pos + buf[pos];
/*		if (buf[ptv++] == 0x0F)
		{
			intramsg->msglen = buf[ptv++];
			memcpy ( intramsg->data, buf + ptv, intramsg->msglen );
		}
*/
		parse_oparam ( buf + ptv, len - ptv, intramsg, NetID, ansi_flag );
		break;
    case CREF_MSG:
        if( len < 5 )
            SCCPCapBuf.watch_dog[4]++;  //invalid CREF message 
        memcpy ( &intramsg->aDLR, buf + pos, 3 );       //DLR
        pos += 3;
        //intramsg->aDLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        intramsg->cause = buf[pos++];
		ptv = pos + buf[pos];
		parse_oparam ( buf + ptv, len - ptv, intramsg, NetID, ansi_flag );
        break;
    case UDT_MSG:
        if( len < 2 )
            SCCPCapBuf.watch_dog[5]++;  //invalid UDT message 

        intramsg->msgclass = buf[pos++];
        ptv = pos + buf[pos];
        pos++;
        if( !ansi_flag )
            vlen = decode_addr ( buf + ptv, &( intramsg->CDA ), NetID );
        else
            vlen = decode_addr_Ansi ( buf + ptv, &( intramsg->CDA ) );
        ptv = pos + buf[pos];
        pos++;
        if( !ansi_flag )
            vlen = decode_addr ( buf + ptv, &( intramsg->CGA ), NetID );
        else
            vlen = decode_addr_Ansi ( buf + ptv, &( intramsg->CGA ) );

        ptv = pos + buf[pos];
        pos++;
        intramsg->msglen = buf[ptv];
        memcpy ( intramsg->data, buf + ptv + 1, intramsg->msglen );
        break;
    case UDTS_MSG:
        if( len < 2 )
            SCCPCapBuf.watch_dog[6]++;  //invalid UDTs message 

        intramsg->cause = buf[pos++];
        ptv = pos + buf[pos];
        pos++;
        if( !ansi_flag )
            vlen = decode_addr ( buf + ptv, &( intramsg->CDA ), NetID );
        else
            vlen = decode_addr_Ansi ( buf + ptv, &( intramsg->CDA ) );
        ptv = pos + buf[pos];
        pos++;
        if( !ansi_flag )
            vlen = decode_addr ( buf + ptv, &( intramsg->CGA ), NetID );
        else
            vlen = decode_addr_Ansi ( buf + ptv, &( intramsg->CGA ) );

        ptv = pos + buf[pos];
        pos++;
        intramsg->msglen = buf[ptv];
        memcpy ( intramsg->data, buf + ptv + 1, intramsg->msglen );
        break;
    case XUDT_MSG:
        //if (len < 2)
        //      SCCPCapBuf.watch_dog[5]++;//invalid XUDT message 

        intramsg->msgclass = buf[pos++];
        intramsg->Hop = buf[pos++];
        ptv = pos + buf[pos];
        pos++;
        vlen = decode_addr ( buf + ptv, &( intramsg->CDA ), NetID );
        ptv = pos + buf[pos];
        pos++;
        vlen = decode_addr ( buf + ptv, &( intramsg->CGA ), NetID );

        if( vlen + ptv >= len )
            return 1;
        ptv = pos + buf[pos];
        pos = ptv;
        intramsg->msglen = buf[pos++];
        memcpy ( intramsg->data, buf + pos, intramsg->msglen );
        pos += intramsg->msglen;
        parse_oparam ( buf + pos, len - pos, intramsg, NetID, ansi_flag );
        break;
    case DT1_MSG:
        if( len < 5 )
            SCCPCapBuf.watch_dog[7]++;  //invalid DT1 message 

        memcpy ( &intramsg->aDLR, buf + pos, 3 );       //DLR
        pos += 3;
        //intramsg->aDLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        intramsg->EOD = buf[pos++];

        ptv = pos + buf[pos];
        pos++;
        intramsg->msglen = buf[ptv];
        memcpy ( intramsg->data, buf + ptv + 1, intramsg->msglen );
        break;
    case DT2_MSG:
        if( len < 7 )
            SCCPCapBuf.watch_dog[8]++;  //invalid DT2 message 
        memcpy ( &intramsg->aDLR, buf + pos, 3 );       //DLR
        pos += 3;
        //intramsg->aDLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        intramsg->PS = buf[pos++] / 2;
        intramsg->PR = buf[pos] / 2;
        intramsg->EOD = buf[pos++] % 2;

        ptv = pos + buf[pos];
        pos++;
        intramsg->msglen = buf[ptv];
        memcpy ( intramsg->data, buf + ptv + 1, intramsg->msglen );
        break;
    case RLSD_MSG:
        if( len < 8 )
            SCCPCapBuf.watch_dog[9]++;  //invalid RLSD message 
        memcpy ( &intramsg->aDLR, buf + pos, 3 );       //DLR
        pos += 3;
        memcpy ( &intramsg->aSLR, buf + pos, 3 );       //SLR
        pos += 3;
        //intramsg->aDLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        //intramsg->aSLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        intramsg->cause = buf[pos++];
        break;
    case RLC_MSG:
        if( len < 7 )
            SCCPCapBuf.watch_dog[10]++; //invalid RLC message 
        memcpy ( &intramsg->aDLR, buf + pos, 3 );       //DLR
        pos += 3;
        memcpy ( &intramsg->aSLR, buf + pos, 3 );       //SLR
        pos += 3;
        //intramsg->aDLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        //intramsg->aSLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        break;
    case IT_MSG:
        if( len < 8 )
            SCCPCapBuf.watch_dog[11]++; //invalid IT message 
        memcpy ( &intramsg->aDLR, buf + pos, 3 );       //DLR
        pos += 3;
        memcpy ( &intramsg->aSLR, buf + pos, 3 );       //SLR
        pos += 3;
        //intramsg->aDLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        //intramsg->aSLR = decode_int ( buf + pos, 3 );
        //pos += 3;
        intramsg->msgclass = buf[pos++];
        break;
    }
    return 1;
}

int parse_oparam ( BYTE * buf, int len, Intra_Msg * intramsg, BYTE NetID, BYTE ansi_flag )
{
    int pos = 0;
    BYTE nparam;

    while ( pos < len )
    {
        nparam = buf[pos++];
        switch ( nparam )
        {
        case P_EOP:
            return 1;
        case P_CDA:
            /*                      if (!ansi_flag)
               pos += decode_addr(buf + pos, &(intramsg->CDA), NetID); 
               else
               pos += decode_addr_Ansi(buf + pos, &(intramsg->CDA)); */
            break;
        case P_CGA:
            if( !ansi_flag )
                pos += decode_addr ( buf + pos, &( intramsg->CGA ), NetID );
            else
                pos += decode_addr_Ansi ( buf + pos, &( intramsg->CGA ) );
            break;
        case P_Data:
            intramsg->msglen = buf[pos++];
            memcpy ( intramsg->data, buf + pos, intramsg->msglen );
            pos += intramsg->msglen;
            break;
        case P_SEG:
            if( buf[pos] != 4 )
            {
                spLogDebug ( SCCPDB_USER, "SCCP XUDT Msg Segmentaion Parameters length error!" );
            }
            pos++;
            memcpy ( &intramsg->Segmnt, &buf[pos], 4 );
            intramsg->SegPresent = 1;
            pos += 4;
            break;
        case P_DLR:
        case P_SLR:
        case P_PLC:
        case P_EOD:
        case P_PR:
        case P_SEQ:
        case P_Credit:
        case P_RLC:
        case P_RTC:
        case P_RSC:
        case P_ERC:
        case P_RFC:
        case P_HC:
        case P_Importance:
        case P_Ldata:
            break;
        }
    }
    return 1;
}
/*
int encode_int ( BYTE * buf, unsigned int val, BYTE len )
{
    BYTE temp[4];

    temp[0] = ( BYTE ) ( ( val & 0xFF000000 ) >> 24 );
    temp[1] = ( BYTE ) ( ( val & 0xFF0000 ) >> 16 );
    temp[2] = ( BYTE ) ( ( val & 0xFF00 ) >> 8 );
    temp[3] = ( BYTE ) ( val & 0xFF );
    memcpy ( buf, temp + 4 - len, len );

    return len;
}

unsigned int decode_int ( BYTE * buf, BYTE len )
{
    unsigned int rtn = 0, i;

    for ( i = 0; i < len; i++ )
        rtn = rtn << 8 | buf[i];
    return rtn;
}
*/
int encode_addr ( BYTE * buf, SCCP_ADDR * addr, BYTE NetID )
{
    BYTE len = 0, cp_len;
    BYTE RI_MASK = 0x40, SSN_MASK = 0x02, DPC_MASK = 0x01, GT_MASK = 0x04;

     /*GTI*/ len = 2;
    //if(addr->RI == RI_SSN && addr->SSN > 0)
    //      addr->GTI = 0; 

    buf[1] = ( RI_MASK * addr->RI ) | ( SSN_MASK ) | ( DPC_MASK & ( addr->DPC > 0 ? 1 : 0 ) & ( addr->AI & 1 ) ) | ( GT_MASK * addr->GTI );

    if( ( addr->DPC > 0 ) & ( addr->AI & 1 ) )
    {
        memcpy ( buf + len, ( BYTE * ) & addr->DPC, SCCP_Param.spclen[NetID] );
        len += SCCP_Param.spclen[NetID];
    }
    buf[len++] = addr->SSN;
    switch ( addr->GTI )
    {
    case 0:                    //no global title included
        break;
    case 1:                    //global title includes nature of address indicator only
        buf[len++] = addr->NAI;
        memcpy ( buf + len, addr->GTAI, ( addr->len + 1 ) / 2 );
        len += ( addr->len + 1 ) / 2;

        break;
    case 2:                    //global title includes translation type only
        buf[len++] = addr->TT;
        memcpy ( buf + len, addr->GTAI, ( addr->len + 1 ) / 2 );
        len += ( addr->len + 1 ) / 2;
        break;
    case 3:                    //global title includes translation type, NP, EC
        buf[len++] = addr->TT;
        cp_len = ( addr->len + 1 ) / 2;
        if( addr->len & 1 )     //odd number of address signals
        {
            addr->ES = 1;
            addr->GTAI[cp_len - 1] = addr->GTAI[cp_len - 1] & 0x0F;
        }
        else
            addr->ES = 2;

        buf[len++] = addr->NP * 16 + addr->ES;
        addr->GTAI[len] = 0;
        memcpy ( buf + len, addr->GTAI, cp_len );
        len += cp_len;
        break;
    case 4:                    //global title includes translation type, NP, EC, NAI
        buf[len++] = addr->TT;

        addr->len %= 18;
        cp_len = ( addr->len + 1 ) / 2;
        if( addr->len & 1 )     //odd number of address signals
        {
            addr->ES = 1;
            addr->GTAI[cp_len - 1] = addr->GTAI[cp_len - 1] & 0x0F;
        }
        else
            addr->ES = 2;

        buf[len++] = addr->NP * 16 + addr->ES;
        buf[len++] = addr->NAI;
        memcpy ( buf + len, addr->GTAI, cp_len );
        len += cp_len;
        break;
    }
    buf[0] = len - 1;
    return len;
}

int decode_addr ( BYTE * buf, SCCP_ADDR * addr, BYTE NetID )
{
    BYTE len, pos, nbyte;
    BYTE RI_MASK = 0x40, SSN_MASK = 0x02, DPC_MASK = 0x01, GT_MASK = 0x3C;
    BYTE DPCI;

    len = buf[0] + 1;
    addr->RI = ( buf[1] & RI_MASK ) >> 6;
    addr->GTI = ( buf[1] & GT_MASK ) >> 2;
    DPCI = ( buf[1] & DPC_MASK );
    addr->SSN = ( buf[1] & SSN_MASK ) >> 1;
    pos = 2;
    if( DPCI )
    {
        memcpy ( ( BYTE * ) & addr->DPC, buf + pos, SCCP_Param.spclen[NetID] );
        pos += SCCP_Param.spclen[NetID];
    }
    if( addr->SSN )
        addr->SSN = buf[pos++];

    switch ( addr->GTI )
    {
    case 0:                    //no global title included
        break;
    case 1:                    //global title includes nature of address indicator only
        addr->NAI = buf[pos++] & 0x7F;
        nbyte = len - pos;
        addr->len = 2 * nbyte;
        if( ( buf[pos - 1] & 0x80 ) == 0x80 )   //odd number of address signals
            addr->len--;

        memcpy ( addr->GTAI, buf + pos, nbyte % ( MAX_DIGITS + 1 ) );
        break;
    case 2:                    //global title includes translation type only
        addr->TT = buf[pos++];
        nbyte = len - pos;
        addr->len = 2 * nbyte;
        memcpy ( addr->GTAI, buf + pos, nbyte % ( MAX_DIGITS + 1 ) );
        break;
    case 3:                    //global title includes translation type, NP, EC
        addr->TT = buf[pos++];
        addr->NP = buf[pos] / 16;
        addr->ES = buf[pos++] % 16;
        nbyte = len - pos;
        addr->len = 2 * nbyte;
        if( addr->ES == 1 )
            addr->len--;
        memcpy ( addr->GTAI, buf + pos, nbyte % ( MAX_DIGITS + 1 ) );
        break;
    case 4:                    //global title includes translation type, NP, EC, NAI
        addr->TT = buf[pos++];
        addr->NP = buf[pos] / 16;
        addr->ES = buf[pos++] % 16;
        addr->NAI = buf[pos++] & 0x7F;
        nbyte = len - pos;
        addr->len = 2 * nbyte;
        if( addr->ES == 1 )
            addr->len--;
        memcpy ( addr->GTAI, buf + pos, nbyte % ( MAX_DIGITS + 1 ) );
        break;
    }
    return len;
}

//----->ansi

int encode_addr_Ansi ( BYTE * buf, SCCP_ADDR * addr )
{
    BYTE len = 0, cp_len;
    BYTE NAT_MASK = 0x80, RI_MASK = 0x40, DPC_MASK = 0x02, SSN_MASK = 0x01, GT_MASK = 0x04;
    BYTE spclen = 3;            //ansi is always 24 bit,3 bytes

     /*GTI*/ len = 2;
    //if(addr->RI == RI_SSN && addr->SSN > 0)
    //      addr->GTI = 0; 

    switch ( addr->GTI )
    {
    case 4:
        addr->GTI = 2;
        break;
    default:
        break;
    }

    buf[1] = NAT_MASK | ( RI_MASK * addr->RI ) | ( SSN_MASK ) | ( DPC_MASK & ( ( addr->DPC > 0 ? 1 : 0 ) * 2 ) & ( ( addr->AI & 1 ) * 2 ) ) | ( GT_MASK * addr->GTI );

    buf[len++] = addr->SSN;

    if( addr->DPC > 0 && ( addr->AI & 1 ) )
    {
        /*              memcpy(buf + len, (BYTE *)&addr->DPC, SCCP_Param.spclen[NetID]); 
           len += SCCP_Param.spclen[NetID]; */
        memcpy ( buf + len, ( BYTE * ) & addr->DPC, spclen );
        len += spclen;
    }

    switch ( addr->GTI )
    {
    case 0:                    //no global title included
        break;
    case 1:                    //global title includes translation type, NP, EC
        buf[len++] = addr->TT;
        cp_len = ( addr->len + 1 ) / 2;
        if( addr->len & 1 )     //odd number of address signals
        {
            addr->ES = 1;
            addr->GTAI[cp_len - 1] = addr->GTAI[cp_len - 1] & 0x0F;
        }
        else
            addr->ES = 2;

        buf[len++] = addr->NP * 16 + addr->ES;
        addr->GTAI[len] = 0;
        memcpy ( buf + len, addr->GTAI, cp_len );
        len += cp_len;
        break;
    case 2:                    //global title includes translation type only
        buf[len++] = addr->TT;
        /* added by Pierre, 2006-09-30 for the filler */
        cp_len = ( addr->len + 1 ) / 2;
        if( addr->len & 1 )     //odd number of address signals
        {
            addr->GTAI[cp_len - 1] = addr->GTAI[cp_len - 1] & 0x0F;
        }
        /* above lines added by Pierre */

        memcpy ( buf + len, addr->GTAI, ( addr->len + 1 ) / 2 );
        len += ( addr->len + 1 ) / 2;
        break;
    default:
        break;
    }
    buf[0] = len - 1;
    return len;
}

int decode_addr_Ansi ( BYTE * buf, SCCP_ADDR * addr )
{
    BYTE len, pos, nbyte;
    BYTE RI_MASK = 0x40, DPC_MASK = 0x02, SSN_MASK = 0x01, GT_MASK = 0x3C;
    BYTE DPCI;
    BYTE spclen = 3;            //ansi is always 24 bit,3 bytes

    len = buf[0] + 1;
    addr->RI = ( buf[1] & RI_MASK ) >> 6;
    addr->GTI = ( buf[1] & GT_MASK ) >> 2;
    DPCI = ( buf[1] & DPC_MASK ) >> 1;
    addr->SSN = ( buf[1] & SSN_MASK );
    pos = 2;

    if( addr->SSN )
        addr->SSN = buf[pos++];
    if( DPCI )
    {
        /*              memcpy((BYTE *)&addr->DPC, buf + pos, SCCP_Param.spclen[NetID]); 
           pos += SCCP_Param.spclen[NetID]; */
        memcpy ( ( BYTE * ) & addr->DPC, buf + pos, spclen );
        pos += spclen;
    }

    switch ( addr->GTI )
    {
    case 0:                    //no global title included
        break;
    case 1:                    //global title includes translation type, NP, EC
        addr->TT = buf[pos++];
        addr->NP = buf[pos] / 16;
        addr->ES = buf[pos++] % 16;
        nbyte = len - pos;
        addr->len = 2 * nbyte;
        if( addr->ES == 1 )
            addr->len--;
        memcpy ( addr->GTAI, buf + pos, nbyte % ( MAX_DIGITS + 1 ) );
        break;
    case 2:                    //global title includes translation type only
        addr->TT = buf[pos++];
        nbyte = len - pos;
        addr->len = 2 * nbyte;
        memcpy ( addr->GTAI, buf + pos, nbyte % ( MAX_DIGITS + 1 ) );
        break;
    default:
        break;
    }
    return len;
}
