summaryrefslogtreecommitdiff
path: root/channels/sig_pri.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2012-04-25 19:55:12 +0000
committerRichard Mudgett <rmudgett@digium.com>2012-04-25 19:55:12 +0000
commitd2ac624b877d3a4f9c47dfa85dba58f791582565 (patch)
tree93936fd717c3a1941ec8487d29330670b52bf1e9 /channels/sig_pri.c
parent04ddb5714fbddc64b8a81f3418e12ae371807527 (diff)
Clear ISDN channel resetting state if the peer continues to use it.
Some ISDN switches occasionally fail to send a RESTART ACKNOWLEDGE in response to a RESTART request. * Made the second SETUP received after sending a RESTART request clear the channel resetting state as if the peer had sent the expected RESTART ACKNOWLEDGE before continuing to process the SETUP. The peer may not be sending the expected RESTART ACKNOWLEDGE. (issue ASTERISK-19608) (issue AST-844) (issue AST-815) Patches: jira_ast_815_v1.8.patch (license #5621) patch uploaded by rmudgett (modified) ........ Merged revisions 363687 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 363688 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@363689 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/sig_pri.c')
-rw-r--r--channels/sig_pri.c78
1 files changed, 58 insertions, 20 deletions
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index 47724a8e9..28bb6712f 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -196,11 +196,11 @@ void sig_pri_set_alarm(struct sig_pri_chan *p, int in_alarm)
}
/*
- * Clear the channel restart flag when the channel alarm changes
- * to prevent the flag from getting stuck when the link goes
- * down.
+ * Clear the channel restart state when the channel alarm
+ * changes to prevent the state from getting stuck when the link
+ * goes down.
*/
- p->resetting = 0;
+ p->resetting = SIG_PRI_RESET_IDLE;
p->inalarm = in_alarm;
if (p->calls->set_alarm) {
@@ -1159,7 +1159,8 @@ static void pri_find_dchan(struct sig_pri_span *pri)
*/
static int sig_pri_is_chan_in_use(struct sig_pri_chan *pvt)
{
- return pvt->owner || pvt->call || pvt->allocated || pvt->resetting || pvt->inalarm;
+ return pvt->owner || pvt->call || pvt->allocated || pvt->inalarm
+ || pvt->resetting != SIG_PRI_RESET_IDLE;
}
/*!
@@ -1714,7 +1715,7 @@ static void pri_check_restart(struct sig_pri_span *pri)
}
if (pri->resetpos < pri->numchans) {
/* Mark the channel as resetting and restart it */
- pri->pvts[pri->resetpos]->resetting = 1;
+ pri->pvts[pri->resetpos]->resetting = SIG_PRI_RESET_ACTIVE;
pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
} else {
pri->resetting = 0;
@@ -5951,13 +5952,40 @@ static void *pri_dchannel(void *vpri)
"Span %d: SETUP on unconfigured channel %d/%d\n",
pri->span, PRI_SPAN(e->ring.channel),
PRI_CHANNEL(e->ring.channel));
- } else if (!sig_pri_is_chan_available(pri->pvts[chanpos])) {
- /* This is where we handle initial glare */
- ast_debug(1,
- "Span %d: SETUP requested unavailable channel %d/%d. Attempting to renegotiate.\n",
- pri->span, PRI_SPAN(e->ring.channel),
- PRI_CHANNEL(e->ring.channel));
- chanpos = -1;
+ } else {
+ switch (pri->pvts[chanpos]->resetting) {
+ case SIG_PRI_RESET_IDLE:
+ break;
+ case SIG_PRI_RESET_ACTIVE:
+ /*
+ * The peer may have lost the expected ack or not received the
+ * RESTART yet.
+ */
+ pri->pvts[chanpos]->resetting = SIG_PRI_RESET_NO_ACK;
+ break;
+ case SIG_PRI_RESET_NO_ACK:
+ /* The peer likely is not going to ack the RESTART. */
+ ast_debug(1,
+ "Span %d: Second SETUP while waiting for RESTART ACKNOWLEDGE on channel %d/%d\n",
+ pri->span, PRI_SPAN(e->ring.channel),
+ PRI_CHANNEL(e->ring.channel));
+
+ /* Assume we got the ack. */
+ pri->pvts[chanpos]->resetting = SIG_PRI_RESET_IDLE;
+ if (pri->resetting) {
+ /* Go on to the next idle channel to RESTART. */
+ pri_check_restart(pri);
+ }
+ break;
+ }
+ if (!sig_pri_is_chan_available(pri->pvts[chanpos])) {
+ /* This is where we handle initial glare */
+ ast_debug(1,
+ "Span %d: SETUP requested unavailable channel %d/%d. Attempting to renegotiate.\n",
+ pri->span, PRI_SPAN(e->ring.channel),
+ PRI_CHANNEL(e->ring.channel));
+ chanpos = -1;
+ }
}
#if defined(ALWAYS_PICK_CHANNEL)
if (e->ring.flexible) {
@@ -6778,12 +6806,12 @@ static void *pri_dchannel(void *vpri)
#if defined(FORCE_RESTART_UNAVAIL_CHANS)
if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
&& pri->sig != SIG_BRI_PTMP && !pri->resetting
- && !pri->pvts[chanpos]->resetting) {
+ && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
ast_verb(3,
"Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
pri->span, pri->pvts[chanpos]->logicalspan,
pri->pvts[chanpos]->prioffset);
- pri->pvts[chanpos]->resetting = 1;
+ pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
}
#endif /* defined(FORCE_RESTART_UNAVAIL_CHANS) */
@@ -6926,12 +6954,12 @@ static void *pri_dchannel(void *vpri)
#if defined(FORCE_RESTART_UNAVAIL_CHANS)
if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL
&& pri->sig != SIG_BRI_PTMP && !pri->resetting
- && !pri->pvts[chanpos]->resetting) {
+ && pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
ast_verb(3,
"Span %d: Forcing restart of channel %d/%d since channel reported in use\n",
pri->span, pri->pvts[chanpos]->logicalspan,
pri->pvts[chanpos]->prioffset);
- pri->pvts[chanpos]->resetting = 1;
+ pri->pvts[chanpos]->resetting = SIG_PRI_RESET_ACTIVE;
pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
}
#endif /* defined(FORCE_RESTART_UNAVAIL_CHANS) */
@@ -6995,7 +7023,8 @@ static void *pri_dchannel(void *vpri)
channel number, so we have to figure it out... This must be why
everybody resets exactly a channel at a time. */
for (x = 0; x < pri->numchans; x++) {
- if (pri->pvts[x] && pri->pvts[x]->resetting) {
+ if (pri->pvts[x]
+ && pri->pvts[x]->resetting != SIG_PRI_RESET_IDLE) {
chanpos = x;
sig_pri_lock_private(pri->pvts[chanpos]);
ast_debug(1,
@@ -7009,7 +7038,7 @@ static void *pri_dchannel(void *vpri)
pri->pvts[chanpos]->prioffset);
ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
}
- pri->pvts[chanpos]->resetting = 0;
+ pri->pvts[chanpos]->resetting = SIG_PRI_RESET_IDLE;
ast_verb(3,
"Span %d: Channel %d/%d successfully restarted\n",
pri->span, pri->pvts[chanpos]->logicalspan,
@@ -7028,6 +7057,15 @@ static void *pri_dchannel(void *vpri)
}
} else {
sig_pri_lock_private(pri->pvts[chanpos]);
+ if (pri->pvts[chanpos]->resetting == SIG_PRI_RESET_IDLE) {
+ /* The channel is not in the resetting state. */
+ ast_debug(1,
+ "Span %d: Unexpected or late restart ack on channel %d/%d (Ignoring)\n",
+ pri->span, pri->pvts[chanpos]->logicalspan,
+ pri->pvts[chanpos]->prioffset);
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ break;
+ }
if (pri->pvts[chanpos]->owner) {
ast_log(LOG_WARNING,
"Span %d: Got restart ack on channel %d/%d with owner\n",
@@ -7035,7 +7073,7 @@ static void *pri_dchannel(void *vpri)
pri->pvts[chanpos]->prioffset);
ast_channel_softhangup_internal_flag_add(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
}
- pri->pvts[chanpos]->resetting = 0;
+ pri->pvts[chanpos]->resetting = SIG_PRI_RESET_IDLE;
ast_verb(3,
"Span %d: Channel %d/%d successfully restarted\n",
pri->span, pri->pvts[chanpos]->logicalspan,