/*********************************************************** 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: ************************************************************/ #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; }