[svn-commits] rmudgett: branch rmudgett/check_tei r2095 - /team/rmudgett/check_tei/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Nov 5 11:46:40 CDT 2010


Author: rmudgett
Date: Fri Nov  5 11:46:36 2010
New Revision: 2095

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=2095
Log:
Added TEI identity check feature.

Modified:
    team/rmudgett/check_tei/pri.c
    team/rmudgett/check_tei/pri_internal.h
    team/rmudgett/check_tei/pri_q921.h
    team/rmudgett/check_tei/q921.c

Modified: team/rmudgett/check_tei/pri.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/check_tei/pri.c?view=diff&rev=2095&r1=2094&r2=2095
==============================================================================
--- team/rmudgett/check_tei/pri.c (original)
+++ team/rmudgett/check_tei/pri.c Fri Nov  5 11:46:36 2010
@@ -63,6 +63,7 @@
 	{ "N202",           PRI_TIMER_N202,             PRI_ALL_SWITCHES },
 	{ "K",              PRI_TIMER_K,                PRI_ALL_SWITCHES },
 	{ "T200",           PRI_TIMER_T200,             PRI_ALL_SWITCHES },
+	{ "T201",           PRI_TIMER_T201,             PRI_ALL_SWITCHES },
 	{ "T202",           PRI_TIMER_T202,             PRI_ALL_SWITCHES },
 	{ "T203",           PRI_TIMER_T203,             PRI_ALL_SWITCHES },
 	{ "T300",           PRI_TIMER_T300,             PRI_ALL_SWITCHES },
@@ -165,21 +166,25 @@
 	ctrl->timers[PRI_TIMER_N200] = 3;			/* Max numer of Q.921 retransmissions */
 	ctrl->timers[PRI_TIMER_N202] = 3;			/* Max numer of transmissions of the TEI identity request message */
 
-	if (ctrl->bri == 1)
-		ctrl->timers[PRI_TIMER_K] = 1;				/* Max number of outstanding I-frames */
-	else
-		ctrl->timers[PRI_TIMER_K] = 7;				/* Max number of outstanding I-frames */
+	if (ctrl->bri) {
+		ctrl->timers[PRI_TIMER_K] = 1;			/* Max number of outstanding I-frames */
+	} else {
+		ctrl->timers[PRI_TIMER_K] = 7;			/* Max number of outstanding I-frames */
+	}
 
 	ctrl->timers[PRI_TIMER_T200] = 1000;		/* Time between SABME's */
+	ctrl->timers[PRI_TIMER_T201] = ctrl->timers[PRI_TIMER_T200];/* Time between TEI Identity Checks (Default same as T200) */
 	ctrl->timers[PRI_TIMER_T202] = 10 * 1000;	/* Min time between transmission of TEI Identity request messages */
 	ctrl->timers[PRI_TIMER_T203] = 10 * 1000;	/* Max time without exchanging packets */
+
+	ctrl->timers[PRI_TIMER_T303] = 4 * 1000;	/* Length between SETUP retransmissions and timeout */
 	ctrl->timers[PRI_TIMER_T305] = 30 * 1000;	/* Wait for DISCONNECT acknowledge */
 	ctrl->timers[PRI_TIMER_T308] = 4 * 1000;	/* Wait for RELEASE acknowledge */
+	ctrl->timers[PRI_TIMER_T309] = 6 * 1000;	/* Time to wait before clearing calls in case of D-channel transient event.  Q.931 specifies 6-90 seconds */
 	ctrl->timers[PRI_TIMER_T313] = 4 * 1000;	/* Wait for CONNECT acknowledge, CPE side only */
+
 	ctrl->timers[PRI_TIMER_TM20] = 2500;		/* Max time awaiting XID response - Q.921 Appendix IV */
 	ctrl->timers[PRI_TIMER_NM20] = 3;			/* Number of XID retransmits - Q.921 Appendix IV */
