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

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Apr 18 12:44:41 CDT 2014


Author: rmudgett
Date: Fri Apr 18 12:44:31 2014
New Revision: 2318

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=2318
Log:
libpri: Make TE-PTP mode respond to MDL TEI check requests.

Some BRI devices in France insist on checking TEI's when in point-to-point
mode.  If they don't get a response for TEI 0 they drop layer 1 even
though libpri keeps trying to bring layer 2 up.

* Made q921_mdl_receive() handle TEI check request messages in TE-PTP
mode.  Had to change q921_mdl_send()/Q921_INIT() because the PTP modes do
not setup a link structure specifically for MDL as the PTMP modes do.

* Fixed q921_tei_check()/t201_expire() to check TEI's even if the network
side doesn't have any assigned.  This should make TE's that request the
TEI verify procedure (Q.921 Section 5.3.5) happy when the network side
doesn't have any TEI's allocated.

PRI-165
Reported by: Denis Alberto Martinez
Patches:
      jira_pri_165_ptp_respond_tei_check.patch (license #5621) patch uploaded by rmudgett
Review: https://reviewboard.asterisk.org/r/3434/


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=2318&r1=2317&r2=2318
==============================================================================
--- branches/1.4/q921.c (original)
+++ branches/1.4/q921.c Fri Apr 18 12:44:31 2014
@@ -45,13 +45,19 @@
  */
 //#define RANDOM_DROPS	1
 
-#define Q921_INIT(link, hf) do { \
-	memset(&(hf),0,sizeof(hf)); \
-	(hf).h.sapi = (link)->sapi; \
-	(hf).h.ea1 = 0; \
-	(hf).h.ea2 = 1; \
-	(hf).h.tei = (link)->tei; \
-} while (0)
+#define Q921_INIT(fr, l_sapi, l_tei) \
+	do { \
+		(fr)->h.sapi = l_sapi; \
+		(fr)->h.ea1 = 0; \
+		(fr)->h.ea2 = 1; \
+		(fr)->h.tei = l_tei; \
+	} while (0)
+
+#define Q921_CLEAR_INIT(fr, l_sapi, l_tei) \
+	do { \
+		memset((fr), 0, sizeof(*(fr))); \
+		Q921_INIT((fr), (l_sapi), (l_tei)); \
+	} while (0)
 
 static void q921_dump_pri(struct q921_link *link, char direction_tag);
 static void q921_establish_data_link(struct q921_link *link);
@@ -196,17 +202,14 @@
 	return 0;
 }
 
-static void q921_send_tei(struct pri *ctrl, enum q921_tei_identity message, int ri, int ai, int iscommand)
+static void q921_mdl_send(struct pri *ctrl, enum q921_tei_identity message, int ri, int ai, int iscommand)
 {
 	q921_u *f;
-	struct q921_link *link;
-
-	link = &ctrl->link;
 
 	if (!(f = calloc(1, sizeof(*f) + 5)))
 		return;
 
-	Q921_INIT(link, *f);
+	Q921_INIT(f, Q921_SAPI_LAYER2_MANAGEMENT, Q921_TEI_GROUP);
 	f->h.c_r = (ctrl->localtype == PRI_NETWORK) ? iscommand : !iscommand;
 	f->ft = Q921_FRAMETYPE_U;
 	f->data[0] = 0x0f;	/* Management entity */
@@ -216,7 +219,7 @@
 	f->data[4] = (ai << 1) | 1;
 	if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
 		pri_message(ctrl,
-			"Sending TEI management message %d(%s), TEI=%d\n",
+			"Sending MDL message: %d(%s), TEI=%d\n",
 			message, q921_tei_mgmt2str(message), ai);
 	}
 	q921_transmit(ctrl, (q921_h *)f, 8);
@@ -265,7 +268,7 @@
 
 	/* Send TEI request */
 	link->ri = random() % 65535;
-	q921_send_tei(ctrl, Q921_TEI_IDENTITY_REQUEST, link->ri, Q921_TEI_GROUP, 1);
+	q921_mdl_send(ctrl, Q921_TEI_IDENTITY_REQUEST, link->ri, Q921_TEI_GROUP, 1);
 }
 
 static void q921_tei_request(struct q921_link *link)
@@ -280,8 +283,8 @@
 	 * Q.921 Section 5.3.2 says we should send the remove message
 	 * twice, in case of message loss.
 	 */
