#include "./include/m2ua_pub.h"
#include "./include/m2ua.h"
#include "./include/m2ua_const.h"
#include "./include/m2ua_struct.h"
#include "./include/m2ua_ext.h"
#include "./include/m2ua_msg.h"
#include "./include/m2ua_debug.h"

//add by yizane
int find_sg_by_ipv4(DWORD ipv4,uint16_t sg_id)
{
	WORD sg;
	BYTE	type;
	BYTE	ascitemp_buf[256];
	
	if (sg_id == M2UA_LISTEN_SG_NUM_0  ||
			sg_id == M2UA_LISTEN_SG_NUM_1)
		type =	M2UA_APP;
	else if (sg_id == IUA_LISTEN_SG_NUM_0 ||
					 sg_id == IUA_LISTEN_SG_NUM_1)
		type =	IUA_APP;
	
	for (sg = 0; sg < M2UA_MAX_SG_NUM; sg++)
	{
		if (m2ua_para.sg_para[sg].enable &&
			m2ua_sg_info[sg].enable	&&
			m2ua_para.sg_para[sg].server &&
			((m2ua_para.sg_para[sg].xUA_ack>>1)==type) &&			
			(m2ua_para.sg_para[sg].ip == ipv4)
			)
			return sg;
	}
	sprintf(ascitemp_buf, "can't find sg by ipv4: %X\n\r", ipv4);
	m2ua_log_err(sg_id, ascitemp_buf);
	return -1;
}
/*
int find_sg_by_ipv4(DWORD ipv4)
{
	WORD sg;
	
	for (sg = 0; sg < M2UA_MAX_SG_NUM; sg++)
	{
		if (m2ua_para.sg_para[sg].enable &&
			m2ua_para.sg_para[sg].server &&
			(m2ua_para.sg_para[sg].ip == ipv4))
			return sg;
	}
	
	return -1;
}
*/
int rel_sid(WORD sg, BYTE lk)
{
	WORD	ostr;
	BYTE	dw_index, bit_index;
	
	if (m2ua_lk_info[lk].sid == 0)
		return -1;
	
	ostr = m2ua_lk_info[lk].sid - 1;
	m2ua_lk_info[lk].sid = 0;
	
	dw_index 	= ostr / 32;
	bit_index	= ostr % 32;
	
	m2ua_sg_info[sg].sid_st[dw_index] &= (~(0x00000001 << bit_index));
	m2ua_sg_info[sg].rem_ostrs++;
	
	return 0;
}

int assign_sid(WORD sg, BYTE lk)
{
	WORD	i;
	BYTE	dw_index, bit_index;
	
	if ((m2ua_sg_info[sg].ostrs < 2) ||(m2ua_sg_info[sg].ostrs > 257) ||
		(m2ua_sg_info[sg].rem_ostrs == 0) || (m2ua_lk_info[lk].sid > 0))
		return -1;
	
	for (i = 0; i < m2ua_sg_info[sg].ostrs - 1; i++)
	{
		dw_index 	= i / 32;
		bit_index	= i % 32;
		if ((m2ua_sg_info[sg].sid_st[dw_index] >> bit_index) & 1)
			continue;
		else
		{
			m2ua_sg_info[sg].sid_st[dw_index] |= (0x00000001 << bit_index);
			m2ua_sg_info[sg].rem_ostrs--;
			m2ua_lk_info[lk].sid = i + 1;
			return 0;
		}
	}
	
	return -1;
}

int rel_sg_lk(WORD sg_id)
{
	WORD 	lk;
	BYTE	flag = 0;
	
	if ((m2ua_para.sg_para[sg_id].enable == 0) ||
		(m2ua_para.sg_para[sg_id].enable == 2))
		flag = 1;
	
	for (lk = 0; lk < M2UA_MAX_LK_NUM; lk++)
	{
		if ((m2ua_para.lk_para[lk].lk_sg == sg_id) &&
			m2ua_lk_info[lk].enable)
		{
			rel_sid(sg_id, lk);
			if (m2ua_lk_info[lk].lk_st > M2UA_LK_DOWN)
			{
				m2ua_lk_info[lk].lk_st = M2UA_LK_DOWN;
				m2ua_lk_info[lk].alarm_code = m2ua_sg_info[sg_id].alarm_code;
				m2ua_sd_mtp3_primi(lk, M2UA_LK_DOWN);
				m2ua_csta.lk_csta[lk].lk_dn_times++;
			}
			if (flag)
			{
				m2ua_lk_info[lk].enable = 0;
				m2ua_lk_info[lk].lk_st = M2UA_LK_IDLE;
			}
		}
	}
	
	m2ua_sg_info[sg_id].up_lks_cur = 0;
	m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_NORMAL;
	
	return 0;
}

int chg_sg_lk_status(WORD sg_id, BYTE status)
{
	WORD lk;
	
	for (lk = 0; lk < M2UA_MAX_LK_NUM; lk++)
	{
		if ((m2ua_para.lk_para[lk].lk_sg == sg_id) &&
			m2ua_lk_info[lk].enable)
			m2ua_lk_info[lk].lk_st = status;
	}
	
	return 1;
}

