]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
-> adding ftmod_sangoma_ss7 support
authorKonrad Hammel <konrad@sangoma.com>
Sat, 5 Jun 2010 22:23:39 +0000 (18:23 -0400)
committerMoises Silva <moy@sangoma.com>
Fri, 18 Jun 2010 22:31:53 +0000 (18:31 -0400)
libs/freetdm/Makefile.am
libs/freetdm/configure.ac
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_suppport.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c [new file with mode: 0644]

index ed9d6197e1fc4b0705874a44457d84398993a870..be16cd5383f260e70e93646c5d56bc6a1c4766c9 100644 (file)
@@ -37,7 +37,10 @@ libdir = @libdir@
 library_includedir = $(PREFIX)/include
 
 INCS      = -I$(FT_SRCDIR)/$(SRC)/include -I$(FT_SRCDIR)/$(SRC)/isdn/include -I$(FT_SRCDIR)/$(SRC)/include/private
-INCS +=   -I$(FT_SRCDIR)/$(SRC)/ftmod/ftmod_sangoma_boost 
+INCS +=   -I$(FT_SRCDIR)/$(SRC)/ftmod/ftmod_sangoma_boost
+if SNGSS7
+INCS += -I/usr/include/wanpipe/sng_ss7/
+endif 
 MY_CFLAGS = $(INCS) $(FTDM_CFLAGS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@
 COMPILE   = $(CC) $(MY_CFLAGS) $(INCS)
 LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(COMPILE)
@@ -164,6 +167,10 @@ if LIBPRI
 mod_LTLIBRARIES += ftmod_libpri.la
 endif
 
+if SNGSS7
+mod_LTLIBRARIES += ftmod_sangoma_ss7.la
+endif
+
 if OPENR2
 mod_LTLIBRARIES += ftmod_r2.la
 endif
@@ -236,6 +243,20 @@ ftmod_libpri_la_LDFLAGS = -module  -avoid-version -lpri
 ftmod_libpri_la_LIBADD  = $(MYLIB)
 endif
 
+if SNGSS7
+ftmod_sangoma_ss7_la_SOURCES =  $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c \
+                               $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c \
+                               $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c \
+                               $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c \
+                               $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c \
+                               $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c \
+                               $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c \
+                               $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
+ftmod_sangoma_ss7_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE
+ftmod_sangoma_ss7_la_LDFLAGS = -module  -avoid-version -lsng_ss7
+ftmod_sangoma_ss7_la_LIBADD  = $(MYLIB)
+endif
+
 if OPENR2
 ftmod_r2_la_SOURCES = $(SRC)/ftmod/ftmod_r2/ftmod_r2.c 
 ftmod_r2_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
index fc141e888e72ccbc9b1c46d46df394b498d65c91..cad37c3705e7e78d6d6cdac89d7d8563fcca0dd7 100644 (file)
@@ -170,6 +170,9 @@ AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"])
 
 AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"])
 
+AC_CHECK_LIB([sng_ss7], [sng_isup_init], [have_sng_ss7="yes"])
+AM_CONDITIONAL([SNGSS7],[test "${have_sng_ss7}" = "yes"])
+
 AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [have_openr2="yes"])
 AM_CONDITIONAL([OPENR2],[test "${have_openr2}" = "yes"])
 
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
new file mode 100644 (file)
index 0000000..eaf36cf
--- /dev/null
@@ -0,0 +1,1023 @@
+/*
+ * Copyright (c) 2009|Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms|with or without
+ * modification|are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice|this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice|this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES|INCLUDING|BUT NOT
+ * LIMITED TO|THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT|INDIRECT|INCIDENTAL|SPECIAL,
+ * EXEMPLARY|OR CONSEQUENTIAL DAMAGES (INCLUDING|BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE|DATA|OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY|WHETHER IN CONTRACT|STRICT LIABILITY|OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE|EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* INCLUDE ********************************************************************/
+#include "ftmod_sangoma_ss7_main.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data);
+
+static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream);
+
+static ftdm_status_t handle_set_function_trace(ftdm_stream_handle_t *stream, int on, int level);
+static ftdm_status_t handle_set_message_trace(ftdm_stream_handle_t *stream, int on, int level);
+static ftdm_status_t handle_set_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose);
+static ftdm_status_t handle_set_unblks(ftdm_stream_handle_t *stream, int span, int chan, int verbose);
+
+static ftdm_status_t handle_show_free(ftdm_stream_handle_t *stream, int span, int chan, int verbose);
+static ftdm_status_t handle_show_inuse(ftdm_stream_handle_t *stream, int span, int chan, int verbose);
+static ftdm_status_t handle_show_inreset(ftdm_stream_handle_t *stream, int span, int chan, int verbose);
+static ftdm_status_t handle_show_flags(ftdm_stream_handle_t *stream, int span, int chan, int verbose);
+static ftdm_status_t handle_show_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose);
+static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, int chan, int verbose);
+
+static ftdm_status_t handle_status_link(ftdm_stream_handle_t *stream, char *name);
+static ftdm_status_t handle_status_linkset(ftdm_stream_handle_t *stream, char *name);
+
+static ftdm_status_t extract_span_chan(char *argv[10], int pos, int *span, int *chan);
+static ftdm_status_t check_arg_count(int args, int min);
+/******************************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data)
+{
+    char    *mycmd = NULL;
+    char    *argv[10] = { 0 };
+    int     argc = 0;
+    int     span = 0;
+    int     chan = 0;
+    int     trace = 0;
+    int     trace_level = 7;
+    int     verbose = 1;
+    int     c = 0;
+
+    if (data) {
+        mycmd = ftdm_strdup(data);
+        argc = ftdm_separate_string(mycmd,' ',argv,(sizeof(argv) / sizeof(argv[0])));
+    }
+
+    if (check_arg_count(argc, 1)) goto handle_cli_error_argc;
+    
+    if (!strcasecmp(argv[c], "show")) {
+    /**************************************************************************/   
+        if (check_arg_count(argc, 4)) goto handle_cli_error_argc;
+        c++;
+
+        if (!strcasecmp(argv[c], "status")) {
+        /**********************************************************************/
+            c++;
+
+            if (!strcasecmp(argv[c], "link")) {
+            /******************************************************************/
+                c++;
+                handle_status_link(stream, argv[c]);
+            /******************************************************************/
+            } else if (!strcasecmp(argv[c], "linkset")) {
+            /******************************************************************/
+                c++;
+                handle_status_linkset(stream, argv[c]);
+            /******************************************************************/
+            } else if (!strcasecmp(argv[c], "span")) {
+            /******************************************************************/
+                if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+
+                if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan;
+
+                handle_show_status(stream, span, chan, verbose);
+            /******************************************************************/
+            } else {
+            /******************************************************************/
+                stream->write_function(stream, "Unknown \"status\" command\n");
+                goto handle_cli_error;
+            /******************************************************************/
+            }
+        /**********************************************************************/
+        } else if (!strcasecmp(argv[c], "inuse")) {
+        /**********************************************************************/
+            if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+            c++;
+
+            if (!strcasecmp(argv[c], "span")) {
+            /******************************************************************/
+                if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+
+                if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan;
+
+                handle_show_inuse(stream, span, chan, verbose);
+            /******************************************************************/
+            } else {
+            /******************************************************************/
+                stream->write_function(stream, "Unknown \"inuse\" command\n");
+                goto handle_cli_error;
+            /******************************************************************/
+            }           
+        /**********************************************************************/
+        } else if (!strcasecmp(argv[c], "inreset")) {
+        /**********************************************************************/
+            if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+            c++;
+
+            if (!strcasecmp(argv[c], "span")) {
+            /******************************************************************/
+                if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+
+                if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan;
+
+                handle_show_inreset(stream, span, chan, verbose);
+            /******************************************************************/
+            } else {
+            /******************************************************************/
+                stream->write_function(stream, "Unknown \"inreset\" command\n");
+                goto handle_cli_error;
+            /******************************************************************/
+            }   
+        /**********************************************************************/
+        } else if (!strcasecmp(argv[c], "free")) {
+        /**********************************************************************/
+            if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+            c++;
+
+            if (!strcasecmp(argv[c], "span")) {
+            /******************************************************************/
+                if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+
+                if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan;
+
+                handle_show_free(stream, span, chan, verbose);
+            /******************************************************************/
+            } else {
+            /******************************************************************/
+                stream->write_function(stream, "Unknown \"free\" command\n");
+                goto handle_cli_error;
+            /******************************************************************/
+            }   
+        /**********************************************************************/
+        } else if (!strcasecmp(argv[c], "blocks")) {
+        /**********************************************************************/
+            if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+            c++;
+
+            if (!strcasecmp(argv[c], "span")) {
+            /******************************************************************/
+                if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+
+                if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan;
+
+                handle_show_blocks(stream, span, chan, verbose);
+            /******************************************************************/
+            } else {
+            /******************************************************************/
+                stream->write_function(stream, "Unknown \"blocks\" command\n");
+                goto handle_cli_error;
+            /******************************************************************/
+            }   
+        /**********************************************************************/
+        } else if (!strcasecmp(argv[c], "flags")) {
+        /**********************************************************************/
+            if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+            c++;
+
+            if (!strcasecmp(argv[c], "span")) {
+            /******************************************************************/
+                if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+
+                if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan;
+
+                handle_show_flags(stream, span, chan, verbose);
+            /******************************************************************/
+            } else {
+            /******************************************************************/
+                stream->write_function(stream, "Unknown \"flags\" command\n");
+                goto handle_cli_error;
+            /******************************************************************/
+            }   
+        /**********************************************************************/
+        } else {
+        /**********************************************************************/
+            stream->write_function(stream, "Unknown \"show\" command\n");
+            goto handle_cli_error;
+        /**********************************************************************/
+        }
+    /**************************************************************************/
+    } else if (!strcasecmp(argv[c], "set")) {
+    /**************************************************************************/
+        if (check_arg_count(argc, 4)) goto handle_cli_error_argc;
+        c++;
+
+        if (!strcasecmp(argv[c], "ftrace")) {
+        /**********************************************************************/
+            c++;
+            trace = atoi(argv[c]);
+            c++;
+            trace_level = atoi(argv[c]);
+            c++;
+            handle_set_function_trace(stream, trace, trace_level);
+        /**********************************************************************/
+        } else if (!strcasecmp(argv[c], "mtrace")) {
+        /**********************************************************************/
+            c++;
+            trace = atoi(argv[c]);
+            c++;
+            trace_level = atoi(argv[c]);
+            c++;
+            handle_set_message_trace(stream, trace, trace_level);
+        /**********************************************************************/
+        } else {
+        /**********************************************************************/
+            stream->write_function(stream, "Unknown \"set\" command\n");
+            goto handle_cli_error;
+        /**********************************************************************/
+        }  
+    /**************************************************************************/
+    } else if (!strcasecmp(argv[c], "block")) {
+    /**************************************************************************/
+        if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+        c++;
+
+        if (!strcasecmp(argv[c], "span")) {
+        /**********************************************************************/
+            if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+
+            if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan;
+
+            handle_set_blocks(stream, span, chan, verbose);
+        /**********************************************************************/
+        } else {
+        /**********************************************************************/
+            stream->write_function(stream, "Unknown \"block\" command\n");
+            goto handle_cli_error;
+        /**********************************************************************/
+        }   
+    /**************************************************************************/
+    } else if (!strcasecmp(argv[c], "unblock")) {
+    /**************************************************************************/
+        if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+        c++;
+
+        if (!strcasecmp(argv[c], "span")) {
+        /**********************************************************************/
+            if (check_arg_count(argc, 6)) goto handle_cli_error_argc;
+
+            if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan;
+
+            handle_set_unblks(stream, span, chan, verbose);
+        /**********************************************************************/
+        } else {
+        /**********************************************************************/
+            stream->write_function(stream, "Unknown \"unblock\" command\n");
+            goto handle_cli_error;
+        /**********************************************************************/
+        } 
+    /**************************************************************************/
+    } else {
+    /**************************************************************************/
+        goto handle_cli_error;
+    /**************************************************************************/
+    }
+
+    return FTDM_SUCCESS;
+
+handle_cli_error_argc:
+    stream->write_function(stream, "Invalid # of arguments in command\n");
+    handle_print_usuage(stream);
+    return FTDM_SUCCESS;
+
+handle_cli_error_span_chan:
+    stream->write_function(stream, "Unknown \"span\\chan\" command\n");
+    handle_print_usuage(stream);
+    return FTDM_SUCCESS;
+
+handle_cli_error:
+    stream->write_function(stream, "Unknown command requested\n");
+    handle_print_usuage(stream);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream)
+{
+    stream->write_function(stream, "Sangoma SS7 CLI usuage:\n\n");
+
+    stream->write_function(stream, "Ftmod_sangoma_ss7 general control:\n");
+    stream->write_function(stream, "ftdm ss7 set ftace X Y\n");
+    stream->write_function(stream, "ftdm ss7 set mtace X Y\n");
+    stream->write_function(stream, "\n");
+    stream->write_function(stream, "Ftmod_sangoma_ss7 information:\n");
+    stream->write_function(stream, "ftdm ss7 show status link X\n");
+    stream->write_function(stream, "ftdm ss7 show status linkset X\n");
+    stream->write_function(stream, "ftdm ss7 show status span X chan Y\n");
+    stream->write_function(stream, "ftdm ss7 show free span X chan Y\n");
+    stream->write_function(stream, "ftdm ss7 show inuse span X chan Y\n");
+    stream->write_function(stream, "ftdm ss7 show inreset span X chan Y\n");
+    stream->write_function(stream, "\n");
+    stream->write_function(stream, "Ftmod_sangoma_ss7 circuit control:\n");
+    stream->write_function(stream, "ftdm ss7 set block span X chan Y\n");
+    stream->write_function(stream, "ftdm ss7 set unblk span X chan Y\n");
+    stream->write_function(stream, "\n");
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_set_function_trace(ftdm_stream_handle_t *stream, int on, int level)
+{
+    stream->write_function(stream, "ftmod_sangoma_ss7 Function Trace was %s, level = %d\n",
+                            (g_ftdm_sngss7_data.function_trace == 1) ? "ON" : "OFF",
+                            g_ftdm_sngss7_data.function_trace_level);
+
+    g_ftdm_sngss7_data.function_trace = on;
+    g_ftdm_sngss7_data.function_trace_level = level;
+
+    stream->write_function(stream, "ftmod_sangoma_ss7 Function Trace now is %s, level = %d\n",
+                            (g_ftdm_sngss7_data.function_trace == 1) ? "ON" : "OFF",
+                            g_ftdm_sngss7_data.function_trace_level);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_set_message_trace(ftdm_stream_handle_t *stream, int on, int level)
+{
+    stream->write_function(stream, "ftmod_sangoma_ss7 Message Trace was %s, level = %d\n",
+                            (g_ftdm_sngss7_data.message_trace == 1) ? "ON" : "OFF",
+                            g_ftdm_sngss7_data.message_trace_level);
+
+    g_ftdm_sngss7_data.message_trace = on;
+    g_ftdm_sngss7_data.message_trace_level = level;
+
+    stream->write_function(stream, "ftmod_sangoma_ss7 Message Trace now is %s, level = %d\n",
+                            (g_ftdm_sngss7_data.message_trace == 1) ? "ON" : "OFF",
+                            g_ftdm_sngss7_data.message_trace_level);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_show_free(ftdm_stream_handle_t *stream, int span, int chan, int verbose)
+{
+    int                 x;
+    int                 free;
+    sngss7_chan_data_t  *ss7_info;
+    ftdm_channel_t      *ftdmchan;
+    int                 lspan;
+    int                 lchan;
+
+    x=1;
+    free = 0;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) {
+            ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj;
+            ftdmchan = ss7_info->ftdmchan;
+
+            /* if span == 0 then all spans should be printed */
+            if (span == 0) {
+                lspan = ftdmchan->physical_span_id;
+            } else {
+                lspan = span;
+            }
+
+            /* if chan == 0 then all chans should be printed */
+            if (chan == 0) {
+                lchan = ftdmchan->physical_chan_id;
+            } else {
+                lchan = chan;
+            }
+
+            if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
+                switch (ftdmchan->state) {
+                /******************************************************************/
+                case (FTDM_CHANNEL_STATE_DOWN):
+                    if (verbose) {
+                        stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|state=%s\n",
+                                    ftdmchan->physical_span_id,
+                                    ftdmchan->physical_chan_id,
+                                    ss7_info->circuit->cic,
+                                    ftdm_channel_state2str(ftdmchan->state));
+                    } /* if (verbose) */
+
+                    /*increment the count of circuits in reset */
+                    free++;
+                    break;
+                /******************************************************************/
+                default:
+                    break;
+                /******************************************************************/
+                } /* switch (ftdmchan->state) */
+            } /* if ( span and chan) */
+        } /* if ( cic != 0) */
+
+        /* go the next circuit */
+        x++;
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */
+
+    stream->write_function(stream, "\nTotal # of CICs free = %d\n",free);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_show_inuse(ftdm_stream_handle_t *stream, int span, int chan, int verbose)
+{
+    int                 x;
+    int                 in_use;
+    sngss7_chan_data_t  *ss7_info;
+    ftdm_channel_t      *ftdmchan;
+    int                 lspan;
+    int                 lchan;
+
+    x=1;
+    in_use = 0;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) {
+            ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj;
+            ftdmchan = ss7_info->ftdmchan;
+
+            /* if span == 0 then all spans should be printed */
+            if (span == 0) {
+                lspan = ftdmchan->physical_span_id;
+            } else {
+                lspan = span;
+            }
+
+            /* if chan == 0 then all chans should be printed */
+            if (chan == 0) {
+                lchan = ftdmchan->physical_chan_id;
+            } else {
+                lchan = chan;
+            }
+
+            if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
+                switch (ftdmchan->state) {
+                /******************************************************************/
+                case (FTDM_CHANNEL_STATE_COLLECT):
+                case (FTDM_CHANNEL_STATE_RING):
+                case (FTDM_CHANNEL_STATE_DIALING):
+                case (FTDM_CHANNEL_STATE_PROGRESS):
+                case (FTDM_CHANNEL_STATE_PROGRESS_MEDIA):
+                case (FTDM_CHANNEL_STATE_UP):
+                case (FTDM_CHANNEL_STATE_TERMINATING):
+                case (FTDM_CHANNEL_STATE_HANGUP):
+                    if (verbose) {
+                        stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|state=%s\n",
+                                    ftdmchan->physical_span_id,
+                                    ftdmchan->physical_chan_id,
+                                    ss7_info->circuit->cic,
+                                    ftdm_channel_state2str(ftdmchan->state));
+                    } /* if (verbose) */
+
+                    /*increment the count of circuits in reset */
+                    in_use++;
+                    break;
+                /******************************************************************/
+                default:
+                    break;
+                /******************************************************************/
+                } /* switch (ftdmchan->state) */
+            } /* if ( span and chan) */
+        } /* if ( cic != 0) */
+
+        /* go the next circuit */
+        x++;
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */
+
+    stream->write_function(stream, "\nTotal # of CICs in use = %d\n",in_use);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_show_inreset(ftdm_stream_handle_t *stream, int span, int chan, int verbose)
+{
+    int                 x;
+    int                 in_reset;
+    sngss7_chan_data_t  *ss7_info;
+    ftdm_channel_t      *ftdmchan;
+    int                 lspan;
+    int                 lchan;
+
+    x=1;
+    in_reset = 0;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) {
+            ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj;
+            ftdmchan = ss7_info->ftdmchan;
+
+            /* if span == 0 then all spans should be printed */
+            if (span == 0) {
+                lspan = ftdmchan->physical_span_id;
+            } else {
+                lspan = span;
+            }
+
+            /* if chan == 0 then all chans should be printed */
+            if (chan == 0) {
+                lchan = ftdmchan->physical_chan_id;
+            } else {
+                lchan = chan;
+            }
+
+            if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
+                if ((sngss7_test_flag(ss7_info, FLAG_RESET_RX)) || (sngss7_test_flag(ss7_info, FLAG_RESET_TX))) {
+                    if (verbose) {
+                        stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|in_reset=Y\n",
+                                    ftdmchan->physical_span_id,
+                                    ftdmchan->physical_chan_id,
+                                    ss7_info->circuit->cic);
+                    } /* if (verbose) */
+        
+                    /*increment the count of circuits in reset */
+                    in_reset++;
+                } /* if ((sngss7_test_flag(ss7_info, FLAG_RESET_RX) ... */
+            } /* if ( span and chan) */
+        } /* if ( cic != 0) */
+
+        /* go the next circuit */
+        x++;
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */
+
+    stream->write_function(stream, "\nTotal # of CICs in reset = %d\n",in_reset);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_show_flags(ftdm_stream_handle_t *stream, int span, int chan, int verbose)
+{
+    int                 x;
+    int                 bit;
+    sngss7_chan_data_t  *ss7_info;
+    ftdm_channel_t      *ftdmchan;
+    int                 lspan;
+    int                 lchan;
+
+    x=1;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) {
+            ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj;
+            ftdmchan = ss7_info->ftdmchan;
+
+            /* if span == 0 then all spans should be printed */
+            if (span == 0) {
+                lspan = ftdmchan->physical_span_id;
+            } else {
+                lspan = span;
+            }
+
+            /* if chan == 0 then all chans should be printed */
+            if (chan == 0) {
+                lchan = ftdmchan->physical_chan_id;
+            } else {
+                lchan = chan;
+            }
+
+            if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
+                stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d",
+                            ftdmchan->physical_span_id,
+                            ftdmchan->physical_chan_id,
+                            ss7_info->circuit->cic);
+    
+                for (bit = 0; bit < 33; bit++) {
+                    stream->write_function(stream, "|");
+                    if (ss7_info->flags & ( 0x1 << bit)) {
+                        stream->write_function(stream, "%2d=1", bit);
+                    } else {
+                        stream->write_function(stream, "%2d=0", bit);
+                    }
+                }
+
+                stream->write_function(stream, "\n");
+            } /* if ( span and chan) */
+
+        } /* if ( cic != 0) */
+
+        /* go the next circuit */
+        x++;
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_show_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose)
+{
+    int                 x;
+    sngss7_chan_data_t  *ss7_info;
+    ftdm_channel_t      *ftdmchan;
+    int                 lspan;
+    int                 lchan;
+
+    x=1;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) {
+            ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj;
+            ftdmchan = ss7_info->ftdmchan;
+
+            /* if span == 0 then all spans should be printed */
+            if (span == 0) {
+                lspan = ftdmchan->physical_span_id;
+            } else {
+                lspan = span;
+            }
+
+            /* if chan == 0 then all chans should be printed */
+            if (chan == 0) {
+                lchan = ftdmchan->physical_chan_id;
+            } else {
+                lchan = chan;
+            }
+
+            if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
+                stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|",
+                            ftdmchan->physical_span_id,
+                            ftdmchan->physical_chan_id,
+                            ss7_info->circuit->cic);
+
+                if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX))) {
+                    stream->write_function(stream, "l_mn=Y|");
+                }else {
+                    stream->write_function(stream, "l_mn=N|");
+                }
+
+                if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_RX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_RX))) {
+                    stream->write_function(stream, "r_mn=Y|");
+                }else {
+                    stream->write_function(stream, "r_mn=N|");
+                }
+
+                if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) {
+                    stream->write_function(stream, "l_hw=Y|");
+                }else {
+                    stream->write_function(stream, "l_hw=N|");
+                }
+
+                if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_RX)) {
+                    stream->write_function(stream, "r_hw=Y\n");
+                }else {
+                    stream->write_function(stream, "r_hw=N\n");
+                }
+            } /* if ( span and chan) */
+
+        } /* if ( cic != 0) */
+
+        /* go the next circuit */
+        x++;
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, int chan, int verbose)
+{
+    int                 x;
+    sngss7_chan_data_t  *ss7_info;
+    ftdm_channel_t      *ftdmchan;
+    int                 lspan;
+    int                 lchan;
+    ftdm_signaling_status_t sigstatus = FTDM_SIG_STATE_DOWN;
+
+    x=1;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) {
+            ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj;
+            ftdmchan = ss7_info->ftdmchan;
+
+            /* if span == 0 then all spans should be printed */
+            if (span == 0) {
+                lspan = ftdmchan->physical_span_id;
+            } else {
+                lspan = span;
+            }
+
+            /* if chan == 0 then all chans should be printed */
+            if (chan == 0) {
+                lchan = ftdmchan->physical_chan_id;
+            } else {
+                lchan = chan;
+            }
+
+            if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
+                /* grab the signaling_status */
+                ftdm_channel_get_sig_status(ftdmchan, &sigstatus);
+
+                stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|sig_status=%s|state=%s|",
+                            ftdmchan->physical_span_id,
+                            ftdmchan->physical_chan_id,
+                            ss7_info->circuit->cic,
+                            ftdm_signaling_status2str(sigstatus),
+                            ftdm_channel_state2str(ftdmchan->state));
+
+                if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX))) {
+                    stream->write_function(stream, "l_mn=Y|");
+                }else {
+                    stream->write_function(stream, "l_mn=N|");
+                }
+
+                if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_RX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_RX))) {
+                    stream->write_function(stream, "r_mn=Y|");
+                }else {
+                    stream->write_function(stream, "r_mn=N|");
+                }
+
+                if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) {
+                    stream->write_function(stream, "l_hw=Y|");
+                }else {
+                    stream->write_function(stream, "l_hw=N|");
+                }
+
+                if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_RX)) {
+                    stream->write_function(stream, "r_hw=Y\n");
+                }else {
+                    stream->write_function(stream, "r_hw=N\n");
+                }
+            } /* if ( span and chan) */
+
+        } /* if ( cic != 0) */
+
+        /* go the next circuit */
+        x++;
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */
+
+    return FTDM_SUCCESS;
+
+    return FTDM_SUCCESS;
+}
+/******************************************************************************/
+static ftdm_status_t handle_set_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose)
+{
+    int                 x;
+    sngss7_chan_data_t  *ss7_info;
+    ftdm_channel_t      *ftdmchan;
+    int                 lspan;
+    int                 lchan;
+
+    x=1;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) {
+            ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj;
+            ftdmchan = ss7_info->ftdmchan;
+
+            /* if span == 0 then all spans should be printed */
+            if (span == 0) {
+                lspan = ftdmchan->physical_span_id;
+            } else {
+                lspan = span;
+            }
+
+            /* if chan == 0 then all chans should be printed */
+            if (chan == 0) {
+                lchan = ftdmchan->physical_chan_id;
+            } else {
+                lchan = chan;
+            }
+
+            if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
+                /* now that we have the right channel...put a lock on it so no-one else can use it */
+                ftdm_mutex_lock(ftdmchan->mutex);
+
+                /* check if there is a pending state change|give it a bit to clear */
+                if (check_for_state_change(ftdmchan)) {
+                    SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic);
+                } else {
+                    /* throw the ckt block flag */
+                    sngss7_set_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX);
+
+                    /* set the channel to suspended state */
+                    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+                }
+
+                /* unlock the channel again before we exit */
+                ftdm_mutex_unlock(ftdmchan->mutex);
+
+            } /* if ( span and chan) */
+
+        } /* if ( cic != 0) */
+
+        /* go the next circuit */
+        x++;
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */
+
+    handle_show_blocks(stream, span, chan, verbose);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_set_unblks(ftdm_stream_handle_t *stream, int span, int chan, int verbose)
+{
+    int                 x;
+    sngss7_chan_data_t  *ss7_info;
+    ftdm_channel_t      *ftdmchan;
+    int                 lspan;
+    int                 lchan;
+
+    x=1;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) {
+            ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj;
+            ftdmchan = ss7_info->ftdmchan;
+
+            /* if span == 0 then all spans should be printed */
+            if (span == 0) {
+                lspan = ftdmchan->physical_span_id;
+            } else {
+                lspan = span;
+            }
+
+            /* if chan == 0 then all chans should be printed */
+            if (chan == 0) {
+                lchan = ftdmchan->physical_chan_id;
+            } else {
+                lchan = chan;
+            }
+
+            if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) {
+                /* now that we have the right channel...put a lock on it so no-one else can use it */
+                ftdm_mutex_lock(ftdmchan->mutex);
+
+                /* check if there is a pending state change|give it a bit to clear */
+                if (check_for_state_change(ftdmchan)) {
+                    SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic);
+                } else {
+                    /* throw the ckt block flag */
+                    sngss7_set_flag(ss7_info, FLAG_CKT_MN_UNBLK_TX);
+
+                    /* clear the block flag */
+                    sngss7_clear_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX);
+
+                    /* set the channel to suspended state */
+                    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+                }
+
+                /* unlock the channel again before we exit */
+                ftdm_mutex_unlock(ftdmchan->mutex);
+
+            } /* if ( span and chan) */
+
+        } /* if ( cic != 0) */
+
+        /* go the next circuit */
+        x++;
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */
+
+    handle_show_blocks(stream, span, chan, verbose);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_status_link(ftdm_stream_handle_t *stream, char *name)
+{
+    int x;
+    sng_mtp3Link_sta_t  sta;
+
+    /* find the link request by it's name */
+    x = 1;
+    while(g_ftdm_sngss7_data.cfg.mtp3Link[x].id != 0) {
+        if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtp3Link[x].name, name)) {
+            /* send the status request */
+            if (sng_sta_mtp3_link(&g_ftdm_sngss7_data.cfg, x, &sta)) {
+                stream->write_function(stream, "Failed to read link=%s status\n", name);
+                return FTDM_FAIL;
+            }
+
+            /* print the results */
+            stream->write_function(stream, "%s|state=%s|l_blk=%s|r_blk=%s|l_inhbt=%s|r_inhbt=%s\n",
+                        name,
+                        DECODE_LSN_LINK_STATUS(sta.state),
+                        (sta.lblkd) ? "Y":"N",
+                        (sta.rblkd) ? "Y":"N",
+                        (sta.linhbt) ? "Y":"N",
+                        (sta.rinhbt) ? "Y":"N");
+            break;
+        }
+        
+        /* move to the next link */
+        x++;
+    } /* while (id != 0) */
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_status_linkset(ftdm_stream_handle_t *stream, char *name)
+{
+    int x;
+    sng_mtp3LinkSet_sta_t  sta;
+
+    /* find the linkset request by it's name */
+    x = 1;
+    while(g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].id != 0) {
+        if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].name, name)) {
+            /* send the status request */
+            if (sng_sta_mtp3_linkset(&g_ftdm_sngss7_data.cfg, x, 0, &sta)) {
+                stream->write_function(stream, "Failed to read linkset=%s status\n", name);
+                return FTDM_FAIL;
+            }
+
+            /* print the results */
+            stream->write_function(stream, "%s|state=%s|nmbActLnk=%d\n",
+                        name,
+                        DECODE_LSN_LINKSET_STATUS(sta.state),
+                        sta.nmbActLnks);
+            break;
+        }
+        /* move to the next linkset */
+        x++;
+    } /* while (id != 0) */
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t extract_span_chan(char *argv[10], int pos, int *span, int *chan)
+{
+
+    if (!strcasecmp(argv[pos], "span")) {
+    /**************************************************************************/
+        pos++;
+        *span = atoi(argv[pos]);
+
+        pos++;
+        if (!strcasecmp(argv[pos], "chan")) {
+        /**********************************************************************/
+            pos++;
+            *chan = atoi(argv[pos]);
+        /**********************************************************************/
+        } else {
+        /**********************************************************************/
+            return FTDM_FAIL;
+        /**********************************************************************/
+        }
+    /**************************************************************************/
+    } else {
+    /**************************************************************************/
+        *span = atoi(argv[pos]);
+
+        pos++;
+        if (!strcasecmp(argv[pos], "chan")) {
+        /**********************************************************************/
+            pos++;
+            *chan = atoi(argv[pos]);
+        /**********************************************************************/
+        } else {
+        /**********************************************************************/
+            return FTDM_FAIL;
+        /**********************************************************************/
+        }
+    /**************************************************************************/
+    }
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t check_arg_count(int args, int min)
+{
+    if ( args < min ) {
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}        
+
+/******************************************************************************/
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+/******************************************************************************/
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c
new file mode 100644 (file)
index 0000000..f0c1572
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* INCLUDE ********************************************************************/
+#include "ftmod_sangoma_ss7_main.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+void handle_sng_log(uint8_t level, char *fmt,...);
+void handle_sng_alarm(sng_alrm_t t_alarm);
+
+static void handle_entsi_alarm(sng_alrm_t t_alarm);
+
+int ft_to_sngss7_cfg(void);
+int ft_to_sngss7_activate_all(void);
+
+static int ftmod_ss7_general_configuration(void);
+
+static int ftmod_ss7_configure_mtp1_link(int id);
+
+static int ftmod_ss7_configure_mtp2_link(int id);
+
+static int ftmod_ss7_configure_mtp3_link(int id);
+static int ftmod_ss7_configure_mtp3_linkset(int id);
+static int ftmod_ss7_configure_mtp3_route(int id);
+static int ftmod_ss7_configure_mtp3_isup(int id);
+
+static int ftmod_ss7_configure_isup_mtp3(int id);
+static int ftmod_ss7_configure_isup_interface(int id);
+static int ftmod_ss7_configure_isup_circuit(int id);
+static int ftmod_ss7_configure_isup_cc(int id);
+
+static int ftmod_ss7_configure_cc_isup(int id);
+
+/******************************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+
+/* LOGGIGING ******************************************************************/
+void handle_sng_log(uint8_t level, char *fmt,...)
+{
+    char    *data;
+    int     ret;
+    va_list ap;
+
+    va_start(ap, fmt);
+    ret = vasprintf(&data, fmt, ap);
+    if (ret == -1) {
+        return;
+    }
+
+    switch (level) {
+    /**************************************************************************/
+    case SNG_LOGLEVEL_DEBUG:
+        ftdm_log(FTDM_LOG_DEBUG, "sng_ss7->%s", data);
+        break;
+    /**************************************************************************/
+    case SNG_LOGLEVEL_WARN:
+        ftdm_log(FTDM_LOG_INFO, "sng_ss7->%s", data);
+        break;
+    /**************************************************************************/
+    case SNG_LOGLEVEL_INFO:
+        ftdm_log(FTDM_LOG_INFO, "sng_ss7->%s", data);
+        break;
+    /**************************************************************************/
+    case SNG_LOGLEVEL_STATS:
+        ftdm_log(FTDM_LOG_INFO, "sng_ss7->%s", data);
+        break;
+    /**************************************************************************/
+    case SNG_LOGLEVEL_ERROR:
+        ftdm_log(FTDM_LOG_ERROR, "sng_ss7->%s", data);
+        break;
+    /**************************************************************************/
+    case SNG_LOGLEVEL_CRIT:
+        printf("%s",data);
+        /*ftdm_log(FTDM_LOG_CRIT, "sng_ss7->%s", data);*/
+        break;
+    /**************************************************************************/
+    default:
+        ftdm_log(FTDM_LOG_INFO, "sng_ss7->%s", data);
+        break;
+    /**************************************************************************/
+    }
+
+    return;
+}
+
+/******************************************************************************/
+void handle_sng_alarm(sng_alrm_t t_alarm)
+{
+
+    switch (t_alarm.entity) {
+    /**************************************************************************/
+    case (ENTL1):
+        ftdm_log(FTDM_LOG_WARNING,"[SNG-MTP1] %s : %s : %s \n",
+                                    DECODE_LL1_EVENT(t_alarm.event),
+                                    DECODE_LL1_CAUSE(t_alarm.cause),
+                                    DECODE_LL1_PARM(t_alarm.eventParm[0]));
+        break;
+    /**************************************************************************/
+    case (ENTSD):
+        ftdm_log(FTDM_LOG_WARNING,"[SNG-MTP2] %s : %s \n",
+                                    DECODE_LSD_EVENT(t_alarm.event),
+                                    DECODE_LSD_CAUSE(t_alarm.cause));
+        break;
+    /**************************************************************************/
+    case (ENTSN):
+        ftdm_log(FTDM_LOG_WARNING,"[SNG-MTP3] %s on %d: %s \n",
+                                    DECODE_LSN_EVENT(t_alarm.event),
+                                    t_alarm.id,
+                                    DECODE_LSN_CAUSE(t_alarm.cause));
+        break;
+    /**************************************************************************/
+    case (ENTSI):
+        handle_entsi_alarm(t_alarm);
+        break;
+    /**************************************************************************/
+    case (ENTCC):
+        ftdm_log(FTDM_LOG_DEBUG,"[SNG-CC] %s : %s \n",
+                                    DECODE_LCC_EVENT(t_alarm.event),
+                                    DECODE_LCC_CAUSE(t_alarm.cause));
+        break;
+    /**************************************************************************/
+    default:
+        ftdm_log(FTDM_LOG_WARNING,"Received alarm from unknown entity");
+        break;
+    /**************************************************************************/
+    } /* switch (t_alarm.entity) */
+
+    return;
+}
+
+/******************************************************************************/
+static void handle_entsi_alarm(sng_alrm_t alarm)
+{
+
+    switch (alarm.event) {
+    /**************************************************************************/
+    case (LCM_EVENT_TIMEOUT):
+        /* this event always has the circuit value embedded */
+        SS7_WARN("[ISUP] Timer %d expired on CIC %d\n",
+                    (alarm.eventParm[1] > 0 ) ? alarm.eventParm[1] : alarm.eventParm[8],
+                    g_ftdm_sngss7_data.cfg.isupCircuit[alarm.eventParm[0]].cic);
+        break;
+    /**************************************************************************/
+    case (LSI_EVENT_REMOTE):
+        SS7_WARN("[ISUP] %s received on CIC %d\n",
+                    DECODE_LSI_CAUSE(alarm.cause),
+                    g_ftdm_sngss7_data.cfg.isupCircuit[alarm.eventParm[0]].cic);
+        break;
+    /**************************************************************************/
+    case (LSI_EVENT_LOCAL):
+        SS7_WARN("[ISUP] %s transmitted on CIC %d\n",
+                    DECODE_LSI_CAUSE(alarm.cause),
+                    g_ftdm_sngss7_data.cfg.isupCircuit[alarm.eventParm[0]].cic);
+        break;
+    /**************************************************************************/
+    case (LSI_EVENT_MTP):
+        SS7_WARN("[ISUP] Received %s on %d\n",
+                    DECODE_LSI_CAUSE(alarm.cause),
+                    g_ftdm_sngss7_data.cfg.mtp3_isup[alarm.eventParm[2]].id);
+        break;
+    /**************************************************************************/
+    case (LCM_EVENT_UI_INV_EVT):
+        switch (alarm.cause) {
+        /**********************************************************************/
+        case (LSI_CAUSE_INV_CIRCUIT):
+            SS7_WARN("[ISUP] Invalid circuit = %d (CIC = %d)\n",
+                        alarm.eventParm[0],
+                        g_ftdm_sngss7_data.cfg.isupCircuit[alarm.eventParm[0]].cic);
+            break;
+        /**********************************************************************/
+        }
+        break;
+    /**************************************************************************/
+    case (LCM_EVENT_LI_INV_EVT):
+        switch (alarm.cause) {
+        /**********************************************************************/
+        case (LCM_CAUSE_INV_SAP):
+            SS7_WARN("[ISUP] Invalid spId = %d\n",
+                        alarm.eventParm[3]);
+            break;
+        /**********************************************************************/
+        }
+        break;
+    /**************************************************************************/
+    default:
+        SS7_WARN("[ISUP] %s : %s \n", DECODE_LSI_EVENT(alarm.event), DECODE_LSI_CAUSE(alarm.cause));
+        break;
+    /**************************************************************************/
+    } /* switch (alarm.event) */
+    return;
+}
+
+/* ACTIVATION *****************************************************************/
+int ft_to_sngss7_activate_all(void)
+{
+    sng_isup_cc_t       *cc_isup = NULL;
+    sng_mtp3_isup_t     *isup_mtp3 = NULL;
+    sng_mtp3LinkSet_t   *mtp3_linkset = NULL;
+    int                 x;
+
+    /* CC to ISUP *************************************************************/
+    x = 1;
+    cc_isup = &g_ftdm_sngss7_data.cfg.isup_cc[x];
+    while (cc_isup->id != 0) {
+        if (sngss7_test_flag(cc_isup, SNGSS7_FLAG_ACTIVE)) {
+            SS7_DEBUG("CC-ISUP interface already active = %d\n", cc_isup->id);
+        } else {
+            if (sng_activate_cc_isup_inf(cc_isup->ccId)) {
+                SS7_ERROR("Failed to activate CC-ISUP = %d\n",cc_isup->id);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Started CC-ISUP interface = %d\n", cc_isup->id);
+                sngss7_set_flag(cc_isup, SNGSS7_FLAG_ACTIVE);
+            }
+        } /* if (sngss7_test_flag(cc_isup, SNGSS7_FLAG_ACTIVE) */
+
+        x++;
+        cc_isup = &g_ftdm_sngss7_data.cfg.isup_cc[x];
+    } /* while (cc_isup->id != 0) */
+
+    /* ISUP - MTP3 ************************************************************/
+    x = 1;
+    isup_mtp3 = &g_ftdm_sngss7_data.cfg.mtp3_isup[x];
+    while (isup_mtp3->id != 0) {
+        if (sngss7_test_flag(isup_mtp3, SNGSS7_FLAG_ACTIVE)) {
+            SS7_DEBUG("ISUP-MTP3 interface already active = %d\n", isup_mtp3->id);
+        } else {
+            if (sng_activate_isup_mtp3_inf(isup_mtp3->id)) {
+                SS7_ERROR("Failed to activate ISUP-MTP3 = %d\n",isup_mtp3->id);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Started ISUP-MTP3interface = %d\n", isup_mtp3->id);
+                sngss7_set_flag(isup_mtp3, SNGSS7_FLAG_ACTIVE);
+            }
+        } /* if (sngss7_test_flag(isup_mtp3, SNGSS7_FLAG_ACTIVE) */
+
+        x++;
+        isup_mtp3 = &g_ftdm_sngss7_data.cfg.mtp3_isup[x];
+    } /* while (isup_mtp3->id != 0) */
+
+    /* MTP3 Linkset (MTP3 - MTP2 - MTP1) **************************************/
+    x = 1;
+    mtp3_linkset = &g_ftdm_sngss7_data.cfg.mtp3LinkSet[x];
+    while (mtp3_linkset->id != 0) {
+        if (sngss7_test_flag(mtp3_linkset, SNGSS7_FLAG_ACTIVE)) {
+            SS7_DEBUG("MTP3 Linkset already active = %s\n", mtp3_linkset->name);
+        } else {
+            if (sng_activate_mtp3_linkset(mtp3_linkset->id)) {
+                SS7_ERROR("Failed to activate MTP3 Linkset = %s\n",mtp3_linkset->name);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Started MTP3 Linkset = %s\n", mtp3_linkset->name);
+                sngss7_set_flag(mtp3_linkset, SNGSS7_FLAG_ACTIVE);
+            }
+        } /* if (sngss7_test_flag(mtp3_linkset, SNGSS7_FLAG_ACTIVE) */
+
+        x++;
+        mtp3_linkset = &g_ftdm_sngss7_data.cfg.mtp3LinkSet[x];
+    } /* while (mtp3_linkset->id != 0) */
+
+    return FTDM_SUCCESS;
+}
+
+/* CONFIGURATION **************************************************************/
+int  ft_to_sngss7_cfg(void)
+{
+    sng_mtp1Link_t      *mtp1_link = NULL;
+    sng_mtp2Link_t      *mtp2_link = NULL;
+    sng_mtp3Link_t      *mtp3_link = NULL;
+    sng_mtp3LinkSet_t   *mtp3_linkset = NULL;
+    sng_mtp3Route_t     *mtp3_route = NULL;
+    sng_mtp3_isup_t     *mtp3_isup = NULL;
+    sng_mtp3_isup_t     *isup_mtp3 = NULL;
+    sng_isupInterface_t *isup_interface = NULL;
+    sng_isupCircuit_t   *isup_circuit = NULL;
+    sng_isup_cc_t       *isup_cc = NULL;
+    sng_isup_cc_t       *cc_isup = NULL;
+    int x;
+
+    SS7_DEBUG("Starting LibSngSS7 configuration...\n");
+
+    if (g_ftdm_sngss7_data.gen_config_done == 0) {
+        /* perform general configuration */
+        if(ftmod_ss7_general_configuration()) {
+            SS7_ERROR("Failed to run general configuration!\n");
+            return FTDM_FAIL;
+        } else {
+            SS7_INFO("General Configuration was successful\n");
+            g_ftdm_sngss7_data.gen_config_done = 1;
+        }
+    } else {
+        SS7_DEBUG("General configuration already done.\n");
+    }
+
+    /* MTP1 *******************************************************************/
+    x=1;
+    mtp1_link = &g_ftdm_sngss7_data.cfg.mtp1Link[x];
+    while (mtp1_link->id != 0) {
+
+        if (sngss7_test_flag(mtp1_link, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("MTP1 Link already configured = %s\n",mtp1_link->name);
+        } else {
+            if (ftmod_ss7_configure_mtp1_link(x)) {
+                SS7_ERROR("Failed to configure MTP1 link = %s\n!", mtp1_link->name);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured MTP1 link = %s\n", mtp1_link->name);
+                sngss7_set_flag(mtp1_link, SNGSS7_FLAG_CONFIGURED);
+            }
+        }
+
+        /* next link */
+        x++;
+        mtp1_link = &g_ftdm_sngss7_data.cfg.mtp1Link[x];
+    } /* while (g_ftdm_sngss7_data.cfg.mtp1Link[x]->id != 0) */
+
+    /* MTP2 *******************************************************************/
+    x=1;
+    mtp2_link = &g_ftdm_sngss7_data.cfg.mtp2Link[x];
+    while (mtp2_link->id != 0) {
+        if (sngss7_test_flag(mtp2_link, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("MTP2 Link already configured = %s\n",mtp2_link->name);
+        } else {
+            if (ftmod_ss7_configure_mtp2_link(x)) {
+                SS7_ERROR("Failed to configure MTP2 link = %s\n!", mtp2_link->name);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured MTP2 link = %s\n", mtp2_link->name);
+                sngss7_set_flag(mtp2_link, SNGSS7_FLAG_CONFIGURED);
+            }
+        }
+        /* next link */
+        x++;
+        mtp2_link = &g_ftdm_sngss7_data.cfg.mtp2Link[x];
+    } /* while (g_ftdm_sngss7_data.cfg.mtp2Link[x]->id != 0) */
+
+    /* MTP3 *******************************************************************/
+    x=1;
+    mtp3_link = &g_ftdm_sngss7_data.cfg.mtp3Link[x];
+    while (mtp3_link->id != 0) {
+        if (sngss7_test_flag(mtp3_link, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("MTP3 Link already configured = %s\n", mtp3_link->name);
+        } else {
+            if (ftmod_ss7_configure_mtp3_link(x)) {
+                SS7_ERROR("Failed to configure MTP3 link = %s\n!", mtp3_link->name);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured MTP3 link = %s\n", mtp3_link->name);
+                sngss7_set_flag(mtp3_link, SNGSS7_FLAG_CONFIGURED);
+            }
+        }
+        /* next link */
+        x++;
+        mtp3_link = &g_ftdm_sngss7_data.cfg.mtp3Link[x];
+    } /* while (g_ftdm_sngss7_data.cfg.mtp3Link[x]->id != 0) */
+
+    x=1;
+    mtp3_linkset = &g_ftdm_sngss7_data.cfg.mtp3LinkSet[x];
+    while (mtp3_linkset->id != 0) {
+        if (sngss7_test_flag(mtp3_linkset, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("MTP3 LinkSet already configured = %s\n", mtp3_linkset->name);
+        } else {
+            if (ftmod_ss7_configure_mtp3_linkset(x)) {
+                SS7_ERROR("Failed to configure MTP3 link = %s\n!", mtp3_linkset->name);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured MTP3 link = %s\n", mtp3_linkset->name);
+                sngss7_set_flag(mtp3_linkset, SNGSS7_FLAG_CONFIGURED);
+            }
+        }
+        /* next link */
+        x++;
+        mtp3_linkset = &g_ftdm_sngss7_data.cfg.mtp3LinkSet[x];
+    } /* while (g_ftdm_sngss7_data.cfg.mtp1Link[x]->id != 0) */
+
+    x=1;
+    mtp3_route = &g_ftdm_sngss7_data.cfg.mtp3Route[x];
+    while (mtp3_route->id != 0) {
+        if (sngss7_test_flag(mtp3_route, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("MTP3 Route already configured = %s\n", mtp3_route->name);
+        } else {
+            if (ftmod_ss7_configure_mtp3_route(x)) {
+                SS7_ERROR("Failed to configure MTP3 route = %s\n!", mtp3_route->name);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured MTP3 route = %s\n", mtp3_route->name);
+                sngss7_set_flag(mtp3_route, SNGSS7_FLAG_CONFIGURED);
+            }
+        }
+        /* next link */
+        x++;
+        mtp3_route = &g_ftdm_sngss7_data.cfg.mtp3Route[x];
+    } /* while (g_ftdm_sngss7_data.cfg.mtp3Route[x]->id != 0) */
+
+    mtp3_route = &g_ftdm_sngss7_data.cfg.mtp3Route[0];
+    if (sngss7_test_flag(mtp3_route, SNGSS7_FLAG_CONFIGURED)) {
+        SS7_DEBUG("MTP3 Self Route already configured\n");
+    } else {
+        if (ftmod_ss7_configure_mtp3_route(0)) {
+            SS7_ERROR("Failed to configure MTP3 Route = SelfRoute\n!");
+            return FTDM_FAIL;
+        } else {
+            SS7_INFO("Successfully configured MTP3 Route = SelfRoute\n");
+            sngss7_set_flag(mtp3_route, SNGSS7_FLAG_CONFIGURED);
+        }
+    }
+
+    x=1;
+    mtp3_isup = &g_ftdm_sngss7_data.cfg.mtp3_isup[x];
+    while (mtp3_isup->id != 0) {
+        if (sngss7_test_flag(mtp3_isup, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("MTP3-ISUP interface already configured = %d\n", mtp3_isup->id);
+        } else {
+            if (ftmod_ss7_configure_mtp3_isup(x)) {
+                SS7_ERROR("Failed to configure MTP3-ISUP interface = %d\n!", mtp3_isup->id);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured MTP3-ISUP interface = %d\n", mtp3_isup->id);
+            }
+        }
+        /* next link */
+        x++;
+        mtp3_isup = &g_ftdm_sngss7_data.cfg.mtp3_isup[x];
+    } /* while (g_ftdm_sngss7_data.cfg.mtp3_isup[x]->id != 0) */
+
+    /* ISUP *******************************************************************/
+    x=1;
+    isup_mtp3 = &g_ftdm_sngss7_data.cfg.mtp3_isup[x];
+    while (isup_mtp3->id != 0) {
+        if (sngss7_test_flag(isup_mtp3, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("ISUP-MTP3 interface already configured = %d\n", isup_mtp3->id);
+        } else {
+            if (ftmod_ss7_configure_isup_mtp3(x)) {
+                SS7_ERROR("Failed to configure ISUP-MTP3 interface = %d\n!", isup_mtp3->id);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured ISUP-MTP3 interface = %d\n", isup_mtp3->id);
+                sngss7_set_flag(isup_mtp3, SNGSS7_FLAG_CONFIGURED);
+            }
+        }
+        /* next link */
+        x++;
+        isup_mtp3 = &g_ftdm_sngss7_data.cfg.mtp3_isup[x];
+    } /* while (g_ftdm_sngss7_data.cfg.isup_mtp3[x]->id != 0) */
+
+    x=1;
+    isup_cc = &g_ftdm_sngss7_data.cfg.isup_cc[x];
+    while (isup_cc->id != 0) {
+        if (sngss7_test_flag(isup_cc, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("ISUP-CC interface already configured = %d\n", isup_cc->id);
+        } else {
+            if (ftmod_ss7_configure_isup_cc(x)) {
+                SS7_ERROR("Failed to configure ISUP-CC interface = %d\n!", isup_cc->id);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured ISUP-CC interface = %d\n", isup_cc->id);
+            }
+        }
+        /* next link */
+        x++;
+        isup_cc = &g_ftdm_sngss7_data.cfg.isup_cc[x];
+    } /* while (g_ftdm_sngss7_data.cfg.isup_cc[x]->id != 0) */
+
+    x=1;
+    isup_interface = &g_ftdm_sngss7_data.cfg.isupInterface[x];
+    while (isup_interface->id != 0) {
+        if (sngss7_test_flag(isup_interface, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("ISUP interface already configured = %s\n", isup_interface->name);
+        } else {
+            if (ftmod_ss7_configure_isup_interface(x)) {
+                SS7_ERROR("Failed to configure ISUP interface = %s\n!", isup_interface->name);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured ISUP interface = %s\n", isup_interface->name);
+                sngss7_set_flag(isup_interface, SNGSS7_FLAG_CONFIGURED);
+            }
+        }
+        /* next link */
+        x++;
+        isup_interface = &g_ftdm_sngss7_data.cfg.isupInterface[x];
+    } /* while (g_ftdm_sngss7_data.cfg.isup_interface[x]->id != 0) */
+
+    x=1;
+    isup_circuit = &g_ftdm_sngss7_data.cfg.isupCircuit[x];
+    while (isup_circuit->id != 0) {
+        if (isup_circuit->cic != 0) {
+            if (sngss7_test_flag(isup_circuit, SNGSS7_FLAG_CONFIGURED)) {
+                SS7_DEBUG("ISUP Circuit already configured = %d\n", isup_circuit->id);
+            } else {
+                if (ftmod_ss7_configure_isup_circuit(x)) {
+                    SS7_ERROR("Failed to configure ISUP circuit = %d\n!", isup_circuit->id);
+                    return FTDM_FAIL;
+                } else {
+                    SS7_INFO("Successfully configured ISUP circuit = %d\n", isup_circuit->id);
+                    sngss7_set_flag(isup_circuit, SNGSS7_FLAG_CONFIGURED);
+                }
+            }
+        }
+        /* next link */
+        x++;
+        isup_circuit = &g_ftdm_sngss7_data.cfg.isupCircuit[x];
+    } /* while (g_ftdm_sngss7_data.cfg.isup_circuit[x]->id != 0) */
+
+    /* CC *********************************************************************/
+
+    x=1;
+    cc_isup = &g_ftdm_sngss7_data.cfg.isup_cc[x];
+    while (cc_isup->id != 0) {
+        if (sngss7_test_flag(cc_isup, SNGSS7_FLAG_CONFIGURED)) {
+            SS7_DEBUG("CC-ISUP interface already configured = %d\n", cc_isup->id);
+        } else {
+            if (ftmod_ss7_configure_cc_isup(x)) {
+                SS7_ERROR("Failed to configure CC-ISUP interface = %d\n!", cc_isup->id);
+                return FTDM_FAIL;
+            } else {
+                SS7_INFO("Successfully configured CC-ISUP interface = %d\n", cc_isup->id);
+                sngss7_set_flag(cc_isup, SNGSS7_FLAG_CONFIGURED);
+            }
+        }
+        /* next link */
+        x++;
+        cc_isup = &g_ftdm_sngss7_data.cfg.isup_cc[x];
+    } /* while (g_ftdm_sngss7_data.cfg.cc_isup[x]->id != 0) */
+    
+    SS7_DEBUG("Finished LibSngSS7 configuration...\n");
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_general_configuration(void)
+{
+
+    if(sng_cfg_mtp1_gen(&g_ftdm_sngss7_data.cfg)) {
+        SS7_ERROR("General configuration for MTP1 failed!\n");
+        return FTDM_FAIL;
+    } else {
+        SS7_INFO("General configuration for MTP1 was successful\n");
+    }
+
+    if(sng_cfg_mtp2_gen(&g_ftdm_sngss7_data.cfg)) {
+        SS7_ERROR("General configuration for MTP2 failed!\n");
+        return FTDM_FAIL;
+    } else {
+        SS7_INFO("General configuration for MTP2 was successful\n");
+    }
+
+    if(sng_cfg_mtp3_gen(&g_ftdm_sngss7_data.cfg)) {
+        SS7_ERROR("General configuration for MTP3 failed!\n");
+        return FTDM_FAIL;
+    } else {
+        SS7_INFO("General configuration for MTP3 was successful\n");
+    }
+
+    if(sng_cfg_isup_gen(&g_ftdm_sngss7_data.cfg)) {
+        SS7_ERROR("General configuration for ISUP failed!\n");
+        return FTDM_FAIL;
+    } else {
+        SS7_INFO("General configuration for ISUP was successful\n");
+    }
+
+    if(sng_cfg_cc_gen(&g_ftdm_sngss7_data.cfg)) {
+        SS7_ERROR("General configuration for Call-Control failed!\n");
+        return FTDM_FAIL;
+    } else {
+        SS7_INFO("General configuration for Call-Control was successful\n");
+    }
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_mtp1_link(int id)
+{
+    if(sng_cfg_mtp1_link(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_mtp2_link(int id)
+{
+    if(sng_cfg_mtp2_link(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_mtp3_link(int id)
+{
+    if(sng_cfg_mtp3_link(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_mtp3_linkset(int id)
+{
+    if(sng_cfg_mtp3_linkset(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_mtp3_route(int id)
+{
+    if(sng_cfg_mtp3_route(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_mtp3_isup(int id)
+{
+    if(sng_cfg_mtp3_isup_interface(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_isup_mtp3(int id)
+{
+    if(sng_cfg_isup_mtp3_interface(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_isup_interface(int id)
+{
+    if(sng_cfg_isup_interface(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_isup_circuit(int id)
+{
+    if(sng_cfg_isup_circuit(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_isup_cc(int id)
+{
+    if(sng_cfg_isup_cc_interface(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+/******************************************************************************/
+static int ftmod_ss7_configure_cc_isup(int id)
+{
+    if(sng_cfg_cc_isup_interface(&g_ftdm_sngss7_data.cfg, id)){
+        return FTDM_FAIL;
+    } else {
+        return FTDM_SUCCESS;
+    }
+}
+
+
+/******************************************************************************/
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+/******************************************************************************/
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c
new file mode 100644 (file)
index 0000000..d720e70
--- /dev/null
@@ -0,0 +1,1482 @@
+/*
+ * Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* INCLUDE ********************************************************************/
+#include "ftmod_sangoma_ss7_main.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt);
+void sngss7_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt);
+void sngss7_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCnStEvnt *siCnStEvnt, uint8_t evntType);
+void sngss7_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt);
+void sngss7_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt);
+void sngss7_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiInfoEvnt *siInfoEvnt);
+void sngss7_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt);
+void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt);
+void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit);
+
+static ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_pause(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_resume(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+
+static ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_cot_stop(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_cot(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+
+static ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_local_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+
+static ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_blo_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+static ftdm_status_t handle_ubl_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+
+
+
+/******************************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info ;
+    ftdm_channel_t      *ftdmchan;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    };
+
+    SS7_MSG_TRACE("Received IAM on CIC # %d\n", sngss7_info->circuit->cic);
+
+    /* check whether the ftdm channel is in a state to accept a call */
+    switch (ftdmchan->state) {
+    /**************************************************************************/
+    case (FTDM_CHANNEL_STATE_DOWN):     /* only state it is fully valid to get IAM */
+
+        /* fill in the channels SS7 Stack information */
+        sngss7_info->suInstId = get_unique_id();
+        sngss7_info->spInstId = spInstId;
+
+        /* try to open the ftdm channel */
+        if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+            SS7_ERROR("Failed to open span: %d, chan: %d\n",
+                        ftdmchan->physical_span_id,
+                        ftdmchan->physical_chan_id);
+
+             /* set the flag to indicate this hangup is started from the local side */
+            sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL);
+
+            ftdmchan->caller_data.hangup_cause = 41;
+
+            /* move the state to CANCEL */
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+
+        } else {
+
+            /* fill in cid/ani number */
+            if (siConEvnt->cgPtyNum.addrSig.pres) {
+                copy_tknStr_from_sngss7(siConEvnt->cgPtyNum.addrSig,
+                                        ftdmchan->caller_data.cid_num.digits, 
+                                        siConEvnt->cgPtyNum.oddEven);
+
+                /* fill in cid Name */
+                ftdm_set_string(ftdmchan->caller_data.cid_name, ftdmchan->caller_data.cid_num.digits);
+
+                ftdm_set_string(ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.cid_num.digits);
+
+            } else {
+                SS7_INFO("No Calling party (ANI) information in IAM!\n");
+            }
+
+            /* fill in dnis */
+            if (siConEvnt->cdPtyNum.addrSig.pres) {
+                copy_tknStr_from_sngss7(siConEvnt->cdPtyNum.addrSig, 
+                                        ftdmchan->caller_data.dnis.digits, 
+                                        siConEvnt->cdPtyNum.oddEven);
+            }   else {
+                SS7_INFO("No Called party (DNIS) information in IAM!\n");
+            }
+
+            /* fill in rdnis */
+            if (siConEvnt->redirgNum.addrSig.pres) {
+                copy_tknStr_from_sngss7(siConEvnt->redirgNum.addrSig, 
+                                        ftdmchan->caller_data.rdnis.digits, 
+                                        siConEvnt->cgPtyNum.oddEven);
+            }   else {
+                SS7_INFO("No RDNIS party information in IAM!\n");
+            }
+
+            /* fill in screening/presentation */
+            ftdmchan->caller_data.screen = siConEvnt->cgPtyNum.scrnInd.val;
+            ftdmchan->caller_data.pres = siConEvnt->cgPtyNum.presRest.val;
+
+            /* set the state of the channel to collecting...the rest is done by the chan monitor */
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
+
+        } /* if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) */
+
+        break;
+    /**************************************************************************/
+    case (FTDM_CHANNEL_STATE_DIALING):             /* glare */
+        SS7_ERROR("Got IAM in DIALING state...glare... queueing incoming call\n");
+        
+        /* the flag the channel as having a collision */
+        sngss7_set_flag(sngss7_info, FLAG_GLARE);
+
+        /* save the IAM for processing once the channel has gone to DOWN */
+        memcpy(&sngss7_info->glare.iam, siConEvnt, sizeof(*siConEvnt));
+        sngss7_info->glare.suInstId = suInstId;
+        sngss7_info->glare.spInstId = spInstId;
+        sngss7_info->glare.circuit  = circuit;
+
+        break;
+    /**************************************************************************/
+    default:    /* should not have gotten an IAM while in this state */
+        SS7_ERROR("Got IAM in an invalid state!\n");
+
+        /* move the state of the channel to RESTART to force a reset */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+
+        break;
+    /**************************************************************************/
+    } /* switch (ftdmchan->state) */
+
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void sngss7_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info ;
+    ftdm_channel_t      *ftdmchan;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    };
+
+    SS7_MSG_TRACE("Received ANM on CIC # %d\n", sngss7_info->circuit->cic);
+
+    /* check whether the ftdm channel is in a state to accept a call */
+    switch (ftdmchan->state) {
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_PROGRESS:
+    case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+
+        /* go to UP */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+
+        break;
+    /**************************************************************************/
+    default:    /* incorrect state...reset the CIC */
+
+        /* go to RESTART */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+
+        break;
+    /**************************************************************************/
+    }
+
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void sngss7_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCnStEvnt *siCnStEvnt, uint8_t evntType)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info ;
+    ftdm_channel_t      *ftdmchan;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+    switch (evntType) {
+    /**************************************************************************/
+    case (ADDRCMPLT):
+        SS7_MSG_TRACE("Received ACM on CIC # %d\n", sngss7_info->circuit->cic);
+        switch (ftdmchan->state) {
+        /**********************************************************************/
+        case FTDM_CHANNEL_STATE_DIALING:
+            /* KONRAD: should we confirm the instance ids ? */
+
+            /* need to grab the sp instance id */ 
+            sngss7_info->spInstId = spInstId;
+
+            /* go to PROGRESS */
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+        break;
+        /**********************************************************************/
+        default:    /* incorrect state...reset the CIC */
+            /* go to RESTART */
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+        break;
+        /**********************************************************************/
+        } /* switch (ftdmchan->state) */
+    /**************************************************************************/
+    case (MODIFY):
+        SS7_MSG_TRACE("Received MODIFY on CIC # %d\n", sngss7_info->circuit->cic);
+        break;
+    /**************************************************************************/
+    case (MODCMPLT):
+        SS7_MSG_TRACE( "Received MODIFY_COMPLETE on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (MODREJ):
+        SS7_MSG_TRACE( "Received MODIFY_REJECT on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (PROGRESS):
+        SS7_MSG_TRACE( "Received CPG on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (FRWDTRSFR):
+        SS7_MSG_TRACE( "Received FOT on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (INFORMATION):
+        SS7_MSG_TRACE( "Received INF on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (INFORMATREQ):
+        SS7_MSG_TRACE( "Received INR on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (SUBSADDR):
+        SS7_MSG_TRACE( "Received SAM on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (EXIT):
+        SS7_MSG_TRACE( "Received EXIT on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (NETRESMGT):
+        SS7_MSG_TRACE( "Received NRM on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (IDENTREQ):
+        SS7_MSG_TRACE( "Received IDR on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (IDENTRSP):
+        SS7_MSG_TRACE( "Received IRS on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (MALCLLPRNT):
+        SS7_MSG_TRACE( "Received MALICIOUS CALL on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (CHARGE):
+        SS7_MSG_TRACE( "Received CRG on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (TRFFCHGE):
+        SS7_MSG_TRACE( "Received CRG-Tariff Change on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (CHARGEACK):
+        SS7_MSG_TRACE( "Received CRG-Acknowledge on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (CALLOFFMSG):
+        SS7_MSG_TRACE( "Received CALL_OFFER on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (LOOPPRVNT):
+        SS7_MSG_TRACE( "Received LOP on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (TECT_TIMEOUT):
+        SS7_MSG_TRACE( "Received ECT Timeout on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (RINGSEND):
+        SS7_MSG_TRACE( "Received Ringing Send on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (CALLCLEAR):
+        SS7_MSG_TRACE( "Received Call_Line_clear on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (PRERELEASE):
+        SS7_MSG_TRACE( "Received PRI on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (APPTRANSPORT):
+        SS7_MSG_TRACE( "Received APM on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (OPERATOR):
+        SS7_MSG_TRACE( "Received Operator on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (METPULSE):
+        SS7_MSG_TRACE( "Received Metering Pulse on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (CLGPTCLR):
+        SS7_MSG_TRACE( "Received Calling_Party_Clear on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    case (SUBDIRNUM):
+        SS7_MSG_TRACE( "Received subsequent directory number on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    default:
+        ftdm_log(FTDM_LOG_ERROR, "Received Unknown message on circuit # %d\n", circuit);
+        break;
+    /**************************************************************************/
+    }
+
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void sngss7_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info ;
+    ftdm_channel_t      *ftdmchan;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    };
+
+    SS7_MSG_TRACE("Received REL on CIC # %d\n", sngss7_info->circuit->cic);
+
+    /* check whether the ftdm channel is in a state to release a call */
+    switch (ftdmchan->state) {
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_RING:
+    case FTDM_CHANNEL_STATE_DIALING:
+    case FTDM_CHANNEL_STATE_PROGRESS:
+    case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+    case FTDM_CHANNEL_STATE_UP:
+
+        /* pass the release code up to FTDM */
+        if (siRelEvnt->causeDgn.causeVal.pres) {
+            ftdmchan->caller_data.hangup_cause = siRelEvnt->causeDgn.causeVal.val;
+        } else {
+            SS7_ERROR("REL does not have a cause code!\n");
+            ftdmchan->caller_data.hangup_cause = 0;
+        }
+
+        /* move the state of the channel to TERMINATING to end the call */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+
+        break;
+    /**************************************************************************/
+    default:
+
+        /* fill in the channels SS7 Stack information */
+        sngss7_info->suInstId = get_unique_id();
+        sngss7_info->spInstId = spInstId;
+
+        /* throw the reset flag */
+        sngss7_set_flag(sngss7_info, FLAG_RESET_RX);
+
+        /* set the state to RESTART */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+        break;
+    /**************************************************************************/
+    } /* switch (ftdmchan->state) */
+
+
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+
+/******************************************************************************/
+void sngss7_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+    
+    sngss7_chan_data_t  *sngss7_info ;
+    ftdm_channel_t      *ftdmchan;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    };
+
+    SS7_MSG_TRACE("Received RLC on CIC # %d\n", sngss7_info->circuit->cic);
+
+    /* check whether the ftdm channel is in a state to accept a call */
+    switch (ftdmchan->state) {
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+
+        /* go to DOWN */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_DOWN:
+        /* do nothing, just drop the message */
+        break;
+    /**************************************************************************/
+    default:    
+        /* KONRAD: should just stop the call...but a reset is easier for now (since it does hangup the call) */
+
+        /* go to RESTART */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+
+        break;
+    /**************************************************************************/
+    }
+
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void sngss7_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiInfoEvnt *siInfoEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+    SS7_MSG_TRACE( "Received DATA indication on circuit # %d\n", circuit);
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void sngss7_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+    SS7_MSG_TRACE( "Received FAC request on circuit # %d\n", circuit);
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+    SS7_MSG_TRACE( "Received FAC confirm on circuit # %d\n", circuit);
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    SS7_MSG_TRACE( "Received User to User message on circuit # %d\n", circuit);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/* GENERAL STATUS *************************************************************/
+void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    SS7_MSG_TRACE("[SNG-CC] Received %s indicaton on cic = %d\n", 
+                DECODE_LCC_EVENT(evntType),
+                g_ftdm_sngss7_data.cfg.isupCircuit[circuit].cic);
+
+    switch (evntType) {
+    /**************************************************************************/
+    case SIT_STA_REATTEMPT:         /* reattempt indication */
+        handle_reattempt(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_ERRORIND:          /* error indication */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CONTCHK:           /* continuity check */
+        handle_cot_start(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CONTREP:           /* continuity report */
+        handle_cot(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_STPCONTIN:         /* stop continuity */
+        handle_cot_stop(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CGQRYRSP:          /* circuit grp query response from far end forwarded to upper layer by ISUP */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CONFUSION:         /* confusion */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_LOOPBACKACK:       /* loop-back acknowledge */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRRSRVREQ:        /* circuit reservation request */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRRSRVACK:        /* circuit reservation acknowledgement */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRBLOREQ:         /* circuit blocking request */
+        handle_blo_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRBLORSP:         /* circuit blocking response   */
+        handle_blo_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRUBLREQ:         /* circuit unblocking request */
+        handle_ubl_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRUBLRSP:         /* circuit unblocking response */
+        handle_ubl_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRRESREQ:         /* circuit reset request - RSC */
+        handle_rsc_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRLOCRES:         /* reset initiated locally by the software */
+        handle_local_rsc_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRRESRSP:         /* circuit reset response */
+        handle_rsc_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_CGBREQ:            /* CGB request */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CGUREQ:            /* CGU request */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CGQRYREQ:          /* circuit group query request */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CGBRSP:            /* mntc. oriented CGB response */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CGURSP:            /* mntc. oriented CGU response */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_GRSREQ:            /* circuit group reset request */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRUNEQPD:         /* circuit unequipped indication */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_GRSRSP:            /* circuit group reset response */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_PAUSEIND:          /* pause indication */
+        handle_pause(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_RESUMEIND:         /* resume indication */
+        handle_resume(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);
+        break;
+    /**************************************************************************/
+    case SIT_STA_USRPARTA:          /* user part available */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_RMTUSRUNAV:        /* remote user not available */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_MTPCONG0:          /* congestion indication level 0 */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_MTPCONG1:          /* congestion indication level 1 */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_MTPCONG2:          /* congestion indication level 2 */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_MTPCONG3:          /* congestion indication level 3 */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_MTPSTPCONG:        /* stop congestion indication level 0 */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break; 
+    /**************************************************************************/
+    case SIT_STA_CIRLOCALBLOIND:    /* Mngmt local blocking */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRLOCALUBLIND:    /* Mngmt local unblocking */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_OVERLOAD:          /* Overload */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_LMCGBREQ:          /* when LM requests ckt grp blocking */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_LMCGUREQ:          /* when LM requests ckt grp unblocking */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_LMGRSREQ:          /* when LM requests ckt grp reset */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CGBINFOIND:        /* circuit grp blking ind , no resp req */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_LMCQMINFOREQ:      /* when LM requests ckt grp query */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_CIRLOCGRS:         /* group reset initiated locally by the software */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_GRSRSPIND:         /* indication to IW to idle the RM */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    case SIT_STA_RLCIND:            /* RLC indicattion to IW to idle the RM */
+        SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));
+        break;
+    /**************************************************************************/
+    default:
+        SS7_INFO("[SNG-CC] Received Unknown indication %d\n", evntType);
+        break;
+    } /* switch (evntType) */
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for ISUP circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+
+    switch (ftdmchan->state) {
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_DIALING:
+        /* glare, go to down state*/
+
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+        
+        break;
+    /**************************************************************************/
+    default:
+        /* fuck...this shouldn't happen */
+        SS7_ERROR("Received reattempt indication on CIC %d in invalid state %s\n", 
+                    sngss7_info->circuit->cic,
+                    ftdm_channel_state2str(ftdmchan->state));
+
+        /* throw the channel into reset */
+        sngss7_set_flag(sngss7_info, FLAG_RESET_TX);
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+
+        break;
+    /**************************************************************************/
+    }
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_pause(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+    int                 infId;
+    int                 i;
+
+    /* extract the affect infId from the circuit structure */
+    infId = g_ftdm_sngss7_data.cfg.isupCircuit[circuit].infId;
+
+    /* go through all the circuits now and find any other circuits on this infId */
+    i = 1;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[i].id != 0) {
+        
+        /* check that the infId matches and that this is not a siglink */
+        if ((g_ftdm_sngss7_data.cfg.isupCircuit[i].infId == infId) && 
+            (g_ftdm_sngss7_data.cfg.isupCircuit[i].siglink == 0)) {
+
+            /* get the ftdmchan and ss7_chan_data from the circuit */
+            if (extract_chan_data(i, &sngss7_info, &ftdmchan)) {
+                SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+                i++;
+                continue;
+            }
+
+            /* lock the channel */
+            ftdm_mutex_lock(ftdmchan->mutex);
+
+            /* check if there is a pending state change, give it a bit to clear */
+            if (check_for_state_change(ftdmchan)) {
+                SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+                ftdm_mutex_unlock(ftdmchan->mutex);
+                i++;
+                continue;
+            };
+
+            /* set the pause flag on the channel */
+            sngss7_set_flag(sngss7_info, FLAG_INFID_PAUSED);
+
+            /* set the statet o SUSPENDED to bring the sig status down */ 
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+
+            /* unlock the channel again before we exit */
+            ftdm_mutex_unlock(ftdmchan->mutex);
+
+        } /* if (g_ftdm_sngss7_data.cfg.isupCircuit[i].infId == infId) */
+
+        /* move to the next circuit */
+        i++;
+
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[i].id != 0) */
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_resume(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+    int                 infId;
+    int                 i;
+
+    /* extract the affect infId from the circuit structure */
+    infId = g_ftdm_sngss7_data.cfg.isupCircuit[circuit].infId;
+
+    /* go through all the circuits now and find any other circuits on this infId */
+    i = 1;
+    while (g_ftdm_sngss7_data.cfg.isupCircuit[i].id != 0) {
+
+        /* check that the infId matches and that this is not a siglink */
+        if ((g_ftdm_sngss7_data.cfg.isupCircuit[i].infId == infId) && 
+            (g_ftdm_sngss7_data.cfg.isupCircuit[i].siglink == 0)) {
+
+            /* get the ftdmchan and ss7_chan_data from the circuit */
+            if (extract_chan_data(i, &sngss7_info, &ftdmchan)) {
+                SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+                i++;
+                continue;
+            }
+
+            /* lock the channel */
+            ftdm_mutex_lock(ftdmchan->mutex);
+
+            /* check if there is a pending state change, give it a bit to clear */
+            if (check_for_state_change(ftdmchan)) {
+                SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+                ftdm_mutex_unlock(ftdmchan->mutex);
+                i++;
+                continue;
+            };
+
+            /* set the resume flag on the channel */
+            sngss7_set_flag(sngss7_info, FLAG_INFID_RESUME);
+
+            /* clear the paused flag */
+            sngss7_clear_flag(sngss7_info, FLAG_INFID_PAUSED);
+
+            /* set the statet to SUSPENDED to bring the sig status up */ 
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+
+            /* unlock the channel again before we exit */
+            ftdm_mutex_unlock(ftdmchan->mutex);
+
+        } /* if (g_ftdm_sngss7_data.cfg.isupCircuit[i].infId == infId) */
+
+        /* move to the next circuit */
+        i++;
+
+    } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[i].id != 0) */
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    /* open the channel if it is not open */
+    if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+        if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+            SS7_ERROR("Failed to open CIC %d for COT test!\n", sngss7_info->circuit->cic);
+            /* KONRAD FIX ME */
+            SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+            return FTDM_FAIL;
+        }
+    }
+
+    /* tell the core to loop the channel */
+    ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_LOOP, NULL);
+
+    /* switch to the IN_LOOP state */
+    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP);
+
+    /* store the sngss7 ids */
+    if (suInstId == 0) {
+        sngss7_info->suInstId = get_unique_id();
+    } else {
+        sngss7_info->suInstId = suInstId;
+    }
+    sngss7_info->spInstId = spInstId;
+    sngss7_info->globalFlg = globalFlg;
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_cot_stop(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    /* tell the core to stop looping the channel */
+    ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL);
+
+    /* exit out of the LOOP state to the last state */
+    ftdm_set_state_locked(ftdmchan, ftdmchan->last_state);
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_cot(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    if ( (siStaEvnt->contInd.eh.pres > 0) && (siStaEvnt->contInd.contInd.pres > 0)) {
+        SS7_INFO("Continuity Test result for CIC = %d (span %d, chan %d) is: \"%s\"\n",
+                    g_ftdm_sngss7_data.cfg.isupCircuit[circuit].cic,
+                    g_ftdm_sngss7_data.cfg.isupCircuit[circuit].span,
+                    g_ftdm_sngss7_data.cfg.isupCircuit[circuit].chan,
+                    (siStaEvnt->contInd.contInd.val) ? "PASS" : "FAIL");
+    } else {
+        SS7_ERROR("Recieved Continuity report containing no results!\n");
+    }
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    switch (ftdmchan->state) {
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_RESTART:
+        /* since we are already in RESTART, the channel is already free...
+         * just waitng for the other side to clean up it's channel.
+         * just send an acknowledge to this reset, don't go through the master
+         * state handler....bad but...
+         */
+
+        sngss7_info->spInstId = 0;
+        sngss7_info->suInstId = 0;
+        sngss7_info->globalFlg = globalFlg;
+
+        ft_to_sngss7_rsca(ftdmchan);
+        break;
+    /**************************************************************************/
+    default:
+        /* throw the channels RESET_RX flag */
+        sngss7_set_flag(sngss7_info, FLAG_RESET_RX);
+
+        sngss7_info->spInstId = 0;
+        sngss7_info->suInstId = 0;
+        sngss7_info->globalFlg = globalFlg;
+
+        /* set the state of the channel to restart...the rest is done by the chan monitor */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+        break;
+    /**************************************************************************/
+    }
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_local_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    /* the stack is sending out a RSC for us */
+    sngss7_set_flag(sngss7_info, FLAG_RESET_RX);
+
+    sngss7_info->spInstId = 0;
+    sngss7_info->suInstId = 0;
+    sngss7_info->globalFlg = globalFlg;
+
+    /* set the state of the channel to restart...the rest is done by the chan monitor */
+    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    switch (ftdmchan->state) {
+    /**********************************************************************/
+    case FTDM_CHANNEL_STATE_RESTART:
+
+        /* go to DOWN */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+
+        break;
+    /**********************************************************************/
+    case FTDM_CHANNEL_STATE_DOWN:
+        /* do nothing, just drop the message */
+        break;
+    /**********************************************************************/
+    case FTDM_CHANNEL_STATE_TERMINATING:
+    case FTDM_CHANNEL_STATE_HANGUP:
+    case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+    /**********************************************************************/
+        /* go to DOWN */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+
+        break;
+    /**********************************************************************/
+    default:    
+        /* ITU Q764-2.9.5.1.c -> release the circuit */
+        if ((siStaEvnt != NULL) && 
+            (siStaEvnt->causeDgn.eh.pres ==PRSNT_NODEF) && 
+            (siStaEvnt->causeDgn.causeVal.pres == PRSNT_NODEF)) {
+            ftdmchan->caller_data.hangup_cause = siStaEvnt->causeDgn.causeVal.val;
+        } else {
+            ftdmchan->caller_data.hangup_cause = 98;    /* Message not compatiable with call state */
+        }
+
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+        break;
+    /**********************************************************************/
+    }
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    /* check if the circuit is already blocked or not */
+    if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) {
+        SS7_WARN("Received BLO on circuit that is already blocked!\n");
+    }
+
+    /* throw the ckt block flag */
+    sngss7_set_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX);
+
+    /* set the channel to suspended state */
+    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_blo_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    /* KONRAD FIX ME */
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    /* check if the channel is blocked */
+    if (!(sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX))) {
+        SS7_WARN("Received UBL on circuit that is not blocked!\n");
+    }
+
+    /* throw the unblock flag */
+    sngss7_set_flag(sngss7_info, FLAG_CKT_MN_UNBLK_RX);
+
+    /* clear the block flag */
+    sngss7_clear_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX);
+
+    /* set the channel to suspended state */
+    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t handle_ubl_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    /* KONRAD FIX ME */
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+#if 0
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+    if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
+        SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    }
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /* check if there is a pending state change, give it a bit to clear */
+    if (check_for_state_change(ftdmchan)) {
+        SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+        SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+        return FTDM_FAIL;
+    };
+
+    /* fill in here */
+
+    /* unlock the channel again before we exit */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+/******************************************************************************/
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c
new file mode 100644 (file)
index 0000000..55c6e6a
--- /dev/null
@@ -0,0 +1,1188 @@
+/*
+ * Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* INCLUDE ********************************************************************/
+#include "ftmod_sangoma_ss7_main.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+static sng_isup_event_interface_t   sng_event;
+static ftdm_io_interface_t          g_ftdm_sngss7_interface;
+ftdm_sngss7_data_t                  g_ftdm_sngss7_data;
+ftdm_sched_t                        *sngss7_sched;
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+static void *ftdm_ss7_run(ftdm_thread_t *me, void *obj);
+static void ftdm_ss7_process_state_change(ftdm_channel_t *ftdmchan);
+
+static ftdm_status_t ftdm_ss7_stop(ftdm_span_t *span);
+static ftdm_status_t ftdm_ss7_start(ftdm_span_t *span);
+/******************************************************************************/
+
+/* STATE MAP ******************************************************************/
+ftdm_state_map_t sangoma_ss7_state_map = {
+    {
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_ANY_STATE, FTDM_END},
+            {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END}
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+            {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_CANCEL, FTDM_END},
+            {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END},
+            {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_DIALING,
+             FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
+             FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+            {FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_COLLECT, FTDM_END},
+            {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END},
+            {FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_RING, FTDM_END},
+            {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
+            {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+            {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END},
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_UP, FTDM_END},
+            {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+            {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+            {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+        },
+        {
+            ZSD_INBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+            {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+        },
+    /**************************************************************************/
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_ANY_STATE, FTDM_END},
+            {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+            {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_CANCEL, FTDM_END},
+            {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END},
+            {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_DIALING,
+             FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
+             FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+            {FTDM_CHANNEL_STATE_DIALING, FTDM_END}
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+            {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
+            {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+            {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END},
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_UP, FTDM_END},
+            {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+            {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+            {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+        },
+        {
+            ZSD_OUTBOUND,
+            ZSM_UNACCEPTABLE,
+            {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+            {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+        }
+    }
+};
+/******************************************************************************/
+
+/* MONITIOR THREADS ***********************************************************/
+static void *ftdm_ss7_run(ftdm_thread_t *me, void *obj)
+{
+    ftdm_interrupt_t    *ftdm_ss7_int = NULL;
+    ftdm_span_t         *span   = (ftdm_span_t *) obj;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u started.\n", span->span_id);
+
+    /* set IN_THREAD flag so that we know this thread is running */
+    ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
+
+    /* get an interrupt queue for this span */
+    if(ftdm_queue_get_interrupt(span->pendingchans, &ftdm_ss7_int) != FTDM_SUCCESS) {
+        SS7_CRITICAL("Failed to get a ftdm_interrupt for span = %d!\n", span->span_id);
+        goto ftdm_ss7_run_exit;
+    }
+
+    while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) {
+
+        /* find out why we returned from the interrupt queue */
+        switch ((ftdm_interrupt_wait(ftdm_ss7_int, 100))) {
+        /**********************************************************************/
+        case FTDM_SUCCESS:  /* there was a state change on the span */
+            /* process all pending state changes */
+            while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
+                /* double check that this channel has a state change pending */
+                if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+                    ftdm_ss7_process_state_change(ftdmchan);
+                } else {
+                    SS7_ERROR("ftdm_core reported state change, but state change flag not set on ft-span = %d, ft-chan = %d\n",
+                                ftdmchan->span_id,
+                                ftdmchan->chan_id);
+                }
+            } /* while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans)))  */
+
+            break;
+        /**********************************************************************/
+        case FTDM_TIMEOUT:
+            SS7_DEVEL_DEBUG("ftdm_interrupt_wait timed-out on span = %d\n", span->span_id);
+            break;
+        /**********************************************************************/
+        case FTDM_FAIL:
+            SS7_ERROR("ftdm_interrupt_wait returned error!\non span = %d\n", span->span_id);
+            break;
+        /**********************************************************************/
+        default:
+            SS7_ERROR("ftdm_interrupt_wait returned with unknown code on span = %d\n", span->span_id);
+            break;
+        /**********************************************************************/
+        } /* switch ((ftdm_interrupt_wait(ftdm_ss7_int, 100))) */
+
+    } /* master while loop */
+
+    /* clear the IN_THREAD flag so that we know the thread is done */
+    ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+
+    ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u stopping.\n", span->span_id);
+
+    return NULL;
+
+ftdm_ss7_run_exit:
+
+    /* clear the IN_THREAD flag so that we know the thread is done */
+    ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+
+    ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u stopping due to error.\n", span->span_id);
+
+    ftdm_ss7_stop(span);
+
+    return NULL;
+}
+
+/******************************************************************************/
+static void ftdm_ss7_process_state_change(ftdm_channel_t *ftdmchan)
+{
+    ftdm_sigmsg_t           sigev;
+    ftdm_signaling_status_t status;
+    sngss7_chan_data_t      *sngss7_info = ftdmchan->call_data;
+
+    memset(&sigev, 0, sizeof(sigev));
+
+    sigev.chan_id = ftdmchan->chan_id;
+    sigev.span_id = ftdmchan->span_id;
+    sigev.channel = ftdmchan;
+
+    /*first lock the channel*/
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    /*clear the state change flag...since we might be setting a new state*/
+    ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+
+    /*check what state we are supposed to be in*/
+    switch (ftdmchan->state) {
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_COLLECT:     /* IAM received but wating on digits */
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                            ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        int i = 0;
+
+        while (ftdmchan->caller_data.cid_num.digits[i] != '\0') {
+            i++;
+        }
+
+        /* check if the end of pulsing character has arrived or the right number of digits */
+        if (ftdmchan->caller_data.cid_num.digits[i] == 0xF) {
+            SS7_DEBUG("Received the end of pulsing character\n");
+
+            /*now go to the RING state*/
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+        } else if (i >= g_ftdm_sngss7_data.min_digits) {
+            SS7_DEBUG("Received %d digits (min digits = %d)\n", i, g_ftdm_sngss7_data.min_digits);
+
+            /*now go to the RING state*/
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+        } else {
+            SS7_INFO("Received %d out of %d so far: %s...starting T35\n",
+                        i,
+                        g_ftdm_sngss7_data.min_digits,
+                        ftdmchan->caller_data.cid_num.digits);
+
+            /* start ISUP t35 */
+            if (ftdm_sched_timer(sngss7_info->t35.sched, 
+                                 "t35", 
+                                 sngss7_info->t35.beat, 
+                                 sngss7_info->t35.callback, 
+                                 &sngss7_info->t35,
+                                 &sngss7_info->t35.heartbeat_timer)) {
+
+                SS7_ERROR("Unable to schedule timer, hanging up call!\n");
+
+                ftdmchan->caller_data.hangup_cause = 41;
+
+                 /* set the flag to indicate this hangup is started from the local side */
+                sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL);
+
+                /* end the call */
+                ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+            } else {
+                if(ftdm_sched_free_run(sngss7_info->t35.sched)) {
+                    SS7_ERROR("Unable to run timer, hanging up call!\n");
+
+                    ftdmchan->caller_data.hangup_cause = 41;
+
+                    /* set the flag to indicate this hangup is started from the local side */
+                    sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL);
+
+                    /* end the call */
+                    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+                } /* if(ftdm_sched_free_run(sngss7_info->t35.sched)) */
+            } /* if (ftdm_sched_timer(sngss7_info->t35.sched, */
+
+        } /* checking ST/#digits */
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_RING:                      /*incoming call request*/
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        SS7_DEBUG("Sending incoming call from %s to %s to FTDM core\n",
+                        ftdmchan->caller_data.ani.digits,
+                        ftdmchan->caller_data.dnis.digits);
+
+
+        /* we have enough information to inform FTDM of the call*/
+        sigev.event_id = FTDM_SIGEVENT_START;
+        ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_DIALING:                   /*outgoing call request*/
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        /*call sangoma_ss7_dial to make outgoing call*/
+        ft_to_sngss7_iam(ftdmchan);
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_PROGRESS:
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        /*check if the channel is inbound or outbound*/
+        if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+                /*OUTBOUND...so we were told by the line of this so noifiy the user*/
+                sigev.event_id = FTDM_SIGEVENT_PROGRESS;
+                ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+                ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+
+        } else {
+            /* inbound call so we need to send out ACM */
+            ft_to_sngss7_acm(ftdmchan);
+        }
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        /* nothing to do at this time */
+        break; 
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_UP: /*call is accpeted...both incoming and outgoing*/
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        /*check if the channel is inbound or outbound*/
+        if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+                /*OUTBOUND...so we were told by the line that the other side answered*/
+                sigev.event_id = FTDM_SIGEVENT_UP;
+                ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+        } else {
+                /*INBOUND...so FS told us it was going to answer...tell the stack*/
+                ft_to_sngss7_anm(ftdmchan);
+        }
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_CANCEL:
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        SS7_ERROR("Hanging up call before informing user on span = %d, chan = %d!\n", ftdmchan->span_id,ftdmchan->chan_id);
+
+        /*now go to the HANGUP complete state*/
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_TERMINATING:            /*call is hung up remotely*/
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        /* set the flag to indicate this hangup is started from the remote side */
+        sngss7_set_flag(sngss7_info, FLAG_REMOTE_REL);
+
+        /*this state is set when the line is hanging up*/
+        sigev.event_id = FTDM_SIGEVENT_STOP;
+        ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_HANGUP:                  /*call is hung up locally*/
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        /* check for remote hangup flag */
+        if (sngss7_test_flag(sngss7_info, FLAG_REMOTE_REL)) {
+            SS7_DEBUG("Hanging up remotely requested call!\n"); 
+        } else {
+            SS7_DEBUG("Hanging up Locally requested call!\n");
+
+             /* set the flag to indicate this hangup is started from the local side */
+            sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL);
+
+            /*this state is set when FS is hanging up...so tell the stack*/
+            ft_to_sngss7_rel(ftdmchan);
+        }
+
+        /*now go to the HANGUP complete state*/
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        if (sngss7_test_flag(sngss7_info, FLAG_REMOTE_REL)) {
+
+            /* check if this hangup is from a tx RSC */
+            if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX)) {
+
+                /* go to RESTART State until RSCa is received */
+                ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+            } else {
+                if (!(sngss7_test_flag(sngss7_info, FLAG_RESET_RX))) {
+                    /* send out the release complete */
+                    ft_to_sngss7_rlc(ftdmchan);
+                }
+                /*now go to the DOWN state*/
+                ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+            }
+
+            SS7_DEBUG("Completing remotely requested hangup!\n");
+        } else {
+            SS7_DEBUG("Completing locally requested hangup!\n");
+        }
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_DOWN:           /*the call is finished and removed*/
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+            SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n");
+            break;
+        }
+
+        /* check if there is a reset response that needs to be sent */
+        if (sngss7_test_flag(sngss7_info, FLAG_RESET_RX)) {
+            /* send a RLC */
+            ft_to_sngss7_rsca(ftdmchan);
+
+            /* inform Ftdm that the "sig" is up now for this channel */
+            status = FTDM_SIG_STATE_UP;
+            sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+            sigev.raw_data = &status;
+            ftdm_span_send_signal(ftdmchan->span, &sigev);
+        }
+
+        /* check if we got the reset response */
+        if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX)) {
+            /* inform Ftdm that the "sig" is up now for this channel */
+            status = FTDM_SIG_STATE_UP;
+            sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+            sigev.raw_data = &status;
+            ftdm_span_send_signal(ftdmchan->span, &sigev);
+        }
+
+        /* check if the circuit has the glare flag up */
+        if (sngss7_test_flag(sngss7_info, FLAG_GLARE)) {
+            SS7_DEBUG("Glare flag is up....spoofing incoming call on span=%, chan=%d\n",
+                        ftdmchan->span_id,ftdmchan->chan_id);
+            /* clear all the call specific data */
+            sngss7_info->suInstId = 0;
+            sngss7_info->spInstId = 0;
+            sngss7_info->globalFlg = 0;
+            sngss7_info->spId = 0;
+            sngss7_info->flags = 0;
+
+            /* close the channel */
+            if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+                ftdm_channel_t *close_chan = ftdmchan;
+                /* close the channel */
+                ftdm_channel_close(&close_chan);
+            }
+
+            /* spoof an incoming call */
+            sngss7_con_ind(sngss7_info->glare.suInstId, 
+                           sngss7_info->glare.spInstId, 
+                           sngss7_info->glare.circuit, 
+                           &sngss7_info->glare.iam);
+        } else {
+            /* clear all of the call specific data store in the channel structure */
+            sngss7_info->suInstId = 0;
+            sngss7_info->spInstId = 0;
+            sngss7_info->globalFlg = 0;
+            sngss7_info->spId = 0;
+            sngss7_info->flags = 0;
+        
+            if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+                ftdm_channel_t *close_chan = ftdmchan;
+                /* close the channel */
+                ftdm_channel_close(&close_chan);
+            }
+        }
+
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_RESTART:                    /* CICs needs a Reset */
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+            /* bring the call down first...then process the rest of the reset */
+            switch (ftdmchan->last_state) {
+            /******************************************************************/
+            case(FTDM_CHANNEL_STATE_TERMINATING):
+            case(FTDM_CHANNEL_STATE_HANGUP):
+            case(FTDM_CHANNEL_STATE_HANGUP_COMPLETE):
+                /* go back to the last state after taking care of the rest of the restart state */
+                ftdm_set_state_locked(ftdmchan, ftdmchan->last_state);
+                break;
+            /******************************************************************/
+            default:
+                /* KONRAD: find out what the cause code should be */
+                ftdmchan->caller_data.hangup_cause = 41;
+
+                /* change the state to terminatting, it will throw us back here 
+                 * once the call is done 
+                 */
+                ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+                break;
+            /******************************************************************/
+            }
+        } else {
+
+            /* check if this an incoming RSC */
+            if (sngss7_test_flag(sngss7_info, FLAG_RESET_RX)) {
+                /* go to a down state to clear the channel and send RSCa */
+                ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+            } /* if (sngss7_test_flag(sngss7_info, FLAG_RESET_RX)) */
+        } /* if (inuse) */
+
+        /* check if this is an outgoing RSC */
+        if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX)) {
+    
+            /* make sure we aren't coming from hanging up a call */
+            if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP_COMPLETE) {
+                /* send a reset request */
+                ft_to_sngss7_rsc(ftdmchan);
+            }
+    
+            /* don't change to the DOWN state as we need to wait for the RSCa */
+        } /* if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX)) */
+        
+        /* send a sig event to the core to disable the channel */
+        status = FTDM_SIG_STATE_DOWN;
+        sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+        sigev.raw_data = &status;
+        ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_SUSPENDED:            /* circuit has been blocked */
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        /**********************************************************************/
+        if (sngss7_test_flag(sngss7_info, FLAG_INFID_PAUSED)) {
+            SS7_DEBUG("processing pause for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id);
+            /* bring the channel signaling status to down */
+            status = FTDM_SIG_STATE_DOWN;
+            sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+            sigev.raw_data = &status;
+            ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+            /* check the last state and return to it to allow the call to finish */
+            ftdm_set_state_locked(ftdmchan, ftdmchan->last_state);
+        }
+        if (sngss7_test_flag(sngss7_info, FLAG_INFID_RESUME)) {
+            SS7_DEBUG("processing resume for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id);
+            /* we just resumed...throw the channel into reset */
+            sngss7_set_flag(sngss7_info, FLAG_RESET_TX);
+
+            /* clear the resume flag */
+            sngss7_clear_flag(sngss7_info, FLAG_INFID_RESUME);
+
+            /* go to restart state */
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+        }
+        /**********************************************************************/
+        if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) {
+            SS7_DEBUG("processing rx Mn ckt block for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id);
+            /* bring the channel signaling status to down */
+            status = FTDM_SIG_STATE_DOWN;
+            sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+            sigev.raw_data = &status;
+            ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+            /* send a BLA */
+            ft_to_sngss7_bla(ftdmchan);
+
+            /* check the last state and return to it to allow the call to finish */
+            ftdm_set_state_locked(ftdmchan, ftdmchan->last_state);
+        }
+        if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_UNBLK_RX)) {
+            SS7_DEBUG("processing rx Mn ckt unblock for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id);
+            /* bring the channel signaling status to up */
+            status = FTDM_SIG_STATE_UP;
+            sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+            sigev.raw_data = &status;
+            ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+            /* clear the unblock flag */
+            sngss7_clear_flag(sngss7_info, FLAG_CKT_MN_UNBLK_RX);
+
+            /* send a uba */
+            ft_to_sngss7_uba(ftdmchan);
+
+            /* check the last state and return to it to allow the call to finish */
+            ftdm_set_state_locked(ftdmchan, ftdmchan->last_state);
+        }
+        /**********************************************************************/
+        if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) {
+            SS7_DEBUG("processing tx Mn ckt block for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id);
+            /* bring the channel signaling status to down */
+            status = FTDM_SIG_STATE_DOWN;
+            sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+            sigev.raw_data = &status;
+            ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+            /* send a blo */
+            ft_to_sngss7_blo(ftdmchan);
+
+            /* check the last state and return to it to allow the call to finish */
+            ftdm_set_state_locked(ftdmchan, ftdmchan->last_state);
+        }
+        if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX)) {
+            SS7_DEBUG("processing tx Mn ckt unblock for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id);
+            /* bring the channel signaling status to up */
+            status = FTDM_SIG_STATE_UP;
+            sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+            sigev.raw_data = &status;
+            ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+            /* clear the unblock flag */
+            sngss7_clear_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX);
+
+            /* send a ubl */
+            ft_to_sngss7_ubl(ftdmchan);
+
+            /* check the last state and return to it to allow the call to finish */
+            ftdm_set_state_locked(ftdmchan, ftdmchan->last_state);
+        }
+        /**********************************************************************/
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_IN_LOOP:                              /* COT test */
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+
+        /* send the lpa */
+        ft_to_sngss7_lpa(ftdmchan);
+
+        break;
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_HOLD:
+    case FTDM_CHANNEL_STATE_DIALTONE:
+    case FTDM_CHANNEL_STATE_BUSY:
+    case FTDM_CHANNEL_STATE_ATTN:
+    case FTDM_CHANNEL_STATE_GENRING:
+    case FTDM_CHANNEL_STATE_GET_CALLERID:
+    case FTDM_CHANNEL_STATE_CALLWAITING:
+    case FTDM_CHANNEL_STATE_IDLE:
+    case FTDM_CHANNEL_STATE_INVALID:
+        ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 does not support state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+        break;
+    /**************************************************************************/
+    default:
+        /*this is bad...we're in an unknown state...should we kill this channel???*/
+        ftdm_log(FTDM_LOG_ERROR, "ftmod_sangoma_ss7 in unknown state %s on span=%u,chan=%u\n",
+                                    ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id);
+        break;
+    } /*switch (ftdmchan->state)*/
+
+    /*unlock*/
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    return;
+}
+/******************************************************************************/
+
+/******************************************************************************/
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_ss7_outgoing_call)
+{
+    sngss7_chan_data_t  *sngss7_info;
+    int c;
+
+    /* lock the channel while we check whether it is availble */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    switch (ftdmchan->state) {
+    /**************************************************************************/
+    case FTDM_CHANNEL_STATE_DOWN:
+        /* inform the monitor thread that we want to make a call */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+
+        /* unlock the channel */
+        ftdm_mutex_unlock(ftdmchan->mutex);
+
+        /* now we have to wait for either the stack to reject the call because of
+         * glare or for the network to acknowledge the call
+         */
+        c = 0;
+        while (c < 20) {
+
+            /* lock the channel while we check whether it is availble */
+            ftdm_mutex_lock(ftdmchan->mutex);
+
+            /* extract the sngss7_chan_data structure */
+            sngss7_info = (sngss7_chan_data_t  *)ftdmchan->call_data;
+
+            if (sngss7_test_flag(sngss7_info, FLAG_GLARE)) {
+                SS7_ERROR("Glare flag on span=%d, chan=%d\n",
+                            ftdmchan->span_id,ftdmchan->chan_id);
+
+                /* move the channel to DOWN to clear the existing channel allocations */
+                ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+                goto outgoing_glare;
+            }
+
+            switch (ftdmchan->state) {
+            /******************************************************************/
+            case FTDM_CHANNEL_STATE_DIALING:
+                break;
+            /******************************************************************/
+            case FTDM_CHANNEL_STATE_PROGRESS:
+            case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+            case FTDM_CHANNEL_STATE_UP:
+                SS7_DEBUG("Outgoing call request successful on span=%d, chan=%d\n",
+                            ftdmchan->span_id,ftdmchan->chan_id);
+                goto outgoing_successful;
+                break;
+            /******************************************************************/
+            default:
+                SS7_ERROR("Channel in invalid state (%s) on span=%d, chan=%d...should not happen\n",
+                        ftdm_channel_state2str(ftdmchan->state),
+                        ftdmchan->span_id,
+                        ftdmchan->chan_id);
+                goto outgoing_fail;
+                break;
+            /******************************************************************/
+            }
+
+            /* unlock the channel */
+            ftdm_mutex_unlock(ftdmchan->mutex);
+
+            /* sleep for a bit to let the state change */
+            ftdm_sleep(50);
+
+            /* increment the timeout counter */
+            c++;
+
+        } /* while (c < 4) */
+
+        /* if we got here we have timed-out waiting for acknowledgment, kill the call */
+        SS7_DEBUG("Timeout waiting for outgoing call to be accepted by network, ok'ing outgoing call on span=%d, chan=%d\n",
+                        ftdmchan->span_id,ftdmchan->chan_id);
+
+        /* consider the call good .... for now */
+        goto outgoing_successful;
+
+        break;
+    /**************************************************************************/
+    default:
+        /* the channel is already used...this can't be, end the request */
+        SS7_ERROR("Outgoing call requested channel in already in use...indicating glare on span=%d, chan=%d\n",
+                            ftdmchan->span_id,ftdmchan->chan_id);
+        goto outgoing_glare;
+        break;        
+    /**************************************************************************/
+    }
+
+    /* we should not get to this here...all exit points above use goto */
+    SS7_ERROR("WE SHOULD NOT HERE HERE!!!!\n");
+
+outgoing_fail:
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+    return FTDM_FAIL;
+
+outgoing_glare:
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);  
+    return FTDM_BREAK;
+
+outgoing_successful:
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+    return FTDM_SUCCESS;
+}
+/******************************************************************************/
+#if 0
+static FIO_CHANNEL_REQUEST_FUNCTION(ftdm_ss7_request_chan)
+{
+    SS7_INFO("KONRAD-> I got called %s\n",__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+#endif
+
+/******************************************************************************/
+
+/* FT-CORE SIG STATUS FUNCTIONS ***********************************************/
+static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_ss7_get_sig_status)
+{
+    
+    if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
+        *status = FTDM_SIG_STATE_UP;
+    } else {
+        *status = FTDM_SIG_STATE_DOWN;
+    }
+
+    return FTDM_SUCCESS;
+}
+
+static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_ss7_set_sig_status)
+{
+    SS7_ERROR("Cannot set channel status in this module\n");
+
+    return FTDM_NOTIMPL;
+}
+
+/* FT-CORE SIG FUNCTIONS *******************************************************/
+static ftdm_status_t ftdm_ss7_start(ftdm_span_t *span)
+{
+    SS7_INFO("Starting span %s:%u.\n",span->name,span->span_id);
+
+    /* clear the monitor thread stop flag */
+    ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
+    ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+
+    /* activate all the configured ss7 links */
+    if (ft_to_sngss7_activate_all()) {
+        SS7_CRITICAL("Failed to activate LibSngSS7!\n");
+        return FTDM_FAIL;
+    }
+
+    /*start the span monitor thread*/
+    if(ftdm_thread_create_detached(ftdm_ss7_run, span) != FTDM_SUCCESS) {
+        SS7_CRITICAL("Failed to start Span Monitor Thread!\n");
+        return FTDM_FAIL;
+    }
+
+    SS7_DEBUG("Finished starting span %s:%u.\n",span->name,span->span_id);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static ftdm_status_t ftdm_ss7_stop(ftdm_span_t *span)
+{
+    /*this function is called by the FT-Core to stop this span*/
+    
+    ftdm_log(FTDM_LOG_INFO, "Stopping span %s:%u.\n",span->name,span->span_id);
+    
+    /* throw the STOP_THREAD flag to signal monitor thread stop */
+    ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
+    
+    /* wait for the thread to stop */
+    while(ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
+        ftdm_log(FTDM_LOG_DEBUG, "Waiting for monitor thread to end for %s:%u.\n",span->name,span->span_id);
+        ftdm_sleep(1);
+    }
+
+    /* KONRAD FIX ME - deconfigure any circuits, links, attached to this span */
+
+    ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s:%u.\n",span->name,span->span_id);
+
+    return FTDM_SUCCESS;
+}
+/******************************************************************************/
+
+/* SIG_FUNCTIONS ***************************************************************/
+static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_ss7_span_config)
+{
+    ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_ss7 span = %s(%d)...\n", 
+                    span->name,
+                    span->span_id);
+
+    /* parse the configuration and apply to the global config structure */
+    if (ftmod_ss7_parse_xml(ftdm_parameters, span)) {
+        ftdm_log(FTDM_LOG_CRIT, "Failed to parse configuration!\n");
+
+        return FTDM_FAIL;
+    }
+
+    /* configure libsngss7 */
+    if (ft_to_sngss7_cfg()) {
+        ftdm_log(FTDM_LOG_CRIT, "Failed to configure LibSngSS7!\n");
+        return FTDM_FAIL;
+    }
+
+    /*setup the span structure with the info so far*/
+    g_ftdm_sngss7_data.sig_cb = sig_cb;
+
+    span->start                     = ftdm_ss7_start;
+    span->stop                      = ftdm_ss7_stop;
+    span->signal_type               = FTDM_SIGTYPE_SANGOMASS7;
+    span->signal_data               = NULL;
+    span->outgoing_call             = ftdm_ss7_outgoing_call;
+    span->channel_request           = NULL;
+    span->signal_cb                 = sig_cb;
+    span->get_channel_sig_status    = ftdm_ss7_get_sig_status;
+    span->set_channel_sig_status    = ftdm_ss7_set_sig_status;
+    span->state_map                 = &sangoma_ss7_state_map;
+    ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
+
+    ftdm_log(FTDM_LOG_INFO, "Finished configuring ftmod_sangoma_ss7 span = %s(%d)...\n", 
+                    span->name,
+                    span->span_id);
+#if 0
+    /* start the span up */
+    ftdm_ss7_start(span);
+#endif
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static FIO_SIG_LOAD_FUNCTION(ftdm_ss7_init)
+{
+    /*this function is called by the FT-core to load the signaling module*/
+
+    ftdm_log(FTDM_LOG_INFO, "Loading ftmod_sangoma_ss7...\n");
+
+    /* default the global structure */
+    memset(&g_ftdm_sngss7_data, 0x0, sizeof(ftdm_sngss7_data_t));
+
+    sngss7_id = 0;
+
+    /* global flag indicating that general configuration has been done */
+    g_ftdm_sngss7_data.gen_config_done = 0;
+
+    /* min. number of digitis to wait for */
+    g_ftdm_sngss7_data.min_digits = 7;
+
+    /* function trace initizalation */
+    g_ftdm_sngss7_data.function_trace = 1;
+    g_ftdm_sngss7_data.function_trace_level = 7;
+
+    /* message (IAM, ACM, ANM, etc) trace initizalation */
+    g_ftdm_sngss7_data.message_trace = 1;
+    g_ftdm_sngss7_data.message_trace_level = 7;
+
+    /* create a timer schedule */
+    if (ftdm_sched_create(&sngss7_sched, "SngSS7_Schedule")) {
+        SS7_CRITICAL("Unable to create timer schedule!\n");
+        return FTDM_FAIL;
+    }
+
+    /* setup the call backs needed by Sangoma_SS7 library */
+    sng_event.cc.sng_con_ind = sngss7_con_ind;
+    sng_event.cc.sng_con_cfm = sngss7_con_cfm;
+    sng_event.cc.sng_con_sta = sngss7_con_sta;
+    sng_event.cc.sng_rel_ind = sngss7_rel_ind;
+    sng_event.cc.sng_rel_cfm = sngss7_rel_cfm;
+    sng_event.cc.sng_dat_ind = sngss7_dat_ind;
+    sng_event.cc.sng_fac_ind = sngss7_fac_ind;
+    sng_event.cc.sng_fac_cfm = sngss7_fac_cfm;
+    sng_event.cc.sng_sta_ind = sngss7_sta_ind;
+    sng_event.cc.sng_umsg_ind = sngss7_umsg_ind;
+    sng_event.cc.sng_susp_ind = NULL;
+    sng_event.cc.sng_resm_ind = NULL;
+    sng_event.cc.sng_ssp_sta_cfm = NULL;
+
+    sng_event.sm.sng_log = handle_sng_log;
+    sng_event.sm.sng_mtp1_alarm = handle_sng_alarm;
+    sng_event.sm.sng_mtp2_alarm = handle_sng_alarm;
+    sng_event.sm.sng_mtp3_alarm = handle_sng_alarm;
+    sng_event.sm.sng_isup_alarm = handle_sng_alarm;
+    sng_event.sm.sng_cc_alarm = handle_sng_alarm;
+
+    /* initalize sng_ss7 library */
+    sng_isup_init(&sng_event);
+
+    /* crash on assert fail */
+    ftdm_global_set_crash_policy(FTDM_CRASH_ON_ASSERT);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static FIO_SIG_UNLOAD_FUNCTION(ftdm_ss7_unload)
+{
+    /*this function is called by the FT-core to unload the signaling module*/
+
+    ftdm_log(FTDM_LOG_INFO, "Starting ftmod_sangoma_ss7 unload...\n");
+
+    sng_isup_free(); 
+
+    ftdm_log(FTDM_LOG_INFO, "Finished ftmod_sangoma_ss7 unload!\n");
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static FIO_API_FUNCTION(ftdm_ss7_api)
+{
+    /* handle this in it's own file....so much to do */
+    return (ftdm_sngss7_handle_cli_cmd(stream, data));
+}
+
+/******************************************************************************/
+static FIO_IO_LOAD_FUNCTION(ftdm_ss7_io_init)
+{
+    assert(fio != NULL);
+    memset(&g_ftdm_sngss7_interface, 0, sizeof(g_ftdm_sngss7_interface));
+
+    g_ftdm_sngss7_interface.name = "ss7";
+    g_ftdm_sngss7_interface.api = ftdm_ss7_api;
+
+    *fio = &g_ftdm_sngss7_interface;
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+
+
+/* START **********************************************************************/
+ftdm_module_t ftdm_module =
+{
+    "sangoma_ss7",                  /*char name[256];                   */
+    ftdm_ss7_io_init,               /*fio_io_load_t                     */
+    NULL,                           /*fio_io_unload_t                   */
+    ftdm_ss7_init,                  /*fio_sig_load_t                    */
+    NULL,                           /*fio_sig_configure_t               */
+    ftdm_ss7_unload,                /*fio_sig_unload_t                  */
+    ftdm_ss7_span_config            /*fio_configure_span_signaling_t    */
+};
+/******************************************************************************/
+
+/*****************************************************************************/
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
+/******************************************************************************/
+
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
new file mode 100644 (file)
index 0000000..5f4aaca
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/******************************************************************************/
+#ifndef __FTMOD_SNG_SS7_H__
+#define __FTMOD_SNG_SS7_H__
+/******************************************************************************/
+
+/* INCLUDE ********************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "private/ftdm_core.h"
+
+#include "sng_sit.h"
+#include "sng_ss7.h"
+#include "sng_ss7_error.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+#define MAX_CIC_LENGTH      5
+#define MAX_CIC_MAP_LENGTH  256 
+#define MAX_MTP_LINKS       MAX_SN_LINKSETS
+
+#if 0
+#define SS7_HARDCODED
+#endif
+#define SNG_BASE    1
+
+typedef enum {
+    SNG_IAM = 1,
+    SNG_ACM,
+    SNG_CPG,
+    SNG_ANM,
+    SNG_REL,
+    SNG_RLC
+}sng_msg_type_t;
+
+typedef struct ftdm_sngss7_data {
+    sng_config_t        cfg;
+    int                 gen_config_done;
+    int                 min_digits;
+    int                 function_trace;
+    int                 function_trace_level;
+    int                 message_trace;
+    int                 message_trace_level;
+    fio_signal_cb_t     sig_cb;
+}ftdm_sngss7_data_t;
+
+typedef struct sngss7_timer_data {
+    ftdm_timer_t            *heartbeat_timer;
+    int                     beat;
+    int                     counter;
+    ftdm_sched_callback_t   callback;
+    ftdm_sched_t            *sched;
+    void                    *sngss7_info;
+}sngss7_timer_data_t;
+
+typedef struct sngss7_glare_data {
+    uint32_t                suInstId; 
+    uint32_t                spInstId;
+    uint32_t                circuit; 
+    SiConEvnt               iam;
+}sngss7_glare_data_t;
+
+typedef struct sngss7_chan_data {
+    ftdm_channel_t          *ftdmchan;
+    sng_isupCircuit_t       *circuit;
+    uint32_t                suInstId;
+    uint32_t                spInstId;
+    uint32_t                spId;
+    uint8_t                 globalFlg;
+    uint32_t                flags;
+    sngss7_glare_data_t     glare;
+    sngss7_timer_data_t     t35;
+}sngss7_chan_data_t;
+
+
+
+typedef enum {
+    FLAG_RESET_RX           = (1 << 0),
+    FLAG_RESET_TX           = (1 << 1),
+    FLAG_REMOTE_REL         = (1 << 2),
+    FLAG_LOCAL_REL          = (1 << 3),
+    FLAG_GLARE              = (1 << 4),
+    FLAG_INFID_RESUME       = (1 << 17),
+    FLAG_INFID_PAUSED       = (1 << 18),
+    FLAG_CKT_MN_BLOCK_RX    = (1 << 19),
+    FLAG_CKT_MN_BLOCK_TX    = (1 << 20),
+    FLAG_CKT_MN_UNBLK_RX    = (1 << 21),
+    FLAG_CKT_MN_UNBLK_TX    = (1 << 22),
+    FLAG_GRP_HW_BLOCK_RX    = (1 << 23),
+    FLAG_GRP_HW_BLOCK_TX    = (1 << 24),
+    FLAG_GRP_MN_BLOCK_RX    = (1 << 25),
+    FLAG_GRP_MN_BLOCK_TX    = (1 << 28),
+    FLAG_GRP_HW_UNBLK_RX    = (1 << 27),
+    FLAG_GRP_HW_UNBLK_TX    = (1 << 28),
+    FLAG_GRP_MN_UNBLK_RX    = (1 << 29),
+    FLAG_GRP_MN_UNBLK_TX    = (1 << 30)
+} flag_t;
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+extern ftdm_sngss7_data_t   g_ftdm_sngss7_data;
+extern uint32_t             sngss7_id;
+extern ftdm_sched_t         *sngss7_sched;
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+extern void handle_sng_log(uint8_t level, char *fmt,...);
+extern void handle_sng_alarm(sng_alrm_t t_alarm);
+
+extern int  ft_to_sngss7_cfg(void);
+extern int  ft_to_sngss7_activate_all(void);
+
+extern void ft_to_sngss7_iam(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_acm(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_anm(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_rel(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_rlc(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_rsc(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_rsca(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_blo(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_bla(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_ubl(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_uba(ftdm_channel_t *ftdmchan);
+extern void ft_to_sngss7_lpa(ftdm_channel_t *ftdmchan);
+
+extern void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+extern void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt);
+extern void sngss7_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt);
+extern void sngss7_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCnStEvnt *siCnStEvnt, uint8_t evntType);
+extern void sngss7_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt);
+extern void sngss7_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt);
+extern void sngss7_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiInfoEvnt *siInfoEvnt);
+extern void sngss7_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt);
+extern void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt);
+extern void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt);
+extern void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit);
+
+extern uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum);
+extern uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum);
+extern uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum);
+extern uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum);
+extern uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven);
+extern int check_for_state_change(ftdm_channel_t *ftdmchan);
+extern ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan);
+extern unsigned long get_unique_id(void);
+
+extern int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span);
+
+extern void handle_isup_t35(void *userdata);
+
+extern ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data);
+/******************************************************************************/
+
+/* MACROS *********************************************************************/
+#define SS7_DEBUG(a,...)    ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ );
+#define SS7_INFO(a,...)     ftdm_log(FTDM_LOG_INFO,a,##__VA_ARGS__ );
+#define SS7_WARN(a,...)     ftdm_log(FTDM_LOG_WARNING,a,##__VA_ARGS__ );
+#define SS7_ERROR(a,...)    ftdm_log(FTDM_LOG_ERROR,a,##__VA_ARGS__ );
+#define SS7_CRITICAL(a,...) ftdm_log(FTDM_LOG_CRIT,a,##__VA_ARGS__ );
+
+#ifdef KONRAD_DEVEL
+#define SS7_DEVEL_DEBUG(a,...)   ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ );
+#else
+#define SS7_DEVEL_DEBUG(a,...)
+#endif
+
+#define SS7_FUNC_TRACE_ENTER(a) if (g_ftdm_sngss7_data.function_trace) { \
+                                    switch (g_ftdm_sngss7_data.function_trace_level) { \
+                                        case 0: \
+                                            ftdm_log(FTDM_LOG_EMERG,"Entering %s\n", a); \
+                                            break; \
+                                        case 1: \
+                                            ftdm_log(FTDM_LOG_ALERT,"Entering %s\n", a); \
+                                            break; \
+                                        case 2: \
+                                            ftdm_log(FTDM_LOG_CRIT,"Entering %s\n", a); \
+                                            break; \
+                                        case 3: \
+                                            ftdm_log(FTDM_LOG_ERROR,"Entering %s\n", a); \
+                                            break; \
+                                        case 4: \
+                                            ftdm_log(FTDM_LOG_WARNING,"Entering %s\n", a); \
+                                            break; \
+                                        case 5: \
+                                            ftdm_log(FTDM_LOG_NOTICE,"Entering %s\n", a); \
+                                            break; \
+                                        case 6: \
+                                            ftdm_log(FTDM_LOG_INFO,"Entering %s\n", a); \
+                                            break; \
+                                        case 7: \
+                                            ftdm_log(FTDM_LOG_DEBUG,"Entering %s\n", a); \
+                                            break; \
+                                        default: \
+                                            ftdm_log(FTDM_LOG_INFO,"Entering %s\n", a); \
+                                            break; \
+                                        } /* switch (g_ftdm_sngss7_data.function_trace_level) */ \
+                                } /*  if(g_ftdm_sngss7_data.function_trace) */
+
+#define SS7_FUNC_TRACE_EXIT(a) if (g_ftdm_sngss7_data.function_trace) { \
+                                    switch (g_ftdm_sngss7_data.function_trace_level) { \
+                                        case 0: \
+                                            ftdm_log(FTDM_LOG_EMERG,"Exitting %s\n", a); \
+                                            break; \
+                                        case 1: \
+                                            ftdm_log(FTDM_LOG_ALERT,"Exitting %s\n", a); \
+                                            break; \
+                                        case 2: \
+                                            ftdm_log(FTDM_LOG_CRIT,"Exitting %s\n", a); \
+                                            break; \
+                                        case 3: \
+                                            ftdm_log(FTDM_LOG_ERROR,"Exitting %s\n", a); \
+                                            break; \
+                                        case 4: \
+                                            ftdm_log(FTDM_LOG_WARNING,"Exitting %s\n", a); \
+                                            break; \
+                                        case 5: \
+                                            ftdm_log(FTDM_LOG_NOTICE,"Exitting %s\n", a); \
+                                            break; \
+                                        case 6: \
+                                            ftdm_log(FTDM_LOG_INFO,"Exitting %s\n", a); \
+                                            break; \
+                                        case 7: \
+                                            ftdm_log(FTDM_LOG_DEBUG,"Exitting %s\n", a); \
+                                            break; \
+                                        default: \
+                                            ftdm_log(FTDM_LOG_INFO,"Exitting %s\n", a); \
+                                            break; \
+                                        } /* switch (g_ftdm_sngss7_data.function_trace_level) */ \
+                                } /*  if(g_ftdm_sngss7_data.function_trace) */
+
+#define SS7_MSG_TRACE(a,...) if (g_ftdm_sngss7_data.message_trace) { \
+                                    switch (g_ftdm_sngss7_data.message_trace_level) { \
+                                        case 0: \
+                                            ftdm_log(FTDM_LOG_EMERG,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        case 1: \
+                                            ftdm_log(FTDM_LOG_ALERT,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        case 2: \
+                                            ftdm_log(FTDM_LOG_CRIT,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        case 3: \
+                                            ftdm_log(FTDM_LOG_ERROR,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        case 4: \
+                                            ftdm_log(FTDM_LOG_WARNING,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        case 5: \
+                                            ftdm_log(FTDM_LOG_NOTICE,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        case 6: \
+                                            ftdm_log(FTDM_LOG_INFO,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        case 7: \
+                                            ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        default: \
+                                            ftdm_log(FTDM_LOG_INFO,a,##__VA_ARGS__ ); \
+                                            break; \
+                                        } /* switch (g_ftdm_sngss7_data.message_trace_level) */ \
+                                } /* if(g_ftdm_sngss7_data.message_trace) */
+
+#define sngss7_test_flag(obj, flag)  ((obj)->flags & flag)
+#define sngss7_clear_flag(obj, flag) ((obj)->flags &= ~(flag))
+#define sngss7_set_flag(obj, flag)   ((obj)->flags |= (flag))
+
+/******************************************************************************/
+
+/******************************************************************************/
+#endif /* __FTMOD_SNG_SS7_H__ */
+/******************************************************************************/
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
new file mode 100644 (file)
index 0000000..c592933
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* INCLUDE ********************************************************************/
+#include "ftmod_sangoma_ss7_main.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+void ft_to_sngss7_iam(ftdm_channel_t *ftdmchan);
+void ft_to_sngss7_acm(ftdm_channel_t *ftdmchan);
+void ft_to_sngss7_anm(ftdm_channel_t *ftdmchan);
+void ft_to_sngss7_rel(ftdm_channel_t *ftdmchan);
+void ft_to_sngss7_rlc(ftdm_channel_t *ftdmchan);
+
+void ft_to_sngss7_rsc(ftdm_channel_t *ftdmchan);
+void ft_to_sngss7_rsca(ftdm_channel_t *ftdmchan);
+
+void ft_to_sngss7_blo(ftdm_channel_t *ftdmchan);
+void ft_to_sngss7_bla(ftdm_channel_t *ftdmchan);
+void ft_to_sngss7_ubl(ftdm_channel_t *ftdmchan);
+void ft_to_sngss7_uba(ftdm_channel_t *ftdmchan);
+
+void ft_to_sngss7_lpa(ftdm_channel_t *ftdmchan);
+
+/* FUNCTIONS ******************************************************************/
+void ft_to_sngss7_iam(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;;
+    SiConEvnt           iam;
+
+    sngss7_info->suInstId = get_unique_id();
+    sngss7_info->spInstId = 0;
+    sngss7_info->spId = 1;
+
+    memset(&iam, 0x0, sizeof(iam));
+
+    /* copy down the nature of connection indicators */
+    iam.natConInd.eh.pres              = PRSNT_NODEF;
+    iam.natConInd.satInd.pres          = PRSNT_NODEF;
+    iam.natConInd.satInd.val           = 0;
+    iam.natConInd.contChkInd.pres      = PRSNT_NODEF;
+    iam.natConInd.contChkInd.val       = 0x00;
+    iam.natConInd.echoCntrlDevInd.pres = PRSNT_NODEF;
+    iam.natConInd.echoCntrlDevInd.val  = 0x01;
+
+    /* copy down the forward call indicators */
+    iam.fwdCallInd.eh.pres                 = PRSNT_NODEF;
+    iam.fwdCallInd.natIntCallInd.pres      = PRSNT_NODEF;
+    iam.fwdCallInd.natIntCallInd.val       = 0x00;
+    iam.fwdCallInd.end2EndMethInd.pres     = PRSNT_NODEF;
+    iam.fwdCallInd.end2EndMethInd.val      = 0x00;
+    iam.fwdCallInd.intInd.pres             = PRSNT_NODEF;
+    iam.fwdCallInd.intInd.val              = 0x01;
+    iam.fwdCallInd.end2EndInfoInd.pres     = PRSNT_NODEF;
+    iam.fwdCallInd.end2EndInfoInd.val      = 0x00;
+    iam.fwdCallInd.isdnUsrPrtInd.pres      = PRSNT_NODEF;
+    iam.fwdCallInd.isdnUsrPrtInd.val       = 0x01;
+    iam.fwdCallInd.isdnUsrPrtPrfInd.pres   = PRSNT_NODEF;
+    iam.fwdCallInd.isdnUsrPrtPrfInd.val    = 0x02;
+    iam.fwdCallInd.isdnAccInd.pres         = PRSNT_NODEF;
+    iam.fwdCallInd.isdnAccInd.val          = 0x01;
+    iam.fwdCallInd.sccpMethInd.pres        = PRSNT_NODEF;
+    iam.fwdCallInd.sccpMethInd.val         = 0x00;
+
+    /* copy down the calling number information */
+    iam.cgPtyCat.eh.pres       = PRSNT_NODEF;
+    iam.cgPtyCat.cgPtyCat.pres = PRSNT_NODEF;
+    iam.cgPtyCat.cgPtyCat.val  = 0x0a;
+
+    /* copy down the transmission medium requirements */
+    iam.txMedReq.eh.pres       = PRSNT_NODEF;
+    iam.txMedReq.trMedReq.pres = PRSNT_NODEF;
+    iam.txMedReq.trMedReq.val  = 0;    /* SPEECH = 0, 3.1Khz = 3, 64k unres = 2 */
+
+    /* copy down the called number information */
+    copy_cdPtyNum_to_sngss7(&ftdmchan->caller_data, &iam.cdPtyNum);
+
+    /* copy down the calling number information */
+    copy_cgPtyNum_to_sngss7(&ftdmchan->caller_data, &iam.cgPtyNum);
+
+    sng_cc_con_request(sngss7_info->spId, 
+                        sngss7_info->suInstId, 
+                        sngss7_info->spInstId, 
+                        sngss7_info->circuit->id, 
+                        &iam, 
+                        0);
+
+    SS7_MSG_TRACE("Transmitted IAM on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+/******************************************************************************/
+
+void ft_to_sngss7_acm(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+    SiCnStEvnt          acm;
+
+    memset(&acm, 0x0, sizeof(acm));
+
+    /* fill in the needed information for the ACM */
+    acm.bckCallInd.eh.pres              = PRSNT_NODEF;
+    acm.bckCallInd.chrgInd.pres         = PRSNT_NODEF;
+    acm.bckCallInd.chrgInd.val          = 0x00;
+    acm.bckCallInd.cadPtyStatInd.pres   = PRSNT_NODEF;
+    acm.bckCallInd.cadPtyStatInd.val    = 0x01;
+    acm.bckCallInd.cadPtyCatInd.pres    = PRSNT_NODEF;
+    acm.bckCallInd.cadPtyCatInd.val     = 0x00;
+    acm.bckCallInd.end2EndMethInd.pres  = PRSNT_NODEF;
+    acm.bckCallInd.end2EndMethInd.val   = 0x00;
+    acm.bckCallInd.intInd.pres          = PRSNT_NODEF;
+    acm.bckCallInd.intInd.val           = 0x00;
+    acm.bckCallInd.end2EndInfoInd.pres  = PRSNT_NODEF;
+    acm.bckCallInd.end2EndInfoInd.val   = 0x00;
+    acm.bckCallInd.isdnUsrPrtInd.pres   = PRSNT_NODEF;
+    acm.bckCallInd.isdnUsrPrtInd.val    = 0x0;
+    acm.bckCallInd.holdInd.pres         = PRSNT_NODEF;
+    acm.bckCallInd.holdInd.val          = 0x00;
+    acm.bckCallInd.isdnAccInd.pres      = PRSNT_NODEF;
+    acm.bckCallInd.isdnAccInd.val       = 0x0;
+    acm.bckCallInd.echoCtrlDevInd.pres  = PRSNT_NODEF;
+    acm.bckCallInd.echoCtrlDevInd.val   = 0x0;
+    acm.bckCallInd.sccpMethInd.pres     = PRSNT_NODEF;
+    acm.bckCallInd.sccpMethInd.val      = 0x00;
+
+    /* send the ACM request to LibSngSS7 */
+    sng_cc_con_status(1, 
+                      sngss7_info->suInstId, 
+                      sngss7_info->spInstId, 
+                      sngss7_info->circuit->id,
+                      &acm, 
+                      ADDRCMPLT);
+
+    SS7_MSG_TRACE("Transmitted ACM on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+/******************************************************************************/
+
+void ft_to_sngss7_anm(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+    SiConEvnt           anm;
+
+    memset(&anm, 0x0, sizeof(anm));
+
+    /* send the ANM request to LibSngSS7 */
+    sng_cc_con_response(1, 
+                        sngss7_info->suInstId, 
+                        sngss7_info->spInstId, 
+                        sngss7_info->circuit->id, 
+                        &anm, 
+                        5);
+
+    SS7_MSG_TRACE("Transmitted ANM on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_rel(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+    SiRelEvnt           rel;
+
+    memset(&rel, 0x0, sizeof(rel));
+
+    rel.causeDgn.eh.pres           = PRSNT_NODEF;
+    rel.causeDgn.location.pres     = PRSNT_NODEF;
+    rel.causeDgn.location.val      = 0x01;
+    rel.causeDgn.cdeStand.pres     = PRSNT_NODEF;
+    rel.causeDgn.cdeStand.val      = 0x00;
+    rel.causeDgn.recommend.pres    = NOTPRSNT;
+    rel.causeDgn.causeVal.pres     = PRSNT_NODEF;
+    rel.causeDgn.causeVal.val      = (uint8_t)ftdmchan->caller_data.hangup_cause;
+    rel.causeDgn.dgnVal.pres       = NOTPRSNT;
+
+    /* send the REL request to LibSngSS7 */
+    sng_cc_rel_request(1, 
+                       sngss7_info->suInstId, 
+                       sngss7_info->spInstId, 
+                       sngss7_info->circuit->id, 
+                       &rel);
+
+    SS7_MSG_TRACE("Transmitted REL on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_rlc(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+    SiRelEvnt           rlc;
+
+    memset(&rlc, 0x0, sizeof(rlc));
+
+    /* send the RLC request to LibSngSS7 */
+    sng_cc_rel_response(1, 
+                        sngss7_info->suInstId, 
+                        sngss7_info->spInstId, 
+                        sngss7_info->circuit->id, 
+                        &rlc);
+
+    SS7_MSG_TRACE("Transmitted RLC on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_rsc(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+
+    sng_cc_sta_request(1, 
+                        sngss7_info->suInstId, 
+                        sngss7_info->spInstId, 
+                        sngss7_info->circuit->id, 
+                        sngss7_info->globalFlg, 
+                        SIT_STA_CIRRESREQ, 
+                        NULL);
+
+    SS7_MSG_TRACE("Transmitted RSC on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_rsca(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+
+    sng_cc_sta_request(1, 
+                        sngss7_info->suInstId, 
+                        sngss7_info->spInstId, 
+                        sngss7_info->circuit->id, 
+                        sngss7_info->globalFlg, 
+                        SIT_STA_CIRRESRSP, 
+                        NULL);
+
+    SS7_MSG_TRACE("Transmitted RSC-RLC on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_blo(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+
+    sng_cc_sta_request(1, 
+                       0, 
+                       0, 
+                       sngss7_info->circuit->id, 
+                       sngss7_info->globalFlg, 
+                       SIT_STA_CIRBLOREQ, 
+                       NULL);
+
+    SS7_MSG_TRACE("Transmitted BLO on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_bla(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+
+    sng_cc_sta_request(1, 
+                       0, 
+                       0, 
+                       sngss7_info->circuit->id, 
+                       sngss7_info->globalFlg, 
+                       SIT_STA_CIRBLORSP, 
+                       NULL);
+
+    SS7_MSG_TRACE("Transmitted BLA on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_ubl(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+
+    sng_cc_sta_request(1, 
+                       0, 
+                       0, 
+                       sngss7_info->circuit->id, 
+                       sngss7_info->globalFlg, 
+                       SIT_STA_CIRUBLREQ, 
+                       NULL);
+
+    SS7_MSG_TRACE("Transmitted UBL on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_uba(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+
+    sng_cc_sta_request(1, 
+                       0, 
+                       0, 
+                       sngss7_info->circuit->id, 
+                       sngss7_info->globalFlg, 
+                       SIT_STA_CIRUBLRSP, 
+                       NULL);
+
+    SS7_MSG_TRACE("Transmitted UBA on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+/******************************************************************************/
+void ft_to_sngss7_lpa(ftdm_channel_t *ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_chan_data_t  *sngss7_info = ftdmchan->call_data;
+
+    sng_cc_sta_request(1, 
+                       sngss7_info->suInstId, 
+                       sngss7_info->spInstId, 
+                       sngss7_info->circuit->id, 
+                       sngss7_info->globalFlg, 
+                       SIT_STA_LOOPBACKACK, 
+                       NULL);
+
+    SS7_MSG_TRACE("Transmitted LPA on CIC # %d\n", sngss7_info->circuit->cic);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+/******************************************************************************/
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+/******************************************************************************/
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_suppport.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_suppport.c
new file mode 100644 (file)
index 0000000..85c29f2
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* INCLUDE ********************************************************************/
+#include "ftmod_sangoma_ss7_main.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+uint32_t sngss7_id;
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven);
+uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum);
+uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum);
+uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum);
+uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum);
+
+int check_for_state_change(ftdm_channel_t *ftdmchan);
+unsigned long get_unique_id(void);
+
+ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan);
+
+/******************************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum)
+{
+
+    return 0;
+}
+
+/******************************************************************************/
+uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum)
+{
+    int k;
+    int j;
+    int flag;
+    char tmp;
+    unsigned char lower;
+    unsigned char upper;
+
+    /**************************************************************************/
+    cgPtyNum->eh.pres           = PRSNT_NODEF;
+    /**************************************************************************/
+    cgPtyNum->natAddrInd.pres   = PRSNT_NODEF;
+    cgPtyNum->natAddrInd.val    = 0x03;
+    /**************************************************************************/
+    cgPtyNum->scrnInd.pres      = PRSNT_NODEF;
+    cgPtyNum->scrnInd.val       = ftdm->screen;
+    /**************************************************************************/
+    cgPtyNum->presRest.pres     = PRSNT_NODEF;
+    cgPtyNum->presRest.val      = ftdm->pres;
+    /**************************************************************************/
+    cgPtyNum->numPlan.pres      = PRSNT_NODEF;
+    cgPtyNum->numPlan.val       = 0x01;
+    /**************************************************************************/
+    cgPtyNum->niInd.pres        = PRSNT_NODEF;
+    cgPtyNum->niInd.val         = 0x00;
+    /**************************************************************************/
+    cgPtyNum->addrSig.pres      = PRSNT_NODEF;
+
+    k = 0;
+    j = 0;
+    flag = 0;
+    while (1) {
+        tmp = ftdm->cid_num.digits[k];
+        if (tmp != '\0') {
+            if (isdigit(tmp)) {
+                lower = atoi(&tmp);
+                k++;
+                tmp = ftdm->cid_num.digits[k];
+            } else {
+                while (!(isdigit(tmp)) && (tmp != '\0')) {
+                    k++;
+                    tmp = ftdm->cid_num.digits[k];
+                } /* while(!(isdigit(tmp))) */
+
+                if (tmp != '\0') {
+                    lower = atoi(&tmp);
+                    k++;
+                    tmp = ftdm->cid_num.digits[k];
+                } else {
+                    flag = 1;
+                    lower = 0xf;
+                } /* if (tmp != '\0') */
+            } /* (isdigit(tmp)) */
+        } else {
+            flag = 1;
+            lower = 0xf;
+        } /* if (tmp != '\0') */
+
+        tmp = ftdm->cid_num.digits[k];
+        if (tmp != '\0') {
+            if (isdigit(tmp)) {
+                upper = (atoi(&tmp)) << 4;
+            } else {
+                 while (!(isdigit(tmp)) && (tmp != '\0')) {
+                    k++;
+                    tmp = ftdm->cid_num.digits[k];
+                } /* while(!(isdigit(tmp))) */
+
+                if (tmp != '\0') {
+                    upper = (atoi(&tmp)) << 4;
+                    k++;
+                } else {
+                    flag = 1;
+                    upper = 0xf;
+                } /*  if (tmp != '\0') */
+            } /* if (isdigit(tmp)) */
+        } else {
+            if (flag == 1){
+                upper = 0x0;
+            } else {
+                flag = 1;
+                upper = 0xf;
+            } /* if (flag == 1) */
+        } /* if (tmp != '\0') */
+
+        cgPtyNum->addrSig.val[j] = upper | lower;
+        j++;
+
+        if (flag) {
+            break;
+        } else {
+            k++;
+        }
+    } /* while(1) */
+
+    cgPtyNum->addrSig.len = j;
+    /**************************************************************************/
+    cgPtyNum->oddEven.pres      = PRSNT_NODEF;
+    cgPtyNum->oddEven.val       = ((cgPtyNum->addrSig.val[j] >>4) == 0x0 ) ? 0x01 : 0x00;
+    /**************************************************************************/
+    return 0;
+}
+
+/******************************************************************************/
+uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum)
+{
+
+    return 0;
+}
+
+/******************************************************************************/
+uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum)
+{
+    int k;
+    int j;
+    int flag;
+    char tmp;
+    unsigned char lower;
+    unsigned char upper;
+
+    /**************************************************************************/
+    cdPtyNum->eh.pres           = PRSNT_NODEF;
+    /**************************************************************************/
+    cdPtyNum->natAddrInd.pres   = PRSNT_NODEF;
+    cdPtyNum->natAddrInd.val    = 0x03;
+    /**************************************************************************/
+    cdPtyNum->numPlan.pres      = PRSNT_NODEF;
+    cdPtyNum->numPlan.val       = 0x01;
+    /**************************************************************************/
+    cdPtyNum->innInd.pres       = PRSNT_NODEF;
+    cdPtyNum->innInd.val        = 0x01;
+    /**************************************************************************/
+    cdPtyNum->addrSig.pres      = PRSNT_NODEF;
+
+    k = 0;
+    j = 0;
+    flag = 0;
+    while (1) {
+        tmp = ftdm->dnis.digits[k];
+        if (tmp != '\0') {
+            if (isdigit(tmp)) {
+                lower = atoi(&tmp);
+                k++;
+                tmp = ftdm->dnis.digits[k];
+            } else {
+                while (!(isdigit(tmp)) && (tmp != '\0')) {
+                    k++;
+                    tmp = ftdm->dnis.digits[k];
+                } /* while(!(isdigit(tmp))) */
+
+                if (tmp != '\0') {
+                    lower = atoi(&tmp);
+                    k++;
+                    tmp = ftdm->dnis.digits[k];
+                } else {
+                    flag = 1;
+                    lower = 0xf;
+                } /* if (tmp != '\0') */
+            } /* (isdigit(tmp)) */
+        } else {
+            flag = 1;
+            lower = 0xf;
+        } /* if (tmp != '\0') */
+
+        tmp = ftdm->dnis.digits[k];
+        if (tmp != '\0') {
+            if (isdigit(tmp)) {
+                upper = (atoi(&tmp)) << 4;
+            } else {
+                 while (!(isdigit(tmp)) && (tmp != '\0')) {
+                    k++;
+                    tmp = ftdm->dnis.digits[k];
+                } /* while(!(isdigit(tmp))) */
+
+                if (tmp != '\0') {
+                    upper = (atoi(&tmp)) << 4;
+                    k++;
+                } else {
+                    flag = 1;
+                    upper = 0xf;
+                } /*  if (tmp != '\0') */
+            } /* if (isdigit(tmp)) */
+        } else {
+            if (flag == 1){
+                upper = 0x0;
+            } else {
+                flag = 1;
+                upper = 0xf;
+            } /* if (flag == 1) */
+        } /* if (tmp != '\0') */
+
+        cdPtyNum->addrSig.val[j] = upper | lower;
+        j++;
+
+        if (flag) {
+            break;
+        } else {
+            k++;
+        }
+    } /* while(1) */
+
+    cdPtyNum->addrSig.len = j;
+    /**************************************************************************/
+    cdPtyNum->oddEven.pres      = PRSNT_NODEF;
+    cdPtyNum->oddEven.val       = ((cdPtyNum->addrSig.val[j] >>4) == 0x0 ) ? 0x01 : 0x00;
+    /**************************************************************************/
+    return 0;
+}
+
+/******************************************************************************/
+uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
+{
+    uint8_t i;
+    uint8_t j;
+
+    /* check if the token string is present */
+    if (str.pres == 1) {
+        j=0;
+
+        for (i=0; i < str.len; i++) {
+            sprintf(&ftdm[j], "%d", (str.val[i] & 0x0F));
+            j++;
+            sprintf(&ftdm[j], "%d", ((str.val[i] & 0xF0) >> 4));
+            j++;
+        }
+
+        /* if the odd flag is up the last digit is a fake "0" */
+        if ((oddEven.pres == 1) && (oddEven.val == 1)) {
+            ftdm[j-1] = '\0';
+        } else {
+            ftdm[j] = '\0';
+        }
+    } else {
+        SS7_ERROR("Asked to copy tknStr that is not present!\n");
+        return 1;
+    }
+
+    return 0;
+}
+
+/******************************************************************************/
+int check_for_state_change(ftdm_channel_t *ftdmchan)
+{
+
+#if 0
+    SS7_DEBUG("Checking for pending state change on span: %d, chan: %d\n!",
+                ftdmchan->physical_span_id, 
+                ftdmchan->physical_chan_id);
+#endif
+    /* check to see if there are any pending state changes on the channel and give them a sec to happen*/
+    ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 5000);
+
+    /* check the flag to confirm it is clear now */
+    if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+        /* the flag is still up...so we have a problem */
+        SS7_ERROR("FTDM_CHANNEL_STATE_CHANGE set for over 500ms on span: %d, chan: %d\n", 
+                    ftdmchan->physical_span_id,
+                    ftdmchan->physical_chan_id);
+
+        /* move the state of the channel to RESTART to force a reset */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+
+        return 1;
+    }
+    return 0;
+}
+
+/******************************************************************************/
+ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    if (g_ftdm_sngss7_data.cfg.isupCircuit[circuit].obj == NULL) {
+        SS7_ERROR("sngss7_info is Null for circuit #%d\n", circuit);
+        return FTDM_FAIL;
+    }
+
+    ftdm_assert_return(g_ftdm_sngss7_data.cfg.isupCircuit[circuit].obj,FTDM_FAIL,"received message on signalling link or non-configured cic\n");
+    *sngss7_info = g_ftdm_sngss7_data.cfg.isupCircuit[circuit].obj;
+
+    ftdm_assert_return((*sngss7_info)->ftdmchan,FTDM_FAIL,"received message on signalling link or non-configured cic\n");
+    *ftdmchan = (*sngss7_info)->ftdmchan;
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+unsigned long get_unique_id(void)
+{
+
+    if (sngss7_id < 420000000) {
+        sngss7_id++;
+    } else {
+        sngss7_id = 1;
+    }
+
+    return(sngss7_id);
+}
+
+/******************************************************************************/
+
+/******************************************************************************/
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+/******************************************************************************/
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c
new file mode 100644 (file)
index 0000000..5185ffc
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* INCLUDE ********************************************************************/
+#include "ftmod_sangoma_ss7_main.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+void handle_isup_t35(void *userdata);
+/******************************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+void handle_isup_t35(void *userdata)
+{
+    SS7_FUNC_TRACE_ENTER(__FUNCTION__);
+
+    sngss7_timer_data_t *timer = userdata;
+    sngss7_chan_data_t  *sngss7_info = timer->sngss7_info;
+    ftdm_channel_t      *ftdmchan = sngss7_info->ftdmchan;
+
+    /* now that we have the right channel...put a lock on it so no-one else can use it */
+    ftdm_mutex_lock(ftdmchan->mutex);
+
+    SS7_ERROR("[Call-Control] Timer 35 expired on CIC = %d\n", sngss7_info->circuit->cic);
+
+    /* set the flag to indicate this hangup is started from the local side */
+    sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL);
+
+    /* hang up on timer expiry */
+    ftdmchan->caller_data.hangup_cause = 102;
+
+    /* end the call */
+    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+
+    /*unlock*/
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+/******************************************************************************/
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+/******************************************************************************/
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c
new file mode 100644 (file)
index 0000000..31856f4
--- /dev/null
@@ -0,0 +1,1867 @@
+/*
+ * Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* INCLUDE ********************************************************************/
+#include "ftmod_sangoma_ss7_main.h"
+/******************************************************************************/
+
+/* DEFINES ********************************************************************/
+/******************************************************************************/
+
+/* GLOBALS ********************************************************************/
+typedef struct sng_timeslot
+{
+    int     channel;
+    int     siglink;
+    int     gap;
+    int     hole;
+}sng_timeslot_t;
+/******************************************************************************/
+
+/* PROTOTYPES *****************************************************************/
+int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span);
+
+static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup);
+
+static int ftmod_ss7_parse_mtp_linksets(ftdm_conf_node_t *mtp_linksets);
+static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset);
+static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp1Link_t *mtp1_link,
+                                     sng_mtp2Link_t *mtp2_link, sng_mtp3Link_t *mtp3_link);
+
+static int ftmod_ss7_parse_mtp_routes(ftdm_conf_node_t *mtp_routes);
+static int ftmod_ss7_parse_mtp_route(ftdm_conf_node_t *mtp_route);
+
+static int ftmod_ss7_parse_isup_interfaces(ftdm_conf_node_t *isup_interfaces);
+static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface);
+
+static int ftmod_ss7_fill_in_mtp1_link(sng_mtp1Link_t *mtp1_link);
+static int ftmod_ss7_fill_in_mtp2_link(sng_mtp2Link_t *mtp2_link);
+static int ftmod_ss7_fill_in_mtp3_link(sng_mtp3Link_t *mtp3_link);
+static int ftmod_ss7_fill_in_mtp3_linkset(sng_mtp3LinkSet_t *mtp3_linkset);
+static int ftmod_ss7_fill_in_mtp3_route(sng_mtp3Route_t *mtp3_route);
+static int ftmod_ss7_fill_in_mtp3_isup_interface(sng_mtp3Route_t *mtp3_route);
+static int ftmod_ss7_fill_in_isup_interface(sng_isupInterface_t *sng_isup);
+static int ftmod_ss7_fill_in_isup_cc_interface(sng_isup_cc_t *sng_cc);
+
+static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, int ssf);
+
+static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, int isup_id, ftdm_span_t *span);
+static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot);
+
+/******************************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span)
+{
+    int              i = 0;
+    int              x = 0;
+    const char       *var = NULL;
+    const char       *val = NULL;
+    ftdm_conf_node_t *ptr = NULL;
+    sng_mtp3Route_t  self_route;
+    char             ch_map[MAX_CIC_MAP_LENGTH];
+    int              typeCntrl = 0;
+    int              cicbase = 0;
+
+    /* clean out the self route */
+    memset(&self_route, 0x0, sizeof(sng_mtp3Route_t));
+
+    var = ftdm_parameters[i].var;
+    val = ftdm_parameters[i].val;
+    ptr = (ftdm_conf_node_t *)ftdm_parameters[i].ptr;
+
+    /* confirm that the first parameter is the "confnode" */
+    if (!strcasecmp(var, "confnode")) {
+        /* parse the confnode and fill in the global libsng_ss7 config structure */
+        if (ftmod_ss7_parse_sng_isup(ptr)) {
+            SS7_ERROR("Failed to parse the \"confnode\"!\n");
+            goto ftmod_ss7_parse_xml_error;
+        }
+    } else {
+        /* ERROR...exit */
+        SS7_ERROR("The \"confnode\" configuration was not the first parameter!\n");
+        SS7_ERROR("\tFound \"%s\" in the first slot\n", var);
+        goto ftmod_ss7_parse_xml_error;
+    }
+
+    i++;
+    while (ftdm_parameters[i].var != NULL) {
+
+        var = ftdm_parameters[i].var;
+        val = ftdm_parameters[i].val;
+
+        if (!strcasecmp(var, "ch_map")) {
+        /**********************************************************************/
+            strcpy(ch_map, val);
+            SS7_DEBUG("\tFound channel map \"%s\"\n", ch_map);
+        /**********************************************************************/
+        } else if (!strcasecmp(var, "typeCntrl")) {
+            if (!strcasecmp(val, "bothway")) {
+                typeCntrl = SNG_BOTHWAY;
+                SS7_DEBUG("\tFound control type \"bothway\"\n");
+            } else if (!strcasecmp(val, "incoming")) {
+                typeCntrl = SNG_INCOMING;
+                SS7_DEBUG("\tFound control type \"incoming\"\n");
+            } else if (!strcasecmp(val, "outgoing")) {
+                typeCntrl = SNG_OUTGOING;
+                SS7_DEBUG("\tFound control type \"outgoing\"\n");
+            } else if (!strcasecmp(val, "controlled")) {
+                typeCntrl = SNG_CONTROLLED;
+                SS7_DEBUG("\tFound control type \"controlled\"\n");
+            } else if (!strcasecmp(val, "controlling")) {
+                typeCntrl = SNG_CONTROLLING;
+                SS7_DEBUG("\tFound control type \"controlling\"\n");
+            } else {
+                SS7_ERROR("Found invalid circuit control type \"%s\"!", val);
+                goto ftmod_ss7_parse_xml_error;
+            }
+        /**********************************************************************/
+        } else if (!strcasecmp(var, "cicbase")) {
+            cicbase = atoi(val);
+            SS7_DEBUG("\tFound cicbase = %d\n", cicbase);
+        /**********************************************************************/
+        } else if (!strcasecmp(var, "dialplan")) {
+            /* do i give a shit about this??? */
+        /**********************************************************************/
+        } else if (!strcasecmp(var, "context")) {
+            /* do i give a shit about this??? */
+        /**********************************************************************/
+        } else if (!strcasecmp(var, "isup_interface")) {
+            /* go through all the existing interfaces and see if we find a match */
+            x = 1;
+            while (g_ftdm_sngss7_data.cfg.isupInterface[x].id != 0) {
+                if (!strcasecmp(g_ftdm_sngss7_data.cfg.isupInterface[x].name, val)) {
+                    /* we have a match so break out of this loop */
+                    break;
+                }
+                /* move on to the next one */
+                x++;
+            }
+            SS7_DEBUG("\tFound isup_interface = %s\n",g_ftdm_sngss7_data.cfg.isupInterface[x].name );
+        /**********************************************************************/
+        } else {
+            SS7_ERROR("Unknown parameter found =\"%s\"...ignoring it!\n", var);
+        /**********************************************************************/
+        }
+
+        i++;
+    } /* while (ftdm_parameters[i].var != NULL) */
+
+    /* setup the self mtp3 route */
+    i = g_ftdm_sngss7_data.cfg.isupInterface[x].mtp3RouteId;
+
+    if(ftmod_ss7_fill_in_self_route(g_ftdm_sngss7_data.cfg.spc,
+                                    g_ftdm_sngss7_data.cfg.mtp3Route[i].linkType,
+                                    g_ftdm_sngss7_data.cfg.isupInterface[x].switchType,
+                                    g_ftdm_sngss7_data.cfg.mtp3Route[i].ssf)) {
+        SS7_ERROR("Failed to fill in self route structure!\n");
+        goto ftmod_ss7_parse_xml_error;
+    }
+
+
+    /* setup the circuits structure */
+    if(ftmod_ss7_fill_in_circuits(ch_map, 
+                                  cicbase, 
+                                  typeCntrl, 
+                                  g_ftdm_sngss7_data.cfg.isupInterface[x].id,
+                                  span)) {
+        SS7_ERROR("Failed to fill in circuits structure!\n");
+        goto ftmod_ss7_parse_xml_error;
+    }
+
+    return FTDM_SUCCESS;
+
+ftmod_ss7_parse_xml_error:
+    return FTDM_FAIL;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup)
+{
+    ftdm_conf_node_t    *mtp_linksets = NULL;
+    ftdm_conf_node_t    *mtp_routes = NULL;
+    ftdm_conf_node_t    *isup_interfaces = NULL;
+    ftdm_conf_node_t    *tmp_node = NULL;
+
+    /* confirm that we are looking at sng_isup */
+    if (strcasecmp(sng_isup->name, "sng_isup")) {
+        SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"sng_isup\"!\n",sng_isup->name);
+        return FTDM_FAIL;
+    }  else {
+        SS7_DEBUG("Parsing \"sng_isup\"...\n");
+    }
+
+    /* extract the 3 main sections of the sng_isup block */
+    tmp_node = sng_isup->child;
+    while (tmp_node != NULL) {
+
+        if (!strcasecmp(tmp_node->name, "mtp_linksets")) {
+            if (mtp_linksets == NULL) {
+                mtp_linksets = tmp_node;
+                SS7_DEBUG("\tFound a \"mtp_linksets section!\n");
+            } else {
+                SS7_ERROR("\tFound a second \"mtp_linksets\" section!\n");
+                return FTDM_FAIL;
+            }
+        } else if (!strcasecmp(tmp_node->name, "mtp_routes")) {
+            if (mtp_routes == NULL) {
+                mtp_routes = tmp_node;
+                SS7_DEBUG("\tFound a \"mtp_routes\" section!\n");
+            } else {
+                SS7_ERROR("\tFound a second \"mtp_routes\" section!\n");
+                return FTDM_FAIL;
+            }
+        } else if (!strcasecmp(tmp_node->name, "isup_interfaces")) {
+            if (isup_interfaces == NULL) {
+                isup_interfaces = tmp_node;
+                SS7_DEBUG("\tFound a \"isup_interfaces\" section!\n");
+            } else {
+                SS7_ERROR("\tFound a second \"isup_interfaces\" section\n!");
+                return FTDM_FAIL;
+            }
+        } else {
+            SS7_ERROR("\tFound an unknown section \"%s\"!\n", tmp_node->name);
+            return FTDM_FAIL;
+        }
+
+        /* go to the next sibling */
+        tmp_node = tmp_node->next;
+
+    } /* while (tmp_node != NULL) */
+
+    /* now try to parse the sections */
+    if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) {
+        SS7_ERROR("Failed to parse \"mtp_linksets\"!\n");
+        return FTDM_FAIL;
+    }
+
+    if (ftmod_ss7_parse_mtp_routes(mtp_routes)) {
+        SS7_ERROR("Failed to parse \"mtp_routes\"!\n");
+        return FTDM_FAIL;
+    }
+
+    if (ftmod_ss7_parse_isup_interfaces(isup_interfaces)) {
+        SS7_ERROR("Failed to parse \"isup_interfaces\"!\n");
+        return FTDM_FAIL;
+    }
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_parse_mtp_linksets(ftdm_conf_node_t *mtp_linksets)
+{
+    ftdm_conf_node_t    *mtp_linkset = NULL;
+
+    /* confirm that we are looking at mtp_linksets */
+    if (strcasecmp(mtp_linksets->name, "mtp_linksets")) {
+        SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_linksets\"!\n",mtp_linksets->name);
+        return FTDM_FAIL;
+    }  else {
+        SS7_DEBUG("Parsing \"mtp_linksets\"...\n");
+    }
+
+    /* extract the mtp_links */
+    mtp_linkset = mtp_linksets->child;
+
+    /* run through all of the mtp_linksets found  */
+    while (mtp_linkset != NULL) {
+        /* try to the parse mtp_linkset */
+        if (ftmod_ss7_parse_mtp_linkset(mtp_linkset)) {
+            SS7_ERROR("Failed to parse \"mtp_linkset\"!\n");
+            return FTDM_FAIL;
+        }
+
+        /* move on to the next linkset */
+        mtp_linkset = mtp_linkset->next;
+
+    } /* while (mtp_linkset != NULL) */
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset)
+{
+    ftdm_conf_parameter_t   *parm = mtp_linkset->parameters;
+    int                     num_parms = mtp_linkset->n_parameters;
+    ftdm_conf_node_t        *mtp_link = NULL;
+    sng_mtp1Link_t          mtp1_link[MAX_MTP_LINKS];
+    sng_mtp2Link_t          mtp2_link[MAX_MTP_LINKS];
+    sng_mtp3Link_t          mtp3_link[MAX_MTP_LINKS];
+    sng_mtp3LinkSet_t       mtp3_linkset;
+    int                     count;
+    int                     i;
+
+    /* initialize the mtp_link structures */
+    for (i = 0; i < MAX_MTP_LINKS; i++) {
+        memset(&mtp1_link[i], 0x0, sizeof(mtp1_link[i]));
+        memset(&mtp2_link[i], 0x0, sizeof(mtp2_link[i]));
+        memset(&mtp3_link[i], 0x0, sizeof(mtp3_link[i]));
+    }
+    memset(&mtp3_linkset, 0x0, sizeof(mtp3_linkset));
+
+    /* confirm that we are looking at mtp_linkset */
+    if (strcasecmp(mtp_linkset->name, "mtp_linkset")) {
+        SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_linkset\"!\n",mtp_linkset->name);
+        return FTDM_FAIL;
+    } else {
+        SS7_DEBUG("Parsing \"mtp_linkset\"...\n");
+    }
+
+    /* extract all the information from the parameters */
+    for (i = 0; i < num_parms; i++) {
+        /**********************************************************************/
+        if (!strcasecmp(parm->var, "name")) {
+            strcpy((char *)mtp3_linkset.name, parm->val);
+            SS7_DEBUG("\tFound an \"mtp_linkset\" named = %s\n", mtp3_linkset.name);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "apc")) {
+            mtp3_linkset.apc = atoi(parm->val);
+            SS7_DEBUG("\tFound mtp3_linkSet->apc = %d\n", mtp3_linkset.apc);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "minActive")) {
+            mtp3_linkset.minActive = atoi(parm->val);
+            SS7_DEBUG("\tFound mtp3_linkSet->minActive = %d\n", mtp3_linkset.minActive);
+        /**********************************************************************/
+        } else {
+            SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val);
+            return FTDM_FAIL;
+        }
+
+        /* move to the next parmeter */
+        parm = parm + 1;
+
+    } /* for (i = 0; i < num_parms; i++) */
+
+    /* grab the first mtp-link (which sits below the mtp_links section) */
+    mtp_link = mtp_linkset->child->child;
+
+    /* initalize the link counter */
+    count = 0;
+
+    /* run through all of the mtp_links found  */
+    while (mtp_link != NULL) {
+        /* try to the parse mtp_linkset */
+        if (ftmod_ss7_parse_mtp_link(mtp_link, &mtp1_link[count], &mtp2_link[count], &mtp3_link[count] )) {
+            SS7_ERROR("Failed to parse \"mtp_link\"!\n");
+            return FTDM_FAIL;
+        }
+
+        /* incremenet the link counter */
+        count++;
+
+        /* move on to the next link */
+        mtp_link = mtp_link->next;
+
+    } /* while (mtp_link != NULL) */
+
+    /* confirm we have the right number of links */
+    if (count < 1 || count > 15 ) {
+        SS7_ERROR("Invalid number of mtp_links found (%d)\n", count);
+        return FTDM_FAIL;
+    } else {
+        mtp3_linkset.numLinks = count;
+    }
+
+    /* now we need to see if this linkset exists already or not and grab an Id */
+    i = 1;
+    while (g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].id != 0) {
+        if (!strcasecmp((const char *)g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].name, (const char *)mtp3_linkset.name)) {
+            /* we've found the linkset...so it has already been configured */
+            break;
+        }
+        i++;
+        /* add in error check to make sure we don't go out-of-bounds */
+    }
+
+    /* if the id value is 0 that means we didn't find the linkset */
+    if (g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].id  == 0) {
+        mtp3_linkset.id = i;
+        SS7_DEBUG("found new mtp3_linkset, id is = %d\n", mtp3_linkset.id);
+    } else {
+        mtp3_linkset.id = i;
+        SS7_DEBUG("found existing mtp3_linkset, id is = %d\n", mtp3_linkset.id);
+    }
+
+    /* we now have all the information to fill in the Libsng_ss7 structures */
+    i = 0;
+    count = 0;
+    while (mtp1_link[i].span != 0 ){
+        /* fill in the mtp1 link structure */
+        mtp2_link[i].spId = ftmod_ss7_fill_in_mtp1_link(&mtp1_link[i]);
+        /* fill in the mtp2 link structure */
+        mtp3_link[i].mtp2LinkId = ftmod_ss7_fill_in_mtp2_link(&mtp2_link[i]);
+        /* have to grab a couple of values from the linkset */
+        mtp3_link[i].apc = mtp3_linkset.apc;
+        mtp3_link[i].linkSetId = mtp3_linkset.id;
+        /* fill in the mtp3 link structure */
+        mtp3_linkset.links[count] = ftmod_ss7_fill_in_mtp3_link(&mtp3_link[i]);
+        /* increment the links counter */
+        count++;
+        /* increment the index value */
+        i++;
+    }
+
+    ftmod_ss7_fill_in_mtp3_linkset(&mtp3_linkset);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp1Link_t *mtp1_link,
+            sng_mtp2Link_t *mtp2_link, sng_mtp3Link_t *mtp3_link)
+{
+    ftdm_conf_parameter_t   *parm = mtp_link->parameters;
+    int                     num_parms = mtp_link->n_parameters;
+    int                     i;
+
+    /* confirm that we are looking at an mtp_link */
+    if (strcasecmp(mtp_link->name, "mtp_link")) {
+        SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_link\"!\n",mtp_link->name);
+        return FTDM_FAIL;
+    } else {
+        SS7_DEBUG("Parsing \"mtp_link\"...\n");
+    }
+
+    for (i = 0; i < num_parms; i++) {
+        /* try to match the parameter to what we expect */
+        /**********************************************************************/
+        if (!strcasecmp(parm->var, "name")) {
+            strcpy((char *)mtp1_link->name, parm->val);
+            strcpy((char *)mtp2_link->name, parm->val);
+            strcpy((char *)mtp3_link->name, parm->val);
+            SS7_DEBUG("\tFound an \"mtp_link\" named = %s\n", mtp1_link->name);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "span")) {
+            mtp1_link->span = atoi(parm->val);
+            SS7_DEBUG("\tFound mtp1_link->span = %d\n", mtp1_link->span);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "chan")) {
+            mtp1_link->chan = atoi(parm->val);
+            SS7_DEBUG("\tFound mtp1_link->chan = %d\n", mtp1_link->chan);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "span")) {
+            mtp1_link->span = atoi(parm->val);
+            SS7_DEBUG("\tFound mtp1_link->span = %d\n", mtp1_link->span);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "errorType")) {
+            if (!strcasecmp(parm->val, "basic")) {
+                mtp2_link->errorType = SNG_BASIC_ERR;
+            } else if (!strcasecmp(parm->val, "pcr")) {
+                mtp2_link->errorType = SNG_PCR_ERR;
+            } else {
+                SS7_ERROR("\tFound an invalid \"errorType\" = %s\n", parm->var);
+                return FTDM_FAIL;
+            }
+            SS7_DEBUG("\tFound mtp2_link->errorType=%s\n", parm->val);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "lssuLength")) {
+            mtp2_link->lssuLength = atoi(parm->val);
+            if ((mtp2_link->lssuLength != 1) && (mtp2_link->lssuLength != 2)) {
+                SS7_ERROR("\tFound an invalid \"lssuLength\" = %d\n", mtp2_link->lssuLength);
+                return FTDM_FAIL;
+            } else {
+                SS7_DEBUG("\tFound mtp2_link->lssuLength=%d\n", mtp2_link->lssuLength);
+            }
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "priority")) {
+            mtp3_link->priority = atoi(parm->val);
+            if ((mtp3_link->priority == 0) || (mtp3_link->priority == 1) || 
+                (mtp3_link->priority == 2) || (mtp3_link->priority == 3)) {
+                SS7_DEBUG("\tFound mtp3_link->priority = %d\n",mtp3_link->priority);
+            } else {
+                SS7_ERROR("\tFound an invalid \"priority\"=%d\n", mtp3_link->priority);
+                return FTDM_FAIL;
+            } 
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "linkType")) {
+            if (!strcasecmp(parm->val, "itu92")) {
+                mtp2_link->linkType = SNG_MTP2_ITU92;
+                mtp3_link->linkType = SNG_MTP3_ITU92;
+                SS7_DEBUG("\tFound mtp3_link->linkType = \"ITU92\"\n");
+            } else if (!strcasecmp(parm->val, "itu88")) {
+                mtp2_link->linkType = SNG_MTP2_ITU88;
+                mtp3_link->linkType = SNG_MTP3_ITU88;
+                SS7_DEBUG("\tFound mtp3_link->linkType = \"ITU88\"\n");
+            } else {
+                SS7_ERROR("\tFound an invalid linktype of \"%s\"!\n", parm->val);
+                return FTDM_FAIL;
+            }
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "switchType")) {
+            if (!strcasecmp(parm->val, "itu97")) {
+                mtp3_link->switchType = SNG_ISUP_ITU97;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"ITU97\"\n");
+            } else if (!strcasecmp(parm->val, "itu88")) {
+                mtp3_link->switchType = SNG_ISUP_ITU88;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"ITU88\"\n");
+            } else if (!strcasecmp(parm->val, "itu92")) {
+                mtp3_link->switchType = SNG_ISUP_ITU92;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"ITU92\"\n");
+            } else if (!strcasecmp(parm->val, "itu00")) {
+                mtp3_link->switchType = SNG_ISUP_ITU00;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"ITU00\"\n");
+            } else if (!strcasecmp(parm->val, "ETSIV2")) {
+                mtp3_link->switchType = SNG_ISUP_ETSIV2;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"ETSIV2\"\n");
+            } else if (!strcasecmp(parm->val, "ETSIV3")) {
+                mtp3_link->switchType = SNG_ISUP_ETSIV3;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"ETSIV3\"\n");
+            } else if (!strcasecmp(parm->val, "UK")) {
+                mtp3_link->switchType = SNG_ISUP_UK;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"UK\"\n");
+            } else if (!strcasecmp(parm->val, "RUSSIA")) {
+                mtp3_link->switchType = SNG_ISUP_RUSSIA;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"RUSSIA\"\n");
+            } else if (!strcasecmp(parm->val, "INDIA")) {
+                mtp3_link->switchType = SNG_ISUP_INDIA;
+                SS7_DEBUG("\tFound mtp3_link->switchType = \"INDIA\"\n");
+            } else {
+                SS7_ERROR("\tFound an invalid linktype of \"%s\"!\n", parm->val);
+                return FTDM_FAIL;
+            }
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "ssf")) {
+            if (!strcasecmp(parm->val, "nat")) {
+                mtp3_link->ssf = SNG_SSF_NAT;
+            } else if (!strcasecmp(parm->val, "int")) {
+                mtp3_link->ssf = SNG_SSF_INTER;
+            } else {
+                SS7_ERROR("\tFound an invalid ssf of \"%s\"!\n", parm->val);
+                return FTDM_FAIL;
+            }
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "slc")) {
+            mtp3_link->lnkTstSLC = atoi(parm->val);
+            SS7_DEBUG("\tFound mtp3_link->slc = \"%d\"\n",mtp3_link->lnkTstSLC);
+        /**********************************************************************/
+        } else {
+            SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val);
+            return FTDM_FAIL;
+        }
+
+        /* move to the next parameter */
+        parm = parm + 1;
+    }
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_parse_mtp_routes(ftdm_conf_node_t *mtp_routes)
+{
+    ftdm_conf_node_t    *mtp_route = NULL;
+
+    /* confirm that we are looking at an mtp_routes */
+    if (strcasecmp(mtp_routes->name, "mtp_routes")) {
+        SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_routes\"!\n",mtp_routes->name);
+        return FTDM_FAIL;
+    } else {
+        SS7_DEBUG("Parsing \"mtp_routes\"...\n");
+    }
+
+    /* extract the mtp_routes */
+    mtp_route = mtp_routes->child;
+
+    while (mtp_route != NULL) {
+        /* parse the found mtp_route */
+        if (ftmod_ss7_parse_mtp_route(mtp_route)) {
+            SS7_ERROR("Failed to parse \"mtp_route\"\n");
+            return FTDM_FAIL;
+        }
+
+        /* go to the next mtp_route */
+        mtp_route = mtp_route->next;
+    }
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_parse_mtp_route(ftdm_conf_node_t *mtp_route)
+{
+    sng_mtp3Route_t         mtp3_route;
+    ftdm_conf_parameter_t   *parm = mtp_route->parameters;
+    int                     num_parms = mtp_route->n_parameters;
+    int                     i;
+
+    memset(&mtp3_route, 0x0, sizeof(sng_mtp3Route_t));
+
+    /* confirm that we are looking at an mtp_link */
+    if (strcasecmp(mtp_route->name, "mtp_route")) {
+        SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_route\"!\n",mtp_route->name);
+        return FTDM_FAIL;
+    } else {
+        SS7_DEBUG("Parsing \"mtp_route\"...\n");
+    }
+
+    for (i = 0; i < num_parms; i++) {
+        /* try to match the parameter to what we expect */
+        /**********************************************************************/
+        if (!strcasecmp(parm->var, "name")) {
+            strcpy((char *)mtp3_route.name, parm->val);
+            SS7_DEBUG("\tFound an \"mtp_route\" named = %s\n", mtp3_route.name);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "dpc")) {
+            mtp3_route.dpc = atoi(parm->val);
+            SS7_DEBUG("\tFound mtp3_route->dpc = %d\n", mtp3_route.dpc);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "mtp_linkset")) {
+            /* find the linkset by it's name */
+            int x = 1;
+            while (g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].id != 0) {
+                /* check if the name matches */
+                if (!strcasecmp((char *)g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].name, parm->val)) {
+                    /* grab the mtp3_link id value first*/
+                    int id = g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].links[0];
+                    /* now, harvest the required infomormation from the global structure */
+                    mtp3_route.linkType     = g_ftdm_sngss7_data.cfg.mtp3Link[id].linkType;
+                    mtp3_route.switchType   = g_ftdm_sngss7_data.cfg.mtp3Link[id].switchType;
+                    mtp3_route.ssf          = g_ftdm_sngss7_data.cfg.mtp3Link[id].ssf;
+                    mtp3_route.cmbLinkSetId = g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].id;
+                    break;
+                }
+                x++;
+            }
+
+            /* check why we exited the wile loop ... and react accordingly */
+            if (mtp3_route.cmbLinkSetId == 0) {
+                SS7_ERROR("\tFailed to find the linkset = \"%s\"!\n", parm->val);
+                return FTDM_FAIL;
+            } else {
+                SS7_DEBUG("\tFound mtp3_route->linkset = %s\n", parm->val);
+            }
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "isSTP")) {
+            if (!strcasecmp(parm->val, "no")) {
+                mtp3_route.isSTP = 0;
+                SS7_DEBUG("\tFound mtp3_route->isSTP = no\n");
+            } else if (!strcasecmp(parm->val, "yes")) {
+                mtp3_route.isSTP = 1;
+                SS7_DEBUG("\tFound mtp3_route->isSTP = yes\n");
+            } else {
+                SS7_ERROR("\tFound an invalid parameter for isSTP \"%s\"!\n", parm->val);
+               return FTDM_FAIL;
+            }
+        /**********************************************************************/
+        } else {
+            SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val);
+            return FTDM_FAIL;
+
+        }
+
+        /* move to the next parameter */
+        parm = parm + 1;
+    }
+
+    ftmod_ss7_fill_in_mtp3_route(&mtp3_route);
+
+    ftmod_ss7_fill_in_mtp3_isup_interface(&mtp3_route);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_parse_isup_interfaces(ftdm_conf_node_t *isup_interfaces)
+{
+    ftdm_conf_node_t    *isup_interface = NULL;
+
+    /* confirm that we are looking at isup_interfaces */
+    if (strcasecmp(isup_interfaces->name, "isup_interfaces")) {
+        SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"isup_interfaces\"!\n",isup_interfaces->name);
+        return FTDM_FAIL;
+    } else {
+        SS7_DEBUG("Parsing \"isup_interfaces\"...\n");
+    }
+
+    /* extract the isup_interfaces */
+    isup_interface = isup_interfaces->child;
+
+    while (isup_interface != NULL) {
+        /* parse the found mtp_route */
+        if (ftmod_ss7_parse_isup_interface(isup_interface)) {
+            SS7_ERROR("Failed to parse \"isup_interface\"\n");
+            return FTDM_FAIL;
+        }
+
+        /* go to the next mtp_route */
+        isup_interface = isup_interface->next;
+    }
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface)
+{
+    sng_isupInterface_t     sng_isup;
+    sng_isup_cc_t           sng_cc;
+    ftdm_conf_parameter_t   *parm = isup_interface->parameters;
+    int                     num_parms = isup_interface->n_parameters;
+    int                     i;
+
+    memset(&sng_isup, 0x0, sizeof(sng_isupInterface_t));
+    memset(&sng_cc, 0x0, sizeof(sng_isup_cc_t));
+
+    /* confirm that we are looking at an mtp_link */
+    if (strcasecmp(isup_interface->name, "isup_interface")) {
+        SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"isup_interface\"!\n",isup_interface->name);
+        return FTDM_FAIL;
+    } else {
+        SS7_DEBUG("Parsing \"isup_interface\"...\n");
+    }
+
+
+    for (i = 0; i < num_parms; i++) {
+        /* try to match the parameter to what we expect */
+        /**********************************************************************/
+        if (!strcasecmp(parm->var, "name")) {
+            strcpy((char *)sng_isup.name, parm->val);
+            SS7_DEBUG("\tFound an \"isup_interface\" named = %s\n", sng_isup.name);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "spc")) {
+            g_ftdm_sngss7_data.cfg.spc = atoi(parm->val);
+            SS7_DEBUG("\tFound SPC = %d\n", g_ftdm_sngss7_data.cfg.spc);
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "mtp_route")) {
+            /* find the route by it's name */
+            int x = 1;
+            while (g_ftdm_sngss7_data.cfg.mtp3Route[x].id != 0) {
+                /* check if the name matches */
+                if (!strcasecmp((char *)g_ftdm_sngss7_data.cfg.mtp3Route[x].name, parm->val)) {
+                    /* now, harvest the required information from the global structure */
+                    sng_isup.mtp3RouteId    = g_ftdm_sngss7_data.cfg.mtp3Route[x].id;
+                    sng_isup.dpc            = g_ftdm_sngss7_data.cfg.mtp3Route[x].dpc;
+                    sng_isup.switchType     = g_ftdm_sngss7_data.cfg.mtp3Route[x].switchType;
+                    sng_cc.switchType       = g_ftdm_sngss7_data.cfg.mtp3Route[x].switchType;
+
+                    /* find the nwID from the mtp3_isup_interface */
+                    int y = 1;
+                    while (g_ftdm_sngss7_data.cfg.mtp3_isup[y].id != 0) {
+                        if (g_ftdm_sngss7_data.cfg.mtp3_isup[y].linkType == g_ftdm_sngss7_data.cfg.mtp3Route[x].linkType &&
+                            g_ftdm_sngss7_data.cfg.mtp3_isup[y].switchType == g_ftdm_sngss7_data.cfg.mtp3Route[x].switchType &&
+                            g_ftdm_sngss7_data.cfg.mtp3_isup[y].ssf == g_ftdm_sngss7_data.cfg.mtp3Route[x].ssf) {
+
+                            /* we have a match so break out of this loop */
+                            break;
+                        }
+                        /* move on to the next one */
+                        y++;
+                    } /* while (g_ftdm_sngss7_data.cfg.mtp3_isup[y].id != 0) */
+
+                    /* check how we exited the last while loop */
+                    if (g_ftdm_sngss7_data.cfg.mtp3_isup[y].id == 0) {
+                        SS7_ERROR("\tFailed to find the nwID for = \"%s\"!\n", parm->val);
+                        return FTDM_FAIL;
+                    } else {
+                        sng_isup.nwId = g_ftdm_sngss7_data.cfg.mtp3_isup[y].nwId;
+                    }
+
+                    break;
+                }
+                x++;
+            } /* while (g_ftdm_sngss7_data.cfg.mtp3Route[x].id != 0) */
+
+            /* check why we exited the while loop ... and react accordingly */
+            if (sng_isup.mtp3RouteId == 0) {
+                SS7_ERROR("\tFailed to find the MTP3 Route = \"%s\"!\n", parm->val);
+                return FTDM_FAIL;
+            } else {
+                SS7_DEBUG("\tFound MTP3 Route = %s\n", parm->val);
+            }
+        /**********************************************************************/
+        } else if (!strcasecmp(parm->var, "ssf")) {
+            if (!strcasecmp(parm->val, "nat")) {
+                sng_isup.ssf = SNG_SSF_NAT;
+                sng_cc.ssf   = SNG_SSF_NAT;
+            } else if (!strcasecmp(parm->val, "int")) {
+                sng_isup.ssf = SNG_SSF_INTER;
+                sng_cc.ssf      = SNG_SSF_INTER;
+            } else {
+                SS7_ERROR("\tFound an invalid ssf of \"%s\"!\n", parm->val);
+                return FTDM_FAIL;
+            }
+        /**********************************************************************/
+        } else {
+            SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val);
+            return FTDM_FAIL;
+
+        }
+
+        /* move to the next parameter */
+        parm = parm + 1;
+    }
+
+    ftmod_ss7_fill_in_isup_interface(&sng_isup);
+
+    ftmod_ss7_fill_in_isup_cc_interface(&sng_cc);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_mtp1_link(sng_mtp1Link_t *mtp1_link)
+{
+    int i;
+
+    /* go through all the existing links and see if we find a match */
+    i = 1;
+    while (g_ftdm_sngss7_data.cfg.mtp1Link[i].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.mtp1Link[i].span == mtp1_link->span &&
+            g_ftdm_sngss7_data.cfg.mtp1Link[i].chan == mtp1_link->chan) {
+
+            /* we have a match so break out of this loop */
+            break;
+        }
+        /* move on to the next one */
+        i++;
+    }
+
+    /* if the id value is 0 that means we didn't find the link */
+    if (g_ftdm_sngss7_data.cfg.mtp1Link[i].id  == 0) {
+        mtp1_link->id = i;
+        SS7_DEBUG("found new mtp1_link on span=%d, chan=%d, id = %d\n", 
+                    mtp1_link->span, 
+                    mtp1_link->chan, 
+                    mtp1_link->id);
+    } else {
+        mtp1_link->id = i;
+        SS7_DEBUG("found existing mtp1_link on span=%d, chan=%d, id = %d\n", 
+                    mtp1_link->span, 
+                    mtp1_link->chan, 
+                    mtp1_link->id);
+    }
+
+    /* fill in the information */
+
+    strcpy((char *)g_ftdm_sngss7_data.cfg.mtp1Link[i].name, (char *)mtp1_link->name);
+
+    g_ftdm_sngss7_data.cfg.mtp1Link[i].id = mtp1_link->id;
+    g_ftdm_sngss7_data.cfg.mtp1Link[i].span = mtp1_link->span;
+    g_ftdm_sngss7_data.cfg.mtp1Link[i].chan = mtp1_link->chan;
+
+    return (mtp1_link->id);
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_mtp2_link(sng_mtp2Link_t *mtp2_link)
+{
+    /* the mtp2link->spId is also the index value */
+
+    int i = mtp2_link->spId;
+
+    mtp2_link->id = i;
+
+    if (g_ftdm_sngss7_data.cfg.mtp2Link[i].id == 0) {
+        SS7_DEBUG("found new mtp2_link, id is = %d\n", mtp2_link->id);
+    } else {
+        SS7_DEBUG("found existing mtp2_link, id is = %d\n", mtp2_link->id);
+    } 
+
+    strcpy((char *)g_ftdm_sngss7_data.cfg.mtp2Link[i].name, (char *)mtp2_link->name);
+
+    g_ftdm_sngss7_data.cfg.mtp2Link[i].id           = mtp2_link->id;
+    g_ftdm_sngss7_data.cfg.mtp2Link[i].spId         = mtp2_link->spId;
+    g_ftdm_sngss7_data.cfg.mtp2Link[i].linkType     = mtp2_link->linkType;
+    g_ftdm_sngss7_data.cfg.mtp2Link[i].errorType    = mtp2_link->errorType;
+    g_ftdm_sngss7_data.cfg.mtp2Link[i].lssuLength   = mtp2_link->lssuLength;
+
+    if ( mtp2_link->t1 != 0 ) {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t1       = mtp2_link->t1;
+    }else {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t1       = 500;
+    }
+    if ( mtp2_link->t2 != 0 ) {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t2       = mtp2_link->t2;
+    }else {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t2       = 250;
+    }
+    if ( mtp2_link->t3 != 0 ) {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t3       = mtp2_link->t3;
+    }else {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t3       = 20;
+    }
+    if ( mtp2_link->t4n != 0 ) {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t4n      = mtp2_link->t4n;
+    }else {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t4n      = 80;
+    }
+    if ( mtp2_link->t4e != 0 ) {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t4e      = mtp2_link->t4e;
+    }else {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t4e      = 5;
+    }
+    if ( mtp2_link->t5 != 0 ) {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t5       = mtp2_link->t5;
+    }else {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t5       = 1;
+    }
+    if ( mtp2_link->t6 != 0 ) {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t6       = mtp2_link->t6;
+    }else {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t6       = 60;
+    }
+    if ( mtp2_link->t7 != 0 ) {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t7       = mtp2_link->t7;
+    }else {
+        g_ftdm_sngss7_data.cfg.mtp2Link[i].t7       = 20;
+    }
+
+    return(mtp2_link->id);
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_mtp3_link(sng_mtp3Link_t *mtp3_link)
+{
+    int i = mtp3_link->mtp2LinkId;
+
+    mtp3_link->id = i;
+
+    if (g_ftdm_sngss7_data.cfg.mtp3Link[i].id == 0) {
+        SS7_DEBUG("found new mtp3_link, id is = %d\n", mtp3_link->id);
+    } else {
+        SS7_DEBUG("found existing mtp3_link, id is = %d\n", mtp3_link->id);
+    }
+
+    strcpy((char *)g_ftdm_sngss7_data.cfg.mtp3Link[i].name, (char *)mtp3_link->name);
+
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].id           = mtp3_link->id;
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].mtp2LinkId   = mtp3_link->mtp2LinkId;
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].linkSetId    = mtp3_link->linkSetId;
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].priority     = mtp3_link->priority;
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].linkType     = mtp3_link->linkType;
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].switchType   = mtp3_link->switchType;
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].apc          = mtp3_link->apc;
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].ssf          = mtp3_link->ssf;
+    g_ftdm_sngss7_data.cfg.mtp3Link[i].lnkTstSLC    = mtp3_link->lnkTstSLC;
+    if (mtp3_link->t1 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t1       = mtp3_link->t1;
+    } else { 
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t1       = 8;
+    }
+    if (mtp3_link->t2 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t2       = mtp3_link->t2;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t2       = 14;
+    }
+    if (mtp3_link->t3 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t3       = mtp3_link->t3;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t3       = 8;
+    }
+    if (mtp3_link->t4 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t4       = mtp3_link->t4;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t4       = 8;
+    }
+    if (mtp3_link->t5 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t5       = mtp3_link->t5;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t5       = 8;
+    }
+    if (mtp3_link->t7 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t7       = mtp3_link->t7;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t7       = 15;
+    }
+    if (mtp3_link->t12 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t12      = mtp3_link->t12;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t12      = 15;
+    }
+    if (mtp3_link->t13 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t13      = mtp3_link->t13;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t13      = 15;
+    }
+    if (mtp3_link->t14 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t14      = mtp3_link->t14;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t14      = 30;
+    }
+    if (mtp3_link->t17 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t17      = mtp3_link->t17;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t17      = 15;
+    }
+    if (mtp3_link->t22 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t22      = mtp3_link->t22;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t22      = 1800;
+    }
+    if (mtp3_link->t23 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t23      = mtp3_link->t23;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t23      = 1800;
+    }
+    if (mtp3_link->t24 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t24      = mtp3_link->t24;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t24      = 5;
+    }
+    if (mtp3_link->t31 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t31       = mtp3_link->t31;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t31      = 50;
+    }
+    if (mtp3_link->t32 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t32      = mtp3_link->t32;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t32      = 120;
+    }
+    if (mtp3_link->t33 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t33       = mtp3_link->t33;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t33      = 3000;
+    }
+    if (mtp3_link->t34 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t34       = mtp3_link->t34;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].t34      = 600;
+    }
+    if (mtp3_link->tflc != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].tflc       = mtp3_link->tflc;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Link[i].tflc     = 300;
+    }
+
+    return(mtp3_link->id);
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_mtp3_linkset(sng_mtp3LinkSet_t *mtp3_linkset)
+{
+    int count;
+    int i = mtp3_linkset->id;
+
+    strcpy((char *)g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].name, (char *)mtp3_linkset->name);
+
+    g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].id          = mtp3_linkset->id;
+    g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].apc         = mtp3_linkset->apc;
+    g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].minActive   = mtp3_linkset->minActive;
+    g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].numLinks    = mtp3_linkset->numLinks;
+
+    for (count = 0; count < mtp3_linkset->numLinks; count++) {
+        g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].links[count]    = mtp3_linkset->links[count];
+    }
+
+    return 0;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_mtp3_route(sng_mtp3Route_t *mtp3_route)
+{
+    int i;
+
+    /* go through all the existing routes and see if we find a match */
+    i = 1;
+    while (g_ftdm_sngss7_data.cfg.mtp3Route[i].id != 0) {
+            if (g_ftdm_sngss7_data.cfg.mtp3Route[i].dpc == mtp3_route->dpc) {
+
+            /* we have a match so break out of this loop */
+            break;
+        }
+        /* move on to the next one */
+        i++;
+    }
+
+    if (g_ftdm_sngss7_data.cfg.mtp3Route[i].id == 0) {
+        mtp3_route->id = i;
+        SS7_DEBUG("found new mtp3_route, id is = %d\n", mtp3_route->id);
+    } else {
+        mtp3_route->id = i;
+        SS7_DEBUG("found existing mtp3_route, id is = %d\n", mtp3_route->id);
+    }
+
+    strcpy((char *)g_ftdm_sngss7_data.cfg.mtp3Route[i].name, (char *)mtp3_route->name);
+
+    g_ftdm_sngss7_data.cfg.mtp3Route[i].id            = mtp3_route->id;
+    g_ftdm_sngss7_data.cfg.mtp3Route[i].dpc           = mtp3_route->dpc;
+    g_ftdm_sngss7_data.cfg.mtp3Route[i].linkType      = mtp3_route->linkType;
+    g_ftdm_sngss7_data.cfg.mtp3Route[i].switchType    = mtp3_route->switchType;
+    g_ftdm_sngss7_data.cfg.mtp3Route[i].cmbLinkSetId  = 1; /* mtp3_route->cmbLinkSetId;*/
+    g_ftdm_sngss7_data.cfg.mtp3Route[i].isSTP         = mtp3_route->isSTP;
+    g_ftdm_sngss7_data.cfg.mtp3Route[i].ssf           = mtp3_route->ssf;
+    if (mtp3_route->t6 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t6        = mtp3_route->t6;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t6        = 8;
+    }
+    if (mtp3_route->t8 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t8        = mtp3_route->t8;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t8        = 12;
+    }
+    if (mtp3_route->t10 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t10        = mtp3_route->t10;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t10       = 300;
+    }
+    if (mtp3_route->t11 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t11        = mtp3_route->t11;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t11       = 300;
+    }
+    if (mtp3_route->t15 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t15        = mtp3_route->t15;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t15       = 30;
+    }
+    if (mtp3_route->t16 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t16        = mtp3_route->t16;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t16       = 20;
+    }
+    if (mtp3_route->t18 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t18        = mtp3_route->t18;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t18       = 200;
+    }
+    if (mtp3_route->t19 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t19        = mtp3_route->t19;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t19       = 690;
+    }
+    if (mtp3_route->t21 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t21        = mtp3_route->t21;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t21       = 650; 
+    }
+    if (mtp3_route->t25 != 0) {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t25        = mtp3_route->t25;
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3Route[i].t25       = 100;
+    }
+
+    return 0;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_mtp3_isup_interface(sng_mtp3Route_t *mtp3_route)
+{
+
+    int i;
+
+    /* go through all the existing interfaces and see if we find a match */
+    i = 1;
+    while (g_ftdm_sngss7_data.cfg.mtp3_isup[i].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.mtp3_isup[i].linkType == mtp3_route->linkType &&
+            g_ftdm_sngss7_data.cfg.mtp3_isup[i].switchType == mtp3_route->switchType &&
+            g_ftdm_sngss7_data.cfg.mtp3_isup[i].ssf == mtp3_route->ssf) {
+
+            /* we have a match so break out of this loop */
+            break;
+        }
+        /* move on to the next one */
+        i++;
+    }
+
+    if (g_ftdm_sngss7_data.cfg.mtp3_isup[i].id == 0) {
+        g_ftdm_sngss7_data.cfg.mtp3_isup[i].id = i;
+        SS7_DEBUG("found new mtp3_isup interface, id is = %d\n", g_ftdm_sngss7_data.cfg.mtp3_isup[i].id);
+    } else {
+        g_ftdm_sngss7_data.cfg.mtp3_isup[i].id = i;
+        SS7_DEBUG("found existing mtp3_isup interface, id is = %d\n", g_ftdm_sngss7_data.cfg.mtp3_isup[i].id);
+    }
+
+    g_ftdm_sngss7_data.cfg.mtp3_isup[i].nwId          = g_ftdm_sngss7_data.cfg.mtp3_isup[i].id;
+    g_ftdm_sngss7_data.cfg.mtp3_isup[i].linkType      = mtp3_route->linkType;
+    g_ftdm_sngss7_data.cfg.mtp3_isup[i].switchType    = mtp3_route->switchType;
+    g_ftdm_sngss7_data.cfg.mtp3_isup[i].ssf           = mtp3_route->ssf;
+
+    return 0;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_isup_interface(sng_isupInterface_t *sng_isup)
+{
+
+    int i;
+
+    /* go through all the existing interfaces and see if we find a match */
+    i = 1;
+    while (g_ftdm_sngss7_data.cfg.isupInterface[i].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isupInterface[i].nwId == sng_isup->nwId) {
+
+            /* we have a match so break out of this loop */
+            break;
+        }
+        /* move on to the next one */
+        i++;
+    }
+
+    if (g_ftdm_sngss7_data.cfg.isupInterface[i].id == 0) {
+        sng_isup->id = i;
+        SS7_DEBUG("found new isup interface, id is = %d\n", sng_isup->id);
+    } else {
+        sng_isup->id = i;
+        SS7_DEBUG("found existing isup interface, id is = %d\n", sng_isup->id);
+    }
+
+    strcpy((char *)g_ftdm_sngss7_data.cfg.isupInterface[i].name, (char *)sng_isup->name);
+
+    g_ftdm_sngss7_data.cfg.isupInterface[i].id             = sng_isup->id;
+    g_ftdm_sngss7_data.cfg.isupInterface[i].mtp3RouteId    = sng_isup->mtp3RouteId;
+    g_ftdm_sngss7_data.cfg.isupInterface[i].nwId           = sng_isup->nwId;
+    g_ftdm_sngss7_data.cfg.isupInterface[i].dpc            = sng_isup->dpc;
+    g_ftdm_sngss7_data.cfg.isupInterface[i].switchType     = sng_isup->switchType;
+    g_ftdm_sngss7_data.cfg.isupInterface[i].ssf            = sng_isup->ssf;
+    if (sng_isup->t4 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t4         = sng_isup->t4;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t4         = 3000;
+    }
+    if (sng_isup->t10 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t10        = sng_isup->t10;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t10        = 50;
+    }
+    if (sng_isup->t11 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t11        = sng_isup->t11;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t11        = 170;
+    }
+    if (sng_isup->t18 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t18        = sng_isup->t18;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t18        = 300;
+    }
+    if (sng_isup->t19 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t19        = sng_isup->t19;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t19        = 3000;
+    }
+    if (sng_isup->t20 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t20        = sng_isup->t20;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t20        = 300;
+    }
+    if (sng_isup->t21 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t21        = sng_isup->t21;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t21        = 3000;
+    }
+    if (sng_isup->t22 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t22        = sng_isup->t22;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t22        = 300;
+    }
+    if (sng_isup->t23 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t23        = sng_isup->t23;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t23        = 3000;
+    }
+    if (sng_isup->t24 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t24        = sng_isup->t24;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t24        = 10;
+    }
+    if (sng_isup->t25 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t25        = sng_isup->t25;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t25        = 20;
+    }
+    if (sng_isup->t26 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t26        = sng_isup->t26;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t26        = 600;
+    }
+    if (sng_isup->t28 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t28        = sng_isup->t28;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t28        = 100;
+    }
+    if (sng_isup->t29 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t29        = sng_isup->t29;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t29        = 6;
+    }
+    if (sng_isup->t30 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t30        = sng_isup->t30;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t30        = 50;
+    }
+    if (sng_isup->t32 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t32        = sng_isup->t32;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t32        = 30;
+    }
+    if (sng_isup->t35 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t35        = sng_isup->t35;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t35        = 170;
+    }
+    if (sng_isup->t37 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t37        = sng_isup->t37;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t37        = 20;
+    }
+    if (sng_isup->t38 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t38        = sng_isup->t38;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t38        = 1200;
+    }
+    if (sng_isup->t39 != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t39        = sng_isup->t39;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].t39        = 300;
+    }
+    if (sng_isup->tfgr != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].tfgr       = sng_isup->tfgr;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].tfgr       = 50;
+    }
+    if (sng_isup->tpause != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].tpause     = sng_isup->tpause;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].tpause     = 150;
+    }
+    if (sng_isup->tstaenq != 0) {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].tstaenq    = sng_isup->tstaenq;
+    } else {
+        g_ftdm_sngss7_data.cfg.isupInterface[i].tstaenq    = 5000;
+    }
+
+    return 0;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_isup_cc_interface(sng_isup_cc_t *sng_cc)
+{
+
+    int i;
+
+    /* go through all the existing interfaces and see if we find a match */
+    i = 1;
+    while (g_ftdm_sngss7_data.cfg.isup_cc[i].id != 0) {
+        if (g_ftdm_sngss7_data.cfg.isup_cc[i].switchType == sng_cc->switchType) {
+
+            /* we have a match so break out of this loop */
+            break;
+        }
+        /* move on to the next one */
+        i++;
+    }
+
+    if (g_ftdm_sngss7_data.cfg.isup_cc[i].id == 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].id = i;
+        SS7_DEBUG("found new isup to cc interface, id is = %d\n", g_ftdm_sngss7_data.cfg.isup_cc[i].id);
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].id = i;
+        SS7_DEBUG("found existing isup to cc interface, id is = %d\n", g_ftdm_sngss7_data.cfg.isup_cc[i].id);
+    }
+
+    SS7_ERROR("KONRAD -> you're hard coding the CC id....fix me!!!!\n");
+    g_ftdm_sngss7_data.cfg.isup_cc[i].ccId          = 1; /*KONRAD FIX ME */
+    g_ftdm_sngss7_data.cfg.isup_cc[i].switchType    = sng_cc->switchType;
+    g_ftdm_sngss7_data.cfg.isup_cc[i].ssf           = sng_cc->ssf;
+    if (sng_cc->t1 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t1        = sng_cc->t1;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t1        = 200;
+    }
+    if (sng_cc->t2 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t2        = sng_cc->t2;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t2        = 1800;
+    }
+    if (sng_cc->t5 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t5        = sng_cc->t5;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t5        = 3000;
+    }
+    if (sng_cc->t6 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t6        = sng_cc->t6;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t6        = 200;
+    }
+    if (sng_cc->t7 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t7        = sng_cc->t7;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t7        = 250;
+    }
+    if (sng_cc->t8 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t8        = sng_cc->t8;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t8        = 120;
+    }
+    if (sng_cc->t9 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t9        = sng_cc->t9;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t9        = 1800;
+    }
+    if (sng_cc->t27 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t27       = sng_cc->t27;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t27       = 2400;
+    }
+    if (sng_cc->t31 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t31       = sng_cc->t31;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t31       = 3650;
+    }
+    if (sng_cc->t33 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t33       = sng_cc->t33;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t33       = 120;
+    }
+    if (sng_cc->t34 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t34       = sng_cc->t34;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t34       = 40;
+    }
+    if (sng_cc->t36 != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t36       = sng_cc->t36;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].t36       = 120;
+    }
+    if (sng_cc->tccr != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tccr      = sng_cc->tccr;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tccr      = 200;
+    }
+    if (sng_cc->tccrt != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tccrt     = sng_cc->tccrt;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tccrt     = 20;
+    }
+    if (sng_cc->tex != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tex       = sng_cc->tex;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tex       = 10;
+    }
+    if (sng_cc->tcrm != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tcrm      = sng_cc->tcrm;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tcrm      = 30;
+    }
+    if (sng_cc->tcra != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tcra      = sng_cc->tcra;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tcra      = 100;
+    }
+    if (sng_cc->tect != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tect      = sng_cc->tect;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tect      = 10;
+    }
+    if (sng_cc->trelrsp != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].trelrsp   = sng_cc->trelrsp;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].trelrsp   = 10;
+    }
+    if (sng_cc->tfnlrelrsp != 0) {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tfnlrelrsp= sng_cc->tfnlrelrsp;
+    } else {
+        g_ftdm_sngss7_data.cfg.isup_cc[i].tfnlrelrsp= 10;
+    }
+
+    return 0;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, int ssf)
+{
+
+    if (g_ftdm_sngss7_data.cfg.mtp3Route[0].dpc == 0){
+        SS7_DEBUG("found new mtp3 self route\n");
+    } else if (g_ftdm_sngss7_data.cfg.mtp3Route[0].dpc == spc) {
+        SS7_DEBUG("found existing mtp3 self route\n");
+        return FTDM_SUCCESS;
+    } else {
+        SS7_ERROR("found new mtp3 self route but it does not much the route already configured\n");
+        return FTDM_FAIL;
+    }
+
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].id            = 0;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].dpc           = spc;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].linkType      = linkType;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].switchType    = switchType;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].cmbLinkSetId  = 0;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].isSTP         = 0;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].ssf           = 0;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t6        = 8;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t8        = 12;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t10       = 300;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t11       = 300;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t15       = 30;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t16       = 20;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t18       = 200;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t19       = 690;
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t21       = 650; 
+    g_ftdm_sngss7_data.cfg.mtp3Route[0].t25        = 100;
+
+
+    return 0;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, int isup_id, ftdm_span_t *span)
+{
+    sngss7_chan_data_t  *ss7_info = NULL;
+    ftdm_channel_t      *ftdmchan = NULL;
+    sng_timeslot_t      timeslot;
+    int                 count;
+    int                 i;
+    int                 x;
+
+    count = 1;
+
+    while (ch_map[0] != '\0') {
+
+         /* pull out the next timeslot */
+        if (ftmod_ss7_next_timeslot(ch_map, &timeslot)) {
+            SS7_ERROR("Failed to parse the channel map!\n");
+            return FTDM_FAIL;
+        }
+
+        if ((timeslot.siglink) || (timeslot.gap)) {
+            /* try to find the channel in the circuits structure*/
+            x = 1;
+            while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+                if ((g_ftdm_sngss7_data.cfg.isupCircuit[x].chan == count) &&
+                    (g_ftdm_sngss7_data.cfg.isupCircuit[x].span == span->channels[1]->physical_span_id)) {
+
+                    SS7_DEVEL_DEBUG("Circuit for span=%d, chan=%d is already exists...id=%d\n",
+                                span->channels[1]->physical_span_id,
+                                count,
+                                x);
+
+                    /* we have a match so this circuit already exists in the structure */
+                    break;
+                }
+                /* move to the next circuit */
+                x++;
+            } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) */
+
+                       /* check why we exited the while loop */
+            if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) {
+                SS7_DEVEL_DEBUG("Circuit for span=%d, chan=%d is new...id=%d\n",
+                span->channels[1]->physical_span_id,
+                count,
+                x);
+
+                /* prepare the global info sturcture */
+                ss7_info = ftdm_calloc(1, sizeof(sngss7_chan_data_t));
+                ss7_info->ftdmchan = NULL;
+                ss7_info->circuit = &g_ftdm_sngss7_data.cfg.isupCircuit[x];
+
+                /* circuit is new so fill in the needed information */
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].id          = x;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].span        = span->channels[1]->physical_span_id;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].chan        = count;
+                if (timeslot.siglink) {
+                    g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink     = 1;
+                } else {
+                    g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink     = 0;
+                }
+                if (timeslot.channel) {
+                    g_ftdm_sngss7_data.cfg.isupCircuit[x].hole        = 0;
+                    g_ftdm_sngss7_data.cfg.isupCircuit[x].cic         = cicbase;
+                    cicbase++;
+                } else {
+                    g_ftdm_sngss7_data.cfg.isupCircuit[x].hole        = 1;
+                    g_ftdm_sngss7_data.cfg.isupCircuit[x].cic         = 0;
+                }
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].infId       = isup_id;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].typeCntrl   = typeCntrl;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t3          = 1200;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t12         = 300;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t13         = 3000;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t14         = 300;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t15         = 3000;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t16         = 300;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t17         = 3000;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].tval        = 10;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].obj         = ss7_info;
+
+            } /* if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) */
+        } else { /* if ((timeslot.siglink) || (timeslot.gap)) */
+            /* find the ftdm the channel structure for this channel*/
+            i = 1;
+            while (span->channels[i] != NULL) {
+                if (span->channels[i]->physical_chan_id == timeslot.channel) {
+                    break;
+                }
+                i++;
+            } /* while (span->channels[i] != NULL) */
+
+            if (span->channels[i] == NULL) {
+                /* we weren't able to find the channel in the ftdm channels */
+                SS7_ERROR("Unable to find the requested channel %d in the FreeTDM channels!\n", timeslot.channel);
+                return FTDM_FAIL;
+            } else {
+                ftdmchan = span->channels[i];
+            }
+
+            /* try to find a match for the physical span and chan */
+            x = 1;
+            while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) {
+                if ((g_ftdm_sngss7_data.cfg.isupCircuit[x].chan == ftdmchan->physical_chan_id) 
+                    && (g_ftdm_sngss7_data.cfg.isupCircuit[x].span == ftdmchan->physical_span_id)) {
+
+                    /* we have a match so this circuit already exists in the structure */
+                    break;
+                }
+                /* move to the next circuit */
+                x++;
+            } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) */
+
+            /* check why we exited the while loop */
+            if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) {
+                SS7_DEVEL_DEBUG("Circuit for span=%d, chan=%d is new...id=%d\n",
+                ftdmchan->physical_span_id,
+                ftdmchan->physical_chan_id,
+                x);
+
+                /* prepare the global info sturcture */
+                ss7_info = ftdm_calloc(1, sizeof(sngss7_chan_data_t));
+                ss7_info->ftdmchan = ftdmchan;
+                ss7_info->circuit = &g_ftdm_sngss7_data.cfg.isupCircuit[x];
+                ftdmchan->call_data = ss7_info;
+
+                /* prepare the timer structures */
+                ss7_info->t35.sched         = sngss7_sched;
+                ss7_info->t35.counter       = 1;
+                ss7_info->t35.beat          = g_ftdm_sngss7_data.cfg.isupInterface[isup_id].t35*100; /* beat is in ms, t35 is in 100ms */
+                ss7_info->t35.callback      = handle_isup_t35;
+                ss7_info->t35.sngss7_info   = ss7_info;
+
+                /* circuit is new so fill in the needed information */
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].id          = x;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].span        = ftdmchan->physical_span_id;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].chan        = ftdmchan->physical_chan_id;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink     = 0;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].hole        = 0;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].cic         = cicbase;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].infId       = isup_id;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].typeCntrl   = typeCntrl;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t3          = 1200;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t12         = 300;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t13         = 3000;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t14         = 300;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t15         = 3000;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t16         = 300;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].t17         = 3000;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].tval        = 10;
+                g_ftdm_sngss7_data.cfg.isupCircuit[x].obj         = ss7_info;
+
+                /* increment the cicbase */
+                cicbase++;
+            } else { /* if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) */
+                SS7_DEBUG("Circuit for span=%d, chan=%d is new...id=%d\n",
+                                    ftdmchan->physical_span_id,
+                                    ftdmchan->physical_chan_id,
+                                    x);
+
+                /* for now make sure ss7_info is set to null */
+                ss7_info = NULL;
+
+                /* KONRAD FIX ME -> confirm that it is the same circuit */
+            }  /* if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) */
+
+            /* increment the span channel count */
+            count++;
+        } /* if ((timeslot.siglink) || (timeslot.gap)) */
+
+        if (ss7_info == NULL) {
+            SS7_ERROR("KONRAD -> circuit was not configured !\n");
+            return FTDM_FAIL;
+        }
+
+        if (ss7_info->ftdmchan == NULL) {
+            SS7_INFO("Added span = %d, chan = %d, cic = %d, FTDM chan = %d, ISUP cirId = %d\n",
+                        g_ftdm_sngss7_data.cfg.isupCircuit[x].span,
+                        g_ftdm_sngss7_data.cfg.isupCircuit[x].chan,
+                        g_ftdm_sngss7_data.cfg.isupCircuit[x].cic,
+                        0,
+                        g_ftdm_sngss7_data.cfg.isupCircuit[x].id);
+        } else {
+            SS7_INFO("Added span = %d, chan = %d, cic = %d, FTDM chan = %d, ISUP cirId = %d\n",
+                        g_ftdm_sngss7_data.cfg.isupCircuit[x].span,
+                        g_ftdm_sngss7_data.cfg.isupCircuit[x].chan,
+                        g_ftdm_sngss7_data.cfg.isupCircuit[x].cic,
+                        ss7_info->ftdmchan->chan_id,
+                        g_ftdm_sngss7_data.cfg.isupCircuit[x].id);
+        }
+
+    } /* while (ch_map[0] != '\0') */
+
+    return 0;
+}
+
+/******************************************************************************/
+static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot)
+{
+    int             i;
+    int             x;
+    int             lower;
+    int             upper;
+    char            tmp[5]; /*KONRAD FIX ME*/
+    char            new_ch_map[MAX_CIC_LENGTH];
+
+    memset(&tmp[0], '\0', sizeof(tmp));
+    memset(&new_ch_map[0], '\0', sizeof(new_ch_map));
+    memset(timeslot, 0x0, sizeof(sng_timeslot_t));
+
+    SS7_DEVEL_DEBUG("Old channel map = \"%s\"\n", ch_map);
+
+    /* start at the beginning of the ch_map */
+    x = 0;
+
+    switch (ch_map[x]) {
+    /**************************************************************************/
+    case 'S':
+    case 's':   /* we have a sig link */
+        timeslot->siglink = 1;
+
+        /* check what comes next either a comma or a number */
+        x++;
+        if (ch_map[x] == ',') {
+            timeslot->hole = 1;
+            SS7_DEVEL_DEBUG(" Found a siglink in the channel map with a hole in the cic map\n");
+        } else if (isdigit(ch_map[x])) {
+            /* consume all digits until a comma as this is the channel */
+            SS7_DEVEL_DEBUG(" Found a siglink in the channel map with out a hole in the cic map\n");
+        } else {
+            SS7_ERROR("Found an illegal channel map character after signal link flag = \"%c\"!\n", ch_map[x]);
+            return FTDM_FAIL;
+        }
+        break;
+    /**************************************************************************/
+    case 'G':
+    case 'g':   /* we have a channel gap */
+        timeslot->gap = 1;
+
+        /* check what comes next either a comma or a number */
+        x++;
+        if (ch_map[x] == ',') {
+            timeslot->hole = 1;
+            SS7_DEVEL_DEBUG(" Found a gap in the channel map with a hole in the cic map\n");
+        } else if (isdigit(ch_map[x])) {
+            SS7_DEVEL_DEBUG(" Found a gap in the channel map with out a hole in the cic map\n");
+            /* consume all digits until a comma as this is the channel */
+        } else {
+            SS7_ERROR("Found an illegal channel map character after signal link flag = \"%c\"!\n", ch_map[x]);
+            return FTDM_FAIL;
+        }
+        break;
+    /**************************************************************************/
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':   /* we have a channel */
+        /* consume all digits until a comma or a dash */
+        SS7_DEVEL_DEBUG("Found a starting channel in the channel map\n");
+        break;
+    /**************************************************************************/
+    default:
+        SS7_ERROR("Found an illegal channel map character = \"%c\"!\n", ch_map[x]);
+        return FTDM_FAIL;
+    /**************************************************************************/
+    } /* switch (ch_map[x]) */
+
+    /* grab the first number in the string */
+    i = 0;
+    while ((ch_map[x] != '\0') && (ch_map[x] != '-') && (ch_map[x] != ',')) {
+        tmp[i] = ch_map[x];
+        i++;
+        x++;
+    }
+    tmp[i] = '\0';
+    timeslot->channel = atoi(tmp);
+    lower = timeslot->channel + 1;
+
+    /* check the next value in the list */
+    if (ch_map[x] == '-') {
+        /* consume the number after the dash */
+        x++;
+        i = 0;
+        while ((ch_map[x] != '\0') && (ch_map[x] != '-') && (ch_map[x] != ',')) {
+            tmp[i] = ch_map[x];
+            i++;
+            x++;
+        }
+        tmp[i] = '\0';
+        upper = atoi(tmp);
+
+        /* check if the upper end of the range is the same as the lower end of the range */
+        if (upper == lower) {
+            /* the range is completed, eat the next comma or \0  and write it */
+            sprintf(new_ch_map, "%d", lower);
+        } else if ( upper > lower) {
+            /* the list continues, add 1 from the channel map value and re-insert it to the list */
+            sprintf(new_ch_map, "%d-%d", lower, upper);
+        } else {
+            SS7_ERROR("The upper is less then the lower end of the range...should not happen!\n");
+            return FTDM_FAIL;
+        }
+
+        /* the the rest of ch_map to new_ch_map */
+        strncat(new_ch_map, &ch_map[x], strlen(&ch_map[x]));
+
+        /* set the new cic map to ch_map*/
+        strcpy(ch_map, new_ch_map);
+
+    } else if (ch_map[x] == ',') {
+        /* move past the comma */
+        x++;
+
+        /* copy the rest of the list to new_ch_map */
+        strcpy(new_ch_map, &ch_map[x]);
+
+        /* copy the new_ch_map over the old one */
+        strcpy(ch_map, new_ch_map);
+
+    } else if (ch_map[x] == '\0') {
+        /* we're at the end of the string...copy the rest of the list to new_ch_map */
+        strcpy(new_ch_map, &ch_map[x]);
+
+        /* set the new cic map to ch_map*/
+        strcpy(ch_map, new_ch_map);
+    } else { 
+        /* nothing to do */
+    }
+
+    SS7_DEVEL_DEBUG("New channel map = \"%s\"\n", ch_map);
+
+    return FTDM_SUCCESS;
+}
+
+/******************************************************************************/