/***********************************************************
Copyright (C), LGC Wireless.
File Name:		isdn_rm.c
Description:	ISDN Resource Management
Version:		v9.0.0
Author:			Gengxin Chen
Create Date:	2008-2-19
History:
	<author>	<date>		<version>		<desc>
	
************************************************************/
#include "./include/isdn_const.h"
#include "../../m2ua/src/include/m2ua_const.h"
#include "./include/isdn_rm.h"
#include "./include/isdn_debug.h"
#include "./include/isdn_ext.h"
#include "./include/isdn_inc.h"


extern void isdn_cpc_proc(u32 pid);
extern void service_bc_proc(u32 pid);
extern void service_dc_proc(u32 pid);
extern void isdn_restart_ctrl(u32 pid);
extern int isdn_rel_proc(u32 pid, u32 cause);
extern int rel_cr(u32 pid);
extern inline void isdn_cpc_clear(ISDN_Port_struct *pPort);
extern int isdn_event_handle(u32 pid, u8 primitive);
extern void isdn_set_cause(CauseStr *cause_ptr, u8 val);
extern void isdn_set_status(IsdnStatus *status_ptr, u8 state, u8 cause_val);
//msc
extern int msc_give_cic_value(u32 tg_id, int head_cic);

static int isdn_encode_alert(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnAlert *ptr = &src->msg_list.alert;
	u8 *flw_ptr = dst;

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->br_cap.pres == 1)
		{
			flw_ptr[0] = IE_BR_CAP;
			flw_ptr[1] = itu_encode_br_cap(flw_ptr+2, &ptr->br_cap);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	if(ptr->chnl_id.pres == 1)
	{
		flw_ptr[0] = IE_CHNL_ID;
		if(variant == VARIANT_QSIG)
			flw_ptr[1] = qsig_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		else
			flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(ptr->prg_ind.pres == 1)
	{
		flw_ptr[0] = IE_PRG_IND;
		flw_ptr[1] = isdn_encode_prg_ind(flw_ptr+2, &ptr->prg_ind);
		flw_ptr += flw_ptr[1] + 2;
	}
	
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->hl_comp.pres == 1)
		{
			flw_ptr[0] = IE_HL_COMP;
			flw_ptr[1] = isdn_encode_hl_comp(flw_ptr+2, &ptr->hl_comp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	return flw_ptr - dst;
}

int isdn_decode_alert(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnAlert *ptr = &dst->msg_list.alert;
	u8 *flw_ptr = src;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			break;
		}
		switch(*flw_ptr)
		{
			case IE_BR_CAP:
				if(variant == VARIANT_ITU)
					itu_decode_br_cap(&ptr->br_cap, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CHNL_ID:
				if(variant == VARIANT_QSIG)
					qsig_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				else
					isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_PRG_IND:
				isdn_decode_prg_ind(&ptr->prg_ind, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_HL_COMP:
				if(variant == VARIANT_ITU)
					isdn_decode_hl_comp(&ptr->hl_comp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}

	return ISDN_CM_OK;
}

static int isdn_encode_call_proc(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnCallProc *ptr = &src->msg_list.callProc;
	u8 *flw_ptr = dst;

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->br_cap.pres == 1)
		{
			flw_ptr[0] = IE_BR_CAP;
			flw_ptr[1] = itu_encode_br_cap(flw_ptr+2, &ptr->br_cap);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	//if(ptr->chnl_id.pres == 1)
	{
		flw_ptr[0] = IE_CHNL_ID;
		if(variant == VARIANT_QSIG)
			flw_ptr[1] = qsig_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		else
			flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		flw_ptr += flw_ptr[1] + 2;
	}

	if(variant == VARIANT_ITU)
	{
		if(ptr->prg_ind.pres == 1)
		{
			flw_ptr[0] = IE_PRG_IND;
			flw_ptr[1] = isdn_encode_prg_ind(flw_ptr+2, &ptr->prg_ind);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->hl_comp.pres == 1)
		{
			flw_ptr[0] = IE_HL_COMP;
			flw_ptr[1] = isdn_encode_hl_comp(flw_ptr+2, &ptr->hl_comp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;	
}

int isdn_decode_call_proc(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnCallProc *ptr = &dst->msg_list.callProc;
	u8 *flw_ptr = src;
	u8 ie_m = 0;
	int ret = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_BR_CAP:
				if(variant == VARIANT_ITU)
					itu_decode_br_cap(&ptr->br_cap, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CHNL_ID:		//M
				if(variant == VARIANT_QSIG)
					ret = qsig_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				else
					ret = isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				if(!ret)
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_PRG_IND:
				if(variant == VARIANT_ITU)
					isdn_decode_prg_ind(&ptr->prg_ind, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_HL_COMP:
				if(variant == VARIANT_ITU)
					isdn_decode_hl_comp(&ptr->hl_comp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 1)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_conn(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnConn *ptr = &src->msg_list.conn;
	u8 *flw_ptr = dst;

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->br_cap.pres == 1)
		{
			flw_ptr[0] = IE_BR_CAP;
			flw_ptr[1] = itu_encode_br_cap(flw_ptr+2, &ptr->br_cap);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	if(ptr->chnl_id.pres == 1)
	{
		flw_ptr[0] = IE_CHNL_ID;
		if(variant == VARIANT_QSIG)
			flw_ptr[1] = qsig_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		else
			flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(ptr->prg_ind.pres == 1)
	{
		flw_ptr[0] = IE_PRG_IND;
		flw_ptr[1] = isdn_encode_prg_ind(flw_ptr+2, &ptr->prg_ind);
		flw_ptr += flw_ptr[1] + 2;
	}

	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->dt_time.pres == 1)
		{
			flw_ptr[0] = IE_DT_TIME;
			flw_ptr[1] = isdn_encode_dt_time(flw_ptr+2, &ptr->dt_time);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->ll_comp.pres == 1)
		{
			flw_ptr[0] = IE_LL_COMP;
			flw_ptr[1] = isdn_encode_ll_comp(flw_ptr+2, &ptr->ll_comp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->hl_comp.pres == 1)
		{
			flw_ptr[0] = IE_HL_COMP;
			flw_ptr[1] = isdn_encode_hl_comp(flw_ptr+2, &ptr->hl_comp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	else if(variant == VARIANT_QSIG)
	{
		if(ptr->conn_num.pres == 1)
		{
			flw_ptr[0] = IE_CONN_NUM;
			flw_ptr[1] = qsig_encode_conn_num(flw_ptr+2, &ptr->conn_num);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->ll_comp.pres == 1)
		{
			flw_ptr[0] = IE_LL_COMP;
			flw_ptr[1] = isdn_encode_ll_comp(flw_ptr+2, &ptr->ll_comp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_conn(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnConn *ptr = &dst->msg_list.conn;
	u8 *flw_ptr = src;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			break;
		}
		switch(*flw_ptr)
		{
			case IE_BR_CAP:
				if(variant == VARIANT_ITU)
					itu_decode_br_cap(&ptr->br_cap, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CHNL_ID:
				if(variant == VARIANT_QSIG)				
					qsig_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				else
					isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_PRG_IND:
				isdn_decode_prg_ind(&ptr->prg_ind, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DT_TIME:
				if(variant == VARIANT_ITU)
					isdn_decode_dt_time(&ptr->dt_time, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CONN_NUM:
				if(variant == VARIANT_QSIG)
					qsig_decode_conn_num(&ptr->conn_num, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_LL_COMP:
				if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
					isdn_decode_ll_comp(&ptr->ll_comp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_HL_COMP:
				if(variant == VARIANT_ITU)
					isdn_decode_hl_comp(&ptr->hl_comp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}

	return ISDN_CM_OK;
}

static int isdn_encode_conn_ack(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnConnAck *ptr = &src->msg_list.connAck;
	u8 *flw_ptr = dst;

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_conn_ack(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnConnAck *ptr = &dst->msg_list.connAck;
	u8 *flw_ptr = src;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			break;
		}
		switch(*flw_ptr)
		{
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}

	return ISDN_CM_OK;
}

static int isdn_encode_prog(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnProg *ptr = &src->msg_list.prog;
	u8 *flw_ptr = dst;

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->br_cap.pres == 1)
		{
			flw_ptr[0] = IE_BR_CAP;
			flw_ptr[1] = itu_encode_br_cap(flw_ptr+2, &ptr->br_cap);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	if(ptr->cause.pres == 1)
	{
		flw_ptr[0] = IE_CAUSE;
		flw_ptr[1] = isdn_encode_cause(flw_ptr+2, &ptr->cause);
		flw_ptr += flw_ptr[1] + 2;
	}
	
	//Mandatory	if(ptr->prg_ind.pres == 1)
	{
		flw_ptr[0] = IE_PRG_IND;
		flw_ptr[1] = isdn_encode_prg_ind(flw_ptr+2, &ptr->prg_ind);
		flw_ptr += flw_ptr[1] + 2;
	}

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->hl_comp.pres == 1)
		{
			flw_ptr[0] = IE_HL_COMP;
			flw_ptr[1] = isdn_encode_hl_comp(flw_ptr+2, &ptr->hl_comp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_prog(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnProg *ptr = &dst->msg_list.prog;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_BR_CAP:
				if(variant == VARIANT_ITU)
					itu_decode_br_cap(&ptr->br_cap, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CAUSE:
				isdn_decode_cause(&ptr->cause, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_PRG_IND:		//M
				if(!(isdn_decode_prg_ind(&ptr->prg_ind, flw_ptr+2, flw_ptr[1])))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_HL_COMP:
				if(variant == VARIANT_ITU)
					isdn_decode_hl_comp(&ptr->hl_comp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 1)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_setup(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnSetup *ptr = &src->msg_list.setup;
	u8 *flw_ptr = dst;

	//Optional
	if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
	{
		if(ptr->sd_comp.pres == 1)
		{
			flw_ptr[0] = IE_SD_COMP;
			flw_ptr += 1;
		}
	}

	if(variant == VARIANT_ITU)
	{
		if(ptr->rpt_ind.pres == 1)
		{
			flw_ptr[0] = IE_RPT_IND;
			flw_ptr += 1;
		}
	}

	//Mandatory	if(ptr->br_cap.pres == 1)
	{
		flw_ptr[0] = IE_BR_CAP;
		if(variant == VARIANT_ITU)
			flw_ptr[1] = itu_encode_br_cap(flw_ptr+2, &ptr->br_cap);
		else
			flw_ptr[1] = isdn_encode_br_cap(flw_ptr+2, &ptr->br_cap);
		flw_ptr += flw_ptr[1] + 2;
	}
	//if(ptr->chnl_id.pres == 1)		//user side is optional but network side is mandatory
	{
		flw_ptr[0] = IE_CHNL_ID;
		if(variant == VARIANT_QSIG)
			flw_ptr[1] = qsig_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		else
			flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		flw_ptr += flw_ptr[1] + 2;
	}

	//Optional
	if(ptr->prg_ind.pres == 1)
	{
		flw_ptr[0] = IE_PRG_IND;
		flw_ptr[1] = isdn_encode_prg_ind(flw_ptr+2, &ptr->prg_ind);
		flw_ptr += flw_ptr[1] + 2;
	}

	if(variant == VARIANT_ITU || variant == VARIANT_ANSI)
	{
		if(ptr->nt_sp_fac.pres == 1)
		{
			flw_ptr[0] = IE_NT_SP_FAC;
			flw_ptr[1] = isdn_encode_ntsp_fac(flw_ptr+2, &ptr->nt_sp_fac);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->dt_time.pres == 1)
		{
			flw_ptr[0] = IE_DT_TIME;
			flw_ptr[1] = isdn_encode_dt_time(flw_ptr+2, &ptr->dt_time);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->kpd_fac.pres == 1)
		{
			flw_ptr[0] = IE_KPD_FAC;
			flw_ptr[1] = isdn_encode_kpd_fac(flw_ptr+2, &ptr->kpd_fac);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	if(ptr->cg_pty_num.pres == 1)
	{
		flw_ptr[0] = IE_CG_PTY_NUM;
		flw_ptr[1] = isdn_encode_cg_num(flw_ptr+2, &ptr->cg_pty_num);
		flw_ptr += flw_ptr[1] + 2;
	}

	if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
	{
		if(ptr->cg_pty_addr.pres == 1)
		{
			flw_ptr[0] = IE_CG_PTY_ADDR;
			flw_ptr[1] = isdn_encode_cg_addr(flw_ptr+2, &ptr->cg_pty_addr);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	if(ptr->cd_pty_num.pres == 1)
	{
		flw_ptr[0] = IE_CD_PTY_NUM;
		flw_ptr[1] = isdn_encode_cd_num(flw_ptr+2, &ptr->cd_pty_num);
		flw_ptr += flw_ptr[1] + 2;
	}

	if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
	{
		if(ptr->cd_pty_addr.pres == 1)
		{
			flw_ptr[0] = IE_CD_PTY_ADDR;
			flw_ptr[1] = isdn_encode_cd_addr(flw_ptr+2, &ptr->cd_pty_addr);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	if(variant == VARIANT_ANSI)
	{
		if(ptr->redir_num.pres == 1)
		{
			flw_ptr[0] = IE_REDIR_NUM;
			flw_ptr[1] = ansi_encode_redir_num(flw_ptr+2, &ptr->redir_num);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	if(variant == VARIANT_ITU || variant == VARIANT_ANSI)
	{
		if(ptr->tran_nt_sel.pres == 1)
		{
			flw_ptr[0] = IE_TRAN_NT_SEL;
			flw_ptr[1] = isdn_encode_tran_sel(flw_ptr+2, &ptr->tran_nt_sel);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
	{
		if(ptr->ll_comp.pres == 1)
		{
			flw_ptr[0] = IE_LL_COMP;
			flw_ptr[1] = isdn_encode_ll_comp(flw_ptr+2, &ptr->ll_comp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->hl_comp.pres == 1)
		{
			flw_ptr[0] = IE_HL_COMP;
			flw_ptr[1] = isdn_encode_hl_comp(flw_ptr+2, &ptr->hl_comp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_setup(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnSetup *ptr = &dst->msg_list.setup;
	u8 *flw_ptr = src;
	u8 ie_m = 0;
	int ret = 0;
	int qsig_ie_m = 0;

	while(flw_ptr+1-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			if(qsig_ie_m != 2 && variant != VARIANT_ITU)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_SD_COMP:
				if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
					ptr->sd_comp.pres = 1;
				flw_ptr += 1;
				break;
			case IE_RPT_IND:
				if(variant == VARIANT_ITU)
					ptr->rpt_ind.pres = 1;
				flw_ptr += 1;
				break;
			case IE_BR_CAP:		//M
				if(!itu_decode_br_cap(&ptr->br_cap, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CHNL_ID:		//M
				if(variant == VARIANT_QSIG)
					ret = qsig_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				else
					ret = isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				if(!ret)
				{
					printf("channel identification ie is err!\n");
					return 2;
				}
				qsig_ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_PRG_IND:
				isdn_decode_prg_ind(&ptr->prg_ind, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_NT_SP_FAC:
				if(variant == VARIANT_ITU || variant == VARIANT_ANSI)
					isdn_decode_ntsp_fac(&ptr->nt_sp_fac, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DT_TIME:
				if(variant == VARIANT_ITU)
					isdn_decode_dt_time(&ptr->dt_time, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_KPD_FAC:
				if(variant == VARIANT_ITU)
					isdn_decode_kpd_fac(&ptr->kpd_fac, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CG_PTY_NUM:
				isdn_decode_cg_num(&ptr->cg_pty_num, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CG_PTY_ADDR:
				if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
					isdn_decode_cg_addr(&ptr->cg_pty_addr, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CD_PTY_NUM:
				ret = isdn_decode_cd_num(&ptr->cd_pty_num, flw_ptr+2, flw_ptr[1]);
				if((!ret) && (variant != VARIANT_ITU))
				{
					printf("called number ie is err!\n");
					return 2;
				}
				qsig_ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CD_PTY_ADDR:
				if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
					isdn_decode_cd_addr(&ptr->cd_pty_addr, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_REDIR_NUM:
				if(variant == VARIANT_ANSI)
					ansi_decode_redir_num(&ptr->redir_num, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_TRAN_NT_SEL:
				if(variant == VARIANT_ITU || variant == VARIANT_ANSI)
					isdn_decode_tran_sel(&ptr->tran_nt_sel, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_LL_COMP:
				if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
					isdn_decode_ll_comp(&ptr->ll_comp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_HL_COMP:
				if(variant == VARIANT_ITU || variant == VARIANT_QSIG)
					isdn_decode_hl_comp(&ptr->hl_comp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 1)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}
	if(qsig_ie_m != 2 && variant != VARIANT_ITU)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}
			
	return ISDN_CM_OK;
}

static int isdn_encode_setup_ack(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnSetupAck *ptr = &src->msg_list.setupAck;
	u8 *flw_ptr = dst;

	//Optional
	if(variant == VARIANT_ITU)
	{
		//if(ptr->chnl_id.pres == 1)
		{
			flw_ptr[0] = IE_CHNL_ID;
			flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->prg_ind.pres == 1)
		{
			flw_ptr[0] = IE_PRG_IND;
			flw_ptr[1] = isdn_encode_prg_ind(flw_ptr+2, &ptr->prg_ind);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	else if(variant == VARIANT_QSIG)
	{
		//if(ptr->chnl_id.pres == 1)
		{
			flw_ptr[0] = IE_CHNL_ID;
			flw_ptr[1] = qsig_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	else
	{
		printf("encode: there isnot msg setup ack in ansi!\n");
		return -1;
	}
	
	return flw_ptr - dst;
}

int isdn_decode_setup_ack(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnSetupAck *ptr = &dst->msg_list.setupAck;
	u8 *flw_ptr = src;
	u8 ie_m = 0;
	int ret;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CHNL_ID:		//M
				if(variant == VARIANT_QSIG)
					ret = qsig_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				else
					ret = isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				if(!ret)
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_PRG_IND:
				if(variant == VARIANT_ITU)
					isdn_decode_prg_ind(&ptr->prg_ind, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 1)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_disc(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnDisc *ptr = &src->msg_list.disc;
	u8 *flw_ptr = dst;

	//Mandatory	if(ptr->cause.pres == 1)
	{
		flw_ptr[0] = IE_CAUSE;
		flw_ptr[1] = isdn_encode_cause(flw_ptr+2, &ptr->cause);
		flw_ptr += flw_ptr[1] + 2;
	}

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->prg_ind.pres == 1)
		{
			flw_ptr[0] = IE_PRG_IND;
			flw_ptr[1] = isdn_encode_prg_ind(flw_ptr+2, &ptr->prg_ind);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_disc(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnDisc *ptr = &dst->msg_list.disc;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CAUSE:
				if(!isdn_decode_cause(&ptr->cause, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_PRG_IND:
				if(variant == VARIANT_ITU)
					isdn_decode_prg_ind(&ptr->prg_ind, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 1)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_rel(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnRel *ptr = &src->msg_list.rel;
	u8 *flw_ptr = dst;
	
	//Optional
//	if(ptr->cause.pres == 1)
	{
		flw_ptr[0] = IE_CAUSE;
		flw_ptr[1] = isdn_encode_cause(flw_ptr+2, &ptr->cause);
		flw_ptr += flw_ptr[1] + 2;
	}
	
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_rel(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnRel *ptr = &dst->msg_list.rel;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CAUSE:
				if(!isdn_decode_cause(&ptr->cause, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}

	return ISDN_CM_OK;
}

static int isdn_encode_rel_comp(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnRelComp *ptr = &src->msg_list.relComp;
	u8 *flw_ptr = dst;
	
	//Optional
	if(ptr->cause.pres == 1)
	{
		flw_ptr[0] = IE_CAUSE;
		flw_ptr[1] = isdn_encode_cause(flw_ptr+2, &ptr->cause);
		flw_ptr += flw_ptr[1] + 2;
	}
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_rel_comp(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnRelComp *ptr = &dst->msg_list.relComp;
	u8 *flw_ptr = src;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CAUSE:
				isdn_decode_cause(&ptr->cause, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}

	return ISDN_CM_OK;
}

static int isdn_encode_restart(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnRestart *ptr = &src->msg_list.restart;
	u8 *flw_ptr = dst;

	//Optional
	if(ptr->chnl_id.pres == 1)
	{
		flw_ptr[0] = IE_CHNL_ID;
		flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		flw_ptr += flw_ptr[1] + 2;
	}

	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	//Mandatory	if(ptr->restart_ind.pres == 1)
	{
		flw_ptr[0] = IE_RESTART_IND;
		flw_ptr[1] = isdn_encode_restart_ind(flw_ptr+2, &ptr->restart_ind);
		flw_ptr += flw_ptr[1] + 2;
	}
	
	return flw_ptr - dst;
}

int isdn_decode_restart(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnRestart *ptr = &dst->msg_list.restart;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CHNL_ID:
				isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_RESTART_IND:
				if(!isdn_decode_restart_ind(&ptr->restart_ind, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 1)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_rest_ack(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnRestAck *ptr = &src->msg_list.restAck;
	u8 *flw_ptr = dst;

	//Optional
	if(ptr->chnl_id.pres == 1)
	{
		flw_ptr[0] = IE_CHNL_ID;
		flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		flw_ptr += flw_ptr[1] + 2;
	}

	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	//Mandatory	if(ptr->restart_ind.pres == 1)
	{
		flw_ptr[0] = IE_RESTART_IND;
		flw_ptr[1] = isdn_encode_restart_ind(flw_ptr+2, &ptr->restart_ind);
		flw_ptr += flw_ptr[1] + 2;
	}
	
	return flw_ptr - dst;
}

int isdn_decode_rest_ack(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnRestAck *ptr = &dst->msg_list.restAck;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CHNL_ID:
				isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_RESTART_IND:
				if(!isdn_decode_restart_ind(&ptr->restart_ind, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 1)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_info(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnInfo *ptr = &src->msg_list.info;
	u8 *flw_ptr = dst;

	//Optional
	if(ptr->sd_comp.pres == 1)
	{
		flw_ptr[0] = IE_SD_COMP;
		flw_ptr += 1;
	}
	
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->kpd_fac.pres == 1)
		{
			flw_ptr[0] = IE_KPD_FAC;
			flw_ptr[1] = isdn_encode_kpd_fac(flw_ptr+2, &ptr->kpd_fac);
			flw_ptr += flw_ptr[1] + 2;
		}
		if(ptr->sign.pres == 1)
		{
			flw_ptr[0] = IE_SIGN;
			flw_ptr[1] = isdn_encode_sign(flw_ptr+2, &ptr->sign);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	if(ptr->cd_pty_num.pres == 1)
	{
		flw_ptr[0] = IE_CD_PTY_NUM;
		flw_ptr[1] = isdn_encode_cd_num(flw_ptr+2, &ptr->cd_pty_num);
		flw_ptr += flw_ptr[1] + 2;
	}
	
	return flw_ptr - dst;
}

int isdn_decode_info(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnInfo *ptr = &dst->msg_list.info;
	u8 *flw_ptr = src;

	while(flw_ptr+1-src <= len)
	{
		if(*flw_ptr == 0)
		{
			break;
		}
		switch(*flw_ptr)
		{
			case IE_SD_COMP:
				ptr->sd_comp.pres = 1;
				flw_ptr += 1;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_KPD_FAC:
				if(variant == VARIANT_ITU)
					isdn_decode_kpd_fac(&ptr->kpd_fac, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_SIGN:
				if(variant == VARIANT_ITU)
					isdn_decode_sign(&ptr->sign, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CD_PTY_NUM:
				isdn_decode_cd_num(&ptr->cd_pty_num, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}

	return ISDN_CM_OK;
}

static int isdn_encode_noti(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnNoti *ptr = &src->msg_list.noti;
	u8 *flw_ptr = dst;

	//Mandatory
	
	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->br_cap.pres == 1)
		{
			flw_ptr[0] = IE_BR_CAP;
			flw_ptr[1] = itu_encode_br_cap(flw_ptr+2, &ptr->br_cap);
			flw_ptr += flw_ptr[1] + 2;
		}
	}

	//Mandatory	if(ptr->notify_ind.pres == 1)
	{
		flw_ptr[0] = IE_NOTIFY_IND;
		flw_ptr[1] = isdn_encode_notify_ind(flw_ptr+2, &ptr->notify_ind);
		flw_ptr += flw_ptr[1] + 2;
	}

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_noti(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnNoti *ptr = &dst->msg_list.noti;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 1)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_BR_CAP:
				if(variant == VARIANT_ITU)
					itu_decode_br_cap(&ptr->br_cap, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_NOTIFY_IND:
				if(!isdn_decode_notify_ind(&ptr->notify_ind, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 1)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_status(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnStatus *ptr = &src->msg_list.status;
	u8 *flw_ptr = dst;

	//Mandatory	if(ptr->cause.pres == 1)
	{
		flw_ptr[0] = IE_CAUSE;
		flw_ptr[1] = isdn_encode_cause(flw_ptr+2, &ptr->cause);
		flw_ptr += flw_ptr[1] + 2;
	}
	//if(ptr->call_stat.pres == 1)
	{
		flw_ptr[0] = IE_CALL_STAT;
		flw_ptr[1] = isdn_encode_call_stat(flw_ptr+2, &ptr->call_stat);
		flw_ptr += flw_ptr[1] + 2;
	}

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_status(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnStatus *ptr = &dst->msg_list.status;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 2)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CAUSE:
				if(!isdn_decode_cause(&ptr->cause, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CALL_STAT:
				if(!isdn_decode_call_stat(&ptr->call_stat, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 2)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_stat_enq(u8 *dst, IsdnMsgStr *src, int variant)
{
	IsdnStatEnq *ptr = &src->msg_list.statEnq;
	u8 *flw_ptr = dst;

	//Optional
	if(variant == VARIANT_ITU)
	{
		if(ptr->disp.pres == 1)
		{
			flw_ptr[0] = IE_DISP;
			flw_ptr[1] = isdn_encode_disp(flw_ptr+2, &ptr->disp);
			flw_ptr += flw_ptr[1] + 2;
		}
	}
	
	return flw_ptr - dst;
}

int isdn_decode_stat_enq(IsdnMsgStr *dst, u8 *src, int variant, u8 len)
{
	IsdnStatEnq *ptr = &dst->msg_list.statEnq;
	u8 *flw_ptr = src;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			break;
		}
		switch(*flw_ptr)
		{
			case IE_DISP:
				if(variant == VARIANT_ITU)
					isdn_decode_disp(&ptr->disp, flw_ptr+2, flw_ptr[1]);
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}

	return ISDN_CM_OK;
}


//maintenance messages		ansi
static int isdn_encode_service(u8 *dst, IsdnMsgStr *src)
{
	IsdnService *ptr = &src->msg_list.service;
	u8 *flw_ptr = dst;
	
	//Mandatory	if(ptr->chg_stat.pres)
	{
		flw_ptr[0] = IE_CHG_STAT;
		flw_ptr[1] = ansi_encode_chg_stat(flw_ptr+2, &ptr->chg_stat);
		flw_ptr += flw_ptr[1] + 2;
	}
	//if(ptr->chnl_id.pres)
	{
		flw_ptr[0] = IE_CHNL_ID;
		flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		flw_ptr += flw_ptr[1] + 2;
	}

	return flw_ptr - dst;
}

int isdn_decode_service(IsdnMsgStr *dst, u8 *src, u8 len)
{
	IsdnService *ptr = &dst->msg_list.service;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 2)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CHG_STAT:
				if(!ansi_decode_chg_stat(&ptr->chg_stat, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CHNL_ID:
				if(!isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 2)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}

static int isdn_encode_servAck(u8 *dst, IsdnMsgStr *src)
{
	IsdnServAck *ptr = &src->msg_list.servAck;
	u8 *flw_ptr = dst;
	
	//Mandatory	if(ptr->chg_stat.pres)
	{
		flw_ptr[0] = IE_CHG_STAT;
		flw_ptr[1] = ansi_encode_chg_stat(flw_ptr+2, &ptr->chg_stat);
		flw_ptr += flw_ptr[1] + 2;
	}
	//if(ptr->chnl_id.pres)
	{
		flw_ptr[0] = IE_CHNL_ID;
		flw_ptr[1] = isdn_encode_chnl_id(flw_ptr+2, &ptr->chnl_id);
		flw_ptr += flw_ptr[1] + 2;
	}

	return flw_ptr - dst;
}

int isdn_decode_servAck(IsdnMsgStr *dst, u8 *src, u8 len)
{
	IsdnServAck *ptr = &dst->msg_list.servAck;
	u8 *flw_ptr = src;
	u8 ie_m = 0;

	while(flw_ptr+2-src <= len)
	{
		if(*flw_ptr == 0)
		{
			if(ie_m != 2)
			{
				printf("mandatory ie is absent!\n");
				return 3;
			}
			break;
		}
		switch(*flw_ptr)
		{
			case IE_CHG_STAT:
				if(!ansi_decode_chg_stat(&ptr->chg_stat, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			case IE_CHNL_ID:
				if(!isdn_decode_chnl_id(&ptr->chnl_id, flw_ptr+2, flw_ptr[1]))
				{
					printf("mandatory ie is err!\n");
					return 2;
				}
				ie_m++;
				flw_ptr += flw_ptr[1] + 2;
				break;
			default:
				if(*flw_ptr >= 0x80)	//single octet IE
					flw_ptr += 1;
				else
					flw_ptr += flw_ptr[1] + 2;
				break;
		}
	}
	if(ie_m != 2)
	{
		printf("mandatory ie is absent!\n");
		return 3;
	}

	return ISDN_CM_OK;
}


/*************************************************************
Function:		itu_msg_encode
Description:	encode ITU isdn message
Output:		dst:preserving destination, src:source msg structure
Return:		isdn msg length:success
			ISDN_CM_FAILED:failed
*************************************************************/
int itu_msg_encode(u8 *dst, IsdnMsgStr *src)	//msg from isdn to iua
{
	switch(src->msg_m.msg_type)
	{
	//	
		case MSG_ALERT:
			return isdn_encode_alert(dst, src, VARIANT_ITU);
		case MSG_CALL_PROC:
			return isdn_encode_call_proc(dst, src, VARIANT_ITU);
		case MSG_CONN:
			return isdn_encode_conn(dst, src, VARIANT_ITU);
		case MSG_CONNACK:
			return isdn_encode_conn_ack(dst, src, VARIANT_ITU);
		case MSG_PROG:
			return isdn_encode_prog(dst, src, VARIANT_ITU);
		case MSG_SETUP:
			return isdn_encode_setup(dst, src, VARIANT_ITU);
		case MSG_SETUP_ACK:
			return isdn_encode_setup_ack(dst, src, VARIANT_ITU);
	//
		case MSG_DISC:
			return isdn_encode_disc(dst, src, VARIANT_ITU);
		case MSG_REL:
			return isdn_encode_rel(dst, src, VARIANT_ITU);
		case MSG_REL_COMP:
			return isdn_encode_rel_comp(dst, src, VARIANT_ITU);
		case MSG_RESTART:
			return isdn_encode_restart(dst, src, VARIANT_ITU);
		case MSG_REST_ACK:
			return isdn_encode_rest_ack(dst, src, VARIANT_ITU);
	//
		case MSG_INFORMATION:
			return isdn_encode_info(dst, src, VARIANT_ITU);
		case MSG_NOTI:
			return isdn_encode_noti(dst, src, VARIANT_ITU);
		case MSG_STATUS:
			return isdn_encode_status(dst, src, VARIANT_ITU);
		case MSG_STAT_ENQ:
			return isdn_encode_stat_enq(dst, src, VARIANT_ITU);
		default:
			break;
	}

	return -1;
}

/*************************************************************
Function:		itu_msg_decode
Description:	decode ITU isdn message
Input:		msgtype:msg type, len:msg length
Output:		dst:preserving destination structure, src:source msg code stream
Return:		ISDN_CM_OK:success
			ISDN_CM_FAILED or 2 or 3:failed
*************************************************************/
int itu_msg_decode(IsdnMsgStr *dst, u8 *src, u8 msgtype, u8 len)	//msg from iua to isdn
{
	u8 msg_clas, msg_type;

	msg_clas = (msgtype & 0x60) >> 5;
	msg_type = (msgtype & 0x1F);

	switch(msg_clas)
	{
		case 0x0:	//
			switch(msg_type)
			{
				case (MSG_ALERT & 0x1F):
					return isdn_decode_alert(dst, src, VARIANT_ITU, len);
				case (MSG_CALL_PROC & 0x1F):
					return isdn_decode_call_proc(dst, src, VARIANT_ITU, len);
				case (MSG_CONN & 0x1F):
					return isdn_decode_conn(dst, src, VARIANT_ITU, len);
				case (MSG_CONNACK & 0x1F):
					return isdn_decode_conn_ack(dst, src, VARIANT_ITU, len);
				case (MSG_PROG & 0x1F):
					return isdn_decode_prog(dst, src, VARIANT_ITU, len);
				case (MSG_SETUP & 0x1F):
					return isdn_decode_setup(dst, src, VARIANT_ITU, len);
				case (MSG_SETUP_ACK & 0x1F):
					return isdn_decode_setup_ack(dst, src, VARIANT_ITU, len);
				default:
					break;
			}
			break;
		case 0x1:	//
			break;
		case 0x2:	//
			switch(msg_type)
			{
				case (MSG_DISC & 0x1F):
					return isdn_decode_disc(dst, src, VARIANT_ITU, len);
				case (MSG_REL & 0x1F):
					return isdn_decode_rel(dst, src, VARIANT_ITU, len);
				case (MSG_REL_COMP & 0x1F):
					return isdn_decode_rel_comp(dst, src, VARIANT_ITU, len);
				case (MSG_RESTART & 0x1F):
					return isdn_decode_restart(dst, src, VARIANT_ITU, len);
				case (MSG_REST_ACK & 0x1F):
					return isdn_decode_rest_ack(dst, src, VARIANT_ITU, len);
				default:
					break;
			}
			break;
		case 0x3:	//
			switch(msg_type)
			{
				case (MSG_INFORMATION & 0x1F):
					return isdn_decode_info(dst, src, VARIANT_ITU, len);
				case (MSG_NOTI & 0x1F):
					return isdn_decode_noti(dst, src, VARIANT_ITU, len);
				case (MSG_STATUS & 0x1F):
					return isdn_decode_status(dst, src, VARIANT_ITU, len);
				case (MSG_STAT_ENQ & 0x1F):
					return isdn_decode_stat_enq(dst, src, VARIANT_ITU, len);
				default:
					break;
			}
			break;
			
		default:
			break;
	}
	
	return ISDN_CM_FAILED;
}

int ansi_msg_encode(u8 *dst, IsdnMsgStr *src)	//msg from isdn to iua
{
	switch(src->msg_m.msg_type)
	{
	//	
		case MSG_ALERT:
			return isdn_encode_alert(dst, src, VARIANT_ANSI);
		case MSG_CALL_PROC:
			return isdn_encode_call_proc(dst, src, VARIANT_ANSI);
		case MSG_CONN:
			return isdn_encode_conn(dst, src, VARIANT_ANSI);
		case MSG_CONNACK:
			return isdn_encode_conn_ack(dst, src, VARIANT_ANSI);
		case MSG_PROG:
			return isdn_encode_prog(dst, src, VARIANT_ANSI);
		case MSG_SETUP:
			return isdn_encode_setup(dst, src, VARIANT_ANSI);
	//
		case MSG_DISC:
			return isdn_encode_disc(dst, src, VARIANT_ANSI);
		case MSG_REL:
			return isdn_encode_rel(dst, src, VARIANT_ANSI);
		case MSG_REL_COMP:
			return isdn_encode_rel_comp(dst, src, VARIANT_ANSI);
		case MSG_RESTART:
			return isdn_encode_restart(dst, src, VARIANT_ANSI);
		case MSG_REST_ACK:
			return isdn_encode_rest_ack(dst, src, VARIANT_ANSI);
	//
		case MSG_NOTI:
			return isdn_encode_noti(dst, src, VARIANT_ANSI);
		case MSG_STATUS:
			return isdn_encode_status(dst, src, VARIANT_ANSI);
		case MSG_STAT_ENQ:
			return isdn_encode_stat_enq(dst, src, VARIANT_ANSI);
		default:
			break;
	}

	return -1;
}

int ansi_msg_decode(IsdnMsgStr *dst, u8 *src, u8 msgtype, u8 len)	//msg from iua to isdn
{
	u8 msg_clas, msg_type;

	msg_clas = (msgtype & 0x60) >> 5;
	msg_type = (msgtype & 0x1F);

	switch(msg_clas)
	{
		case 0x0:	//
			switch(msg_type)
			{
				case (MSG_ALERT & 0x1F):
					return isdn_decode_alert(dst, src, VARIANT_ANSI, len);
				case (MSG_CALL_PROC & 0x1F):	
					return isdn_decode_call_proc(dst, src, VARIANT_ANSI, len);
				case (MSG_CONN & 0x1F):
					return isdn_decode_conn(dst, src, VARIANT_ANSI, len);
				case (MSG_CONNACK & 0x1F):
					return isdn_decode_conn_ack(dst, src, VARIANT_ANSI, len);
				case (MSG_PROG & 0x1F):
					return isdn_decode_prog(dst, src, VARIANT_ANSI, len);
				case (MSG_SETUP & 0x1F):
					return isdn_decode_setup(dst, src, VARIANT_ANSI, len);
				default:
					break;
			}
			break;
		case 0x1:	//
			break;
		case 0x2:	//
			switch(msg_type)
			{
				case (MSG_DISC & 0x1F):
					return isdn_decode_disc(dst, src, VARIANT_ANSI, len);
				case (MSG_REL & 0x1F):
					return isdn_decode_rel(dst, src, VARIANT_ANSI, len);
				case (MSG_REL_COMP & 0x1F):
					return isdn_decode_rel_comp(dst, src, VARIANT_ANSI, len);
				case (MSG_RESTART & 0x1F):
					return isdn_decode_restart(dst, src, VARIANT_ANSI, len);
				case (MSG_REST_ACK & 0x1F):
					return isdn_decode_rest_ack(dst, src, VARIANT_ANSI, len);
				default:
					break;
			}
			break;
		case 0x3:	//
			switch(msg_type)
			{
				case (MSG_NOTI & 0x1F):
					return isdn_decode_noti(dst, src, VARIANT_ANSI, len);
				case (MSG_STATUS & 0x1F):
					return isdn_decode_status(dst, src, VARIANT_ANSI, len);
				case (MSG_STAT_ENQ & 0x1F):
					return isdn_decode_stat_enq(dst, src, VARIANT_ANSI, len);
				default:
					break;
			}
			break;
			
		default:
			break;
	}
	
	return ISDN_CM_FAILED;
}

int qsig_msg_encode(u8 *dst, IsdnMsgStr *src)	//msg from isdn to iua
{
	switch(src->msg_m.msg_type)
	{
	//	
		case MSG_ALERT:
			return isdn_encode_alert(dst, src, VARIANT_QSIG);
		case MSG_CALL_PROC:
			return isdn_encode_call_proc(dst, src, VARIANT_QSIG);
		case MSG_CONN:
			return isdn_encode_conn(dst, src, VARIANT_QSIG);
		case MSG_CONNACK:
			return isdn_encode_conn_ack(dst, src, VARIANT_QSIG);
		case MSG_PROG:
			return isdn_encode_prog(dst, src, VARIANT_QSIG);
		case MSG_SETUP:
			return isdn_encode_setup(dst, src, VARIANT_QSIG);
		case MSG_SETUP_ACK:
			return isdn_encode_setup_ack(dst, src, VARIANT_QSIG);
	//
		case MSG_DISC:
			return isdn_encode_disc(dst, src, VARIANT_QSIG);
		case MSG_REL:
			return isdn_encode_rel(dst, src, VARIANT_QSIG);
		case MSG_REL_COMP:
			return isdn_encode_rel_comp(dst, src, VARIANT_QSIG);
		case MSG_RESTART:
			return isdn_encode_restart(dst, src, VARIANT_QSIG);
		case MSG_REST_ACK:
			return isdn_encode_rest_ack(dst, src, VARIANT_QSIG);
	//
		case MSG_INFORMATION:
			return isdn_encode_info(dst, src, VARIANT_QSIG);
		case MSG_STATUS:
			return isdn_encode_status(dst, src, VARIANT_QSIG);
		case MSG_STAT_ENQ:
			return isdn_encode_stat_enq(dst, src, VARIANT_QSIG);
		default:
			break;
	}

	return -1;
}

int qsig_msg_decode(IsdnMsgStr *dst, u8 *src, u8 msgtype, u8 len)	//msg from iua to isdn
{
	u8 msg_clas, msg_type;

	msg_clas = (msgtype & 0x60) >> 5;
	msg_type = (msgtype & 0x1F);

	switch(msg_clas)
	{
		case 0x0:	//
			switch(msg_type)
			{
				case (MSG_ALERT & 0x1F):
					return isdn_decode_alert(dst, src, VARIANT_QSIG, len);
				case (MSG_CALL_PROC & 0x1F):	
					return isdn_decode_call_proc(dst, src, VARIANT_QSIG, len);
				case (MSG_CONN & 0x1F):
					return isdn_decode_conn(dst, src, VARIANT_QSIG, len);
				case (MSG_CONNACK & 0x1F):
					return isdn_decode_conn_ack(dst, src, VARIANT_QSIG, len);
				case (MSG_PROG & 0x1F):
					return isdn_decode_prog(dst, src, VARIANT_QSIG, len);
				case (MSG_SETUP & 0x1F):
					return isdn_decode_setup(dst, src, VARIANT_QSIG, len);
				default:
					break;
			}
			break;
		case 0x1:	//
			break;
		case 0x2:	//
			switch(msg_type)
			{
				case (MSG_DISC & 0x1F):
					return isdn_decode_disc(dst, src, VARIANT_QSIG, len);
				case (MSG_REL & 0x1F):
					return isdn_decode_rel(dst, src, VARIANT_QSIG, len);
				case (MSG_REL_COMP & 0x1F):
					return isdn_decode_rel_comp(dst, src, VARIANT_QSIG, len);
				case (MSG_RESTART & 0x1F):
					return isdn_decode_restart(dst, src, VARIANT_QSIG, len);
				case (MSG_REST_ACK & 0x1F):
					return isdn_decode_rest_ack(dst, src, VARIANT_QSIG, len);
				default:
					break;
			}
			break;
		case 0x3:	//
			switch(msg_type)
			{
				case (MSG_INFORMATION & 0x1F):
					return isdn_decode_info(dst, src, VARIANT_QSIG, len);
				case (MSG_STATUS & 0x1F):
					return isdn_decode_status(dst, src, VARIANT_QSIG, len);
				case (MSG_STAT_ENQ & 0x1F):
					return isdn_decode_stat_enq(dst, src, VARIANT_QSIG, len);
				default:
					break;
			}
			break;
			
		default:
			break;
	}
	
	return ISDN_CM_FAILED;
}



/*************************************************************
Function:		maintenance_msg_encode
Description:	encode ansi isdn maintenance message
Output:		dst:preserving destination, src:source msg structure
Return:		isdn msg length:success
			ISDN_CM_FAILED:failed
*************************************************************/
int maintenance_msg_encode(u8 *dst, IsdnMsgStr *src)	//msg from isdn to iua
{
	switch(src->msg_m.msg_type)
	{
		case MSG_SERVICE:
			return isdn_encode_service(dst, src);
		case MSG_SERVICE_ACK:
			return isdn_encode_servAck(dst, src);
		default:
			break;
	}

	return -1;
}

/*************************************************************
Function:		maintenance_msg_decode
Description:	decode ansi isdn maintenance message
Input:		msgtype:msg type, len:msg length
Output:		dst:preserving destination structure, src:source msg code stream
Return:		ISDN_CM_OK:success
			ISDN_CM_FAILED or 2 or 3:failed
*************************************************************/
int maintenance_msg_decode(IsdnMsgStr *dst, u8 *src, u8 msgtype, u8 len)	//msg from iua to isdn
{
	switch(msgtype)
	{
		case MSG_SERVICE:
			return isdn_decode_service(dst, src, len);
		case MSG_SERVICE_ACK:
			return isdn_decode_servAck(dst, src, len);
		default:
			break;
	}

	return ISDN_CM_FAILED;
}


void isdn_send_heartbeat(int link_id)
{
	message_list msg_trans;

	memset(&msg_trans, 0, sizeof(message_list));
	msg_trans.msgSrcPort = ISDN_IP_PORT;
	msg_trans.msgDstIP = isdn_rs.attrib.isdn_remote_ip;
	msg_trans.msgDstPort = ISDN_IP_PORT;
	msg_trans.msgLength = 3;
	msg_trans.msgContent[0] = 1;	//type
	msg_trans.msgContent[1] = link_id;
	msg_trans.msgContent[2] = isdn_rs.link_pond[link_id].dc_status;

	if(iptrPlatPutMessage(msg_trans) == 0)
		isdn_log_err(0, "send heartbeat err!link id =%d, remote ip =%d, link status =%d \r\n",
			link_id, isdn_rs.attrib.isdn_remote_ip, isdn_rs.link_pond[link_id].dc_status);
}
void isdn_redirect_send(IuaMsgStr *iua_src, int type)
{
	message_list msg_trans;

	memset(&msg_trans, 0, sizeof(message_list));
	msg_trans.msgSrcPort = ISDN_IP_PORT;
	msg_trans.msgDstIP = isdn_rs.attrib.isdn_remote_ip;
	msg_trans.msgDstPort = ISDN_IP_PORT;
	msg_trans.msgLength = iua_src->msg_length + 5;
	msg_trans.msgContent[0] = type;
	memcpy(msg_trans.msgContent+1, &iua_src->msg_class, msg_trans.msgLength-1);
	monitor_isdn_msg(0, "RD=>", iua_src, COL_BLUE);
	if(iua_src->msgcontent.isdn_msg.msg_m.proto_Discr == PROTOCOL_DISCR)
		isdn_msg_csta(iua_src->msgcontent.isdn_msg.msg_m.msg_type, 2);
	if(iptrPlatPutMessage(msg_trans) == 0)
		isdn_log_err(0, "redirect send err! msg type =0x%02x\r\n",iua_src->msgcontent.isdn_msg.msg_m.msg_type);
}


int isdn_msg_encode(u8 *dst, IsdnMsgStr *src, int variant)	//msg from isdn to iua
{
	switch(variant)
	{
		case VARIANT_ITU:
			return itu_msg_encode(dst, src);
		case VARIANT_ANSI:
			return ansi_msg_encode(dst, src);
		case VARIANT_QSIG:
			return qsig_msg_encode(dst, src);
		default:
			break;
	}

	return -1;
}

/*************************************************************
Function:		isdn_msg_decode
Description:	decode isdn message
Input:		msgtype:msg type, len:msg length, variant:proto variant
Output:		dst:preserving destination structure, src:source msg code stream
Return:		ISDN_CM_OK:success
			ISDN_CM_FAILED or 2 or 3:failed
*************************************************************/
int isdn_msg_decode(IsdnMsgStr *dst, u8 *src, u8 msgtype, int variant, u8 len)		//msg from iua to isdn
{
	switch(variant)
	{
		case VARIANT_ITU:
			return itu_msg_decode(dst, src, msgtype, len);
		case VARIANT_ANSI:
			return ansi_msg_decode(dst, src, msgtype, len);
		case VARIANT_QSIG:
			return qsig_msg_decode(dst, src, msgtype, len);
		default:
			break;
	}

	return -1;
}

/*************************************************************
Function:		isdn_msdc_proc
Description:	isdn Message Sending Control, msg from isdn to iua
Input:		pid:port id
Output:		iua_src:iua msg structure
Return:		NULL
*************************************************************/
void isdn_msdc_proc(u32 pid, IuaMsgStr *iua_src)
{
	int circuit_id, cg_id, ds_0, ds_1, d_chnl, i;
	const pal_circuit_struct *circuit_ptr = NULL;
	const pal_cg_struct *cg_ptr = NULL;

	circuit_id = pid /ISDN_CIRCUIT_CIC;
	circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
		return;

	d_chnl = pid % ISDN_CIRCUIT_CIC;
	cg_id = circuit_ptr->cg_id;
	cg_ptr = pal_cg_ptr(cg_id);
	if(cg_ptr == NULL)
		return;
	if(cg_ptr->attrib.protocol != PROTO_ISDN)
		return;

	ds_0 = cg_ptr->attrib.nfas.prim_link;
	ds_1 = cg_ptr->attrib.nfas.backup_link;

	iua_src->msg_class = IUA_QPTM_MSG;
	if((cg_ptr->attrib.nfas.flag == NFAS_ENABLE) && 
		(circuit_ptr->attrib.d_chnl != d_chnl))
	{
		if(isdn_rs.link_pond[ds_0].dc_status == DS_IS)
		{
			iua_src->e1_no = ds_0;
			for(i = 0; i < PAL_MAX_CIRCUIT; i++)
			{
				circuit_ptr = pal_circuit_ptr(i);
				if(circuit_ptr == NULL)
					continue;
				if(circuit_ptr->cg_id != cg_id)
					continue;

				if((circuit_ptr->attrib.link_id == ds_0) && 
					(isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE) && 
					(isdn_rs.attrib.systemID != circuit_ptr->attrib.plat_id))
				{
					monitor_isdn_msg(pid, "SD<=", iua_src, COL_WHITE);
					isdn_redirect_send(iua_src, 2);	//send to another plat
					return;
				}
			}
		}
		else if(isdn_rs.link_pond[ds_1].dc_status == DS_IS)
		{
			iua_src->e1_no = ds_1;
			for(i = 0; i < PAL_MAX_CIRCUIT; i++)
			{
				circuit_ptr = pal_circuit_ptr(i);
				if(circuit_ptr == NULL)
					continue;
				if(circuit_ptr->cg_id != cg_id)
					continue;

				if((circuit_ptr->attrib.link_id == ds_1) && 
					(isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE) && 
					(isdn_rs.attrib.systemID != circuit_ptr->attrib.plat_id))
				{
					monitor_isdn_msg(pid, "SD<=", iua_src, COL_WHITE);
					isdn_redirect_send(iua_src, 2);	//send to another plat
					return;
				}
			}
		}
		else
		{
			isdn_log_err(pid, "no link is ds_is state!ds_0=%d, ds_0_status=%d, ds_1=%d, ds_1_status=%d\n",
				ds_0, isdn_rs.link_pond[ds_0].dc_status, ds_1, isdn_rs.link_pond[ds_1].dc_status);
			return;
		}
	}
	else
		iua_src->e1_no = circuit_ptr->attrib.link_id;

	monitor_isdn_msg(pid, "SD<=", iua_src, COL_WHITE);
	iua_src->msg_length = htons(iua_src->msg_length);
	if(iua_src->msgcontent.isdn_msg.msg_m.proto_Discr == PROTOCOL_DISCR)
		isdn_msg_csta(iua_src->msgcontent.isdn_msg.msg_m.msg_type, 1);
	if(put_xua_msg((xua_up_msg_t*)&iua_src->msg_class) == -1)
		isdn_log_err(pid, "send msg to iua err!msg class=%d,msg type=0x%02x\r\n",
			iua_src->msg_class, iua_src->msgcontent.isdn_msg.msg_m.msg_type);
	else
		isdn_rs.port_pond[pid].pre_send_msg = iua_src->msgcontent.isdn_msg.msg_m.msg_type;
}

/*************************************************************
Function:		isdn_send_msg
Description:	isdn send msg to iua, include encode msg
Input:		pid:port id, msg_type:msg type
Return:		ISDN_CM_OK:success
			ISDN_CM_FAILED:failed
*************************************************************/
int isdn_send_msg(u32 pid, u8 msg_type)
{
	u16 call_ref;
	u8 callout_fg;
	int ret, variant;
	IuaMsgStr *src = &iua_sd_msg;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	u8 *flw_ptr = src->msgcontent.isdn_msg.ie_content;	//message flow pointer
	const pal_circuit_struct *circuit_ptr = NULL;
	const pal_cg_struct *cg_ptr = NULL;

	memset(src, 0, sizeof(IuaMsgStr));
	call_ref = pPort->call_ref;
	callout_fg = pPort->callout_fg;
	circuit_ptr = pal_circuit_ptr(pid /ISDN_CIRCUIT_CIC);
	if(circuit_ptr == NULL)
		return ISDN_CM_FAILED;

	cg_ptr = pal_cg_ptr(circuit_ptr->cg_id);
	if(cg_ptr == NULL)
		return ISDN_CM_FAILED;
	if(cg_ptr->attrib.protocol != PROTO_ISDN)
		return ISDN_CM_FAILED;

	variant = cg_ptr->attrib.variant;
	
	isdn_sd_msg.msg_m.proto_Discr = PROTOCOL_DISCR;
	isdn_sd_msg.msg_m.cr_len = 2;
	isdn_sd_msg.msg_m.call_ref[0] = ((call_ref & 0x7F00) >> 8) | (callout_fg << 7);	//High
	isdn_sd_msg.msg_m.call_ref[1] = (call_ref & 0xFF);	//Low
	isdn_sd_msg.msg_m.msg_type = msg_type;

	ret = isdn_msg_encode(flw_ptr, &isdn_sd_msg, variant);
	if(ret == -1)
	{
		isdn_log_err(pid, "unknown msg encode, msg=0x%02x\r\n", msg_type);
		return ISDN_CM_FAILED;
	}

	memcpy(&src->msgcontent.isdn_msg.msg_m, &isdn_sd_msg.msg_m, sizeof(MsgMan));
	src->msg_length = ret + 0x0005;
	isdn_msdc_proc(pid, src);

	return ISDN_CM_OK;
}

/*************************************************************
Function:		isdn_send_maintenance_msg
Description:	isdn send ansi isdn maintenance msg to iua, include encode msg
Input:		pid:port id, msg_type:msg type
Return:		ISDN_CM_OK:success
			ISDN_CM_FAILED:failed
*************************************************************/
int isdn_send_maintenance_msg(u32 pid, u8 msg_type)
{
	u16 call_ref;
	u8 callout_fg;
	 int ret;
	IuaMsgStr *src = &iua_sd_msg;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	u8 *flw_ptr = src->msgcontent.isdn_msg.ie_content;	//message flow pointer

	memset(src, 0, sizeof(IuaMsgStr));
	call_ref = pPort->call_ref;
	callout_fg = pPort->callout_fg;
	
	isdn_sd_msg.msg_m.proto_Discr = M_PROTOCOL_DISCR;
	isdn_sd_msg.msg_m.cr_len = 2;
	isdn_sd_msg.msg_m.call_ref[0] = ((call_ref & 0x7F00) >> 8) | (callout_fg << 7);	//High
	isdn_sd_msg.msg_m.call_ref[1] = (call_ref & 0xFF);	//Low
	isdn_sd_msg.msg_m.msg_type = msg_type;

	ret = maintenance_msg_encode(flw_ptr, &isdn_sd_msg);
	if(ret == -1)
	{
		isdn_log_err(pid, "unknown msg encode, msg=0x%02x\r\n", msg_type);
		return ISDN_CM_FAILED;
	}

	memcpy(&src->msgcontent.isdn_msg.msg_m, &isdn_sd_msg.msg_m, sizeof(MsgMan));
	src->msg_length = ret + 0x0005;
	isdn_msdc_proc(pid, src);

	return ISDN_CM_OK;
}


/*************************************************************
Function:		n0_ext_proc
Description:	reinforce to receive abnormity msg at null state
Input:		pid:port id, msg_type:msg type
Return:		NULL
*************************************************************/
static inline void n0_ext_proc(u32 pid, u8 msg_type)
{
	if(msg_type == MSG_REL_COMP)
	{
		isdn_log_err(pid, "receive rel_comp at null state , invalid call reference!\r\n");
		return;
	}
	else if(msg_type == MSG_STAT_ENQ)
	{
		isdn_set_status(&isdn_sd_msg.msg_list.status, 0, CAUSE_STAT_ENQ);
		isdn_send_msg(pid, MSG_STATUS);
		isdn_log_err(pid, "receive stat_enq at null state, response status msg!\r\n");
		return;
	}
	else if(msg_type == MSG_STATUS)
	{
		if(isdn_rv_msg.msg_list.status.call_stat.stat_val == 0)
		{
			isdn_log_err(pid, "receive status at null state, and indicate state value is 0!\r\n");
			return;
		}
		isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_MSG_NOTCOMP);	//cause 101
	}
	else		//unknown or unexpected msg
		isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_INVALID_CR);	//cause 81, invalid call reference
	isdn_send_msg(pid, MSG_REL_COMP);
	isdn_log_err(pid, "invalid call reference!\r\n");
	return;
}

/*************************************************************
Function:		setup_abn_ie
Description:	decode setup with abnormity information elements
Input:		pid:port id, ret:decode result
Return:		NULL
*************************************************************/
static inline void setup_abn_ie(u32 pid, int ret)
{
	if(ret == 3)
	{
		isdn_log_err(pid, "setup mandatory information element is absent!\r\n");
		isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_M_IE_MISS);
	}
	else if(ret == 2)
	{
		isdn_log_err(pid, "setup mandatory information element is err!\r\n");
		isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_IE_INVALID);
	}
	isdn_send_msg(pid, MSG_REL_COMP);
	rel_cr(pid);
}

/*************************************************************
Function:		isdn_mdsc_proc
Description:	isdn Message Distribution Control, msg from iua to isdn
Input:		NULL
Return:		ISDN_CM_OK:success
			ISDN_CM_FAILED:failed
*************************************************************/
static int isdn_mdsc_proc()
{
	u32 pid, cic, head_cic;
	u16 cref = 0;
	int msg_type, variant, cg_id, circuit_newId, link_id;
	u8 global_flag;
	int ret, len, i;
	const pal_circuit_struct *circuit_ptr = NULL;
	const pal_cg_struct *cg_ptr = NULL;
	u8 *flw_ptr;
	
	flw_ptr = iua_rv_msg.msgcontent.isdn_msg.ie_content;
	len = iua_rv_msg.msg_length - 5;

	isdn_msg_csta(iua_rv_msg.msgcontent.isdn_msg.msg_m.msg_type, 0);
	if(iua_rv_msg.msgcontent.isdn_msg.msg_m.cr_len != 2)
	{
		isdn_log_err(0, "call reference len is not 2!\r\n");	//dummy call reference
		monitor_isdn_msg(0, "RV=>", &iua_rv_msg,COL_YELLOW);
		return ISDN_CM_FAILED;
	}
	
	link_id = iua_rv_msg.e1_no;
	if((circuit_ptr = pal_isdn_find_circuit_of_link(link_id)) == NULL)
	{
		isdn_log_err(0, "mdsc: link_id %d is unknown link!\r\n", link_id);
		monitor_isdn_msg(0, "RV=>", &iua_rv_msg,COL_YELLOW);
		return ISDN_CM_FAILED;
	}
//	circuit_id = circuit_ptr->id;
	cg_id = circuit_ptr->cg_id;
	cg_ptr = pal_cg_ptr(cg_id);
	if(cg_ptr == NULL)
		return ISDN_CM_FAILED;
	if(cg_ptr->attrib.protocol != PROTO_ISDN)
		return ISDN_CM_FAILED;
	if(!(cg_ptr->attrib.variant == VARIANT_ITU || cg_ptr->attrib.variant == VARIANT_ANSI || cg_ptr->attrib.variant == VARIANT_QSIG) || 
		(cg_ptr->attrib.variant == VARIANT_QSIG && (cg_ptr->attrib.nfas.flag || circuit_ptr->attrib.user_network_if == NETWORK_SIDE)))
		return ISDN_CM_FAILED;

	variant = cg_ptr->attrib.variant;
	
	cref = iua_rv_msg.msgcontent.isdn_msg.msg_m.call_ref[0];
	cref = (cref << 8) | (iua_rv_msg.msgcontent.isdn_msg.msg_m.call_ref[1]);
	msg_type = iua_rv_msg.msgcontent.isdn_msg.msg_m.msg_type;
	memset(&isdn_sd_msg, 0, sizeof(IsdnMsgStr));
	memset(&isdn_rv_msg, 0, sizeof(IsdnMsgStr));

	if((cref & 0x7FFF) == 0)	//Global call reference message 
	{
		global_flag = 1;
		pid = circuit_ptr->id * ISDN_CIRCUIT_CIC;
		isdn_rs.port_pond[pid].call_ref = cref;
		isdn_rs.port_pond[pid].callout_fg = ((cref >> 15) ^ 0x01);
		if((msg_type != MSG_RESTART) && 
			(msg_type != MSG_REST_ACK) && 
			(msg_type != MSG_STATUS))
		{
			isdn_log_err(0, "invalid call reference, cr = 0!\r\n");
			isdn_set_status(&isdn_sd_msg.msg_list.status, 0, CAUSE_INVALID_CR);	//cause 81, state?
			isdn_send_msg(pid, MSG_STATUS);
			return ISDN_CM_FAILED;
		}
		else if(msg_type == MSG_STATUS)
		{
			isdn_log_err(0, "receive status in cr=0, reserved in current state!\r\n");
			return ISDN_CM_FAILED;
		}
	}
	else
	{
		global_flag = 0;
		if(cg_ptr->attrib.nfas.flag == NFAS_ENABLE)
		{
			if(isdn_rs.link_pond[link_id].dc_status != DS_IS)
			{
				isdn_log_err(0, "the link %d is not DS_IS state!\r\n", link_id);
				return ISDN_CM_FAILED;
			}
			
			for(i = 0; i < PAL_MAX_CIRCUIT; i++)
			{
				circuit_ptr = pal_circuit_ptr(i);
				if(circuit_ptr == NULL)
					continue;
				if(circuit_ptr->cg_id != cg_id)
					continue;

				if((circuit_ptr->enable) && 
					(pid = find_port_by_callref(cref, i)))
				{
//					circuit_id = i;
					break;
				}
			}
			if((pid == 0) && (msg_type != MSG_SETUP) && 
				(isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE) && 
				(circuit_ptr->attrib.plat_id == isdn_rs.attrib.systemID))
			{
				monitor_isdn_msg(0, "RV=>", &iua_rv_msg, COL_YELLOW);
				isdn_redirect_send(&iua_rv_msg, 3);	//send to another plat
				return ISDN_CM_FAILED;
			}
		}
		else
			pid = find_port_by_callref(cref, circuit_ptr->id);
	}

	memcpy(&isdn_rv_msg.msg_m, &iua_rv_msg.msgcontent.isdn_msg.msg_m, sizeof(MsgMan));
	ret = isdn_msg_decode(&isdn_rv_msg, flw_ptr, msg_type, variant, len);
	if((pid == 0) && (global_flag == 0))
	{
		if(msg_type != MSG_SETUP)	//NULL STATE of other proc
		{
			isdn_log_err(0, "receice msg=0x%02x, when port id is 0!\r\n", msg_type);
			pid = circuit_ptr->id * ISDN_CIRCUIT_CIC;
			isdn_rs.port_pond[pid].call_ref = cref;
			isdn_rs.port_pond[pid].callout_fg = ((cref >> 15) ^ 0x01);
			n0_ext_proc(pid, msg_type);
			return ISDN_CM_FAILED;
		}
		else if((cref & 0x8000) != 0)
		{
			isdn_log_err(0, "the call reference is not from the original call!\r\n");
			return ISDN_CM_FAILED;
		}
		//else goto setup to find port id
	}

	if(ret == 0)
	{
		isdn_log_err(pid, "decode isdn msg is unknown! msg=0x%02x\r\n",msg_type);
		isdn_set_status(&isdn_sd_msg.msg_list.status, isdn_rs.port_pond[pid].fsm_state.cpc_state, CAUSE_MSG_NOTCOMP_NOTIMPL);	//cause 97 or 98	u01-04
		isdn_send_msg(pid, MSG_STATUS);
		return ISDN_CM_FAILED;
	}
	else if(ret == -1)
	{
		isdn_log_err(pid, "unknown protocol discriminator! proto_discr=%d\r\n", iua_rv_msg.msgcontent.isdn_msg.msg_m.proto_Discr);
		return ISDN_CM_FAILED;
	}
	
	switch(msg_type)
	{
		case MSG_SETUP:
			if(pid != 0)
			{
				isdn_log_err(0, "setup has reveived! pid=%d\r\n", pid);
				return ISDN_CM_FAILED;
			}
			if(ret != 1)
			{
				pid = circuit_ptr->id * ISDN_CIRCUIT_CIC;
				isdn_rs.port_pond[pid].call_ref = cref;
				isdn_rs.port_pond[pid].callout_fg = ((cref >> 15) ^ 0x01);
				setup_abn_ie(pid, ret);
				return ISDN_CM_FAILED;
			}
			if(cg_ptr->attrib.nfas.flag)
			{
				if((isdn_rv_msg.msg_list.setup.chnl_id.pres) &&
					(isdn_rv_msg.msg_list.setup.chnl_id.b3.int_id_pre))
				{
					if((circuit_newId = find_circuit_by_interfaceId(cg_id, isdn_rv_msg.msg_list.setup.chnl_id.b3.int_id)) == -1)
					{
						if(circuit_ptr->attrib.plat_id == isdn_rs.attrib.systemID)
						{
							monitor_isdn_msg(0, "RV=>", &iua_rv_msg, COL_YELLOW);
							isdn_redirect_send(&iua_rv_msg, 3);	//send to another plat
							return ISDN_CM_FAILED;
						}
						else
						{
							isdn_log_err(0, "not find current circuit! circuit id=%d\r\n", circuit_ptr->id);
							return ISDN_CM_FAILED;
						}
					}
					else
					{
						circuit_ptr = pal_circuit_ptr(circuit_newId);
						if(circuit_ptr == NULL)
						{
							isdn_log_err(0, "receive setup err! circuit_id=%d, can't find circuit_ptr!\r\n", circuit_newId);
							return ISDN_CM_FAILED;
						}
						if(circuit_ptr->cg_id != cg_id)
							return ISDN_CM_FAILED;
					}
				}
				else
				{
					isdn_log_err(0, "err!\n");
					return ISDN_CM_FAILED;
				}
			}
			if((isdn_rv_msg.msg_list.setup.chnl_id.pres) && 
				(isdn_rv_msg.msg_list.setup.chnl_id.b3.int_type))
			{
				head_cic = circuit_ptr->attrib.head_cic;
				if(circuit_ptr->attrib.cic_range == 24)
					head_cic--;
				cic = head_cic + isdn_rv_msg.msg_list.setup.chnl_id.b3.chnl_num;
				if((cic < circuit_ptr->attrib.head_cic) || (cic - circuit_ptr->attrib.head_cic) >= (circuit_ptr->attrib.cic_range))
				{
					pid = circuit_ptr->id * ISDN_CIRCUIT_CIC;
					isdn_rs.port_pond[pid].call_ref = cref;
					isdn_rs.port_pond[pid].callout_fg = ((cref >> 15) ^ 0x01);
					isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_IE_INVALID);
					isdn_send_msg(pid, MSG_REL_COMP);
					isdn_log_err(0, "decode cic err!cic=0x%04x\r\n",cic);
					return ISDN_CM_FAILED;
				}
				else		//find pid by cic
				{
					pid = find_port_by_cic(cic, circuit_ptr->id);
					if(isdn_rs.port_pond[pid].cic_state.maintenance_state != IN_SERVICE)
					{
						isdn_log_err(pid, "this cic is not in service in receive setup!\n");
						return ISDN_CM_FAILED;
					}
					if(isdn_rs.port_pond[pid].enable == 1)	//priority
					{
						if(!cg_ptr->attrib.priority)
						{
							isdn_event_handle(pid, ISDN_REATTEMPT_IND);
							rel_cr(pid);
							isdn_cpc_clear(&isdn_rs.port_pond[pid]);
						}
						else
							return ISDN_CM_FAILED;
					}
				}
			}
			if(pid == 0)	//assign new pid
			{
				if(cg_ptr->attrib.nfas.flag)
				{
					if(!isdn_rv_msg.msg_list.setup.chnl_id.b3.int_id_pre)
					{
						cic = msc_give_cic_value(cg_ptr->attrib.tg_id, -1);
						if((circuit_ptr = pal_locate_circuit(cg_id, cic)) == NULL)
						{
							isdn_log_err(0, "the assign cic is not found the adscription of circuit! cic=%, cg_id=%d\n",cic, cg_id);
							return ISDN_CM_FAILED;
						}
					}
					else
						cic = msc_give_cic_value(cg_ptr->attrib.tg_id, circuit_ptr->attrib.head_cic);
				}
				else
					cic = msc_give_cic_value(cg_ptr->attrib.tg_id, circuit_ptr->attrib.head_cic);
				pid = find_port_by_cic(cic, circuit_ptr->id);
			}
			isdn_rs.port_pond[pid].call_ref = cref;
			//msg_cref[pid] = cref;
			if(circuit_ptr->attrib.user_network_if)
			{
				isdn_rs.port_pond[pid].timer_flag |= CALLIN_FLAG;
				isdn_rs.port_pond[pid].cic_state.call_state = CALLIN_FLAG;
			}
			else
			{
				isdn_rs.port_pond[pid].timer_flag |= CALLOUT_FLAG;
				isdn_rs.port_pond[pid].cic_state.call_state = CALLOUT_FLAG;
			}
			isdn_rs.port_pond[pid].callout_fg = 1;
			isdn_rs.port_pond[pid].enable = 1;
			break;
		case MSG_DISC:
			if(ret == 3)
			{
				isdn_log_err(pid, "disc mandatory information element is absent!\r\n");
				isdn_set_cause(&isdn_rv_msg.msg_list.disc.cause, CAUSE_M_IE_MISS);
			}
			else if(ret == 2)
			{
				isdn_log_err(pid, "disc mandatory information element is err!\r\n");
				isdn_set_cause(&isdn_rv_msg.msg_list.disc.cause, CAUSE_IE_INVALID);
			}
			memcpy(&isdn_sd_msg.msg_list.rel.cause, &isdn_rv_msg.msg_list.disc.cause, sizeof(CauseStr));
			break;
		case MSG_REL:
			if(ret == 3)	//u03-18  u00-13  u07-12
			{
				isdn_log_err(pid, "rel mandatory information element is absent!\r\n");
				isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_M_IE_MISS);
				memcpy(&isdn_rv_msg, &isdn_sd_msg, sizeof(IsdnMsgStr));
			}
			else if(ret == 2)	//u03-19  u00-14  u07-13	
			{
				isdn_log_err(pid, "rel mandatory information element is err!\r\n");
				isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_IE_INVALID);
				memcpy(&isdn_rv_msg, &isdn_sd_msg, sizeof(IsdnMsgStr));
			}
			else
				memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr));
			break;
		case MSG_RESTART:
		case MSG_REST_ACK:
			if(msg_type == MSG_RESTART)
			{
				if(cg_ptr->attrib.nfas.flag)
				{
					if((isdn_rv_msg.msg_list.restart.chnl_id.pres) &&
						(isdn_rv_msg.msg_list.restart.chnl_id.b3.int_id_pre))
					{
						if((circuit_newId = find_circuit_by_interfaceId(cg_id, isdn_rv_msg.msg_list.restart.chnl_id.b3.int_id)) == -1)
						{
							if(circuit_ptr->attrib.plat_id == isdn_rs.attrib.systemID)
							{
								monitor_isdn_msg(0, "RV=>", &iua_rv_msg, COL_YELLOW);
								isdn_redirect_send(&iua_rv_msg, 3);	//send to another plat
								return ISDN_CM_FAILED;
							}
							else
							{
								isdn_log_err(0, "not find current circuit! circuit id=%d\r\n", circuit_ptr->id);
								return ISDN_CM_FAILED;
							}
						}
						else
						{
							circuit_ptr = pal_circuit_ptr(circuit_newId);
							if(circuit_ptr == NULL)
							{
								isdn_log_err(0, "receive restart err! circuit_id=%d, can't find circuit_ptr!\r\n", circuit_newId);
								return ISDN_CM_FAILED;
							}
							if(circuit_ptr->cg_id != cg_id)
								return ISDN_CM_FAILED;
						}
					}
					else
					{
						isdn_log_err(0, "receive restart err!\n");
						return ISDN_CM_FAILED;
					}
				}
			}
			else
			{
				if(cg_ptr->attrib.nfas.flag)
				{
					if((isdn_rv_msg.msg_list.restAck.chnl_id.pres) &&
						(isdn_rv_msg.msg_list.restAck.chnl_id.b3.int_id_pre))
					{
						if((circuit_newId = find_circuit_by_interfaceId(cg_id, isdn_rv_msg.msg_list.restAck.chnl_id.b3.int_id)) == -1)
						{
							if(circuit_ptr->attrib.plat_id == isdn_rs.attrib.systemID)
							{
								monitor_isdn_msg(0, "RV=>", &iua_rv_msg, COL_YELLOW);
								isdn_redirect_send(&iua_rv_msg, 3);	//send to another plat
								return ISDN_CM_FAILED;
							}
							else
							{
								isdn_log_err(0, "not find current circuit! circuit id=%d\r\n", circuit_ptr->id);
								return ISDN_CM_FAILED;
							}
						}
						else
						{
							circuit_ptr = pal_circuit_ptr(circuit_newId);
							if(circuit_ptr == NULL)
							{
								isdn_log_err(0, "receive restart ack err! circuit_id=%d, can't find circuit_ptr!\r\n", circuit_newId);
								return ISDN_CM_FAILED;
							}
							if(circuit_ptr->cg_id != cg_id)
								return ISDN_CM_FAILED;
						}
					}
					else
					{
						isdn_log_err(0, "receive restart ack err!\n");
						return ISDN_CM_FAILED;
					}
				}
			}
			pid = circuit_ptr->id * ISDN_CIRCUIT_CIC;
			head_cic = circuit_ptr->attrib.head_cic;
			if(circuit_ptr->attrib.cic_range == 24)
				head_cic--;
			isdn_rs.port_pond[pid].callout_fg = ((cref >> 15) ^ 0x01);
			isdn_rs.link_pond[circuit_ptr->attrib.link_id].restart_clas = isdn_rv_msg.msg_list.restart.restart_ind.clas;
			if(isdn_rs.link_pond[circuit_ptr->attrib.link_id].restart_clas == 0)
				isdn_rs.port_pond[pid].cic_val = head_cic + isdn_rv_msg.msg_list.restart.chnl_id.b3.chnl_num;
		default:	//other
			if(ret == 3)
			{
				isdn_log_err(pid, "msg=0x%02x mandatory information element is absent!\r\n", msg_type);
				isdn_set_status(&isdn_sd_msg.msg_list.status, isdn_rs.port_pond[pid].fsm_state.cpc_state, CAUSE_M_IE_MISS);
				isdn_send_msg(pid, MSG_STATUS);
				return ISDN_CM_FAILED;
			}
			else if(ret == 2)
			{
				isdn_log_err(pid, "msg=0x%02x mandatory information element is err!\r\n",msg_type);
				isdn_set_status(&isdn_sd_msg.msg_list.status, isdn_rs.port_pond[pid].fsm_state.cpc_state, CAUSE_IE_INVALID);
				isdn_send_msg(pid, MSG_STATUS);
				return ISDN_CM_FAILED;
			}
			break;
	}

	monitor_isdn_msg(pid, "RV=>", &iua_rv_msg, COL_YELLOW);
	isdn_rs.port_pond[pid].msg_cmd = msg_type;
	if(global_flag)
	{
		isdn_restart_ctrl(pid);
	}
	else if((isdn_rs.port_pond[pid].cic_state.call_state == CALLOUT_FLAG) || 
		(isdn_rs.port_pond[pid].cic_state.call_state == CALLIN_FLAG))
	{
		isdn_cpc_proc(pid);
	}
	
	if(isdn_rs.port_pond[pid].msg_cmd != 0)
	{
		isdn_log_err(pid, "ignore the message! msg_cmd=0x%x\r\n", isdn_rs.port_pond[pid].msg_cmd);
		isdn_rs.port_pond[pid].msg_cmd = 0;
	}
	
	return ISDN_CM_OK;
}

static int isdn_m_mdsc_proc()
{
	u32 pid, cic, head_cic;
	u16 cref = 0;
	u8 msg_type, link_id;
	int ret, len, cg_id, circuit_newId;
	const pal_circuit_struct *circuit_ptr = NULL;
	const pal_cg_struct *cg_ptr = NULL;
	u8 *flw_ptr;
	flw_ptr = iua_rv_msg.msgcontent.isdn_msg.ie_content;
	len = iua_rv_msg.msg_length - 5;
	link_id = iua_rv_msg.e1_no;

	if((circuit_ptr = pal_isdn_find_circuit_of_link(link_id)) == NULL)
	{
		isdn_log_err(0, "m_mdsc: link_id %d is unknown link!\r\n", link_id);
		monitor_isdn_msg(0, "RV=>", &iua_rv_msg,COL_YELLOW);
		return ISDN_CM_FAILED;
	}
	cg_id = circuit_ptr->cg_id;
	cg_ptr = pal_cg_ptr(cg_id);
	if(cg_ptr == NULL)
		return ISDN_CM_FAILED;
	if(cg_ptr->attrib.protocol != PROTO_ISDN)
		return ISDN_CM_FAILED;
	if(!(cg_ptr->attrib.variant == VARIANT_ITU || cg_ptr->attrib.variant == VARIANT_ANSI || cg_ptr->attrib.variant == VARIANT_QSIG) || 
		(cg_ptr->attrib.variant == VARIANT_QSIG && (cg_ptr->attrib.nfas.flag || circuit_ptr->attrib.user_network_if == NETWORK_SIDE)))
		return ISDN_CM_FAILED;
	
	if(cg_ptr->attrib.variant != VARIANT_ANSI)
	{
		isdn_log_err(0, "variant type=%d, is not ansi!\r\n", cg_ptr->attrib.variant);
		monitor_isdn_msg(0, "RV=>", &iua_rv_msg, COL_YELLOW);
		return ISDN_CM_FAILED;
	}
	if(iua_rv_msg.msgcontent.isdn_msg.msg_m.cr_len != 2)
	{
		isdn_log_err(0, "call reference len is not 2!)\n");	//dummy call reference
		return ISDN_CM_FAILED;
	}
	cref = iua_rv_msg.msgcontent.isdn_msg.msg_m.call_ref[0];
	cref = (cref << 8) | (iua_rv_msg.msgcontent.isdn_msg.msg_m.call_ref[1]);
	msg_type = iua_rv_msg.msgcontent.isdn_msg.msg_m.msg_type;

	memset(&isdn_sd_msg, 0, sizeof(IsdnMsgStr));
	memset(&isdn_rv_msg, 0, sizeof(IsdnMsgStr));
	if(cref & 0x7FFF)	//NOT Global call reference message 
	{
		isdn_log_err(pid, "Invalid global call reference, CR=0x%02x\r\n",cref);
		return ISDN_CM_FAILED;
	}
	memcpy(&isdn_rv_msg.msg_m, &iua_rv_msg.msgcontent.isdn_msg.msg_m, sizeof(MsgMan));
	ret = maintenance_msg_decode(&isdn_rv_msg, flw_ptr, msg_type, len);
	if(ret != 1)
	{
		isdn_log_err(0, "decode msg err!\r\n");
		return ISDN_CM_FAILED;
	}

	switch(msg_type)
	{
		case MSG_SERVICE:
			if((cref & 0x8000) != 0)
			{
				isdn_log_err(0, "the call reference of service is err!\r\n");
				return ISDN_CM_FAILED;
			}

			if(cg_ptr->attrib.nfas.flag)
			{
				if((isdn_rv_msg.msg_list.service.chnl_id.pres) &&
					(isdn_rv_msg.msg_list.service.chnl_id.b3.int_id_pre))
				{
					if((circuit_newId = find_circuit_by_interfaceId(cg_id, isdn_rv_msg.msg_list.service.chnl_id.b3.int_id)) == -1)
					{
						if(circuit_ptr->attrib.plat_id == isdn_rs.attrib.systemID)
						{
							monitor_isdn_msg(0, "RV=>", &iua_rv_msg, COL_YELLOW);
							isdn_redirect_send(&iua_rv_msg, 3);	//send to another plat
							return ISDN_CM_FAILED;
						}
						else
						{
							isdn_log_err(0, "not find current circuit! circuit id=%d\r\n", circuit_ptr->id);
							return ISDN_CM_FAILED;
						}
					}
					else
					{
						circuit_ptr = pal_circuit_ptr(circuit_newId);
						if(circuit_ptr == NULL)
						{
							isdn_log_err(0, "receive SERVICE err! circuit_id=%d, can't find circuit_ptr!\r\n", circuit_newId);
							return ISDN_CM_FAILED;
						}
						if(circuit_ptr->cg_id != cg_id)
							return ISDN_CM_FAILED;
					}
				}
				else
				{
					isdn_log_err(0, "err!\n");
					return ISDN_CM_FAILED;
				}
			}

			if((isdn_rv_msg.msg_list.service.chnl_id.pres) && 
				(isdn_rv_msg.msg_list.service.chnl_id.b3.int_type))
			{
				head_cic = circuit_ptr->attrib.head_cic;
				if(circuit_ptr->attrib.cic_range == 24)
					head_cic--;
				if(isdn_rv_msg.msg_list.service.chnl_id.b3.has_chnl)
					cic = head_cic + isdn_rv_msg.msg_list.service.chnl_id.b3.chnl_num;
				else
				{
					if(circuit_ptr->attrib.cic_range == 24)	// T1
						cic = circuit_ptr->attrib.head_cic + 23;
					else
						cic = circuit_ptr->attrib.head_cic;
				}
			}
			else
			{
				isdn_log_err(0, "SERVICE does not include chnl_id ie(pres=%d), or chnl_id does not include cic(int_type=%d)!\r\n", 
					isdn_rv_msg.msg_list.service.chnl_id.pres, isdn_rv_msg.msg_list.service.chnl_id.b3.int_type);
				return ISDN_CM_FAILED;
			}
			break;
		case MSG_SERVICE_ACK:
			if(cg_ptr->attrib.nfas.flag)
			{
				if((isdn_rv_msg.msg_list.servAck.chnl_id.pres) &&
					(isdn_rv_msg.msg_list.servAck.chnl_id.b3.int_id_pre))
				{
					if((circuit_newId = find_circuit_by_interfaceId(cg_id, isdn_rv_msg.msg_list.servAck.chnl_id.b3.int_id)) == -1)
					{
						if(circuit_ptr->attrib.plat_id == isdn_rs.attrib.systemID)
						{
							monitor_isdn_msg(0, "RV=>", &iua_rv_msg, COL_YELLOW);
							isdn_redirect_send(&iua_rv_msg, 3);	//send to another plat
							return ISDN_CM_FAILED;
						}
						else
						{
							isdn_log_err(0, "not find current circuit! circuit id=%d\r\n", circuit_ptr->id);
							return ISDN_CM_FAILED;
						}
					}
					else
					{
						circuit_ptr = pal_circuit_ptr(circuit_newId);
						if(circuit_ptr == NULL)
						{
							isdn_log_err(0, "receive SERVICE ACK err! circuit_id=%d, can't find circuit_ptr!\r\n", circuit_newId);
							return ISDN_CM_FAILED;
						}
						if(circuit_ptr->cg_id != cg_id)
							return ISDN_CM_FAILED;
					}
				}
				else
				{
					isdn_log_err(0, "err!\n");
					return ISDN_CM_FAILED;
				}
			}
			
			if((isdn_rv_msg.msg_list.servAck.chnl_id.pres) && 
				(isdn_rv_msg.msg_list.servAck.chnl_id.b3.int_type))
			{
				head_cic = circuit_ptr->attrib.head_cic;
				if(circuit_ptr->attrib.cic_range == 24)
					head_cic--;
				if(isdn_rv_msg.msg_list.servAck.chnl_id.b3.has_chnl)
					cic = head_cic + isdn_rv_msg.msg_list.servAck.chnl_id.b3.chnl_num;
				else
				{
					if(circuit_ptr->attrib.cic_range == 24)	// T1
						cic = circuit_ptr->attrib.head_cic + 23;
					else
						cic = circuit_ptr->attrib.head_cic;
				}
			}
			else
			{
				isdn_log_err(0, "SERVICE ACK does not include chnl_id ie(pres=%d), or chnl_id does not include cic(int_type=%d)!\r\n",
					isdn_rv_msg.msg_list.servAck.chnl_id.pres, isdn_rv_msg.msg_list.servAck.chnl_id.b3.int_type);
				return ISDN_CM_FAILED;
			}
			break;
		default:
			return ISDN_CM_FAILED;
	}

	head_cic = circuit_ptr->attrib.head_cic;
	if(circuit_ptr->attrib.cic_range == 24)
		head_cic--;
	if((cic < circuit_ptr->attrib.head_cic) || 
		(cic - circuit_ptr->attrib.head_cic) >= (circuit_ptr->attrib.cic_range))
	{
		isdn_log_err(0, "decode cic err!cic=0x04x\r\n", cic);
		return ISDN_CM_FAILED;
	}
	else
	{
		pid = find_port_by_cic(cic, circuit_ptr->id);
		if((circuit_ptr->attrib.d_chnl+head_cic) == cic)
			isdn_rs.port_pond[pid].timer_flag |= DC_M_FLAG;
		else
			isdn_rs.port_pond[pid].timer_flag |= BC_M_FLAG;
	}

	monitor_isdn_msg(pid, "RV=>", &iua_rv_msg, COL_YELLOW);
	isdn_rs.port_pond[pid].msg_cmd = msg_type;
	if(isdn_rs.port_pond[pid].timer_flag & DC_M_FLAG)
		service_dc_proc(pid);
	else if(isdn_rs.port_pond[pid].timer_flag & BC_M_FLAG)
		service_bc_proc(pid);
	
	if(isdn_rs.port_pond[pid].msg_cmd != 0)
	{
		isdn_log_err(pid, "ignore the message! msg_cmd=%d\r\n", isdn_rs.port_pond[pid].msg_cmd);
		isdn_rs.port_pond[pid].msg_cmd = 0;
	}

	return ISDN_CM_OK;
}


/*************************************************************
Function:		isdn_receive_msg
Description:	isdn receive msg from iua 
Input:		NULL
Return:		ISDN_CM_OK:success
			ISDN_CM_FAILED:failed
*************************************************************/
int isdn_receive_msg()
{
	u16 len;
	int link_id;
	xua_up_msg_t *src = 0;
	
	if((get_xua_msg(IUA_APP, &src)) <= 0)
	{
//		printf("isdn get iua err!\n");
		return ISDN_CM_FAILED;
	}
	memcpy(&iua_rv_msg.msg_class, src, sizeof(xua_up_msg_t));
	link_id = iua_rv_msg.e1_no;
	if(iua_rv_msg.msg_class == IUA_MGMT_CMD)	//heartbeat
	{
		if(iua_rv_msg.msgcontent.lkmsg.opercode == M2UA_LK_DOWN)
		{
			isdn_rs.link_pond[link_id].lk2_status = LK_OOS;	//out of service
		}
		else if(iua_rv_msg.msgcontent.lkmsg.opercode == M2UA_LK_UP)
		{
			isdn_rs.link_pond[link_id].lk2_status = LK_IS;	//in service
			isdn_rs.link_pond[link_id].link_heartbeat_time = 0;
		}
		isdn_rs.link_pond[link_id].lk3_status = isdn_rs.link_pond[link_id].lk2_status;
		return ISDN_CM_FAILED;
	}

	len = ntohs(iua_rv_msg.msg_length);
	iua_rv_msg.msg_length = len;
	if((iua_rv_msg.msgcontent.isdn_msg.msg_m.proto_Discr == PROTOCOL_DISCR) && 
		(len > 4))
	{
		isdn_mdsc_proc();
		return ISDN_CM_OK;
	}
	else if((iua_rv_msg.msgcontent.isdn_msg.msg_m.proto_Discr == M_PROTOCOL_DISCR) && 
		(len > 4))
	{
		isdn_m_mdsc_proc();
		return ISDN_CM_OK;
	}
	
	isdn_log_err(0, "there is not isdn msg!\r\n");
	return ISDN_CM_FAILED;
}


int isdn_redirect_receive()
{
	int type, link_id;
	message_list msg_trans;
	xua_up_msg_t iua_msg;
	
	if(iptrGetMessage(&msg_trans, ISDN_IP_PORT) == 0)
	{
//		isdn_log_err(0, "do not receive msg from another plat!\r\n");
		return ISDN_CM_FAILED;
	}
	if(msg_trans.msgSrcIP != isdn_rs.attrib.isdn_remote_ip)
	{
		isdn_log_err(0, "remote ip is not compatible!\r\n");
		return ISDN_CM_FAILED;
	}
	
	type = msg_trans.msgContent[0];
	
	switch(type)
	{
		case 1:	//heartbeat
			if(msg_trans.msgLength == 3)
			{
				link_id = msg_trans.msgContent[1];
				isdn_rs.link_pond[link_id].dc_status = msg_trans.msgContent[2];
				isdn_rs.link_pond[link_id].plat_heartbeat_time = isdn_timer_var.t1s;
				return ISDN_CM_OK;
			}
			break;
		case 2:	//msg, don't decode msg, and send the msg to the other switch
			if(msg_trans.msgLength > 5)
			{
				memcpy(&iua_msg, msg_trans.msgContent+1, msg_trans.msgLength-1);
				put_xua_msg(&iua_msg);
				return ISDN_CM_OK;
			}
			break;
		case 3:	//msg, need decode msg
			if(msg_trans.msgLength > 5)
			{
				memcpy(&iua_rv_msg.msg_class, msg_trans.msgContent+1, msg_trans.msgLength-1);
				iua_rv_msg.msg_length = ntohs(iua_rv_msg.msg_length);
				if(iua_rv_msg.msgcontent.isdn_msg.msg_m.proto_Discr == PROTOCOL_DISCR)
				{
					isdn_mdsc_proc();
					return ISDN_CM_OK;
				}
				else if(iua_rv_msg.msgcontent.isdn_msg.msg_m.proto_Discr == M_PROTOCOL_DISCR)
				{
					isdn_m_mdsc_proc();
					return ISDN_CM_OK;
				}
			}
			break;
		default:
			break;
	}

	isdn_log_err(0, "redirect receive err!\n");
	return ISDN_CM_FAILED;
}

