PRI links do not retain active calls if the link comes back before T309 expires.

The DL-ESTABLISH confirm event was not passed from Q.921 to Q.931 so Q.931
never cancelled the T309 timer.

Refactored q931_dl_tei_removal() and q931_dl_indication() into
q931_dl_event() to allow the DL-ESTABLISH confirm/indication and
DL-RELEASE confirm/indication events to be passed to Q.931.


git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1991 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
Richard Mudgett 2010-09-13 21:21:37 +00:00
parent 05158ec5fb
commit 384ae1e688
3 changed files with 144 additions and 101 deletions

View File

@ -502,8 +502,15 @@ void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx);
void q931_destroycall(struct pri *pri, q931_call *c); void q931_destroycall(struct pri *pri, q931_call *c);
void q931_dl_tei_removal(struct pri *link); enum Q931_DL_EVENT {
void q931_dl_indication(struct pri *link, int event); Q931_DL_EVENT_NONE,
Q931_DL_EVENT_DL_ESTABLISH_IND,
Q931_DL_EVENT_DL_ESTABLISH_CONFIRM,
Q931_DL_EVENT_DL_RELEASE_IND,
Q931_DL_EVENT_DL_RELEASE_CONFIRM,
Q931_DL_EVENT_TEI_REMOVAL,
};
void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event);
int q931_send_hold(struct pri *ctrl, struct q931_call *call); int q931_send_hold(struct pri *ctrl, struct q931_call *call);
int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call); int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call);

48
q921.c
View File

