diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_dahdi.c | 5 | ||||
-rw-r--r-- | channels/sig_pri.c | 78 | ||||
-rw-r--r-- | channels/sig_pri.h | 24 |
3 files changed, 84 insertions, 23 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 0487d5238..6b63ed381 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -15536,8 +15536,9 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli struct sig_pri_chan *chan = tmp->sig_pvt; ast_cli(a->fd, "PRI Flags: "); - if (chan->resetting) - ast_cli(a->fd, "Resetting "); + if (chan->resetting != SIG_PRI_RESET_IDLE) { + ast_cli(a->fd, "Resetting=%d ", chan->resetting); + } if (chan->call) ast_cli(a->fd, "Call "); if (chan->allocated) { 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, diff --git a/channels/sig_pri.h b/channels/sig_pri.h index 7a48d824a..6c1ca2aa3 100644 --- a/channels/sig_pri.h +++ b/channels/sig_pri.h @@ -150,6 +150,27 @@ enum sig_pri_call_level { SIG_PRI_CALL_LEVEL_CONNECT, }; +enum sig_pri_reset_state { + /*! \brief The channel is not being RESTARTed. */ + SIG_PRI_RESET_IDLE, + /*! + * \brief The channel is being RESTARTed. + * \note Waiting for a RESTART ACKNOWLEDGE from the peer. + */ + SIG_PRI_RESET_ACTIVE, + /*! + * \brief Peer may not be sending the expected RESTART ACKNOWLEDGE. + * + * \details We have already received a SETUP on this channel. + * If another SETUP comes in on this channel then the peer + * considers this channel useable. Assume that the peer is + * never going to give us a RESTART ACKNOWLEDGE and assume that + * we have received one. This is not according to Q.931, but + * some peers occasionally fail to send a RESTART ACKNOWLEDGE. + */ + SIG_PRI_RESET_NO_ACK, +}; + struct sig_pri_span; struct sig_pri_callback { @@ -299,7 +320,6 @@ struct sig_pri_chan { unsigned int alreadyhungup:1; /*!< TRUE if the call has already gone/hungup */ unsigned int isidlecall:1; /*!< TRUE if this is an idle call */ unsigned int progress:1; /*!< TRUE if the call has seen inband-information progress through the network */ - unsigned int resetting:1; /*!< TRUE if this channel is being reset/restarted */ /*! * \brief TRUE when this channel is allocated. @@ -328,6 +348,8 @@ struct sig_pri_chan { /*! Call establishment life cycle level for simple comparisons. */ enum sig_pri_call_level call_level; + /*! \brief Channel reset/restart state. */ + enum sig_pri_reset_state resetting; int prioffset; /*!< channel number in span */ int logicalspan; /*!< logical span number within trunk group */ int mastertrunkgroup; /*!< what trunk group is our master */ |