[libpri-commits] rmudgett: branch 1.4 r1275 - /branches/1.4/

SVN commits to the libpri project libpri-commits at lists.digium.com
Tue Nov 10 13:27:38 CST 2009


Author: rmudgett
Date: Tue Nov 10 13:27:34 2009
New Revision: 1275

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1275
Log:
Add dummy call reference support.

Fixes problem where PTMP NT mode responds erroneously to a FACILITY
message from a phone on the dummy call reference.  LibPRI behaved as if
the dummy call reference were an invalid call reference and proceeded to
respond on the global call reference.

Modified:
    branches/1.4/libpri.h
    branches/1.4/pri.c
    branches/1.4/pri_internal.h
    branches/1.4/q931.c

Modified: branches/1.4/libpri.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/libpri.h?view=diff&rev=1275&r1=1274&r2=1275
==============================================================================
--- branches/1.4/libpri.h (original)
+++ branches/1.4/libpri.h Tue Nov 10 13:27:34 2009
@@ -929,6 +929,14 @@
 /* Create a new call */
 q931_call *pri_new_call(struct pri *pri);
 
+/*!
+ * \brief Deterimine if the given call control pointer is a dummy call.
+ *
+ * \retval TRUE if given call is a dummy call.
+ * \retval FALSE otherwise.
+ */
+int pri_is_dummy_call(q931_call *call);
+
 /* Retrieve CRV reference for GR-303 calls.  Returns >0 on success. */
 int pri_get_crv(struct pri *pri, q931_call *call, int *callmode);
 

Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=1275&r1=1274&r2=1275
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Tue Nov 10 13:27:34 2009
@@ -226,18 +226,44 @@
 	return res;
 }
 
-/* Pass in the master for this function */
 void __pri_free_tei(struct pri * p)
 {
-	free(p);
+	if (p) {
+		struct q931_call *call;
+
+		call = p->dummy_call;
+		if (call) {
+			pri_schedule_del(call->pri, call->retranstimer);
+			pri_call_apdu_queue_cleanup(call);
+		}
+		free(p);
+	}
 }
 
 struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri)
 {
+	struct d_ctrl_dummy *dummy_ctrl;
 	struct pri *p;
 
-	if (!(p = calloc(1, sizeof(*p))))
-		return NULL;
+	switch (switchtype) {
+	case PRI_SWITCH_GR303_EOC:
+	case PRI_SWITCH_GR303_TMC:
+	case PRI_SWITCH_GR303_TMC_SWITCHING:
+	case PRI_SWITCH_GR303_EOC_PATH:
+		p = calloc(1, sizeof(*p));
+		if (!p) {
+			return NULL;
+		}
+		dummy_ctrl = NULL;
+		break;
+	default:
+		dummy_ctrl = calloc(1, sizeof(*dummy_ctrl));
+		if (!dummy_ctrl) {
+			return NULL;
+		}
+		p = &dummy_ctrl->ctrl;
+		break;
+	}
 
 	p->bri = bri;
 	p->fd = fd;
@@ -265,7 +291,14 @@
 	p->q931_rxcount = 0;
 	p->q931_txcount = 0;
 #endif
-	if (switchtype == PRI_SWITCH_GR303_EOC) {
+	if (dummy_ctrl) {
+		/* Initialize the dummy call reference call record. */
+		dummy_ctrl->ctrl.dummy_call = &dummy_ctrl->dummy_call;
+		q931_init_call_record(&dummy_ctrl->ctrl, dummy_ctrl->ctrl.dummy_call,
+			Q931_DUMMY_CALL_REFERENCE);
+	}
+	switch (switchtype) {
+	case PRI_SWITCH_GR303_EOC:
 		p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
 		p->sapi = Q921_SAPI_GR303_EOC;
 		p->tei = Q921_TEI_GR303_EOC_OPS;
@@ -274,7 +307,8 @@
 			free(p);
 			p = NULL;
 		}
-	} else if (switchtype == PRI_SWITCH_GR303_TMC) {
+		break;
+	case PRI_SWITCH_GR303_TMC:
 		p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
 		p->sapi = Q921_SAPI_GR303_TMC_CALLPROC;
 		p->tei = Q921_TEI_GR303_TMC_CALLPROC;
@@ -283,14 +317,19 @@
 			free(p);
 			p = NULL;
 		}
-	} else if (switchtype == PRI_SWITCH_GR303_TMC_SWITCHING) {
+		break;
+	case PRI_SWITCH_GR303_TMC_SWITCHING:
 		p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
 		p->sapi = Q921_SAPI_GR303_TMC_SWITCHING;
 		p->tei = Q921_TEI_GR303_TMC_SWITCHING;
-	} else if (switchtype == PRI_SWITCH_GR303_EOC_PATH) {
+		break;
+	case PRI_SWITCH_GR303_EOC_PATH:
 		p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
 		p->sapi = Q921_SAPI_GR303_EOC;
 		p->tei = Q921_TEI_GR303_EOC_PATH;
+		break;
+	default:
+		break;
 	}
 	/* Start Q.921 layer, Wait if we're the network */
 	if (p)