-	q921_send_tei(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
-	q921_send_tei(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
+	q921_mdl_send(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
+	q921_mdl_send(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
 }
 
 static void q921_send_dm(struct q921_link *link, int fbit)
@@ -291,7 +294,7 @@
 
 	ctrl = link->ctrl;
 
-	Q921_INIT(link, h);
+	Q921_CLEAR_INIT(&h, link->sapi, link->tei);
 	h.u.m3 = 0;	/* M3 = 0 */
 	h.u.m2 = 3;	/* M2 = 3 */
 	h.u.p_f = fbit;	/* Final set appropriately */
@@ -320,7 +323,7 @@
 
 	ctrl = link->ctrl;
 
-	Q921_INIT(link, h);
+	Q921_CLEAR_INIT(&h, link->sapi, link->tei);
 	h.u.m3 = 2;	/* M3 = 2 */
 	h.u.m2 = 0;	/* M2 = 0 */
 	h.u.p_f = pbit;	/* Poll set appropriately */
@@ -349,7 +352,7 @@
 
 	ctrl = link->ctrl;
 
-	Q921_INIT(link, h);
+	Q921_CLEAR_INIT(&h, link->sapi, link->tei);
 	h.u.m3 = 3;		/* M3 = 3 */
 	h.u.m2 = 0;		/* M2 = 0 */
 	h.u.p_f = fbit;	/* Final set appropriately */
@@ -378,7 +381,7 @@
 
 	ctrl = link->ctrl;
 
-	Q921_INIT(link, h);
+	Q921_CLEAR_INIT(&h, link->sapi, link->tei);
 	h.u.m3 = 3;	/* M3 = 3 */
 	h.u.m2 = 3;	/* M2 = 3 */
 	h.u.p_f = 1;	/* Poll bit set */
@@ -809,7 +812,7 @@
 
 	ctrl = link->ctrl;
 
-	Q921_INIT(link, h);
+	Q921_CLEAR_INIT(&h, link->sapi, link->tei);
 	h.s.x0 = 0;	/* Always 0 */
 	h.s.ss = 2;	/* Reject */
 	h.s.ft = 1;	/* Frametype (01) */
@@ -839,7 +842,7 @@
 
 	ctrl = link->ctrl;
 
-	Q921_INIT(link, h);
+	Q921_CLEAR_INIT(&h, link->sapi, link->tei);
 	h.s.x0 = 0;	/* Always 0 */
 	h.s.ss = 0; /* Receive Ready */
 	h.s.ft = 1;	/* Frametype (01) */
@@ -1066,7 +1069,7 @@
 
 		f = calloc(1, sizeof(struct q921_frame) + len + 2);
 		if (f) {
-			Q921_INIT(link, f->h);
+			Q921_INIT(&f->h, link->sapi, link->tei);
 			switch (ctrl->localtype) {
 			case PRI_NETWORK:
 				if (cr)
@@ -1396,12 +1399,6 @@
 
 	ctrl = vctrl;
 
-	if (!ctrl->link.next) {
-		/* No TEI links remain. */
-		ctrl->t201_timer = 0;
-		return;
-	}
-
 	/* Start the TEI check timer. */
 	ctrl->t201_timer =
 		pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T201], t201_expire, ctrl);
@@ -1462,7 +1459,7 @@
 			}
 		}
 	}
-	q921_send_tei(ctrl, Q921_TEI_IDENTITY_CHECK_REQUEST, 0, Q921_TEI_GROUP, 1);
+	q921_mdl_send(ctrl, Q921_TEI_IDENTITY_CHECK_REQUEST, 0, Q921_TEI_GROUP, 1);
 }
 
 static void q921_tei_check(struct pri *ctrl)
@@ -1475,7 +1472,19 @@
 	t201_expire(ctrl);
 }
 
