From e7a5d0da62bc2b19a9f74f32775b5ad78fa48273 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 17 Feb 2011 21:12:04 +0000 Subject: [PATCH] B channel lost by incoming call in BRI NT PTMP mode. A phone's RELEASE_COMPLETE as a response to an initial broadcast SETUP blocks one B channel permantly when the call is cancelled. Scenario: A call to the ISDN Bus is acknowledged (ALERTING) by one phone/endpoint and rejected by another phone/endpoint with a RELEASE_COMPLETE. The call is then cancelled by the caller. If the whole procedure is repeated once again then any further call attempt is rejected (WARNING[5666]: app_dial.c:1546 dial_exec_full: Unable to create channel of type 'DAHDI' (cause 34 - Circuit/channel congestion)). It seems that receiving a RELEASE_COMPLETE in that state blocks one B channel permanently when the call is cancelled by the caller. Background: The ISDN phones (Siemens Gigaset 3035 or CX253) we use for testing additionally contain a DECT base station, which operates as a different endpoint on the ISDN Bus (TEI). If the DECT base station is not in use then there are no DECT phones registered to the base station. The DECT base station responds to an incoming call not directed toward it with (RELEASE_COMPLETE, cause: no user responding). * Made initiate_hangup_if_needed() also hangup the subcall if it is in the NULL state. * Simplified q931_set_subcall_winner(). JIRA ABE-2745 JIRA SWP-2954 git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@2207 2fbb986a-6c06-0410-b554-c9c1f0a7f128 --- q931.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/q931.c b/q931.c index 9407dd6..f90de95 100644 --- a/q931.c +++ b/q931.c @@ -6597,7 +6597,7 @@ static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause) return 0; } -static void initiate_hangup_if_needed(struct pri *pri, q931_call *call, int cause); +static void initiate_hangup_if_needed(struct pri *ctrl, struct q931_call *subcall, int cause); int q931_hangup(struct pri *ctrl, q931_call *call, int cause) { @@ -6614,7 +6614,7 @@ int q931_hangup(struct pri *ctrl, q931_call *call, int cause) if (i == call->master_call->pri_winner) { __q931_hangup(call->subcalls[i]->pri, call->subcalls[i], cause); } else { - initiate_hangup_if_needed(call->subcalls[i]->pri, call->subcalls[i], cause); + 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__, @@ -6850,11 +6850,29 @@ static struct q931_call *q931_get_subcall_winner(struct q931_call *master) } } -static void initiate_hangup_if_needed(struct pri *pri, q931_call *call, int cause) +static void initiate_hangup_if_needed(struct pri *ctrl, struct q931_call *subcall, int cause) { - if (!call->hangupinitiated) { - q931_hangup(pri, call, cause); - call->alive = 0; + 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; + } } } @@ -6880,20 +6898,21 @@ static void q931_set_subcall_winner(struct q931_call *subcall) int i; /* Set the winner first */ - for (i = 0; i < ARRAY_LEN(realcall->subcalls); ++i) { - if (realcall->subcalls[i] && realcall->subcalls[i] == subcall) { - realcall->pri_winner = i; + for (i = 0; ; ++i) { + if (ARRAY_LEN(realcall->subcalls) <= i) { + pri_error(subcall->pri, "We should always find the winner in the list!\n"); + return; + } + if (realcall->subcalls[i] == subcall) { + realcall->pri_winner = i; + break; } - } - if (realcall->pri_winner < 0) { - pri_error(subcall->pri, "We should always find the winner in the list!\n"); - return; } /* Start tear down of calls that were not chosen */ for (i = 0; i < ARRAY_LEN(realcall->subcalls); ++i) { if (realcall->subcalls[i] && realcall->subcalls[i] != subcall) { - initiate_hangup_if_needed(realcall->subcalls[i]->pri, realcall->subcalls[i], + initiate_hangup_if_needed(realcall->pri, realcall->subcalls[i], PRI_CAUSE_NONSELECTED_USER_CLEARING); } }