@@ -935,6 +974,14 @@
 	return q931_new_call(pri);
 }
 
+int pri_is_dummy_call(q931_call *call)
+{
+	if (!call) {
+		return 0;
+	}
+	return q931_is_dummy_call(call);
+}
+
 void pri_dump_event(struct pri *pri, pri_event *e)
 {
 	if (!pri || !e)

Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=1275&r1=1274&r2=1275
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Tue Nov 10 13:27:34 2009
@@ -114,6 +114,13 @@
 	q931_call **callpool;
 	q931_call *localpool;
 
+	/*!
+	 * \brief Q.931 Dummy call reference call associated with this TEI.
+	 * \note If present then this call is allocated as part of the
+	 * D channel control structure.
+	 */
+	q931_call *dummy_call;
+
 	/* do we do overlap dialing */
 	int overlapdial;
 
@@ -506,6 +513,14 @@
 	int pri_winner;
 };
 
+/*! D channel control structure with associated dummy call reference record. */
+struct d_ctrl_dummy {
+	/*! D channel control structure. */
+	struct pri ctrl;
+	/*! Dummy call reference call record. */
+	struct q931_call dummy_call;
+};
+
 extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
 
 extern pri_event *pri_schedule_run(struct pri *pri);
@@ -522,6 +537,8 @@
 struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri);
 
 void __pri_free_tei(struct pri *p);
+
+void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr);
 
 void q931_party_name_init(struct q931_party_name *name);
 void q931_party_number_init(struct q931_party_number *number);
@@ -589,4 +606,17 @@
 	return pri->bri && (((pri)->localtype == PRI_CPE) && ((pri)->tei == Q921_TEI_GROUP));
 }
 
+#define Q931_DUMMY_CALL_REFERENCE	-1
+
+/*!
+ * \brief Deterimine if the given call control pointer is a dummy call.
+ *
+ * \retval TRUE if given call is a dummy call.
+ * \retval FALSE otherwise.
+ */
+static inline int q931_is_dummy_call(const q931_call *call)
+{
+	return (call->cr == Q931_DUMMY_CALL_REFERENCE) ? 1 : 0;
+}
+
 #endif

Modified: branches/1.4/q931.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q931.c?view=diff&rev=1275&r1=1274&r2=1275
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Tue Nov 10 13:27:34 2009
@@ -3307,30 +3307,38 @@
 	return "Unknown Message Type";
 }
 
+/* Decode the call reference */
 static inline int q931_cr(q931_h *h)
 {
-	int cr = 0;
+	int cr;
 	int x;
+
 	if (h->crlen > 3) {
 		pri_error(NULL, "Call Reference Length Too long: %d\n", h->crlen);
-		return -1;
+		return Q931_DUMMY_CALL_REFERENCE;
 	}
 	switch (h->crlen) {
-		case 2: 
-			for (x=0;x<h->crlen;x++) {
-				cr <<= 8;
-				cr |= h->crv[x];
-			}
-			break;
-		case 1:
-			cr = h->crv[0];
-			if (cr & 0x80) {
-				cr &= ~0x80;
-				cr |= 0x8000;
-			}
-			break;
-		default:
-			pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen);
+	case 2:
+		cr = 0;
+		for (x = 0; x < h->crlen; ++x) {
+			cr <<= 8;
+			cr |= h->crv[x];
+		}
+		break;
+	case 1:
+		cr = h->crv[0];
+		if (cr & 0x80) {
+			cr &= ~0x80;
+			cr |= 0x8000;
+		}
+		break;
+	case 0:
+		cr = Q931_DUMMY_CALL_REFERENCE;
+		break;
+	default:
+		pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen);
+		cr = Q931_DUMMY_CALL_REFERENCE;
+		break;
 	}
 	return cr;
 }
