[svn-commits] rmudgett: branch 1.4 r1630 - /branches/1.4/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Apr 19 17:40:43 CDT 2010


Author: rmudgett
Date: Mon Apr 19 17:40:41 2010
New Revision: 1630

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1630
Log:
PTMP NT mode call reference value ambiguity.

Since the TE side can pick CR values independently, the TE CR needs to be
qualified by TEI to distinguish CR values from other devices.  Without
doing this, multiple phones on the BRI line will have intermittent call
failures.

JIRA LIBPRI-30

Also eliminated some wierdness in q931_status() and several places where
it is called.

Modified:
    branches/1.4/pri_internal.h
    branches/1.4/pri_q931.h
    branches/1.4/pridump.c
    branches/1.4/q931.c

Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=1630&r1=1629&r2=1630
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Mon Apr 19 17:40:41 2010
@@ -513,8 +513,6 @@
 							   -1 - No reverse charging
 							    1 - Reverse charging
 							0,2-7 - Reserved for future use */
-	/*! \brief TEI associated with call */
-	int tei;
 	int t303_timer;
 	int t303_expirycnt;
 
@@ -719,6 +717,7 @@
 }
 
 #define Q931_DUMMY_CALL_REFERENCE	-1
+#define Q931_CALL_REFERENCE_FLAG	0x8000	/* Identify which end allocted the CR. */
 
 /*!
  * \brief Deterimine if the given call control pointer is a dummy call.

Modified: branches/1.4/pri_q931.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_q931.h?view=diff&rev=1630&r1=1629&r2=1630
==============================================================================
--- branches/1.4/pri_q931.h (original)
+++ branches/1.4/pri_q931.h Mon Apr 19 17:40:41 2010
@@ -486,10 +486,11 @@
 
 extern int q931_call_setcrv(struct pri *pri, q931_call *call, int crv, int callmode);
 
-extern q931_call *q931_new_call(struct pri *pri);
+struct q931_call *q931_find_call(struct pri *ctrl, int cr);
+struct q931_call *q931_new_call(struct pri *pri);
 
 extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req);
-extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx);
+void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx);
 
 void q931_destroycall(struct pri *pri, q931_call *c);
 

Modified: branches/1.4/pridump.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pridump.c?view=diff&rev=1630&r1=1629&r2=1630
==============================================================================
--- branches/1.4/pridump.c (original)
+++ branches/1.4/pridump.c Mon Apr 19 17:40:41 2010
@@ -73,7 +73,7 @@
 	q921_h *h = (q921_h *)buf;
 	q921_dump(pri, h, len, 1, txrx);
 	if (!((h->h.data[0] & Q921_FRAMETYPE_MASK) & 0x3)) {
-		q931_dump(pri, (q931_h *)(h->i.data), len - 4 - 2 /* FCS */, txrx);
+		q931_dump(pri, h->h.tei, (q931_h *)(h->i.data), len - 4 - 2 /* FCS */, txrx);
 	}
 	fflush(stdout);
 	fflush(stderr);

Modified: branches/1.4/q931.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q931.c?view=diff&rev=1630&r1=1629&r2=1630
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Mon Apr 19 17:40:41 2010
@@ -3396,7 +3396,7 @@
 		cr = h->crv[0];
 		if (cr & 0x80) {
 			cr &= ~0x80;
-			cr |= 0x8000;
+			cr |= Q931_CALL_REFERENCE_FLAG;
 		}
 		break;
 	case 0:
@@ -3502,88 +3502,164 @@
 	}
 }
 