@ -215,7 +215,7 @@ static void t202_expire(void *vpri)
case Q921_ESTABLISH_AWAITING_TEI: case Q921_ESTABLISH_AWAITING_TEI:
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */ /* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
break; break;
default: default:
break; break;
@ -671,7 +671,7 @@ static void t200_expire(void *vpri)
q921_mdl_error(ctrl, 'G'); q921_mdl_error(ctrl, 'G');
q921_setstate(ctrl, Q921_TEI_ASSIGNED); q921_setstate(ctrl, Q921_TEI_ASSIGNED);
/* DL-RELEASE indication */ /* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
} }
break; break;
case Q921_AWAITING_RELEASE: case Q921_AWAITING_RELEASE:
@ -682,6 +682,7 @@ static void t200_expire(void *vpri)
} else { } else {
q921_mdl_error(ctrl, 'H'); q921_mdl_error(ctrl, 'H');
/* DL-RELEASE confirm */ /* DL-RELEASE confirm */
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
q921_setstate(ctrl, Q921_TEI_ASSIGNED); q921_setstate(ctrl, Q921_TEI_ASSIGNED);
} }
break; break;
@ -1280,7 +1281,7 @@ static void q921_clear_exception_conditions(struct pri *ctrl)
static pri_event * q921_sabme_rx(struct pri *ctrl, q921_h *h) static pri_event * q921_sabme_rx(struct pri *ctrl, q921_h *h)
{ {
pri_event *res = NULL; pri_event *res = NULL;
int delay_q931_dl_indication; enum Q931_DL_EVENT delay_q931_dl_event;
switch (ctrl->q921_state) { switch (ctrl->q921_state) {
case Q921_TIMER_RECOVERY: case Q921_TIMER_RECOVERY:
@ -1293,17 +1294,17 @@ static pri_event * q921_sabme_rx(struct pri *ctrl, q921_h *h)
if (ctrl->v_s != ctrl->v_a) { if (ctrl->v_s != ctrl->v_a) {
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
/* DL-ESTABLISH indication */ /* DL-ESTABLISH indication */
delay_q931_dl_indication = 1; delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
} else { } else {
delay_q931_dl_indication = 0; delay_q931_dl_event = Q931_DL_EVENT_NONE;
} }
stop_t200(ctrl); stop_t200(ctrl);
start_t203(ctrl); start_t203(ctrl);
ctrl->v_s = ctrl->v_a = ctrl->v_r = 0; ctrl->v_s = ctrl->v_a = ctrl->v_r = 0;
q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED); q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED);
if (delay_q931_dl_indication) { if (delay_q931_dl_event != Q931_DL_EVENT_NONE) {
/* Delayed because Q.931 could send STATUS messages. */ /* Delayed because Q.931 could send STATUS messages. */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_UP); q931_dl_event(ctrl, delay_q931_dl_event);
} }
break; break;
case Q921_TEI_ASSIGNED: case Q921_TEI_ASSIGNED:
@ -1311,17 +1312,16 @@ static pri_event * q921_sabme_rx(struct pri *ctrl, q921_h *h)
q921_clear_exception_conditions(ctrl); q921_clear_exception_conditions(ctrl);
ctrl->v_s = ctrl->v_a = ctrl->v_r = 0; ctrl->v_s = ctrl->v_a = ctrl->v_r = 0;
/* DL-ESTABLISH indication */ /* DL-ESTABLISH indication */
//delay_q931_dl_indication = 1; delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
if (PTP_MODE(ctrl)) { if (PTP_MODE(ctrl)) {
ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP; ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP;
res = &ctrl->ev; res = &ctrl->ev;
} }
start_t203(ctrl); start_t203(ctrl);
q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED); q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED);
//if (delay_q931_dl_indication) if (delay_q931_dl_event != Q931_DL_EVENT_NONE) {
{
/* Delayed because Q.931 could send STATUS messages. */ /* Delayed because Q.931 could send STATUS messages. */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_UP); q931_dl_event(ctrl, delay_q931_dl_event);
} }
break; break;
case Q921_AWAITING_ESTABLISHMENT: case Q921_AWAITING_ESTABLISHMENT:
@ -1360,7 +1360,7 @@ static pri_event *q921_disc_rx(struct pri *ctrl, q921_h *h)
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
q921_send_ua(ctrl, h->u.p_f); q921_send_ua(ctrl, h->u.p_f);
/* DL-RELEASE indication */ /* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl); stop_t200(ctrl);
if (ctrl->q921_state == Q921_MULTI_FRAME_ESTABLISHED) if (ctrl->q921_state == Q921_MULTI_FRAME_ESTABLISHED)
stop_t203(ctrl); stop_t203(ctrl);
@ -1402,20 +1402,21 @@ static void q921_mdl_remove(struct pri *ctrl)
case Q921_AWAITING_ESTABLISHMENT: case Q921_AWAITING_ESTABLISHMENT:
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */ /* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl); stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED); q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break; break;
case Q921_AWAITING_RELEASE: case Q921_AWAITING_RELEASE:
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
/* DL-RELEASE confirm */ /* DL-RELEASE confirm */
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
stop_t200(ctrl); stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED); q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break; break;
case Q921_MULTI_FRAME_ESTABLISHED: case Q921_MULTI_FRAME_ESTABLISHED:
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */ /* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl); stop_t200(ctrl);
stop_t203(ctrl); stop_t203(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED); q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
@ -1423,7 +1424,7 @@ static void q921_mdl_remove(struct pri *ctrl)
case Q921_TIMER_RECOVERY: case Q921_TIMER_RECOVERY:
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */ /* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl); stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED); q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break; break;
@ -1433,7 +1434,7 @@ static void q921_mdl_remove(struct pri *ctrl)
return; return;
} }
q931_dl_tei_removal(ctrl); q931_dl_event(ctrl, Q931_DL_EVENT_TEI_REMOVAL);
/* /*
* Negate the TEI value so debug messages will display a * Negate the TEI value so debug messages will display a
@ -1711,7 +1712,7 @@ static void q921_mdl_error(struct pri *ctrl, char error)
static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h) static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h)
{ {
pri_event *res = NULL; pri_event *res = NULL;
int delay_q931_dl_indication; enum Q931_DL_EVENT delay_q931_dl_event;
if (ctrl->debug & PRI_DEBUG_Q921_STATE) { if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
pri_message(ctrl, "TEI=%d Got UA\n", ctrl->tei); pri_message(ctrl, "TEI=%d Got UA\n", ctrl->tei);
@ -1733,16 +1734,17 @@ static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h)
break; break;
} }
delay_q931_dl_indication = 0; delay_q931_dl_event = Q931_DL_EVENT_NONE;
if (!ctrl->l3initiated) { if (!ctrl->l3initiated) {
if (ctrl->v_s != ctrl->v_a) { if (ctrl->v_s != ctrl->v_a) {
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
/* DL-ESTABLISH indication */ /* DL-ESTABLISH indication */
delay_q931_dl_indication = 1; delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
} }
} else { } else {
ctrl->l3initiated = 0; ctrl->l3initiated = 0;
/* DL-ESTABLISH confirm */ /* DL-ESTABLISH confirm */
delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_CONFIRM;
} }
if (PTP_MODE(ctrl)) { if (PTP_MODE(ctrl)) {
@ -1756,9 +1758,9 @@ static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h)
ctrl->v_r = ctrl->v_s = ctrl->v_a = 0; ctrl->v_r = ctrl->v_s = ctrl->v_a = 0;
q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED); q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED);
if (delay_q931_dl_indication) { if (delay_q931_dl_event != Q931_DL_EVENT_NONE) {
/* Delayed because Q.931 could send STATUS messages. */ /* Delayed because Q.931 could send STATUS messages. */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_UP); q931_dl_event(ctrl, delay_q931_dl_event);
} }
break; break;
case Q921_AWAITING_RELEASE: case Q921_AWAITING_RELEASE:
@ -1766,6 +1768,7 @@ static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h)
q921_mdl_error(ctrl, 'D'); q921_mdl_error(ctrl, 'D');
} else { } else {
/* DL-RELEASE confirm */ /* DL-RELEASE confirm */
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
stop_t200(ctrl); stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_ASSIGNED); q921_setstate(ctrl, Q921_TEI_ASSIGNED);
} }
@ -2181,7 +2184,7 @@ static pri_event *q921_dm_rx(struct pri *ctrl, q921_h *h)
q921_discard_iqueue(ctrl); q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */ /* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl); stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_ASSIGNED); q921_setstate(ctrl, Q921_TEI_ASSIGNED);
q921_restart_ptp_link_if_needed(ctrl); q921_restart_ptp_link_if_needed(ctrl);
@ -2190,6 +2193,7 @@ static pri_event *q921_dm_rx(struct pri *ctrl, q921_h *h)
if (!h->u.p_f) if (!h->u.p_f)
break; break;
/* DL-RELEASE confirm */ /* DL-RELEASE confirm */
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
stop_t200(ctrl); stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_ASSIGNED); q921_setstate(ctrl, Q921_TEI_ASSIGNED);
break; break;

