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:
parent
df22f0e1cb
commit
e7a5d0da62
47
q931.c
47
q931.c
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user