[svn-commits] rmudgett: branch rmudgett/t312 r2224 - /team/rmudgett/t312/q931.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Feb 25 23:30:11 CST 2011


Author: rmudgett
Date: Fri Feb 25 23:30:06 2011
New Revision: 2224

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=2224
Log:
BRI NT PTMP incoming call T309 processing loses B channel and has invalid read.

The lost B channel is because the last subcall needed to request a fake
clearing.

Invalid read is because the master call is destroyed before moving on to
the next call record.

Modified:
    team/rmudgett/t312/q931.c

Modified: team/rmudgett/t312/q931.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/t312/q931.c?view=diff&rev=2224&r1=2223&r2=2224
==============================================================================
--- team/rmudgett/t312/q931.c (original)
+++ team/rmudgett/t312/q931.c Fri Feb 25 23:30:06 2011
@@ -4228,6 +4228,56 @@
 	return count;
 }
 
+static int pri_internal_clear(struct q931_call *call);
+
+/*!
+ * \brief Fake RELEASE for NT-PTMP initiated SETUPs w/o response
+ *
+ * \param param call Call is not a subcall call record.
+ */
+static void pri_fake_clearing(struct q931_call *call)
+{
+	struct pri *ctrl;
+
+	ctrl = call->pri;
+	if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+		pri_message(ctrl, "Fake clearing.  cref:%d\n", call->cr);
+	}
+
+	/*
+	 * This does not need to be running since this is what we are
+	 * doing right now anyway.
+	 */
+	pri_schedule_del(ctrl, call->fake_clearing_timer);
+	call->fake_clearing_timer = 0;
+
+	if (call->cause == -1) {
+		/* Ensure that there is a resonable cause code. */
+		call->cause = PRI_CAUSE_NO_USER_RESPONSE;
+	}
+	if (pri_internal_clear(call) == Q931_RES_HAVEEVENT) {
+		ctrl->schedev = 1;
+	}
+}
+
+static void pri_fake_clearing_expiry(void *data)
+{
+	struct q931_call *master = data;
+
+	master->fake_clearing_timer = 0;
+	pri_fake_clearing(master);
+}
+
+static void pri_create_fake_clearing(struct pri *ctrl, struct q931_call *master)
+{
+	if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+		pri_message(ctrl, "Fake clearing requested.  cref:%d\n", master->cr);
+	}
+	pri_schedule_del(ctrl, master->fake_clearing_timer);
+	master->fake_clearing_timer = pri_schedule_event(ctrl, 0, pri_fake_clearing_expiry,
+		master);
+}
+
 static void t312_expiry(void *data)
 {
 	struct q931_call *master = data;
@@ -4239,18 +4289,19 @@
 	}
 
 	master->t312_timer = 0;
-	switch (master->ourcallstate) {
-	case Q931_CALL_STATE_CALL_ABORT:
-		if (!q931_get_subcall_count(master)) {
-			/*
-			 * T312 has expired and no slaves are left so we can
-			 * destroy the master.
-			 */
+	if (!q931_get_subcall_count(master)) {
+		/* No subcalls remain. */
+		switch (master->ourcallstate) {
+		case Q931_CALL_STATE_CALL_ABORT:
+			/* We can destroy the master. */
 			q931_destroycall(ctrl, master);
-		}
-		break;
-	default:
-		break;
+			break;
+		default:
+			/* Let the upper layer know about the lack of call prospects. */
+			UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_ABORT);
+			pri_fake_clearing(master);
+			break;
+		}
 	}
 }
 
@@ -4337,10 +4388,23 @@
 					return;
 				}
 
-				/* No slaves left.  We can safely destroy the master. */
+				/* No slaves left. */
+				switch (cur->ourcallstate) {
+				case Q931_CALL_STATE_CALL_ABORT:
+					break;
+				default:
+					/* Let the upper layer know about the call clearing. */
+					UPDATE_OURCALLSTATE(ctrl, cur, Q931_CALL_STATE_CALL_ABORT);
+					pri_create_fake_clearing(ctrl, cur);
+					return;
+				}
+
+				/* We can try to destroy the master now. */
 			} else {
 				/* Destroy any slaves that may be present as well. */
+				slavesleft = 0;
 				for (i = 0; i < ARRAY_LEN(cur->subcalls); ++i) {
+					++slavesleft;
 					if (cur->subcalls[i]) {
 						q931_destroy_subcall(cur, i);
 					}
@@ -4353,6 +4417,12 @@
 				 * the master call record.
 				 */
 				return;
+			}
+			if (slavesleft) {
+				/* This is likely not good. */
+				pri_error(ctrl,
+					"Destroyed %d subcalls unconditionally with the master.  cref:%d\n",
+					slavesleft, cur->cr);
 			}
 
 			/* Master call or normal call destruction. */
@@ -5733,44 +5803,6 @@
 		call);
 }
 
-static int pri_internal_clear(struct q931_call *c);
-
-/*!
- * \brief Fake RELEASE for NT-PTMP initiated SETUPs w/o response
- *
- * \param param call Call is not a subcall call record.
- */
-static void pri_fake_clearing(struct q931_call *call)
-{
-	struct pri *ctrl;
-
-	ctrl = call->pri;
-	if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
-		pri_message(ctrl, "Fake clearing.  cref:%d\n", call->cr);
-	}
-	if (pri_internal_clear(call) == Q931_RES_HAVEEVENT) {
-		ctrl->schedev = 1;
-	}
-}
-
-static void pri_fake_clearing_expiry(void *data)
-{
-	struct q931_call *master = data;
-
-	master->fake_clearing_timer = 0;
-	pri_fake_clearing(master);
-}
-
-static void pri_create_fake_clearing(struct pri *ctrl, struct q931_call *master)
-{
-	if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
-		pri_message(ctrl, "Fake clearing requested.  cref:%d\n", master->cr);
-	}
-	pri_schedule_del(ctrl, master->fake_clearing_timer);
-	master->fake_clearing_timer = pri_schedule_event(ctrl, 0, pri_fake_clearing_expiry,
-		master);
-}
-
 static void t303_expiry(void *data)
 {
 	struct q931_call *c = data;/* Call is not a subcall call record. */
@@ -9263,6 +9295,7 @@
 void q931_dl_event(struct q921_link *link, enum Q931_DL_EVENT event)
 {
 	struct q931_call *cur;
+	struct q931_call *cur_next;
 	struct q931_call *call;
 	struct pri *ctrl;
 	int idx;
@@ -9341,7 +9374,10 @@
 		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) {
+			/* The master call could get destroyed if the last subcall dies. */
+			cur_next = cur->next;
+
 			if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
 				/* Don't do anything on the global call reference call record. */
 				continue;




More information about the svn-commits mailing list