[svn-commits] rmudgett: branch 1.4 r1918 - /branches/1.4/q921.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Aug 30 12:53:41 CDT 2010


Author: rmudgett
Date: Mon Aug 30 12:53:33 2010
New Revision: 1918

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1918
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:
    branches/1.4/q921.c

Modified: branches/1.4/q921.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q921.c?view=diff&rev=1918&r1=1917&r2=1918
==============================================================================
--- branches/1.4/q921.c (original)
+++ branches/1.4/q921.c Mon Aug 30 12:53:33 2010
@@ -196,19 +196,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)
@@ -397,6 +427,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;
@@ -619,9 +657,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 */
@@ -636,9 +681,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:
@@ -698,6 +741,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",
@@ -1049,6 +1094,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");
@@ -1072,10 +1119,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??? */
 }
@@ -1182,6 +1236,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 */
@@ -1192,7 +1258,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;
@@ -1200,6 +1265,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);
@@ -1215,19 +1281,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)
@@ -2020,19 +2081,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 svn-commits mailing list