int m2ua_fsm(WORD sg_id)
{
	WORD 	m2ua_cmd, mtp3_cmd, mgmt_cmd;
	BYTE	iid, lk_enable;
	BYTE	server;
	int		ret_val;
	
	m2ua_cmd = m2ua_sg_info[sg_id].m2ua_cmd;
	mtp3_cmd = m2ua_sg_info[sg_id].mtp3_cmd;
	mgmt_cmd = m2ua_sg_info[sg_id].mgmt_cmd;
	
	if (m2ua_sg_info[sg_id].m2ua_state < 3)
	{
		if (mgmt_cmd != M2UA_CMD_IDLEW)
			m2ua_sg_info[sg_id].mgmt_cmd = M2UA_CMD_IDLEW;
		if (mtp3_cmd != M2UA_CMD_IDLEW)
			m2ua_sg_info[sg_id].mtp3_cmd = M2UA_CMD_IDLEW;
		if (m2ua_cmd != M2UA_CMD_IDLEW)
			m2ua_sg_info[sg_id].m2ua_cmd = M2UA_CMD_IDLEW;
	}
	
	server		= m2ua_para.sg_para[sg_id].server;
	iid			= m2ua_sg_info[sg_id].iid;
	lk_enable 	= m2ua_para.lk_para[iid].enable;
	
	switch (m2ua_sg_info[sg_id].m2ua_state)
	{
		case 0:	// Wait For M2UA ASP Up, or send ASP Up
			if (server)
			{
				if (m2ua_cmd != M2UA_CMD_IDLEW)
				{
					if (m2ua_cmd == M2UA_ASPSM_ASP_UP)
					{
						m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_UP_ACK);
						m2ua_sg_info[sg_id].status = (M2UA_STATUS_TYPE_AS_STATE_CHG << 16) | M2UA_STATUS_INFO_AS_INACTIVE;
						m2ua_send_msg(sg_id, M2UA_MGMT_NOTIFY);
						m2ua_sg_info[sg_id].T_r = 0;
						m2ua_sg_info[sg_id].m2ua_state = 1;
					}
					else if (m2ua_cmd == M2UA_ASPSM_ASP_DOWN)
						m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_DOWN_ACK);
					else if ((m2ua_cmd == M2UA_ASPTM_ASP_ACTIVE) ||
						(m2ua_cmd == M2UA_ASPTM_ASP_INACTIVE))
					{
						m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_DOWN_ACK);
						m2ua_sg_info[sg_id].err_code = M2UA_ERR_UNEXPECTED_MSG;
						m2ua_send_msg(sg_id, M2UA_MGMT_ERROR);
					}
				}
			}
			else
			{
				m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_UP);
				m2ua_sg_info[sg_id].T_ack = M2UA_T_ACK;
				m2ua_sg_info[sg_id].m2ua_state = 1;
				//add by yizane;
				m2ua_sg_info[sg_id].retrans_times = 0;
			}
			break;
		case 1:	// Wait For M2UA ASP Active, or wait for ASP Up Ack
			if (server)
			{
				if (m2ua_cmd != M2UA_CMD_IDLEW)
				{
					if (m2ua_cmd == M2UA_ASPTM_ASP_ACTIVE)
					{
						m2ua_send_msg(sg_id, M2UA_ASPTM_ASP_ACTIVE_ACK);
						m2ua_sg_info[sg_id].status = (M2UA_STATUS_TYPE_AS_STATE_CHG << 16) | M2UA_STATUS_INFO_AS_ACTIVE;
						m2ua_send_msg(sg_id, M2UA_MGMT_NOTIFY);
						m2ua_sg_info[sg_id].T_r = 0;
						m2ua_sg_info[sg_id].m2ua_state = 3;
					}
					else if (m2ua_cmd == M2UA_ASPSM_ASP_UP)
						m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_UP_ACK);
					else if (m2ua_cmd == M2UA_ASPTM_ASP_INACTIVE)
						m2ua_send_msg(sg_id, M2UA_ASPTM_ASP_INACTIVE_ACK);
					else if (m2ua_cmd == M2UA_ASPSM_ASP_DOWN)
					{
						m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_DOWN_ACK);
						m2ua_sg_info[sg_id].T_r = 0;
						m2ua_sg_info[sg_id].m2ua_state = 0;
					}
				}
				
				if (m2ua_sg_info[sg_id].T_r > 0)
				{
					if (--m2ua_sg_info[sg_id].T_r == 0)
					{
						m2ua_sg_info[sg_id].status = (M2UA_STATUS_TYPE_AS_STATE_CHG << 16) | M2UA_STATUS_INFO_AS_INACTIVE;
						m2ua_send_msg(sg_id, M2UA_MGMT_NOTIFY);
					}
				}
			}
			else
			{
				if (m2ua_cmd == M2UA_ASPSM_ASP_UP_ACK)
				{
					m2ua_send_msg(sg_id, M2UA_ASPTM_ASP_ACTIVE);
					m2ua_sg_info[sg_id].T_ack = M2UA_T_ACK;
					m2ua_sg_info[sg_id].m2ua_state = 2;
					m2ua_sg_info[sg_id].retrans_times = 0;
				}
				else if (m2ua_sg_info[sg_id].T_ack > 0)
				{
					if (--m2ua_sg_info[sg_id].T_ack == 0)
					{
						if (++m2ua_sg_info[sg_id].retrans_times >= M2UA_MAX_RETRANS)
							return -2;
						else
						{
							m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_UP);
							m2ua_sg_info[sg_id].T_ack = M2UA_T_ACK;
						}
					}
				}
			}
			break;
		case 2:	// Wait for ASP ACTIVE ACK, only client can come to this state
			if (m2ua_cmd == M2UA_ASPTM_ASP_ACTIVE_ACK)
			{
				m2ua_sg_info[sg_id].T_ack = 0;
				m2ua_sg_info[sg_id].m2ua_state = 3;
				chg_sg_lk_status(sg_id, M2UA_LK_DOWN);
				m2ua_sg_info[sg_id].retrans_times = 0;
			}
			else if (m2ua_cmd == M2UA_MGMT_ERROR)
			{
				m2ua_sg_info[sg_id].T_ack = 0;
				m2ua_sg_info[sg_id].retrans_times = 0;
				m2ua_sg_info[sg_id].m2ua_state = 0;
				return -2;
			}
			else if (m2ua_sg_info[sg_id].T_ack > 0)
			{
				if (--m2ua_sg_info[sg_id].T_ack == 0)
				{
					if (++m2ua_sg_info[sg_id].retrans_times >= M2UA_MAX_RETRANS)
						return -2;
					else
					{
						m2ua_send_msg(sg_id, M2UA_ASPTM_ASP_ACTIVE);
						m2ua_sg_info[sg_id].T_ack = M2UA_T_ACK;
					}
				}
			}
			break;
		case 3:	// M2UA ASP Active
			if (mgmt_cmd != M2UA_CMD_IDLEW)
			{
				m2ua_sg_info[sg_id].mgmt_cmd = M2UA_CMD_IDLEW;
				if (((mgmt_cmd == M2UA_MGMT_CMD_LK_LOCK)
					||(mgmt_cmd == COMBO_W(M2UA_MGMT_CMD,M2UA_MGMT_CMD_LK_LOCK)))
					 &&(m2ua_lk_info[iid].lk_st >= M2UA_LK_UP))
				{
					if (server)
						m2ua_send_msg(sg_id, M2UA_MAUP_RELEASE_IND);
					else
						m2ua_send_msg(sg_id, M2UA_MAUP_RELEASE_REQ);
					m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
					m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_LOCAL_LINK_MAINTENANCE;
					m2ua_sd_mtp3_primi(iid, M2UA_LK_DOWN);
					rel_sid(sg_id, iid);
					m2ua_csta.lk_csta[iid].lk_dn_times++;
					if (m2ua_sg_info[sg_id].up_lks_cur)
						m2ua_sg_info[sg_id].up_lks_cur--;
				}
				else if ((mgmt_cmd == COMBO_W(IUA_MGMT_CMD,M2UA_MGMT_CMD_LK_LOCK)) &&
					(m2ua_lk_info[iid].lk_st >= M2UA_LK_UP))
				{
					if (server)
						m2ua_send_msg(sg_id, IUA_QPTM_RELEASE_IND);
					else
						m2ua_send_msg(sg_id, IUA_QPTM_RELEASE_REQ);
					m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
					m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_LOCAL_LINK_MAINTENANCE;
					iua_sd_q931_primi(iid, M2UA_LK_DOWN);
					rel_sid(sg_id, iid);
					m2ua_csta.lk_csta[iid].lk_dn_times++;
					if (m2ua_sg_info[sg_id].up_lks_cur)
						m2ua_sg_info[sg_id].up_lks_cur--;
				}					
				return -1;
			}
			
			if (server)
			{
				if (mtp3_cmd != M2UA_CMD_IDLEW)
				{
					m2ua_sg_info[sg_id].mtp3_cmd = M2UA_CMD_IDLEW;
					if ((m2ua_lk_info[iid].lk_st >= M2UA_LK_UP) &&
						( (mtp3_cmd == M2UA_MTP3_CMD_DEACTIVE_LK) ||
						  (mtp3_cmd == M2UA_MTP3_CMD_STOP_L2) ||
						  (mtp3_cmd == COMBO_W(M2UA_MGMT_CMD,M2UA_MTP3_CMD_DEACTIVE_LK)) ||
						  (mtp3_cmd == COMBO_W(M2UA_MGMT_CMD,M2UA_MTP3_CMD_STOP_L2))
						))
					{
						m2ua_send_msg(sg_id, M2UA_MAUP_RELEASE_IND);
						rel_sid(sg_id, iid);
						m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
						m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_LOCAL_MTP3_REQUEST_LINK_DOWN;
						m2ua_sd_mtp3_primi(iid, M2UA_LK_DOWN);
						m2ua_csta.lk_csta[iid].lk_dn_times++;
						if (m2ua_sg_info[sg_id].up_lks_cur)
							m2ua_sg_info[sg_id].up_lks_cur--;
					}
					else if ((m2ua_lk_info[iid].lk_st >= M2UA_LK_UP) &&
						((mtp3_cmd == COMBO_W(IUA_MGMT_CMD,M2UA_MTP3_CMD_DEACTIVE_LK)) ||
						(mtp3_cmd == COMBO_W(IUA_MGMT_CMD,M2UA_MTP3_CMD_STOP_L2))))
					{ 
						m2ua_sg_info[sg_id].rel_reason = IUA_RELEASE_MGMT;
						m2ua_send_msg(sg_id, IUA_QPTM_RELEASE_IND);
						rel_sid(sg_id, iid);
						m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
						m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_LOCAL_MTP3_REQUEST_LINK_DOWN;
						iua_sd_q931_primi(iid, M2UA_LK_DOWN);
						m2ua_csta.lk_csta[iid].lk_dn_times++;
						if (m2ua_sg_info[sg_id].up_lks_cur)
							m2ua_sg_info[sg_id].up_lks_cur--;
					}					
				}
				else if (m2ua_cmd != M2UA_CMD_IDLEW)
				{
					m2ua_sg_info[sg_id].m2ua_cmd = M2UA_CMD_IDLEW;
					if (m2ua_cmd == M2UA_MAUP_DATA)
					{
						if (m2ua_lk_info[iid].lk_st == M2UA_LK_UP)
						{
							m2ua_sd_mtp3_msg(sg_id, iid);
							err[13]++;
						}
						return 0;
					}
					else if (m2ua_cmd == M2UA_MAUP_ESTABLISH_REQ)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1))
						{
							assign_sid(sg_id, iid);
							if (m2ua_lk_info[iid].sid > 0)
							{
								m2ua_send_msg(sg_id, M2UA_MAUP_ESTABLISH_CFM);
								if (m2ua_lk_info[iid].lk_st == M2UA_LK_DOWN)
								{
									m2ua_sg_info[sg_id].up_lks_pre++;
									m2ua_sg_info[sg_id].up_lks_cur++;
								}
								m2ua_lk_info[iid].lk_st = M2UA_LK_UP;
								m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_NORMAL;
								m2ua_sd_mtp3_primi(iid, M2UA_LK_UP);
							}
						}
					}
					else if (m2ua_cmd == M2UA_MAUP_RELEASE_REQ)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1))
						{
							assign_sid(sg_id, iid);
							if (m2ua_lk_info[iid].sid > 0)
							{
								m2ua_send_msg(sg_id, M2UA_MAUP_RELEASE_CFM);
								rel_sid(sg_id, iid);
								if (m2ua_lk_info[iid].lk_st > M2UA_LK_DOWN)
								{
									m2ua_csta.lk_csta[iid].lk_dn_times++;
									if (m2ua_sg_info[sg_id].up_lks_cur)
										m2ua_sg_info[sg_id].up_lks_cur--;
								}
								m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
								m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_REMOTE_LINK_RELEASE;
								m2ua_sd_mtp3_primi(iid, M2UA_LK_DOWN);
							}
						}
					}
					else if (m2ua_cmd == M2UA_MAUP_STATE_REQ)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1))
						{
							ret_val = assign_sid(sg_id, iid);
							if (m2ua_lk_info[iid].sid > 0)
							{
								if (m2ua_sg_info[sg_id].state == M2UA_STATUS_AUDIT)
								{
									if (m2ua_lk_info[iid].lk_st == M2UA_LK_UP)
										m2ua_send_msg(sg_id, M2UA_MAUP_ESTABLISH_CFM);
									else
										m2ua_send_msg(sg_id, M2UA_MAUP_RELEASE_IND);
								}
								m2ua_send_msg(sg_id, M2UA_MAUP_STATE_CFM);
								if (ret_val != -1)
									rel_sid(sg_id, iid);
							}
						}
					}
					//add by yizane
					//for iua
					else if (m2ua_cmd == IUA_QPTM_DATA_REQ ||m2ua_cmd == IUA_QPTM_UDATA_REQ)
					{
						if (m2ua_lk_info[iid].lk_st == M2UA_LK_UP)
						{
							iua_sd_q931_msg(sg_id, iid);
							err[13]++;
						}
						return 0;
					}
					else if (m2ua_cmd == IUA_QPTM_ESTABLISH_REQ)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1))
						{
							assign_sid(sg_id, iid);
							if (m2ua_lk_info[iid].sid > 0)
							{
								m2ua_send_msg(sg_id, IUA_QPTM_ESTABLISH_CFM);
								if (m2ua_lk_info[iid].lk_st == M2UA_LK_DOWN)
								{
									m2ua_sg_info[sg_id].up_lks_pre++;
									m2ua_sg_info[sg_id].up_lks_cur++;
								}
								m2ua_lk_info[iid].lk_st = M2UA_LK_UP;
								m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_NORMAL;
								iua_sd_q931_primi(iid, M2UA_LK_UP);
							}
						}
					}
					else if (m2ua_cmd == IUA_QPTM_RELEASE_REQ)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1))
						{
							assign_sid(sg_id, iid);
							if (m2ua_lk_info[iid].sid > 0)
							{
								m2ua_sg_info[sg_id].rel_reason = IUA_RELEASE_MGMT;
								m2ua_send_msg(sg_id, IUA_QPTM_RELEASE_CFM);
								rel_sid(sg_id, iid);
								if (m2ua_lk_info[iid].lk_st > M2UA_LK_DOWN)
								{
									m2ua_csta.lk_csta[iid].lk_dn_times++;
									if (m2ua_sg_info[sg_id].up_lks_cur)
										m2ua_sg_info[sg_id].up_lks_cur--;
								}
								m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
								m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_REMOTE_LINK_RELEASE;
								iua_sd_q931_primi(iid, M2UA_LK_DOWN);
							}
						}
					}
					//add by yizane
					else if (m2ua_cmd == M2UA_ASPTM_ASP_ACTIVE)
						m2ua_send_msg(sg_id, M2UA_ASPTM_ASP_ACTIVE_ACK);
					else if ((m2ua_cmd == M2UA_ASPSM_ASP_DOWN) 	||
							 (m2ua_cmd == M2UA_ASPSM_ASP_UP)	||
							(m2ua_cmd == M2UA_ASPTM_ASP_INACTIVE))
					{
						if (m2ua_cmd == M2UA_ASPSM_ASP_UP)
						{
							m2ua_sg_info[sg_id].err_code = M2UA_ERR_UNEXPECTED_MSG;
							m2ua_send_msg(sg_id, M2UA_MGMT_ERROR);
							m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_UP_ACK);
							m2ua_sg_info[sg_id].m2ua_state = 1;
						}
						else if (m2ua_cmd == M2UA_ASPSM_ASP_DOWN)
						{
							m2ua_send_msg(sg_id, M2UA_ASPSM_ASP_DOWN_ACK);
							m2ua_sg_info[sg_id].status = (M2UA_STATUS_TYPE_AS_STATE_CHG << 16) | M2UA_STATUS_INFO_AS_PENDING;
							m2ua_send_msg(sg_id, M2UA_MGMT_NOTIFY);
							m2ua_sg_info[sg_id].m2ua_state = 0;
						}
						else if (m2ua_cmd == M2UA_ASPTM_ASP_INACTIVE)
						{
							m2ua_send_msg(sg_id, M2UA_ASPTM_ASP_INACTIVE_ACK);
							m2ua_sg_info[sg_id].status = (M2UA_STATUS_TYPE_AS_STATE_CHG << 16) | M2UA_STATUS_INFO_AS_PENDING;
							m2ua_send_msg(sg_id, M2UA_MGMT_NOTIFY);
							m2ua_sg_info[sg_id].T_r = M2UA_T_R;
							m2ua_sg_info[sg_id].m2ua_state = 1;
						}
						m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_REMOTE_AS_DOWN;
						rel_sg_lk(sg_id);
						chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
						m2ua_csta.sg_csta[sg_id].sg_asp_dn_times++;
					}
				}
			}
			else
			{
				if (mtp3_cmd != M2UA_CMD_IDLEW)
				{
					m2ua_sg_info[sg_id].mtp3_cmd = M2UA_CMD_IDLEW;
					if ((mtp3_cmd == M2UA_MTP3_CMD_ACTIVE_LK) ||
						(mtp3_cmd == M2UA_MTP3_CMD_EMERG_ALIGN) ||
						(mtp3_cmd == COMBO_W(M2UA_MGMT_CMD,M2UA_MTP3_CMD_ACTIVE_LK)) ||
						(mtp3_cmd == COMBO_W(M2UA_MGMT_CMD,M2UA_MTP3_CMD_EMERG_ALIGN))
						)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1) &&
							(!m2ua_lk_info[iid].lk_timer))
						{
							assign_sid(sg_id, iid);
							if (m2ua_lk_info[iid].sid > 0)
							{
								/*
								if (mtp3_cmd == M2UA_MTP3_CMD_EMERG_ALIGN)
								{
									m2ua_sg_info[sg_id].state = M2UA_STATUS_EMER_SET;
									m2ua_send_msg(sg_id, M2UA_MAUP_STATE_REQ);
								}
								*/
								if (m2ua_lk_info[iid].lk_st >= M2UA_LK_UP)
								{
									m2ua_send_msg(sg_id, M2UA_MAUP_RELEASE_REQ);
									if (m2ua_sg_info[sg_id].up_lks_cur)
										m2ua_sg_info[sg_id].up_lks_cur--;
									m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_LOCAL_MTP3_REQUEST_LINK_DOWN;
									m2ua_sd_mtp3_primi(iid, M2UA_LK_DOWN);
								}
								else
									m2ua_send_msg(sg_id, M2UA_MAUP_ESTABLISH_REQ);
								m2ua_lk_info[iid].lk_timer = M2UA_T_LK_ESTAB;
								m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
							}
						}
					}
					else if ((m2ua_lk_info[iid].lk_st >= M2UA_LK_UP) && (!m2ua_lk_info[iid].lk_timer) && 
						((mtp3_cmd == M2UA_MTP3_CMD_DEACTIVE_LK) ||
						(mtp3_cmd == M2UA_MTP3_CMD_STOP_L2) ||
						(mtp3_cmd == COMBO_W(M2UA_MGMT_CMD,M2UA_MTP3_CMD_DEACTIVE_LK)) ||
						(mtp3_cmd == COMBO_W(M2UA_MGMT_CMD,M2UA_MTP3_CMD_STOP_L2))
						))
					{
						m2ua_send_msg(sg_id, M2UA_MAUP_RELEASE_REQ);
						m2ua_lk_info[iid].lk_timer = M2UA_T_LK_ESTAB;
						rel_sid(sg_id, iid);
						m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
						m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_LOCAL_MTP3_REQUEST_LINK_DOWN;
						m2ua_sd_mtp3_primi(iid, M2UA_LK_DOWN);
						m2ua_csta.lk_csta[iid].lk_dn_times++;
						if (m2ua_sg_info[sg_id].up_lks_cur)
							m2ua_sg_info[sg_id].up_lks_cur--;
					}
					//add by yizane 
					//iua->
					else if ((mtp3_cmd == COMBO_W(IUA_MGMT_CMD,M2UA_MTP3_CMD_ACTIVE_LK)) ||
						(mtp3_cmd == COMBO_W(IUA_MGMT_CMD,M2UA_MTP3_CMD_EMERG_ALIGN)))
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1) &&
							(!m2ua_lk_info[iid].lk_timer))
						{
							assign_sid(sg_id, iid);
							if (m2ua_lk_info[iid].sid > 0)
							{
								/*
								if (mtp3_cmd == M2UA_MTP3_CMD_EMERG_ALIGN)
								{
									m2ua_sg_info[sg_id].state = M2UA_STATUS_EMER_SET;
									m2ua_send_msg(sg_id, M2UA_MAUP_STATE_REQ);
								}
								*/
								m2ua_sg_info[sg_id].rel_reason = IUA_RELEASE_MGMT;
//								if (m2ua_lk_info[iid].lk_st >= M2UA_LK_UP)
								if (m2ua_lk_info[iid].lk_st > M2UA_LK_UP)									
								{
									m2ua_send_msg(sg_id, IUA_QPTM_RELEASE_REQ);
									if (m2ua_sg_info[sg_id].up_lks_cur)
										m2ua_sg_info[sg_id].up_lks_cur--;
									m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_LOCAL_MTP3_REQUEST_LINK_DOWN;
									iua_sd_q931_primi(iid, M2UA_LK_DOWN);
								}
								else
									m2ua_send_msg(sg_id, IUA_QPTM_ESTABLISH_REQ);
								m2ua_lk_info[iid].lk_timer = M2UA_T_LK_ESTAB;
								m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
							}
						}
					}
					else if ((m2ua_lk_info[iid].lk_st >= M2UA_LK_UP) && (!m2ua_lk_info[iid].lk_timer) && 
						((mtp3_cmd == COMBO_W(IUA_MGMT_CMD,M2UA_MTP3_CMD_DEACTIVE_LK)) ||
						(mtp3_cmd == COMBO_W(IUA_MGMT_CMD,M2UA_MTP3_CMD_STOP_L2))))
					{
						m2ua_sg_info[sg_id].rel_reason = IUA_RELEASE_MGMT;
						m2ua_send_msg(sg_id, IUA_QPTM_RELEASE_REQ);
						m2ua_lk_info[iid].lk_timer = M2UA_T_LK_ESTAB;
						rel_sid(sg_id, iid);
						m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
						m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_LOCAL_MTP3_REQUEST_LINK_DOWN;
						iua_sd_q931_primi(iid, M2UA_LK_DOWN);
						m2ua_csta.lk_csta[iid].lk_dn_times++;
						if (m2ua_sg_info[sg_id].up_lks_cur)
							m2ua_sg_info[sg_id].up_lks_cur--;
					}					
					//iua<-
					//add by yizane 
				}
				else if (m2ua_cmd != M2UA_CMD_IDLEW)
				{
					m2ua_sg_info[sg_id].m2ua_cmd = M2UA_CMD_IDLEW;
					if (m2ua_cmd == M2UA_MAUP_DATA)
					{
						if (m2ua_lk_info[iid].lk_st == M2UA_LK_UP)
						{
							err[13]++;
							m2ua_sd_mtp3_msg(sg_id, iid);
//							if ((m2ua_para.sg_para[sg_id].data_ack == 1) &&
							if (((m2ua_para.sg_para[sg_id].xUA_ack&0x01) == 0x01) &&
								(m2ua_sg_info[sg_id].cor_id != 0))
								m2ua_send_msg(sg_id, M2UA_MAUP_DATA_ACK);
						}
						return 0;
					}
					else if (m2ua_cmd == M2UA_MAUP_ESTABLISH_CFM)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1))
						{
							m2ua_lk_info[iid].lk_st = M2UA_LK_UP;
							m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_NORMAL;
							m2ua_sd_mtp3_primi(iid, M2UA_LK_UP);
							m2ua_sg_info[sg_id].up_lks_pre++;
							m2ua_sg_info[sg_id].up_lks_cur++;
						}
					}
					else if (m2ua_cmd == M2UA_MAUP_RELEASE_IND)
					{
						rel_sid(sg_id, iid);
						if (m2ua_lk_info[iid].lk_st > M2UA_LK_DOWN)
						{
							m2ua_csta.lk_csta[iid].lk_dn_times++;
							if (m2ua_sg_info[sg_id].up_lks_cur)
								m2ua_sg_info[sg_id].up_lks_cur--;
						}
						m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
						m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_REMOTE_LINK_RELEASE;
						m2ua_sd_mtp3_primi(iid, M2UA_LK_DOWN);
					}
					//add by yizane 
					//for iua
					else if (m2ua_cmd == IUA_QPTM_DATA_IND ||m2ua_cmd == IUA_QPTM_UDATA_IND)
					{
						if (m2ua_lk_info[iid].lk_st == M2UA_LK_UP)
						{
							err[13]++;
							iua_sd_q931_msg(sg_id, iid);
						}
						return 0;
					}
					else if (m2ua_cmd == IUA_QPTM_ESTABLISH_CFM)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1))
						{
							m2ua_lk_info[iid].lk_st = M2UA_LK_UP;
							m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_NORMAL;
							iua_sd_q931_primi(iid, M2UA_LK_UP);
							m2ua_sg_info[sg_id].up_lks_pre++;
							m2ua_sg_info[sg_id].up_lks_cur++;
						}
					}
					else if (m2ua_cmd == IUA_QPTM_ESTABLISH_IND)
					{
						if ((lk_enable == 1) && 
							(m2ua_lk_info[iid].enable == 1))
						{
							assign_sid(sg_id, iid);
							if (m2ua_lk_info[iid].sid > 0)
							{
								m2ua_send_msg(sg_id, IUA_QPTM_ESTABLISH_CFM);
								if (m2ua_lk_info[iid].lk_st == M2UA_LK_DOWN)
								{
									m2ua_sg_info[sg_id].up_lks_pre++;
									m2ua_sg_info[sg_id].up_lks_cur++;
								}
								m2ua_lk_info[iid].lk_st = M2UA_LK_UP;
								m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_NORMAL;
								iua_sd_q931_primi(iid, M2UA_LK_UP);
							}
						}
					}
					else if (m2ua_cmd == IUA_QPTM_RELEASE_IND)
					{
						rel_sid(sg_id, iid);
						if (m2ua_lk_info[iid].lk_st > M2UA_LK_DOWN)
						{
							m2ua_csta.lk_csta[iid].lk_dn_times++;
							if (m2ua_sg_info[sg_id].up_lks_cur)
								m2ua_sg_info[sg_id].up_lks_cur--;
						}
						m2ua_lk_info[iid].lk_st = M2UA_LK_DOWN;
						m2ua_lk_info[iid].alarm_code = M2UA_ALARM_CODE_REMOTE_LINK_RELEASE;
						iua_sd_q931_primi(iid, M2UA_LK_DOWN);
					}
					//add by yizane
				}
			}
			break;
		default:
			m2ua_sg_info[sg_id].m2ua_state = 0;
			break;
	}
	
	return -1;
}