-static q931_call *q931_getcall(struct pri *ctrl, int cr)
-{
-	q931_call *cur;
-	q931_call *prev;
+/*!
+ * \internal
+ * \brief Create a new call record.
+ *
+ * \param ctrl D channel controller.
+ * \param cr Call Reference identifier.
+ *
+ * \retval record on success.
+ * \retval NULL on error.
+ */
+static struct q931_call *q931_create_call_record(struct pri *ctrl, int cr)
+{
+	struct q931_call *call;
+	struct q931_call *prev;
+	struct pri *master;
+
+	if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+		pri_message(ctrl, "-- Making new call for cref %d\n", cr);
+	}
+
+	call = calloc(1, sizeof(*call));
+	if (!call) {
+		return NULL;
+	}
+
+	/* Initialize call structure. */
+	q931_init_call_record(ctrl, call, cr);
+
+	/* Find the master - He has the call pool */
+	master = PRI_MASTER(ctrl);
+
+	/* Append to the list end */
+	if (*master->callpool) {
+		/* Find the list end. */
+		for (prev = *master->callpool; prev->next; prev = prev->next) {
+		}
+		prev->next = call;
+	} else {
+		/* List was empty. */
+		*master->callpool = call;
+	}
+
+	return call;
+}
+
+/*!
+ * \brief Find a call in the active call pool.
+ *
+ * \param ctrl D channel controller.
+ * \param cr Call Reference identifier.
+ *
+ * \retval call if found.
+ * \retval NULL if not found.
+ */
+struct q931_call *q931_find_call(struct pri *ctrl, int cr)
+{
+	struct q931_call *cur;
 	struct pri *master;
 
 	if (cr == Q931_DUMMY_CALL_REFERENCE) {
 		return ctrl->dummy_call;
 	}
 
-	/* Find the master  - He has the call pool */
+	/* Find the master - He has the call pool */
 	master = PRI_MASTER(ctrl);
 
-	cur = *master->callpool;
-	prev = NULL;
-	while (cur) {
-		if (cur->cr == cr) {
-			/* Found existing call. */
-			switch (ctrl->switchtype) {
-			case PRI_SWITCH_GR303_EOC:
-			case PRI_SWITCH_GR303_EOC_PATH:
-			case PRI_SWITCH_GR303_TMC:
-			case PRI_SWITCH_GR303_TMC_SWITCHING:
+	if (BRI_NT_PTMP(ctrl) && !(cr & Q931_CALL_REFERENCE_FLAG)) {
+		if (ctrl->tei == Q921_TEI_GROUP) {
+			/* Broadcast TEI.  This is bad.  We are using the wrong ctrl structure. */
+			pri_error(ctrl, "Looking for cref %d when using broadcast TEI.\n", cr);
+			return NULL;
+		}
+
+		/* We are looking for a call reference value that the other side allocated. */
+		for (cur = *master->callpool; cur; cur = cur->next) {
+			if (cur->cr == cr && cur->pri == ctrl) {
+				/* Found existing call.  The call reference and TEI matched. */
 				break;
-			default:
-				if (!ctrl->bri) {
-					/* PRI is set to whoever called us */
-					cur->pri = ctrl;
+			}
+		}
+	} else {
+		for (cur = *master->callpool; cur; cur = cur->next) {
+			if (cur->cr == cr) {
+				/* Found existing call. */
+				switch (ctrl->switchtype) {
+				case PRI_SWITCH_GR303_EOC:
+				case PRI_SWITCH_GR303_EOC_PATH:
+				case PRI_SWITCH_GR303_TMC:
+				case PRI_SWITCH_GR303_TMC_SWITCHING:
+					break;
+				default:
+					if (!ctrl->bri) {
+						/* PRI is set to whoever called us */
+						cur->pri = ctrl;
+					}
+					break;
 				}
 				break;
 			}
-			return cur;
-		}
-		prev = cur;
-		cur = cur->next;
-	}
-
-	/* No call exists, make a new one */
-	if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
-		pri_message(ctrl, "-- Making new call for cr %d\n", cr);
-	}
-
-	cur = calloc(1, sizeof(*cur));
-	if (!cur) {
-		return NULL;
-	}
-
-	/* Initialize call structure. */
-	q931_init_call_record(ctrl, cur, cr);
-
-	/* Append to end of list */
-	if (prev) {
-		prev->next = cur;
-	} else {
-		*master->callpool = cur;
-	}
-
+		}
+	}
 	return cur;
 }
 
-q931_call *q931_new_call(struct pri *ctrl)
-{
-	q931_call *cur;
-
+static struct q931_call *q931_getcall(struct pri *ctrl, int cr)
+{
+	struct q931_call *cur;
+
+	cur = q931_find_call(ctrl, cr);
+	if (cur) {
+		return cur;
+	}
+
+	/* No call record exists, make a new one */
+	return q931_create_call_record(ctrl, cr);
+}
+
+struct q931_call *q931_new_call(struct pri *ctrl)
+{
+	struct q931_call *cur;
+	struct pri *master;
+	int first_cref;
+	int cref;
+
+	/* Find the master - He has the call pool */
+	master = PRI_MASTER(ctrl);
+
+	/* Find a new call reference value. */
+	first_cref = master->cref;
 	do {
-		cur = *ctrl->callpool;
-		ctrl->cref++;
-		if (!ctrl->bri) {
-			if (ctrl->cref > 32767)
-				ctrl->cref = 1;
+		cref = Q931_CALL_REFERENCE_FLAG | master->cref;
+
+		/* Next call reference. */
+		++master->cref;
+		if (!master->bri) {
+			if (master->cref > 32767) {
+				master->cref = 1;
+			}
 		} else {
-			if (ctrl->cref > 127)
-				ctrl->cref = 1;
-		}
-		while(cur) {
-			if (cur->cr == (0x8000 | ctrl->cref))
+			if (master->cref > 127) {
+				master->cref = 1;
+			}
+		}
+
+		/* Is the call reference value in use? */
+		for (cur = *master->callpool; cur; cur = cur->next) {
+			if (cur->cr == cref) {
+				/* Yes it is in use. */
+				if (first_cref == master->cref) {
+					/* All call reference values are in use! */
+					return NULL;
+				}
 				break;
-			cur = cur->next;
-		}
-	} while(cur);
-
-	return q931_getcall(ctrl, ctrl->cref | 0x8000);
+			}
+		}
+	} while (cur);
+
+	return q931_create_call_record(ctrl, cref);
 }
 
 static void stop_t303(struct q931_call *call);
@@ -3797,7 +3873,7 @@
 	return code2str(disc, discs, sizeof(discs) / sizeof(discs[0]));
 }
 