-	ctrl->timers[PRI_TIMER_T303] = 4 * 1000;			/* Length between SETUP retransmissions and timeout */
-	ctrl->timers[PRI_TIMER_T309] = 6000;		/* Time to wait before clearing calls in case of D-channel transient event.  Q.931 specifies 6-90 seconds */
 
 	ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000;	/* Wait for HOLD request response. */
 	ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */

Modified: team/rmudgett/check_tei/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/check_tei/pri_internal.h?view=diff&rev=2095&r1=2094&r2=2095
==============================================================================
--- team/rmudgett/check_tei/pri_internal.h (original)
+++ team/rmudgett/check_tei/pri_internal.h Fri Nov  5 11:46:36 2010
@@ -115,6 +115,10 @@
 
 	/*! Layer 2 link control for D channel. */
 	struct q921_link link;
+	/*! T201 TEI Identity Check timer. */
+	int t201_timer;
+	/*! Number of times T201 has expired. */
+	int t201_expirycnt;
 	
 	int cref;			/* Next call reference value */
 

Modified: team/rmudgett/check_tei/pri_q921.h
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/check_tei/pri_q921.h?view=diff&rev=2095&r1=2094&r2=2095
==============================================================================
--- team/rmudgett/check_tei/pri_q921.h (original)
+++ team/rmudgett/check_tei/pri_q921.h Fri Nov  5 11:46:36 2010
@@ -57,6 +57,8 @@
 #define Q921_TEI_GR303_EOC_OPS			4
 #define Q921_TEI_GR303_TMC_SWITCHING	0
 #define Q921_TEI_GR303_TMC_CALLPROC		0
+#define Q921_TEI_AUTO_FIRST				64
+#define Q921_TEI_AUTO_LAST				126
 
 #define Q921_SAPI_CALL_CTRL		0
 #define Q921_SAPI_GR303_EOC		1
@@ -183,6 +185,18 @@
 	Q921_TIMER_RECOVERY = 8,
 } q921_state;
 