-static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
+static void q921_mdl_ignore(struct pri *ctrl, q921_u *h, const char *reason)
+{
+	if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+		/*
+		 * Send out this message in debug modes since it is possible the
+		 * user has misconfigured their link for the wrong mode.
+		 */
+		pri_message(ctrl, "Ignoring MDL message: %d(%s)  %s\n",
+			h->data[3], q921_tei_mgmt2str(h->data[3]), reason);
+	}
+}
+
+static pri_event *q921_mdl_receive(struct pri *ctrl, q921_u *h, int len)
 {
 	int ri;
 	struct q921_link *sub;
@@ -1485,32 +1494,13 @@
 	int count;
 	int tei;
 
-	if (!BRI_NT_PTMP(ctrl) && !BRI_TE_PTMP(ctrl)) {
-		/*
-		 * Some telco switches send out MDL messages even though they
-		 * are configured for PTP.  Usually they are checking for
-		 * assigned TEI's.
-		 */
-		if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
-			/*
-			 * Send out this message in debug modes since it is possible the
-			 * user has misconfigured their link for the wrong mode.
-			 */
-			pri_message(ctrl, "Not configured for PTMP.  Ignoring MDL message: %d(%s)\n",
-				h->data[3], q921_tei_mgmt2str(h->data[3]));
-		}
+	if (len <= &h->data[0] - (u_int8_t *) h) {
+		pri_error(ctrl, "Received short MDL frame\n");
 		return NULL;
 	}
-
-	if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
-		pri_message(ctrl, "Received MDL message\n");
-	}
-	if (len <= &h->data[0] - (u_int8_t *) h) {
-		pri_error(ctrl, "Received short frame\n");
-		return NULL;
-	}
 	if (h->data[0] != 0x0f) {
-		pri_error(ctrl, "Received MDL with unsupported management entity %02x\n", h->data[0]);
+		pri_error(ctrl, "Received MDL with unsupported management entity %02x\n",
+			h->data[0]);
 		return NULL;
 	}
 	if (len <= &h->data[4] - (u_int8_t *) h) {
@@ -1519,8 +1509,20 @@
 	}
 	if (h->data[3] != Q921_TEI_IDENTITY_CHECK_RESPONSE
 		&& !(h->data[4] & 0x01)) {
-		pri_error(ctrl, "Received %d(%s) with Ai E bit not set.\n", h->data[3],
-			q921_tei_mgmt2str(h->data[3]));
+		pri_error(ctrl, "Received MDL message: %d(%s) with Ai E bit not set.\n",
+			h->data[3], q921_tei_mgmt2str(h->data[3]));
+		return NULL;
+	}
+	if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+		pri_message(ctrl, "Received MDL message: %d(%s)\n",
+			h->data[3], q921_tei_mgmt2str(h->data[3]));
+	}
+	if (PTP_MODE(ctrl) && NT_MODE(ctrl)) {
+		/*
+		 * We are not managing automatic TEI's in this mode so we can
+		 * ignore MDL messages from the CPE.
+		 */
+		q921_mdl_ignore(ctrl, h, "We are in NT-PTP mode.");
 		return NULL;
 	}
 	ri = (h->data[1] << 8) | h->data[2];
@@ -1529,13 +1531,14 @@
 	switch (h->data[3]) {
 	case Q921_TEI_IDENTITY_REQUEST:
 		if (!BRI_NT_PTMP(ctrl)) {
+			q921_mdl_ignore(ctrl, h, "We are not in NT-PTMP mode.");
 			return NULL;
 		}
 
 		if (tei != Q921_TEI_GROUP) {
 			pri_error(ctrl, "Received %s with invalid TEI %d\n",
 				q921_tei_mgmt2str(Q921_TEI_IDENTITY_REQUEST), tei);
-			q921_send_tei(ctrl, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
+			q921_mdl_send(ctrl, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
 			return NULL;
 		}
 
@@ -1550,7 +1553,7 @@
 						break;
 					}
 					pri_error(ctrl, "TEI pool exhausted.  Reclaiming dead TEIs.\n");
-					q921_send_tei(ctrl, Q921_TEI_IDENTITY_DENIED, ri, Q921_TEI_GROUP, 1);
+					q921_mdl_send(ctrl, Q921_TEI_IDENTITY_DENIED, ri, Q921_TEI_GROUP, 1);
 					q921_tei_check(ctrl);
 					return NULL;
 				}
@@ -1567,7 +1570,7 @@
 		}
 		sub->next = link;
 		q921_setstate(link, Q921_TEI_ASSIGNED);
