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
This commit is contained in:
Richard Mudgett 2010-10-21 18:00:03 +00:00
parent 5923df047d
commit 7f55b600e0
9 changed files with 90 additions and 6 deletions

View File

@ -25,7 +25,13 @@ FSM CC_PTMP_Agent
Action Send_CC_Available(Q931_DISCONNECT); Action Send_CC_Available(Q931_DISCONNECT);
Next_State CC_STATE_AVAILABLE; 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 { Stimulus CC_EVENT_CANCEL {
Action Release_LinkID;
Next_State CC_STATE_IDLE; Next_State CC_STATE_IDLE;
} }
} }
@ -45,6 +51,10 @@ FSM CC_PTMP_Agent
Action Pass_Up_CC_Request; Action Pass_Up_CC_Request;
Next_State CC_STATE_REQUESTED; Next_State CC_STATE_REQUESTED;
} }
Stimulus CC_EVENT_INTERNAL_CLEARING {
Action Stop_T_RETENTION;
Action Start_T_RETENTION;
}
Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Stimulus CC_EVENT_TIMEOUT_T_RETENTION {
Action Send_EraseCallLinkageID; Action Send_EraseCallLinkageID;
Action Release_LinkID; Action Release_LinkID;

View File

@ -20,7 +20,14 @@ FSM CC_PTMP_Agent
Action Send_CC_Available(Q931_DISCONNECT); Action Send_CC_Available(Q931_DISCONNECT);
Next_State CC_STATE_AVAILABLE; 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 { Stimulus CC_EVENT_CANCEL {
Action Release_LinkID;
Action Set_Selfdestruct; Action Set_Selfdestruct;
Next_State CC_STATE_IDLE; Next_State CC_STATE_IDLE;
} }
@ -39,6 +46,10 @@ FSM CC_PTMP_Agent
Action Stop_T_RETENTION; Action Stop_T_RETENTION;
Next_State CC_STATE_REQUESTED; Next_State CC_STATE_REQUESTED;
} }
Stimulus CC_EVENT_INTERNAL_CLEARING {
Action Stop_T_RETENTION;
Action Start_T_RETENTION;
}
Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Stimulus CC_EVENT_TIMEOUT_T_RETENTION {
Action Send_EraseCallLinkageID; Action Send_EraseCallLinkageID;
Action Release_LinkID; Action Release_LinkID;

View File

@ -25,6 +25,10 @@ FSM CC_PTP_Agent
Action Send_CC_Available(Q931_DISCONNECT); Action Send_CC_Available(Q931_DISCONNECT);
Next_State CC_STATE_AVAILABLE; Next_State CC_STATE_AVAILABLE;
} }
Stimulus CC_EVENT_INTERNAL_CLEARING {
Action Pass_Up_CC_Cancel;
Next_State CC_STATE_IDLE;
}
Stimulus CC_EVENT_CANCEL { Stimulus CC_EVENT_CANCEL {
Next_State CC_STATE_IDLE; Next_State CC_STATE_IDLE;
} }
@ -53,6 +57,10 @@ FSM CC_PTP_Agent
Action Stop_T_RETENTION; Action Stop_T_RETENTION;
Next_State CC_STATE_REQUESTED; Next_State CC_STATE_REQUESTED;
} }
Stimulus CC_EVENT_INTERNAL_CLEARING {
Action Stop_T_RETENTION;
Action Start_T_RETENTION;
}
Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Stimulus CC_EVENT_TIMEOUT_T_RETENTION {
Action Pass_Up_CC_Cancel; Action Pass_Up_CC_Cancel;
Next_State CC_STATE_IDLE; Next_State CC_STATE_IDLE;

View File

@ -20,6 +20,11 @@ FSM CC_PTP_Agent
Action Send_CC_Available(Q931_DISCONNECT); Action Send_CC_Available(Q931_DISCONNECT);
Next_State CC_STATE_AVAILABLE; 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 { Stimulus CC_EVENT_CANCEL {
Action Set_Selfdestruct; Action Set_Selfdestruct;
Next_State CC_STATE_IDLE; Next_State CC_STATE_IDLE;
@ -46,6 +51,10 @@ FSM CC_PTP_Agent
Action Stop_T_RETENTION; Action Stop_T_RETENTION;
Next_State CC_STATE_REQUESTED; Next_State CC_STATE_REQUESTED;
} }
Stimulus CC_EVENT_INTERNAL_CLEARING {
Action Stop_T_RETENTION;
Action Start_T_RETENTION;
}
Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Stimulus CC_EVENT_TIMEOUT_T_RETENTION {
Action Pass_Up_CC_Cancel; Action Pass_Up_CC_Cancel;
Action Stop_T_RETENTION; Action Stop_T_RETENTION;

View File

@ -41,6 +41,10 @@ FSM CC_QSIG_Agent
Action Send_Call_Proceeding; Action Send_Call_Proceeding;
Next_State CC_STATE_REQUESTED; Next_State CC_STATE_REQUESTED;
} }
Stimulus CC_EVENT_INTERNAL_CLEARING {
Action Stop_T_RETENTION;
Action Start_T_RETENTION;
}
Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Stimulus CC_EVENT_TIMEOUT_T_RETENTION {
Action Pass_Up_CC_Cancel; Action Pass_Up_CC_Cancel;
Next_State CC_STATE_IDLE; Next_State CC_STATE_IDLE;

View File

@ -34,6 +34,10 @@ FSM CC_QSIG_Agent
Action Stop_T_RETENTION; Action Stop_T_RETENTION;
Next_State CC_STATE_REQUESTED; Next_State CC_STATE_REQUESTED;
} }
Stimulus CC_EVENT_INTERNAL_CLEARING {
Action Stop_T_RETENTION;
Action Start_T_RETENTION;
}
Stimulus CC_EVENT_TIMEOUT_T_RETENTION { Stimulus CC_EVENT_TIMEOUT_T_RETENTION {
Action Pass_Up_CC_Cancel; Action Pass_Up_CC_Cancel;
Action Stop_T_RETENTION; Action Stop_T_RETENTION;

View File

@ -2613,6 +2613,9 @@ static const char *pri_cc_fsm_event_str(enum CC_EVENTS event)
case CC_EVENT_CANCEL: case CC_EVENT_CANCEL:
str = "CC_EVENT_CANCEL"; str = "CC_EVENT_CANCEL";
break; break;
case CC_EVENT_INTERNAL_CLEARING:
str = "CC_EVENT_INTERNAL_CLEARING";
break;
case CC_EVENT_SIGNALING_GONE: case CC_EVENT_SIGNALING_GONE:
str = "CC_EVENT_SIGNALING_GONE"; str = "CC_EVENT_SIGNALING_GONE";
break; 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); pri_cc_act_send_cc_available(ctrl, cc_record, call, Q931_DISCONNECT);
cc_record->state = CC_STATE_AVAILABLE; cc_record->state = CC_STATE_AVAILABLE;
break; 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: case CC_EVENT_CANCEL:
pri_cc_act_release_link_id(ctrl, cc_record);
pri_cc_act_set_self_destruct(ctrl, cc_record); pri_cc_act_set_self_destruct(ctrl, cc_record);
cc_record->state = CC_STATE_IDLE; cc_record->state = CC_STATE_IDLE;
break; 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); pri_cc_act_stop_t_retention(ctrl, cc_record);
cc_record->state = CC_STATE_REQUESTED; cc_record->state = CC_STATE_REQUESTED;
break; 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: case CC_EVENT_TIMEOUT_T_RETENTION:
pri_cc_act_send_erase_call_linkage_id(ctrl, cc_record); pri_cc_act_send_erase_call_linkage_id(ctrl, cc_record);
pri_cc_act_release_link_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); pri_cc_act_send_cc_available(ctrl, cc_record, call, Q931_DISCONNECT);
cc_record->state = CC_STATE_AVAILABLE; cc_record->state = CC_STATE_AVAILABLE;
break; 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: case CC_EVENT_CANCEL:
pri_cc_act_set_self_destruct(ctrl, cc_record); pri_cc_act_set_self_destruct(ctrl, cc_record);
cc_record->state = CC_STATE_IDLE; 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); pri_cc_act_stop_t_retention(ctrl, cc_record);
cc_record->state = CC_STATE_REQUESTED; cc_record->state = CC_STATE_REQUESTED;
break; 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: case CC_EVENT_TIMEOUT_T_RETENTION:
pri_cc_act_pass_up_cc_cancel(ctrl, cc_record); pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
pri_cc_act_stop_t_retention(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); pri_cc_act_stop_t_retention(ctrl, cc_record);
cc_record->state = CC_STATE_REQUESTED; cc_record->state = CC_STATE_REQUESTED;
break; 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: case CC_EVENT_TIMEOUT_T_RETENTION:
pri_cc_act_pass_up_cc_cancel(ctrl, cc_record); pri_cc_act_pass_up_cc_cancel(ctrl, cc_record);
pri_cc_act_stop_t_retention(ctrl, cc_record); pri_cc_act_stop_t_retention(ctrl, cc_record);