+/*! TEI identity check procedure states. */
+enum q921_tei_check_state {
+	/*! Not participating in the TEI check procedure. */
+	Q921_TEI_CHECK_NONE,
+	/*! No reply to TEI check received. */
+	Q921_TEI_CHECK_DEAD,
+	/*! Reply to TEI check received in current poll. */
+	Q921_TEI_CHECK_REPLY,
+	/*! No reply to current TEI check poll received.  A previous poll got a reply. */
+	Q921_TEI_CHECK_DEAD_REPLY,
+};
+
 /*! \brief Q.921 link controller structure */
 struct q921_link {
 	/*! Next Q.921 link in the chain. */
@@ -205,6 +219,9 @@
 	/*! Q.921 State */
 	enum q921_state state;
 
+	/*! TEI identity check procedure state. */
+	enum q921_tei_check_state tei_check;
+
 	/*! Service Access Profile Identifier (SAPI) of this link */
 	int sapi;
 	/*! Terminal Endpoint Identifier (TEI) of this link */
@@ -233,7 +250,6 @@
 	/* MDL variables */
 	int mdl_timer;
 	int mdl_error;
-	enum q921_state mdl_error_state;
 	unsigned int mdl_free_me:1;
 
 	unsigned int peer_rx_busy:1;

Modified: team/rmudgett/check_tei/q921.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/check_tei/q921.c?view=diff&rev=2095&r1=2094&r2=2095
==============================================================================
--- team/rmudgett/check_tei/q921.c (original)
+++ team/rmudgett/check_tei/q921.c Fri Nov  5 11:46:36 2010
@@ -57,6 +57,7 @@
 static void q921_establish_data_link(struct q921_link *link);
 static void q921_mdl_error(struct q921_link *link, char error);
 static void q921_mdl_remove(struct q921_link *link);
+static void q921_mdl_destroy(struct q921_link *link);
 static void q921_restart_ptp_link_if_needed(struct q921_link *link);
 
 /*!
@@ -1191,12 +1192,103 @@
 	}
 }
 
+#define Q921_TEI_CHECK_MAX_POLLS	2
+
+static void t201_expire(void *vctrl)
+{
+	struct pri *ctrl;
+	struct q921_link *link;
+	struct q921_link *link_next;
+
+	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);
+
+	++ctrl->t201_expirycnt;
+	if (Q921_TEI_CHECK_MAX_POLLS < ctrl->t201_expirycnt) {
+		pri_schedule_del(ctrl, ctrl->t201_timer);
+		ctrl->t201_timer = 0;
+
+		/* Reclaim any dead TEI links. */
+		for (link = ctrl->link.next; link; link = link_next) {
+			link_next = link->next;
+
+			switch (link->tei_check) {
+			case Q921_TEI_CHECK_DEAD:
+				link->tei_check = Q921_TEI_CHECK_NONE;
+				q921_tei_remove(ctrl, link->tei);
+				q921_mdl_destroy(link);
+				break;
+			default:
+				link->tei_check = Q921_TEI_CHECK_NONE;
+				break;
+			}
+		}
+		return;
+	}
+
+	if (!ctrl->t201_timer) {
+		pri_error(ctrl, "Could not start T201 timer.");
+
+		/* Abort the remaining TEI check. */
+		for (link = ctrl->link.next; link; link = link->next) {
+			link->tei_check = Q921_TEI_CHECK_NONE;
+		}
+		return;
+	}
+
+	if (ctrl->t201_expirycnt == 1) {
+		/* First poll.  Setup TEI check state. */
+		for (link = ctrl->link.next; link; link = link->next) {
+			if (link->state < Q921_TEI_ASSIGNED) {
+				/* We do not have a TEI. */
+				link->tei_check = Q921_TEI_CHECK_NONE;
+			} else {
+				/* Mark TEI as dead until proved otherwise. */
+				link->tei_check = Q921_TEI_CHECK_DEAD;
+			}
+		}
+	} else {
+		/* Subsequent polls.  Setup for new TEI check poll. */
+		for (link = ctrl->link.next; link; link = link->next) {
+			switch (link->tei_check) {
+			case Q921_TEI_CHECK_REPLY:
+				link->tei_check = Q921_TEI_CHECK_DEAD_REPLY;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	q921_send_tei(ctrl, Q921_TEI_IDENTITY_CHECK_REQUEST, 0, Q921_TEI_GROUP, 1);
+}
+
+static void q921_tei_check(struct pri *ctrl)
+{
+	if (ctrl->t201_timer) {
+		/* TEI check procedure already in progress.  Do not disturb it. */
+		return;
+	}
+	ctrl->t201_expirycnt = 0;
+	t201_expire(ctrl);
+}
+
 static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
 {
 	int ri;
 	struct q921_link *sub;
 	struct q921_link *link;
 	pri_event *res = NULL;
+	u_int8_t *action;
+	int count;
 	int tei;
 
 	if (!BRI_NT_PTMP(ctrl) && !BRI_TE_PTMP(ctrl)) {
@@ -1207,42 +1299,53 @@
 	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]);
 		return NULL;
 	}
-	if (!(h->data[4] & 0x01)) {
-		pri_error(ctrl, "Received MDL with multibyte TEI identifier\n");
+	if (len <= &h->data[4] - (u_int8_t *) h) {
+		pri_error(ctrl, "Received short MDL message\n");
+		return NULL;
+	}
+	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]));
 		return NULL;
 	}
 	ri = (h->data[1] << 8) | h->data[2];
 	tei = (h->data[4] >> 1);
 
