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
This commit is contained in:
Richard Mudgett 2011-02-17 21:12:04 +00:00
parent df22f0e1cb
commit e7a5d0da62

47
q931.c
View File

@ -6597,7 +6597,7 @@ static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
return 0; 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) 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) { if (i == call->master_call->pri_winner) {
__q931_hangup(call->subcalls[i]->pri, call->subcalls[i], cause); __q931_hangup(call->subcalls[i]->pri, call->subcalls[i], cause);
} else { } 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) { if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "%s: Hanging up %d, winner %d\n", __FUNCTION__, 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) { if (!subcall->hangupinitiated) {
q931_hangup(pri, call, cause); q931_hangup(ctrl, subcall, cause);
call->alive = 0; 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; int i;
/* Set the winner first */ /* Set the winner first */
for (i = 0; i < ARRAY_LEN(realcall->subcalls); ++i) { for (i = 0; ; ++i) {
if (realcall->subcalls[i] && realcall->subcalls[i] == subcall) { if (ARRAY_LEN(realcall->subcalls) <= i) {
realcall->pri_winner = 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 */ /* Start tear down of calls that were not chosen */
for (i = 0; i < ARRAY_LEN(realcall->subcalls); ++i) { for (i = 0; i < ARRAY_LEN(realcall->subcalls); ++i) {
if (realcall->subcalls[i] && realcall->subcalls[i] != subcall) { 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); PRI_CAUSE_NONSELECTED_USER_CLEARING);
} }
} }