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_dl_tei_removal(struct pri *link);
void q931_dl_indication(struct pri *link, int event);
enum Q931_DL_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_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:
q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
break;
default:
break;
@ -671,7 +671,7 @@ static void t200_expire(void *vpri)
q921_mdl_error(ctrl, 'G');
q921_setstate(ctrl, Q921_TEI_ASSIGNED);
/* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
}
break;
case Q921_AWAITING_RELEASE:
@ -682,6 +682,7 @@ static void t200_expire(void *vpri)
} else {
q921_mdl_error(ctrl, 'H');
/* DL-RELEASE confirm */
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
q921_setstate(ctrl, Q921_TEI_ASSIGNED);
}
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)
{
pri_event *res = NULL;
int delay_q931_dl_indication;
enum Q931_DL_EVENT delay_q931_dl_event;
switch (ctrl->q921_state) {
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) {
q921_discard_iqueue(ctrl);
/* DL-ESTABLISH indication */
delay_q931_dl_indication = 1;
delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
} else {
delay_q931_dl_indication = 0;
delay_q931_dl_event = Q931_DL_EVENT_NONE;
}
stop_t200(ctrl);
start_t203(ctrl);
ctrl->v_s = ctrl->v_a = ctrl->v_r = 0;
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. */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_UP);
q931_dl_event(ctrl, delay_q931_dl_event);
}
break;
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);
ctrl->v_s = ctrl->v_a = ctrl->v_r = 0;
/* DL-ESTABLISH indication */
//delay_q931_dl_indication = 1;
delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
if (PTP_MODE(ctrl)) {
ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP;
res = &ctrl->ev;
}
start_t203(ctrl);
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. */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_UP);
q931_dl_event(ctrl, delay_q931_dl_event);
}
break;
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_send_ua(ctrl, h->u.p_f);
/* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl);
if (ctrl->q921_state == Q921_MULTI_FRAME_ESTABLISHED)
stop_t203(ctrl);
@ -1402,20 +1402,21 @@ static void q921_mdl_remove(struct pri *ctrl)
case Q921_AWAITING_ESTABLISHMENT:
q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
case Q921_AWAITING_RELEASE:
q921_discard_iqueue(ctrl);
/* DL-RELEASE confirm */
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
case Q921_MULTI_FRAME_ESTABLISHED:
q921_discard_iqueue(ctrl);
/* 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_t203(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
@ -1423,7 +1424,7 @@ static void q921_mdl_remove(struct pri *ctrl)
case Q921_TIMER_RECOVERY:
q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
@ -1433,7 +1434,7 @@ static void q921_mdl_remove(struct pri *ctrl)
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
@ -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)
{
pri_event *res = NULL;
int delay_q931_dl_indication;
enum Q931_DL_EVENT delay_q931_dl_event;
if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
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;
}
delay_q931_dl_indication = 0;
delay_q931_dl_event = Q931_DL_EVENT_NONE;
if (!ctrl->l3initiated) {
if (ctrl->v_s != ctrl->v_a) {
q921_discard_iqueue(ctrl);
/* DL-ESTABLISH indication */
delay_q931_dl_indication = 1;
delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
}
} else {
ctrl->l3initiated = 0;
/* DL-ESTABLISH confirm */
delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_CONFIRM;
}
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;
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. */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_UP);
q931_dl_event(ctrl, delay_q931_dl_event);
}
break;
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');
} else {
/* DL-RELEASE confirm */
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
stop_t200(ctrl);
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);
/* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_ASSIGNED);
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)
break;
/* DL-RELEASE confirm */
q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_ASSIGNED);
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
* 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.
* \return DL event string
*/
static const char *q931_dl_event2str(enum Q931_DL_EVENT event)
{
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
*/
void q931_dl_tei_removal(struct pri *link)
{
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)
void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
{
struct q931_call *cur;
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 */
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)) {
/* The link is always the master */
link = ctrl;
}
switch (event) {
case PRI_EVENT_DCHAN_DOWN:
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "DL-RELEASE indication (link is DOWN)\n");
case Q931_DL_EVENT_TEI_REMOVAL:
if (!BRI_NT_PTMP(ctrl)) {
/* 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) {
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
/* 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;
case PRI_EVENT_DCHAN_UP:
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "DL-ESTABLISH indication (link is UP)\n");
}
case Q931_DL_EVENT_DL_ESTABLISH_IND:
case Q931_DL_EVENT_DL_ESTABLISH_CONFIRM:
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. */
@ -8605,6 +8629,14 @@ void q931_dl_indication(struct pri *link, int event)
case Q931_CALL_STATE_RELEASE_REQUEST:
break;
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,
* but it may help anyway.