@@ -3370,11 +3378,72 @@
 	pri_error(ctrl, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie));
 }
 
+/*!
+ * \brief Initialize the call record.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * 
+ * \note The call record is assumed to already be memset() to zero.
+ *
+ * \return Nothing
+ */
+void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr)
+{
+	call->cr = cr;
+	call->slotmap = -1;
+	call->channelno = -1;
+	if (cr != Q931_DUMMY_CALL_REFERENCE) {
+		call->newcall = 1;
+	}
+	call->ourcallstate = Q931_CALL_STATE_NULL;
+	call->peercallstate = Q931_CALL_STATE_NULL;
+	call->sugcallstate = Q931_CALL_STATE_NOT_SET;
+	call->ri = -1;
+	call->transcapability = -1;
+	call->transmoderate = -1;
+	call->transmultiple = -1;
+	call->userl1 = -1;
+	call->userl2 = -1;
+	call->userl3 = -1;
+	call->rateadaption = -1;
+	call->progress = -1;
+	call->causecode = -1;
+	call->causeloc = -1;
+	call->cause = -1;
+	call->useruserprotocoldisc = -1;
+	call->aoc_units = -1;
+	call->changestatus = -1;
+	call->reversecharge = -1;
+	call->pri_winner = -1;
+	call->master_call = call;
+	q931_party_number_init(&call->redirection_number);
+	q931_party_address_init(&call->called);
+	q931_party_id_init(&call->local_id);
+	q931_party_id_init(&call->remote_id);
+	q931_party_redirecting_init(&call->redirecting);
+
+	/* PRI is set to whoever called us */
+	if (BRI_TE_PTMP(ctrl)) {
+		/*
+		 * Point to the master to avoid stale pointer problems if
+		 * the TEI is removed later.
+		 */
+		call->pri = PRI_MASTER(ctrl);
+	} else {
+		call->pri = ctrl;
+	}
+}
+
 static q931_call *q931_getcall(struct pri *ctrl, int cr)
 {
 	q931_call *cur;
 	q931_call *prev;
 	struct pri *master;
+
+	if (cr == Q931_DUMMY_CALL_REFERENCE) {
+		return ctrl->dummy_call;
+	}
 
 	/* Find the master  - He has the call pool */
 	master = PRI_MASTER(ctrl);
@@ -3414,47 +3483,7 @@
 	}
 
 	/* Initialize call structure. */
-	cur->cr = cr;
-	cur->slotmap = -1;
-	cur->channelno = -1;
-	cur->newcall = 1;
-	cur->ourcallstate = Q931_CALL_STATE_NULL;
-	cur->peercallstate = Q931_CALL_STATE_NULL;
-	cur->sugcallstate = Q931_CALL_STATE_NOT_SET;
-	cur->ri = -1;
-	cur->transcapability = -1;
-	cur->transmoderate = -1;
-	cur->transmultiple = -1;
-	cur->userl1 = -1;
-	cur->userl2 = -1;
-	cur->userl3 = -1;
-	cur->rateadaption = -1;
-	cur->progress = -1;
-	cur->causecode = -1;
-	cur->causeloc = -1;
-	cur->cause = -1;
-	cur->useruserprotocoldisc = -1;
-	cur->aoc_units = -1;
-	cur->changestatus = -1;
-	cur->reversecharge = -1;
-	cur->pri_winner = -1;
-	cur->master_call = cur;
-	q931_party_number_init(&cur->redirection_number);
-	q931_party_address_init(&cur->called);
-	q931_party_id_init(&cur->local_id);
-	q931_party_id_init(&cur->remote_id);
-	q931_party_redirecting_init(&cur->redirecting);
-
-	/* PRI is set to whoever called us */
-	if (BRI_TE_PTMP(ctrl)) {
-		/*
-		 * Point to the master to avoid stale pointer problems if
-		 * the TEI is removed later.
-		 */
-		cur->pri = master;
-	} else {
-		cur->pri = ctrl;
-	}
+	q931_init_call_record(ctrl, cur, cr);
 
 	/* Append to end of list */
 	if (prev) {
@@ -3511,6 +3540,10 @@
 	int slavesleft;
 	int slaveidx;
 
+	if (q931_is_dummy_call(c)) {
+		/* Cannot destroy the dummy call. */
+		return;
+	}
 	if (c->master_call != c) {
 		slave = c;
 		c = slave->master_call;
@@ -3711,7 +3744,9 @@
 	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 & 0x8000) ? "Terminator" : "Originator");