View File

@ -664,6 +664,8 @@ enum CC_EVENTS {
CC_EVENT_LINK_CANCEL, CC_EVENT_LINK_CANCEL,
/*! Tear down CC request from upper layer. */ /*! Tear down CC request from upper layer. */
CC_EVENT_CANCEL, 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. */ /*! Received message indicating tear down of CC signaling link completed. */
CC_EVENT_SIGNALING_GONE, CC_EVENT_SIGNALING_GONE,
/*! Delayed hangup request for the signaling link to allow subcmd events to be passed up. */ /*! Delayed hangup request for the signaling link to allow subcmd events to be passed up. */

21
q931.c
View File

@ -8472,22 +8472,31 @@ static int pri_internal_clear(void *data)
pri_message(ctrl, "clearing, alive %d, hangupack %d\n", c->alive, c->sendhangupack); pri_message(ctrl, "clearing, alive %d, hangupack %d\n", c->alive, c->sendhangupack);
} }
if (c->cc.record && c->cc.record->signaling == c) { if (c->cc.record) {
pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_SIGNALING_GONE); 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 */ /* Free resources */
if (c->alive) { if (c->alive) {
c->alive = 0;
ctrl->ev.e = PRI_EVENT_HANGUP; ctrl->ev.e = PRI_EVENT_HANGUP;
res = Q931_RES_HAVEEVENT; res = Q931_RES_HAVEEVENT;
c->alive = 0;
} else if (c->sendhangupack) { } else if (c->sendhangupack) {
res = Q931_RES_HAVEEVENT; pri_hangup(ctrl, c, c->cause);
ctrl->ev.e = PRI_EVENT_HANGUP_ACK; ctrl->ev.e = PRI_EVENT_HANGUP_ACK;
pri_hangup(ctrl, c, c->cause); res = Q931_RES_HAVEEVENT;
} else { } else {
res = 0;
pri_hangup(ctrl, c, c->cause); 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; return res;