-	switch(h->data[3]) {
+	switch (h->data[3]) {
 	case Q921_TEI_IDENTITY_REQUEST:
 		if (!BRI_NT_PTMP(ctrl)) {
 			return NULL;
 		}
 
 		if (tei != Q921_TEI_GROUP) {
-			pri_error(ctrl, "Received TEI identity request with invalid TEI %d\n", tei);
+			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);
 			return NULL;
 		}
 
 		/* Find a TEI that is not allocated. */
-		tei = 64;
+		tei = Q921_TEI_AUTO_FIRST;
 		do {
 			for (sub = &ctrl->link; sub->next; sub = sub->next) {
 				if (sub->next->tei == tei) {
 					/* This TEI is already assigned, try next one. */
 					++tei;
-					if (tei < Q921_TEI_GROUP) {
+					if (tei <= Q921_TEI_AUTO_LAST) {
 						break;
 					}
-					/* XXX : TODO later sometime: Implement the TEI check procedure to reclaim some dead TEIs. */
-					pri_error(ctrl, "Reached maximum TEI quota, cannot assign new TEI\n");
+					pri_error(ctrl, "TEI pool exhausted.  Reclaiming dead TEIs.\n");
 					q921_send_tei(ctrl, Q921_TEI_IDENTITY_DENIED, ri, Q921_TEI_GROUP, 1);
+					q921_tei_check(ctrl);
 					return NULL;
 				}
 			}
@@ -1258,10 +1361,81 @@
 		}
 		q921_setstate(sub->next, Q921_TEI_ASSIGNED);
 		q921_send_tei(ctrl, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
+
+		count = 0;
+		for (sub = ctrl->link.next; sub; sub = sub->next) {
+			++count;
+		}
+		if (Q921_TEI_AUTO_LAST - Q921_TEI_AUTO_FIRST + 1 <= count) {
+			/*
+			 * We just allocated the last TEI.  Try to reclaim dead TEIs
+			 * before another is requested.
+			 */
+			q921_tei_check(ctrl);
+		}
+		break;
+	case Q921_TEI_IDENTITY_CHECK_RESPONSE:
+		if (!BRI_NT_PTMP(ctrl)) {
+			return NULL;
+		}
+
+		/* For each TEI listed in the message */
+		action = &h->data[4];
+		len -= (action - (u_int8_t *) h);
+		for (; len; --len, ++action) {
+			if (*action & 0x01) {
+				/* This is the last TEI in the list because the Ai E bit is set. */
+				len = 1;
+			}
+			tei = (*action >> 1);
+
+			if (tei == Q921_TEI_GROUP) {
+				pri_error(ctrl, "Received %s with invalid TEI %d\n",
+					q921_tei_mgmt2str(Q921_TEI_IDENTITY_CHECK_RESPONSE), tei);
+				continue;
+			}
+
+			for (sub = ctrl->link.next; sub; sub = sub->next) {
+				if (sub->tei == tei) {
+					/* Found the TEI. */
+					switch (sub->tei_check) {
+					case Q921_TEI_CHECK_NONE:
+						break;
+					case Q921_TEI_CHECK_DEAD:
+					case Q921_TEI_CHECK_DEAD_REPLY:
+						sub->tei_check = Q921_TEI_CHECK_REPLY;
+						break;
+					case Q921_TEI_CHECK_REPLY:
+						/* Duplicate TEI detected. */
+						sub->tei_check = Q921_TEI_CHECK_NONE;
+						q921_tei_remove(ctrl, tei);
+						q921_mdl_destroy(sub);
+						break;
+					}
+					break;
+				}
+			}
+			if (!sub) {
+				/* TEI not found. */
+				q921_tei_remove(ctrl, tei);
+			}
+		}
+		break;
+	case Q921_TEI_IDENTITY_VERIFY:
+		if (!BRI_NT_PTMP(ctrl)) {
+			return NULL;
+		}
+		if (tei == Q921_TEI_GROUP) {
+			pri_error(ctrl, "Received %s with invalid TEI %d\n",
+				q921_tei_mgmt2str(Q921_TEI_IDENTITY_VERIFY), tei);
+			return NULL;
+		}
+		q921_tei_check(ctrl);
 		break;
 	case Q921_TEI_IDENTITY_ASSIGNED:
-		if (!BRI_TE_PTMP(ctrl))
+		if (!BRI_TE_PTMP(ctrl)) {
 			return NULL;
+		}
 
 		/* Assuming we're operating on the specific TEI link here */
 		link = ctrl->link.next;
@@ -1325,8 +1499,9 @@
 		}
 		break;
 	case Q921_TEI_IDENTITY_CHECK_REQUEST:
-		if (!BRI_TE_PTMP(ctrl))
+		if (!BRI_TE_PTMP(ctrl)) {
 			return NULL;
+		}
 
 		/* Assuming we're operating on the specific TEI link here */
 		link = ctrl->link.next;
@@ -1342,8 +1517,9 @@
 		}
 		break;
 	case Q921_TEI_IDENTITY_REMOVE:
-		if (!BRI_TE_PTMP(ctrl))
+		if (!BRI_TE_PTMP(ctrl)) {
 			return NULL;
+		}
 
 		/* Assuming we're operating on the specific TEI link here */
 		link = ctrl->link.next;
@@ -1559,6 +1735,42 @@
 	link->mdl_free_me = mdl_free_me;
 }
 