186
q931.c
View File

@ -8379,81 +8379,50 @@ static void pri_dl_down_cancelcall(void *data)
} }
/*! /*!
* \brief Layer 2 is removing the link's TEI. * \internal
* \brief Convert the DL event to a string.
* *
* \param link Q.921 link losing it's TEI. * \param event Data-link event to convert to a string.
* *
* \note * \return DL event string
* For NT PTMP, this deviation from the specifications is needed */
* because we have no way to re-associate any T309 calls on the static const char *q931_dl_event2str(enum Q931_DL_EVENT event)
* removed TEI. {
const char *str;
str = "Unknown";
switch (event) {
case Q931_DL_EVENT_NONE:
str = "Q931_DL_EVENT_NONE";
break;
case Q931_DL_EVENT_DL_ESTABLISH_IND:
str = "Q931_DL_EVENT_DL_ESTABLISH_IND";
break;
case Q931_DL_EVENT_DL_ESTABLISH_CONFIRM:
str = "Q931_DL_EVENT_DL_ESTABLISH_CONFIRM";
break;
case Q931_DL_EVENT_DL_RELEASE_IND:
str = "Q931_DL_EVENT_DL_RELEASE_IND";
break;
case Q931_DL_EVENT_DL_RELEASE_CONFIRM:
str = "Q931_DL_EVENT_DL_RELEASE_CONFIRM";
break;
case Q931_DL_EVENT_TEI_REMOVAL:
str = "Q931_DL_EVENT_TEI_REMOVAL";
break;
}
return str;
}
/*!
* \brief Receive a DL event from layer 2.
*
* \param link Q.921 link event occurred on.
* \param event Data-link event reporting.
* *
* \return Nothing * \return Nothing
*/ */
void q931_dl_tei_removal(struct pri *link) void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
{
struct q931_call *cur;
struct q931_call *call;
struct pri *ctrl;
int idx;
/* Find the master - He has the call pool */
ctrl = PRI_MASTER(link);
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "DL TEI removal\n");
}
if (!BRI_NT_PTMP(ctrl)) {
/* Only NT PTMP has anything to worry about when the TEI is removed. */
return;
}
for (cur = *ctrl->callpool; cur; cur = cur->next) {
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
/* Don't do anything on the global call reference call record. */
continue;
}
if (cur->outboundbroadcast) {
/* Does this master call have a subcall on the link that went down? */
call = NULL;
for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
if (cur->subcalls[idx] && cur->subcalls[idx]->pri == link) {
/* This subcall is on the link that went down. */
call = cur->subcalls[idx];
break;
}
}
if (!call) {
/* No subcall is on the link that went down. */
continue;
}
} else if (cur->pri != link) {
/* This call is not on the link that went down. */
continue;
} else {
call = cur;
}
/*
* NOTE: We are gambling that no T309 timer's have had a chance
* to expire. They should not expire since we are either called
* immediately after the q931_dl_indication() or after a timeout
* of 0.
*/
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "Cancel call cref=%d on channel %d in state %d (%s)\n",
call->cr, call->channelno, call->ourcallstate,
q931_call_state_str(call->ourcallstate));
}
call->pri = ctrl;/* Point to a safer place until the call is destroyed. */
pri_schedule_del(ctrl, call->retranstimer);
call->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall, call);
}
}
/* Receive an indication from Layer 2 */
void q931_dl_indication(struct pri *link, int event)
{ {
struct q931_call *cur; struct q931_call *cur;
struct q931_call *call; struct q931_call *call;
@ -8467,16 +8436,73 @@ void q931_dl_indication(struct pri *link, int event)
/* Find the master - He has the call pool */ /* Find the master - He has the call pool */
ctrl = PRI_MASTER(link); ctrl = PRI_MASTER(link);
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "TEI=%d DL event: %s(%d)\n", link->tei,
q931_dl_event2str(event), event);
}
if (BRI_TE_PTMP(ctrl)) { if (BRI_TE_PTMP(ctrl)) {
/* The link is always the master */ /* The link is always the master */
link = ctrl; link = ctrl;
} }
switch (event) { switch (event) {
case PRI_EVENT_DCHAN_DOWN: case Q931_DL_EVENT_TEI_REMOVAL:
if (ctrl->debug & PRI_DEBUG_Q931_STATE) { if (!BRI_NT_PTMP(ctrl)) {
pri_message(ctrl, "DL-RELEASE indication (link is DOWN)\n"); /* Only NT PTMP has anything to worry about when the TEI is removed. */
break;
} }
/*
* For NT PTMP, this deviation from the specifications is needed
* because we have no way to re-associate any T309 calls on the
* removed TEI.
*/
for (cur = *ctrl->callpool; cur; cur = cur->next) {
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
/* Don't do anything on the global call reference call record. */
continue;
}
if (cur->outboundbroadcast) {
/* Does this master call have a subcall on the link that went down? */
call = NULL;
for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
if (cur->subcalls[idx] && cur->subcalls[idx]->pri == link) {
/* This subcall is on the link that went down. */
call = cur->subcalls[idx];
break;
}
}
if (!call) {
/* No subcall is on the link that went down. */
continue;
}
} else if (cur->pri != link) {
/* This call is not on the link that went down. */
continue;
} else {
call = cur;
}
/*
* NOTE: We are gambling that no T309 timer's have had a chance
* to expire. They should not expire since we are either called
* immediately after the Q931_DL_EVENT_DL_RELEASE_xxx or after a
* timeout of 0.
*/
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "Cancel call cref=%d on channel %d in state %d (%s)\n",
call->cr, call->channelno, call->ourcallstate,
q931_call_state_str(call->ourcallstate));
}
call->pri = ctrl;/* Point to a safer place until the call is destroyed. */
pri_schedule_del(ctrl, call->retranstimer);
call->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall,
call);
}
break;
case Q931_DL_EVENT_DL_RELEASE_IND:
case Q931_DL_EVENT_DL_RELEASE_CONFIRM:
for (cur = *ctrl->callpool; cur; cur = cur->next) { for (cur = *ctrl->callpool; cur; cur = cur->next) {
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) { if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
/* Don't do anything on the global call reference call record. */ /* Don't do anything on the global call reference call record. */
@ -8557,10 +8583,8 @@ void q931_dl_indication(struct pri *link, int event)
} }
} }
break; break;
case PRI_EVENT_DCHAN_UP: case Q931_DL_EVENT_DL_ESTABLISH_IND:
if (ctrl->debug & PRI_DEBUG_Q931_STATE) { case Q931_DL_EVENT_DL_ESTABLISH_CONFIRM:
pri_message(ctrl, "DL-ESTABLISH indication (link is UP)\n");
}
for (cur = *ctrl->callpool; cur; cur = cur->next) { for (cur = *ctrl->callpool; cur; cur = cur->next) {
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) { if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
/* Don't do anything on the global call reference call record. */ /* Don't do anything on the global call reference call record. */
@ -8605,6 +8629,14 @@ void q931_dl_indication(struct pri *link, int event)
case Q931_CALL_STATE_RELEASE_REQUEST: case Q931_CALL_STATE_RELEASE_REQUEST:
break; break;
default: default:
if (event == Q931_DL_EVENT_DL_ESTABLISH_CONFIRM) {
/*
* Lets not send a STATUS message for this call as we
* requested the link to be established as a likely
* result of this call.
*/
break;
}
/* /*
* The STATUS message sent here is not required by Q.931, * The STATUS message sent here is not required by Q.931,
* but it may help anyway. * but it may help anyway.