int m2ua_sctp_down(WORD sg_id)
{
	if (m2ua_sg_info[sg_id].m2ua_state == 3)
		m2ua_csta.sg_csta[sg_id].sg_asp_dn_times++;
	
	m2ua_sg_info[sg_id].m2ua_state 		= 0;
	m2ua_sg_info[sg_id].T_ack 			= 0;
	m2ua_sg_info[sg_id].T_r 			= 0;
	
	m2ua_sg_info[sg_id].sctp_cmd 		= M2UA_CMD_IDLEW;
	
	rel_sg_lk(sg_id);
	
	m2ua_sg_info[sg_id].up_lks_pre = m2ua_sg_info[sg_id].up_lks_cur = 0;
	
	return 0;
}

int m2ua_sg_fsm(WORD sg_id)
{	
	int		fd;
	int		msg, con_sg, ret;
	BYTE	enable;
	BYTE 	conn_id;
	BYTE	server;
	DWORD 	sctp_cmd;
#ifndef _LKSCTP
	struct 	t_opthdr *oh;
	t_scalar_t	*str_val;
	m2ua_sctp_addr_t *addr;
#else
	struct 	sctp_assoc_change *sac;
	int		new_fd, addr_len;
	struct 	sockaddr_in sin[1];
	BYTE	ascitemp_buf[256];
	struct 	timeval TOut = {0, 0};
    fd_set 	ReadFds;
#endif
	
	if (((m2ua_sg_info[sg_id].enable == 0) ||(m2ua_sg_info[sg_id].fd == 0)) &&
		!((m2ua_sg_info[sg_id].sctp_state == 3) && (m2ua_sg_info[sg_id].sctp_state_1 == 1)))	// Not Client at sctp 3-1 state
		return -1;
	else
	{
		fd 			= m2ua_sg_info[sg_id].fd;
		sctp_cmd 	= m2ua_sg_info[sg_id].sctp_cmd;
		if (sg_id < M2UA_MAX_SG_NUM)
		{
			enable	= m2ua_para.sg_para[sg_id].enable;
			server	= m2ua_para.sg_para[sg_id].server;
		}
		else
		{
			con_sg 	= m2ua_sg_info[sg_id].con_sg;
			enable	= m2ua_para.sg_para[con_sg].enable;
			server	= m2ua_para.sg_para[con_sg].server;
		}
	}
	
	switch (m2ua_sg_info[sg_id].sctp_state)
	{
		case 0:	// SCTP Option Negotiate
			if (((enable == 0) || (enable == 2)) &&
				(sg_id < M2UA_MAX_SG_NUM))
			{
#ifndef _LKSCTP
				m2ua_sctp_close(fd, sg_id);
#else
				m2ua_sctp_discon_req_lksctp(fd, sg_id, 0);
#endif
				m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
				m2ua_sctp_down(sg_id);
				chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
				
				if (enable == 2)
					m2ua_para.sg_para[sg_id].enable = 0;
				
				m2ua_sg_init(sg_id);
				m2ua_log_err(sg_id, "SG disabled!");
				return -1;
			}
			
			switch (m2ua_sg_info[sg_id].sctp_state_1)
			{
				case 0:	// Send optmgnt request
#ifndef _LKSCTP
					m2ua_sctp_optmgmt_req(fd, sg_id, T_NEGOTIATE);
					m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
					m2ua_sg_info[sg_id].sctp_state_1 = 1;
#else
					if (m2ua_sctp_optmgmt_req_lksctp(fd, sg_id) == 0)
					{
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
						m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
					}
					else
					{
					//add by yizane
					//	if ((sg_id == M2UA_MAX_SG_NUM) ||
						if ((sg_id >= M2UA_MAX_SG_NUM) ||
							((sg_id < M2UA_MAX_SG_NUM) && !server))  
						{	// Client or Listener
							m2ua_sg_info[sg_id].sctp_state = 1;
							m2ua_sg_info[sg_id].sctp_state_1 = 0;
							m2ua_sg_info[sg_id].sg_timer = 0;
						}
						else
						{	// Server
							m2ua_sg_info[sg_id].sctp_state = 2;
							m2ua_sg_info[sg_id].sctp_state_1 = 5;
							m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
						}
					}
#endif
					break;
				case 1:	// Receive optmgmt response
#ifndef _LKSCTP
					if (expect(fd, sg_id, &msg, T_OPTMGMT_ACK) != M2UA_FAILURE)
					{
						m2ua_sg_info[sg_id].sctp_state = 1;
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
						m2ua_sg_info[sg_id].sg_timer = 0;
					}
					else if (m2ua_sg_info[sg_id].sg_timer)
#else
					if (m2ua_sg_info[sg_id].sg_timer)
#endif
						m2ua_sg_info[sg_id].sg_timer--;
					else
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
					break;
				default:
					m2ua_sg_info[sg_id].sctp_state_1 = 0;
					break;
			}
			break;
		case 1:	// SCTP Address Bind
			if (((enable == 0) || (enable == 2)) &&
				(sg_id < M2UA_MAX_SG_NUM))
			{
#ifndef _LKSCTP
				m2ua_sctp_close(fd, sg_id);
#else
				m2ua_sctp_discon_req_lksctp(fd, sg_id, 0);
#endif
				m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
				m2ua_sctp_down(sg_id);
				chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
				
				if (enable == 2)
					m2ua_para.sg_para[sg_id].enable = 0;
				
				m2ua_sg_init(sg_id);
				m2ua_log_err(sg_id, "SG disabled!");
				return -1;
			}
			
			switch (m2ua_sg_info[sg_id].sctp_state_1)
			{
				case 0:	// Send bind request
				//add by yizane
				//if (sg_id == M2UA_MAX_SG_NUM)
					if (sg_id >= M2UA_MAX_SG_NUM)
						conn_id = 1;
					else
						conn_id = 0;
					m2ua_sctp_addr.addr.s_addr = htonl(INADDR_ANY);
#ifndef _LKSCTP
//add by yizane
					if (sg_id == M2UA_LISTEN_SG_NUM_0)
						m2ua_sctp_addr.port = htons(M2UA_PORT_0);
					else if (sg_id == M2UA_LISTEN_SG_NUM_1)	
						m2ua_sctp_addr.port = htons(M2UA_PORT_1);
					else if (sg_id == IUA_LISTEN_SG_NUM_0)	
						m2ua_sctp_addr.port = htons(IUA_PORT_0);		
					else if (sg_id == IUA_LISTEN_SG_NUM_1)	
						m2ua_sctp_addr.port = htons(IUA_PORT_1);
					else if ((m2ua_para.sg_para[sg_id].xUA_ack>>1) == M2UA_APP)
						m2ua_sctp_addr.port = htons(M2UA_PORT_0+10000);
					else if ((m2ua_para.sg_para[sg_id].xUA_ack>>1) == IUA_APP)
						m2ua_sctp_addr.port = htons(IUA_PORT_0+10000);
//add by yizane													
					m2ua_sctp_bind_req(fd, sg_id, &m2ua_sctp_addr, conn_id);			
					m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
					m2ua_sg_info[sg_id].sctp_state_1 = 1;
#else
					if ((sg_id >= M2UA_MAX_SG_NUM) ||
						((sg_id < M2UA_MAX_SG_NUM) && !server))  
					{	// Client or Listener
						if (sg_id == M2UA_LISTEN_SG_NUM_0)
							m2ua_sctp_addr.port = htons(M2UA_PORT_0);
						else if (sg_id == M2UA_LISTEN_SG_NUM_1)	
							m2ua_sctp_addr.port = htons(M2UA_PORT_1);
						else if (sg_id == IUA_LISTEN_SG_NUM_0)	
							m2ua_sctp_addr.port = htons(IUA_PORT_0);		
						else if (sg_id == IUA_LISTEN_SG_NUM_1)	
							m2ua_sctp_addr.port = htons(IUA_PORT_1);							
						else
							m2ua_sctp_addr.port = 0;
						if (m2ua_sctp_bind_req_lksctp(fd, sg_id, &m2ua_sctp_addr, conn_id) == 0)
						{
							m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
							m2ua_sg_info[sg_id].sctp_state_1 = 1;
							break;
						}
					}
					m2ua_sg_info[sg_id].sctp_state = 2;
					m2ua_sg_info[sg_id].sctp_state_1 = 0;
					m2ua_sg_info[sg_id].sg_timer = 0;
#endif
					break;
				case 1:	// Receive bind response
#ifndef _LKSCTP
					if (expect(fd, sg_id, &msg, T_BIND_ACK) != M2UA_FAILURE)
					{
						m2ua_sg_info[sg_id].sctp_state = 2;
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
						m2ua_sg_info[sg_id].sg_timer = 0;
					}
					else if (m2ua_sg_info[sg_id].sg_timer)
#else
					if (m2ua_sg_info[sg_id].sg_timer)
#endif
						m2ua_sg_info[sg_id].sg_timer--;
					else
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
					break;
				default:
					m2ua_sg_info[sg_id].sctp_state_1 = 0;
					break;
			}
			break;
		case 2:	// Wait for SCTP Connection Request from peer or Send conn req to the peer
			switch (m2ua_sg_info[sg_id].sctp_state_1)
			{
				case 0:	// Wait for connection indication from peer or conn req to the peer
					//add by yizane
					//if (sg_id == M2UA_MAX_SG_NUM)
					if (sg_id >= M2UA_MAX_SG_NUM)
					{
#ifndef _LKSCTP						
						if (expect(fd, sg_id, &msg, T_CONN_IND) == M2UA_SUCCESS)
						{
							m2ua_sg_info[sg_id].seq = m2ua_sctp_cmd.tpi.conn_ind.SEQ_number;
							addr 	= (m2ua_sctp_addr_t *) (m2ua_sctp_cmd.cbuf + m2ua_sctp_cmd.tpi.conn_ind.SRC_offset);
							//add by yizane
							//con_sg 	= find_sg_by_ipv4(addr->addr.s_addr);
							con_sg 	= find_sg_by_ipv4(addr->addr.s_addr,sg_id);
							if (con_sg < 0)
								m2ua_sctp_discon_req(fd, sg_id, m2ua_sg_info[sg_id].seq);
							else
							{
								oh = (struct t_opthdr *) (m2ua_sctp_cmd.cbuf + m2ua_sctp_cmd.tpi.conn_ind.OPT_offset);
								str_val = (t_uscalar_t *)(oh + 1);
								if (oh->name == T_SCTP_ISTREAMS)
									m2ua_sg_info[sg_id].istrs = *str_val;
								oh = (struct t_opthdr *)((BYTE *)oh + oh->len);
								str_val = (t_uscalar_t *)(oh + 1);
								if (oh->name == T_SCTP_OSTREAMS)
									m2ua_sg_info[sg_id].ostrs = *str_val;
								m2ua_sg_info[sg_id].con_sg 			= con_sg;
								m2ua_sg_info[sg_id].sctp_state_1 	= 1;
							}
						}
#else
						FD_ZERO(&ReadFds);
						FD_SET(fd, &ReadFds);
						if ((select(fd + 1, &ReadFds, NULL, NULL, &TOut) > 0) &&
							FD_ISSET(fd, &ReadFds))
						{
							addr_len = sizeof(*sin);
							if ((new_fd = accept(fd, (struct sockaddr *)sin, &addr_len)) > 0)
							{
								if (fcntl(new_fd, F_SETFL, O_NONBLOCK) < 0)
	       							m2ua_log_err(sg_id, "got lksctp incoming connection, but set nonblock failure!");
	       							//add by yizane	
								con_sg 	= find_sg_by_ipv4(sin->sin_addr.s_addr,sg_id);
								if ((con_sg < 0) || (m2ua_sg_info[con_sg].enable == 0))
								{
									if (con_sg < 0)
										sprintf(ascitemp_buf, "got lksctp incoming connection, but can't find sg by ipv4: %X\n\r", sin->sin_addr.s_addr);									
									else
										sprintf(ascitemp_buf, "got lksctp incoming connection, but sg[%d] not enabled!\n\r", con_sg);
									m2ua_log_err(sg_id, ascitemp_buf);
									m2ua_asciout_proc(m2ua_ascitemp_buf);
									m2ua_sctp_discon_req_lksctp(new_fd, sg_id, 0);
								}
								else if ((m2ua_sg_info[con_sg].sctp_state == 3) &&
										(m2ua_sg_info[con_sg].sctp_state_1 == 0))
								{
									m2ua_sg_info[con_sg].sctp_cmd = M2UA_LKSCTP_ASSOC_CHANGE_COMM_LOST;
									sprintf(ascitemp_buf, "got lksctp incoming connection, but sg[%d] is still in ESTABLISHED state! Disconnect it!\n\r", con_sg);
									m2ua_log_err(sg_id, ascitemp_buf);
									m2ua_sctp_discon_req_lksctp(new_fd, sg_id, 0);
								}
								else
								{
									m2ua_sg_info[con_sg].fd	= new_fd;
									m2ua_sg_info[con_sg].rem_port = sin->sin_port;
								}
							}
						}
#endif
					}
					else
					{	
						if ((enable == 0) || (enable == 2))
						{
#ifndef _LKSCTP
							m2ua_sctp_close(fd, sg_id);
#else
							m2ua_sctp_discon_req_lksctp(fd, sg_id, 0);
#endif
							m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
							m2ua_sctp_down(sg_id);
							chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
							
							if (enable == 2)
								m2ua_para.sg_para[sg_id].enable = 0;
							
							m2ua_sg_init(sg_id);
							m2ua_log_err(sg_id, "SG disabled!");
							return -1;
						}
						
						if (sctp_cmd != M2UA_CMD_IDLEW)
							m2ua_sg_info[sg_id].sctp_cmd = M2UA_CMD_IDLEW;
						
						if (!server && (enable == 1))
						{	// M2UA Client
							m2ua_sctp_server_addr.port = htons(m2ua_para.sg_para[sg_id].plat_port[0]);
							m2ua_sctp_server_addr.addr.s_addr = m2ua_para.sg_para[sg_id].ip;
							if (m2ua_sg_info[sg_id].sg_timer)
								m2ua_sg_info[sg_id].sg_timer--;
#ifndef _LKSCTP
							else if (m2ua_sctp_conn_req(fd, sg_id, &m2ua_sctp_server_addr) != M2UA_FAILURE)
							{
								m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
								m2ua_sg_info[sg_id].sctp_state_1 = 3;
								chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
							}
#else
							else if (m2ua_sctp_conn_req_lksctp(fd, sg_id, &m2ua_sctp_server_addr) != M2UA_FAILURE)
							{
								m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_2;
								m2ua_sg_info[sg_id].sctp_state_1 = 4;
								chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
							}
#endif
							else
								m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
						}
					}
					break;
#ifndef _LKSCTP
				case 1:	// Only SG_ID = M2UA_MAX_SG_NUM can come to this state
					if ((enable == 1) && server &&
						(m2ua_sg_info[con_sg].sctp_state == 2))
					{
						m2ua_sg_info[con_sg].seq = m2ua_sg_info[sg_id].seq;
						m2ua_sg_info[con_sg].istrs = m2ua_sg_info[sg_id].istrs;
						m2ua_sg_info[con_sg].ostrs = m2ua_sg_info[sg_id].ostrs;
						m2ua_sg_info[con_sg].rem_ostrs = m2ua_sg_info[sg_id].ostrs - 1;
						
						if (m2ua_sctp_conn_res(fd, m2ua_sg_info[con_sg].fd, sg_id, m2ua_sg_info[sg_id].seq) != M2UA_FAILURE)
						{
							m2ua_sg_info[sg_id].sctp_state_1 = 2;
							m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
							chg_sg_lk_status(con_sg, M2UA_LK_IDLE);
							break;
						}
					}
					m2ua_sctp_discon_req(fd, sg_id, m2ua_sg_info[sg_id].seq);
					m2ua_sg_info[sg_id].sctp_state_1 = 0;
					if ((enable == 1) && server &&
						(m2ua_sg_info[con_sg].sctp_state == 3))
						m2ua_sg_info[con_sg].sctp_cmd = T_DISCON_IND;
					break;
				case 2:	// Only SG_ID = M2UA_MAX_SG_NUM can come to this state
					if (expect(fd, sg_id, &msg, T_OK_ACK) == M2UA_SUCCESS)
					{
						m2ua_sg_info[sg_id].sctp_state = 2;
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
						m2ua_sg_info[sg_id].sg_timer = 0;
						
						m2ua_sg_info[con_sg].sctp_state = 3;
						m2ua_sg_info[con_sg].sctp_state_1 = 0;
					}
					else if ((msg == T_ERROR_ACK) || (!m2ua_sg_info[sg_id].sg_timer))
					{
						m2ua_sctp_discon_req(fd, sg_id, m2ua_sg_info[sg_id].seq);
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
						m2ua_sg_info[sg_id].sg_timer = 0;
						if ((enable == 1) && server &&
							(m2ua_sg_info[con_sg].sctp_state == 3))
							m2ua_sg_info[con_sg].sctp_cmd = T_DISCON_IND;
					}
					else
						m2ua_sg_info[sg_id].sg_timer--;
					break;
				case 3:	// Only M2UA client can come to this state
					if ((enable == 0) || (enable == 2))
					{
						m2ua_sctp_discon_req(fd, sg_id, 0);
						m2ua_sctp_close(fd, sg_id);
						m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
						m2ua_sctp_down(sg_id);
						chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
						
						if (enable == 2)
							m2ua_para.sg_para[sg_id].enable = 0;
						
						m2ua_sg_init(sg_id);
						m2ua_log_err(sg_id, "SG disabled!");
						return -1;
					}
					
					if (expect(fd, sg_id, &msg, T_OK_ACK) == M2UA_SUCCESS)
					{
						m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_2;
						m2ua_sg_info[sg_id].sctp_state_1 = 4;
					}
					else if (msg == T_ERROR_ACK)
					{
						m2ua_sctp_discon_req(fd, sg_id, 0);
						m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
					}
					else if (m2ua_sg_info[sg_id].sg_timer > 0)
						m2ua_sg_info[sg_id].sg_timer--;
					else
					{
						m2ua_sctp_discon_req(fd, sg_id, 0);
						m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_1;
						m2ua_sg_info[sg_id].sctp_state_1 = 0;
					}
					break;
#endif
				case 4:	// only M2UA client can come to this state
					if ((enable == 0) || (enable == 2))
					{
#ifndef _LKSCTP				
						m2ua_sctp_discon_req(fd, sg_id, 0);
						m2ua_sctp_close(fd, sg_id);
#else
						m2ua_sctp_discon_req_lksctp(fd, sg_id, 0);
#endif
						m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
						m2ua_sctp_down(sg_id);
						chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
						
						if (enable == 2)
							m2ua_para.sg_para[sg_id].enable = 0;
						
						m2ua_sg_init(sg_id);
						m2ua_log_err(sg_id, "SG disabled!");
						return -1;
					}

#ifndef _LKSCTP					
					if (expect(fd, sg_id, &msg, T_CONN_CON) == M2UA_SUCCESS)
					{
						m2ua_sg_info[sg_id].sg_timer = 0;
						oh = (struct t_opthdr *) (m2ua_sctp_cmd.cbuf + m2ua_sctp_cmd.tpi.conn_con.OPT_offset);
						str_val = (t_uscalar_t *)(oh + 1);
						if (oh->name == T_SCTP_ISTREAMS)
							m2ua_sg_info[sg_id].istrs = *str_val;
						oh = (struct t_opthdr *)((BYTE *)oh + oh->len);
						str_val = (t_uscalar_t *)(oh + 1);
						if (oh->name == T_SCTP_OSTREAMS)
						{
							m2ua_sg_info[sg_id].ostrs = *str_val;
							m2ua_sg_info[sg_id].rem_ostrs = m2ua_sg_info[sg_id].ostrs - 1;
						}
						m2ua_sg_info[sg_id].sctp_state 		= 3;
						m2ua_sg_info[sg_id].sctp_state_1 	= 0;
					}
#else
					if (expect_lksctp(fd, sg_id, &msg, M2UA_LKSCTP_ASSOC_CHANGE_COMM_UP) == M2UA_SUCCESS)
					{
						sac = (struct sctp_assoc_change *) m2ua_sctp_dat;
						m2ua_sg_info[sg_id].istrs = sac->sac_inbound_streams;
						m2ua_sg_info[sg_id].ostrs = sac->sac_outbound_streams;
						m2ua_sg_info[sg_id].rem_ostrs = m2ua_sg_info[sg_id].ostrs - 1;
						m2ua_sg_info[sg_id].sg_timer = 0;
						m2ua_sg_info[sg_id].sctp_state 		= 3;
						m2ua_sg_info[sg_id].sctp_state_1 	= 0;
						m2ua_sctp_optmgmt_req_lksctp_ext(fd, sg_id);
					}
#endif
					else
					{
#ifndef _LKSCTP
						if (msg == T_DISCON_IND)
						{
							m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_3;
							m2ua_sg_info[sg_id].sctp_state_1 = 0;
						}
#else
						if (msg == M2UA_LKSCTP_ASSOC_CHANGE_CANT_STR_ASSOC)
						{
							m2ua_sctp_discon_req_lksctp(fd, sg_id, 1);
							m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_3;
							m2ua_sg_info[sg_id].sctp_state = 3;
							m2ua_sg_info[sg_id].sctp_state_1 = 1;
						}
#endif
						else if (m2ua_sg_info[sg_id].sg_timer > 0)
							m2ua_sg_info[sg_id].sg_timer--;
						else
						{
#ifndef _LKSCTP
							m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_3;
							m2ua_sg_info[sg_id].sctp_state_1 = 0;
#else
							m2ua_sctp_discon_req_lksctp(fd, sg_id, 1);
							m2ua_sg_info[sg_id].sg_timer = M2UA_T_SG_ESTAB_3;
							m2ua_sg_info[sg_id].sctp_state = 3;
							m2ua_sg_info[sg_id].sctp_state_1 = 1;
#endif
						}
					}
					break;
#ifdef _LKSCTP
				case 5:	// only M2UA server_lksctp can come to this state
					if ((enable == 0) || (enable == 2))
					{
						m2ua_sctp_discon_req_lksctp(m2ua_sg_info[sg_id].fd, sg_id, 0);
						
						m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
						m2ua_sctp_down(sg_id);
						chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
						
						if (enable == 2)
							m2ua_para.sg_para[sg_id].enable = 0;
						
						m2ua_sg_init(sg_id);
						m2ua_log_err(sg_id, "SG disabled!");
						return -1;
					}
					
					if (expect_lksctp(fd, sg_id, &msg, M2UA_LKSCTP_ASSOC_CHANGE_COMM_UP) == M2UA_SUCCESS)
					{
						sac = (struct sctp_assoc_change *) m2ua_sctp_dat;
						m2ua_sg_info[sg_id].istrs = sac->sac_inbound_streams;
						m2ua_sg_info[sg_id].ostrs = sac->sac_outbound_streams;
						m2ua_sg_info[sg_id].rem_ostrs = m2ua_sg_info[sg_id].ostrs - 1;
						m2ua_sg_info[sg_id].sg_timer 		= 0;
						m2ua_sg_info[sg_id].sctp_state 		= 3;
						m2ua_sg_info[sg_id].sctp_state_1 	= 0;
						m2ua_sctp_optmgmt_req_lksctp_ext(fd, sg_id);
					}
					else
					{
						if (msg == M2UA_LKSCTP_ASSOC_CHANGE_COMM_LOST)
						{
							m2ua_sctp_discon_req_lksctp(m2ua_sg_info[sg_id].fd, sg_id, 1);//fixed by zane
							m2ua_sg_info[sg_id].sg_timer 		= 0;
							m2ua_sg_info[sg_id].sctp_state 		= 0;
							m2ua_sg_info[sg_id].sctp_state_1 	= 0;
						}
						else if (m2ua_sg_info[sg_id].sg_timer > 0)
							m2ua_sg_info[sg_id].sg_timer--;
						else
						{
							m2ua_sctp_discon_req_lksctp(m2ua_sg_info[sg_id].fd, sg_id, 1);//fixed by zane
							m2ua_sg_info[sg_id].sg_timer 		= 0;
							m2ua_sg_info[sg_id].sctp_state 		= 0;
							m2ua_sg_info[sg_id].sctp_state_1 	= 0;
						}
					}
					break;
#endif
				default:
					m2ua_sg_info[sg_id].sctp_state_1 = 0;
					break;
			};
			break;
		case 3:	// M2UA SCTP Link Established
			switch (m2ua_sg_info[sg_id].sctp_state_1)
			{
				case 0:	// Normal
#ifndef _LKSCTP
					if ((enable == 0) || (enable == 2) || (sctp_cmd == T_DISCON_IND) ||
						(!server && !m2ua_sg_info[sg_id].up_lks_cur && m2ua_sg_info[sg_id].up_lks_pre))
					{
						if ((enable == 0) || (enable == 2))
							m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
						else
							m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_SCTP_FAILURE;
						m2ua_sctp_discon_req(fd, sg_id, 0);
#else
					if ((enable == 0) || (enable == 2) || (sctp_cmd == M2UA_LKSCTP_ASSOC_CHANGE_COMM_LOST) ||
						(!server && !m2ua_sg_info[sg_id].up_lks_cur && m2ua_sg_info[sg_id].up_lks_pre))
					{
						if ((enable == 0) || (enable == 2))
						{
							m2ua_sctp_discon_req_lksctp(fd, sg_id, 0);
							m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
						}
						else
						{
							m2ua_sctp_discon_req_lksctp(fd, sg_id, 1);
							m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_SCTP_FAILURE;
						}
#endif
						m2ua_sctp_down(sg_id);
						chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
						
						if ((enable == 0) || (enable == 2))
						{
							if (enable == 2)
								m2ua_para.sg_para[sg_id].enable = 0;
							m2ua_sg_init(sg_id);
							m2ua_log_err(sg_id, "SG disabled!");
						}
						else
						{
							m2ua_sg_info[sg_id].sctp_state 		= 3;	
							m2ua_sg_info[sg_id].sctp_state_1 	= 1;
							m2ua_sg_info[sg_id].sg_timer 		= M2UA_T_SG_ESTAB_3;
							m2ua_log_err(sg_id, "All links are down, to reestablish the SCTP link!");
						}
						
						return -1;
					}
					else if (m2ua_sg_info[sg_id].up_lks_pre != m2ua_sg_info[sg_id].up_lks_cur)
						m2ua_sg_info[sg_id].up_lks_pre = m2ua_sg_info[sg_id].up_lks_cur;

#ifndef _LKSCTP					
					if (expect(fd, sg_id, &msg, T_DATA_IND) == M2UA_FAILURE)
					{	// Handle SCTP Primitives
						if ((msg == T_DISCON_IND) || (msg == T_ORDREL_IND))
						{
							if (msg == T_ORDREL_IND)
								m2ua_sctp_ordrel_req(fd, sg_id);
#else
					if (expect_lksctp(fd, sg_id, &msg, M2UA_LKSCTP_DATA_IND) == M2UA_FAILURE)
					{	// Handle SCTP Primitives
						if ((msg == M2UA_LKSCTP_ASSOC_CHANGE_COMM_LOST) || 
							(msg == M2UA_LKSCTP_ASSOC_CHANGE_SHUTDOWN_COMP) ||
							(msg == M2UA_LKSCTP_SHUTDOWN_EVENT))
						{
							m2ua_sctp_discon_req_lksctp(fd, sg_id, 1);
#endif	
							m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_SCTP_FAILURE;
							m2ua_sctp_down(sg_id);
							chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
							
							m2ua_sg_info[sg_id].sctp_state 		= 3;	
							m2ua_sg_info[sg_id].sctp_state_1 	= 1;
							if(server)
								m2ua_sg_info[sg_id].sg_timer 	= M2UA_T_SG_WAIT;
							else
								m2ua_sg_info[sg_id].sg_timer 	= M2UA_T_SG_ESTAB_3;
							m2ua_log_err(sg_id, "Got discon_ind from SCTP, wait to reestablish the SCTP link!");
							
							return -1;
						}
#ifdef _LKSCTP	
						else if (msg == M2UA_LKSCTP_ASSOC_CHANGE_RESTART)
						{
							m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_SCTP_FAILURE;
							m2ua_sctp_down(sg_id);
							chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
							m2ua_log_err(sg_id, "Got M2UA_LKSCTP_ASSOC_CHANGE_RESTART from SCTP!");
							return -1;
						}
#endif
						ret = -1;
					}
					else
					{
						m2ua_dec_msg(sg_id);
						ret = 0;
					}
					
					if ((m2ua_fsm(sg_id) == -2) && (!server))
					{
#ifndef _LKSCTP	
						m2ua_sctp_discon_req(fd, sg_id, 0);
#else
						m2ua_sctp_discon_req_lksctp(fd, sg_id, 1);//fixed by zane
#endif
						m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_REMOTE_AS_DOWN;
						m2ua_sctp_down(sg_id);
						m2ua_sg_info[sg_id].sctp_state 		= 3;	
						m2ua_sg_info[sg_id].sctp_state_1 	= 1;
						m2ua_sg_info[sg_id].sg_timer 		= M2UA_T_SG_ESTAB_3;
						
						m2ua_log_err(sg_id, "ASP UP/ACTIVE timeout, wait to reestablish the SCTP link!");
						
						return -2;
					}
					else
						return ret;
					break;
				case 1:	// Wait...
					if ((enable == 0) || (enable == 2))
					{
#ifndef _LKSCTP				
						m2ua_sctp_close(fd, sg_id);
#else
						m2ua_sctp_discon_req_lksctp(fd, sg_id, 0);
#endif
						m2ua_sg_info[sg_id].alarm_code = M2UA_ALARM_CODE_LOCAL_SG_MAINTENANCE;
						m2ua_sctp_down(sg_id);
						chg_sg_lk_status(sg_id, M2UA_LK_IDLE);
						
						if (enable == 2)
							m2ua_para.sg_para[sg_id].enable = 0;
						
						m2ua_sg_init(sg_id);
						m2ua_log_err(sg_id, "SG disabled!");
						return -1;
					}
#ifndef _LKSCTP
					if ((m2ua_sg_info[sg_id].sg_timer--) > 0)
						expect(fd, sg_id, &msg, T_OK_ACK);
					else
					{
						m2ua_sg_info[sg_id].sctp_state 		= 2;	
						m2ua_sg_info[sg_id].sctp_state_1 	= 0;
						m2ua_sg_info[sg_id].sg_timer 		= 0;
					}
#else
					if ((m2ua_sg_info[sg_id].sg_timer--) > 0);
						//expect_lksctp(fd, sg_id, &msg, M2UA_LKSCTP_DATA_IND);
					else
					{
						m2ua_sg_info[sg_id].sctp_state 		= 0;	
						m2ua_sg_info[sg_id].sctp_state_1 	= 0;
						m2ua_sg_info[sg_id].sg_timer 		= 0;
					}
#endif
					break;
				default:
					break;
			}
			break;
		default:
			m2ua_sg_info[sg_id].sctp_state 		= 0;
			m2ua_sg_info[sg_id].sctp_state_1 	= 0;
			break;
	}
	
	return -1;
}