+static void q921_mdl_link_destroy(struct q921_link *link)
+{
+	struct pri *ctrl;
+	struct q921_link *freep;
+	struct q921_link *prev;
+
+	ctrl = link->ctrl;
+
+	freep = NULL;
+	for (prev = &ctrl->link; prev->next; prev = prev->next) {
+		if (prev->next == link) {
+			prev->next = link->next;
+			freep = link;
+			break;
+		}
+	}
+	if (freep == NULL) {
+		pri_error(ctrl, "Huh!? no match found in list for TEI %d\n", -link->tei);
+		return;
+	}
+
+	if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+		pri_message(ctrl, "Freeing TEI of %d\n", -freep->tei);
+	}
+
+	pri_link_destroy(freep);
+}
+
+static void q921_mdl_destroy(struct q921_link *link)
+{
+	q921_mdl_remove(link);
+	if (link->mdl_free_me) {
+		q921_mdl_link_destroy(link);
+	}
+}
+
 static int q921_mdl_handle_network_error(struct q921_link *link, char error)
 {
 	int handled = 0;
@@ -1674,7 +1886,7 @@
 	}
 }
 
-static void q921_mdl_handle_error(struct q921_link *link, char error, int errored_state)
+static void q921_mdl_handle_error(struct q921_link *link, char error)
 {
 	struct pri *ctrl;
 
@@ -1695,36 +1907,13 @@
 {
 	struct q921_link *link = vlink;
 
-	q921_mdl_handle_error(link, link->mdl_error, link->mdl_error_state);
+	q921_mdl_handle_error(link, link->mdl_error);
 
 	link->mdl_error = 0;
 	link->mdl_timer = 0;
 
 	if (link->mdl_free_me) {
-		struct pri *ctrl;
-		struct q921_link *freep;
-		struct q921_link *prev;
-
-		ctrl = link->ctrl;
-
-		freep = NULL;
-		for (prev = &ctrl->link; prev->next; prev = prev->next) {
-			if (prev->next == link) {
-				prev->next = link->next;
-				freep = link;
-				break;
-			}
-		}
-		if (freep == NULL) {
-			pri_error(ctrl, "Huh!? no match found in list for TEI %d\n", -link->tei);
-			return;
-		}
-
-		if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
-			pri_message(ctrl, "Freeing TEI of %d\n", -freep->tei);
-		}
-
-		pri_link_destroy(freep);
+		q921_mdl_link_destroy(link);
 	}
 }
 
@@ -1835,7 +2024,6 @@
 		return;
 	}
 	link->mdl_error = error;
-	link->mdl_error_state = link->state;
 	link->mdl_timer = pri_schedule_event(ctrl, 0, q921_mdl_handle_error_callback, link);
 }
 




More information about the svn-commits mailing list