Implement the mandatory T312 timer for NT PTMP broadcast SETUP calls.
* Fixed stopping T303 too early on a NT PTMP broadcast SETUP call if a subcall just receives a RELEASE_COMPLETE(busy). * Fixed a valgrind reported invalid read/write when hanging up a NT PTMP broadcast SETUP call. JIRA LIBPRI-32 JIRA SWP-2548 git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@2238 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
afd91f7f31
commit
1013e7626d
2
libpri.h
2
libpri.h
@ -2153,6 +2153,8 @@ enum PRI_TIMERS_AND_COUNTERS {
|
||||
PRI_TIMER_QSIG_CC_T3, /*!< Max time to wait for user A to respond to user B availability. */
|
||||
PRI_TIMER_QSIG_CC_T4, /*!< Path reservation supervision timeout. */
|
||||
|
||||
PRI_TIMER_T312, /*!< Supervise broadcast SETUP message call reference retention. */
|
||||
|
||||
/* Must be last in the enum list */
|
||||
PRI_MAX_TIMERS
|
||||
};
|
||||
|
2
pri.c
2
pri.c
@ -77,6 +77,7 @@ static const struct pri_timer_table pri_timer[] = {
|
||||
{ "T308", PRI_TIMER_T308, PRI_ALL_SWITCHES },
|
||||
{ "T309", PRI_TIMER_T309, PRI_ALL_SWITCHES },
|
||||
{ "T310", PRI_TIMER_T310, PRI_ALL_SWITCHES },
|
||||
{ "T312", PRI_TIMER_T312, PRI_ALL_SWITCHES },
|
||||
{ "T313", PRI_TIMER_T313, PRI_ALL_SWITCHES },
|
||||
{ "T314", PRI_TIMER_T314, PRI_ALL_SWITCHES },
|
||||
{ "T316", PRI_TIMER_T316, PRI_ALL_SWITCHES },
|
||||
@ -181,6 +182,7 @@ static void pri_default_timers(struct pri *ctrl, int switchtype)
|
||||
ctrl->timers[PRI_TIMER_T305] = 30 * 1000; /* Wait for DISCONNECT acknowledge */
|
||||
ctrl->timers[PRI_TIMER_T308] = 4 * 1000; /* Wait for RELEASE acknowledge */
|
||||
ctrl->timers[PRI_TIMER_T309] = 6 * 1000; /* Time to wait before clearing calls in case of D-channel transient event. Q.931 specifies 6-90 seconds */
|
||||
ctrl->timers[PRI_TIMER_T312] = (4 + 2) * 1000;/* Supervise broadcast SETUP message call reference retention. T303 + 2 seconds */
|
||||
ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */
|
||||
|
||||
ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
|
||||
|
@ -578,11 +578,14 @@ struct q931_call {
|
||||
0,2-7 - Reserved for future use */
|
||||
int t303_timer;
|
||||
int t303_expirycnt;
|
||||
int t312_timer;
|
||||
int fake_clearing_timer;
|
||||
|
||||
int hangupinitiated;
|
||||
/*! \brief TRUE if we broadcast this call's SETUP message. */
|
||||
int outboundbroadcast;
|
||||
int performing_fake_clearing;
|
||||
/*! TRUE if the master call is processing a hangup. Don't destroy it now. */
|
||||
int master_hanging_up;
|
||||
/*!
|
||||
* \brief Master call controlling this call.
|
||||
* \note Always valid. Master and normal calls point to self.
|
||||
|
@ -443,6 +443,8 @@ enum Q931_RANKED_CALL_STATE {
|
||||
Q931_RANKED_CALL_STATE_CONNECT,
|
||||
/*! Call is in some non-call establishment state (likely disconnecting). */
|
||||
Q931_RANKED_CALL_STATE_OTHER,
|
||||
/*! Master call is aborting. */
|
||||
Q931_RANKED_CALL_STATE_ABORT,
|
||||
};
|
||||
|
||||
/* EuroISDN */
|
||||
|
605
q931.c
605
q931.c
@ -4184,10 +4184,23 @@ struct q931_call *q931_new_call(struct pri *ctrl)
|
||||
|
||||
static void stop_t303(struct q931_call *call);
|
||||
|
||||
static void stop_t312(struct q931_call *call)
|
||||
{
|
||||
/* T312 should only be running on the master call */
|
||||
pri_schedule_del(call->pri, call->t312_timer);
|
||||
call->t312_timer = 0;
|
||||
}
|
||||
|
||||
static void cleanup_and_free_call(struct q931_call *cur)
|
||||
{
|
||||
struct pri *ctrl;
|
||||
|
||||
ctrl = cur->pri;
|
||||
pri_schedule_del(ctrl, cur->retranstimer);
|
||||
pri_schedule_del(ctrl, cur->hold_timer);
|
||||
pri_schedule_del(ctrl, cur->fake_clearing_timer);
|
||||
stop_t303(cur);
|
||||
pri_schedule_del(cur->pri, cur->retranstimer);
|
||||
stop_t312(cur);
|
||||
pri_call_apdu_queue_cleanup(cur);
|
||||
if (cur->cc.record) {
|
||||
/* Unlink CC associations. */
|
||||
@ -4215,7 +4228,118 @@ int q931_get_subcall_count(struct q931_call *master)
|
||||
return count;
|
||||
}
|
||||
|
||||
static void pri_create_fake_clearing(struct q931_call *c, struct pri *master);
|
||||
static int pri_internal_clear(struct q931_call *call);
|
||||
|
||||
/*!
|
||||
* \brief Fake RELEASE for NT-PTMP initiated SETUPs w/o response
|
||||
*
|
||||
* \param param call Call is not a subcall call record.
|
||||
*/
|
||||
static void pri_fake_clearing(struct q931_call *call)
|
||||
{
|
||||
struct pri *ctrl;
|
||||
|
||||
ctrl = call->pri;
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Fake clearing. cref:%d\n", call->cr);
|
||||
}
|
||||
|
||||
/*
|
||||
* This does not need to be running since this is what we are
|
||||
* doing right now anyway.
|
||||
*/
|
||||
pri_schedule_del(ctrl, call->fake_clearing_timer);
|
||||
call->fake_clearing_timer = 0;
|
||||
|
||||
if (call->cause == -1) {
|
||||
/* Ensure that there is a resonable cause code. */
|
||||
call->cause = PRI_CAUSE_NO_USER_RESPONSE;
|
||||
}
|
||||
if (pri_internal_clear(call) == Q931_RES_HAVEEVENT) {
|
||||
ctrl->schedev = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void pri_fake_clearing_expiry(void *data)
|
||||
{
|
||||
struct q931_call *master = data;
|
||||
|
||||
master->fake_clearing_timer = 0;
|
||||
pri_fake_clearing(master);
|
||||
}
|
||||
|
||||
static void pri_create_fake_clearing(struct pri *ctrl, struct q931_call *master)
|
||||
{
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Fake clearing requested. cref:%d\n", master->cr);
|
||||
}
|
||||
pri_schedule_del(ctrl, master->fake_clearing_timer);
|
||||
master->fake_clearing_timer = pri_schedule_event(ctrl, 0, pri_fake_clearing_expiry,
|
||||
master);
|
||||
}
|
||||
|
||||
static void t312_expiry(void *data)
|
||||
{
|
||||
struct q931_call *master = data;
|
||||
struct pri *ctrl;
|
||||
|
||||
ctrl = master->pri;
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "T312 timed out. cref:%d\n", master->cr);
|
||||
}
|
||||
|
||||
master->t312_timer = 0;
|
||||
if (!q931_get_subcall_count(master)) {
|
||||
/* No subcalls remain. */
|
||||
switch (master->ourcallstate) {
|
||||
case Q931_CALL_STATE_CALL_ABORT:
|
||||
/* We can destroy the master. */
|
||||
q931_destroycall(ctrl, master);
|
||||
break;
|
||||
default:
|
||||
/* Let the upper layer know about the lack of call prospects. */
|
||||
UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_ABORT);
|
||||
pri_fake_clearing(master);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \param master Master call record for PTMP NT call. */
|
||||
static void start_t312(struct q931_call *master)
|
||||
{
|
||||
struct pri *ctrl;
|
||||
|
||||
ctrl = master->pri;
|
||||
pri_schedule_del(ctrl, master->t312_timer);
|
||||
master->t312_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T312],
|
||||
t312_expiry, master);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Helper function to destroy a subcall.
|
||||
*
|
||||
* \param master Q.931 master call of subcall to destroy.
|
||||
* \param idx Master subcall index to destroy.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void q931_destroy_subcall(struct q931_call *master, int idx)
|
||||
{
|
||||
struct pri *ctrl = master->pri;
|
||||
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Destroying subcall %p of call %p at %d\n",
|
||||
master->subcalls[idx], master, idx);
|
||||
}
|
||||
cleanup_and_free_call(master->subcalls[idx]);
|
||||
if (master->pri_winner == idx) {
|
||||
/* This was the winning subcall. */
|
||||
master->pri_winner = -1;
|
||||
}
|
||||
master->subcalls[idx] = NULL;
|
||||
}
|
||||
|
||||
void q931_destroycall(struct pri *ctrl, q931_call *c)
|
||||
{
|
||||
@ -4224,7 +4348,6 @@ void q931_destroycall(struct pri *ctrl, q931_call *c)
|
||||
struct q931_call *slave;
|
||||
int i;
|
||||
int slavesleft;
|
||||
int slaveidx;
|
||||
|
||||
if (q931_is_dummy_call(c)) {
|
||||
/* Cannot destroy the dummy call. */
|
||||
@ -4241,93 +4364,68 @@ void q931_destroycall(struct pri *ctrl, q931_call *c)
|
||||
cur = *ctrl->callpool;
|
||||
while (cur) {
|
||||
if (cur == c) {
|
||||
slaveidx = -1;
|
||||
if (slave) {
|
||||
/* Destroying a slave. */
|
||||
for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) {
|
||||
if (cur->subcalls[i] == slave) {
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Destroying subcall %p of call %p at %d\n",
|
||||
slave, cur, i);
|
||||
}
|
||||
cleanup_and_free_call(slave);
|
||||
cur->subcalls[i] = NULL;
|
||||
slaveidx = i;
|
||||
q931_destroy_subcall(cur, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slavesleft = 0;
|
||||
for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) {
|
||||
if (cur->subcalls[i]) {
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Subcall still present at %d\n", i);
|
||||
/* How many slaves are left? */
|
||||
slavesleft = 0;
|
||||
for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) {
|
||||
if (cur->subcalls[i]) {
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Subcall still present at %d\n", i);
|
||||
}
|
||||
++slavesleft;
|
||||
}
|
||||
}
|
||||
|
||||
if (slavesleft || cur->t312_timer || cur->master_hanging_up) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* No slaves left. */
|
||||
switch (cur->ourcallstate) {
|
||||
case Q931_CALL_STATE_CALL_ABORT:
|
||||
break;
|
||||
default:
|
||||
/* Let the upper layer know about the call clearing. */
|
||||
UPDATE_OURCALLSTATE(ctrl, cur, Q931_CALL_STATE_CALL_ABORT);
|
||||
pri_create_fake_clearing(ctrl, cur);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We can try to destroy the master now. */
|
||||
} else {
|
||||
/* Destroy any slaves that may be present as well. */
|
||||
slavesleft = 0;
|
||||
for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) {
|
||||
if (cur->subcalls[i]) {
|
||||
++slavesleft;
|
||||
q931_destroy_subcall(cur, i);
|
||||
}
|
||||
slavesleft++;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have 3 different phases to deal with:
|
||||
* 1.) Sent outbound call, but no response (no subcalls present)
|
||||
* 2.) Sent outbound call, with responses (subcalls present)
|
||||
* 3.) Outbound call connected, indicated by pri_winner > -1
|
||||
*
|
||||
* If chan_dahdi hangs up in phase:
|
||||
* 1.) T303 will be present, and we will fake clear in this case
|
||||
* 2.) pri_winner will be < 0 and subcalls will be present.
|
||||
* 3.) pri_winner will be > -1 and we will free the master when the winner dies.
|
||||
*
|
||||
* If remote ends hang up in phase:
|
||||
* 1.) Impossible, defined by phase.
|
||||
* 2.) When last end hangs up, we should cause a fake clearing.
|
||||
* 3.) Pass events to winner up and be freed when winner is freed
|
||||
*
|
||||
* Exceptional conditions in phase:
|
||||
* 1.) None.
|
||||
* 2.) None.
|
||||
* 3.) We hang up a call so quickly that it hangs up before other competing lines finish hangup sequence
|
||||
* Subcalls present still even though we have hung up the winner.
|
||||
*
|
||||
* So, we could say:
|
||||
* If, when the library user hangs up the master call, and there are more than one subcall up, we fake clear
|
||||
* regardless of whether or not we drop down to one subcall left in the clearing process.
|
||||
*
|
||||
* If there is only one call up, we mirror what it does.
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Phase 2. them clearing:
|
||||
* For handling of Phase 2 (indicated by not running and pri_winner not present):
|
||||
* We create a fake hangup sequence after all the subcalls have been destroyed and after
|
||||
*
|
||||
* "" us clearing:
|
||||
* For we need to start the fake clearing, but it needs to be half of a fake clearing, not a full one (since we already had a hangup).
|
||||
*
|
||||
* For handling of Phase 3 plus exceptions:
|
||||
*
|
||||
* If pri_winner exists, we mirror him in terms of events (which provides our hangup sequence), and when we have the complete
|
||||
* hangup sequence completed (destroy called on master call), if there still exist non winner subcalls at this time, we declare the master
|
||||
* call as dead and free it when the last subcall clears.
|
||||
*/
|
||||
|
||||
if (slave && !slavesleft /* i.e., The last slave was just destroyed */
|
||||
&& (cur->pri_winner < 0 || slaveidx != cur->pri_winner)) {
|
||||
pri_create_fake_clearing(cur, ctrl);
|
||||
if (cur->fake_clearing_timer) {
|
||||
/*
|
||||
* Must wait for the fake clearing to complete before destroying
|
||||
* the master call record.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (slavesleft) {
|
||||
return;
|
||||
/* This is likely not good. */
|
||||
pri_error(ctrl,
|
||||
"Destroyed %d subcalls unconditionally with the master. cref:%d\n",
|
||||
slavesleft, cur->cr);
|
||||
}
|
||||
|
||||
/* Master call or normal call destruction. */
|
||||
if ((cur->pri_winner > -1) && cur->outboundbroadcast) {
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl,
|
||||
"Since we already had a winner, we should just be able to kill the call anyways\n");
|
||||
}
|
||||
}
|
||||
if (prev)
|
||||
prev->next = cur->next;
|
||||
else
|
||||
@ -4339,7 +4437,6 @@ void q931_destroycall(struct pri *ctrl, q931_call *c)
|
||||
q931_call_state_str(cur->ourcallstate),
|
||||
q931_call_state_str(cur->peercallstate),
|
||||
q931_hold_state_str(cur->hold_state));
|
||||
pri_schedule_del(ctrl, cur->hold_timer);
|
||||
cleanup_and_free_call(cur);
|
||||
return;
|
||||
}
|
||||
@ -5689,36 +5786,45 @@ static int cis_setup_ies[] = {
|
||||
static void stop_t303(struct q931_call *call)
|
||||
{
|
||||
/* T303 should only be running on the master call */
|
||||
pri_schedule_del(call->master_call->pri, call->master_call->t303_timer);
|
||||
call->master_call->t303_timer = 0;
|
||||
pri_schedule_del(call->pri, call->t303_timer);
|
||||
call->t303_timer = 0;
|
||||
}
|
||||
|
||||
static void t303_expiry(void *data);
|
||||
|
||||
/*! \param call Call is not a subcall call record. */
|
||||
static void start_t303(struct q931_call *call)
|
||||
{
|
||||
if (call->t303_timer) {
|
||||
pri_error(call->pri, "Should not have T303 set when starting again. Stopping first\n");
|
||||
stop_t303(call);
|
||||
}
|
||||
struct pri *ctrl;
|
||||
|
||||
//pri_error(call->pri, "T303 should be %d\n", call->pri->timers[PRI_TIMER_T303]);
|
||||
call->t303_timer = pri_schedule_event(call->pri, call->pri->timers[PRI_TIMER_T303], t303_expiry, call);
|
||||
ctrl = call->pri;
|
||||
pri_schedule_del(ctrl, call->t303_timer);
|
||||
call->t303_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T303], t303_expiry,
|
||||
call);
|
||||
}
|
||||
|
||||
static void pri_fake_clearing(void *data);
|
||||
|
||||
static void t303_expiry(void *data)
|
||||
{
|
||||
struct q931_call *c = data;
|
||||
struct q931_call *c = data;/* Call is not a subcall call record. */
|
||||
struct pri *ctrl = c->pri;
|
||||
int res;
|
||||
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "T303 timed out. cref:%d\n", c->cr);
|
||||
}
|
||||
|
||||
c->t303_expirycnt++;
|
||||
c->t303_timer = 0;
|
||||
|
||||
if (c->cause != -1) {
|
||||
/* We got a DISCONNECT, RELEASE, or RELEASE_COMPLETE and no other responses. */
|
||||
if (c->outboundbroadcast) {
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_ABORT);
|
||||
} else {
|
||||
/* This should never happen. T303 should not be running in this case. */
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
|
||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||
}
|
||||
pri_fake_clearing(c);
|
||||
} else if (c->t303_expirycnt < 2) {
|
||||
/*!
|
||||
@ -5745,8 +5851,22 @@ static void t303_expiry(void *data)
|
||||
pri_error(ctrl, "Error resending setup message!\n");
|
||||
}
|
||||
start_t303(c);
|
||||
if (c->outboundbroadcast) {
|
||||
start_t312(c);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We never got any response for a normal call or an
|
||||
* establishment response from any TEI for a master/subcall
|
||||
* call.
|
||||
*/
|
||||
c->cause = PRI_CAUSE_NO_USER_RESPONSE;
|
||||
if (c->outboundbroadcast) {
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_ABORT);
|
||||
} else {
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
|
||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||
}
|
||||
pri_fake_clearing(c);
|
||||
}
|
||||
}
|
||||
@ -5859,6 +5979,9 @@ int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req)
|
||||
c->peercallstate = Q931_CALL_STATE_CALL_PRESENT;
|
||||
c->t303_expirycnt = 0;
|
||||
start_t303(c);
|
||||
if (c->outboundbroadcast) {
|
||||
start_t312(c);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -6400,37 +6523,10 @@ int q931_send_retrieve_rej(struct pri *ctrl, struct q931_call *call, int cause)
|
||||
return q931_send_retrieve_rej_msg(ctrl, winner, cause);
|
||||
}
|
||||
|
||||
static int pri_internal_clear(struct q931_call *call);
|
||||
|
||||
/* Fake RELEASE for NT-PTMP initiated SETUPs w/o response */
|
||||
static void pri_fake_clearing(void *data)
|
||||
{
|
||||
struct q931_call *c = data;
|
||||
struct pri *ctrl = c->pri;
|
||||
|
||||
/*
|
||||
* We cannot clear the retranstimer id because we are called by t303_expiry also.
|
||||
* Fortunately, it doesn't matter because pri_internal_clear() will stop it if
|
||||
* it was actually running.
|
||||
*/
|
||||
//c->retranstimer = 0;
|
||||
c->performing_fake_clearing = 1;
|
||||
if (pri_internal_clear(c) == Q931_RES_HAVEEVENT) {
|
||||
ctrl->schedev = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void pri_create_fake_clearing(struct q931_call *c, struct pri *master)
|
||||
{
|
||||
pri_schedule_del(master, c->retranstimer);
|
||||
c->retranstimer = pri_schedule_event(master, 0, pri_fake_clearing, c);
|
||||
}
|
||||
|
||||
static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
|
||||
{
|
||||
int disconnect = 1;
|
||||
int release_compl = 0;
|
||||
int t303_was_running = c->master_call->t303_timer;
|
||||
|
||||
if (!ctrl || !c) {
|
||||
return -1;
|
||||
@ -6517,17 +6613,6 @@ static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
|
||||
q931_release_complete(ctrl,c,cause);
|
||||
break;
|
||||
case Q931_CALL_STATE_CALL_INITIATED:
|
||||
if (c->outboundbroadcast && c->master_call == c && t303_was_running) {
|
||||
//c->fakeclearing = 1;
|
||||
//c->alive = 0;
|
||||
/* We need to fake a received clearing sequence in this case... */
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Faking clearing\n");
|
||||
}
|
||||
pri_create_fake_clearing(c, ctrl);
|
||||
/* This means that we never got a response from a TEI */
|
||||
return 0;
|
||||
}
|
||||
/* we sent SETUP */
|
||||
case Q931_CALL_STATE_OVERLAP_SENDING:
|
||||
/* received SETUP_ACKNOWLEDGE */
|
||||
@ -6580,6 +6665,9 @@ static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
|
||||
/* sent DISCONNECT */
|
||||
q931_release(ctrl,c,cause);
|
||||
break;
|
||||
case Q931_CALL_STATE_CALL_ABORT:
|
||||
/* Don't do anything, waiting for T312 to expire. */
|
||||
break;
|
||||
case Q931_CALL_STATE_DISCONNECT_INDICATION:
|
||||
/* received DISCONNECT */
|
||||
if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST) {
|
||||
@ -6615,7 +6703,7 @@ static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void initiate_hangup_if_needed(struct pri *ctrl, struct q931_call *subcall, int cause);
|
||||
static void initiate_hangup_if_needed(struct q931_call *master, int idx, int cause);
|
||||
|
||||
int q931_hangup(struct pri *ctrl, q931_call *call, int cause)
|
||||
{
|
||||
@ -6623,42 +6711,72 @@ int q931_hangup(struct pri *ctrl, q931_call *call, int cause)
|
||||
|
||||
if (call->master_call->outboundbroadcast) {
|
||||
if (call->master_call == call) {
|
||||
int slaves = 0;
|
||||
int slaves;
|
||||
|
||||
/* Master is called with hangup - initiate hangup with slaves */
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, DBGHEAD "Hangup master cref:%d\n", DBGINFO, call->cr);
|
||||
}
|
||||
|
||||
UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_CALL_ABORT);
|
||||
if (call->pri_winner < 0 && call->alive) {
|
||||
/*
|
||||
* Fake clearing if we have no winner to get rid of the upper
|
||||
* layer.
|
||||
*/
|
||||
pri_create_fake_clearing(ctrl, call);
|
||||
} else if (call->fake_clearing_timer) {
|
||||
/*
|
||||
* No need for fake clearing to be running anymore.
|
||||
* Will this actually happen?
|
||||
*/
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Fake clearing request cancelled. cref:%d\n",
|
||||
call->cr);
|
||||
}
|
||||
pri_schedule_del(ctrl, call->fake_clearing_timer);
|
||||
call->fake_clearing_timer = 0;
|
||||
}
|
||||
|
||||
/* Initiate hangup of slaves */
|
||||
call->master_hanging_up = 1;
|
||||
for (i = 0; i < ARRAY_LEN(call->subcalls); ++i) {
|
||||
if (call->subcalls[i]) {
|
||||
slaves++;
|
||||
if (i == call->master_call->pri_winner) {
|
||||
__q931_hangup(call->subcalls[i]->pri, call->subcalls[i], cause);
|
||||
} else {
|
||||
initiate_hangup_if_needed(ctrl, call->subcalls[i], cause);
|
||||
}
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "%s: Hanging up %d, winner %d\n", __FUNCTION__,
|
||||
i, call->master_call->pri_winner);
|
||||
pri_message(ctrl, DBGHEAD "Hanging up %d, winner:%d subcall:%p\n",
|
||||
DBGINFO, i, call->pri_winner, call->subcalls[i]);
|
||||
}
|
||||
if (i == call->pri_winner) {
|
||||
q931_hangup(ctrl, call->subcalls[i], cause);
|
||||
} else {
|
||||
initiate_hangup_if_needed(call, i, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
call->master_hanging_up = 0;
|
||||
|
||||
call->hangupinitiated = 1;
|
||||
|
||||
if ((!slaves && (call->master_call->pri_winner < 0)) || (call->performing_fake_clearing)) {
|
||||
__q931_hangup(ctrl, call, cause);
|
||||
}
|
||||
slaves = q931_get_subcall_count(call);
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "%s: Slaves %d\n", __FUNCTION__, slaves);
|
||||
pri_message(ctrl, DBGHEAD "Remaining slaves %d\n", DBGINFO, slaves);
|
||||
}
|
||||
|
||||
stop_t303(call);
|
||||
if (!call->t312_timer && !slaves) {
|
||||
/*
|
||||
* T312 has expired and no slaves are left so we can safely
|
||||
* destroy the master.
|
||||
*/
|
||||
q931_destroycall(ctrl, call);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "%s: Slave hangup\n", __FUNCTION__);
|
||||
pri_message(ctrl, DBGHEAD "Hangup slave cref:%d\n", DBGINFO, call->cr);
|
||||
}
|
||||
return __q931_hangup(ctrl, call, cause);
|
||||
}
|
||||
} else {
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "%s: other hangup\n", __FUNCTION__);
|
||||
pri_message(ctrl, DBGHEAD "Hangup other cref:%d\n", DBGINFO, call->cr);
|
||||
}
|
||||
return __q931_hangup(ctrl, call, cause);
|
||||
}
|
||||
@ -6868,28 +6986,19 @@ static struct q931_call *q931_get_subcall_winner(struct q931_call *master)
|
||||
}
|
||||
}
|
||||
|
||||
static void initiate_hangup_if_needed(struct pri *ctrl, struct q931_call *subcall, int cause)
|
||||
static void initiate_hangup_if_needed(struct q931_call *master, int idx, int cause)
|
||||
{
|
||||
struct pri *ctrl;
|
||||
struct q931_call *subcall;
|
||||
|
||||
ctrl = master->pri;
|
||||
subcall = master->subcalls[idx];
|
||||
|
||||
if (!subcall->hangupinitiated) {
|
||||
q931_hangup(ctrl, subcall, cause);
|
||||
subcall->alive = 0;
|
||||
} else {
|
||||
switch (subcall->ourcallstate) {
|
||||
case Q931_CALL_STATE_NULL:
|
||||
switch (subcall->peercallstate) {
|
||||
case Q931_CALL_STATE_NULL:
|
||||
/*
|
||||
* Complete the hangup of the dead subcall. Noone else will at
|
||||
* this point.
|
||||
*/
|
||||
q931_hangup(ctrl, subcall, cause);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (master->subcalls[idx] == subcall) {
|
||||
/* The subcall was not destroyed. */
|
||||
subcall->alive = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6914,8 +7023,7 @@ static void q931_set_subcall_winner(struct q931_call *subcall)
|
||||
/* Start tear down of calls that were not chosen */
|
||||
for (i = 0; i < ARRAY_LEN(master->subcalls); ++i) {
|
||||
if (master->subcalls[i] && master->subcalls[i] != subcall) {
|
||||
initiate_hangup_if_needed(master->pri, master->subcalls[i],
|
||||
PRI_CAUSE_NONSELECTED_USER_CLEARING);
|
||||
initiate_hangup_if_needed(master, i, PRI_CAUSE_NONSELECTED_USER_CLEARING);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6962,9 +7070,17 @@ static struct q931_call *q931_get_subcall(struct q921_link *link, struct q931_ca
|
||||
cur->subcalls[i] = NULL;
|
||||
}
|
||||
cur->t303_timer = 0;/* T303 should only be on on the master call */
|
||||
cur->t312_timer = 0;/* T312 should only be on on the master call */
|
||||
cur->fake_clearing_timer = 0;/* Fake clearing should only be on on the master call */
|
||||
cur->hold_timer = 0;
|
||||
cur->retranstimer = 0;
|
||||
|
||||
/*
|
||||
* Mark this subcall as a newcall until it is determined if the
|
||||
* subcall can compete for the call.
|
||||
*/
|
||||
cur->newcall = 1;
|
||||
|
||||
/* Assume we sent a SETUP and this is the first response to it from this peer. */
|
||||
cur->ourcallstate = Q931_CALL_STATE_CALL_INITIATED;
|
||||
cur->peercallstate = Q931_CALL_STATE_CALL_PRESENT;
|
||||
@ -7065,12 +7181,7 @@ int q931_receive(struct q921_link *link, q931_h *h, int len)
|
||||
case Q931_PROTOCOL_DISCRIMINATOR:
|
||||
if (prepare_to_handle_q931_message(ctrl, mh, c)) {
|
||||
/* Discard message. We don't know how to handle it. */
|
||||
if (!c->master_call->outboundbroadcast && c->newcall) {
|
||||
/*
|
||||
* Destroy new non-subcalls immediately. Let the normal
|
||||
* disconnect/destruction of subcalls happen when there is a
|
||||
* winner.
|
||||
*/
|
||||
if (c->newcall) {
|
||||
pri_destroycall(ctrl, c);
|
||||
}
|
||||
return 0;
|
||||
@ -7317,6 +7428,9 @@ static enum Q931_RANKED_CALL_STATE q931_rank_state(enum Q931_CALL_STATE state)
|
||||
case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE:
|
||||
rank = Q931_RANKED_CALL_STATE_CONNECT;
|
||||
break;
|
||||
case Q931_CALL_STATE_CALL_ABORT:
|
||||
rank = Q931_RANKED_CALL_STATE_ABORT;
|
||||
break;
|
||||
default:
|
||||
rank = Q931_RANKED_CALL_STATE_OTHER;
|
||||
break;
|
||||
@ -7446,7 +7560,6 @@ static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, st
|
||||
struct q931_call *winner = q931_get_subcall_winner(master);
|
||||
enum Q931_RANKED_CALL_STATE master_rank;
|
||||
enum Q931_RANKED_CALL_STATE subcall_rank;
|
||||
enum Q931_CALL_STATE newstate;
|
||||
|
||||
/* For broadcast calls, we default to not allowing events to keep events received to a minimum
|
||||
* and to allow post processing, since that is where hangup and subcall state handling and other processing is done */
|
||||
@ -7454,6 +7567,10 @@ static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, st
|
||||
*allow_posthandle = 1;
|
||||
|
||||
master_rank = q931_rank_state(master->ourcallstate);
|
||||
if (master_rank < Q931_RANKED_CALL_STATE_CONNECT) {
|
||||
/* This subcall can compete for the call. */
|
||||
subcall->newcall = 0;
|
||||
}
|
||||
|
||||
switch (mh->msg) {
|
||||
case Q931_SETUP_ACKNOWLEDGE:
|
||||
@ -7496,22 +7613,53 @@ static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, st
|
||||
}
|
||||
break;
|
||||
case Q931_DISCONNECT:
|
||||
newstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
|
||||
goto process_hangup;
|
||||
case Q931_RELEASE:
|
||||
case Q931_RELEASE_COMPLETE:
|
||||
newstate = Q931_CALL_STATE_NULL;
|
||||
process_hangup:
|
||||
if (!winner) {
|
||||
/* If there's not a winner, we just take the cause and pass it up to the
|
||||
* master_call */
|
||||
master->cause = subcall->cause;
|
||||
int master_priority;
|
||||
int slave_priority;
|
||||
|
||||
/* Pass up the cause on a priority basis. */
|
||||
switch (master->cause) {
|
||||
case PRI_CAUSE_USER_BUSY:
|
||||
master_priority = 2;
|
||||
break;
|
||||
case PRI_CAUSE_CALL_REJECTED:
|
||||
master_priority = 1;
|
||||
break;
|
||||
default:
|
||||
master_priority = 0;
|
||||
break;
|
||||
case -1:
|
||||
/* First time priority. */
|
||||
master_priority = -2;
|
||||
break;
|
||||
}
|
||||
switch (subcall->cause) {
|
||||
case PRI_CAUSE_USER_BUSY:
|
||||
slave_priority = 2;
|
||||
break;
|
||||
case PRI_CAUSE_CALL_REJECTED:
|
||||
slave_priority = 1;
|
||||
break;
|
||||
default:
|
||||
slave_priority = 0;
|
||||
break;
|
||||
case PRI_CAUSE_INCOMPATIBLE_DESTINATION:
|
||||
/* Cause explicitly ignored */
|
||||
slave_priority = -1;
|
||||
break;
|
||||
}
|
||||
if (master_priority < slave_priority) {
|
||||
/* Pass up the cause to the master. */
|
||||
master->cause = subcall->cause;
|
||||
}
|
||||
} else {
|
||||
/* There *is* a winner */
|
||||
if (subcall == winner) {
|
||||
/* .. and we're it: */
|
||||
*allow_event = 1;
|
||||
UPDATE_OURCALLSTATE(ctrl, master, newstate);
|
||||
UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_ABORT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -7958,6 +8106,34 @@ static struct q931_call *q931_find_held_call(struct pri *ctrl, struct q931_call
|
||||
return match;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Determine RELEASE_COMPLETE cause code for newcall rejection.
|
||||
*
|
||||
* \param call Q.931 call leg.
|
||||
*
|
||||
* \return Cause code for RELEASE_COMPLETE.
|
||||
*/
|
||||
static int newcall_rel_comp_cause(struct q931_call *call)
|
||||
{
|
||||
struct q931_call *master;
|
||||
int cause;
|
||||
|
||||
cause = PRI_CAUSE_INVALID_CALL_REFERENCE;
|
||||
master = call->master_call;
|
||||
if (master != call && master->t312_timer) {
|
||||
switch (master->ourcallstate) {
|
||||
case Q931_CALL_STATE_CALL_ABORT:
|
||||
cause = PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cause;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Process the decoded information in the Q.931 message.
|
||||
@ -8077,9 +8253,9 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case Q931_ALERTING:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
stop_t303(c);
|
||||
stop_t303(c->master_call);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_DELIVERED);
|
||||
@ -8113,9 +8289,9 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case Q931_CONNECT:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
stop_t303(c);
|
||||
stop_t303(c->master_call);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
switch (c->ourcallstate) {
|
||||
@ -8170,7 +8346,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
case Q931_FACILITY:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
switch (c->incoming_ct_state) {
|
||||
@ -8201,10 +8377,10 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
/* Fall through */
|
||||
case Q931_CALL_PROCEEDING:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
stop_t303(c);
|
||||
stop_t303(c->master_call);
|
||||
ctrl->ev.proceeding.subcmds = &ctrl->subcmds;
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
if ((c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED) &&
|
||||
@ -8235,7 +8411,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
case Q931_CONNECT_ACKNOWLEDGE:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
switch (c->ourcallstate) {
|
||||
@ -8307,6 +8483,12 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
|
||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||
|
||||
if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) {
|
||||
/* Complete clearing the disconnecting non-winning subcall. */
|
||||
pri_hangup(ctrl, c, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Free resources */
|
||||
if (c->alive) {
|
||||
ctrl->ev.e = PRI_EVENT_HANGUP;
|
||||
@ -8342,6 +8524,12 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
pri_cc_event(ctrl, c, c->cc.record, CC_EVENT_SIGNALING_GONE);
|
||||
}
|
||||
|
||||
if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) {
|
||||
/* Complete clearing the disconnecting non-winning subcall. */
|
||||
pri_hangup(ctrl, c, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Free resources */
|
||||
if (c->alive) {
|
||||
ctrl->ev.e = PRI_EVENT_HANGUP;
|
||||
@ -8374,7 +8562,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
|
||||
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -8395,7 +8583,9 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
}
|
||||
|
||||
if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) {
|
||||
return pri_hangup(ctrl, c, -1);
|
||||
/* Complete clearing the disconnecting non-winning subcall. */
|
||||
pri_hangup(ctrl, c, -1);
|
||||
return 0;
|
||||
}
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case Q931_DISCONNECT:
|
||||
@ -8406,7 +8596,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -8476,6 +8666,12 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
|
||||
c->useruserinfo[0] = '\0';
|
||||
|
||||
if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) {
|
||||
/* Complete clearing the disconnecting non-winning subcall. */
|
||||
pri_hangup(ctrl, c, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c->alive) {
|
||||
switch (c->cause) {
|
||||
case PRI_CAUSE_USER_BUSY:
|
||||
@ -8511,7 +8707,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
XXX */
|
||||
q931_display_subcmd(ctrl, c);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
if (c->ourcallstate != Q931_CALL_STATE_OVERLAP_RECEIVING) {
|
||||
@ -8541,15 +8737,15 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
case Q931_STATUS_ENQUIRY:
|
||||
q931_display_clear(c);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
} else
|
||||
q931_status(ctrl,c, PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY);
|
||||
break;
|
||||
case Q931_SETUP_ACKNOWLEDGE:
|
||||
q931_display_subcmd(ctrl, c);
|
||||
stop_t303(c);
|
||||
stop_t303(c->master_call);
|
||||
if (c->newcall) {
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
q931_release_complete(ctrl, c, newcall_rel_comp_cause(c));
|
||||
break;
|
||||
}
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_SENDING);
|
||||
@ -8921,12 +9117,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
msg2str(mh->msg), mh->msg);
|
||||
q931_display_clear(c);
|
||||
q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
|
||||
if (!c->master_call->outboundbroadcast && c->newcall) {
|
||||
/*
|
||||
* Destroy new non-subcalls immediately. Let the normal
|
||||
* disconnect/destruction of subcalls happen when there is a
|
||||
* winner.
|
||||
*/
|
||||
if (c->newcall) {
|
||||
pri_destroycall(ctrl, c);
|
||||
}
|
||||
return -1;
|
||||
@ -8949,18 +9140,10 @@ static int pri_internal_clear(struct q931_call *c)
|
||||
c->sugcallstate = Q931_CALL_STATE_NOT_SET;
|
||||
c->aoc_units = -1;
|
||||
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
|
||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||
|
||||
if (c->master_call->outboundbroadcast
|
||||
&& c == q931_find_winning_call(c)) {
|
||||
/* Pass the hangup cause to the master_call. */
|
||||
c->master_call->cause = c->cause;
|
||||
|
||||
/* Declare this winning subcall to no longer be the winner and destroy it. */
|
||||
c->master_call->pri_winner = -1;
|
||||
q931_destroycall(ctrl, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
q931_clr_subcommands(ctrl);
|
||||
@ -9021,6 +9204,8 @@ static void pri_dl_down_timeout(void *data)
|
||||
|
||||
c->retranstimer = 0;
|
||||
c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER;
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
|
||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||
if (pri_internal_clear(c) == Q931_RES_HAVEEVENT) {
|
||||
ctrl->schedev = 1;
|
||||
}
|
||||
@ -9038,6 +9223,8 @@ static void pri_dl_down_cancelcall(void *data)
|
||||
|
||||
c->retranstimer = 0;
|
||||
c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER;
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
|
||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||
if (pri_internal_clear(c) == Q931_RES_HAVEEVENT) {
|
||||
ctrl->schedev = 1;
|
||||
}
|
||||
@ -9090,6 +9277,7 @@ static const char *q931_dl_event2str(enum Q931_DL_EVENT event)
|
||||
void q931_dl_event(struct q921_link *link, enum Q931_DL_EVENT event)
|
||||
{
|
||||
struct q931_call *cur;
|
||||
struct q931_call *cur_next;
|
||||
struct q931_call *call;
|
||||
struct pri *ctrl;
|
||||
int idx;
|
||||
@ -9168,7 +9356,10 @@ void q931_dl_event(struct q921_link *link, enum Q931_DL_EVENT event)
|
||||
break;
|
||||
case Q931_DL_EVENT_DL_RELEASE_IND:
|
||||
case Q931_DL_EVENT_DL_RELEASE_CONFIRM:
|
||||
for (cur = *ctrl->callpool; cur; cur = cur->next) {
|
||||
for (cur = *ctrl->callpool; cur; cur = cur_next) {
|
||||
/* The master call could get destroyed if the last subcall dies. */
|
||||
cur_next = cur->next;
|
||||
|
||||
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
|
||||
/* Don't do anything on the global call reference call record. */
|
||||
continue;
|
||||
|
Loading…
Reference in New Issue
Block a user