-void q931_dump(struct pri *ctrl, q931_h *h, int len, int txrx)
+void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx)
 {
 	q931_mh *mh;
 	char c;
@@ -3809,11 +3885,12 @@
 	c = txrx ? '>' : '<';
 	pri_message(ctrl, "%c Protocol Discriminator: %s (%d)  len=%d\n", c, disc2str(h->pd), h->pd, len);
 	cref = q931_cr(h);
-	pri_message(ctrl, "%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n",
-		c, h->crlen, cref & 0x7FFF, cref & 0x7FFF,
-		(cref == Q931_DUMMY_CALL_REFERENCE)
+	pri_message(ctrl, "%c TEI=%d Call Ref: len=%2d (reference %d/0x%X) (%s)\n",
+		c, tei, h->crlen, cref & ~Q931_CALL_REFERENCE_FLAG,
+		cref & ~Q931_CALL_REFERENCE_FLAG, (cref == Q931_DUMMY_CALL_REFERENCE)
 			? "Dummy"
-			: (cref & 0x8000) ? "Terminator" : "Originator");
+			: (cref & Q931_CALL_REFERENCE_FLAG)
+				? "Sent to originator" : "Sent from originator");
 
 	/* Message header begins at the end of the call reference number */
 	mh = (q931_mh *)(h->contents + h->crlen);
@@ -3885,19 +3962,20 @@
 	} else if (!ctrl->bri) {
 		/* Two bytes of Call Reference. */
 		h->crlen = 2;
-		/* Invert the top bit to make it from our sense */
-		crv = (unsigned) call->cr;
-		h->crv[0] = ((crv >> 8) ^ 0x80) & 0xff;
+		if (ctrl->subchannel) {
+			/* On GR-303, Q931_CALL_REFERENCE_FLAG is always 0 */
+			crv = ((unsigned) call->cr) & ~Q931_CALL_REFERENCE_FLAG;
+		} else {
+			/* Invert the Q931_CALL_REFERENCE_FLAG to make it from our sense */
+			crv = ((unsigned) call->cr) ^ Q931_CALL_REFERENCE_FLAG;
+		}
+		h->crv[0] = (crv >> 8) & 0xff;
 		h->crv[1] = crv & 0xff;
-		if (ctrl->subchannel && !ctrl->bri) {
-			/* On GR-303, top bit is always 0 */
-			h->crv[0] &= 0x7f;
-		}
 	} else {
 		h->crlen = 1;
-		/* Invert the top bit to make it from our sense */
-		crv = (unsigned) call->cr;
-		h->crv[0] = (((crv >> 8) ^ 0x80) & 0x80) | (crv & 0x7f);
+		/* Invert the Q931_CALL_REFERENCE_FLAG to make it from our sense */
+		crv = ((unsigned) call->cr) ^ Q931_CALL_REFERENCE_FLAG;
+		h->crv[0] = ((crv >> 8) & 0x80) | (crv & 0x7f);
 	}
 	*hb = h;
 
@@ -3920,7 +3998,7 @@
 	   message body after the transmit puts the sections of the message in the
 	   right order in the log */
 	if (ctrl->debug & PRI_DEBUG_Q931_DUMP)
-		q931_dump(ctrl, h, len, 1);
+		q931_dump(ctrl, tei, h, len, 1);
 #ifdef LIBPRI_COUNTERS
 	ctrl->q931_txcount++;
 #endif
@@ -4048,7 +4126,7 @@
 	int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1;
 	int mt = ATT_SERVICE;
 
-	c = q931_getcall(ctrl, 0 | 0x8000);
+	c = q931_getcall(ctrl, 0 | Q931_CALL_REFERENCE_FLAG);
 	if (!c) {
 		return -1;
 	}
@@ -4072,30 +4150,12 @@
 
 static int status_ies[] = { Q931_CAUSE, Q931_IE_CALL_STATE, -1 };
 
