516 lines
15 KiB
C
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;
|
|
}
|
|
|