[libpri-commits] rmudgett: branch rmudgett/check_tei r2095 - /team/rmudgett/check_tei/
SVN commits to the libpri project
libpri-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 libpri-commits
mailing list