/*********************************************************** Copyright (C), LGC Wireless. File Name: isdn_fsm.c Description: ISDN FSM Version: v9.0.0 Author: Gengxin Chen Create Date: 2008-2-19 History: ************************************************************/ #include "./include/isdn_const.h" #include "./include/isdn_rm.h" #include "./include/isdn_debug.h" #include "./include/isdn_ext.h" #include "./include/isdn_inc.h" #define USR 0x00 #define LN 0x02 #define TN 0x03 #define RLN 0x04 #define DF RLN u8 cause_to_loc[128]={ DF, LN, LN, LN, DF, DF, LN, LN, DF, DF, DF, DF, DF, DF, DF, DF, USR,USR,RLN,RLN, DF, USR,LN, DF, DF, RLN,LN, RLN,RLN,RLN, LN, RLN,DF, DF, RLN,DF, DF, DF, USR,DF, DF, RLN,RLN,LN, LN, DF, DF, USR,DF, DF, RLN,DF, DF, DF, DF, RLN,DF, LN, LN, DF, DF, DF, DF, LN, DF, LN, DF, DF, DF, RLN, DF, DF, DF, DF, DF, DF, DF, DF, DF, DF, DF, LN, DF, LN, LN, LN, LN, RLN,USR,DF, DF, LN, DF, DF, DF, LN, LN, RLN,LN, RLN, LN, LN, RLN,DF, DF, DF, DF, DF, DF, DF, DF, RLN,DF, DF, DF, DF, DF, DF, DF, DF, DF, DF, DF, DF, DF, DF, DF, DF }; u16 cr_start[ISDN_MAX_CG] = {0}; u8 cr_state[4096] = {0}; void isdn_cpc_proc(u32 pid); int isdn_event_handle(u32 pid, u8 primitive);//, u8 eventType) static int isdn_cc_nt(u32 pid); static int isdn_cc_lt(u32 pid); extern int isdn_send_msg(u32 pid, u8 msg_type); extern int isdn_send_maintenance_msg(u32 pid, u8 msg_type); /************************************************************* Function: cr_sel Description: according to port id, selection the idle call reference Input: pid:port id, indicate the cic of the IUA link Return: ISDN_CM_OK:success ISDN_CM_FAILED:failed *************************************************************/ int cr_sel(u32 pid) { u16 tmp_cr, i, byte_offset, circuit_id, cg_id; u8 bit_offset, key; const pal_circuit_struct *circuit_ptr = NULL; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; circuit_id = pid / ISDN_CIRCUIT_CIC; circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) return ISDN_CM_FAILED; cg_id = circuit_ptr->cg_id; tmp_cr = (cr_start[cg_id] & 0x3FFF); for(i = 0; i < 0x3FFF; i++) { tmp_cr++; tmp_cr &= 0x3FFF; if(tmp_cr != 0) { tmp_cr = (tmp_cr | ((circuit_ptr->attrib.plat_id & 0x01) << 14)); byte_offset = tmp_cr / 8; bit_offset = tmp_cr % 8; key = ((cr_state[byte_offset] >> bit_offset) & 0x01); if(key == 0) { pPort->call_ref = (tmp_cr | 0x8000); //call_ref[pid] cr_start[cg_id] = tmp_cr; cr_state[byte_offset] = (cr_state[byte_offset] | (0x01 << bit_offset)); return ISDN_CM_OK; } } } return ISDN_CM_FAILED; } /************************************************************* Function: rel_cr Description: release the call reference Input: pid:port id Return: ISDN_CM_OK:success *************************************************************/ int rel_cr(u32 pid) { u16 tmp_cr, byte_offset; u8 bit_offset; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; tmp_cr = (pPort->call_ref & 0x7FFF); if(pPort->call_ref & 0x8000) { byte_offset = tmp_cr / 8; bit_offset = tmp_cr % 8; cr_state[byte_offset] = (cr_state[byte_offset] ^ (0x01 << bit_offset)); } pPort->call_ref = 0; pPort->callout_fg = 0; //msg_cref[pid] = 0; return ISDN_CM_OK; } /************************************************************* Function: rel_B_chnl Description: release B-channel link Input: pid:port id Return: ISDN_CM_OK:success *************************************************************/ int rel_B_chnl(u32 pid) { u8 flag; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; flag = pPort->enable; if (flag != 0) { pPort->enable = 0; pPort->su_proc_id = 0; pPort->cic_val = 0; pPort->pre_send_msg = 0; } return ISDN_CM_OK; } /************************************************************* Function: isdn_cpc_clear Description: clearing the interrelated state of the call at call processing control Output: pPort:port structure pointer Return: NULL *************************************************************/ inline void isdn_cpc_clear(ISDN_Port_struct *pPort) { pPort->timer_flag = 0; pPort->cic_state.call_state = IDLE_FLAG; pPort->fsm_state.cpc_state = NULL_STATE; } /************************************************************* Function: isdn_rel_proc Description: release isdn module process, include rel_B_chnl() and rel_cr() Input: pid:port id, cause:release reason value Return: ISDN_CM_OK:success *************************************************************/ int isdn_rel_proc(u32 pid, u32 cause) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; isdn_event_handle(pid, ISDN_RELEASE_IND); pPort->w_time = 0; rel_B_chnl(pid); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); return ISDN_CM_OK; } /************************************************************* Function: nr_proc Description: processing nr, nr is the interval state identifier in the SDL diagrams Input: pid:port id Return: if LT side, successfully enter the state u19 if NT side, successfully enter the state n19 *************************************************************/ int nr_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; pPort->w_time = 0; //start t308 pPort->timeout_fg = 0; isdn_send_msg(pid, MSG_REL); return REL_REQ_STATE; } /************************************************************* Function: nd_proc Description: processing nd, nd is the interval state identifier in the SDL diagrams Input: pid:port id Return: if LT side, successfully enter the state u12 if NT side, successfully enter the state n11 *************************************************************/ int nd_proc(u32 pid) { int circuit_id; const pal_circuit_struct *circuit_ptr = NULL; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; circuit_id = pid / ISDN_CIRCUIT_CIC; circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) { isdn_log_err(pid, "nd_proc err!circuit_id %d can't find circuit_ptr", circuit_id); return ISDN_CM_FAILED; } /*disconnect B-channel*/ pPort->w_time = 0; //stop all isdn_event_handle(pid, ISDN_DISCONNECT_IND); if(circuit_ptr->attrib.user_network_if) return DISC_IND_STATE; else return DISC_REQ_STATE; } /************************************************************* Function: nc_proc Description: processing nc, nc is the interval state identifier in the SDL diagrams Input: pid:port id Return: if LT side, successfully enter the state u11 if NT side, successfully enter the state n12 *************************************************************/ int nc_proc(u32 pid) { int circuit_id; const pal_circuit_struct *circuit_ptr = NULL; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; circuit_id = pid / ISDN_CIRCUIT_CIC; circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) { isdn_log_err(pid, "nc_proc err!circuit_id %d can't find circuit_ptr", circuit_id); return ISDN_CM_FAILED; } /*disconnect B-channel*/ pPort->w_time = 0; //stop all and start t305 isdn_send_msg(pid, MSG_DISC); if(circuit_ptr->attrib.user_network_if) return DISC_REQ_STATE; else return DISC_IND_STATE; } /************************************************************* Function: isdn_set_cause Description: set the reason value, and keep into cause_ptr Input: val:reason value Output: cause_ptr:cause structure pointer Return: NULL *************************************************************/ void isdn_set_cause(CauseStr *cause_ptr, u8 val) { cause_ptr->pres = 1; cause_ptr->ext_flag = 0x0; cause_ptr->b3.has_ext_a = 1; cause_ptr->b3.code_stan = 0x0; //CCITT standardized coding cause_ptr->b3.loc = cause_to_loc[val]; cause_ptr->cause_val = val; } /************************************************************* Function: isdn_set_status Description: set the call state, and keep into status_ptr Input: state:call state, cause_val:reason value Output: status_ptr:status structure pointer Return: NULL *************************************************************/ void isdn_set_status(IsdnStatus *status_ptr, u8 state, u8 cause_val) { isdn_set_cause(&status_ptr->cause, cause_val); status_ptr->call_stat.code_stan = 0x0; status_ptr->call_stat.stat_val = (state & 0x3F); } /************************************************************* Function: n0_proc Description: Null State, no call exists. Handling the process and entering into next call state Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n0_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_SETUP_REQ) { pPort->primitive_cmd = 0; if(cr_sel(pid) != 1) { isdn_log_err(pid, "cr_sel error!\r\n"); return NULL_STATE; } isdn_send_msg(pid, MSG_SETUP); pPort->timer_flag = CALLIN_FLAG; pPort->w_time = 0; //start t303 pPort->timeout_fg = 0; return CALL_PRE_STATE; } else if(pPort->msg_cmd == MSG_SETUP) { pPort->msg_cmd = 0; //pPort->call_ref = msg_cref[pid]; isdn_event_handle(pid, ISDN_SETUP_IND); return CALL_INIT_STATE; } //MSG_REL, MSG_REL_COMP, MSG_STATUS, and MSG_STAT_ENQ are doing in n0_ext_proc() return -1; } /************************************************************* Function: n1_proc Description: Call initiated state, this state exists for an outgoing call when the network has received a call establishment request but has not yet responded. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n1_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_PROC_REQ) { pPort->primitive_cmd = 0; /*Connect B-channel*/ isdn_send_msg(pid, MSG_CALL_PROC); return OUT_CALL_PROC_STATE; } else if(pPort->primitive_cmd == ISDN_MORE_INFO_REQ) { pPort->primitive_cmd = 0; pPort->w_time = 0; //start t302 /*Connect B-channel*/ isdn_send_msg(pid, MSG_SETUP_ACK); return OVERLAP_SD_STATE; } else if(pPort->primitive_cmd == ISDN_REJECT_REQ) { pPort->primitive_cmd = 0; rel_B_chnl(pid); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); return NULL_STATE; } return -1; } /************************************************************* Function: n2_proc Description: Overlap sending state, this state exists for an outgoing call when the network has acknowledged the call establishment request and is prepared to receive additional call information (if any) in overlap mode. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n2_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_PROC_REQ) { pPort->primitive_cmd = 0; pPort->w_time = 0; //stop t302 isdn_send_msg(pid, MSG_CALL_PROC); return OUT_CALL_PROC_STATE; } else if(pPort->msg_cmd == MSG_INFORMATION) { pPort->msg_cmd = 0; pPort->w_time = 0; //start or restart t302 isdn_event_handle(pid, ISDN_INFO_IND); return OVERLAP_SD_STATE; } else if(pPort->primitive_cmd == ISDN_ALERT_REQ) { pPort->primitive_cmd = 0; pPort->w_time = 0; //stop t302 isdn_send_msg(pid, MSG_ALERT); return CALL_DV_STATE; } else if(pPort->primitive_cmd == ISDN_SETUP_RSP) { pPort->primitive_cmd = 0; pPort->w_time = 0; //stop t302 /* Connect Backwards B-channel Here */ isdn_send_msg(pid, MSG_CONN); return ACTIVE_STATE; } else if(pPort->primitive_cmd == ISDN_PROG_REQ) { pPort->primitive_cmd = 0; pPort->w_time = 0; //stop t302 isdn_send_msg(pid, MSG_PROG); return OVERLAP_SD_STATE; } return -1; } /************************************************************* Function: n3_proc Description: Outgoing call proceeding state, this state exists for an outgoing call when the network has sent acknowledgement that the network has received all call information necessary to effect call establishment. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n3_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_ALERT_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_ALERT); return CALL_DV_STATE; } else if(pPort->primitive_cmd == ISDN_SETUP_RSP) { pPort->primitive_cmd = 0; /* Connect Backwards B-channel Here */ isdn_send_msg(pid, MSG_CONN); return ACTIVE_STATE; } else if(pPort->primitive_cmd == ISDN_PROG_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_PROG); return OUT_CALL_PROC_STATE; } return -1; } /************************************************************* Function: n4_proc Description: Call delivered state, this state exists for an outgoing call when the network has indicated that remote user alerting has been initiated. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n4_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_SETUP_RSP) { pPort->primitive_cmd = 0; /* Connect Backwards B-channel Here */ isdn_send_msg(pid, MSG_CONN); return ACTIVE_STATE; } else if(pPort->primitive_cmd == ISDN_PROG_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_PROG); return CALL_DV_STATE; } return -1; } /************************************************************* Function: n6_proc Description: Call present state, this state exists for an incoming call when the network has sent a call establishment request but has not yet received a satisfactory response. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n6_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_CALL_PROC) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 and start t310 isdn_event_handle(pid, ISDN_PROC_IND); return IN_CALL_PROC_STATE; } else if(pPort->msg_cmd == MSG_ALERT) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 and start t301 isdn_event_handle(pid, ISDN_ALERT_IND); return CALL_RV_STATE; } else if(pPort->msg_cmd == MSG_CONN) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 pPort->primitive_cmd = ISDN_SETUP_CNF; //msc does not provide ISDN_SETUP_COMP_REQ to isdn isdn_event_handle(pid, ISDN_SETUP_CNF); return CONN_REQ_STATE; } else if(pPort->msg_cmd == MSG_SETUP_ACK) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 and start t304 isdn_event_handle(pid, ISDN_MORE_INFO_IND); return OVERLAP_RV_STATE; } else if(pPort->msg_cmd == MSG_REL_COMP) //do it temporarily in isdn_comm_ctrl() { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 // isdn_event_handle(pid, ISDN_REJ_IND); rel_B_chnl(pid); rel_cr(pid); return NULL_STATE; } return -1; } /************************************************************* Function: n7_proc Description: Call received state, this state exists for an incoming call when the network has received an indication that the user is alerting but has not yet received an answer. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n7_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_CONN) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t301 pPort->primitive_cmd = ISDN_SETUP_CNF; //msc does not provide ISDN_SETUP_COMP_REQ to isdn isdn_event_handle(pid, ISDN_SETUP_CNF); return CONN_REQ_STATE; } else if(pPort->msg_cmd == MSG_PROG) //support U04_09 { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t310 isdn_event_handle(pid, ISDN_PROG_IND); return CALL_DV_STATE; } return -1; } /************************************************************* Function: n8_proc Description: Connect request state, this state exists for an incoming call when the network has received an answer but the network has not yet awarded the call. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n8_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_SETUP_COMP_REQ) { pPort->primitive_cmd = 0; /* Connect Backwards B-channel Here */ isdn_send_msg(pid, MSG_CONNACK); return ACTIVE_STATE; } return -1; } /************************************************************* Function: n9_proc Description: Incoming call proceeding state, this state exists for an incoming call when the network has received acknowledgement that the user has received all call information necessary to effect call establishment. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n9_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_ALERT) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t310 and start t301 isdn_event_handle(pid, ISDN_ALERT_IND); return CALL_RV_STATE; } else if(pPort->msg_cmd == MSG_CONN) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t310 pPort->primitive_cmd = ISDN_SETUP_CNF; //msc does not provide ISDN_SETUP_COMP_REQ to isdn isdn_event_handle(pid, ISDN_SETUP_CNF); return CONN_REQ_STATE; } else if(pPort->msg_cmd == MSG_PROG) { pPort->msg_cmd = 0; isdn_event_handle(pid, ISDN_PROG_IND); return IN_CALL_PROC_STATE; } return -1; } /************************************************************* Function: n10_proc Description: Active state, this state exists for an incoming call when the network has awarded the call to the called user, and this state exists for an outgoing call when the network has indicated that the remote user has answered the call. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n10_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_CONNACK) { pPort->msg_cmd = 0; return ACTIVE_STATE; } else if(pPort->msg_cmd == MSG_NOTI) { pPort->msg_cmd = 0; isdn_event_handle(pid, ISDN_NOTI_IND); return ACTIVE_STATE; } else if(pPort->primitive_cmd == ISDN_NOTI_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_NOTI); return ACTIVE_STATE; } return -1; } /************************************************************* Function: n11_proc Description: Disconnect request state, this state exists when the network has received a request from the user to clear the end-to-end connection (if any). Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n11_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_RELEASE_REQ) { pPort->primitive_cmd = 0; return nr_proc(pid); //REL_REQ_STATE; } else if(pPort->msg_cmd == MSG_REL) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop all memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr)); isdn_event_handle(pid, ISDN_RELEASE_CNF); rel_B_chnl(pid); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } return -1; } /************************************************************* Function: n12_proc Description: Disconnect indication state, this state exists when the network has disconnected the end-to-end connection (if any) and has sent an invitation to disconnect the user-network connection. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n12_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_DISC) { pPort->msg_cmd = 0; memcpy(&isdn_sd_msg.msg_list.rel.cause, &isdn_rv_msg.msg_list.disc.cause, sizeof(CauseStr)); return nr_proc(pid); //REL_REQ_STATE } else if(pPort->msg_cmd == MSG_REL) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t305 or t306 memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr)); // isdn_event_handle(pid, ISDN_RELEASE_IND); isdn_event_handle(pid, ISDN_RELEASE_CNF); rel_B_chnl(pid); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } return -1; } /************************************************************* Function: n19_proc Description: Release request state, this state exists when the network has requested the user to release and is waiting for a response. Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n19_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if((pPort->msg_cmd == MSG_REL_COMP) || (pPort->msg_cmd == MSG_REL)) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t308 isdn_event_handle(pid, ISDN_RELEASE_CNF); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } else if(pPort->msg_cmd == MSG_STATUS) { pPort->msg_cmd = 0; if(isdn_rv_msg.msg_list.status.call_stat.stat_val != 0) return REL_REQ_STATE; pPort->w_time = 0; //stop t308 isdn_event_handle(pid, ISDN_STAT_IND); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } return -1; } /************************************************************* Function: n25_proc Description: Overlap receiving state, this state exists for an incoming call when the network has received acknowledgement of the call establishment request which permits the network to send additional call information (if any) in the overlap mode Handling the process and entering into next call state. Input: pid:port id Return: state value:success -1:failed *************************************************************/ int n25_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_INFO_REQ) //ISDN_MORE_INFO_REQ { pPort->primitive_cmd = 0; pPort->w_time = 0; //start or restart t304 isdn_send_msg(pid, MSG_INFORMATION); return OVERLAP_RV_STATE; } else if(pPort->msg_cmd == MSG_ALERT) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t304 and start t301 isdn_event_handle(pid, ISDN_ALERT_IND); return CALL_RV_STATE; } else if(pPort->msg_cmd == MSG_CONN) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t304 pPort->primitive_cmd = ISDN_SETUP_CNF; //msc does not provide ISDN_SETUP_COMP_REQ to isdn isdn_event_handle(pid, ISDN_SETUP_CNF); return CONN_REQ_STATE; } else if(pPort->msg_cmd == MSG_CALL_PROC) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t304 and start t310 isdn_event_handle(pid, ISDN_PROC_IND); return IN_CALL_PROC_STATE; } else if(pPort->msg_cmd == MSG_PROG) { pPort->msg_cmd = 0; isdn_event_handle(pid, ISDN_PROG_IND); return OVERLAP_RV_STATE; } return -1; } /*user side state processing*/ int u0_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_SETUP_REQ) { pPort->primitive_cmd = 0; if(cr_sel(pid) != 1) { isdn_log_err(pid, "cr_sel error!\r\n"); return NULL_STATE; } isdn_send_msg(pid, MSG_SETUP); pPort->timer_flag = CALLOUT_FLAG; pPort->w_time = 0; //start t303 pPort->timeout_fg = 0; return CALL_INIT_STATE; } else if(pPort->msg_cmd == MSG_SETUP) { pPort->msg_cmd = 0; //pPort->call_ref = msg_cref[pid]; isdn_event_handle(pid, ISDN_SETUP_IND); return CALL_PRE_STATE; } return -1; } int u1_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_SETUP_ACK) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 and start t304 isdn_event_handle(pid, ISDN_MORE_INFO_IND); return OVERLAP_SD_STATE; } else if(pPort->msg_cmd == MSG_CALL_PROC) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 and start t310 isdn_event_handle(pid, ISDN_PROC_IND); return OUT_CALL_PROC_STATE; } else if(pPort->msg_cmd == MSG_ALERT) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 isdn_event_handle(pid, ISDN_ALERT_IND); return CALL_DV_STATE; } else if(pPort->msg_cmd == MSG_CONN) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 isdn_event_handle(pid, ISDN_SETUP_CNF); isdn_send_msg(pid, MSG_CONNACK); return ACTIVE_STATE; } else if(pPort->msg_cmd == MSG_REL_COMP) //do it temporarily in isdn_comm_ctrl() { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t303 //isdn_event_handle(pid, ISDN_REJ_IND); rel_cr(pid); return NULL_STATE; } return -1; } int u2_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_CALL_PROC) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t304 and start t310 isdn_event_handle(pid, ISDN_PROC_IND); return OUT_CALL_PROC_STATE; } else if(pPort->msg_cmd == MSG_ALERT) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t304 isdn_event_handle(pid, ISDN_ALERT_IND); return CALL_DV_STATE; } else if(pPort->msg_cmd == MSG_CONN) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t304 isdn_event_handle(pid, ISDN_SETUP_CNF); isdn_send_msg(pid, MSG_CONNACK); return ACTIVE_STATE; } else if(pPort->msg_cmd == MSG_PROG) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t304 isdn_event_handle(pid, ISDN_PROG_IND); return OVERLAP_SD_STATE; } else if(pPort->primitive_cmd == ISDN_INFO_REQ) { pPort->primitive_cmd = 0; pPort->w_time = 0; //start or restart t304 isdn_send_msg(pid, MSG_INFORMATION); return OVERLAP_SD_STATE; } return -1; } int u3_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_ALERT) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t310 and start t301 isdn_event_handle(pid, ISDN_ALERT_IND); return CALL_DV_STATE; } else if(pPort->msg_cmd == MSG_CONN) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t310 isdn_event_handle(pid, ISDN_SETUP_CNF); isdn_send_msg(pid, MSG_CONNACK); return ACTIVE_STATE; } else if(pPort->msg_cmd == MSG_PROG) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t310 isdn_event_handle(pid, ISDN_PROG_IND); return OUT_CALL_PROC_STATE; } return -1; } int u4_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_CONN) { pPort->msg_cmd = 0; isdn_event_handle(pid, ISDN_SETUP_CNF); isdn_send_msg(pid, MSG_CONNACK); return ACTIVE_STATE; } else if(pPort->msg_cmd == MSG_PROG) //support U04_09 { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t310 isdn_event_handle(pid, ISDN_PROG_IND); return CALL_DV_STATE; } return -1; } int u6_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_MORE_INFO_REQ) { pPort->primitive_cmd = 0; pPort->w_time = 0; //start t302 isdn_send_msg(pid, MSG_SETUP_ACK); return OVERLAP_RV_STATE; } else if(pPort->primitive_cmd == ISDN_PROC_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_CALL_PROC); return IN_CALL_PROC_STATE; } else if(pPort->primitive_cmd == ISDN_ALERT_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_ALERT); return CALL_RV_STATE; } else if(pPort->primitive_cmd == ISDN_SETUP_RSP) { pPort->primitive_cmd = 0; pPort->w_time = 0; //start t313 isdn_send_msg(pid, MSG_CONN); return CONN_REQ_STATE; } else if(pPort->primitive_cmd == ISDN_REJECT_REQ) { pPort->primitive_cmd = 0; rel_B_chnl(pid); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); return NULL_STATE; } return -1; } int u7_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_SETUP_RSP) { pPort->primitive_cmd = 0; pPort->w_time = 0; //start t313 isdn_send_msg(pid, MSG_CONN); return CONN_REQ_STATE; } else if(pPort->primitive_cmd == ISDN_PROG_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_PROG); return CALL_DV_STATE; } return -1; } int u8_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_CONNACK) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t313 isdn_event_handle(pid, ISDN_SETUP_COMP_IND); return ACTIVE_STATE; } return -1; } int u9_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->primitive_cmd == ISDN_ALERT_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_ALERT); return CALL_RV_STATE; } else if(pPort->primitive_cmd == ISDN_SETUP_RSP) { pPort->primitive_cmd = 0; pPort->w_time = 0; //start t313 isdn_send_msg(pid, MSG_CONN); return CONN_REQ_STATE; } else if(pPort->primitive_cmd == ISDN_PROG_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_PROG); return IN_CALL_PROC_STATE; } return -1; } int u10_proc(u32 pid) //?? add by gengxin { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_NOTI) { pPort->msg_cmd = 0; isdn_event_handle(pid, ISDN_NOTI_IND); return ACTIVE_STATE; } else if(pPort->primitive_cmd == ISDN_NOTI_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_NOTI); return ACTIVE_STATE; } return -1; } int u11_proc(u32 pid) //0911 { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_DISC) { pPort->msg_cmd = 0; memcpy(&isdn_sd_msg.msg_list.rel.cause, &isdn_rv_msg.msg_list.disc.cause, sizeof(CauseStr)); return nr_proc(pid); } else if(pPort->msg_cmd == MSG_REL) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t305 memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr)); // isdn_event_handle(pid, ISDN_RELEASE_IND); isdn_event_handle(pid, ISDN_RELEASE_CNF); rel_B_chnl(pid); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } return -1; } int u12_proc(u32 pid) //0911 { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_REL) { pPort->msg_cmd = 0; memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr)); // isdn_event_handle(pid, ISDN_RELEASE_IND); isdn_event_handle(pid, ISDN_RELEASE_CNF); rel_B_chnl(pid); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } else if(pPort->primitive_cmd == ISDN_RELEASE_REQ) { pPort->primitive_cmd = 0; return nr_proc(pid); } return -1; } int u19_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if((pPort->msg_cmd == MSG_REL_COMP) || (pPort->msg_cmd == MSG_REL)) { pPort->msg_cmd = 0; isdn_event_handle(pid, ISDN_RELEASE_CNF); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } else if(pPort->msg_cmd == MSG_STATUS) { pPort->msg_cmd = 0; if(isdn_rv_msg.msg_list.status.call_stat.stat_val != 0) return REL_REQ_STATE; isdn_event_handle(pid, ISDN_STAT_IND); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } return -1; } int u25_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_INFORMATION) { pPort->msg_cmd = 0; pPort->w_time = 0; //start t302 isdn_event_handle(pid, ISDN_INFO_IND); return OVERLAP_RV_STATE; } else if(pPort->primitive_cmd == ISDN_PROC_REQ) { pPort->primitive_cmd = 0; pPort->w_time = 0; //stop t302 isdn_send_msg(pid, MSG_CALL_PROC); return IN_CALL_PROC_STATE; } else if(pPort->primitive_cmd == ISDN_ALERT_REQ) { pPort->primitive_cmd = 0; pPort->w_time = 0; //stop t302 isdn_send_msg(pid, MSG_ALERT); return CALL_RV_STATE; } else if(pPort->primitive_cmd == ISDN_SETUP_RSP) { pPort->primitive_cmd = 0; pPort->w_time = 0; //stop t302 and start t313 isdn_send_msg(pid, MSG_CONN); return CONN_REQ_STATE; } else if(pPort->primitive_cmd == ISDN_PROG_REQ) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_PROG); return OVERLAP_RV_STATE; } return -1; } /* Global Call Reference Procedures */ /************************************************************* Function: trans_callref_sd_rest_req Description: Input: Output: Return: *************************************************************/ int trans_callref_sd_rest_req(u32 pid, u8 g_pri_cmd) //isdn_restart_req() { int i, link_id, cic_range; u16 circuit_id; const pal_circuit_struct *circuit_ptr = NULL; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; circuit_id = pid / ISDN_CIRCUIT_CIC; circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) return ISDN_CM_FAILED; link_id = circuit_ptr->attrib.link_id; cic_range = circuit_ptr->attrib.cic_range; if(cic_range == 24) //T1 cic_range++; if(isdn_rs.link_pond[link_id].restart_clas == 0) //indicated channels { if(pPort->cic_val != 0) { pid = find_port_by_cic(pPort->cic_val, circuit_id); pPort = &isdn_rs.port_pond[pid]; if(g_pri_cmd == ISDN_RESTART_REQ) { pPort->g_pri_cmd = ISDN_RESTART_REQ; isdn_cpc_proc(pid); if(pPort->g_pri_cmd != 0 && pPort->g_pri_cmd != ISDN_RESTART_CNF) { isdn_trace_func(pid, "[waring]primitive cmd discard.(cmd=%d)\r\n", pPort->primitive_cmd); pPort->g_pri_cmd = 0; } return circuit_ptr->attrib.cic_range; } else if(g_pri_cmd == ISDN_RESTART_CNF) { if(pPort->g_pri_cmd != g_pri_cmd) { pPort->g_pri_cmd = 0; isdn_trace_func(pid, "[waring]primitive cmd is not ISDN_RESTART_CNF.(cmd=%d)\r\n", pPort->primitive_cmd); return ISDN_CM_FAILED; } pPort->g_pri_cmd = 0; return circuit_ptr->attrib.cic_range; } } } else if(isdn_rs.link_pond[link_id].restart_clas == 6) //single interface { for(i = 1; i < cic_range; i++) { pid = circuit_id * ISDN_CIRCUIT_CIC + i; pPort = &isdn_rs.port_pond[pid]; if(pPort->enable != 0) { if(g_pri_cmd == ISDN_RESTART_REQ) { pPort->g_pri_cmd = ISDN_RESTART_REQ; isdn_cpc_proc(pid); if(pPort->g_pri_cmd != 0 && pPort->g_pri_cmd != ISDN_RESTART_CNF) { isdn_trace_func(pid, "[waring]primitive cmd discard.(cmd=%d)\r\n", pPort->primitive_cmd); pPort->g_pri_cmd = 0; } } else if(g_pri_cmd == ISDN_RESTART_CNF) { if(pPort->g_pri_cmd != g_pri_cmd) { pPort->g_pri_cmd = 0; isdn_trace_func(pid, "[waring]primitive cmd is not ISDN_RESTART_CNF.(cmd=%d)\r\n", pPort->primitive_cmd); return ISDN_CM_FAILED; } pPort->g_pri_cmd = 0; } } } // isdn_rs.link_pond[link_id].restart_clas = 0; return circuit_ptr->attrib.cic_range; } return ISDN_CM_FAILED; } static inline void restart_clear(u32 pid) { int i, link_id, cic_range; u16 circuit_id = pid / ISDN_CIRCUIT_CIC; const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(circuit_id); ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(circuit_ptr == NULL) return; link_id = circuit_ptr->attrib.link_id; cic_range = circuit_ptr->attrib.cic_range; if(cic_range == 24) //T1 cic_range++; if(isdn_rs.link_pond[link_id].restart_clas == 0) //indicated channels { pid = find_port_by_cic(pPort->cic_val, circuit_id); pPort->cic_val = 0; rel_B_chnl(pid); isdn_cpc_clear(pPort); } else { isdn_rs.link_pond[link_id].restart_clas = 0; for(i = 1; i < cic_range; i++) { pid = circuit_id * ISDN_CIRCUIT_CIC + i; pPort = &isdn_rs.port_pond[pid]; if(pPort->enable != 0) { rel_B_chnl(pid); isdn_cpc_clear(pPort); } } } } int rest0_proc(u32 pid, IsdnRestart *restart) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_RESTART) { pPort->msg_cmd = 0; pPort->w_time = 0; //start t317 memcpy(restart, &isdn_rv_msg.msg_list.restart, sizeof(IsdnRestart)); trans_callref_sd_rest_req(pid, ISDN_RESTART_REQ); return GLOBAL_RESTART_STATE; } else if(pPort->g_pri_cmd == ISDN_M_RESTART_REQ) { pPort->g_pri_cmd = 0; pPort->timeout_fg = 0; pPort->w_time = 0; //start t316 isdn_send_msg(pid, MSG_RESTART); trans_callref_sd_rest_req(pid, ISDN_RESTART_REQ); return GLOBAL_RESTART_REQ_STATE; } return -1; } int rest1_proc(u32 pid) { static int rest_resp_on = 0; //?? static int rest_ack_on = 0; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->msg_cmd == MSG_REST_ACK) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t316 if(rest_resp_on) { rest_resp_on = 0; restart_clear(pid); return GLOBAL_NULL_STATE; } else rest_ack_on = 1; } else if(pPort->g_pri_cmd == ISDN_RESTART_CNF) { pPort->g_pri_cmd = 0; if(rest_ack_on) { rest_ack_on = 0; restart_clear(pid); return GLOBAL_NULL_STATE; } else rest_resp_on = 1; } else if(pPort->msg_cmd == MSG_RESTART) { pPort->msg_cmd = 0; trans_callref_sd_rest_req(pid, ISDN_RESTART_REQ); return GLOBAL_RESTART_STATE; } return -1; } int rest2_proc(u32 pid, IsdnRestart restart) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; if(pPort->g_pri_cmd == ISDN_RESTART_CNF) { pPort->g_pri_cmd = 0; pPort->w_time = 0; memcpy(&isdn_sd_msg.msg_list.restAck, (IsdnRestAck *)&restart, sizeof(IsdnRestAck)); isdn_send_msg(pid, MSG_REST_ACK); restart_clear(pid); return GLOBAL_NULL_STATE; } else if(pPort->msg_cmd == MSG_RESTART) { pPort->msg_cmd = 0; trans_callref_sd_rest_req(pid, ISDN_RESTART_REQ); return GLOBAL_RESTART_STATE; } return -1; } void isdn_restart_ctrl(u32 pid) { int num = 0; static IsdnRestart restart; ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]); const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(pid / ISDN_CIRCUIT_CIC); if(circuit_ptr == NULL) return; switch(pPort->cic_state.call_state) { case CALLOUT_FLAG: case CALLIN_FLAG: case GLOBAL_NULL_STATE: switch(rest0_proc(pid, &restart)) { case GLOBAL_RESTART_REQ_STATE: pPort->cic_state.call_state = GLOBAL_RESTART_REQ_STATE; break; case GLOBAL_RESTART_STATE: pPort->cic_state.call_state = GLOBAL_RESTART_STATE; break; default: break; } break; case GLOBAL_RESTART_REQ_STATE: switch(rest1_proc(pid)) { case GLOBAL_NULL_STATE: pPort->cic_state.call_state = GLOBAL_NULL_STATE; break; case GLOBAL_RESTART_STATE: pPort->cic_state.call_state = GLOBAL_RESTART_STATE; break; default: break; } break; case GLOBAL_RESTART_STATE: switch(rest2_proc(pid, restart)) { case GLOBAL_NULL_STATE: pPort->cic_state.call_state = GLOBAL_NULL_STATE; break; case GLOBAL_RESTART_STATE: pPort->cic_state.call_state = GLOBAL_RESTART_STATE; break; default: break; } break; default: break; } // printf("global state = 0x%02x\n",pPort->cic_state.call_state); if(pPort->g_pri_cmd == ISDN_RESTART_REQ) { pPort->g_pri_cmd = 0; if(pPort->cic_state.call_state == GLOBAL_RESTART_STATE) memcpy(&isdn_sd_msg.msg_list.restAck, &isdn_rv_msg.msg_list.restart, sizeof(IsdnRestart)); if((num = trans_callref_sd_rest_req(pid, ISDN_RESTART_CNF)) == circuit_ptr->attrib.cic_range) pPort->g_pri_cmd = ISDN_RESTART_CNF; // isdn_restart_ctrl(pid); } else if(pPort->g_pri_cmd != 0) { isdn_log_err(pid, "global g_pri_cmd = 0x%x\r\n", pPort->g_pri_cmd); pPort->g_pri_cmd = 0; } if(pPort->msg_cmd != 0) { isdn_log_err(pid, "global msg_cmd = 0x%x\r\n", pPort->msg_cmd); pPort->msg_cmd = 0; isdn_set_status(&isdn_sd_msg.msg_list.status, pPort->cic_state.call_state, CAUSE_INVALID_CR); //cause 81 isdn_send_msg(pid, MSG_STATUS); } } /************************************************************* Function: not_isdn_rel_st Description: Handling state is isdn release state or not Input: state:call state Return: ISDN_CM_OK:success ISDN_CM_FAILED:failed *************************************************************/ static int not_isdn_rel_st(u8 state) { if((state != NULL_STATE) && (state != DISC_REQ_STATE) && (state != DISC_IND_STATE) && (state != REL_REQ_STATE)) return ISDN_CM_OK; else return ISDN_CM_FAILED; } /************************************************************* Function: isdn_comm_ctrl Description: ISDN Protocol Common Control Input: pid:port id Return: state value:success *************************************************************/ u8 isdn_comm_ctrl(u32 pid) { u8 state, msg_cmd, pri_cmd, g_pri_cmd; ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]); const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(pid / ISDN_CIRCUIT_CIC); if(circuit_ptr == NULL) { isdn_log_err(pid, "isdn_comm_ctrl err! circuit_id %d can't find circuit_ptr!\r\n",pid/ISDN_CIRCUIT_CIC); return ISDN_CM_FAILED; } state = pPort->fsm_state.cpc_state; msg_cmd = pPort->msg_cmd; pri_cmd = pPort->primitive_cmd; g_pri_cmd = pPort->g_pri_cmd; if(not_isdn_rel_st(state)) { if(msg_cmd == MSG_DISC) { pPort->msg_cmd = 0; if(state != ACTIVE_STATE) { isdn_log_err(pid, "isdn_comm_ctrl err1!\r\n"); } return nd_proc(pid); } else if(pri_cmd == ISDN_DISCONNECT_REQ) { pPort->primitive_cmd = 0; if(state != ACTIVE_STATE) { isdn_log_err(pid, "isdn_comm_ctrl err2!\r\n"); } return nc_proc(pid); } else if(pri_cmd == ISDN_RELEASE_REQ) { pPort->primitive_cmd = 0; isdn_log_err(pid, "isdn_comm_ctrl err3, rv release req!\r\n"); return nr_proc(pid); } else if(msg_cmd == MSG_REL) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop all isdn_log_err(pid, "isdn_comm_ctrl err4, rv rel!\r\n"); isdn_event_handle(pid, ISDN_RELEASE_IND); rel_B_chnl(pid); // memcpy(&isdn_sd_msg.msg_list.relComp, &isdn_rv_msg.msg_list.rel, sizeof(IsdnRel)); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } } if((state != NULL_STATE) && (state != REL_REQ_STATE)) { if(msg_cmd == MSG_STATUS) { pPort->msg_cmd = 0; if(isdn_rv_msg.msg_list.status.call_stat.stat_val == 0) { isdn_log_err(pid, "isdn_comm_ctrl err5, rv status with null state!\r\n"); isdn_event_handle(pid, ISDN_STAT_IND); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } else if(isdn_rv_msg.msg_list.status.call_stat.stat_val != state) { isdn_log_err(pid, "isdn_comm_ctrl err5, rv status with no compatible state!\r\n"); if(state == ACTIVE_STATE) { isdn_send_msg(pid, MSG_STAT_ENQ); return ACTIVE_STATE; } isdn_set_cause(&isdn_rv_msg.msg_list.rel.cause, CAUSE_MSG_NOTCOMP_NOTIMPL); isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_MSG_NOTCOMP_NOTIMPL); isdn_event_handle(pid, ISDN_RELEASE_IND); rel_B_chnl(pid); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } //cs != 0 discard msg } else if(msg_cmd == MSG_REL_COMP) { pPort->msg_cmd = 0; isdn_log_err(pid, "isdn_comm_ctrl err6, rv rel comp!\r\n"); isdn_event_handle(pid, ISDN_RELEASE_IND); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); return NULL_STATE; } else if(msg_cmd == MSG_INFORMATION) { if(state != CALL_INIT_STATE && state != CALL_PRE_STATE && ((state != OVERLAP_RV_STATE && circuit_ptr->attrib.user_network_if == USER_SIDE) || (state != OVERLAP_SD_STATE && circuit_ptr->attrib.user_network_if == NETWORK_SIDE))) { pPort->msg_cmd = 0; isdn_event_handle(pid, ISDN_INFO_IND); } } else if(pri_cmd == ISDN_INFO_REQ) { if(state != CALL_INIT_STATE && state != CALL_PRE_STATE && ((state != OVERLAP_SD_STATE && circuit_ptr->attrib.user_network_if == USER_SIDE) || (state != OVERLAP_RV_STATE && circuit_ptr->attrib.user_network_if == NETWORK_SIDE))) { pPort->primitive_cmd = 0; isdn_send_msg(pid, MSG_INFORMATION); } } } if(msg_cmd == MSG_STAT_ENQ) { pPort->msg_cmd = 0; isdn_log_err(pid, "isdn_comm_ctrl err7, rv status enq!\r\n"); isdn_set_status(&isdn_sd_msg.msg_list.status, state, CAUSE_STAT_ENQ); isdn_send_msg(pid, MSG_STATUS); } if(g_pri_cmd == ISDN_RESTART_REQ) //restart_request { pPort->g_pri_cmd = 0; pPort->w_time = 0; isdn_log_err(pid, "isdn_comm_ctrl err8, rv restart req!\r\n"); isdn_set_cause(&isdn_rv_msg.msg_list.rel.cause, CAUSE_TEMP_FAIL); isdn_event_handle(pid, ISDN_RELEASE_IND); rel_cr(pid); pPort->g_pri_cmd = ISDN_RESTART_CNF; // isdn_event_handle(pid, ISDN_RESTART_CNF); //0411 return NULL_STATE; } /* DL Primitive -- Not Implemented Yet */ return state; } static void isdn_cpc_nt_proc(u32 pid) /* isdn状态机,包含n1 ...n25状态 */ { int state; ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]); state = isdn_comm_ctrl(pid); if(state == pPort->fsm_state.cpc_state) { switch(state) { case NULL_STATE: switch(n0_proc(pid)) { case CALL_INIT_STATE: state = CALL_INIT_STATE; break; case CALL_PRE_STATE: state = CALL_PRE_STATE; break; default: break; } break; case CALL_INIT_STATE: switch(n1_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; case OVERLAP_SD_STATE: state = OVERLAP_SD_STATE; break; case OUT_CALL_PROC_STATE: state = OUT_CALL_PROC_STATE; break; default: break; } break; case OVERLAP_SD_STATE: switch(n2_proc(pid)) { case OUT_CALL_PROC_STATE: state = OUT_CALL_PROC_STATE; break; case CALL_DV_STATE: state = CALL_DV_STATE; break; case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case OUT_CALL_PROC_STATE: switch(n3_proc(pid)) { case CALL_DV_STATE: state = CALL_DV_STATE; break; case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case CALL_DV_STATE: switch(n4_proc(pid)) { case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case CALL_PRE_STATE: switch(n6_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; case CALL_RV_STATE: state = CALL_RV_STATE; break; case CONN_REQ_STATE: state = CONN_REQ_STATE; break; case IN_CALL_PROC_STATE: state = IN_CALL_PROC_STATE; break; case OVERLAP_RV_STATE: state = OVERLAP_RV_STATE; break; default: break; } break; case CALL_RV_STATE: switch(n7_proc(pid)) { case CONN_REQ_STATE: state = CONN_REQ_STATE; break; default: break; } break; case CONN_REQ_STATE: switch(n8_proc(pid)) { case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case IN_CALL_PROC_STATE: switch(n9_proc(pid)) { case CALL_RV_STATE: state = CALL_RV_STATE; break; case CONN_REQ_STATE: state = CONN_REQ_STATE; break; default: break; } break; case ACTIVE_STATE: switch(n10_proc(pid)) { case -1: break; default: break; } break; case DISC_REQ_STATE: switch(n11_proc(pid)) { case REL_REQ_STATE: state = REL_REQ_STATE; break; default: break; } break; case DISC_IND_STATE: switch(n12_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; case REL_REQ_STATE: state = REL_REQ_STATE; break; default: break; } break; case REL_REQ_STATE: switch(n19_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; default: break; } break; case OVERLAP_RV_STATE: switch(n25_proc(pid)) { case CALL_RV_STATE: state = CALL_RV_STATE; break; case CONN_REQ_STATE: state = CONN_REQ_STATE; break; case IN_CALL_PROC_STATE: state = IN_CALL_PROC_STATE; break; default: break; } break; default: break; } } // printf("nt state = 0x%02x\n",state); pPort->fsm_state.cpc_state = state; isdn_cc_nt(pid); //unexpected message and send_isdn_msg(status) //u03-04 u03-05 u01-03 if(pPort->msg_cmd != 0) { pPort->msg_cmd = 0; isdn_log_err(pid, "isdn_cpc_nt_proc, receive msg=0x02%x, not handle!\r\n"); isdn_set_status(&isdn_sd_msg.msg_list.status, pPort->fsm_state.cpc_state, CAUSE_MSG_NOTCOMP); //cause 98 101 isdn_send_msg(pid, MSG_STATUS); } return; } static void isdn_cpc_lt_proc(u32 pid) { int state; ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]); state = isdn_comm_ctrl(pid); if(state == pPort->fsm_state.cpc_state) { switch(state) { case NULL_STATE: switch(u0_proc(pid)) { case CALL_INIT_STATE: state = CALL_INIT_STATE; break; case CALL_PRE_STATE: state = CALL_PRE_STATE; default: break; } break; case CALL_INIT_STATE: switch(u1_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; case OVERLAP_SD_STATE: state = OVERLAP_SD_STATE; break; case OUT_CALL_PROC_STATE: state = OUT_CALL_PROC_STATE; break; case CALL_DV_STATE: state = CALL_DV_STATE; break; case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case OVERLAP_SD_STATE: switch(u2_proc(pid)) { case OUT_CALL_PROC_STATE: state = OUT_CALL_PROC_STATE; break; case CALL_DV_STATE: state = CALL_DV_STATE; break; case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case OUT_CALL_PROC_STATE: switch(u3_proc(pid)) { case CALL_DV_STATE: state = CALL_DV_STATE; break; case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case CALL_DV_STATE: switch(u4_proc(pid)) { case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case CALL_PRE_STATE: switch(u6_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; case CALL_RV_STATE: state = CALL_RV_STATE; break; case CONN_REQ_STATE: state = CONN_REQ_STATE; break; case IN_CALL_PROC_STATE: state = IN_CALL_PROC_STATE; break; case OVERLAP_RV_STATE: state = OVERLAP_RV_STATE; break; default: break; } break; case CALL_RV_STATE: switch(u7_proc(pid)) { case CONN_REQ_STATE: state = CONN_REQ_STATE; break; default: break; } break; case CONN_REQ_STATE: switch(u8_proc(pid)) { case ACTIVE_STATE: state = ACTIVE_STATE; break; default: break; } break; case IN_CALL_PROC_STATE: switch(u9_proc(pid)) { case CALL_RV_STATE: state = CALL_RV_STATE; break; case CONN_REQ_STATE: state = CONN_REQ_STATE; break; default: break; } break; case ACTIVE_STATE: switch(u10_proc(pid)) { case -1: break; default: break; } break; case DISC_REQ_STATE: switch(u11_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; case REL_REQ_STATE: state = REL_REQ_STATE; break; default: break; } break; case DISC_IND_STATE: switch(u12_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; case REL_REQ_STATE: state = REL_REQ_STATE; break; default: break; } break; case REL_REQ_STATE: switch(u19_proc(pid)) { case NULL_STATE: state = NULL_STATE; break; default: break; } break; case OVERLAP_RV_STATE: switch(u25_proc(pid)) { case CALL_RV_STATE: state = CALL_RV_STATE; break; case CONN_REQ_STATE: state = CONN_REQ_STATE; break; case IN_CALL_PROC_STATE: state = IN_CALL_PROC_STATE; break; default: break; } break; default: break; } } // printf("lt state = 0x%02x\n",state); pPort->fsm_state.cpc_state = state; isdn_cc_lt(pid); //unexpected message and send_isdn_msg(status) //u03-04 u01-03 if(pPort->msg_cmd != 0) { pPort->msg_cmd = 0; isdn_log_err(pid, "isdn_cpc_lt_proc, receive msg=0x02%x, not handle!\r\n"); isdn_set_status(&isdn_sd_msg.msg_list.status, pPort->fsm_state.cpc_state, CAUSE_MSG_NOTCOMP); //cause 98 101 isdn_send_msg(pid, MSG_STATUS); } return; } void isdn_cpc_proc(u32 pid) { int circuit_id = pid / ISDN_CIRCUIT_CIC; const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) return; if(circuit_ptr->attrib.user_network_if) isdn_cpc_lt_proc(pid); else isdn_cpc_nt_proc(pid); } static int isdn_cc_nt(u32 pid) { ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]); switch(pPort->fsm_state.cpc_state) { case CONN_REQ_STATE: if(pPort->primitive_cmd == ISDN_SETUP_CNF) //msc does not provide ISDN_SETUP_COMP_REQ to isdn { pPort->primitive_cmd = ISDN_SETUP_COMP_REQ; isdn_cpc_nt_proc(pid); } break; case DISC_REQ_STATE: break; default: break; } if(pPort->primitive_cmd != 0) { pPort->primitive_cmd = 0; isdn_log_err(pid, "isdn_cc_nt, primitive err!\r\n"); return ISDN_CM_FAILED; } return ISDN_CM_OK; } static int isdn_cc_lt(u32 pid) { ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]); switch(pPort->fsm_state.cpc_state) { case DISC_IND_STATE: break; default: break; } if(pPort->primitive_cmd != 0) { pPort->primitive_cmd = 0; isdn_log_err(pid, "isdn_cc_lt, primitive err!\r\n"); return ISDN_CM_FAILED; } return ISDN_CM_OK; } static void isdn_cpc_nt_timer(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; switch(pPort->fsm_state.cpc_state) { case OVERLAP_SD_STATE: // if((++(pPort->w_time)) % (isdn_timer_var.t302) == 0) // { // pPort->w_time = 0; // isdn_log_err(pid, "[timeout]: NT OVERLAP SD STATE\r\n"); // isdn_event_handle(pid, ISDN_TIMEOUT_IND); // } break; case CALL_PRE_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t303) == 0) { pPort->w_time = 0; if(pPort->timeout_fg == 0) { pPort->timeout_fg = 1; isdn_log_err(pid, "[timeout]:t303 NT CALL PRE STATE first timeout, resend SETUP\r\n"); isdn_send_msg(pid, MSG_SETUP); } else { isdn_log_err(pid, "[timeout]:t303 NT CALL PRE STATE second timeout, clear call!\r\n"); isdn_set_cause(&isdn_rv_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY); isdn_event_handle(pid, ISDN_RELEASE_IND); rel_B_chnl(pid); isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_TIMER_EXPIRY); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); } } break; case CALL_RV_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t301) == 0) { pPort->w_time = 0; isdn_log_err(pid, "[timeout]:t301 NT CALL RV STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); } break; case IN_CALL_PROC_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t310) == 0) { pPort->w_time = 0; isdn_log_err(pid, "[timeout]:t310 NT IN CALL PROC STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); } break; case DISC_IND_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t305) == 0) { isdn_log_err(pid, "[timeout]:t305 NT DISC IND STATE\r\n"); isdn_set_cause(&isdn_sd_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY); nr_proc(pid); pPort->fsm_state.cpc_state = REL_REQ_STATE; } break; case REL_REQ_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t308) == 0) { pPort->w_time = 0; if(pPort->timeout_fg == 0) { pPort->timeout_fg = 1; isdn_log_err(pid, "[timeout]:t308 NT REL REQ STATE first timeout, resend REL\r\n"); isdn_set_cause(&isdn_sd_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY); isdn_send_msg(pid, MSG_REL); } else { isdn_log_err(pid, "[timeout]:t308 NT REL REQ STATE\r\n"); isdn_set_cause(&isdn_rv_msg.msg_list.relComp.cause, CAUSE_TIMER_EXPIRY); isdn_event_handle(pid, ISDN_RELEASE_CNF); //error rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); } } break; case OVERLAP_RV_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t304) == 0) { pPort->w_time = 0; isdn_log_err(pid, "[timeout]:t304 NT OVERLAP RV STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); } break; default: break; } return; } static void isdn_cpc_lt_timer(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; switch(pPort->fsm_state.cpc_state) { case CALL_INIT_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t303) == 0) { pPort->w_time = 0; if(pPort->timeout_fg == 0) { pPort->timeout_fg = 1; isdn_log_err(pid, "[timeout]:t303 LT CALL INIT STATE, resend SETUP\r\n"); isdn_send_msg(pid, MSG_SETUP); } else { isdn_log_err(pid, "[timeout]:t303 LT CALL INIT STATE, second timeout, clear call!\r\n"); isdn_set_cause(&isdn_rv_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY); isdn_event_handle(pid, ISDN_RELEASE_IND); rel_B_chnl(pid); isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_TIMER_EXPIRY); isdn_send_msg(pid, MSG_REL_COMP); rel_cr(pid); isdn_cpc_clear(pPort); } } break; case OVERLAP_SD_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t304) == 0) { pPort->w_time = 0; //stop t304 and start t305 isdn_log_err(pid, "[timeout]:t304 LT OVERLAP SD STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); } break; case OUT_CALL_PROC_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t310) == 0) { pPort->w_time = 0; //stop t310 and start t305 isdn_log_err(pid, "[timeout]:t310 LT OUT CALL PROC STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); } break; case CALL_DV_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t301) == 0) { pPort->w_time = 0; isdn_log_err(pid, "[timeout]:t301 LT CALL DV STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); } break; case CONN_REQ_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t313) == 0) { pPort->w_time = 0; //stop t313 and start t305 isdn_log_err(pid, "[timeout]:t313 LT CONN REQ STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); } break; case DISC_REQ_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t305) == 0) { isdn_log_err(pid, "[timeout]:t305 LT DISC REQ STATE\r\n"); isdn_set_cause(&isdn_sd_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY); nr_proc(pid); pPort->fsm_state.cpc_state = REL_REQ_STATE; } break; case REL_REQ_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t308) == 0) { pPort->w_time = 0; if(pPort->timeout_fg == 0) { pPort->timeout_fg = 1; isdn_log_err(pid, "[timeout]:t308 LT REL REQ STATE, resend REL\r\n"); isdn_set_cause(&isdn_sd_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY); isdn_send_msg(pid, MSG_REL); } else { isdn_log_err(pid, "[timeout]:t308 LT REL REQ STATE\r\n"); isdn_set_cause(&isdn_rv_msg.msg_list.relComp.cause, CAUSE_TIMER_EXPIRY); isdn_event_handle(pid, ISDN_RELEASE_CNF); //error rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); } } break; case OVERLAP_RV_STATE: // if((++(pPort->w_time)) % (isdn_timer_var.t302) == 0) // { // pPort->w_time = 0; // isdn_log_err(pid, "[timeout]:t302 LT OVERLAP RV STATE\r\n"); // isdn_event_handle(pid, ISDN_TIMEOUT_IND); // } break; default: break; } return; } void isdn_cpc_timer(u32 pid) { int circuit_id = pid / ISDN_CIRCUIT_CIC; const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) return; if(!(isdn_rs.port_pond[pid].timer_flag & CALLIN_FLAG) && !(isdn_rs.port_pond[pid].timer_flag & CALLOUT_FLAG)) return; if(circuit_ptr->attrib.user_network_if) isdn_cpc_lt_timer(pid); else isdn_cpc_nt_timer(pid); } void isdn_restart_timer(u32 pid) { int circuit_id, i, link_id, cic_range; const pal_circuit_struct *circuit_ptr = NULL; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; circuit_id = pid / ISDN_CIRCUIT_CIC; circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) return; link_id = circuit_ptr->attrib.link_id; cic_range = circuit_ptr->attrib.cic_range; if(cic_range == 24) //T1 cic_range++; switch(pPort->cic_state.call_state) { case GLOBAL_RESTART_REQ_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t316) == 0) { pPort->w_time = 0; if(pPort->timeout_fg == 2) { if(isdn_rs.link_pond[link_id].restart_clas == 0) { pid = find_port_by_cic(pPort->cic_val, circuit_id); isdn_log_err(pid, "[timeout]:t316 GLOBAL RESTART REQ STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); } else { for(i = 1; i < cic_range; i++) { pid = circuit_id * ISDN_CIRCUIT_CIC + i; pPort = &isdn_rs.port_pond[pid]; if(pPort->cic_val != 0) { isdn_log_err(pid, "[timeout]:t316 GLOBAL RESTART REQ STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); } } } } else { pPort->timeout_fg++; isdn_log_err(pid, "[timeout]:t316 GLOBAL RESTART REQ STATE, resend RESTART\r\n"); isdn_send_msg(pid, MSG_RESTART); } } break; case GLOBAL_RESTART_STATE: if((++(pPort->w_time)) % (isdn_timer_var.t317) == 0) { pPort->w_time = 0; if(isdn_rs.link_pond[link_id].restart_clas == 0) { pid = find_port_by_cic(pPort->cic_val, circuit_id); isdn_log_err(pid, "[timeout]:t317 GLOBAL RESTART STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); } else { for(i = 1; i < cic_range; i++) { pid = circuit_id * ISDN_CIRCUIT_CIC + i; pPort = &isdn_rs.port_pond[pid]; if(pPort->cic_val != 0) { isdn_log_err(pid, "[timeout]:t317 GLOBAL RESTART STATE\r\n"); isdn_event_handle(pid, ISDN_TIMEOUT_IND); rel_B_chnl(pid); rel_cr(pid); isdn_cpc_clear(pPort); } } } } break; default: break; } } int isdn_event_handle(u32 pid, u8 primitive) /* 处理msc上层的状态机 */ { int offset, circuit_id; Pst pst; ISDN_EventHandle_struct *event_handle = NULL; const pal_circuit_struct *circuit_ptr = NULL; const pal_cg_struct *cg_ptr = NULL; pst.sp_proc_id = pid; pst.su_proc_id = isdn_rs.port_pond[pid].su_proc_id; circuit_id = pid / ISDN_CIRCUIT_CIC; offset = pid % ISDN_CIRCUIT_CIC; circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) return ISDN_CM_FAILED; if(circuit_ptr->attrib.cic_range == 32) pst.cic = circuit_ptr->attrib.head_cic + offset; else pst.cic = circuit_ptr->attrib.head_cic + offset - 1; pst.cg_id = circuit_ptr->cg_id; cg_ptr = pal_cg_ptr(pst.cg_id); if(cg_ptr == NULL) return ISDN_CM_FAILED; if(cg_ptr->attrib.protocol != PROTO_ISDN) return ISDN_CM_FAILED; pst.tg_id = cg_ptr->attrib.tg_id; event_handle = (ISDN_EventHandle_struct *)pal_get_handler(pst.cg_id); if(event_handle == NULL) return ISDN_CM_FAILED; switch(primitive) { case ISDN_SETUP_IND: if(event_handle->h_isdn_setup_ind == NULL) { isdn_log_err(pid,"Setup indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_setup_ind\r\n"); event_handle->h_isdn_setup_ind(&pst, &(isdn_rv_msg.msg_list.setup)); isdn_rs.port_pond[pid].su_proc_id = pst.su_proc_id; isdn_rs.port_pond[pid].trace_flag = pst.trace_flag; break; case ISDN_MORE_INFO_IND: if(event_handle->h_isdn_minfo_ind == NULL) { isdn_log_err(pid,"More information indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_minfo_ind\r\n"); event_handle->h_isdn_minfo_ind(&pst, &(isdn_rv_msg.msg_list.setupAck)); break; case ISDN_ALERT_IND: if(event_handle->h_isdn_alert_ind == NULL) { isdn_log_err(pid,"Alert indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_alert_ind\r\n"); event_handle->h_isdn_alert_ind(&pst, &(isdn_rv_msg.msg_list.alert)); break; case ISDN_SETUP_CNF: if(event_handle->h_isdn_setup_cnf == NULL) { isdn_log_err(pid,"Setup confirm handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_setup_cnf\r\n"); event_handle->h_isdn_setup_cnf(&pst, &(isdn_rv_msg.msg_list.conn)); break; case ISDN_RELEASE_IND: if(event_handle->h_isdn_rel_ind == NULL) { isdn_log_err(pid,"Release indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_rel_ind\r\n"); event_handle->h_isdn_rel_ind(&pst, &(isdn_rv_msg.msg_list.rel)); break; case ISDN_RELEASE_CNF: if(event_handle->h_isdn_rel_cnf == NULL) { isdn_log_err(pid,"Release confirm handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_rel_cnf\r\n"); event_handle->h_isdn_rel_cnf(&pst, &(isdn_rv_msg.msg_list.relComp)); break; case ISDN_STAT_IND: if(event_handle->h_isdn_stat_ind == NULL) { isdn_log_err(pid,"Status indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_stat_ind\r\n"); event_handle->h_isdn_stat_ind(&pst, &(isdn_rv_msg.msg_list.status)); break; case ISDN_RESTART_REQ: if(event_handle->h_isdn_restart_req == NULL) { isdn_log_err(pid,"Restart request handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_restart_req\r\n"); event_handle->h_isdn_restart_req(&pst, &(isdn_rv_msg.msg_list.restart)); break; case ISDN_RESTART_CNF: if(event_handle->h_isdn_rest_cnf == NULL) { isdn_log_err(pid,"Restart confirm handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_rest_cnf\r\n"); event_handle->h_isdn_rest_cnf(&pst, &(isdn_rv_msg.msg_list.restAck)); break; case ISDN_INFO_IND: if(event_handle->h_isdn_info_ind == NULL) { isdn_log_err(pid,"Information indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_info_ind\r\n"); event_handle->h_isdn_info_ind(&pst, &(isdn_rv_msg.msg_list.info)); break; case ISDN_PROG_IND: if(event_handle->h_isdn_prog_ind == NULL) { isdn_log_err(pid,"Progress indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_prog_ind\r\n"); event_handle->h_isdn_prog_ind(&pst, &(isdn_rv_msg.msg_list.prog)); break; case ISDN_NOTI_IND: if(event_handle->h_isdn_noti_ind == NULL) { isdn_log_err(pid,"Notify indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_noti_ind\r\n"); event_handle->h_isdn_noti_ind(&pst, &(isdn_rv_msg.msg_list.noti)); break; case ISDN_TIMEOUT_IND: if(event_handle->h_isdn_timeout_ind == NULL) { isdn_log_err(pid,"Timeout indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_timeout_ind\r\n"); event_handle->h_isdn_timeout_ind(&pst); break; case ISDN_REATTEMPT_IND: if(event_handle->h_isdn_reattempt_ind == NULL) { isdn_log_err(pid,"Reattempt indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_reattempt_ind\r\n"); event_handle->h_isdn_reattempt_ind(&pst); break; case ISDN_PROC_IND: //msc does not handle /* if(event_handle->h_isdn_proc_ind == NULL) { isdn_log_err(pid,"Call proceeding indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_proc_ind\r\n"); event_handle->h_isdn_proc_ind(&pst, &(isdn_rv_msg.msg_list.callProc)); */ break; case ISDN_SETUP_COMP_IND: break; case ISDN_DISCONNECT_IND: //msc does not handle if(event_handle->h_isdn_disc_ind == NULL) { isdn_log_err(pid,"Disconnect indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_disc_ind\r\n"); event_handle->h_isdn_disc_ind(&pst, &(isdn_rv_msg.msg_list.disc)); break; case ISDN_SERVICE_IND: if(event_handle->h_isdn_service_ind == NULL) { isdn_log_err(pid,"Service indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_service_ind\r\n"); event_handle->h_isdn_service_ind(&pst, &(isdn_rv_msg.msg_list.service)); isdn_rs.port_pond[pid].su_proc_id = pst.su_proc_id; isdn_rs.port_pond[pid].trace_flag = pst.trace_flag; break; case ISDN_SERVICE_CNF: if(event_handle->h_isdn_service_cnf == NULL) { isdn_log_err(pid,"Service confirm handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_service_cnf\r\n"); event_handle->h_isdn_service_cnf(&pst, &(isdn_rv_msg.msg_list.servAck)); break; case ISDN_SER_TIMEOUT_IND: if(event_handle->h_isdn_ser_timeout_ind == NULL) { isdn_log_err(pid,"Service timeout indication handle is not registered@%s\r\n", __FUNCTION__); return ISDN_CM_FAILED; } isdn_trace_func(pid,"APP => function trace: isdn_ser_timeout_ind\r\n"); event_handle->h_isdn_ser_timeout_ind(&pst); break; default: break; } return ISDN_CM_OK; } void stuff_encode_m(u32 pid, IsdnMsgStr *ptr, int type) { ChgStat chg_stat; ChnlId chnl_id; chg_stat.pres = 1; chg_stat.pref = 1; chg_stat.new_stat = isdn_rs.port_pond[pid].cic_state.maintenance_state; chnl_id.pres = 1; chnl_id.b3.int_id_pre = 1; chnl_id.b3.int_type = 1; chnl_id.b3.pref_excl = 1; chnl_id.b3.chnl_ind = 1; chnl_id.b3.info_chnl_sel = 1; chnl_id.b3.int_id = pid / ISDN_CIRCUIT_CIC; chnl_id.b3.has_chnl = 1; chnl_id.b3.code_stan = 0; chnl_id.b3.num_map = 0; chnl_id.b3.chnl_type = 3; chnl_id.b3.chnl_num = pid % ISDN_CIRCUIT_CIC; if(type == MSG_SERVICE) { memcpy(&ptr->msg_list.service.chg_stat, &chg_stat, sizeof(ChgStat)); memcpy(&ptr->msg_list.service.chnl_id, &chnl_id, sizeof(ChnlId)); } else if(type == MSG_SERVICE_ACK) { memcpy(&ptr->msg_list.servAck.chg_stat, &chg_stat, sizeof(ChgStat)); memcpy(&ptr->msg_list.servAck.chnl_id, &chnl_id, sizeof(ChnlId)); } } //ansi isdn maintenance D-channel and B-channel void service_dc_proc(u32 pid) { int circuit_id, link_id, cg_id, ds_0, ds_1; int far_status; const pal_circuit_struct *circuit_ptr = NULL; const pal_cg_struct *cg_ptr = NULL; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; circuit_id = pid / ISDN_CIRCUIT_CIC; circuit_ptr = pal_circuit_ptr(circuit_id); if(circuit_ptr == NULL) return; link_id = circuit_ptr->attrib.link_id; 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; far_status = isdn_rv_msg.msg_list.service.chg_stat.new_stat; if(cg_ptr->attrib.variant == VARIANT_ANSI) //ANSI { switch(pPort->fsm_state.m_state) { case SERVICE_IDLE: if(pPort->g_pri_cmd == ISDN_SERVICE_REQ) { pPort->g_pri_cmd = 0; isdn_rs.link_pond[link_id].dc_status = DS_WAIT; pPort->w_time = 0; //start t321 pPort->timer_flag |= DC_M_FLAG; pPort->cic_state.maintenance_state = IN_SERVICE; stuff_encode_m(pid, &isdn_sd_msg, MSG_SERVICE); isdn_send_maintenance_msg(pid, MSG_SERVICE); pPort->cic_state.maintenance_state = OUT_OF_SERVICE; pPort->fsm_state.m_state = WAIT_SERVICE_ACK; printf("service_dc_proc: wait service ack!\n"); } else if(pPort->msg_cmd == MSG_SERVICE) { pPort->msg_cmd = 0; pPort->callout_fg = 1; if(link_id == ds_0) { if((isdn_rs.link_pond[ds_1].dc_status != DS_IS) && (isdn_rs.link_pond[link_id].lk3_status == LK_IS) && (far_status == IN_SERVICE)) { isdn_rs.link_pond[link_id].dc_status = DS_IS; pPort->cic_state.maintenance_state = IN_SERVICE; stuff_encode_m(pid, &isdn_sd_msg, MSG_SERVICE_ACK); isdn_send_maintenance_msg(pid, MSG_SERVICE_ACK); pPort->fsm_state.m_state = SERVICE_IDLE; } } else if(link_id == ds_1) { if(((isdn_rs.link_pond[ds_0].dc_status) == DS_OOS || (isdn_rs.link_pond[ds_0].dc_status == DS_STBY)) && (isdn_rs.link_pond[link_id].lk3_status == LK_IS) && (far_status == IN_SERVICE)) { isdn_rs.link_pond[link_id].dc_status = DS_IS; pPort->cic_state.maintenance_state = IN_SERVICE; stuff_encode_m(pid, &isdn_sd_msg, MSG_SERVICE_ACK); isdn_send_maintenance_msg(pid, MSG_SERVICE_ACK); pPort->fsm_state.m_state = SERVICE_IDLE; } } printf("service_dc_proc: receive service!\n"); } if(pPort->msg_cmd == MSG_SERVICE_ACK) //timeout t321 TODO { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t321 if(far_status == IN_SERVICE) { isdn_rs.link_pond[link_id].dc_status = DS_IS; pPort->cic_state.maintenance_state = IN_SERVICE; } else { isdn_rs.link_pond[link_id].dc_status = DS_STBY; pPort->cic_state.maintenance_state = OUT_OF_SERVICE; } pPort->fsm_state.m_state = SERVICE_IDLE; printf("service_dc_proc: receive service ack in service idle!\n"); } break; case WAIT_SERVICE_ACK: if(pPort->msg_cmd == MSG_SERVICE_ACK) { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t321 if(far_status == IN_SERVICE) { isdn_rs.link_pond[link_id].dc_status = DS_IS; pPort->cic_state.maintenance_state = IN_SERVICE; } else { isdn_rs.link_pond[link_id].dc_status = DS_STBY; pPort->cic_state.maintenance_state = OUT_OF_SERVICE; } pPort->fsm_state.m_state = SERVICE_IDLE; printf("service_dc_proc: receive service ack!and enter service idle state\n"); } else if(pPort->msg_cmd == MSG_SERVICE) //collision { if(!cg_ptr->attrib.priority) { pPort->w_time = 0; //stop t321 pPort->fsm_state.m_state = SERVICE_IDLE; service_dc_proc(pid); printf("service_dc_proc: collision, and renew the state with service idle to receive msg!\n"); } else { pPort->msg_cmd = 0; isdn_log_err(pid, "service_dc_proc: discard receive msg!\r\n"); return; } } break; case RSP_SERVICE: break; default: break; } } else //ITU { if(pPort->g_pri_cmd == ISDN_SERVICE_REQ) { pPort->g_pri_cmd = 0; isdn_rs.link_pond[link_id].dc_status = DS_IS; } else if(isdn_rs.link_pond[link_id].lk3_status == LK_IS && isdn_rs.link_pond[link_id].dc_status != DS_IS) { isdn_rs.link_pond[link_id].dc_status = DS_STBY; } } // if(isdn_rs.link_pond[link_id].dc_status == DS_OOS && isdn_rs.link_pond[link_id].lk3_status == LK_IS) // isdn_rs.link_pond[link_id].dc_status = DS_STBY; if(isdn_rs.link_pond[ds_0].dc_status == DS_IS && isdn_rs.link_pond[ds_1].dc_status == DS_IS) isdn_rs.link_pond[ds_1].dc_status = DS_STBY; else if(isdn_rs.link_pond[ds_0].dc_status == DS_STBY && isdn_rs.link_pond[ds_1].dc_status == DS_STBY) isdn_rs.link_pond[ds_0].dc_status = DS_IS; else if(isdn_rs.link_pond[ds_0].dc_status == DS_OOS && isdn_rs.link_pond[ds_1].dc_status == DS_STBY) isdn_rs.link_pond[ds_1].dc_status = DS_IS; else if(isdn_rs.link_pond[ds_0].dc_status == DS_STBY && isdn_rs.link_pond[ds_1].dc_status == DS_OOS) isdn_rs.link_pond[ds_0].dc_status = DS_IS; else if(isdn_rs.link_pond[ds_0].dc_status == DS_OOS && isdn_rs.link_pond[ds_1].dc_status == DS_OOS) { isdn_rs.link_pond[ds_0].dc_status = DS_MOOS; isdn_rs.link_pond[ds_1].dc_status = DS_MOOS; } return; } void service_bc_proc(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; const pal_cg_struct *cg_ptr = NULL; const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(pid / ISDN_CIRCUIT_CIC); if(circuit_ptr == NULL) return; cg_ptr = pal_cg_ptr(circuit_ptr->cg_id); if(cg_ptr == NULL) return; if(cg_ptr->attrib.protocol != PROTO_ISDN) return; switch(pPort->fsm_state.m_state) { case SERVICE_IDLE: if(pPort->g_pri_cmd == ISDN_SERVICE_REQ) { pPort->g_pri_cmd = 0; if(isdn_sd_msg.msg_list.service.chg_stat.new_stat != IN_SERVICE) { pPort->primitive_cmd = ISDN_RELEASE_REQ; isdn_cpc_proc(pid); } pPort->w_time = 0; //start t3M1 pPort->timer_flag |= BC_M_FLAG; isdn_send_maintenance_msg(pid, MSG_SERVICE); pPort->cic_state.maintenance_state = isdn_sd_msg.msg_list.service.chg_stat.new_stat; pPort->fsm_state.m_state = WAIT_SERVICE_ACK; printf("service_bc_proc: wait service ack!\n"); } else if(pPort->msg_cmd == MSG_SERVICE) { pPort->msg_cmd = 0; pPort->callout_fg = 1; pPort->cic_state.maintenance_state = isdn_rv_msg.msg_list.service.chg_stat.new_stat; pPort->fsm_state.m_state = RSP_SERVICE; printf("service_bc_proc: receive service!\n"); isdn_event_handle(pid, ISDN_SERVICE_IND); //indicate } else if(pPort->msg_cmd == MSG_SERVICE_ACK) //timeout t3M1 { pPort->msg_cmd = 0; pPort->w_time = 0; //stop t3M1 pPort->cic_state.maintenance_state = isdn_rv_msg.msg_list.service.chg_stat.new_stat; isdn_event_handle(pid, ISDN_SERVICE_CNF); //confirm pPort->fsm_state.m_state = SERVICE_IDLE; printf("service_bc_proc: receive service ack in service idle!\n"); } break; case WAIT_SERVICE_ACK: if(pPort->msg_cmd == MSG_SERVICE_ACK) { pPort->msg_cmd = 0; isdn_event_handle(pid, ISDN_SERVICE_CNF); //confirm pPort->fsm_state.m_state = SERVICE_IDLE; printf("service_bc_proc: receive service ack!\n"); } if(pPort->msg_cmd == MSG_SERVICE) //接收service冲突 TODO { if(!cg_ptr->attrib.priority) { pPort->w_time = 0; pPort->cic_state.maintenance_state = ((pPort->cic_state.maintenance_state & 0x1) | (pPort->cic_state.maintenance_state >> 1)) ^ 0x1; //run back initial pPort->fsm_state.m_state = SERVICE_IDLE; isdn_event_handle(pid, ISDN_REATTEMPT_IND); //indicate service_bc_proc(pid); printf("service_bc_proc: collision, and renew the state with service idle to receive msg!\n"); } else { pPort->msg_cmd = 0; isdn_log_err(pid, "service_dc_proc: discard receive msg!\r\n"); return; } } break; case RSP_SERVICE: if(pPort->g_pri_cmd == ISDN_SERVICE_RSP) { pPort->g_pri_cmd = 0; pPort->fsm_state.m_state = SERVICE_IDLE; pPort->cic_state.maintenance_state = isdn_sd_msg.msg_list.servAck.chg_stat.new_stat; isdn_send_maintenance_msg(pid, MSG_SERVICE_ACK); printf("service_bc_proc: response service!\n"); } break; default: break; } } void service_dc_timer(u32 pid) { int link_id; ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(pid / ISDN_CIRCUIT_CIC); if(circuit_ptr == NULL) return; link_id = circuit_ptr->attrib.link_id; switch(pPort->fsm_state.m_state) { case WAIT_SERVICE_ACK: if((++(pPort->w_time)) % (isdn_timer_var.t321) == 0) { pPort->w_time = 0; //stop t3M1 pPort->fsm_state.m_state = SERVICE_IDLE; pPort->cic_state.maintenance_state = OUT_OF_SERVICE; isdn_rs.link_pond[link_id].dc_status = DS_OOS; isdn_log_err(pid, "service_dc_timer: t321 timeout!\r\n"); } break; default: break; } } void service_bc_timer(u32 pid) { ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid]; switch(pPort->fsm_state.m_state) { case WAIT_SERVICE_ACK: if((++(pPort->w_time)) % (isdn_timer_var.t3M1) == 0) { pPort->w_time = 0; //stop t3M1 isdn_event_handle(pid, ISDN_SER_TIMEOUT_IND); pPort->fsm_state.m_state = SERVICE_IDLE; pPort->cic_state.maintenance_state = OUT_OF_SERVICE; isdn_log_err(pid, "service_bc_timer: t3M1 timeout!\r\n"); } break; default: break; } } void maintenance_timer(u32 pid) { if(isdn_rs.port_pond[pid].timer_flag & BC_M_FLAG) service_bc_timer(pid); if(isdn_rs.port_pond[pid].timer_flag & DC_M_FLAG) service_dc_timer(pid); }