From 7f55b600e01911749b8ab3aa529827165842988e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 21 Oct 2010 18:00:03 +0000 Subject: [PATCH] Fixes CC agents not automatically clearing if T309 clears the original call. Incoming calls with CC enabled will not automatically clear the CC offer record when the call is aborted by T309 processing. All CC agent FSM's have this problem (PTMP, PTP, and Q.SIG). To reproduce: 1) Place incoming call to Asterisk/libpri 2) Either before or after the call is answered, bring the ISDN link down. 3) T309 processing, T309 timeout, or TEI removal will leave the CC agent FSM in the CC available state. The problem is indicated by the "cc report status" CLI command showing a status of CC offered to caller but it will never timeout. The FSM's can be manually cleared by using the "cc cancel all" or "cc cancel core" CLI commands. JIRA LIBPRI-46 JIRA SWP-2241 git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@2079 2fbb986a-6c06-0410-b554-c9c1f0a7f128 --- doc/cc_ptmp_agent.fsm | 10 ++++++++++ doc/cc_ptmp_agent_flattened.fsm | 11 +++++++++++ doc/cc_ptp_agent.fsm | 8 ++++++++ doc/cc_ptp_agent_flattened.fsm | 9 +++++++++ doc/cc_qsig_agent.fsm | 4 ++++ doc/cc_qsig_agent_flattened.fsm | 4 ++++ pri_cc.c | 27 +++++++++++++++++++++++++++ pri_internal.h | 2 ++ q931.c | 21 +++++++++++++++------ 9 files changed, 90 insertions(+), 6 deletions(-) diff --git a/doc/cc_ptmp_agent.fsm b/doc/cc_ptmp_agent.fsm index d298596..e28fd3c 100644 --- a/doc/cc_ptmp_agent.fsm +++ b/doc/cc_ptmp_agent.fsm @@ -25,7 +25,13 @@ FSM CC_PTMP_Agent Action Send_CC_Available(Q931_DISCONNECT); Next_State CC_STATE_AVAILABLE; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Release_LinkID; + Action Pass_Up_CC_Cancel; + Next_State CC_STATE_IDLE; + } Stimulus CC_EVENT_CANCEL { + Action Release_LinkID; Next_State CC_STATE_IDLE; } } @@ -45,6 +51,10 @@ FSM CC_PTMP_Agent Action Pass_Up_CC_Request; Next_State CC_STATE_REQUESTED; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Stop_T_RETENTION; + Action Start_T_RETENTION; + } Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Action Send_EraseCallLinkageID; Action Release_LinkID; diff --git a/doc/cc_ptmp_agent_flattened.fsm b/doc/cc_ptmp_agent_flattened.fsm index e454e3d..0b4f3e2 100644 --- a/doc/cc_ptmp_agent_flattened.fsm +++ b/doc/cc_ptmp_agent_flattened.fsm @@ -20,7 +20,14 @@ FSM CC_PTMP_Agent Action Send_CC_Available(Q931_DISCONNECT); Next_State CC_STATE_AVAILABLE; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Release_LinkID; + Action Pass_Up_CC_Cancel; + Action Set_Selfdestruct; + Next_State CC_STATE_IDLE; + } Stimulus CC_EVENT_CANCEL { + Action Release_LinkID; Action Set_Selfdestruct; Next_State CC_STATE_IDLE; } @@ -39,6 +46,10 @@ FSM CC_PTMP_Agent Action Stop_T_RETENTION; Next_State CC_STATE_REQUESTED; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Stop_T_RETENTION; + Action Start_T_RETENTION; + } Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Action Send_EraseCallLinkageID; Action Release_LinkID; diff --git a/doc/cc_ptp_agent.fsm b/doc/cc_ptp_agent.fsm index db02205..3eb8a13 100644 --- a/doc/cc_ptp_agent.fsm +++ b/doc/cc_ptp_agent.fsm @@ -25,6 +25,10 @@ FSM CC_PTP_Agent Action Send_CC_Available(Q931_DISCONNECT); Next_State CC_STATE_AVAILABLE; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Pass_Up_CC_Cancel; + Next_State CC_STATE_IDLE; + } Stimulus CC_EVENT_CANCEL { Next_State CC_STATE_IDLE; } @@ -53,6 +57,10 @@ FSM CC_PTP_Agent Action Stop_T_RETENTION; Next_State CC_STATE_REQUESTED; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Stop_T_RETENTION; + Action Start_T_RETENTION; + } Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Action Pass_Up_CC_Cancel; Next_State CC_STATE_IDLE; diff --git a/doc/cc_ptp_agent_flattened.fsm b/doc/cc_ptp_agent_flattened.fsm index cc48835..5567b5b 100644 --- a/doc/cc_ptp_agent_flattened.fsm +++ b/doc/cc_ptp_agent_flattened.fsm @@ -20,6 +20,11 @@ FSM CC_PTP_Agent Action Send_CC_Available(Q931_DISCONNECT); Next_State CC_STATE_AVAILABLE; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Pass_Up_CC_Cancel; + Action Set_Selfdestruct; + Next_State CC_STATE_IDLE; + } Stimulus CC_EVENT_CANCEL { Action Set_Selfdestruct; Next_State CC_STATE_IDLE; @@ -46,6 +51,10 @@ FSM CC_PTP_Agent Action Stop_T_RETENTION; Next_State CC_STATE_REQUESTED; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Stop_T_RETENTION; + Action Start_T_RETENTION; + } Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Action Pass_Up_CC_Cancel; Action Stop_T_RETENTION; diff --git a/doc/cc_qsig_agent.fsm b/doc/cc_qsig_agent.fsm index f93f8b6..2b2fd79 100644 --- a/doc/cc_qsig_agent.fsm +++ b/doc/cc_qsig_agent.fsm @@ -41,6 +41,10 @@ FSM CC_QSIG_Agent Action Send_Call_Proceeding; Next_State CC_STATE_REQUESTED; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Stop_T_RETENTION; + Action Start_T_RETENTION; + } Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Action Pass_Up_CC_Cancel; Next_State CC_STATE_IDLE; diff --git a/doc/cc_qsig_agent_flattened.fsm b/doc/cc_qsig_agent_flattened.fsm index ceafcd7..e8a5cc0 100644 --- a/doc/cc_qsig_agent_flattened.fsm +++ b/doc/cc_qsig_agent_flattened.fsm @@ -34,6 +34,10 @@ FSM CC_QSIG_Agent Action Stop_T_RETENTION; Next_State CC_STATE_REQUESTED; } + Stimulus CC_EVENT_INTERNAL_CLEARING { + Action Stop_T_RETENTION; + Action Start_T_RETENTION; + } Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Action Pass_Up_CC_Cancel; Action Stop_T_RETENTION; diff --git a/pri_cc.c b/pri_cc.c index b68127b..c939617 100644 --- a/pri_cc.c +++ b/pri_cc.c @@ -2613,6 +2613,9 @@ static const char *pri_cc_fsm_event_str(enum CC_EVENTS event) case CC_EVENT_CANCEL: str = "CC_EVENT_CANCEL"; break; + case CC_EVENT_INTERNAL_CLEARING: + str = "CC_EVENT_INTERNAL_CLEARING"; + break; case CC_EVENT_SIGNALING_GONE: str = "CC_EVENT_SIGNALING_GONE"; break; @@ -4351,7 +4354,14 @@ static void pri_cc_fsm_ptmp_agent_pend_avail(struct pri *ctrl, q931_call *call, pri_cc_act_send_cc_available(ctrl, cc_record, call, Q931_DISCONNECT); cc_record->state = CC_STATE_AVAILABLE; break; + case CC_EVENT_INTERNAL_CLEARING: + pri_cc_act_release_link_id(ctrl, cc_record); + pri_cc_act_pass_up_cc_cancel(ctrl, cc_record); + pri_cc_act_set_self_destruct(ctrl, cc_record); + cc_record->state = CC_STATE_IDLE; + break; case CC_EVENT_CANCEL: + pri_cc_act_release_link_id(ctrl, cc_record); pri_cc_act_set_self_destruct(ctrl, cc_record); cc_record->state = CC_STATE_IDLE; break; @@ -4384,6 +4394,10 @@ static void pri_cc_fsm_ptmp_agent_avail(struct pri *ctrl, q931_call *call, struc pri_cc_act_stop_t_retention(ctrl, cc_record); cc_record->state = CC_STATE_REQUESTED; break; + case CC_EVENT_INTERNAL_CLEARING: + pri_cc_act_stop_t_retention(ctrl, cc_record); + pri_cc_act_start_t_retention(ctrl, cc_record); + break; case CC_EVENT_TIMEOUT_T_RETENTION: pri_cc_act_send_erase_call_linkage_id(ctrl, cc_record); pri_cc_act_release_link_id(ctrl, cc_record); @@ -5275,6 +5289,11 @@ static void pri_cc_fsm_ptp_agent_pend_avail(struct pri *ctrl, q931_call *call, s pri_cc_act_send_cc_available(ctrl, cc_record, call, Q931_DISCONNECT); cc_record->state = CC_STATE_AVAILABLE; break; + case CC_EVENT_INTERNAL_CLEARING: + pri_cc_act_pass_up_cc_cancel(ctrl, cc_record); + pri_cc_act_set_self_destruct(ctrl, cc_record); + cc_record->state = CC_STATE_IDLE; + break; case CC_EVENT_CANCEL: pri_cc_act_set_self_destruct(ctrl, cc_record); cc_record->state = CC_STATE_IDLE; @@ -5315,6 +5334,10 @@ static void pri_cc_fsm_ptp_agent_avail(struct pri *ctrl, q931_call *call, struct pri_cc_act_stop_t_retention(ctrl, cc_record); cc_record->state = CC_STATE_REQUESTED; break; + case CC_EVENT_INTERNAL_CLEARING: + pri_cc_act_stop_t_retention(ctrl, cc_record); + pri_cc_act_start_t_retention(ctrl, cc_record); + break; case CC_EVENT_TIMEOUT_T_RETENTION: pri_cc_act_pass_up_cc_cancel(ctrl, cc_record); pri_cc_act_stop_t_retention(ctrl, cc_record); @@ -5914,6 +5937,10 @@ static void pri_cc_fsm_qsig_agent_avail(struct pri *ctrl, q931_call *call, struc pri_cc_act_stop_t_retention(ctrl, cc_record); cc_record->state = CC_STATE_REQUESTED; break; + case CC_EVENT_INTERNAL_CLEARING: + pri_cc_act_stop_t_retention(ctrl, cc_record); + pri_cc_act_start_t_retention(ctrl, cc_record); + break; case CC_EVENT_TIMEOUT_T_RETENTION: pri_cc_act_pass_up_cc_cancel(ctrl, cc_record); pri_cc_act_stop_t_retention(ctrl, cc_record); diff --git a/pri_internal.h b/pri_internal.h index 8235092..bf0ffb7 100644 --- a/pri_internal.h +++ b/pri_internal.h @@ -664,6 +664,8 @@ enum CC_EVENTS { CC_EVENT_LINK_CANCEL, /*! Tear down CC request from upper layer. */ CC_EVENT_CANCEL, + /*! Abnormal clearing of original call. (T309 processing/T309 timeout/TEI removal) */ + CC_EVENT_INTERNAL_CLEARING, /*! Received message indicating tear down of CC signaling link completed. */ CC_EVENT_SIGNALING_GONE, /*! Delayed hangup request for the signaling link to allow subcmd events to be passed up. */ diff --git a/q931.c b/q931.c index 764dfd8..8d06310 100644 --- a/q931.c +++ b/q931.c @@ -8472,22 +8472,31 @@ static int pri_internal_clear(void *data) pri_message(ctrl, "clearing, alive %d, hangupack %d\n", c->alive, c->sendhangupack); } - if (c->cc.record && c->cc.record->signaling == c) { - pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_SIGNALING_GONE); + if (c->cc.record) { + if (c->cc.record->signaling == c) { + pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_SIGNALING_GONE); + } else if (c->cc.record->original_call == c) { + pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_INTERNAL_CLEARING); + } } /* Free resources */ if (c->alive) { + c->alive = 0; ctrl->ev.e = PRI_EVENT_HANGUP; res = Q931_RES_HAVEEVENT; - c->alive = 0; } else if (c->sendhangupack) { - res = Q931_RES_HAVEEVENT; - ctrl->ev.e = PRI_EVENT_HANGUP_ACK; pri_hangup(ctrl, c, c->cause); + ctrl->ev.e = PRI_EVENT_HANGUP_ACK; + res = Q931_RES_HAVEEVENT; } else { - res = 0; pri_hangup(ctrl, c, c->cause); + if (ctrl->subcmds.counter_subcmd) { + q931_fill_facility_event(ctrl, ctrl->link.dummy_call); + res = Q931_RES_HAVEEVENT; + } else { + res = 0; + } } return res;