[libpri-commits] rmudgett: branch 1.4 r2105 - /branches/1.4/
SVN commits to the libpri project
libpri-commits at lists.digium.com
Fri Nov 5 15:05:29 CDT 2010
Author: rmudgett
Date: Fri Nov 5 15:05:25 2010
New Revision: 2105
URL: http://svnview.digium.com/svn/libpri?view=rev&rev=2105
Log:
Added TEI identity check feature to reclaim dead TEIs.
This is the new feature portion of JIRA LIBPRI-51/SWP-2453.
Modified:
branches/1.4/pri.c
branches/1.4/pri_internal.h
branches/1.4/pri_q921.h
branches/1.4/q921.c
Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=2105&r1=2104&r2=2105
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Fri Nov 5 15:05:25 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: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=2105&r1=2104&r2=2105
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Fri Nov 5 15:05:25 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: branches/1.4/pri_q921.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_q921.h?view=diff&rev=2105&r1=2104&r2=2105
==============================================================================
--- branches/1.4/pri_q921.h (original)
+++ branches/1.4/pri_q921.h Fri Nov 5 15:05:25 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 */
Modified: branches/1.4/q921.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q921.c?view=diff&rev=2105&r1=2104&r2=2105
==============================================================================
--- branches/1.4/q921.c (original)
+++ branches/1.4/q921.c Fri Nov 5 15:05:25 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);
/*!
@@ -1138,15 +1139,18 @@
if ((h->u.ft == 3) && (h->u.m3 == 0) && (h->u.m2 == 0) && (h->u.data[0] == 0x0f)) {
int ri;
- int tei;
-
- ri = (h->u.data[1] << 8) | h->u.data[2];
- tei = (h->u.data[4] >> 1);
- /* TEI assignment related */
+ u_int8_t *action;
+
+ /* TEI management related */
type = q921_tei_mgmt2str(h->u.data[3]);
pri_message(ctrl, "%c MDL Message: %d(%s)\n", direction_tag, h->u.data[3], type);
- pri_message(ctrl, "%c RI: %d\n", direction_tag, ri);
- pri_message(ctrl, "%c Ai: %d E:%d\n", direction_tag, (h->u.data[4] >> 1) & 0x7f, h->u.data[4] & 1);
+ ri = (h->u.data[1] << 8) | h->u.data[2];
+ pri_message(ctrl, "%c Ri: %d\n", direction_tag, ri);
+ action = &h->u.data[4];
+ for (x = len - (action - (u_int8_t *) h); 0 < x; --x, ++action) {
+ pri_message(ctrl, "%c Ai: %d E:%d\n",
+ direction_tag, (*action >> 1) & 0x7f, *action & 0x01);
+ }
}
}
@@ -1191,12 +1195,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,12 +1302,22 @@
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];
@@ -1232,18 +1337,18 @@
}
/* 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;
}
}
@@ -1259,6 +1364,79 @@
}
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.
+ */
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "Allocated last TEI. Reclaiming dead TEIs.\n");
+ }
+ 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)) {
@@ -1563,6 +1741,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;
@@ -1705,30 +1919,7 @@
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);
}
}
More information about the libpri-commits
mailing list