+		(cref == Q931_DUMMY_CALL_REFERENCE)
+			? "Dummy"
+			: (cref & 0x8000) ? "Terminator" : "Originator");
 
 	/* Message header begins at the end of the call reference number */
 	mh = (q931_mh *)(h->contents + h->crlen);
@@ -3778,7 +3813,9 @@
 		h->pd = ctrl->protodisc;
 	}
 	h->x0 = 0;		/* Reserved 0 */
-	if (!ctrl->bri) {
+	if (q931_is_dummy_call(call)) {
+		h->crlen = 0;
+	} else if (!ctrl->bri) {
 		/* Two bytes of Call Reference. */
 		h->crlen = 2;
 		/* Invert the top bit to make it from our sense */
@@ -3807,18 +3844,11 @@
 
 static int q931_xmit(struct pri *ctrl, q931_h *h, int len, int cr, int uiframe)
 {
-	/* 
-	 * For NT-PTMP mode, we need to check the following:
-	 * MODE = NT-PTMP
-	 * MESSAGE = SETUP
-	 *
-	 * If those are true, we need to send the SETUP in a UI frame
-	 * instead of an I-frame.
-	 */
-	if (BRI_NT_PTMP(ctrl) && uiframe)
+	if (uiframe) {
 		q921_transmit_uiframe(ctrl, h, len);
-	else
+	} else {
 		q921_transmit_iframe(ctrl, h, len, cr);
+	}
 	/* The transmit operation might dump the q921 header, so logging the q931
 	   message body after the transmit puts the sections of the message in the
 	   right order in the log */
@@ -3893,6 +3923,43 @@
 		ctrl = ctrl->subchannel;
 	}
 	if (ctrl) {
+		int uiframe;
+
+		switch (msgtype) {
+		case Q931_SETUP:
+			/* 
+			 * For NT-PTMP mode, we need to check the following:
+			 * MODE = NT-PTMP
+			 * MESSAGE = SETUP
+			 *
+			 * If those are true, we need to send the SETUP in a UI frame
+			 * instead of an I-frame.
+			 */
+			uiframe = call->outboundbroadcast;
+			break;
+		case Q931_FACILITY:
+			if (ctrl->tei == Q921_TEI_GROUP) {
+				/* Broadcast TEI. */
+				if (q931_is_dummy_call(call)) {
+					/*
+					 * This is a FACILITY message on the dummy call reference
+					 * for the broadcast TEI.
+					 */
+					uiframe = 1;
+				} else {
+					pri_error(ctrl,
+						"Attempting to broadcast %s on cref %d\n",
+						msg2str(msgtype), call->cr);
+					return -1;
+				}
+			} else {
+				uiframe = 0;
+			}
+			break;
+		default:
+			uiframe = 0;
+			break;
+		}
 		if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
 			pri_message(ctrl,
 				"Sending message for call %p on %p TEI/SAPI %d/%d, call->pri is %p, TEI/SAPI %d/%d\n",
@@ -3900,7 +3967,7 @@
 				ctrl, ctrl->tei, ctrl->sapi,
 				call->pri, call->pri->tei, call->pri->sapi);
 		}
-		q931_xmit(ctrl, h, len, 1, (msgtype == Q931_SETUP) ? 1 : 0);
+		q931_xmit(ctrl, h, len, 1, uiframe);
 	}
 	call->acked = 1;
 	return 0;
@@ -5375,6 +5442,9 @@
 		c->ri = -1;
 		break;
 	case Q931_FACILITY:
+		if (q931_is_dummy_call(c)) {
+			q931_party_address_init(&c->called);
+		}
 		break;
 	case Q931_SETUP:
 		if (ctrl->debug & PRI_DEBUG_Q931_STATE)
@@ -7288,7 +7358,10 @@
 
 int q931_call_setcrv(struct pri *ctrl, q931_call *call, int crv, int callmode)
 {
-	call->cr = (crv << 3) & 0x7fff;
-	call->cr |= (callmode & 0x7);
+	/* Do not allow changing the dummy call reference */
+	if (!q931_is_dummy_call(call)) {
+		call->cr = (crv << 3) & 0x7fff;
+		call->cr |= (callmode & 0x7);
+	}
 	return 0;
 }




More information about the libpri-commits mailing list