-		q921_send_tei(ctrl, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
+		q921_mdl_send(ctrl, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
 
 		count = 0;
 		for (sub = ctrl->link.next; sub; sub = sub->next) {
@@ -1595,6 +1598,7 @@
 		break;
 	case Q921_TEI_IDENTITY_CHECK_RESPONSE:
 		if (!BRI_NT_PTMP(ctrl)) {
+			/* Silently ignore the message since we never asked for the check. */
 			return NULL;
 		}
 
@@ -1642,6 +1646,7 @@
 		break;
 	case Q921_TEI_IDENTITY_VERIFY:
 		if (!BRI_NT_PTMP(ctrl)) {
+			q921_mdl_ignore(ctrl, h, "We are not in NT-PTMP mode.");
 			return NULL;
 		}
 		if (tei == Q921_TEI_GROUP) {
@@ -1652,11 +1657,20 @@
 		q921_tei_check(ctrl);
 		break;
 	case Q921_TEI_IDENTITY_ASSIGNED:
+		if (NT_MODE(ctrl)) {
+			/* We should not be receiving this message. */
+			q921_mdl_ignore(ctrl, h, "We are the network.");
+			return NULL;
+		}
 		if (!BRI_TE_PTMP(ctrl)) {
+			/*
+			 * Silently ignore the message.  It must not be for us
+			 * since we will never ask for one.
+			 */
 			return NULL;
 		}
 
-		/* Assuming we're operating on the specific TEI link here */
+		/* We're operating on the specific TEI link here */
 		link = ctrl->link.next;
 		
 		switch (link->state) {
@@ -1726,29 +1740,52 @@
 		}
 		break;
 	case Q921_TEI_IDENTITY_CHECK_REQUEST:
-		if (!BRI_TE_PTMP(ctrl)) {
+		if (NT_MODE(ctrl)) {
+			/* We should not be receiving this message. */
+			q921_mdl_ignore(ctrl, h, "We are the network.");
 			return NULL;
 		}
 
-		/* Assuming we're operating on the specific TEI link here */
-		link = ctrl->link.next;
-
-		if (link->state < Q921_TEI_ASSIGNED) {
-			/* We do not have a TEI. */
+		if (PTP_MODE(ctrl)) {
+			/*
+			 * Some telco switches/devices get very unhappy if we don't
+			 * respond to the TEI check request with our permanently
+			 * assigned TEI.
+			 */
+			link = &ctrl->link;
+		} else if (BRI_TE_PTMP(ctrl)) {
+			/* We're operating on the specific TEI link here */
+			link = ctrl->link.next;
+
+			if (link->state < Q921_TEI_ASSIGNED) {
+				/* We do not have a TEI. */
+				return NULL;
+			}
+		} else {
+			/* Should never get here. */
 			return NULL;
 		}
 
 		/* If it's addressed to the group TEI or to our TEI specifically, we respond */
 		if (tei == Q921_TEI_GROUP || tei == link->tei) {
-			q921_send_tei(ctrl, Q921_TEI_IDENTITY_CHECK_RESPONSE, random() % 65535, link->tei, 1);
+			q921_mdl_send(ctrl, Q921_TEI_IDENTITY_CHECK_RESPONSE, random() % 65535, link->tei, 1);
 		}
 		break;
 	case Q921_TEI_IDENTITY_REMOVE:
+		if (NT_MODE(ctrl)) {
+			/* We should not be receiving this message. */
+			q921_mdl_ignore(ctrl, h, "We are the network.");
+			return NULL;
+		}
 		if (!BRI_TE_PTMP(ctrl)) {
+			/*
+			 * Silently ignore the message.  If we are TE-PTP our
+			 * TEI is permanently assigned and cannot be removed.
+			 */
 			return NULL;
 		}
 
-		/* Assuming we're operating on the specific TEI link here */
+		/* We're operating on the specific TEI link here */
 		link = ctrl->link.next;
 
 		if (link->state < Q921_TEI_ASSIGNED) {
@@ -2991,27 +3028,32 @@
 
 static pri_event *q921_handle_unmatched_frame(struct pri *ctrl, q921_h *h, int len)
 {
-	if (h->h.tei < 64) {
-		pri_error(ctrl, "Do not support manual TEI range. Discarding\n");
+	if (!BRI_NT_PTMP(ctrl)) {
 		return NULL;
 	}
 
+	if (h->h.tei < Q921_TEI_AUTO_FIRST) {
+		if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+			pri_message(ctrl, "Manual TEI range is not supported in NT-PTMP mode. Discarding\n");
+		}
+		return NULL;
+	}
+
 	if (h->h.sapi != Q921_SAPI_CALL_CTRL) {
-		pri_error(ctrl, "Message with SAPI other than CALL CTRL is discarded\n");
+		if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+			pri_message(ctrl, "Message with SAPI other than CALL CTRL is discarded\n");
+		}
 		return NULL;
 	}
 
-	/* If we're NT-PTMP, this means an unrecognized TEI that we'll kill */
-	if (BRI_NT_PTMP(ctrl)) {
-		if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
-			pri_message(ctrl,
-				"Could not find a layer 2 link for received frame with SAPI/TEI of %d/%d.\n",
-				h->h.sapi, h->h.tei);
-			pri_message(ctrl, "Sending TEI release, in order to re-establish TEI state\n");
-		}
-	
-		q921_tei_remove(ctrl, h->h.tei);
-	}
+	/* This means an unrecognized TEI that we'll kill */
+	if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+		pri_message(ctrl,
+			"Could not find a layer 2 link for received frame with SAPI/TEI of %d/%d.\n",
+			h->h.sapi, h->h.tei);
+		pri_message(ctrl, "Sending TEI release, in order to re-establish TEI state\n");
+	}
+	q921_tei_remove(ctrl, h->h.tei);
 
 	return NULL;
 }
@@ -3035,7 +3077,7 @@
 	}
 
 	if (h->h.sapi == Q921_SAPI_LAYER2_MANAGEMENT) {
-		return q921_receive_MDL(ctrl, &h->u, len);
+		return q921_mdl_receive(ctrl, &h->u, len);
 	}
 
 	if (h->h.tei == Q921_TEI_GROUP && h->h.sapi != Q921_SAPI_CALL_CTRL) {




More information about the svn-commits mailing list