From 384ae1e6889ee1fa8f85aa1470ce7d6720eae2c3 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 13 Sep 2010 21:21:37 +0000 Subject: [PATCH] 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 --- pri_q931.h | 11 +++- q921.c | 48 +++++++------- q931.c | 186 +++++++++++++++++++++++++++++++---------------------- 3 files changed, 144 insertions(+), 101 deletions(-) diff --git a/pri_q931.h b/pri_q931.h index 06825f0..4c317ae 100644 --- a/pri_q931.h +++ b/pri_q931.h @@ -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); diff --git a/q921.c b/q921.c index 8e0b614..2a69dc2 100644 --- a/q921.c +++ b/q921.c @@ -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; diff --git a/q931.c b/q931.c index 258b204..0d40f9b 100644 --- a/q931.c +++ b/q931.c @@ -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.