[libpri-commits] rmudgett: branch rmudgett/issue17570 r1868 - /team/rmudgett/issue17570/q921.c
SVN commits to the libpri project
libpri-commits at lists.digium.com
Tue Aug 10 14:19:14 CDT 2010
Author: rmudgett
Date: Tue Aug 10 14:19:11 2010
New Revision: 1868
URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1868
Log:
ISDN BRI does not recover from line faults
Q.921 was getting stuck in state 2 (Q921_ASSIGN_AWAITING_TEI). For some
reason the network was removing the TEI. Libpri then immediately tried to
get a new TEI assigned. The network did not reply to the N202(3) attempts
to get a new TEI. Libpri then just gave up trying but did not leave the
state. Some paths in Q.921 Figure B.3 were not implemented.
Q.921 now transitions to the Q921_TEI_UNASSIGNED state when the N202 count
is exceeded. Q.921 will wait there until an incoming or outgoing call is
attempted.
* Fixed initializing the n202_counter. Not initializing the n202_counter
would cause the Q921_TEI_IDENTITY_REQUEST to unexpectedly not go out and
due to how state transitions were done, Q.921 would get stuck in the
Q921_ASSIGN_AWAITING_TEI state.
* Fixed start T202 timer fail causing Q.921 to get stuck in the
Q921_ASSIGN_AWAITING_TEI state if the network did not respond to the
request.
* Fixed handling of Q921_TEI_IDENTITY_REMOVE to do the MDL-REMOVE
primitive (q921_mdl_remove()) instead of transitioning directly to the
Q921_TEI_UNASSIGNED state. Necessary state clean-up was not getting done.
* Minor tweaks to q921_mdl_remove(). The worst problem was erroneously
generating an error message.
* Fixed potential for sending I-frames with an invalid TEI. The I-frame
could have been queued when Q.921 did not have an assigned TEI.
* Fixed testing of the q931_receive() return value when a UI-frame is
received.
(closes issue #17570)
Reported by: jcovert
Patches:
issue17570_v1.4.11.3_v3.patch uploaded by rmudgett (license 664)
issue17570_v1.4_v3.patch uploaded by rmudgett (license 664)
Tested by: jcovert, rmudgett
Modified:
team/rmudgett/issue17570/q921.c
Modified: team/rmudgett/issue17570/q921.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/issue17570/q921.c?view=diff&rev=1868&r1=1867&r2=1868
==============================================================================
--- team/rmudgett/issue17570/q921.c (original)
+++ team/rmudgett/issue17570/q921.c Tue Aug 10 14:19:11 2010
@@ -195,19 +195,49 @@
free(f);
}
-static void q921_tei_request(void *vpri)
+static void t202_expire(void *vpri)
{
struct pri *ctrl = (struct pri *)vpri;
- ctrl->n202_counter++;
- if (ctrl->n202_counter > ctrl->timers[PRI_TIMER_N202]) {
- pri_error(ctrl, "Unable to receive TEI from network!\n");
- ctrl->n202_counter = 0;
+
+ /* Start the TEI request timer. */
+ pri_schedule_del(ctrl, ctrl->t202_timer);
+ ctrl->t202_timer =
+ pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T202], t202_expire, ctrl);
+
+ ++ctrl->n202_counter;
+ if (!ctrl->t202_timer || ctrl->n202_counter > ctrl->timers[PRI_TIMER_N202]) {
+ if (!ctrl->t202_timer) {
+ pri_error(ctrl, "Could not start T202 timer.");
+ } else {
+ pri_schedule_del(ctrl, ctrl->t202_timer);
+ ctrl->t202_timer = 0;
+ }
+ pri_error(ctrl, "Unable to receive TEI from network in state %d(%s)!\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ switch (ctrl->q921_state) {
+ case Q921_ASSIGN_AWAITING_TEI:
+ break;
+ case Q921_ESTABLISH_AWAITING_TEI:
+ q921_discard_iqueue(ctrl);
+ /* DL-RELEASE indication */
+ q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
+ break;
+ default:
+ break;
+ }
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
return;
}
+
+ /* Send TEI request */
ctrl->ri = random() % 65535;
q921_send_tei(PRI_MASTER(ctrl), Q921_TEI_IDENTITY_REQUEST, ctrl->ri, Q921_TEI_GROUP, 1);
- pri_schedule_del(ctrl, ctrl->t202_timer);
- ctrl->t202_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T202], q921_tei_request, ctrl);
+}
+
+static void q921_tei_request(struct pri *ctrl)
+{
+ ctrl->n202_counter = 0;
+ t202_expire(ctrl);
}
static void q921_send_ua(struct pri *ctrl, int pfbit)
@@ -396,6 +426,14 @@
if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
pri_message(ctrl, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, ctrl->timers[PRI_TIMER_K]);
f->transmitted++;
+
+ /*
+ * Send the frame out on the assigned TEI.
+ * Done now because the frame may have been queued before we
+ * had an assigned TEI.
+ */
+ f->h.h.tei = ctrl->tei;
+
f->h.n_s = ctrl->v_s;
f->h.n_r = ctrl->v_r;
f->h.ft = 0;
@@ -618,9 +656,16 @@
/* We don't care what the tei is, since we only support one sub and one TEI */
ctrl = PRI_MASTER(vpri)->subchannel;
- if (ctrl->q921_state == Q921_TEI_UNASSIGNED) {
+ switch (ctrl->q921_state) {
+ case Q921_TEI_UNASSIGNED:
+ q921_setstate(ctrl, Q921_ESTABLISH_AWAITING_TEI);
q921_tei_request(ctrl);
+ break;
+ case Q921_ASSIGN_AWAITING_TEI:
q921_setstate(ctrl, Q921_ESTABLISH_AWAITING_TEI);
+ break;
+ default:
+ break;
}
} else {
/* Should just be PTP modes, which shouldn't have subs */
@@ -635,9 +680,7 @@
ctrl->l3initiated = 1;
q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
/* For all rest, we've done the work to get us up prior to this and fall through */
- case Q921_TEI_UNASSIGNED:
case Q921_ESTABLISH_AWAITING_TEI:
- case Q921_ASSIGN_AWAITING_TEI:
case Q921_TIMER_RECOVERY:
case Q921_AWAITING_ESTABLISHMENT:
case Q921_MULTI_FRAME_ESTABLISHED:
@@ -697,6 +740,8 @@
pri_error(ctrl, "!! Out of memory for Q.921 transmit\n");
return -1;
}
+ case Q921_TEI_UNASSIGNED:
+ case Q921_ASSIGN_AWAITING_TEI:
case Q921_AWAITING_RELEASE:
default:
pri_error(ctrl, "Cannot transmit frames in state %d(%s)\n",
@@ -1048,6 +1093,8 @@
q921_establish_data_link(ctrl);
ctrl->l3initiated = 1;
q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
+ ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP;
+ res = &ctrl->ev;
break;
default:
pri_error(ctrl, "Error 3\n");
@@ -1071,10 +1118,17 @@
if (!BRI_TE_PTMP(ctrl))
return NULL;
+ if (ctrl->subchannel->q921_state < Q921_TEI_ASSIGNED) {
+ /* We do not have a TEI. */
+ return NULL;
+ }
+
+ /* If it's addressed to the group TEI or to our TEI specifically, we respond */
if ((tei == Q921_TEI_GROUP) || (tei == ctrl->subchannel->tei)) {
- q921_setstate(ctrl->subchannel, Q921_TEI_UNASSIGNED);
+ q921_mdl_remove(ctrl->subchannel);
q921_start(ctrl->subchannel);
}
+ break;
}
return res; /* Do we need to return something??? */
}
@@ -1180,6 +1234,18 @@
static void q921_mdl_remove(struct pri *ctrl)
{
+ int mdl_free_me;
+
+ if (BRI_NT_PTMP(ctrl)) {
+ if (ctrl == PRI_MASTER(ctrl)) {
+ pri_error(ctrl, "Bad bad bad! Cannot MDL-REMOVE master\n");
+ return;
+ }
+ mdl_free_me = 1;
+ } else {
+ mdl_free_me = 0;
+ }
+
switch (ctrl->q921_state) {
case Q921_TEI_ASSIGNED:
/* XXX: deviation! Since we don't have a UI queue, we just discard our I-queue */
@@ -1190,7 +1256,6 @@
q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
-
stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
@@ -1198,6 +1263,7 @@
q921_discard_iqueue(ctrl);
/* DL-RELEASE confirm */
stop_t200(ctrl);
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
case Q921_MULTI_FRAME_ESTABLISHED:
q921_discard_iqueue(ctrl);
@@ -1213,19 +1279,14 @@
q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN);
stop_t200(ctrl);
q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
+ break;
default:
- pri_error(ctrl, "Cannot handle MDL remove when PRI is in state %d(%s)\n",
+ pri_error(ctrl, "MDL-REMOVE when in state %d(%s)\n",
ctrl->q921_state, q921_state2str(ctrl->q921_state));
- break;
- }
-
- if (BRI_NT_PTMP(ctrl) && ctrl->q921_state == Q921_TEI_UNASSIGNED) {
- if (ctrl == PRI_MASTER(ctrl)) {
- pri_error(ctrl, "Bad bad bad! Asked to free master\n");
- return;
- }
- ctrl->mdl_free_me = 1;
- }
+ return;
+ }
+
+ ctrl->mdl_free_me = mdl_free_me;
}
static int q921_mdl_handle_network_error(struct pri *ctrl, char error)
@@ -2006,19 +2067,15 @@
break;
} else if (!h->u.m2) {
if ((ctrl->sapi == Q921_SAPI_LAYER2_MANAGEMENT) && (ctrl->tei == Q921_TEI_GROUP)) {
-
pri_error(ctrl, "I should never be called\n");
- q921_receive_MDL(ctrl, (q921_u *)h, len);
-
+ ev = q921_receive_MDL(ctrl, (q921_u *)h, len);
} else {
int res;
res = q931_receive(ctrl, ctrl->tei, (q931_h *) h->u.data, len - 3);
- if (res == -1) {
- ev = NULL;
+ if (res != -1 && (res & Q931_RES_HAVEEVENT)) {
+ ev = &ctrl->ev;
}
- if (res & Q931_RES_HAVEEVENT)
- ev = &ctrl->ev;
}
}
break;
More information about the libpri-commits
mailing list