Files
svc.ems/plat/isdn/src/isdn_rm.c
2024-09-27 15:39:34 +08:00

516 lines
15 KiB
C

/***********************************************************
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 int isdn_receive_msg();
extern int isdn_redirect_receive();
extern void isdn_send_heartbeat(int link_id);
extern void isdn_cpc_timer(u32 pid);
extern void maintenance_timer(u32 pid);
extern void isdn_restart_timer(u32 pid);
extern void service_dc_proc(u32 pid);
extern void isdn_restart_ctrl(u32 pid);
extern int trans_callref_sd_rest_req(u32 pid, u8 g_pri_cmd);
/*************************************************************
Function: timer_init
Description: initialize the timers of isdn
Input: interval_ms:time cycle
Return: NULL
*************************************************************/
static void timer_init(u32 interval_ms)
{
isdn_timer_var.t301 = ISDN_T301 * 1000 / interval_ms;
isdn_timer_var.t302 = ISDN_T302 * 1000 / interval_ms;
isdn_timer_var.t303 = ISDN_T303 * 1000 / interval_ms;
isdn_timer_var.t304 = ISDN_T304 * 1000 / interval_ms;
isdn_timer_var.t305 = ISDN_T305 * 1000 / interval_ms;
isdn_timer_var.t306 = ISDN_T306 * 1000 / interval_ms;
isdn_timer_var.t307 = ISDN_T307 * 1000 / interval_ms;
isdn_timer_var.t308 = ISDN_T308 * 1000 / interval_ms;
isdn_timer_var.t309 = ISDN_T309 * 1000 / interval_ms;
isdn_timer_var.t310 = ISDN_T310 * 1000 / interval_ms;
isdn_timer_var.t312 = ISDN_T312 * 1000 / interval_ms;
isdn_timer_var.t313 = ISDN_T313 * 1000 / interval_ms;
isdn_timer_var.t316 = ISDN_T316 * 1000 / interval_ms;
isdn_timer_var.t317 = ISDN_T317 * 1000 / interval_ms;
isdn_timer_var.t321 = ISDN_T321 * 1000 / interval_ms;
isdn_timer_var.t322 = ISDN_T322 * 1000 / interval_ms;
isdn_timer_var.t1s = ISDN_T1 * 1000 / interval_ms + 20;
isdn_timer_var.t3M1 = ISDN_T3M1 * 1000 / interval_ms;
}
/*************************************************************
Function: isdn_init
Description: initialize the parameters of isdn
Input: systemID:plat id, interval_ms:time cycle
Return: ISDN_CM_OK:success
*************************************************************/
int isdn_init(u8 systemID, u32 interval_ms)
{
u32 stack_size;
if(interval_ms == 0)
interval_ms = 10;
printf("Start ISDN module init...\n");
memset(&isdn_rs, 0, sizeof(ISDN_Resource_Pond));
memset(&isdn_timer_var, 1, sizeof(IsdnTimerStr));
memset(&isdn_rv_msg, 0, sizeof(IsdnMsgStr));
memset(&isdn_sd_msg, 0, sizeof(IsdnMsgStr));
memset(&iua_rv_msg, 0, sizeof(IuaMsgStr));
memset(&iua_sd_msg, 0, sizeof(IuaMsgStr));
timer_init(interval_ms);
isdn_rs.attrib.systemID = systemID;
isdn_rs.attrib.isdn_remote_ip = 0;
isdn_rs.attrib.isdn_run_mode = 0;
stack_size = sizeof(ISDN_Resource_Pond) + sizeof(IsdnTimerStr);
isdn_debug_init();
printf("ISDN module init completed, stack size: %ld bytes\n", stack_size);
return ISDN_CM_OK;
}
/*************************************************************
Function: isdn_sd_link
Description: isdn send link command to iua
Input: iua_id:link number, opercode:link command parameter
Return: ISDN_CM_OK:success
*************************************************************/
int isdn_sd_link(u8 link_id, u8 opercode)
{
IuaMsgStr isdn_lk;
isdn_lk.msg_class = IUA_MGMT_CMD;
isdn_lk.e1_no = link_id;
isdn_lk.msg_length = htons(0x0003);
isdn_lk.msgcontent.lkmsg.opercode = opercode;
put_xua_msg((xua_up_msg_t*)&isdn_lk.msg_class);
return ISDN_CM_OK;
}
/*************************************************************
Function: isdn_link_ctrl
Description: isdn link control
Input: NULL
Return: NULL
*************************************************************/
void isdn_link_ctrl()
{
int i, link_id;
const pal_circuit_struct *circuit_ptr = NULL;
const pal_cg_struct *cg_ptr = NULL;
for(i = 0; i < ISDN_MAX_CIRCUIT; i++) //for timer //setup link
{
circuit_ptr = pal_circuit_ptr(i);
if(circuit_ptr == NULL)
continue;
if(circuit_ptr->enable == 0)
continue;
if((isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE) &&
(circuit_ptr->attrib.plat_id != isdn_rs.attrib.systemID))
continue;
cg_ptr = pal_cg_ptr(circuit_ptr->cg_id);
if(cg_ptr == NULL)
continue;
if(cg_ptr->attrib.protocol != PROTO_ISDN)
continue;
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)))
continue;
link_id = circuit_ptr->attrib.link_id;
if(cg_ptr->enable)
{
if(isdn_rs.link_pond[link_id].lk3_status == LK_OOS)
{
if(cg_ptr->attrib.nfas.flag) //nfas
{
if((cg_ptr->attrib.nfas.prim_link != link_id) &&
(cg_ptr->attrib.nfas.backup_link != link_id))
continue;
}
isdn_sd_link(link_id, xUA_ENABLE_xUA_LINK); //enable
isdn_sd_link(link_id, M2UA_MTP3_CMD_ACTIVE_LK); //active
}
}
else //modify by 080821
{
if(isdn_rs.link_pond[link_id].lk3_status == LK_IS)
{
if(cg_ptr->attrib.nfas.flag)
{
if((cg_ptr->attrib.nfas.prim_link != link_id) &&
(cg_ptr->attrib.nfas.backup_link != link_id))
continue;
}
isdn_sd_link(link_id, M2UA_MTP3_CMD_DEACTIVE_LK);
isdn_sd_link(link_id, xUA_STOP_xUA_LINK);
}
}
}
for(i = 0; i < ISDN_MAX_CIRCUIT; i++) //release link
{
circuit_ptr = pal_circuit_ptr(i);
if(circuit_ptr == NULL)
continue;
/* if(circuit_ptr->enable == 0)
{
continue;
}*/
if(((isdn_rs.attrib.isdn_run_mode == ISDN_SINGLE_MODE) ||
(isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE &&
circuit_ptr->attrib.plat_id == isdn_rs.attrib.systemID)) &&
(circuit_ptr->enable == 1)) //modify by 080821
continue;
cg_ptr = pal_cg_ptr(circuit_ptr->cg_id);
if(cg_ptr == NULL)
continue;
if(cg_ptr->attrib.protocol != PROTO_ISDN)
continue;
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)))
continue;
link_id = circuit_ptr->attrib.link_id;
if(isdn_rs.link_pond[link_id].lk3_status == LK_IS)
{
if(cg_ptr->attrib.nfas.flag)
{
if((cg_ptr->attrib.nfas.prim_link != link_id) &&
(cg_ptr->attrib.nfas.backup_link != link_id))
continue;
}
isdn_sd_link(link_id, M2UA_MTP3_CMD_DEACTIVE_LK);
isdn_sd_link(link_id, xUA_STOP_xUA_LINK);
}
}
}
void isdn_heartbeat_timer(int link_id)
{
if(isdn_rs.link_pond[link_id].plat_heartbeat_time > 0)
{
isdn_rs.link_pond[link_id].plat_heartbeat_time--;
if(isdn_rs.link_pond[link_id].plat_heartbeat_time == 0)
{
isdn_rs.link_pond[link_id].dc_status = DS_OOS;
isdn_log_err(0, "link %d heartbeat timeout: another plat doesnot send link state!\r\n",link_id);
}
}
}
/*************************************************************
Function: isdn_timer
Description: isdn task schedule, include isdn link control, isdn receive msg from iua and control the timer
Input: NULL
Return: NULL
*************************************************************/
void isdn_timer()
{
u16 i, j, chnl_j, cg_id;
u32 offset, pid;
int circuit_cic, link_id, ds_0, ds_1;
static int link_10s = 0;
const pal_circuit_struct *circuit_ptr = NULL;
const pal_cg_struct *cg_ptr = NULL;
link_10s++;
if(link_10s % 600 == 0) // 6s
{
isdn_link_ctrl(); //setup link
link_10s = 0;
}
for(i = 0; i < 64; i++)
{
if(isdn_receive_msg() == 0)
break; //no message in lower layer
if(isdn_redirect_receive() == 0)
break; //no message from another plat
}
for(i = 0; i < ISDN_MAX_CIRCUIT; i++) //for timer
{
circuit_ptr = pal_circuit_ptr(i);
if(circuit_ptr == NULL)
continue;
if(circuit_ptr->enable == 0)
continue;
if((isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE) &&
(circuit_ptr->attrib.plat_id != isdn_rs.attrib.systemID))
continue;
cg_id = circuit_ptr->cg_id;
cg_ptr = pal_cg_ptr(cg_id);
if(cg_ptr == NULL)
continue;
if(cg_ptr->attrib.protocol != PROTO_ISDN)
continue;
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)))
continue;
link_id = circuit_ptr->attrib.link_id;
isdn_rs.link_pond[link_id].link_heartbeat_time++;
if(isdn_rs.link_pond[link_id].link_heartbeat_time % LINK_MAX_TIME == 0)
{
isdn_rs.link_pond[link_id].lk3_status = isdn_rs.link_pond[link_id].lk2_status;
isdn_rs.link_pond[link_id].lk2_status = LK_OOS;
isdn_rs.link_pond[link_id].link_heartbeat_time = 0;
}
circuit_cic = circuit_ptr->attrib.cic_range;
offset = ISDN_CIRCUIT_CIC * i; //ISDN_CIRCUIT_CIC
if(circuit_cic == 24) //T1
{
if((trans_callref_sd_rest_req(offset+24, ISDN_RESTART_CNF)) == circuit_cic)
{
isdn_rs.port_pond[offset+24].g_pri_cmd = ISDN_RESTART_CNF;
isdn_restart_ctrl(offset+24); //restart control
}
// offset++;
}
else
{
if((trans_callref_sd_rest_req(offset, ISDN_RESTART_CNF)) == circuit_cic)
{
isdn_rs.port_pond[offset].g_pri_cmd = ISDN_RESTART_CNF;
isdn_restart_ctrl(offset); //restart control
}
}
for(j = 0; j < circuit_cic; j++)
{
chnl_j = j;
if(circuit_cic == 24) //T1
chnl_j = j + 1;
pid = offset + chnl_j;
if(cg_ptr->attrib.nfas.flag) //NFAS
{
ds_0 = cg_ptr->attrib.nfas.prim_link;
ds_1 = cg_ptr->attrib.nfas.backup_link;
if(circuit_ptr->attrib.d_chnl == chnl_j) //d-channel
{
if(ds_0 == link_id)
{
if(isdn_rs.link_pond[link_id].lk3_status == LK_IS)
{
if((isdn_rs.link_pond[ds_0].dc_status == DS_MOOS) &&
(isdn_rs.link_pond[ds_1].dc_status != DS_IS))
isdn_rs.port_pond[pid].g_pri_cmd = ISDN_SERVICE_REQ;
}
else
isdn_rs.link_pond[link_id].dc_status = DS_OOS;
service_dc_proc(pid);
if((link_10s % 100 == 0) && (isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE)) //send heartbeat per 1 second
isdn_send_heartbeat(link_id);
if(isdn_rs.link_pond[link_id].plat_heartbeat_time > 0)
isdn_rs.link_pond[link_id].plat_heartbeat_time = 0;
}
else if(ds_1 == link_id)
{
if(isdn_rs.link_pond[link_id].lk3_status == LK_IS)
{
if((isdn_rs.link_pond[ds_1].dc_status == DS_MOOS) &&
((isdn_rs.link_pond[ds_0].dc_status == DS_OOS) ||
(isdn_rs.link_pond[ds_0].dc_status == DS_STBY)))
isdn_rs.port_pond[pid].g_pri_cmd = ISDN_SERVICE_REQ;
}
else
isdn_rs.link_pond[link_id].dc_status = DS_OOS;
service_dc_proc(pid);
if((link_10s % 100 == 0) && (isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE)) //send heartbeat per 1 second
isdn_send_heartbeat(link_id);
if(isdn_rs.link_pond[link_id].plat_heartbeat_time > 0)
isdn_rs.link_pond[link_id].plat_heartbeat_time = 0;
}
}
}
else //associated signaling
{
if(isdn_rs.link_pond[link_id].lk3_status == LK_IS)
{
if(circuit_ptr->attrib.d_chnl == chnl_j) //d-channel
isdn_rs.link_pond[link_id].dc_status = DS_IS;
}
else
{
if(circuit_ptr->attrib.d_chnl == chnl_j) //d-channel
isdn_rs.link_pond[link_id].dc_status = DS_OOS;
}
}
if(isdn_rs.port_pond[pid].enable)
isdn_cpc_timer(pid);
isdn_restart_timer(pid);
maintenance_timer(pid);
}
if(isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE)
isdn_heartbeat_timer(i);
}
isdn_debug_timer();
}
/*************************************************************
Function: isdn_assign_port
Description: isdn assign the port id
Input: e1no:link number
Return: port id:success
0:failed
*************************************************************/
u32 isdn_assign_port(u16 circuit_id)
{
u8 i, chnl;
u32 e1nox32 = 0;
u32 portnum = 0;
chnl = 32;
e1nox32 = circuit_id;
e1nox32 = (e1nox32 << 5);
for(i = 0; i < 31; i++)
{
chnl = (chnl - i) & 0x1F;
if (((chnl & 0x1F) != 0) && (chnl != 16))
{
portnum = e1nox32 + chnl;
if (isdn_rs.port_pond[portnum].enable == 0)
{
if(isdn_rs.port_pond[portnum].cic_state.maintenance_state != IN_SERVICE)
{
isdn_log_err(0, "this cic is not in service in assign port!\r\n");
break;
}
isdn_rs.port_pond[portnum].enable = 1;
return portnum;
}
}
}
return 0;
}
/*************************************************************
Function: find_port_by_callref
Description: find port id by the call referrence and link id
Input: cref:call referrence, circuit_id:circuit id
Return: port id:success
0:failed
*************************************************************/
u32 find_port_by_callref(u16 cref, u16 circuit_id)
{
int i, circuit_cic, d_chnl=16;
u32 portnum = 0;
const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(circuit_id);
if(circuit_ptr == NULL)
return ISDN_CM_FAILED;
circuit_cic = circuit_ptr->attrib.cic_range;
if(circuit_cic == 24) //T1
{
d_chnl = 24;
}
portnum = (circuit_id * ISDN_CIRCUIT_CIC) + 1;
for (i = 1; i < circuit_cic; i++, portnum++)
{
if (i != d_chnl)
{
if(isdn_rs.port_pond[portnum].call_ref == cref)
return portnum;
}
}
// isdn_log_err(0, "find port by callref err!call_ref=%d, circuit_id=%d\r\n",cref, circuit_id);
return 0;
}
/*************************************************************
Function: find_port_by_cic
Description: find port id by the cic of one link
Input: cic:cic, circuit_id:circuit id
Return: port id:success
*************************************************************/
u32 find_port_by_cic(u32 cic, u16 circuit_id)
{
u32 head_cic;
const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(circuit_id);
if(circuit_ptr == NULL)
return ISDN_CM_FAILED;
head_cic = circuit_ptr->attrib.head_cic;
if(circuit_ptr->attrib.cic_range == 24)
head_cic--;
return ISDN_CIRCUIT_CIC * circuit_id + (cic - head_cic);
}
int find_circuit_by_interfaceId(int cg_id, u8 interface_id)
{
int i;
const pal_circuit_struct *circuit_ptr = NULL;
for(i = 0; i < ISDN_MAX_CIRCUIT; i++)
{
circuit_ptr = pal_circuit_ptr(i);
if(circuit_ptr == NULL)
continue;
if(circuit_ptr->enable == 0)
continue;
if((isdn_rs.attrib.isdn_run_mode == ISDN_DUAL_MODE) &&
(circuit_ptr->attrib.plat_id != isdn_rs.attrib.systemID))
continue;
if(circuit_ptr->cg_id != cg_id)
continue;
if((circuit_ptr->attrib.cic_range != 0) && (circuit_ptr->attrib.head_cic / circuit_ptr->attrib.cic_range) == interface_id)
return i;
}
isdn_log_err(0, "find circuit by interface id err!cg_id=%d, interface_id=%d\r\n",cg_id, interface_id);
return -1;
}
//d-channel status
int check_dc_status(u8 link_id)
{
if(isdn_rs.link_pond[link_id].dc_status == DS_IS)
return ISDN_CM_OK;
else
return ISDN_CM_FAILED;
}
int isdn_set_run_mode (u8 run_mode, u32 alter_ip)
{
isdn_trace_func(0,"APP => function trace: %s\r\n", __FUNCTION__);
isdn_rs.attrib.isdn_run_mode = run_mode % 2;
isdn_rs.attrib.isdn_remote_ip = alter_ip;
return ISDN_CM_OK;
}