-static int q931_status(struct pri *ctrl, q931_call *c, int cause)
-{
-	q931_call *cur = NULL;
-	if (!cause)
-		cause = PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY;
-	if (c->cr > -1)
-		cur = *ctrl->callpool;
-	while(cur) {
-		if (cur->cr == c->cr) {
-			cur->cause=cause;
-			cur->causecode = CODE_CCITT;
-			cur->causeloc = LOC_USER;
-			break;
-		}
-		cur = cur->next;
-	}
-	if (!cur) {
-		pri_message(ctrl, "YYY Here we get reset YYY\n");
-		/* something went wrong, respond with "no such call" */
-		c->ourcallstate = Q931_CALL_STATE_NULL;
-		c->peercallstate = Q931_CALL_STATE_NULL;
-		cur=c;
-	}
-	return send_message(ctrl, cur, Q931_STATUS, status_ies);
+static int q931_status(struct pri *ctrl, q931_call *call, int cause)
+{
+	call->cause = cause;
+	call->causecode = CODE_CCITT;
+	call->causeloc = LOC_USER;
+	return send_message(ctrl, call, Q931_STATUS, status_ies);
 }
 
 static int information_ies[] = { Q931_CALLED_PARTY_NUMBER, -1 };
@@ -4525,7 +4585,7 @@
 {
 	struct q931_call *c;
 
-	c = q931_getcall(ctrl, 0 | 0x8000);
+	c = q931_getcall(ctrl, 0 | Q931_CALL_REFERENCE_FLAG);
 	if (!c)
 		return -1;
 	if (!channel)
@@ -5772,7 +5832,7 @@
 int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
 {
 	q931_mh *mh;
-	q931_call *c;
+	struct q931_call *c;
 	q931_ie *ie;
 	unsigned int x;
 	int y;
@@ -5786,7 +5846,7 @@
 
 	memset(last_ie, 0, sizeof(last_ie));
 	if (ctrl->debug & PRI_DEBUG_Q931_DUMP)
-		q931_dump(ctrl, h, len, 0);
+		q931_dump(ctrl, tei, h, len, 0);
 #ifdef LIBPRI_COUNTERS
 	ctrl->q931_rxcount++;
 #endif
@@ -7010,7 +7070,7 @@
 		if (c->newcall) {
 			q931_release_complete(ctrl, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
 		} else
-			q931_status(ctrl,c, 0);
+			q931_status(ctrl,c, PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY);
 		break;
 	case Q931_SETUP_ACKNOWLEDGE:
 		stop_t303(c);
@@ -7432,7 +7492,8 @@
 /* Receive an indication from Layer 2 */
 void q931_dl_indication(struct pri *ctrl, int event)
 {
-	q931_call *cur = NULL;
+	struct q931_call *cur;
+	struct q931_call *winner;
 
 	/* Just return if T309 is not enabled. */
 	if (!ctrl || ctrl->timers[PRI_TIMER_T309] < 0)
@@ -7443,8 +7504,7 @@
 		if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
 			pri_message(ctrl, DBGHEAD "link is DOWN\n", DBGINFO);
 		}
-		cur = *ctrl->callpool;
-		while(cur) {
+		for (cur = *ctrl->callpool; cur; cur = cur->next) {
 			if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE) {
 				/* For a call in Active state, activate T309 only if there is no timer already running. */
 				if (!cur->retranstimer) {
@@ -7466,15 +7526,13 @@
 				pri_schedule_del(ctrl, cur->retranstimer);
 				cur->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall, cur);
 			}
-			cur = cur->next;
 		}
 		break;
 	case PRI_EVENT_DCHAN_UP:
 		if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
 			pri_message(ctrl, DBGHEAD "link is UP\n", DBGINFO);
 		}
-		cur = *ctrl->callpool;
-		while(cur) {
+		for (cur = *ctrl->callpool; cur; cur = cur->next) {
 			if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE && cur->retranstimer) {
 				if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
 					pri_message(ctrl,
@@ -7483,16 +7541,24 @@
 				}
 				pri_schedule_del(ctrl, cur->retranstimer);
 				cur->retranstimer = 0;
-				q931_status(ctrl, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
+				winner = q931_find_winning_call(cur);
+				if (winner) {
+					q931_status(ctrl, winner, PRI_CAUSE_NORMAL_UNSPECIFIED);
+				}
 			} else if (cur->ourcallstate != Q931_CALL_STATE_NULL &&
 				cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_REQUEST &&
 				cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_INDICATION &&
 				cur->ourcallstate != Q931_CALL_STATE_RELEASE_REQUEST) {
-
-				/* The STATUS message sent here is not required by Q.931, but it may help anyway. */
-				q931_status(ctrl, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
-			}
-			cur = cur->next;
+				/*
+				 * The STATUS message sent here is not required by Q.931,
+				 * but it may help anyway.
+				 * This looks like a new call started while the link was down.
+				 */
+				winner = q931_find_winning_call(cur);
+				if (winner) {
+					q931_status(ctrl, winner, PRI_CAUSE_NORMAL_UNSPECIFIED);
+				}
+			}
 		}
 		break;
 	default:




More information about the svn-commits mailing list