Implement T316 to allow RESTART messages to be automatically retransmitted.
Q.931 defines the T316 timer to retransmit RESTART messages if a RESTART ACKNOWLEDGE message is not received before the timer expires. Q.931 defaults the time of T316 to 2 minutes with the default number of consecutive RESTART failures as two. * To support legacy behavior, the T316 timer is disabled by default. It is also disabled because the user cannot configure it to disabled if it is enabled. * The N316 count is created to allow the number of RESTART attempts to be configurable. Note you will need to recompile Asterisk to be able to configure N316. (issue ASTERISK-19608) (issue AST-815) (closes issue PRI-133) Reported by: Mike Boylan Tested by: rmudgett git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@2288 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
f78400fc07
commit
fffb7babaf
3
libpri.h
3
libpri.h
@ -2179,7 +2179,7 @@ enum PRI_TIMERS_AND_COUNTERS {
|
|||||||
PRI_TIMER_T310, /*!< Maximum time between receiving a CALL_PROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */
|
PRI_TIMER_T310, /*!< Maximum time between receiving a CALL_PROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */
|
||||||
PRI_TIMER_T313, /*!< Wait for CONNECT acknowledge, CPE side only */
|
PRI_TIMER_T313, /*!< Wait for CONNECT acknowledge, CPE side only */
|
||||||
PRI_TIMER_T314,
|
PRI_TIMER_T314,
|
||||||
PRI_TIMER_T316, /*!< Maximum time between transmitting a RESTART and receiving a RESTART ACK */
|
PRI_TIMER_T316, /*!< Time to wait for a RESTART ACK before retransmitting RESTART. (Timer enabled if greater than zero.) */
|
||||||
PRI_TIMER_T317,
|
PRI_TIMER_T317,
|
||||||
PRI_TIMER_T318,
|
PRI_TIMER_T318,
|
||||||
PRI_TIMER_T319,
|
PRI_TIMER_T319,
|
||||||
@ -2221,6 +2221,7 @@ enum PRI_TIMERS_AND_COUNTERS {
|
|||||||
PRI_TIMER_QSIG_CC_T4, /*!< Path reservation supervision timeout. */
|
PRI_TIMER_QSIG_CC_T4, /*!< Path reservation supervision timeout. */
|
||||||
|
|
||||||
PRI_TIMER_T312, /*!< Supervise broadcast SETUP message call reference retention. */
|
PRI_TIMER_T312, /*!< Supervise broadcast SETUP message call reference retention. */
|
||||||
|
PRI_TIMER_N316, /*!< Number of times to transmit RESTART before giving up if T316 enabled. */
|
||||||
|
|
||||||
/* Must be last in the enum list */
|
/* Must be last in the enum list */
|
||||||
PRI_MAX_TIMERS
|
PRI_MAX_TIMERS
|
||||||
|
8
pri.c
8
pri.c
@ -81,6 +81,7 @@ static const struct pri_timer_table pri_timer[] = {
|
|||||||
{ "T313", PRI_TIMER_T313, PRI_ALL_SWITCHES },
|
{ "T313", PRI_TIMER_T313, PRI_ALL_SWITCHES },
|
||||||
{ "T314", PRI_TIMER_T314, PRI_ALL_SWITCHES },
|
{ "T314", PRI_TIMER_T314, PRI_ALL_SWITCHES },
|
||||||
{ "T316", PRI_TIMER_T316, PRI_ALL_SWITCHES },
|
{ "T316", PRI_TIMER_T316, PRI_ALL_SWITCHES },
|
||||||
|
{ "N316", PRI_TIMER_N316, PRI_ALL_SWITCHES },
|
||||||
{ "T317", PRI_TIMER_T317, PRI_ALL_SWITCHES },
|
{ "T317", PRI_TIMER_T317, PRI_ALL_SWITCHES },
|
||||||
{ "T318", PRI_TIMER_T318, PRI_ALL_SWITCHES },
|
{ "T318", PRI_TIMER_T318, PRI_ALL_SWITCHES },
|
||||||
{ "T319", PRI_TIMER_T319, PRI_ALL_SWITCHES },
|
{ "T319", PRI_TIMER_T319, PRI_ALL_SWITCHES },
|
||||||
@ -184,6 +185,10 @@ static void pri_default_timers(struct pri *ctrl, int switchtype)
|
|||||||
ctrl->timers[PRI_TIMER_T309] = 6 * 1000; /* Time to wait before clearing calls in case of D-channel transient event. Q.931 specifies 6-90 seconds */
|
ctrl->timers[PRI_TIMER_T309] = 6 * 1000; /* Time to wait before clearing calls in case of D-channel transient event. Q.931 specifies 6-90 seconds */
|
||||||
ctrl->timers[PRI_TIMER_T312] = (4 + 2) * 1000;/* Supervise broadcast SETUP message call reference retention. T303 + 2 seconds */
|
ctrl->timers[PRI_TIMER_T312] = (4 + 2) * 1000;/* Supervise broadcast SETUP message call reference retention. T303 + 2 seconds */
|
||||||
ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */
|
ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */
|
||||||
|
#if 0 /* Default disable the T316 timer otherwise the user cannot disable it. */
|
||||||
|
ctrl->timers[PRI_TIMER_T316] = 2 * 60 * 1000; /* RESTART retransmit timer */
|
||||||
|
#endif
|
||||||
|
ctrl->timers[PRI_TIMER_N316] = 2; /* Send RESTART this many times before giving up. */
|
||||||
|
|
||||||
ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
|
ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
|
||||||
ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */
|
ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */
|
||||||
@ -1795,7 +1800,8 @@ char *pri_dump_info_str(struct pri *ctrl)
|
|||||||
enum PRI_TIMERS_AND_COUNTERS tmr;
|
enum PRI_TIMERS_AND_COUNTERS tmr;
|
||||||
|
|
||||||
tmr = pri_timer[idx].number;
|
tmr = pri_timer[idx].number;
|
||||||
if (0 <= ctrl->timers[tmr]) {
|
if (0 <= ctrl->timers[tmr]
|
||||||
|
|| tmr == PRI_TIMER_T316) {
|
||||||
used = pri_snprintf(buf, used, buf_size, " %s: %d\n",
|
used = pri_snprintf(buf, used, buf_size, " %s: %d\n",
|
||||||
pri_timer[idx].name, ctrl->timers[tmr]);
|
pri_timer[idx].name, ctrl->timers[tmr]);
|
||||||
}
|
}
|
||||||
|
@ -652,6 +652,7 @@ struct q931_call {
|
|||||||
|
|
||||||
unsigned int slotmap_size:1;/* TRUE if the slotmap is E1 (32 bits). */
|
unsigned int slotmap_size:1;/* TRUE if the slotmap is E1 (32 bits). */
|
||||||
|
|
||||||
|
/*! Control the RESTART reception to the upper layer. */
|
||||||
struct {
|
struct {
|
||||||
/*! Timer ID of RESTART notification events to upper layer. */
|
/*! Timer ID of RESTART notification events to upper layer. */
|
||||||
int timer;
|
int timer;
|
||||||
@ -662,6 +663,15 @@ struct q931_call {
|
|||||||
/*! Channel ID list */
|
/*! Channel ID list */
|
||||||
char chan_no[32];
|
char chan_no[32];
|
||||||
} restart;
|
} restart;
|
||||||
|
/*! Control the RESTART retransmissions. */
|
||||||
|
struct {
|
||||||
|
/*! T316 RESTART retransmit timer. */
|
||||||
|
int t316_timer;
|
||||||
|
/*! Number of times remaining that RESTART can be transmitted. */
|
||||||
|
int remain;
|
||||||
|
/*! Encoded RESTART channel id. */
|
||||||
|
int channel;
|
||||||
|
} restart_tx;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CC_STATES {
|
enum CC_STATES {
|
||||||
|
114
q931.c
114
q931.c
@ -4422,6 +4422,7 @@ static void cleanup_and_free_call(struct q931_call *cur)
|
|||||||
|
|
||||||
ctrl = cur->pri;
|
ctrl = cur->pri;
|
||||||
pri_schedule_del(ctrl, cur->restart.timer);
|
pri_schedule_del(ctrl, cur->restart.timer);
|
||||||
|
pri_schedule_del(ctrl, cur->restart_tx.t316_timer);
|
||||||
pri_schedule_del(ctrl, cur->retranstimer);
|
pri_schedule_del(ctrl, cur->retranstimer);
|
||||||
pri_schedule_del(ctrl, cur->hold_timer);
|
pri_schedule_del(ctrl, cur->hold_timer);
|
||||||
pri_schedule_del(ctrl, cur->fake_clearing_timer);
|
pri_schedule_del(ctrl, cur->fake_clearing_timer);
|
||||||
@ -5913,6 +5914,81 @@ int q931_release(struct pri *ctrl, q931_call *c, int cause)
|
|||||||
|
|
||||||
static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
|
static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
|
||||||
|
|
||||||
|
static void t316_expire(void *vcall);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
* \brief Send the RESTART message to the peer.
|
||||||
|
*
|
||||||
|
* \param call Q.931 call leg
|
||||||
|
* \param channel Encoded channel id to use.
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
static int q931_send_restart(struct q931_call *call)
|
||||||
|
{
|
||||||
|
struct pri *ctrl = call->pri;
|
||||||
|
int channel = call->restart_tx.channel;
|
||||||
|
|
||||||
|
/* Start timer T316 if enabled. */
|
||||||
|
if (0 < ctrl->timers[PRI_TIMER_T316]) {
|
||||||
|
call->restart_tx.t316_timer =
|
||||||
|
pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T316], t316_expire, call);
|
||||||
|
--call->restart_tx.remain;
|
||||||
|
}
|
||||||
|
|
||||||
|
call->ri = 0;
|
||||||
|
call->ds1no = (channel >> 8) & 0xFF;
|
||||||
|
call->ds1explicit = (channel >> 16) & 0x1;
|
||||||
|
call->channelno = channel & 0xFF;
|
||||||
|
call->chanflags &= ~FLAG_PREFERRED;
|
||||||
|
call->chanflags |= FLAG_EXCLUSIVE;
|
||||||
|
UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_RESTART);
|
||||||
|
call->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
|
||||||
|
return send_message(ctrl, call, Q931_RESTART, restart_ies);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
* \brief T316 expired.
|
||||||
|
*
|
||||||
|
* \param vcall Q.931 call leg
|
||||||
|
*
|
||||||
|
* \return Nothing
|
||||||
|
*/
|
||||||
|
static void t316_expire(void *vcall)
|
||||||
|
{
|
||||||
|
struct q931_call *call = vcall;
|
||||||
|
|
||||||
|
call->restart_tx.t316_timer = 0;
|
||||||
|
|
||||||
|
if (call->restart_tx.remain) {
|
||||||
|
/* Retransmit the RESTART */
|
||||||
|
q931_send_restart(call);
|
||||||
|
} else {
|
||||||
|
int channel = call->restart_tx.channel;
|
||||||
|
|
||||||
|
pri_message(call->pri,
|
||||||
|
"!! Peer failed to ack our RESTART request for ds1/channel:%d/%d.\n",
|
||||||
|
(channel >> 8) & 0xFF, channel & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
* \brief Stop timer T316.
|
||||||
|
*
|
||||||
|
* \param call Q.931 call leg
|
||||||
|
*
|
||||||
|
* \return Nothing
|
||||||
|
*/
|
||||||
|
static void stop_t316(struct q931_call *call)
|
||||||
|
{
|
||||||
|
pri_schedule_del(call->pri, call->restart_tx.t316_timer);
|
||||||
|
call->restart_tx.t316_timer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Send the RESTART message to the peer.
|
* \brief Send the RESTART message to the peer.
|
||||||
*
|
*
|
||||||
@ -5930,9 +6006,6 @@ static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
|
|||||||
* there might not be anything connected. The broadcast could
|
* there might not be anything connected. The broadcast could
|
||||||
* be handled in a similar manner to the broadcast SETUP.
|
* be handled in a similar manner to the broadcast SETUP.
|
||||||
*
|
*
|
||||||
* \todo Need to implement T316 to protect against missing
|
|
||||||
* RESTART_ACKNOWLEDGE and STATUS messages.
|
|
||||||
*
|
|
||||||
* \todo NT PTMP mode should implement some protection from
|
* \todo NT PTMP mode should implement some protection from
|
||||||
* receiving a RESTART on channels in use by another TEI.
|
* receiving a RESTART on channels in use by another TEI.
|
||||||
*
|
*
|
||||||
@ -5941,22 +6014,21 @@ static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
|
|||||||
*/
|
*/
|
||||||
int q931_restart(struct pri *ctrl, int channel)
|
int q931_restart(struct pri *ctrl, int channel)
|
||||||
{
|
{
|
||||||
struct q931_call *c;
|
struct q931_call *call;
|
||||||
|
|
||||||
c = q931_getcall(&ctrl->link, 0 | Q931_CALL_REFERENCE_FLAG);
|
if (!channel) {
|
||||||
if (!c)
|
|
||||||
return -1;
|
return -1;
|
||||||
if (!channel)
|
}
|
||||||
|
call = q931_getcall(&ctrl->link, 0 | Q931_CALL_REFERENCE_FLAG);
|
||||||
|
if (!call) {
|
||||||
return -1;
|
return -1;
|
||||||
c->ri = 0;
|
}
|
||||||
c->ds1no = (channel & 0xff00) >> 8;
|
|
||||||
c->ds1explicit = (channel & 0x10000) >> 16;
|
stop_t316(call);
|
||||||
c->channelno = channel & 0xff;
|
call->restart_tx.remain = (0 < ctrl->timers[PRI_TIMER_N316])
|
||||||
c->chanflags &= ~FLAG_PREFERRED;
|
? ctrl->timers[PRI_TIMER_N316] : 1;
|
||||||
c->chanflags |= FLAG_EXCLUSIVE;
|
call->restart_tx.channel = channel;
|
||||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RESTART);
|
return q931_send_restart(call);
|
||||||
c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
|
|
||||||
return send_message(ctrl, c, Q931_RESTART, restart_ies);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_FACILITY, Q931_IE_USER_USER, -1 };
|
static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_FACILITY, Q931_IE_USER_USER, -1 };
|
||||||
@ -9007,6 +9079,16 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
|||||||
c->peercallstate = Q931_CALL_STATE_NULL;
|
c->peercallstate = Q931_CALL_STATE_NULL;
|
||||||
ctrl->ev.e = PRI_EVENT_RESTART_ACK;
|
ctrl->ev.e = PRI_EVENT_RESTART_ACK;
|
||||||
ctrl->ev.restartack.channel = q931_encode_channel(c);
|
ctrl->ev.restartack.channel = q931_encode_channel(c);
|
||||||
|
if (c->restart_tx.t316_timer
|
||||||
|
/*
|
||||||
|
* Since the DS1 value can vary, only check the channel number.
|
||||||
|
* We're only supposed to have one RESTART request outstanding
|
||||||
|
* at a time anyway.
|
||||||
|
*/
|
||||||
|
&& (c->restart_tx.channel & 0xFF) == (ctrl->ev.restartack.channel & 0xFF)) {
|
||||||
|
/* This is the RESTART ACKNOWLEDGE we are expecting. */
|
||||||
|
stop_t316(c);
|
||||||
|
}
|
||||||
return Q931_RES_HAVEEVENT;
|
return Q931_RES_HAVEEVENT;
|
||||||
case Q931_INFORMATION:
|
case Q931_INFORMATION:
|
||||||
/* XXX We're handling only INFORMATION messages that contain
|
/* XXX We're handling only INFORMATION messages that contain
|
||||||
|
Loading…
Reference in New Issue
Block a user