]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Added sangoma_isdn
authorDavid Yat Sin <dyatsin@sangoma.com>
Wed, 30 Jun 2010 16:42:11 +0000 (12:42 -0400)
committerDavid Yat Sin <dyatsin@sangoma.com>
Wed, 30 Jun 2010 16:42:36 +0000 (12:42 -0400)
13 files changed:
libs/freetdm/Makefile.am
libs/freetdm/configure.ac
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_in.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c [new file with mode: 0644]
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h [new file with mode: 0644]

index c86d00203e9c99411505f2baaedb50774c646db4..1c878e6cb40a0b3c0319577f7f2fd7acc0ffa446 100644 (file)
@@ -257,6 +257,25 @@ ftmod_sangoma_ss7_la_LDFLAGS = -module  -avoid-version -lsng_ss7
 ftmod_sangoma_ss7_la_LIBADD  = $(MYLIB)
 endif
 
+if SNGISDN
+ftmod_sangoma_isdn_la_SOURCES = $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c \
+                               $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c \
+                               $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c \
+                               $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c \
+                               $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c \
+                               $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c \
+                               $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c \
+                               $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_in.c \
+                               $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
+
+
+ftmod_sangoma_isdn_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_sangoma_isdn_la_LDFLAGS = -module -avoid-version -lsng_isdn
+ftmod_sangoma_isdn_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)
@@ -264,7 +283,6 @@ ftmod_r2_la_LDFLAGS = -module  -avoid-version -lopenr2
 ftmod_r2_la_LIBADD  = $(MYLIB)
 endif
 
-
 dox doxygen:
        cd docs && doxygen $(FT_SRCDIR)/docs/Doxygen.conf
 
index cad37c3705e7e78d6d6cdac89d7d8563fcca0dd7..567be4458749692afd384868b0c809ee500e4d6f 100644 (file)
@@ -173,6 +173,9 @@ 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([sng_isdn], [sng_isdn_init], [have_sng_isdn="yes"])
+AM_CONDITIONAL([SNGISDN],[test "${have_sng_isdn}" = "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_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
new file mode 100644 (file)
index 0000000..1872d4a
--- /dev/null
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies 
+ * David Yat Sin <davidy@sangoma.com>
+ * Moises Silva <moy@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 "ftmod_sangoma_isdn.h"
+
+static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj);
+static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
+
+static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
+static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
+
+static ftdm_io_interface_t                     g_sngisdn_io_interface;
+static sng_isdn_event_interface_t              g_sngisdn_event_interface;
+
+ftdm_sngisdn_data_t                            g_sngisdn_data;
+
+extern ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt);
+
+ftdm_state_map_t sangoma_isdn_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_CHANNEL_STATE_UP, 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},
+       }
+       }
+};
+
+static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
+{
+       ftdm_interrupt_t        *ftdm_sangoma_isdn_int = NULL;
+       ftdm_span_t             *span   = (ftdm_span_t *) obj;
+       ftdm_channel_t  *ftdmchan = NULL;
+
+       ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn 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_sangoma_isdn_int) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "%s:Failed to get a ftdm_interrupt for span = %s!\n", span->name);
+               goto ftdm_sangoma_isdn_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_sangoma_isdn_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_sangoma_isdn_process_state_change(ftdmchan);
+                               } else {
+                                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "reported state change but state change flag not set\n");
+                               }
+                       }
+
+                       break;
+
+               case FTDM_TIMEOUT:
+                       /* twiddle */
+                       break;
+
+               case FTDM_FAIL:
+                       ftdm_log(FTDM_LOG_ERROR,"ftdm_interrupt_wait returned error!\non span = %s\n", span->name);
+                       break;
+
+               default:
+                       ftdm_log(FTDM_LOG_ERROR,"ftdm_interrupt_wait returned with unknown code on span = %s\n", span->name);
+                       break;
+
+               }
+
+       }
+
+       /* 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_isdn monitor thread for span %s stopping.\n", span->name);
+
+       return NULL;
+
+ftdm_sangoma_isdn_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_isdn monitor thread for span %s stopping due to error.\n", span->name);
+
+       return NULL;
+}
+
+/******************************************************************************/
+static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
+{
+       ftdm_sigmsg_t           sigev;
+       ftdm_signaling_status_t status;
+       sngisdn_chan_data_t *sngisdn_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);
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "processing state change to %s\n", ftdm_channel_state2str(ftdmchan->state));
+
+       switch (ftdmchan->state) {
+
+       case FTDM_CHANNEL_STATE_COLLECT:         /* SETUP received but wating on digits */
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "re-entering state from processing block/unblock request - do nothing\n");
+                               break;
+                       }
+
+                       /* TODO: Overlap receive not implemented yet - cannot do it the same way as PRI requires sending complete bit */
+
+                       /* Go straight to ring state for now */
+
+                       /*now go to the RING state*/
+            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+               }
+               break;
+       case FTDM_CHANNEL_STATE_RING: /* incoming call request */
+               {
+                       ftdm_log_chan(ftdmchan, FTDM_LOG_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 */
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "re-entering state from processing block/unblock request ... do nothing \n");
+                               break;
+                       }
+                       sngisdn_snd_setup(ftdmchan);
+               }
+               break;
+       case FTDM_CHANNEL_STATE_PROGRESS:
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_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);
+                       } else {
+                               sngisdn_snd_proceed(ftdmchan);
+                       }
+               }
+               break;
+
+       case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+               {
+                       if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+                               sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+                               ftdm_span_send_signal(ftdmchan->span, &sigev);
+                       } else {
+                               sngisdn_snd_progress(ftdmchan);
+                       }
+               }
+               break; 
+
+       case FTDM_CHANNEL_STATE_UP: /* call is answered */
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "re-entering state from processing block/unblock request ... do nothing \n");
+                               break;
+                       }
+
+                       if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+                               if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
+                                       ((sngisdn_span_data_t*)ftdmchan->span->signal_data)->signalling == SNGISDN_SIGNALING_NET) {
+                                       /* Assign the call to a specific equipment */
+                                       sngisdn_snd_con_complete(ftdmchan);
+                               }
+                       }
+
+                       /* 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 just answered ... tell the stack */
+                               sngisdn_snd_connect(ftdmchan);
+                       }
+               }
+               break;
+
+       case FTDM_CHANNEL_STATE_CANCEL:
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "re-entering state from processing block/unblock request ... do nothing \n");
+                               break;
+                       }
+
+                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call before informing user!\n");
+
+                       /* Send a release complete */
+                       sngisdn_snd_release(ftdmchan);
+                       /*now go to the HANGUP complete state*/                         
+                       ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+               }
+               break;
+
+       case FTDM_CHANNEL_STATE_TERMINATING: /* call is hung up by the remote end */
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "re-entering state from processing block/unblock request ... do nothing \n");
+                               break;
+                       }
+
+                       /* 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 */
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "re-entering state from processing block/unblock request ... do nothing \n");
+                               break;
+                       }
+
+                       if (ftdm_test_flag(sngisdn_info, FLAG_REMOTE_REL)) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Acknowledging remote hangup\n");
+                               sngisdn_snd_release(ftdmchan);
+                       } else if (ftdm_test_flag(sngisdn_info, FLAG_REMOTE_ABORT)) {
+                               /* Do not send any messages to remote switch as they aborted */
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Clearing local states from remote abort\n");
+                       } else {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call upon local request!\n");
+
+                                /* set the flag to indicate this hangup is started from the local side */
+                               ftdm_set_flag(sngisdn_info, FLAG_LOCAL_REL);
+
+                               /* If we never sent ack to incoming call, we need to send release instead of disconnect */
+                               if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING) {
+                                       ftdm_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
+                                       sngisdn_snd_release(ftdmchan);
+                               } else {
+                                       sngisdn_snd_disconnect(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:
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "re-entering state from processing block/unblock request ... do nothing \n");
+                               break;
+                       }
+
+                       if (ftdm_test_flag(sngisdn_info, FLAG_REMOTE_REL)) {                    
+                               if (sngisdn_test_flag(sngisdn_info, FLAG_RESET_TX)) {
+                                       /* go to RESTART State until RSCa is received */
+                                       ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                               }
+                               /* Do nothing as we will receive a RELEASE COMPLETE from remote switch */
+                       } else if (ftdm_test_flag(sngisdn_info, FLAG_REMOTE_ABORT) ||
+                                               ftdm_test_flag(sngisdn_info, FLAG_LOCAL_ABORT)) {
+                               /* If the remote side aborted, we will not get anymore message for this call */
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+                       } else {
+                               /* twiddle, waiting on remote confirmation before moving to down */
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Completing locally requested hangup\n");
+                       }
+               }
+               break;
+
+       case FTDM_CHANNEL_STATE_DOWN: /* the call is finished and removed */
+               {
+                       if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_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 (sngisdn_test_flag(sngisdn_info, FLAG_RESET_RX)) {
+                               /* send a RLC */
+                               sngisdn_snd_release(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 (sngisdn_test_flag(sngisdn_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 (sngisdn_test_flag(sngisdn_info, FLAG_GLARE)) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Glare flag is up....spoofing incoming call\n");
+                               /* clear all the call specific data */
+                               clear_call_data(sngisdn_info);
+
+                               /* 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 */
+                               sngisdn_rcv_con_ind(sngisdn_info->glare.suId,
+                                                                       sngisdn_info->glare.suInstId,
+                                                                       sngisdn_info->glare.spInstId,
+                                                                       &sngisdn_info->glare.setup,
+                                                                       sngisdn_info->glare.dChan,
+                                                                       sngisdn_info->glare.ces);
+
+                       } else {
+                               /* clear all of the call specific data store in the channel structure */
+                               clear_call_data(sngisdn_info);
+                       
+                               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:
+               {
+#if 0
+                       /* TODO: Go through channel restart call states. They do not make sense when running ISDN */
+                       
+                       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 (sngisdn_test_flag(sngisdn_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 (sngisdn_test_flag(sngisdn_info, FLAG_RESET_RX)) */
+                       } /* if (inuse) */
+
+                       /* check if this is an outgoing RSC */
+                       if (sngisdn_test_flag(sngisdn_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 */
+                                       sngisdn_snd_reset(ftdmchan);
+                               }
+               
+                               /* don't change to the DOWN state as we need to wait for the RSCa */
+                       } /* if (sngisdn_test_flag(sngisdn_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);
+#endif
+               }
+
+               break;
+       case FTDM_CHANNEL_STATE_SUSPENDED:
+               {
+                       if (sngisdn_test_flag(sngisdn_info, FLAG_INFID_PAUSED)) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "processing PAUSE\n");
+                               /* 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 (sngisdn_test_flag(sngisdn_info, FLAG_INFID_RESUME)) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "processing RESUME\n");
+                               
+                               /* we just resumed...throw the channel into reset */
+                               sngisdn_set_flag(sngisdn_info, FLAG_RESET_TX);
+
+                               /* clear the resume flag */
+                               sngisdn_clear_flag(sngisdn_info, FLAG_INFID_RESUME);
+
+                               /* go to restart state */
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                       }
+
+#if 0
+                       /* CHECK the equivalent for ISDN */
+                       if (sngisdn_test_flag(sngisdn_info, FLAG_CKT_MN_BLOCK_RX)) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "processing MN_BLOCK_RX\n");
+
+                               /* 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 (sngisdn_test_flag(sngisdn_info, FLAG_CKT_MN_UNBLK_RX)) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "processing MN_UNBLK_RX\n");
+                               /* 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 */
+                               sngisdn_clear_flag(sngisdn_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 (sngisdn_test_flag(sngisdn_info, FLAG_CKT_MN_BLOCK_TX)) {
+                               ftdm_log_chan_msg(ftdm_chan, FTDM_LOG_DEBUG, "processing MN_BLOCK_TX\n");
+                               /* 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 (sngisdn_test_flag(sngisdn_info, FLAG_CKT_MN_UNBLK_TX)) {
+                               ftdm_log_chan_msg(ftdm_chan, FTDM_LOG_DEBUG, "processing MN_UNBLOCK_TX\n");
+                               /* 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 */
+                               sngisdn_clear_flag(sngisdn_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);
+                       }
+#endif
+               }
+               break;
+       default:
+               {
+                       ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "unsngisdn_rcvd state %s\n", ftdm_channel_state2str(ftdmchan->state));
+               }
+               break;
+
+       }
+
+       ftdm_mutex_unlock(ftdmchan->mutex);
+       return;
+}
+
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_isdn_outgoing_call)
+{
+       sngisdn_chan_data_t  *sngisdn_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:
+               {
+                       ftdm_set_state(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 < 100) {
+
+                               /* lock the channel while we check whether it is availble */
+                               ftdm_mutex_lock(ftdmchan->mutex);
+
+                               /* extract the sngisdn_chan_data structure */
+                               sngisdn_info = (sngisdn_chan_data_t  *)ftdmchan->call_data;
+
+                               if (ftdm_test_flag(sngisdn_info, FLAG_GLARE)) {
+                                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Glare detected\n");
+                                       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:
+                                               {
+                                                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Outgoing call request successful\n");
+                                                       goto outgoing_successful;
+                                               }
+                                               break;
+                                       case FTDM_CHANNEL_STATE_TERMINATING:
+                                       case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+                                       case FTDM_CHANNEL_STATE_DOWN:
+                                               {
+                                                       /* Remote switch aborted this call */
+                                                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Outgoing call request failed\n");
+                                                       goto outgoing_successful;
+                                               }
+                                               break;
+                                       default:
+                                               {
+                                                       ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Channel in invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
+                                                       goto outgoing_glare;
+                                               }
+                                               break;
+                               }
+
+                               /* unlock the channel */
+                               ftdm_mutex_unlock(ftdmchan->mutex);
+
+                               /* sleep for a bit to let the state change */
+                               ftdm_sleep(10);
+
+                               /* increment the timeout counter */
+                               c++;
+                       }
+
+                       /* only way we can get here is if we are still in STATE_DIALING. We did not get a glare, so exit thread and wait for PROCEED/PROGRESS/ALERT/CONNECT or RELEASE from remote switch  */
+                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Timeout waiting for outgoing call to be accepted by network, returning success anyways\n");
+
+                       /* consider the call good .... for now */
+                       goto outgoing_successful;
+               }
+               break;
+
+       default:
+               {
+                       /* the channel is already used...this can't be, end the request */
+                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Outgoing call requested channel in already in use\n");
+                       goto outgoing_glare;
+               }
+               break;            
+       }
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "WE SHOULD NOT BE HERE!!!!\n");
+
+       ftdm_mutex_unlock(ftdmchan->mutex);
+       return FTDM_FAIL;
+
+outgoing_glare:
+       ftdm_mutex_unlock(ftdmchan->mutex);  
+       return FTDM_BREAK;
+
+outgoing_successful:
+       ftdm_mutex_unlock(ftdmchan->mutex);
+       return FTDM_SUCCESS;
+}
+
+static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_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_sangoma_isdn_set_sig_status)
+{
+       ftdm_log(FTDM_LOG_ERROR,"Cannot set channel status in this module\n");
+       return FTDM_NOTIMPL;
+}
+
+static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
+{
+       ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id);
+       if (sng_isdn_stack_activate(span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "Failed to activate span %s\n", span->name);
+               return FTDM_FAIL;
+       }
+       /* clear the monitor thread stop flag */
+       ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
+       ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+
+       /*start the span monitor thread*/
+       if (ftdm_thread_create_detached(ftdm_sangoma_isdn_run, span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN Span Monitor Thread!\n");
+               return FTDM_FAIL;
+       }
+
+       ftdm_log(FTDM_LOG_DEBUG,"Finished starting span %s\n", span->name);
+       return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span)
+{
+       unsigned i;
+       ftdm_log(FTDM_LOG_INFO, "Stopping span %s\n", span->name);
+       
+       /* 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 span %s\n", span->name);
+               ftdm_sleep(10);
+       }
+
+       /* FIXME: deconfigure any circuits, links, attached to this span */
+       /* TODO: confirm with Moy whether we should start channels at 1 or 0 */
+       for (i=1;i<=span->chan_count;i++) {
+               ftdm_safe_free(span->channels[i]->call_data);
+       }
+       ftdm_safe_free(span->signal_data);
+
+       ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s\n", span->name);
+
+       return FTDM_SUCCESS;
+}
+
+static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
+{
+       sngisdn_span_data_t *span_data;
+       
+       ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_isdn span = %s\n", span->name);      
+
+       span_data = ftdm_calloc(1, sizeof(sngisdn_span_data_t));
+       span_data->ftdm_span = span;
+       span->signal_data = span_data;
+
+       unsigned i;
+       for (i=1;i <= span->chan_count; i++) {
+               sngisdn_chan_data_t *chan_data = ftdm_calloc(1, sizeof(sngisdn_chan_data_t));
+               chan_data->ftdmchan = span->channels[i];
+               span->channels[i]->call_data = chan_data;
+       }
+
+       if (ftmod_isdn_parse_cfg(ftdm_parameters, span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_ERROR, "Failed to parse configuration\n");
+               return FTDM_FAIL;
+       }
+
+       if (sng_isdn_stack_cfg(span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "Sangoma ISDN Stack configuration failed\n");
+               return FTDM_FAIL;
+       }
+
+
+       span->start = ftdm_sangoma_isdn_start;
+       span->stop = ftdm_sangoma_isdn_stop;
+       span->signal_type = FTDM_SIGTYPE_ISDN;
+#if 0
+       span->signal_data = NULL;
+#endif
+       span->outgoing_call = ftdm_sangoma_isdn_outgoing_call;
+       span->channel_request = NULL;
+       span->signal_cb = sig_cb;
+       span->get_channel_sig_status = ftdm_sangoma_isdn_get_sig_status;
+       span->set_channel_sig_status = ftdm_sangoma_isdn_set_sig_status;
+       span->state_map = &sangoma_isdn_state_map;
+       ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
+
+       ftdm_log(FTDM_LOG_INFO, "Finished configuring ftmod_sangoma_isdn span = %s\n", span->name);
+       return FTDM_SUCCESS;
+}
+
+static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init)
+{
+       unsigned i;
+       ftdm_log(FTDM_LOG_INFO, "Loading ftmod_sangoma_isdn...\n");
+
+       memset(&g_sngisdn_data, 0, sizeof(g_sngisdn_data));
+
+       /* set callbacks */
+       g_sngisdn_event_interface.cc.sng_con_ind        = sngisdn_rcv_con_ind;
+       g_sngisdn_event_interface.cc.sng_con_cfm        = sngisdn_rcv_con_cfm;
+       g_sngisdn_event_interface.cc.sng_cnst_ind       = sngisdn_rcv_cnst_ind;
+       g_sngisdn_event_interface.cc.sng_disc_ind       = sngisdn_rcv_disc_ind;
+       g_sngisdn_event_interface.cc.sng_rel_ind        = sngisdn_rcv_rel_ind;
+       g_sngisdn_event_interface.cc.sng_dat_ind        = sngisdn_rcv_dat_ind;
+       g_sngisdn_event_interface.cc.sng_sshl_ind       = sngisdn_rcv_sshl_ind;
+       g_sngisdn_event_interface.cc.sng_sshl_cfm       = sngisdn_rcv_sshl_cfm;
+       g_sngisdn_event_interface.cc.sng_rmrt_ind       = sngisdn_rcv_rmrt_ind;
+       g_sngisdn_event_interface.cc.sng_rmrt_cfm       = sngisdn_rcv_rmrt_cfm;
+       g_sngisdn_event_interface.cc.sng_flc_ind        = sngisdn_rcv_flc_ind;
+       g_sngisdn_event_interface.cc.sng_fac_ind        = sngisdn_rcv_fac_ind;
+       g_sngisdn_event_interface.cc.sng_sta_cfm        = sngisdn_rcv_sta_cfm;
+       g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_ind;
+       g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_cfm;
+       g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_cfm;
+       g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_ind;
+       g_sngisdn_event_interface.cc.sng_rst_cfm        = sngisdn_rcv_rst_cfm;
+
+       g_sngisdn_event_interface.lg.sng_log                    = sngisdn_rcv_sng_log;
+       g_sngisdn_event_interface.sta.sng_phy_sta_ind   = sngisdn_rcv_phy_ind;
+       g_sngisdn_event_interface.sta.sng_q921_sta_ind  = sngisdn_rcv_q921_ind;
+       g_sngisdn_event_interface.sta.sng_q921_trc_ind  = sngisdn_rcv_q921_trace;
+       g_sngisdn_event_interface.sta.sng_q931_sta_ind  = sngisdn_rcv_q931_ind;
+       g_sngisdn_event_interface.sta.sng_q931_trc_ind  = sngisdn_rcv_q931_trace;
+       g_sngisdn_event_interface.sta.sng_cc_sta_ind    = sngisdn_rcv_cc_ind;
+
+       for(i=1;i<=MAX_VARIANTS;i++) {          
+               ftdm_mutex_create(&g_sngisdn_data.ccs[i].request_mutex);
+       }
+       /* initalize sng_isdn library */
+       sng_isdn_init(&g_sngisdn_event_interface);
+
+       /* crash on assert fail */
+       ftdm_global_set_crash_policy(FTDM_CRASH_ON_ASSERT);
+       return FTDM_SUCCESS;
+}
+
+static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_isdn_unload)
+{
+       unsigned i;
+       ftdm_log(FTDM_LOG_INFO, "Starting ftmod_sangoma_isdn unload...\n");
+
+       sng_isdn_free();
+       
+       for(i=1;i<=MAX_VARIANTS;i++) {          
+               ftdm_mutex_destroy(&g_sngisdn_data.ccs[i].request_mutex);
+       }
+
+       ftdm_log(FTDM_LOG_INFO, "Finished ftmod_sangoma_isdn unload!\n");
+       return FTDM_SUCCESS;
+}
+
+static FIO_API_FUNCTION(ftdm_sangoma_isdn_api)
+{
+       ftdm_status_t status = FTDM_SUCCESS;
+       char *mycmd = NULL, *argv[10] = { 0 };
+       int argc = 0;
+
+       if (data) {
+               mycmd = ftdm_strdup(data);
+               argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+       }
+
+       /*ftdm_log(FTDM_LOG_DEBUG, "Sangoma argc:%d argv[0]:%s argv[1]:%s argv[2]:%s \n", argc, argv[0], argv[1], argv[2]);*/
+       if (argc <= 0) {
+               ftdm_log(FTDM_LOG_ERROR, "No parameters provided\n");
+               goto done;
+       }
+
+       if (!strcasecmp(argv[0], "trace")) {
+               char *trace_opt;
+               
+               ftdm_span_t *span;
+
+               if (argc < 3) {
+                       ftdm_log(FTDM_LOG_ERROR, "Usage: ftdm sangoma_isdn trace <q921|q931> <span name>\n");
+                       status = FTDM_FAIL;
+                       goto done;
+               }
+               trace_opt = argv[1];
+               
+               status = ftdm_span_find_by_name(argv[2], &span);
+               if (FTDM_SUCCESS != status) {
+                       stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[2]);
+                       goto done;
+               }
+               if (!strcasecmp(trace_opt, "q921")) {
+                       sng_isdn_activate_trace(span, SNGISDN_TRACE_Q921);
+               } else if (!strcasecmp(trace_opt, "q931")) {
+                       sng_isdn_activate_trace(span, SNGISDN_TRACE_Q931);
+               } else if (!strcasecmp(trace_opt, "disable")) {
+                       sng_isdn_activate_trace(span, SNGISDN_TRACE_DISABLE);
+               } else {
+                       stream->write_function(stream, "-ERR invalid trace option <q921|q931> <span name>\n");
+               }       
+       }
+done:
+       ftdm_safe_free(mycmd);
+       return status;
+}
+
+static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_isdn_io_init)
+{
+       memset(&g_sngisdn_io_interface, 0, sizeof(g_sngisdn_io_interface));
+
+       g_sngisdn_io_interface.name = "sangoma_isdn";
+       g_sngisdn_io_interface.api = ftdm_sangoma_isdn_api;
+
+       *fio = &g_sngisdn_io_interface;
+
+       return FTDM_SUCCESS;
+}
+
+ftdm_module_t ftdm_module =
+{
+       "sangoma_isdn",                /* char name[256]; */
+       ftdm_sangoma_isdn_io_init,     /* fio_io_load_t */
+       NULL,                                              /* fio_io_unload_t */
+       ftdm_sangoma_isdn_init,        /* fio_sig_load_t */
+       NULL,                          /* fio_sig_configure_t */
+       ftdm_sangoma_isdn_unload,      /* fio_sig_unload_t */
+       ftdm_sangoma_isdn_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_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
new file mode 100644 (file)
index 0000000..d3877de
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies 
+ * David Yat Sin <davidy@sangoma.com>
+ * Moises Silva <moy@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_ISDN_H__
+#define __FTMOD_SNG_ISDN_H__
+
+#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_isdn.h>
+
+#define MAX_SPANS_PER_NFAS_LINK          8 /* TODO: Confirm this value */
+#define NUM_E1_CHANNELS_PER_SPAN 32
+#define NUM_T1_CHANNELS_PER_SPAN 24
+#define NUM_BRI_CHANNELS_PER_SPAN 2
+
+/* Should never have DEBUG_MODE defined when used in production */
+#if 0
+#undef DEBUG_MODE
+#define FORCE_SEFGAULT
+#else
+#define DEBUG_MODE
+#define FORCE_SEGFAULT *(int *) 0 = 0;
+#endif
+
+/* TODO: rename all *_cc_* to *_an_*  */
+
+typedef struct sngisdn_glare_data {
+       int16_t         suId;
+    uint32_t   suInstId;
+    uint32_t   spInstId;
+       int16_t         dChan;
+    ConEvnt            setup;
+       uint8_t         ces;
+}sngisdn_glare_data_t;
+
+
+/* Channel specific data */
+typedef struct sngisdn_chan_data {
+    ftdm_channel_t                     *ftdmchan;
+    uint32_t                           flags;
+       uint8_t                                 ces;            /* not used for now */
+       uint8_t                                 dchan_id;
+       uint32_t                                suInstId;       /* instance ID generated locally */
+       uint32_t                                spInstId;       /* instance ID generated by stack */
+
+       uint8_t                 globalFlg;
+       sngisdn_glare_data_t    glare;
+} sngisdn_chan_data_t;
+
+/* Span specific data */
+typedef struct sngisdn_span_data {
+       ftdm_span_t     *ftdm_span;
+       uint8_t         link_id;
+       uint8_t         switchtype;
+       uint8_t         signalling;                     /* SNGISDN_SIGNALING_CPE or SNGISDN_SIGNALING_NET */
+       uint8_t         cc_id;
+       uint8_t         dchan_id;
+       uint8_t         span_id;
+       uint8_t         tei;
+       uint8_t         keep_link_up;
+       uint8_t         trace_flags;
+} sngisdn_span_data_t;
+
+/* dchan_data can have more than 1 span when running NFAS */
+typedef struct sngisdn_dchan_data {
+       uint8_t                         num_spans;
+       sngisdn_span_data_t     *spans[MAX_L1_LINKS+1];
+       uint16_t                        num_chans;
+       /* worst case for number of channel is when using NFAS, and NFAS is only used on T1,
+               so we can use MAX_SPANS_PER_NFAS_LINK*NUM_T1_CHANNELS_PER_SPAN instead of
+               MAX_SPANS_PER_NFAS_LINK*NUM_E1_CHANNELS_PER_SPAN
+       */
+       /* Never seen NFAS on E1 yet, so use NUM_T1_CHANNELS_PER_SPAN */
+       /* b-channels are arranged by physical id's not logical */
+       sngisdn_chan_data_t *channels[MAX_SPANS_PER_NFAS_LINK*NUM_T1_CHANNELS_PER_SPAN];
+}sngisdn_dchan_data_t;
+
+typedef struct sngisdn_cc {
+       /* TODO: use flags instead of config_done and activation_done */
+       uint8_t                         config_done;
+       uint8_t                         activation_done;
+       uint8_t                         switchtype;
+       ftdm_trunk_type_t       trunktype;
+       uint32_t                        last_suInstId;
+       ftdm_mutex_t            *request_mutex;
+       sngisdn_chan_data_t     *active_spInstIds[MAX_INSTID];
+       sngisdn_chan_data_t     *active_suInstIds[MAX_INSTID];
+}sngisdn_cc_t;
+
+/* Global sngisdn data */
+typedef struct ftdm_sngisdn_data {
+       uint8_t gen_config_done;
+       uint8_t num_cc;                                         /* 1 ent per switchtype */
+       struct sngisdn_cc ccs[MAX_VARIANTS+1];
+       uint8_t num_dchan;
+       sngisdn_dchan_data_t dchans[MAX_L1_LINKS+1];
+}ftdm_sngisdn_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_REMOTE_ABORT       = (1 << 4),
+       FLAG_LOCAL_ABORT       = (1 << 4),
+       FLAG_GLARE              = (1 << 5),
+       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)
+} sngisdn_flag_t;
+
+
+typedef enum {
+       SNGISDN_SWITCH_INVALID = 0,     /* invalid */
+       SNGISDN_SWITCH_NI2 ,    /* national isdn-2 */
+       SNGISDN_SWITCH_5ESS,    /* att 5ess */
+       SNGISDN_SWITCH_4ESS,    /* att 4ess */
+       SNGISDN_SWITCH_DMS100,  /* nt dms100 */
+       SNGISDN_SWITCH_EUROISDN,/* etsi */
+       SNGISDN_SWITCH_QSIG,    /* etsi qsig */
+       SNGISDN_SWITCH_INSNET,  /* int - net */
+} sngisdn_switchtype_t;
+
+typedef enum {
+       SNGISDN_SIGNALING_INVALID = 0,          /* invalid */
+       SNGISDN_SIGNALING_CPE ,                         /* customer side emulation */
+       SNGISDN_SIGNALING_NET,                          /* network side emulation */
+} sngisdn_signalingtype_t;
+
+typedef enum {
+       SNGISDN_TRACE_DISABLE = 0,
+       SNGISDN_TRACE_Q921 = 1,
+       SNGISDN_TRACE_Q931 = 2,
+} sngisdn_tracetype_t;
+
+
+#define sngisdn_set_flag(obj, flag)   ((obj)->flags |= (flag))
+#define sngisdn_clear_flag(obj, flag) ((obj)->flags &= ~(flag))
+#define sngisdn_test_flag(obj, flag)  ((obj)->flags & flag)
+
+#define sngisdn_set_trace_flag(obj, flag)   ((obj)->trace_flags |= (flag))
+#define sngisdn_clear_trace_flag(obj, flag) ((obj)->trace_flags &= ~(flag))
+#define sngisdn_test_trace_flag(obj, flag)  ((obj)->trace_flags & flag)
+
+/* TODO implement these 2 functions */
+#define ISDN_FUNC_TRACE_ENTER(a)
+#define ISDN_FUNC_TRACE_EXIT(a)
+
+/* Configuration functions */
+ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span);
+
+/* Support functions */
+uint32_t get_unique_suInstId(uint8_t cc_id);
+void clear_call_data(sngisdn_chan_data_t *sngisdn_info);
+void stack_hdr_init(Header *hdr);
+void stack_pst_init(Pst *pst);
+ftdm_status_t get_ftdmchan_by_spInstId(uint8_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data);
+ftdm_status_t get_ftdmchan_by_suInstId(uint8_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data);
+
+ftdm_status_t check_for_state_change(ftdm_channel_t *ftdmchan);
+
+/* Outbound Call Control functions */
+void sngisdn_snd_setup(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_progress(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_alert(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_connect(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_release(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_reset(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan);
+
+/* Inbound Call Control functions */
+void sngisdn_rcv_con_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, signed short dChan, uint8_t ces);
+void sngisdn_rcv_con_cfm (signed short suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, signed short dChan, uint8_t ces);
+void sngisdn_rcv_cnst_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, uint8_t evntType, signed short dChan, uint8_t ces);
+void sngisdn_rcv_disc_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, DiscEvnt *discEvnt);
+void sngisdn_rcv_rel_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, RelEvnt *relEvnt);
+void sngisdn_rcv_dat_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, InfoEvnt *infoEvnt);
+void sngisdn_rcv_sshl_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action);
+void sngisdn_rcv_sshl_cfm (signed short suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action);
+void sngisdn_rcv_rmrt_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action);
+void sngisdn_rcv_rmrt_cfm (signed short suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action);
+void sngisdn_rcv_flc_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt);
+void sngisdn_rcv_fac_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, FacEvnt *facEvnt, uint8_t evntType, signed short dChan, uint8_t ces);
+void sngisdn_rcv_sta_cfm ( signed short suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt);
+void sngisdn_rcv_srv_ind ( signed short suId, Srv *srvEvnt, signed short dChan, uint8_t ces);
+void sngisdn_rcv_srv_cfm ( signed short suId, Srv *srvEvnt, signed short dChan, uint8_t ces);
+void sngisdn_rcv_rst_cfm ( signed short suId, Rst *rstEvnt, signed short dChan, uint8_t ces, uint8_t evtType);
+void sngisdn_rcv_rst_ind ( signed short suId, Rst *rstEvnt, signed short dChan, uint8_t ces, uint8_t evtType);
+
+
+void sngisdn_rcv_phy_ind(SuId suId, Reason reason);
+void sngisdn_rcv_q921_ind(BdMngmt *status);
+void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf);
+void sngisdn_rcv_q931_ind(InMngmt *status);
+void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf);
+void sngisdn_rcv_cc_ind(CcMngmt *status);
+void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...);
+
+void handle_sng_log(uint8_t level, char *fmt,...);
+void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status);
+
+/* Stack management functions */
+ftdm_status_t sng_isdn_stack_cfg(ftdm_span_t *span);
+ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span);
+
+
+#endif /* __FTMOD_SNG_ISDN_H__ */
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c
new file mode 100644 (file)
index 0000000..d0254fd
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * David Yat Sin <davidy@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 "ftmod_sangoma_isdn.h"
+
+ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span);
+ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span);
+
+extern ftdm_sngisdn_data_t     g_sngisdn_data;
+
+ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span)
+{
+       unsigned i;
+
+       sngisdn_dchan_data_t *dchan_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
+       switch(span->trunk_type) {
+               case FTDM_TRUNK_T1:
+                       if (!strcasecmp(switch_name, "ni2")) {
+                               signal_data->switchtype = SNGISDN_SWITCH_NI2;
+                       } else if (!strcasecmp(switch_name, "5ess")) {
+                               signal_data->switchtype = SNGISDN_SWITCH_5ESS;
+                       } else if (!strcasecmp(switch_name, "4ess")) {
+                               signal_data->switchtype = SNGISDN_SWITCH_4ESS;
+                       } else if (!strcasecmp(switch_name, "dms100")) {
+                               signal_data->switchtype = SNGISDN_SWITCH_DMS100;
+                       } else {
+                               ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
+                               return FTDM_FAIL;
+                       }
+                       break;
+               case FTDM_TRUNK_E1:
+                       if (!strcasecmp(switch_name, "euroisdn") || strcasecmp(switch_name, "etsi")) {
+                               signal_data->switchtype = SNGISDN_SWITCH_EUROISDN;
+                       } else if (!strcasecmp(switch_name, "qsig")) {
+                               signal_data->switchtype = SNGISDN_SWITCH_QSIG;
+                       } else {
+                               ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
+                               return FTDM_FAIL;
+                       }
+                       break;
+               case FTDM_TRUNK_BRI:
+               case FTDM_TRUNK_BRI_PTMP:
+                       if (!strcasecmp(switch_name, "euroisdn") ||
+                               !strcasecmp(switch_name, "etsi")) {
+                               signal_data->switchtype = SNGISDN_SWITCH_EUROISDN;
+                       } else if (!strcasecmp(switch_name, "insnet") ||
+                                               !strcasecmp(switch_name, "ntt")) {
+                               signal_data->switchtype = SNGISDN_SWITCH_INSNET;
+                       } else {
+                               ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
+                               return FTDM_FAIL;
+                       }
+                        /* can be > 1 for some BRI variants */
+                       break;
+               default:
+                       ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
+                       return FTDM_FAIL;
+       }
+       /* see if we have profile with this switch_type already */
+       for (i=1; i <= g_sngisdn_data.num_cc; i++) {
+               if (g_sngisdn_data.ccs[i].switchtype == signal_data->switchtype &&
+                       g_sngisdn_data.ccs[i].trunktype == span->trunk_type) {
+                       break;
+               }
+       }
+       /* need to create a new switch_type */
+       if (i > g_sngisdn_data.num_cc) {
+               g_sngisdn_data.num_cc++;
+               g_sngisdn_data.ccs[i].switchtype = signal_data->switchtype;
+               g_sngisdn_data.ccs[i].trunktype = span->trunk_type;
+               ftdm_log(FTDM_LOG_DEBUG, "%s: New switchtype:%s  cc_id:%u\n", span->name, switch_name, i);
+       }
+
+       /* add this span to its ent_cc */
+       signal_data->cc_id = i;
+
+       /* create a new dchan */ /* for NFAS - no-dchan on b-channels only links */
+       g_sngisdn_data.num_dchan++;
+       signal_data->dchan_id =  g_sngisdn_data.num_dchan;
+
+       dchan_data = &g_sngisdn_data.dchans[signal_data->dchan_id];
+       dchan_data->num_spans++;
+
+       signal_data->span_id = dchan_data->num_spans;
+       dchan_data->spans[signal_data->span_id] = signal_data;
+       
+       ftdm_log(FTDM_LOG_DEBUG, "%s: cc_id:%d dchan_id:%d span_id:%d\n", span->name, signal_data->cc_id, signal_data->dchan_id, signal_data->span_id);
+
+       /* Add the channels to the span */
+       for (i=1;i<=span->chan_count;i++) {
+               unsigned chan_id;
+               ftdm_channel_t *ftdmchan = span->channels[i];
+               /* NFAS is not supported on E1, so span_id will always be 1 for E1 so this will work for E1 as well */
+               chan_id = ((signal_data->span_id-1)*NUM_T1_CHANNELS_PER_SPAN)+ftdmchan->physical_chan_id;
+               dchan_data->channels[chan_id] = (sngisdn_chan_data_t*)ftdmchan->call_data;
+               dchan_data->num_chans++;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span)
+{
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
+       if (!strcasecmp(signalling, "net") ||
+               !strcasecmp(signalling, "pri_net")||
+               !strcasecmp(signalling, "bri_net")) {
+
+               signal_data->signalling = SNGISDN_SIGNALING_NET;
+       } else if (!strcasecmp(signalling, "cpe") ||
+               !strcasecmp(signalling, "pri_cpe")||
+               !strcasecmp(signalling, "bri_cpe")) {
+
+               signal_data->signalling = SNGISDN_SIGNALING_CPE;
+       } else {
+               ftdm_log(FTDM_LOG_ERROR, "Unsupported signalling %s\n", signalling);
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span)
+{
+       unsigned paramindex;
+       const char *var, *val;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
+       /* Set defaults here */
+       signal_data->keep_link_up = 1;
+       signal_data->tei = 0;
+       
+       
+       for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
+               ftdm_log(FTDM_LOG_DEBUG, "Sangoma ISDN key=value, %s=%s\n", ftdm_parameters[paramindex].var, ftdm_parameters[paramindex].val);
+               var = ftdm_parameters[paramindex].var;
+               val = ftdm_parameters[paramindex].val;
+               
+               if (!strcasecmp(var, "switchtype")) {
+                       if (parse_switchtype(val, span) != FTDM_SUCCESS) {
+                               return FTDM_FAIL;
+                       }
+               } else if (!strcasecmp(var, "signalling")) {
+                       if (parse_signalling(val, span) != FTDM_SUCCESS) {
+                               return FTDM_FAIL;
+                       }
+               } else if (!strcasecmp(var, "tei")) {
+                       uint8_t tei = atoi(val);
+                       if (tei > 127) {
+                               ftdm_log(FTDM_LOG_ERROR, "Invalid TEI %d, valid values are (0-127)", tei);
+                               return FTDM_FAIL;
+                       }
+                       signal_data->tei = tei;
+               } else if (!strcasecmp(var, "keep_link_up")) {
+                       if (!strcasecmp(val, "yes")) {
+                               signal_data->keep_link_up = 1;
+                       } else if (!strcasecmp(val, "no")) {
+                               signal_data->keep_link_up = 0;
+                       } else {
+                               ftdm_log(FTDM_LOG_ERROR, "Invalid keep_link_up value, valid values are (yes/no)");
+                               return FTDM_FAIL;
+                       }
+               } else {
+                       ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var);
+               }
+       }
+       signal_data->link_id = span->span_id;
+       if (signal_data->switchtype == SNGISDN_SWITCH_INVALID) {
+               ftdm_log(FTDM_LOG_ERROR, "%s: switchtype not specified", span->name);
+               return FTDM_FAIL;
+       }
+       if (signal_data->signalling == SNGISDN_SIGNALING_INVALID) {
+               ftdm_log(FTDM_LOG_ERROR, "%s: signalling not specified", span->name);
+               return FTDM_FAIL;
+       }
+       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_isdn/ftmod_sangoma_isdn_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c
new file mode 100644 (file)
index 0000000..5299c91
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * David Yat Sin <davidy@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 "ftmod_sangoma_isdn.h"
+
+
+void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status);
+
+void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
+{
+       ftdm_sigmsg_t sig;
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Signalling link status changed to %s\n", ftdm_signaling_status2str(status));
+
+       memset(&sig, 0, sizeof(sig));
+       sig.chan_id = ftdmchan->chan_id;
+       sig.span_id = ftdmchan->span_id;
+       sig.channel = ftdmchan;
+       sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+       sig.raw_data = &status;
+       ftdm_span_send_signal(ftdmchan->span, &sig);
+       return;
+}
+
+
+
+void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status)
+{      
+       unsigned i;
+       /* TODO: use channel iterator once it is implemented */
+
+       for (i=1;i<=ftdmspan->chan_count;i++) {
+               sngisdn_set_chan_sig_status(ftdmspan->channels[i], status);
+       }
+       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_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c
new file mode 100644 (file)
index 0000000..c44228d
--- /dev/null
@@ -0,0 +1,1035 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies 
+ * David Yat Sin <davidy@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 "ftmod_sangoma_isdn.h"
+
+extern ftdm_sngisdn_data_t     g_sngisdn_data;
+
+uint8_t sng_isdn_stack_switchtype(sngisdn_switchtype_t switchtype);
+
+ftdm_status_t sng_isdn_cfg_phy(ftdm_span_t *span);
+ftdm_status_t sng_isdn_cfg_q921(ftdm_span_t *span);
+ftdm_status_t sng_isdn_cfg_q931(ftdm_span_t *span);
+ftdm_status_t sng_isdn_cfg_cc(ftdm_span_t *span);
+
+ftdm_status_t sng_isdn_stack_cfg_phy_gen(void);
+ftdm_status_t sng_isdn_stack_cfg_q921_gen(void);
+ftdm_status_t sng_isdn_stack_cfg_q931_gen(void);
+ftdm_status_t sng_isdn_stack_cfg_cc_gen(void);
+
+
+ftdm_status_t sng_isdn_stack_cfg_phy_psap(ftdm_span_t *span);
+ftdm_status_t sng_isdn_stack_cfg_q921_msap(ftdm_span_t *span);
+ftdm_status_t sng_isdn_stack_cfg_q921_dlsap(ftdm_span_t *span, uint8_t management);
+ftdm_status_t sng_isdn_stack_cfg_q931_tsap(ftdm_span_t *span);
+ftdm_status_t sng_isdn_stack_cfg_q931_dlsap(ftdm_span_t *span);
+ftdm_status_t sng_isdn_stack_cfg_q931_lce(ftdm_span_t *span);
+
+ftdm_status_t sng_isdn_stack_cfg_cc_sap(ftdm_span_t *span);
+
+ftdm_status_t sng_isdn_stack_cfg(ftdm_span_t *span)
+{
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+       if (!g_sngisdn_data.gen_config_done) {
+               g_sngisdn_data.gen_config_done = 1;
+               ftdm_log(FTDM_LOG_DEBUG, "Starting general stack configuration\n");
+               if(sng_isdn_stack_cfg_phy_gen()!= FTDM_SUCCESS) {
+                       ftdm_log(FTDM_LOG_CRIT, "Failed general physical configuration\n");
+                       return FTDM_FAIL;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "General stack physical done\n");
+       
+               if(sng_isdn_stack_cfg_q921_gen()!= FTDM_SUCCESS) {
+                       ftdm_log(FTDM_LOG_CRIT, "Failed general q921 configuration\n");
+                       return FTDM_FAIL;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "General stack q921 done\n");
+
+               if(sng_isdn_stack_cfg_q931_gen()!= FTDM_SUCCESS) {
+                       ftdm_log(FTDM_LOG_CRIT, "Failed general q921 configuration\n");
+                       return FTDM_FAIL;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "General stack q931 done\n");
+
+               if(sng_isdn_stack_cfg_cc_gen()!= FTDM_SUCCESS) {
+                       ftdm_log(FTDM_LOG_CRIT, "Failed general CC configuration\n");
+                       return FTDM_FAIL;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "General stack CC done\n");
+               ftdm_log(FTDM_LOG_INFO, "General stack configuration done\n");
+       }
+
+       /* TODO: for NFAS, should only call these function for spans with d-chans */
+       if (sng_isdn_stack_cfg_phy_psap(span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_ERROR, "%s:phy_psap configuration failed\n", span->name);
+               return FTDM_FAIL;
+       }
+       ftdm_log(FTDM_LOG_DEBUG, "%s:phy_psap configuration done\n", span->name);
+
+       if (sng_isdn_stack_cfg_q921_msap(span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_ERROR, "%s:q921_msap configuration failed\n", span->name);
+               return FTDM_FAIL;
+       }
+       ftdm_log(FTDM_LOG_DEBUG, "%s:q921_msap configuration done\n", span->name);
+
+       if (sng_isdn_stack_cfg_q921_dlsap(span, 0) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_ERROR, "%s:q921_dlsap configuration failed\n", span->name);
+               return FTDM_FAIL;
+       }
+       ftdm_log(FTDM_LOG_DEBUG, "%s:q921_dlsap configuration done\n", span->name);
+
+       if (span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+               if (sng_isdn_stack_cfg_q921_dlsap(span, 1) != FTDM_SUCCESS) {
+                       ftdm_log(FTDM_LOG_ERROR, "%s:q921_dlsap management configuration failed\n", span->name);
+                       return FTDM_FAIL;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "%s:q921_dlsap management configuration done\n", span->name);
+       }
+       
+
+       if (sng_isdn_stack_cfg_q931_dlsap(span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_ERROR, "%s:q931_dlsap configuration failed\n", span->name);
+               return FTDM_FAIL;
+       }
+       ftdm_log(FTDM_LOG_DEBUG, "%s:q931_dlsap configuration done\n", span->name);
+
+       if (sng_isdn_stack_cfg_q931_lce(span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_ERROR, "%s:q931_lce configuration failed\n", span->name);
+               return FTDM_FAIL;
+       }
+       ftdm_log(FTDM_LOG_DEBUG, "%s:q931_lce configuration done\n", span->name);
+
+       if (!g_sngisdn_data.ccs[signal_data->cc_id].config_done) {
+               g_sngisdn_data.ccs[signal_data->cc_id].config_done = 1;
+               /* if BRI, need to configure dlsap_mgmt */
+               if (sng_isdn_stack_cfg_q931_tsap(span) != FTDM_SUCCESS) {
+                       ftdm_log(FTDM_LOG_ERROR, "%s:q931_tsap configuration failed\n", span->name);
+                       return FTDM_FAIL;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "%s:q931_tsap configuration done\n", span->name);
+
+               if (sng_isdn_stack_cfg_cc_sap(span) != FTDM_SUCCESS) {
+                       ftdm_log(FTDM_LOG_ERROR, "%s:cc_sap configuration failed\n", span->name);
+                       return FTDM_FAIL;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "%s:cc_sap configuration done\n", span->name);
+       }
+
+       ftdm_log(FTDM_LOG_INFO, "%s:stack configuration done\n", span->name);
+       return FTDM_SUCCESS;
+}
+
+
+
+ftdm_status_t sng_isdn_stack_cfg_phy_gen(void)
+{
+       /*local variables*/
+    L1Mngmt     cfg;    /*configuration structure*/
+    Pst         pst;    /*post structure*/
+
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+
+    /* insert the destination Entity */
+    pst.dstEnt = ENTL1;
+
+    /*clear the configuration structure*/
+       memset(&cfg, 0, sizeof(cfg));
+
+    /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);
+
+    /*fill in the specific fields of the header*/
+    cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTL1;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STGEN;
+
+    stack_pst_init(&cfg.t.cfg.s.l1Gen.sm );
+    cfg.t.cfg.s.l1Gen.sm.srcEnt     = ENTL1;
+    cfg.t.cfg.s.l1Gen.sm.dstEnt     = ENTSM;
+
+    cfg.t.cfg.s.l1Gen.nmbLnks       = MAX_L1_LINKS+1;
+    cfg.t.cfg.s.l1Gen.poolTrUpper   = POOL_UP_TR;        /* upper pool threshold */
+    cfg.t.cfg.s.l1Gen.poolTrLower   = POOL_LW_TR;        /* lower pool threshold */
+
+       if (sng_isdn_phy_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t sng_isdn_stack_cfg_phy_psap(ftdm_span_t *span)
+{
+       /*local variables*/
+    L1Mngmt     cfg;    /*configuration structure*/
+    Pst         pst;    /*post structure*/
+
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+
+    /* insert the destination Entity */
+    pst.dstEnt = ENTL1;
+
+    /*clear the configuration structure*/
+       memset(&cfg, 0, sizeof(cfg));
+
+    /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);
+
+    /*fill in the specific fields of the header*/
+    cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTL1;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STPSAP;
+
+       cfg.hdr.elmId.elmntInst1    = signal_data->link_id;
+
+    cfg.t.cfg.s.l1PSAP.span    = span->channels[1]->physical_span_id;
+       switch(span->trunk_type) {
+               case FTDM_TRUNK_E1:
+                       cfg.t.cfg.s.l1PSAP.chan = 16;
+                       cfg.t.cfg.s.l1PSAP.type = SNG_LINKTYPE_PRI;
+                       break;
+               case FTDM_TRUNK_T1:
+               case FTDM_TRUNK_J1:
+                       cfg.t.cfg.s.l1PSAP.chan = 24;
+                       cfg.t.cfg.s.l1PSAP.type = SNG_LINKTYPE_PRI;
+                       break;
+               case FTDM_TRUNK_BRI:
+               case FTDM_TRUNK_BRI_PTMP:
+                       cfg.t.cfg.s.l1PSAP.chan = 3;
+                       cfg.t.cfg.s.l1PSAP.type = SNG_LINKTYPE_BRI;
+                       break;
+               default:
+                       ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported trunk type %d\n", span->name, span->trunk_type);
+                       return FTDM_FAIL;
+       }       
+    cfg.t.cfg.s.l1PSAP.spId            = signal_data->link_id;
+
+       if (sng_isdn_phy_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t sng_isdn_stack_cfg_q921_gen(void)
+{
+       BdMngmt cfg;
+    Pst     pst;
+
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+       /* insert the destination Entity */
+    pst.dstEnt = ENTLD;
+
+    /*clear the configuration structure*/
+    memset(&cfg, 0, sizeof(cfg));
+       /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);
+               
+    cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTLD;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STGEN;
+    /* fill in the Gen Conf structures internal pst struct */
+
+    stack_pst_init(&cfg.t.cfg.s.bdGen.sm);
+
+       cfg.t.cfg.s.bdGen.sm.dstEnt    = ENTSM;         /* entity */
+       
+       cfg.t.cfg.s.bdGen.nmbPLnks =    MAX_L1_LINKS+1;
+       cfg.t.cfg.s.bdGen.nmbLDLnks =   MAX_L1_LINKS+1; /* Not used in LAPD */
+       cfg.t.cfg.s.bdGen.nmbDLCs = MAX_L1_LINKS+1;
+       cfg.t.cfg.s.bdGen.nmbDLCs = MAX_TEIS_PER_LINK*(MAX_L1_LINKS+1);
+       cfg.t.cfg.s.bdGen.nmbASPLnks = MAX_L1_LINKS+1;
+
+#ifdef LAPD_3_4
+       cfg.t.cfg.s.bdGen.timeRes     = 10;                              /* timer resolution */
+#endif
+    cfg.t.cfg.s.bdGen.poolTrUpper   = POOL_UP_TR;        /* upper pool threshold */
+    cfg.t.cfg.s.bdGen.poolTrLower   = POOL_LW_TR;        /* lower pool threshold */
+
+       if (sng_isdn_q921_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t sng_isdn_stack_cfg_q921_msap(ftdm_span_t *span)
+{
+       BdMngmt cfg;
+    Pst     pst;
+
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+       /* insert the destination Entity */
+    pst.dstEnt = ENTLD;
+
+    /*clear the configuration structure*/
+    memset(&cfg, 0, sizeof(cfg));
+       /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);
+
+       cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTLD;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STMSAP;
+
+       cfg.t.cfg.s.bdMSAP.lnkNmb      = signal_data->link_id;
+       
+       cfg.t.cfg.s.bdMSAP.maxOutsFrms = 2;            /* MAC window */
+       cfg.t.cfg.s.bdMSAP.tQUpperTrs  = 16;           /* Tx Queue Upper Threshold */
+       cfg.t.cfg.s.bdMSAP.tQLowerTrs  = 8;            /* Tx Queue Lower Threshold */   
+       cfg.t.cfg.s.bdMSAP.selector    = 0;       /* Selector 0 */
+       /* TODO: check if bdMSAP parameters can be initialized by calling stack_pst_init */
+       cfg.t.cfg.s.bdMSAP.mem.region  = S_REG;       /* Memory region */
+       cfg.t.cfg.s.bdMSAP.mem.pool    = S_POOL;      /* Memory pool */
+       cfg.t.cfg.s.bdMSAP.prior       = PRIOR0;            /* Priority */
+       cfg.t.cfg.s.bdMSAP.route       = RTESPEC;            /* Route */
+       cfg.t.cfg.s.bdMSAP.dstProcId   = SFndProcId(); /* destination proc id */
+       cfg.t.cfg.s.bdMSAP.dstEnt      = ENTL1;        /* entity */
+       cfg.t.cfg.s.bdMSAP.dstInst     = S_INST;      /* instance */    
+       cfg.t.cfg.s.bdMSAP.t201Tmr     = 5;            /* T201 */
+       cfg.t.cfg.s.bdMSAP.t202Tmr     = 200;          /* T202 */
+       cfg.t.cfg.s.bdMSAP.bndRetryCnt = 2;            /* bind retry counter */
+       cfg.t.cfg.s.bdMSAP.tIntTmr     = 200;          /* bind retry timer */
+       cfg.t.cfg.s.bdMSAP.n202        = 3;            /* N202 */
+       cfg.t.cfg.s.bdMSAP.lowTei      = 64;         /* Lowest dynamic TEI */
+
+       if (span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
+               signal_data->signalling == SNGISDN_SIGNALING_NET) {
+               cfg.t.cfg.s.bdMSAP.kpL1Up      = FALSE;        /* flag to keep l1 up or not */
+       } else {
+               cfg.t.cfg.s.bdMSAP.kpL1Up      = TRUE;        /* flag to keep l1 up or not */
+       }
+
+       cfg.t.cfg.s.bdMSAP.type        = sng_isdn_stack_switchtype(signal_data->switchtype);
+
+       if (span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+               cfg.t.cfg.s.bdMSAP.teiChkTmr   = 20;         /* Tei check timer */
+       } else {
+               cfg.t.cfg.s.bdMSAP.teiChkTmr   = 0;         /* Tei check timer */
+       }
+
+       if (signal_data->signalling == SNGISDN_SIGNALING_NET) {
+               cfg.t.cfg.s.bdMSAP.logInt      = 1;         /* logical interface = 0 = user, 1= network */
+               cfg.t.cfg.s.bdMSAP.setUpArb    = PASSIVE;       /* set up arbitration */
+       } else {
+               cfg.t.cfg.s.bdMSAP.logInt      = 0;         /* logical interface = 0 = user, 1= network */
+               cfg.t.cfg.s.bdMSAP.setUpArb    = ACTIVE;       /* set up arbitration */
+       }
+
+
+       if (sng_isdn_q921_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t sng_isdn_stack_cfg_q921_dlsap(ftdm_span_t *span, uint8_t management)
+{
+       BdMngmt cfg;
+    Pst     pst;
+
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+       /* insert the destination Entity */
+    pst.dstEnt = ENTLD;
+
+    /*clear the configuration structure*/
+    memset(&cfg, 0, sizeof(cfg));
+       /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);
+
+       /*fill in the specific fields of the header*/
+    cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTLD;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STDLSAP;
+
+       cfg.t.cfg.s.bdDLSAP.lnkNmb              = signal_data->link_id;
+
+       cfg.t.cfg.s.bdDLSAP.n201                = 1028;                 /* n201 */
+       cfg.t.cfg.s.bdDLSAP.k                   = 7;                    /* k */
+       cfg.t.cfg.s.bdDLSAP.n200                = 3;                    /* n200 */
+       cfg.t.cfg.s.bdDLSAP.congTmr             = 300;                  /* congestion timer */
+       cfg.t.cfg.s.bdDLSAP.t200Tmr             = 1;                            /* t1 changed from 25 */
+       cfg.t.cfg.s.bdDLSAP.t203Tmr             = 3;                            /* t3 changed from 50 */
+       cfg.t.cfg.s.bdDLSAP.mod                 = 128;                  /* modulo */
+       cfg.t.cfg.s.bdDLSAP.selector    = 0;                            /* Selector 0 */
+       cfg.t.cfg.s.bdDLSAP.mem.region  = S_REG;                        /* Memory region */
+       cfg.t.cfg.s.bdDLSAP.mem.pool    = S_POOL;                       /* Memory pool */
+       cfg.t.cfg.s.bdDLSAP.prior               = PRIOR0;                       /* Priority */
+       cfg.t.cfg.s.bdDLSAP.route               = RTESPEC;                      /* Route */
+
+       if (management) {
+               cfg.t.cfg.s.bdDLSAP.sapi     = MNGMT_SAPI;
+               cfg.t.cfg.s.bdDLSAP.teiAss     = NON_AUTOMATIC; /* static tei assignment */
+               cfg.t.cfg.s.bdDLSAP.noOfDlc = 1;
+               cfg.t.cfg.s.bdDLSAP.tei[0]  = 0x7f;
+       } else {
+               cfg.t.cfg.s.bdDLSAP.sapi  = Q930_SAPI;
+               if (span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+                       if (signal_data->signalling == SNGISDN_SIGNALING_NET) {
+                               cfg.t.cfg.s.bdDLSAP.teiAss  = AUTOMATIC;
+                               cfg.t.cfg.s.bdDLSAP.noOfDlc = 8;
+
+                               cfg.t.cfg.s.bdDLSAP.tei[0]  = 64;
+                               cfg.t.cfg.s.bdDLSAP.tei[1]  = 65;
+                               cfg.t.cfg.s.bdDLSAP.tei[2]  = 66;
+                               cfg.t.cfg.s.bdDLSAP.tei[3]  = 67;
+                               cfg.t.cfg.s.bdDLSAP.tei[4]  = 68;
+                               cfg.t.cfg.s.bdDLSAP.tei[5]  = 69;
+                               cfg.t.cfg.s.bdDLSAP.tei[6]  = 70;
+                               cfg.t.cfg.s.bdDLSAP.tei[7]  = 71;
+                       } else {
+                               cfg.t.cfg.s.bdDLSAP.teiAss  = AUTOMATIC;
+                               cfg.t.cfg.s.bdDLSAP.noOfDlc = 1;
+                       }
+               } else {
+                       /* Point to point configs */
+                       cfg.t.cfg.s.bdDLSAP.teiAss    = NON_AUTOMATIC;
+                       cfg.t.cfg.s.bdDLSAP.noOfDlc   = 1;
+                       cfg.t.cfg.s.bdDLSAP.tei[0]    = signal_data->tei;
+               }
+       }
+
+       if (sng_isdn_q921_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t sng_isdn_stack_cfg_q931_gen(void)
+{
+       InMngmt cfg;
+    Pst     pst;
+
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+
+    /* insert the destination Entity */
+    pst.dstEnt = ENTIN;
+
+    /*clear the configuration structure*/
+       memset(&cfg, 0, sizeof(cfg));
+
+    /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);
+
+    /*fill in the specific fields of the header*/
+    cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTIN;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STGEN;
+
+    /* fill in the Gen Conf structures internal pst struct */
+    stack_pst_init(&cfg.t.cfg.s.inGen.sm);
+
+       cfg.t.cfg.s.inGen.nmbSaps = MAX_VARIANTS+1;                     /* Total number of variants supported */
+
+       cfg.t.cfg.s.inGen.nmbLnks = MAX_L1_LINKS+1;                     /* number of Data Link SAPs */
+       cfg.t.cfg.s.inGen.nmbSigLnks = MAX_L1_LINKS+1;
+
+       /* number of CESs */
+       cfg.t.cfg.s.inGen.nmbCes = (MAX_L1_LINKS+1)*MAX_NUM_CES_PER_LINK;
+       /* number of global Call References can have 2 per channel when using HOLD/RESUME */
+       cfg.t.cfg.s.inGen.nmbCalRef = MAX_NUM_CALLS;
+       /* number of bearer channels */
+       cfg.t.cfg.s.inGen.nmbBearer = NUM_E1_CHANNELS_PER_SPAN*(MAX_L1_LINKS+1);
+       /* maximum number of routing entries */
+       cfg.t.cfg.s.inGen.nmbRouts = 0;
+       /* number of profiles */
+       cfg.t.cfg.s.inGen.nmbProfiles = 0;
+       /* upper pool threshold */
+       cfg.t.cfg.s.inGen.poolTrUpper = INGEN_POOL_UP_TR;
+       /* time resolution */
+       cfg.t.cfg.s.inGen.timeRes = 10;
+
+       cfg.t.cfg.s.inGen.sm.dstEnt = ENTSM;
+
+       if (sng_isdn_q931_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+/* Link between CC and q931 */
+ftdm_status_t sng_isdn_stack_cfg_q931_tsap(ftdm_span_t *span)
+{
+       InMngmt cfg;
+    Pst     pst;
+       unsigned i;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+
+    /* insert the destination Entity */
+    pst.dstEnt = ENTIN;
+
+    /*clear the configuration structure*/
+       memset(&cfg, 0, sizeof(cfg));
+
+    /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);
+
+    /*fill in the specific fields of the header*/
+    cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTIN;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STTSAP;
+
+       cfg.t.cfg.s.inTSAP.sapId = signal_data->cc_id;
+
+       cfg.t.cfg.s.inTSAP.prior = PRIOR0;
+       cfg.t.cfg.s.inTSAP.route = RTESPEC;
+
+       cfg.t.cfg.s.inTSAP.swtch = sng_isdn_stack_switchtype(signal_data->switchtype);
+       cfg.t.cfg.s.inTSAP.useSubAdr = 0;                                               /* call routing on subaddress */
+       cfg.t.cfg.s.inTSAP.adrPref = 0;                                                 /* use of prefix for int'l calls */
+       cfg.t.cfg.s.inTSAP.nmbPrefDig = 0;                                              /* number of digits used for prefix */
+
+       for (i = 0; i < IN_MAXPREFDIG; i++)
+               cfg.t.cfg.s.inTSAP.prefix[i] = 0;                                       /* address prefix */
+
+       cfg.t.cfg.s.inTSAP.keyPad = 0;
+       cfg.t.cfg.s.inTSAP.wcRout = 0;
+
+       for (i = 0; i < ADRLEN; i++)
+               cfg.t.cfg.s.inTSAP.wcMask[i] = 0;       /* address prefix */
+
+       cfg.t.cfg.s.inTSAP.sidIns = FALSE;              /* SID insertion Flag */
+       cfg.t.cfg.s.inTSAP.sid.length = 0;              /* SID */
+       cfg.t.cfg.s.inTSAP.sidTon = 0;                  /* SID Type of Number */
+       cfg.t.cfg.s.inTSAP.sidNPlan = 0;                /* SID Numbering Plan */
+       cfg.t.cfg.s.inTSAP.callId.len = 0;              /* Default Call Identity */
+       cfg.t.cfg.s.inTSAP.minAdrDig = 0;               /* Minimum number of address digits */
+       cfg.t.cfg.s.inTSAP.comptChck = FALSE;   /* Validate compatibility */
+       cfg.t.cfg.s.inTSAP.nmbApplProf = 0;             /* Number of application profiles */
+       cfg.t.cfg.s.inTSAP.profNmb[0] = 0;              /* Application profiles */
+       cfg.t.cfg.s.inTSAP.mem.region = S_REG;
+       cfg.t.cfg.s.inTSAP.mem.pool = S_POOL;
+       cfg.t.cfg.s.inTSAP.selector = 0;
+
+
+       if (sng_isdn_q931_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t sng_isdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
+{
+       InMngmt cfg;
+    Pst     pst;
+
+       unsigned i;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+
+    /* insert the destination Entity */
+    pst.dstEnt = ENTIN;
+
+    /*clear the configuration structure*/
+       memset(&cfg, 0, sizeof(cfg));
+
+    /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);
+
+    /*fill in the specific fields of the header*/
+    cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTIN;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STDLSAP;
+
+       cfg.hdr.response.selector=0;
+
+       cfg.t.cfg.s.inDLSAP.sapId = signal_data->link_id;
+       cfg.t.cfg.s.inDLSAP.spId = signal_data->link_id;
+       cfg.t.cfg.s.inDLSAP.swtch = sng_isdn_stack_switchtype(signal_data->switchtype);
+
+       cfg.t.cfg.s.inDLSAP.n201 = 1024;
+       cfg.t.cfg.s.inDLSAP.nmbRst = 2;
+       cfg.t.cfg.s.inDLSAP.tCbCfg = TRUE;
+
+       cfg.t.cfg.s.inDLSAP.tCbId = signal_data->cc_id;
+
+       /* TODO : NFAS configuration */
+       cfg.t.cfg.s.inDLSAP.nfasInt = FALSE; /* pass this later */
+
+       if (!cfg.t.cfg.s.inDLSAP.nfasInt) {
+               cfg.t.cfg.s.inDLSAP.intId = 0;
+               cfg.t.cfg.s.inDLSAP.sigInt = 0;
+               cfg.t.cfg.s.inDLSAP.bupInt = 0;
+               cfg.t.cfg.s.inDLSAP.nmbNfasInt = 0;
+               cfg.t.cfg.s.inDLSAP.buIntPr = FALSE;
+
+               for (i = 0; i < IN_MAX_NMB_INTRFS; i++)
+                       cfg.t.cfg.s.inDLSAP.ctldInt[i] = IN_INT_NOT_CFGD;
+
+       } else {
+               /* Need to get these parameters from NFAS */
+               cfg.t.cfg.s.inDLSAP.intId = 0;
+               cfg.t.cfg.s.inDLSAP.sigInt = 0;
+               cfg.t.cfg.s.inDLSAP.bupInt = 1;
+               cfg.t.cfg.s.inDLSAP.nmbNfasInt = 2;
+               cfg.t.cfg.s.inDLSAP.buIntPr = 1;
+
+               for (i = 0; i < IN_MAX_NMB_INTRFS; i++)
+                       cfg.t.cfg.s.inDLSAP.ctldInt[i] = IN_INT_NOT_CFGD;
+
+               /* For primary and backup interfaces, need to initialize this array */
+               cfg.t.cfg.s.inDLSAP.ctldInt[0] = 0; /* This is primary if for NFAS */
+               cfg.t.cfg.s.inDLSAP.ctldInt[1] = 1;
+       }
+
+       cfg.t.cfg.s.inDLSAP.numRstInd = 255;
+       cfg.t.cfg.s.inDLSAP.ackOpt = TRUE;
+       cfg.t.cfg.s.inDLSAP.relOpt = TRUE;
+#ifdef ISDN_SRV
+       cfg.t.cfg.s.inDLSAP.bcas = FALSE;
+       cfg.t.cfg.s.inDLSAP.maxBSrvCnt = 2;
+       cfg.t.cfg.s.inDLSAP.maxDSrvCnt = 2;
+#endif /* ISDN_SRV */
+       
+       if (signal_data->signalling == SNGISDN_SIGNALING_NET) {
+               cfg.t.cfg.s.inDLSAP.intType = NETWORK;
+               cfg.t.cfg.s.inDLSAP.clrGlr = FALSE;                     /* in case of glare, do not clear local call */
+               cfg.t.cfg.s.inDLSAP.statEnqOpt = TRUE;
+               if (span->trunk_type == FTDM_TRUNK_BRI ||
+                       span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+                       cfg.t.cfg.s.inDLSAP.rstOpt = FALSE;
+               } else {
+                       cfg.t.cfg.s.inDLSAP.rstOpt = TRUE;
+               }
+       } else {
+               cfg.t.cfg.s.inDLSAP.intType = USER;
+               cfg.t.cfg.s.inDLSAP.clrGlr = TRUE;                      /* in case of glare, clear local call */
+               cfg.t.cfg.s.inDLSAP.statEnqOpt = FALSE;
+               cfg.t.cfg.s.inDLSAP.rstOpt = FALSE;
+       }
+               
+       for (i = 0; i < IN_MAXBCHNL; i++)
+       {
+               cfg.t.cfg.s.inDLSAP.bProf[i].profNmb = 0;
+               cfg.t.cfg.s.inDLSAP.bProf[i].valid = FALSE;
+               cfg.t.cfg.s.inDLSAP.bProf[i].state = IN_PROV_AVAIL;
+       }
+
+       if (span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
+               signal_data->signalling == SNGISDN_SIGNALING_NET) {
+               cfg.t.cfg.s.inDLSAP.nmbCes = MAX_NUM_CES_PER_LINK;
+       } else {
+               cfg.t.cfg.s.inDLSAP.nmbCes=1;
+       }
+       
+       cfg.t.cfg.s.inDLSAP.useSubAdr = 0;       /* call routing on subaddress */
+       cfg.t.cfg.s.inDLSAP.adrPref = 0;         /* use of prefix for international calls */
+       cfg.t.cfg.s.inDLSAP.nmbPrefDig = 0;      /* number of digits used for prefix */
+       for (i = 0; i < IN_MAXPREFDIG; i++)
+               cfg.t.cfg.s.inDLSAP.prefix[i] = 0;       /* address prefix */
+       cfg.t.cfg.s.inDLSAP.keyPad = 0;
+       cfg.t.cfg.s.inDLSAP.wcRout = 0;
+       for (i = 0; i < ADRLEN; i++)
+               cfg.t.cfg.s.inDLSAP.wcMask[i] = 0;       /* address prefix */
+
+       cfg.t.cfg.s.inDLSAP.sidIns = FALSE;         /* SID insertion flag */
+       cfg.t.cfg.s.inDLSAP.sid.length = 0;                             /* SID */
+       cfg.t.cfg.s.inDLSAP.sidTon = 0;             /* SID Type of Number */
+       cfg.t.cfg.s.inDLSAP.sidNPlan = 0;           /* SID Numbering Plan */
+       cfg.t.cfg.s.inDLSAP.sidPresInd = FALSE;         /* SID Presentation Indicator */
+       cfg.t.cfg.s.inDLSAP.minAdrDig = 0;          /* minimum number of address digits */
+       cfg.t.cfg.s.inDLSAP.srvOpt = FALSE;
+       cfg.t.cfg.s.inDLSAP.callId.len = 0;         /* default call id */
+       cfg.t.cfg.s.inDLSAP.redirSubsc = FALSE;      /* subscription to call redirection */
+       cfg.t.cfg.s.inDLSAP.redirAdr.eh.pres = NOTPRSNT; /* redirAdr Numbering Plan */
+       cfg.t.cfg.s.inDLSAP.forwSubsc = FALSE;        /* programmed forwarding subscription */
+       cfg.t.cfg.s.inDLSAP.cndSubsc = TRUE;         /* calling adddress delivery service subscription */
+
+       /* TODO: Fill in these timers with proper values - eventually pass them */
+       cfg.t.cfg.s.inDLSAP.tmr.t301.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t301.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t302.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t302.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t303.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t303.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t304.enb = TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.t304.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t305.enb = TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.t305.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t306.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t306.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t307.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t307.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t308.enb = TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.t308.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t310.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t310.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t312.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t312.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t313.enb = TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.t313.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t316.enb = TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.t316.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t316c.enb = TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.t316c.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t318.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t318.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t319.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t319.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t322.enb = TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.t322.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.t332.enb = FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.t332.val = 35;
+       cfg.t.cfg.s.inDLSAP.tmr.tRst.enb = TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.tRst.val = 8;
+       cfg.t.cfg.s.inDLSAP.tmr.tAns.enb = FALSE;  /* non-standard timer */
+       cfg.t.cfg.s.inDLSAP.tmr.t396.enb = FALSE;  /* non-standard timer */
+       cfg.t.cfg.s.inDLSAP.tmr.t397.enb = TRUE;  /* non-standard timer */
+       cfg.t.cfg.s.inDLSAP.tmr.tProg.enb= TRUE;
+       cfg.t.cfg.s.inDLSAP.tmr.tProg.val= 35;
+#ifdef NI2
+#ifdef NI2_TREST
+       cfg.t.cfg.s.inDLSAP.tmr.tRest.enb= FALSE;
+       cfg.t.cfg.s.inDLSAP.tmr.tRest.val= 35;    /* tRest timer for NI2 */
+#endif /* NI2_TREST */
+#endif /* NI2 */
+
+       cfg.t.cfg.s.inDLSAP.dstEnt = ENTLD;
+       cfg.t.cfg.s.inDLSAP.dstInst = S_INST;
+       cfg.t.cfg.s.inDLSAP.dstProcId = SFndProcId();
+       cfg.t.cfg.s.inDLSAP.prior = PRIOR0;
+       cfg.t.cfg.s.inDLSAP.route = RTESPEC;
+       cfg.t.cfg.s.inDLSAP.selector = 0;
+       cfg.t.cfg.s.inDLSAP.mem.region = S_REG;
+       cfg.t.cfg.s.inDLSAP.mem.pool = S_POOL;
+
+       switch (span->trunk_type) {
+               case FTDM_TRUNK_E1:
+                       cfg.t.cfg.s.inDLSAP.dChannelNum = 16;
+                       cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_E1_CHANNELS_PER_SPAN;
+                       cfg.t.cfg.s.inDLSAP.firstBChanNum = 0;
+                       cfg.t.cfg.s.inDLSAP.callRefLen = 2;
+                       cfg.t.cfg.s.inDLSAP.teiAlloc = IN_STATIC;
+                       cfg.t.cfg.s.inDLSAP.intCfg = IN_INTCFG_PTPT;
+                       break;
+               case FTDM_TRUNK_T1:
+               case FTDM_TRUNK_J1:
+                               /* if NFAS, could be 0 if no signalling */
+                       cfg.t.cfg.s.inDLSAP.dChannelNum = 24;
+                       cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_T1_CHANNELS_PER_SPAN;
+                       cfg.t.cfg.s.inDLSAP.firstBChanNum = 1;
+                       cfg.t.cfg.s.inDLSAP.callRefLen = 2;
+                       cfg.t.cfg.s.inDLSAP.teiAlloc = IN_STATIC;
+                       cfg.t.cfg.s.inDLSAP.intCfg = IN_INTCFG_PTPT;
+                       break;
+               case FTDM_TRUNK_BRI:
+                       cfg.t.cfg.s.inDLSAP.dChannelNum = 0; /* Unused for BRI */
+                       cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_BRI_CHANNELS_PER_SPAN;
+                       cfg.t.cfg.s.inDLSAP.firstBChanNum = 1;
+                       cfg.t.cfg.s.inDLSAP.callRefLen = 1;
+                       cfg.t.cfg.s.inDLSAP.teiAlloc = IN_STATIC;
+                       cfg.t.cfg.s.inDLSAP.intCfg = IN_INTCFG_PTPT;
+                       break;
+               case FTDM_TRUNK_BRI_PTMP:
+                       cfg.t.cfg.s.inDLSAP.dChannelNum = 0; /* Unused for BRI */
+                       cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_BRI_CHANNELS_PER_SPAN;
+                       cfg.t.cfg.s.inDLSAP.firstBChanNum = 1;
+                       cfg.t.cfg.s.inDLSAP.callRefLen = 1;
+                       cfg.t.cfg.s.inDLSAP.teiAlloc = IN_DYNAMIC;
+                       cfg.t.cfg.s.inDLSAP.intCfg = IN_INTCFG_MULTI;
+                       break;
+               default:
+                       ftdm_log(FTDM_LOG_ERROR, "%s: Unsupported trunk_type\n", span->name);
+                       return FTDM_FAIL;
+       }
+
+       if (sng_isdn_q931_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t sng_isdn_stack_cfg_q931_lce(ftdm_span_t *span)
+{
+       InMngmt cfg;
+    Pst     pst;
+       uint8_t i;
+       uint8_t numCes=1;       
+
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+       if (span->trunk_type == FTDM_TRUNK_BRI_PTMP && signal_data->signalling == SNGISDN_SIGNALING_NET) {
+               numCes = 8;
+       }
+    /* initalize the post structure */
+    stack_pst_init(&pst);
+
+    /* insert the destination Entity */
+    pst.dstEnt = ENTIN;
+
+    /*clear the configuration structure*/
+       memset(&cfg, 0, sizeof(cfg));
+
+    /*fill in some general sections of the header*/
+    stack_hdr_init(&cfg.hdr);  
+
+    /*fill in the specific fields of the header*/
+    cfg.hdr.msgType     = TCFG;
+    cfg.hdr.entId.ent   = ENTIN;
+    cfg.hdr.entId.inst  = S_INST;
+    cfg.hdr.elmId.elmnt = STDLC;
+
+       cfg.hdr.response.selector=0;
+
+       cfg.t.cfg.s.inLCe.sapId = signal_data->link_id;
+       
+
+       cfg.t.cfg.s.inLCe.lnkUpDwnInd = TRUE;
+       cfg.t.cfg.s.inLCe.tCon.enb = TRUE;
+       cfg.t.cfg.s.inLCe.tCon.val = 35;
+       cfg.t.cfg.s.inLCe.tDisc.enb = TRUE;
+       cfg.t.cfg.s.inLCe.tDisc.val = 35;
+       cfg.t.cfg.s.inLCe.t314.enb = FALSE; /* if segmentation enabled, set to TRUE */
+       cfg.t.cfg.s.inLCe.t314.val = 35;
+               
+       cfg.t.cfg.s.inLCe.t332i.enb = FALSE; /* set to TRUE for NFAS */
+
+#ifdef NFAS
+       cfg.t.cfg.s.inLCe.t332i.val = 35;
+#else
+       cfg.t.cfg.s.inLCe.t332i.val = 0;
+#endif
+
+#if (ISDN_NI1 || ISDN_NT || ISDN_ATT)
+       cfg.t.cfg.s.inLCe.tSpid.enb = TRUE;
+       cfg.t.cfg.s.inLCe.tSpid.val = 5;
+
+       /* In case we want to support BRI - NORTH America, we will need to configure 8 spid's per CES */
+       cfg.t.cfg.s.inLCe.spid.pres = NOTPRSNT;
+       cfg.t.cfg.s.inLCe.spid.len = 0;
+#endif
+       cfg.t.cfg.s.inLCe.tRstAck.enb = TRUE;
+       cfg.t.cfg.s.inLCe.tRstAck.val = 10;
+
+
+       cfg.t.cfg.s.inLCe.usid = 0;
+       cfg.t.cfg.s.inLCe.tid = 0;
+
+       for(i=0;i<numCes;i++) {
+               cfg.t.cfg.s.inLCe.ces = i;
+               if (sng_isdn_q931_config(&pst, &cfg)) {
+                       return FTDM_FAIL;
+               }
+       }
+
+       return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t sng_isdn_stack_cfg_cc_gen(void)
+{
+       CcMngmt cfg;
+       Pst     pst;
+
+       /* initalize the post structure */
+       stack_pst_init(&pst);
+
+       /* insert the destination Entity */
+       pst.dstEnt = ENTCC;
+
+       /*clear the configuration structure*/
+       memset(&cfg, 0, sizeof(cfg));
+
+       /*fill in some general sections of the header*/
+       stack_hdr_init(&cfg.hdr);
+
+       /*fill in the specific fields of the header*/
+       cfg.hdr.msgType     = TCFG;
+       cfg.hdr.entId.ent   = ENTCC;
+       cfg.hdr.entId.inst  = S_INST;
+       cfg.hdr.elmId.elmnt = STGEN;
+
+       /* fill in the Gen Conf structures internal pst struct */
+       stack_pst_init(&cfg.t.cfg.s.ccGenCfg.smPst);
+       cfg.t.cfg.s.ccGenCfg.smPst.dstEnt = ENTSM;
+
+       cfg.t.cfg.s.ccGenCfg.poolTrLower = 2;
+       cfg.t.cfg.s.ccGenCfg.poolTrUpper = 4;
+       cfg.t.cfg.s.ccGenCfg.nmbSaps     = MAX_VARIANTS+1; /* Set to number of variants + 1 */
+
+       if (sng_isdn_cc_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t sng_isdn_stack_cfg_cc_sap(ftdm_span_t *span)
+{
+       CcMngmt cfg;
+       Pst     pst;
+
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+       /* initalize the post structure */
+       stack_pst_init(&pst);
+
+       /* insert the destination Entity */
+       pst.dstEnt = ENTCC;
+
+       /*clear the configuration structure*/
+       memset(&cfg, 0, sizeof(cfg));
+
+       /*fill in some general sections of the header*/
+       stack_hdr_init(&cfg.hdr);
+
+       /*fill in the specific fields of the header*/
+       cfg.hdr.msgType     = TCFG;
+       cfg.hdr.entId.ent   = ENTCC;
+       cfg.hdr.entId.inst  = S_INST;
+       cfg.hdr.elmId.elmnt = STTSAP;
+
+       cfg.t.cfg.s.ccISAP.pst.srcProcId        = SFndProcId();
+    cfg.t.cfg.s.ccISAP.pst.srcEnt              = ENTCC;
+    cfg.t.cfg.s.ccISAP.pst.srcInst             = S_INST;
+       cfg.t.cfg.s.ccISAP.pst.dstEnt           = ENTIN;
+       cfg.t.cfg.s.ccISAP.pst.dstInst          = S_INST;
+       cfg.t.cfg.s.ccISAP.pst.dstProcId        = SFndProcId();
+
+    cfg.t.cfg.s.ccISAP.pst.prior               = PRIOR0;
+    cfg.t.cfg.s.ccISAP.pst.route               = RTESPEC;
+    cfg.t.cfg.s.ccISAP.pst.region              = S_REG;
+    cfg.t.cfg.s.ccISAP.pst.pool                        = S_POOL;
+    cfg.t.cfg.s.ccISAP.pst.selector            = 0;
+
+       cfg.t.cfg.s.ccISAP.suId                         = signal_data->cc_id;
+       cfg.t.cfg.s.ccISAP.spId                         = signal_data->cc_id;
+
+       cfg.t.cfg.s.ccISAP.swtch                        = sng_isdn_stack_switchtype(signal_data->switchtype);
+       cfg.t.cfg.s.ccISAP.sapType                      = SNG_SAP_TYPE_ISDN;
+
+       if (sng_isdn_cc_config(&pst, &cfg)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+/* TODO: see if we can move this to inside the library */
+void stack_pst_init(Pst *pst)
+{
+       memset(pst, 0, sizeof(Pst));
+        /*fill in the post structure*/
+    pst->dstProcId   = SFndProcId();
+    pst->dstInst     = S_INST;
+
+    pst->srcProcId   = SFndProcId();
+    pst->srcEnt      = ENTSM;
+    pst->srcInst     = S_INST;
+
+    pst->prior       = PRIOR0;
+    pst->route       = RTESPEC;
+    pst->region      = S_REG;
+    pst->pool        = S_POOL;
+    pst->selector    = 0;
+       return;
+}
+
+
+
+void stack_hdr_init(Header *hdr)
+{
+       hdr->msgType                = 0;
+    hdr->msgLen                 = 0;
+    hdr->entId.ent              = 0;
+    hdr->entId.inst             = 0;
+    hdr->elmId.elmnt            = 0;
+    hdr->elmId.elmntInst1       = 0;
+    hdr->elmId.elmntInst2       = 0;
+    hdr->elmId.elmntInst3       = 0;
+    hdr->seqNmb                 = 0;
+    hdr->version                = 0;
+    hdr->response.prior         = PRIOR0;
+    hdr->response.route         = RTESPEC;
+    hdr->response.mem.region    = S_REG;
+    hdr->response.mem.pool      = S_POOL;
+    hdr->transId                = 0;
+    hdr->response.selector      = 0;
+       return;
+}
+
+uint8_t sng_isdn_stack_switchtype(sngisdn_switchtype_t switchtype)
+{
+       switch (switchtype) {
+               case SNGISDN_SWITCH_NI2:
+                       return SW_NI2;
+               case SNGISDN_SWITCH_5ESS:
+                       return SW_ATT5EP;
+               case SNGISDN_SWITCH_4ESS:
+                       return SW_ATT4E;
+               case SNGISDN_SWITCH_DMS100:
+                       return SW_NTDMS100P;
+               case SNGISDN_SWITCH_EUROISDN:
+                       return SW_ETSI;
+               case SNGISDN_SWITCH_QSIG:
+                       return SW_QSIG;
+               case SNGISDN_SWITCH_INSNET:
+                       return SW_QSIG;
+               case SNGISDN_SWITCH_INVALID:
+                       ftdm_log(FTDM_LOG_ERROR, "%s:Invalid switchtype:%d\n", switchtype);
+                       break;
+       }
+       return 0;
+}
+
+/* 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_isdn/ftmod_sangoma_isdn_stack_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c
new file mode 100644 (file)
index 0000000..ab2f1a3
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies 
+ * David Yat Sin <davidy@sangoma.com>
+ * Moises Silva <moy@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 "ftmod_sangoma_isdn.h"
+
+void stack_resp_hdr_init(Header *hdr);
+
+ftdm_status_t sng_isdn_cntrl_phy(ftdm_span_t *span);
+ftdm_status_t sng_isdn_cntrl_q921(ftdm_span_t *span);
+ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span);
+ftdm_status_t sng_isdn_cntrl_cc(ftdm_span_t *span);
+ftdm_status_t sng_isdn_cntrl_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt);
+
+ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span, uint8_t action, uint8_t subaction);
+ftdm_status_t sng_isdn_cntrl_q921(ftdm_span_t *span, uint8_t action, uint8_t subaction);
+
+extern ftdm_sngisdn_data_t     g_sngisdn_data;
+
+
+ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span)
+{
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+       if (sng_isdn_cntrl_q921(span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q921\n", span->name);
+               return FTDM_FAIL;
+       }
+       ftdm_log(FTDM_LOG_DEBUG, "%s:Stack q921 activated\n", span->name);
+       if (!g_sngisdn_data.ccs[signal_data->cc_id].activation_done) {
+               g_sngisdn_data.ccs[signal_data->cc_id].activation_done = 1;
+               if (sng_isdn_cntrl_cc(span) != FTDM_SUCCESS) {
+                       ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack CC\n", span->name);
+                       return FTDM_FAIL;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "%s:Stack CC activated\n", span->name);
+       }
+
+       if (sng_isdn_cntrl_q931(span) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q931\n", span->name);
+               return FTDM_FAIL;
+       }
+       ftdm_log(FTDM_LOG_DEBUG, "%s:Stack q931 activated\n", span->name);
+
+       ftdm_log(FTDM_LOG_INFO, "%s:Stack activated\n",span->name);
+       return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t sng_isdn_cntrl_phy(ftdm_span_t *span)
+{
+       L1Mngmt cntrl;
+    Pst pst;
+
+       ftdm_log(FTDM_LOG_ERROR, "%s:PHY control not implemented\n", span->name);
+       return FTDM_SUCCESS;
+       /* TODO: phy cntrl not implemented yet */
+
+       sng_isdn_phy_cntrl(&pst, &cntrl);
+       return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t sng_isdn_cntrl_q921(ftdm_span_t *span)
+{
+       ftdm_status_t status;
+       status = sng_isdn_cntrl_q921(span, ABND_ENA, NOTUSED);
+
+       /* Try to find an alternative for this */
+       /* LAPD will call LdUiDatBndCfm before it received a LdLiMacBndCfm from L1,
+               so we need to give some time before activating q931, as q931 will send a
+               LdUiDatConReq when activated, and this requires the Mac SAP to be already
+               bound first */
+
+       if (status == FTDM_SUCCESS) {
+               ftdm_sleep(500);
+       }       
+       return status;
+}
+
+ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span)
+{
+       /* TODO: remove this function later, just call sng_isdn_cntrl_q931 directly */
+       return sng_isdn_cntrl_q931(span, ABND_ENA, SAELMNT);
+}
+
+ftdm_status_t sng_isdn_cntrl_cc(ftdm_span_t *span)
+{
+       CcMngmt cntrl;;
+    Pst pst;
+
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+    /* initalize the post structure */
+   stack_pst_init(&pst);
+
+    /* insert the destination Entity */
+    pst.dstEnt = ENTCC;
+
+    /* initalize the control structure */
+       memset(&cntrl, 0, sizeof(cntrl));
+
+    /* initalize the control header */
+    stack_hdr_init(&cntrl.hdr);
+
+       cntrl.hdr.msgType = TCNTRL;                     /* configuration */
+       cntrl.hdr.entId.ent = ENTCC;            /* entity */
+       cntrl.hdr.entId.inst = S_INST;          /* instance */
+       cntrl.hdr.elmId.elmnt = STTSAP;         /* physical sap */
+
+       cntrl.t.cntrl.action = ABND_ENA;
+       cntrl.t.cntrl.subAction = SAELMNT;
+
+       cntrl.t.cntrl.sapId = signal_data->cc_id;
+       if (sng_isdn_cc_cntrl(&pst, &cntrl)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t sng_isdn_cntrl_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt)
+{
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+       switch (trace_opt) {
+               case SNGISDN_TRACE_DISABLE:
+                       if (sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q921)) {
+                               ftdm_log(FTDM_LOG_INFO, "s%d Disabling q921 trace\n", signal_data->link_id);
+                               sngisdn_clear_trace_flag(signal_data, SNGISDN_TRACE_Q921);
+                               
+                               if (sng_isdn_cntrl_q921(span, ADISIMM, SAELMNT) != FTDM_SUCCESS) {
+                                       ftdm_log(FTDM_LOG_ERROR, "s%d Failed to disable q921 trace\n");
+                               }
+                       }
+                       if (sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q931)) {
+                               ftdm_log(FTDM_LOG_INFO, "s%d Disabling q931 trace\n", signal_data->link_id);
+                               sngisdn_clear_trace_flag(signal_data, SNGISDN_TRACE_Q931);
+
+                               if (sng_isdn_cntrl_q931(span, ADISIMM, SATRC) != FTDM_SUCCESS) {
+                                       ftdm_log(FTDM_LOG_ERROR, "s%d Failed to disable q931 trace\n");
+                               }
+                       }
+                       break;
+               case SNGISDN_TRACE_Q921:
+                       if (!sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q921)) {
+                               ftdm_log(FTDM_LOG_INFO, "s%d Enabling q921 trace\n", signal_data->link_id);
+                               sngisdn_set_trace_flag(signal_data, SNGISDN_TRACE_Q921);
+
+                               if (sng_isdn_cntrl_q921(span, AENA, SATRC) != FTDM_SUCCESS) {
+                                       ftdm_log(FTDM_LOG_ERROR, "s%d Failed to enable q921 trace\n");
+                               }
+                       }
+                       break;
+               case SNGISDN_TRACE_Q931:
+                       if (!sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q931)) {
+                               ftdm_log(FTDM_LOG_INFO, "s%d Enabling q931 trace\n", signal_data->link_id);
+                               sngisdn_set_trace_flag(signal_data, SNGISDN_TRACE_Q931);
+                               
+                               if (sng_isdn_cntrl_q931(span, AENA, SATRC) != FTDM_SUCCESS) {
+                                       ftdm_log(FTDM_LOG_ERROR, "s%d Failed to enable q931 trace\n");
+                               }
+                       }
+                       break;
+       }
+       return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span, uint8_t action, uint8_t subaction)
+{
+       InMngmt cntrl;;
+       Pst pst;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+       /* initalize the post structure */
+       stack_pst_init(&pst);
+
+       /* insert the destination Entity */
+       pst.dstEnt = ENTIN;
+
+       /* initalize the control structure */
+       memset(&cntrl, 0, sizeof(cntrl));
+
+       /* initalize the control header */
+       stack_hdr_init(&cntrl.hdr);
+
+       cntrl.hdr.msgType = TCNTRL;                     /* configuration */
+       cntrl.hdr.entId.ent = ENTIN;            /* entity */
+       cntrl.hdr.entId.inst = S_INST;          /* instance */
+       cntrl.hdr.elmId.elmnt = STDLSAP;        /* physical sap */
+
+       cntrl.t.cntrl.action = action;
+       cntrl.t.cntrl.subAction = subaction;
+
+       if (action == AENA && subaction == SATRC) {
+               cntrl.t.cntrl.trcLen = -1; /* Trace the entire message buffer */
+       }
+       cntrl.t.cntrl.sapId = signal_data->link_id;
+       cntrl.t.cntrl.ces = 0;
+
+       if(sng_isdn_q931_cntrl(&pst, &cntrl)) {
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;    
+
+}
+
+ftdm_status_t sng_isdn_cntrl_q921(ftdm_span_t *span, uint8_t action, uint8_t subaction)
+{
+       BdMngmt cntrl;
+       Pst pst;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+       /* initalize the post structure */
+       stack_pst_init(&pst);
+
+       /* insert the destination Entity */
+       pst.dstEnt = ENTLD;
+
+       /* initalize the control structure */
+       memset(&cntrl, 0, sizeof(cntrl));
+
+       /* initalize the control header */
+       stack_hdr_init(&cntrl.hdr);
+       /* build control request */
+       cntrl.hdr.msgType          = TCNTRL;
+       cntrl.hdr.entId.ent        = ENTLD;
+       cntrl.hdr.entId.inst       = S_INST;
+
+#if (SMBD_LMINT3 || BD_LMINT3)
+       stack_resp_hdr_init(&cntrl.hdr);
+#endif /* _LMINT3 */
+
+       cntrl.hdr.elmId.elmnt      = STMSAP;
+       cntrl.t.cntrl.action       = action;
+       cntrl.t.cntrl.subAction    = subaction;
+
+#if (SMBD_LMINT3 || BD_LMINT3)
+       cntrl.t.cntrl.lnkNmb       = signal_data->link_id;
+       cntrl.t.cntrl.sapi         = NOTUSED;
+       cntrl.t.cntrl.tei          = NOTUSED;
+#else /* _LMINT3 */
+       cntrl.hdr.elmId.elmntInst1 = signal_data->link_id;
+       cntrl.hdr.elmId.elmntInst2 = NOTUSED;
+       cntrl.hdr.elmId.elmntInst3 = NOTUSED;
+#endif /* _LMINT3 */
+
+       cntrl.t.cntrl.logInt       = NOTUSED;
+       cntrl.t.cntrl.trcLen       = NOTUSED;
+       if (action == AENA && subaction == SATRC) {
+               cntrl.t.cntrl.trcLen = -1; /* Trace the entire message buffer */
+       }
+
+       SGetDateTime(&(cntrl.t.cntrl.dt));
+       if(sng_isdn_q921_cntrl(&pst, &cntrl)) {
+               return FTDM_FAIL;
+       }
+
+       return FTDM_SUCCESS;
+}
+
+
+void stack_resp_hdr_init(Header *hdr)
+{ 
+       hdr->response.selector   = 0;
+       hdr->response.mem.region = RTESPEC;
+       hdr->response.mem.pool   = S_POOL;
+       hdr->response.prior      = PRIOR0;
+       hdr->response.route      = RTESPEC;
+
+       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_isdn/ftmod_sangoma_isdn_stack_in.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_in.c
new file mode 100644 (file)
index 0000000..04430cf
--- /dev/null
@@ -0,0 +1,935 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * David Yat Sin <davidy@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 "ftmod_sangoma_isdn.h"
+
+extern ftdm_status_t cpy_calling_num_from_sngisdn(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb);
+extern ftdm_status_t cpy_called_num_from_sngisdn(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb);
+extern ftdm_status_t cpy_called_name_from_sngisdn(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb);
+extern ftdm_status_t cpy_calling_name_from_sngisdn(ftdm_caller_data_t *ftdm, ConEvnt *conEvnt);
+extern void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len);
+extern void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len);
+extern void get_memory_info(void);
+
+extern ftdm_sngisdn_data_t     g_sngisdn_data;
+
+#define MAX_DECODE_STR_LEN 2000
+
+/* Remote side transmit a SETUP */
+void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       uint8_t bchan_no = 0;
+       sngisdn_chan_data_t *sngisdn_info;
+       ftdm_channel_t *ftdmchan;
+       /*sngisdn_span_data_t *span_info;*/
+       
+       ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d dChan:%d ces:%d\n", __FUNCTION__, suId, suInstId, spInstId, dChan, ces);
+
+       ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n");
+       ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n");
+       ftdm_assert(g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] == NULL, "Con Ind on busy spInstId");
+       
+       if (conEvnt->chanId.eh.pres != PRSNT_NODEF) {
+               /* TODO: Implement me */
+               ftdm_log(FTDM_LOG_ERROR, "Incoming call without Channel Id not supported yet\n");
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+               return;
+       }
+
+       if (conEvnt->chanId.chanNmbSlotMap.pres) {
+               bchan_no = conEvnt->chanId.chanNmbSlotMap.val[0];
+       } else if (conEvnt->chanId.infoChanSel.pres) {
+               bchan_no = conEvnt->chanId.infoChanSel.val;
+       }
+
+       if (!bchan_no) {
+               ftdm_log(FTDM_LOG_ERROR, "Failed to obtain b-channel number from SETUP message\n");
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+               return;
+       }
+
+       if (g_sngisdn_data.dchans[dChan].channels[bchan_no] == NULL) {
+               ftdm_log(FTDM_LOG_ERROR, "Incoming call on unconfigured b-channel:%d\n", bchan_no);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+               return;
+       }
+
+       sngisdn_info = g_sngisdn_data.dchans[dChan].channels[bchan_no];
+       ftdmchan = sngisdn_info->ftdmchan;
+       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) != FTDM_SUCCESS) {
+        ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
+        ftdm_mutex_unlock(ftdmchan->mutex);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received SETUP\n");
+       switch (ftdmchan->state){
+               case FTDM_CHANNEL_STATE_DOWN: /* Proper state to receive a SETUP */
+                       sngisdn_info->suInstId = get_unique_suInstId(suId);
+                       sngisdn_info->spInstId = spInstId;
+                       g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
+                       g_sngisdn_data.ccs[suId].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info;
+
+                       /* try to open the channel */
+                       if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to open channel");
+                               sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_REL);
+                               ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE;
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+                       } else {
+                               /* Fill in call information */
+                               cpy_calling_num_from_sngisdn(&ftdmchan->caller_data, &conEvnt->cgPtyNmb);
+                               cpy_called_num_from_sngisdn(&ftdmchan->caller_data, &conEvnt->cdPtyNmb);
+                               cpy_calling_name_from_sngisdn(&ftdmchan->caller_data, conEvnt);
+
+                               /* Get ani2 */
+#if 0
+                               /* TODO: confirm that this works in the field */
+                               if (conEvnt->niOperSysAcc.eh.pres) {
+                                       if (conEvnt->niOperSysAcc.typeAcc.pres) {
+                                               ftdmchan->caller_data.aniII = (uint8_t)conEvnt->niOperSysAcc.typeAcc.val;
+                                               ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Received ANI: type of access:%x", conEvnt->niOperSysAcc.typeAcc.val);
+                                       }
+                                       if (conEvnt->niOperSysAcc.typeServ.pres) {
+                                               ftdmchan->caller_data.aniII = (uint8_t)conEvnt->niOperSysAcc.typeServ.val;
+                                               ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Received ANI: type of service:%x", conEvnt->niOperSysAcc.typeServ.val);
+                                       }
+                               }
+#endif
+
+                               /* 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);
+
+                       }
+                       break;
+               case FTDM_CHANNEL_STATE_DIALING:        /* glare */
+                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Received SETUP in DIALING state, glare, queueing incoming call\n");
+                        /* the flag the channel as having a collision */
+                       sngisdn_set_flag(sngisdn_info, FLAG_GLARE);
+
+                       /* save the SETUP for processing once the channel has gone to DOWN */
+                       memcpy(&sngisdn_info->glare.setup, conEvnt, sizeof(*conEvnt));
+                       sngisdn_info->glare.suId = suId;
+                       sngisdn_info->glare.suInstId = suInstId;
+                       sngisdn_info->glare.spInstId = spInstId;
+                       sngisdn_info->glare.dChan = dChan;
+                       sngisdn_info->glare.ces = ces;
+                       break;
+               default:
+                       ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received SETUP in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
+                       break;
+       }
+       ftdm_mutex_unlock(ftdmchan->mutex);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+/* Remote side transmit a CONNECT or CONNECT ACK */
+void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, int16_t dChan, uint8_t ces)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       sngisdn_chan_data_t *sngisdn_info;
+       ftdm_channel_t *ftdmchan;
+
+       ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d dChan:%d ces:%d\n", __FUNCTION__, suId, suInstId, spInstId, dChan, ces);
+
+       
+       ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n");
+       ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n");
+
+       if (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+               return;
+       }
+
+       ftdmchan = (ftdm_channel_t*)sngisdn_info->ftdmchan;
+
+       if (!sngisdn_info->spInstId) {
+               sngisdn_info->spInstId = spInstId;
+               g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
+       }
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received CONNECT/CONNECT ACK\n");
+       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) != FTDM_SUCCESS) {
+        ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
+        ftdm_mutex_unlock(ftdmchan->mutex);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+       if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
+               ((sngisdn_span_data_t*)ftdmchan->span->signal_data)->signalling == SNGISDN_SIGNALING_NET) {
+
+               if(sngisdn_info->ces == CES_MNGMNT) {
+                       /* We assign the call to the first TE */
+                       sngisdn_info->ces = ces;
+               } else {
+                       /* We already assigned this call, do nothing */
+                       ftdm_mutex_unlock(ftdmchan->mutex);
+                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call already assigned, ignoring connect\n");
+                       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+                       return;
+               }
+       }
+       
+       if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+               switch(ftdmchan->state) {
+                       case FTDM_CHANNEL_STATE_PROGRESS:
+                       case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+                       case FTDM_CHANNEL_STATE_DIALING:
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+                               break;
+                       default:
+                               ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received CONNECT/CONNECT ACK in an invalid state (%s)\n",
+                                               ftdm_channel_state2str(ftdmchan->state));
+
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                               break;
+               }
+       } else {
+               switch(ftdmchan->state) {
+                       case FTDM_CHANNEL_STATE_UP:
+                               /* This is the only valid state we should get a CONNECT ACK on */
+                               /* do nothing */
+                               break;
+                       default:
+                               ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                               break;
+               }
+       }
+       
+       ftdm_mutex_unlock(ftdmchan->mutex);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, uint8_t evntType, int16_t dChan, uint8_t ces)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       sngisdn_chan_data_t *sngisdn_info;
+       ftdm_channel_t *ftdmchan;
+
+       ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d dChan:%d ces:%d\n", __FUNCTION__, suId, suInstId, spInstId, dChan, ces);
+
+       ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n");
+       ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n");
+
+       if (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+               return;
+       }
+
+       if (!sngisdn_info->spInstId) {
+               sngisdn_info->spInstId = spInstId;
+               g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
+       }
+
+       ftdmchan = (ftdm_channel_t*)sngisdn_info->ftdmchan;
+       ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Received %s\n",
+                                                               (evntType == MI_ALERTING)?"ALERT":
+                                                               (evntType == MI_CALLPROC)?"PROCEED":
+                                                               (evntType == MI_PROGRESS)?"PROGRESS":"UNKNOWN");
+       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) != FTDM_SUCCESS) {
+        ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
+        ftdm_mutex_unlock(ftdmchan->mutex);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+       switch(ftdmchan->state) {
+               case FTDM_CHANNEL_STATE_DIALING:
+                       if (evntType == MI_PROGRESS) {
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+                       } else {
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+                       }
+                       break;
+               case FTDM_CHANNEL_STATE_PROGRESS:
+                       if (evntType == MI_PROGRESS) {
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+                       }
+                       break;
+               case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+                       /* Do nothing */
+                       break;
+               default:
+                       ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received ALERT/PROCEED/PROGRESS in an invalid state (%s)\n",
+                                       ftdm_channel_state2str(ftdmchan->state));
+
+                       ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                       break;
+       }
+
+       ftdm_mutex_unlock(ftdmchan->mutex);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, DiscEvnt *discEvnt)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       sngisdn_chan_data_t *sngisdn_info;
+       ftdm_channel_t *ftdmchan = NULL;
+
+       ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d\n", __FUNCTION__, suId, suInstId, spInstId);
+
+       ftdm_assert(spInstId != 0, "Received DISCONNECT with invalid id");
+
+       if (spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) {
+               ftdmchan = (ftdm_channel_t*)sngisdn_info->ftdmchan;
+       } else if (suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS) {
+               ftdmchan = (ftdm_channel_t*)sngisdn_info->ftdmchan;
+       } else {
+               ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+               return;
+       }
+
+       if (!sngisdn_info->spInstId) {
+               sngisdn_info->spInstId = spInstId;
+               g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
+       }
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received DISCONNECT\n");
+       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) != FTDM_SUCCESS) {
+        ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
+        ftdm_mutex_unlock(ftdmchan->mutex);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    }
+
+       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_COLLECT:
+               case FTDM_CHANNEL_STATE_UP:             
+                       if (discEvnt->causeDgn[0].eh.pres && discEvnt->causeDgn[0].causeVal.pres) {
+                               ftdmchan->caller_data.hangup_cause = discEvnt->causeDgn[0].causeVal.val;
+                       } else {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "DISCONNECT did not have a cause code\n");
+                               ftdmchan->caller_data.hangup_cause = 0;
+                       }
+                       sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_REL);
+                       ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+                       break;
+               default:
+                       ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received DISCONNECT in an invalid state (%s)\n",
+                                       ftdm_channel_state2str(ftdmchan->state));
+                       /* start reset procedure */
+                       ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                       break;
+       }
+
+       ftdm_mutex_unlock(ftdmchan->mutex);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_rel_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RelEvnt *relEvnt)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d\n", __FUNCTION__, suId, suInstId, spInstId);
+
+       sngisdn_chan_data_t  *sngisdn_info ;
+    ftdm_channel_t      *ftdmchan = NULL;
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+       if (suInstId && (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) {
+               ftdmchan = sngisdn_info->ftdmchan;
+       } else if (spInstId && (get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS)) {
+               ftdmchan = sngisdn_info->ftdmchan;
+       }
+
+       if (ftdmchan == NULL) {
+               ftdm_log(FTDM_LOG_CRIT, "Failed to find matching channel suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+               return;
+       }
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received RELEASE/RELEASE COMPLETE\n");
+    /* 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)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
+        ftdm_mutex_unlock(ftdmchan->mutex);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    };
+
+    /* 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;
+       case FTDM_CHANNEL_STATE_PROGRESS:
+       case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+               /* Remote side sent a SETUP, then a RELEASE COMPLETE to abort call - this is an abort */
+               sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
+               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+               break;
+       case FTDM_CHANNEL_STATE_DIALING:
+               /* Remote side rejected our SETUP message on outbound call */
+               sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
+               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+               break;
+       case FTDM_CHANNEL_STATE_UP:
+               sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
+               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+               break;
+    default:
+        /* Should just stop the call...but a reset is easier for now (since it does hangup the call) */
+               ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received RELEASE in an invalid state (%s)\n",
+                                       ftdm_channel_state2str(ftdmchan->state));
+
+        /* go to RESTART */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+
+        break;
+    /**************************************************************************/
+    }
+
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_dat_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, InfoEvnt *infoEvnt)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received DATA IND suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_sshl_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received SSHL IND suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received SSHL CFM suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received RESUME/RETRIEVE ind suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received RESUME/RETRIEVE CFM suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received FLOW CONTROL IND suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_fac_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, FacEvnt *facEvnt, uint8_t evntType, int16_t dChan, uint8_t ces)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received FACILITY IND suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_sta_cfm ( int16_t suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d\n", __FUNCTION__, suId, suInstId, spInstId);
+
+       sngisdn_chan_data_t  *sngisdn_info ;
+    ftdm_channel_t      *ftdmchan = NULL;
+       uint8_t                         call_state = 0;
+
+       if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) {
+               call_state = staEvnt->callSte.callGlblSte.val;
+       }
+
+    /* get the ftdmchan and ss7_chan_data from the circuit */
+       if (suInstId && (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) {
+               ftdmchan = sngisdn_info->ftdmchan;
+       } else if (spInstId && (get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS)) {
+               ftdmchan = sngisdn_info->ftdmchan;
+       }
+
+       if (ftdmchan == NULL) {
+               ftdm_log(FTDM_LOG_CRIT, "Failed to find matching channel suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+               return;
+       }
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received STATUS CONFIRM\n");
+    /* 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)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
+        ftdm_mutex_unlock(ftdmchan->mutex);
+               ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+        return;
+    };
+
+       if (staEvnt->causeDgn[0].eh.pres && staEvnt->causeDgn[0].causeVal.pres) {
+               if (staEvnt->causeDgn[0].causeVal.val != 30) {
+                       
+                       if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) {
+                               call_state = staEvnt->callSte.callGlblSte.val;
+                               /* Section 4.3.30 from INT Interface - Service Definition */
+                               ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val;
+
+
+                               /* There is incompatibility between local and remote side call states some Q931 msgs probably got lost - initiate disconnect  */
+                               ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Incompatible call states detected, remote side indicated state:%d our state:%s cause:%d\n", call_state, ftdm_channel_state2str(ftdmchan->state), staEvnt->causeDgn[0].causeVal.val);
+
+                               switch(call_state) {
+                                       /* Sere ITU-T Q931 for definition of call states */
+                                       case 0: /* Remote switch thinks there are no calls on this channel */
+                                               switch (ftdmchan->state) {
+                                                       case FTDM_CHANNEL_STATE_COLLECT:
+                                                       case FTDM_CHANNEL_STATE_DIALING:                                        
+                                                               sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
+                                                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+                                                               break;
+                                                       case FTDM_CHANNEL_STATE_TERMINATING:
+                                                               /* We are in the process of clearing local states,
+                                                                       just make sure we will not send any messages to remote switch */
+                                                               sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
+                                                               break;
+                                                       case FTDM_CHANNEL_STATE_HANGUP:
+                                                               /* This cannot happen, state_advance always sets
+                                                                       ftdmchan to STATE_HANGUP_COMPLETE when in STATE_HANGUP
+                                                                       and we called check_for_state_change earlier so something is very wrong here!!! */
+                                                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "How can we we in FTDM_CHANNEL_STATE_HANGUP after checking for state change?\n");
+                                                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                                                               break;
+                                                       case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+                                                               /* We were waiting for remote switch to send RELEASE COMPLETE
+                                                                       but this will not happen, so just clear local state */
+                                                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+                                                               break;
+                                                       case FTDM_CHANNEL_STATE_DOWN:
+                                                               /* If our local state is down as well, then there is nothing to do */
+                                                               break;
+                                                       default:
+                                                               ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
+                                                               break;
+                                               }
+                                               break;
+                                       case 8: /* Remote switch is in "Connect Request state" */
+                                               switch (ftdmchan->state) {
+                                                       case FTDM_CHANNEL_STATE_UP:
+                                                               /* This is ok. We sent a Connect, and we are waiting for a connect ack */
+                                                               /* Do nothing */
+                                                               break;
+                                                       case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+                                                               /* We hung up locally, but remote switch doesn't know send disconnect again*/
+                                                               sngisdn_snd_disconnect(ftdmchan);
+                                                               break;
+                                                       default:
+                                                               ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
+                                                               break;
+                                               }
+                                               break;
+                                       default:
+                                               ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
+                                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                                               break;                                  
+                               }
+                       } else {
+                               ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val;
+                               /* We could not extract the call state */
+                               ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Incompatible call states detected, but could not determine call (cause:%d)\n", ftdmchan->caller_data.hangup_cause);
+                               ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+                       }
+
+               }
+    /**************************************************************************/
+    }
+
+    /* unlock the channel */
+    ftdm_mutex_unlock(ftdmchan->mutex);
+
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_srv_ind ( int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received SERVICE IND suId:%d dChan:%d ces:%d\n", suId, dChan, ces);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_srv_cfm ( int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received SERVICE CFM suId:%d dChan:%d ces:%d\n", suId, dChan, ces);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evtType)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received RESTART IND suId:%d dChan:%d ces:%d\n", suId, dChan, ces);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+
+void sngisdn_rcv_rst_cfm ( int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evtType)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "Received RESTART CFM suId:%d dChan:%d ces:%d\n", suId, dChan, ces);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_phy_ind(SuId suId, Reason reason)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+    ftdm_log(FTDM_LOG_INFO, "[SNGISDN PHY] D-chan %d : %s\n", suId, DECODE_LL1_REASON(reason));
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+} 
+
+void sngisdn_rcv_q921_ind(BdMngmt *status)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+
+       unsigned j,k;
+       ftdm_span_t *ftdmspan = NULL;
+
+       for(j=1;j<=g_sngisdn_data.num_dchan;j++) {
+               for(k=1;k<=g_sngisdn_data.dchans[j].num_spans;k++) {
+                       if (g_sngisdn_data.dchans[j].spans[k]->link_id == status->t.usta.lnkNmb) {
+                               ftdmspan = (ftdm_span_t*)g_sngisdn_data.dchans[j].spans[k]->ftdm_span;
+                       }
+               }
+       }
+       if (ftdmspan == NULL) {
+               ftdm_log(FTDM_LOG_CRIT, "Received q921 status on unconfigured span\n", status->t.usta.lnkNmb);
+#ifdef DEBUG_MODE
+               FORCE_SEGFAULT
+#endif
+               return;
+       }
+
+       switch (status->t.usta.alarm.category) {
+               case (LCM_CATEGORY_INTERFACE):
+                       ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
+                                                       ftdmspan->name,
+                                                       DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
+                                                       DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
+                                                       DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
+                       break;
+               default:
+                       ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
+                                       ftdmspan->name,
+                                       DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
+                                       DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
+                                       DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
+                       break;
+       }
+       
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__)
+    return;
+}
+void sngisdn_rcv_q931_ind(InMngmt *status)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+
+       
+
+       ftdm_span_t *ftdmspan = NULL;
+       
+       if (status->t.usta.alarm.cause == 287) {
+               get_memory_info();
+               return;
+       }
+
+       switch (status->t.usta.alarm.category) {
+               case (LCM_CATEGORY_INTERFACE):
+                       ftdm_log(FTDM_LOG_WARNING, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n",
+                                                       status->t.usta.suId,
+                                                       DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
+                                                       DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
+                                                       DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
+
+                       /* clean this up later */
+
+                       switch (status->t.usta.alarm.event) {
+                               case LCM_EVENT_UP:
+                               case LCM_EVENT_DOWN:
+                                       {
+                                               unsigned j,k;
+                                               for(j=1;j<=g_sngisdn_data.num_dchan;j++) {
+                                                       for(k=1;k<=g_sngisdn_data.dchans[j].num_spans;k++) {
+                                                               if (g_sngisdn_data.dchans[j].spans[k]->link_id == status->t.usta.suId) {
+                                                                       ftdmspan = (ftdm_span_t*)g_sngisdn_data.dchans[j].spans[k]->ftdm_span;
+                                                               }
+                                                       }
+                                               }
+
+                                               if (ftdmspan == NULL) {
+                                                       ftdm_log(FTDM_LOG_CRIT, "Received q931 LCM EVENT on unconfigured span (suId:%d)\n", status->t.usta.suId);
+                                                       return;
+                                               }
+
+                                               sngisdn_set_span_sig_status(ftdmspan, (status->t.usta.alarm.event == LCM_EVENT_UP)?FTDM_SIG_STATE_UP:FTDM_SIG_STATE_DOWN);
+                                       }
+                                       break;
+                       }
+                       break;
+               default:
+                       ftdm_log(FTDM_LOG_DEBUG, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n",
+                                       status->t.usta.suId,
+                                       DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
+                                       DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
+                                       DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
+                       break;
+       }
+
+
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+       return;
+}
+
+void sngisdn_rcv_cc_ind(CcMngmt *status)
+{
+       ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+       ftdm_log(FTDM_LOG_INFO, "RECEIVED %s\n", __FUNCTION__);
+       ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
+    return;
+}
+
+#define Q931_TRC_EVENT(event) (event == TL3PKTTX)?"TX": \
+                                                               (event == TL3PKTRX)?"RX":"UNKNOWN"
+
+void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf)
+{
+       MsgLen mlen;
+       MsgLen i;
+       int16_t j;
+       Buffer *tmp;
+       Data *cptr;
+       uint8_t data;
+       uint8_t tdata[1000];
+       char *data_str = ftdm_calloc(1,MAX_DECODE_STR_LEN); /* TODO Find a proper size */
+       
+       ftdm_assert(mBuf != NULLP, "Received a Q931 trace with no buffer");
+       mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len;
+
+       if (mlen != 0) {
+               tmp = mBuf->b_cont;
+               cptr = tmp->b_rptr;
+               data = *cptr++;
+               i = 0;
+
+               for(j=0;j<mlen;j++) {
+                       tdata[j]= data;
+
+                       if (cptr == tmp->b_wptr) {
+                               tmp = tmp->b_cont;
+                               if (tmp) cptr = tmp->b_rptr;
+                       }
+                       data = *cptr++;
+               }
+
+               sngisdn_trace_q931(data_str, tdata, mlen);
+               ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] FRAME %s:%s\n", Q931_TRC_EVENT(trc->t.trc.evnt), data_str);
+       }
+
+       ftdm_safe_free(data_str);
+       /* We do not need to free mBuf in this case because stack does it */
+       /* SPutMsg(mBuf); */
+       return;
+}
+
+
+#define Q921_TRC_EVENT(event) (event == TL2FRMRX)?"RX": \
+                                                               (event == TL2FRMTX)?"TX": \
+                                                               (event == TL2TMR)?"TMR EXPIRED":"UNKNOWN"
+
+void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf)
+{
+       MsgLen mlen;
+       MsgLen i;
+       int16_t j;
+       Buffer *tmp;
+       Data *cptr;
+       uint8_t data;
+       uint8_t tdata[16];
+       char *data_str = ftdm_calloc(1,200); /* TODO Find a proper size */
+       
+
+       if (trc->t.trc.evnt == TL2TMR) {
+               goto end_of_trace;
+       }
+
+       ftdm_assert(mBuf != NULLP, "Received a Q921 trace with no buffer");
+       mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len;
+
+       if (mlen != 0) {
+               tmp = mBuf->b_cont;
+               cptr = tmp->b_rptr;
+               data = *cptr++;
+               i = 0;
+               while (i < mlen) {
+                       j = 0;
+                       for(j=0;j<16;j++) {
+                               if (i<mlen) {
+                                       tdata[j]= data;
+                               
+                                       if (cptr == tmp->b_wptr) {
+                                               tmp = tmp->b_cont;
+                                               if (tmp) cptr = tmp->b_rptr;
+                                       }
+                                       i++;
+                                       if (i<mlen) data = *cptr++;
+                               }
+                       }
+
+               }
+               sngisdn_trace_q921(data_str, tdata, mlen);
+               ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] FRAME %s:%s\n", Q921_TRC_EVENT(trc->t.trc.evnt), data_str);
+       }
+end_of_trace:
+       ftdm_safe_free(data_str);
+       SPutMsg(mBuf);
+       return;
+}
+
+
+
+void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...)
+{
+       char    *data;
+    int     ret;
+    va_list ap;
+
+    va_start(ap, fmt);
+    ret = ftdm_vasprintf(&data, fmt, ap);
+    if (ret == -1) {
+        return;
+    }
+
+    switch (level) {
+               case SNG_LOGLEVEL_DEBUG:
+                       ftdm_log(FTDM_LOG_DEBUG, "sng_isdn->%s", data);
+                       break;
+               case SNG_LOGLEVEL_WARN:
+                       ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
+                       break;
+               case SNG_LOGLEVEL_INFO:
+                       ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
+                       break;
+               case SNG_LOGLEVEL_STATS:
+                       ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
+                       break;
+               case SNG_LOGLEVEL_ERROR:
+                       ftdm_log(FTDM_LOG_ERROR, "sng_isdn->%s", data);
+#ifdef DEBUG_MODE
+                       FORCE_SEGFAULT
+#endif
+                       break;
+               case SNG_LOGLEVEL_CRIT:
+                       ftdm_log(FTDM_LOG_CRIT, "sng_isdn->%s", data);
+#ifdef DEBUG_MODE
+                       FORCE_SEGFAULT
+#endif
+                       break;
+               default:
+                       ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
+                       break;
+    }
+       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_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
new file mode 100644 (file)
index 0000000..c5e986b
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * David Yat Sin <davidy@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 "ftmod_sangoma_isdn.h"
+
+extern ftdm_status_t cpy_calling_num_to_sngisdn(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm);
+extern ftdm_status_t cpy_called_num_to_sngisdn(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm);
+extern ftdm_status_t cpy_calling_name_to_sngisdn(ConEvnt *conEvnt, ftdm_channel_t *ftdmchan);
+
+void sngisdn_snd_setup(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_progress(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_connect(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_release(ftdm_channel_t *ftdmchan);
+
+
+void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
+{
+       ConEvnt conEvnt;
+       sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;  
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending SETUP\n");
+
+       sngisdn_info->suInstId = get_unique_suInstId(signal_data->cc_id);
+       sngisdn_info->spInstId = 0;
+
+       memset(&conEvnt, 0, sizeof(conEvnt));
+       
+       conEvnt.bearCap[0].eh.pres = PRSNT_NODEF;
+       conEvnt.bearCap[0].infoTranCap.pres = PRSNT_NODEF;
+
+       conEvnt.bearCap[0].infoTranCap.val = IN_ITC_SPEECH;
+
+       conEvnt.bearCap[0].codeStand0.pres = PRSNT_NODEF;
+       conEvnt.bearCap[0].codeStand0.val = IN_CSTD_CCITT;
+       conEvnt.bearCap[0].infoTranRate0.pres = PRSNT_NODEF;
+       conEvnt.bearCap[0].infoTranRate0.val = IN_ITR_64KBIT;
+       conEvnt.bearCap[0].tranMode.pres = PRSNT_NODEF;
+       conEvnt.bearCap[0].tranMode.val = IN_TM_CIRCUIT;
+
+       conEvnt.chanId.eh.pres = PRSNT_NODEF;
+       conEvnt.chanId.prefExc.pres = PRSNT_NODEF;
+       conEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
+       conEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
+       conEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
+       conEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
+       conEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
+       conEvnt.chanId.intIdent.pres = NOTPRSNT;
+
+       if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
+               ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+               /* Trillium stack rejests lyr1Ident on BRI, but Netbricks always sends it.
+               Check with Trillium if this ever causes calls to fail in the field */
+
+               /* BRI only params */
+               conEvnt.chanId.intType.pres = PRSNT_NODEF;
+               conEvnt.chanId.intType.val = IN_IT_BASIC;
+               conEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
+               conEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
+       } else {
+               /* PRI only params */
+               if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
+                       conEvnt.bearCap[0].usrInfoLyr1Prot.pres = PRSNT_NODEF;
+                       conEvnt.bearCap[0].usrInfoLyr1Prot.val = IN_UIL1_G711ULAW;
+               } else {
+                       conEvnt.bearCap[0].usrInfoLyr1Prot.pres = PRSNT_NODEF;
+                       conEvnt.bearCap[0].usrInfoLyr1Prot.val = IN_UIL1_G711ALAW;
+               }
+               conEvnt.bearCap[0].lyr1Ident.pres = PRSNT_NODEF;
+               conEvnt.bearCap[0].lyr1Ident.val = IN_L1_IDENT;
+
+               conEvnt.chanId.intType.pres = PRSNT_NODEF;
+               conEvnt.chanId.intType.val = IN_IT_OTHER;
+               conEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
+               conEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
+               conEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
+               conEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
+               conEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
+               conEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
+               conEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
+               conEvnt.chanId.chanNmbSlotMap.len = 1;
+               conEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
+       }
+
+       conEvnt.progInd.eh.pres = PRSNT_NODEF;
+       conEvnt.progInd.location.pres = PRSNT_NODEF;
+       conEvnt.progInd.location.val = IN_LOC_USER;
+       conEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
+       conEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
+       conEvnt.progInd.progDesc.pres = PRSNT_NODEF;
+       conEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN; /* Not end-to-end ISDN */
+
+       if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
+               conEvnt.sndCmplt.eh.pres = PRSNT_NODEF;
+       }
+       if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
+               signal_data->signalling == SNGISDN_SIGNALING_NET) {
+               sngisdn_info->ces = CES_MNGMNT;
+       }
+       
+       cpy_calling_num_to_sngisdn(&conEvnt.cgPtyNmb, &ftdmchan->caller_data);
+       cpy_called_num_to_sngisdn(&conEvnt.cdPtyNmb, &ftdmchan->caller_data);
+       cpy_calling_name_to_sngisdn(&conEvnt, ftdmchan);
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con request on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+
+       if (sng_isdn_con_request(signal_data->cc_id, sngisdn_info->suInstId, &conEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused SETUP request\n");
+       }
+       return;
+}
+
+/* Used only for BRI PTMP */
+void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan)
+{
+       CnStEvnt cnStEvnt;
+       
+       sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+       memset(&cnStEvnt, 0, sizeof(cnStEvnt));
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT ACK\n");
+
+       cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
+       cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
+       cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
+       
+       if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
+               ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+
+               /* BRI only params */
+               cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.intType.val = IN_IT_BASIC;
+               cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
+       } else {
+               cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.intType.val = IN_IT_OTHER;
+               cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
+               cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
+               cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
+               cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
+               cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.chanNmbSlotMap.len = 1;
+               cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
+       }
+
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending connect ACK on suId:%d suInstId:%u spInstId:%u ces:%d\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_info->ces);
+
+       if(sng_isdn_con_comp(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT,      "stack refused CONNECT ACK request\n");
+       }
+       return;
+}
+
+
+void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan)
+{
+       CnStEvnt cnStEvnt;
+       
+       sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+       memset(&cnStEvnt, 0, sizeof(cnStEvnt));
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED\n");
+
+       cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
+       cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
+       cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
+       
+       if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
+               ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+
+               /* BRI only params */
+               cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.intType.val = IN_IT_BASIC;
+               cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
+       } else {
+               cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.intType.val = IN_IT_OTHER;
+               cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
+               cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
+               cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
+               cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
+               cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.chanNmbSlotMap.len = 1;
+               cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
+       }
+
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con status on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+
+       if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, MI_CALLPROC, signal_data->dchan_id, sngisdn_info->ces)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT,      "stack refused PROCEED request\n");
+       }
+       return;
+}
+
+void sngisdn_snd_progress(ftdm_channel_t *ftdmchan)
+{
+       CnStEvnt cnStEvnt;
+       
+       sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+       memset(&cnStEvnt, 0, sizeof(cnStEvnt));
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS\n");
+
+
+       cnStEvnt.progInd.eh.pres = PRSNT_NODEF;
+       cnStEvnt.progInd.location.pres = PRSNT_NODEF;
+       cnStEvnt.progInd.location.val = IN_LOC_USER;
+       cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
+       cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
+       cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
+       cnStEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN;
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con status on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+       if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, signal_data->dchan_id, sngisdn_info->ces)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT,      "stack refused PROGRESS request\n");
+       }
+       return;
+}
+
+void sngisdn_snd_alert(ftdm_channel_t *ftdmchan)
+{
+       CnStEvnt cnStEvnt;
+       
+       sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO,  "Sending ALERT\n");
+
+       memset(&cnStEvnt, 0, sizeof(cnStEvnt));
+
+       cnStEvnt.progInd.eh.pres = PRSNT_NODEF;
+       cnStEvnt.progInd.location.pres = PRSNT_NODEF;
+       cnStEvnt.progInd.location.val = IN_LOC_USER;
+       cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
+       cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
+       cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
+       cnStEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN;
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con status on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+
+       if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_ALERTING, signal_data->dchan_id, sngisdn_info->ces)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT,      "stack refused ALERT request\n");
+       }
+       return;
+}
+
+void sngisdn_snd_connect(ftdm_channel_t *ftdmchan)
+{
+       CnStEvnt cnStEvnt;
+       
+       sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT\n");
+
+       memset(&cnStEvnt, 0, sizeof(cnStEvnt));
+
+
+       cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
+       cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
+       cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
+       cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
+       
+       if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
+               ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+
+               /* BRI only params */
+               cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.intType.val = IN_IT_BASIC;
+               cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
+       } else {
+               cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.intType.val = IN_IT_OTHER;
+               cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
+               cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
+               cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
+               cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
+               cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
+               cnStEvnt.chanId.chanNmbSlotMap.len = 1;
+               cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
+       }
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con response on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+       if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused CONNECT request\n");
+       }
+       return;
+}
+
+void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan)
+{      
+       DiscEvnt discEvnt;
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending DISCONNECT\n");
+
+       sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+       memset(&discEvnt, 0, sizeof(discEvnt));
+       
+       /* Fill discEvnt here */        
+       discEvnt.causeDgn[0].eh.pres = PRSNT_NODEF;
+       discEvnt.causeDgn[0].location.pres = PRSNT_NODEF;
+       discEvnt.causeDgn[0].location.val = IN_LOC_PRIVNETLU;
+       discEvnt.causeDgn[0].codeStand3.pres = PRSNT_NODEF;
+       discEvnt.causeDgn[0].codeStand3.val = IN_CSTD_CCITT;
+       discEvnt.causeDgn[0].causeVal.pres = PRSNT_NODEF;
+       discEvnt.causeDgn[0].causeVal.val = ftdmchan->caller_data.hangup_cause;
+       discEvnt.causeDgn[0].recommend.pres = NOTPRSNT;
+       discEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT;
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending disc request on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+       if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused DISCONNECT request\n");
+       }
+       return;
+}
+void sngisdn_snd_release(ftdm_channel_t *ftdmchan)
+{
+       RelEvnt relEvnt;
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending RELEASE/RELEASE COMPLETE\n");
+
+       sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+       memset(&relEvnt, 0, sizeof(relEvnt));
+       
+       /* Fill discEvnt here */        
+       relEvnt.causeDgn[0].eh.pres = PRSNT_NODEF;
+       relEvnt.causeDgn[0].location.pres = PRSNT_NODEF;
+       relEvnt.causeDgn[0].location.val = IN_LOC_PRIVNETLU;
+       relEvnt.causeDgn[0].codeStand3.pres = PRSNT_NODEF;
+       relEvnt.causeDgn[0].codeStand3.val = IN_CSTD_CCITT;
+
+       relEvnt.causeDgn[0].causeVal.pres = PRSNT_NODEF;
+       relEvnt.causeDgn[0].causeVal.val = ftdmchan->caller_data.hangup_cause;
+       relEvnt.causeDgn[0].recommend.pres = NOTPRSNT;
+       relEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT;
+
+       ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending release request on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+
+       if (sng_isdn_release_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &relEvnt)) {
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused RELEASE/RELEASE COMPLETE request\n");
+       }       
+       return;
+}
+
+
+void sngisdn_snd_reset(ftdm_channel_t *ftdmchan)
+{
+       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending RESET\n");
+       ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "%s not implemented\n", __FUNCTION__);
+       /* TODO: implement me */
+       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_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
new file mode 100644 (file)
index 0000000..b922efc
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * David Yat Sin <davidy@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 "ftmod_sangoma_isdn.h"
+
+ftdm_status_t cpy_calling_num_from_sngisdn(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb);
+ftdm_status_t cpy_called_num_from_sngisdn(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb);
+ftdm_status_t cpy_redir_num_from_sngisdn(ftdm_caller_data_t *ftdm, RedirNmb *redirNmb);
+ftdm_status_t cpy_calling_name_from_sngisdn(ftdm_caller_data_t *ftdm, ConEvnt *conEvnt);
+
+ftdm_status_t cpy_calling_num_to_sngisdn(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm);
+ftdm_status_t cpy_called_num_to_sngisdn(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm);
+ftdm_status_t cpy_redir_num_to_sngisdn(RedirNmb *redirNmb, ftdm_caller_data_t *ftdm);
+ftdm_status_t cpy_calling_name_to_sngisdn(ConEvnt *conEvnt, ftdm_channel_t *ftdmchan);
+
+extern ftdm_sngisdn_data_t     g_sngisdn_data;
+void get_memory_info(void);
+
+void clear_call_data(sngisdn_chan_data_t *sngisdn_info)
+{
+       uint32_t cc_id = ((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->cc_id;
+
+       g_sngisdn_data.ccs[cc_id].active_spInstIds[sngisdn_info->spInstId]=NULL;
+       g_sngisdn_data.ccs[cc_id].active_suInstIds[sngisdn_info->suInstId]=NULL;
+       
+       sngisdn_info->suInstId = 0;
+       sngisdn_info->spInstId = 0;
+       sngisdn_info->globalFlg = 0;
+       sngisdn_info->flags = 0;
+       return;
+}
+
+uint32_t get_unique_suInstId(uint8_t cc_id)
+{
+       uint32_t suInstId;
+       ftdm_mutex_lock(g_sngisdn_data.ccs[cc_id].request_mutex);
+       suInstId = g_sngisdn_data.ccs[cc_id].last_suInstId;
+
+       while(1) {
+               if (++suInstId == MAX_INSTID) {
+                       suInstId = 1;
+               }
+               if (g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId] == NULL) {
+                       g_sngisdn_data.ccs[cc_id].last_suInstId = suInstId;
+                       ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].request_mutex);
+                       return suInstId;
+               }
+       }
+       /* Should never reach here */
+       ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].request_mutex);
+       return 0;
+}
+
+ftdm_status_t get_ftdmchan_by_suInstId(uint8_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data)
+{
+       ftdm_assert_return(g_sngisdn_data.ccs[cc_id].activation_done, FTDM_FAIL, "Trying to find call on unconfigured CC\n");
+
+       if (g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId] == NULL) {
+               return FTDM_FAIL;
+       }
+       *sngisdn_data = g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId];   
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t get_ftdmchan_by_spInstId(uint8_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data)
+{
+       ftdm_assert_return(g_sngisdn_data.ccs[cc_id].activation_done, FTDM_FAIL, "Trying to find call on unconfigured CC\n");
+
+       if (g_sngisdn_data.ccs[cc_id].active_spInstIds[spInstId] == NULL) {
+               return FTDM_FAIL;
+       }
+       *sngisdn_data = g_sngisdn_data.ccs[cc_id].active_spInstIds[spInstId];
+       return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t cpy_calling_num_from_sngisdn(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb)
+{
+       if (cgPtyNmb->eh.pres != PRSNT_NODEF) {
+               return FTDM_FAIL;
+       }
+
+       if (cgPtyNmb->screenInd.pres == PRSNT_NODEF) {
+               ftdm->screen = cgPtyNmb->screenInd.val;
+       }
+
+       if (cgPtyNmb->presInd0.pres == PRSNT_NODEF) {
+               ftdm->pres = cgPtyNmb->presInd0.val;
+       }
+
+       if (cgPtyNmb->nmbPlanId.pres == PRSNT_NODEF) {
+               ftdm->cid_num.plan = cgPtyNmb->nmbPlanId.val;
+       }
+       if (cgPtyNmb->typeNmb1.pres == PRSNT_NODEF) {
+               ftdm->cid_num.type = cgPtyNmb->typeNmb1.val;
+       }
+       
+       if (cgPtyNmb->nmbDigits.pres == PRSNT_NODEF) {
+               ftdm_copy_string(ftdm->cid_num.digits, (const char*)cgPtyNmb->nmbDigits.val, cgPtyNmb->nmbDigits.len+1);
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t cpy_called_num_from_sngisdn(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb)
+{
+       if (cdPtyNmb->eh.pres != PRSNT_NODEF) {
+               return FTDM_FAIL;
+       }
+
+       if (cdPtyNmb->nmbPlanId.pres == PRSNT_NODEF) {
+               ftdm->cid_num.plan = cdPtyNmb->nmbPlanId.val;
+       }
+
+       if (cdPtyNmb->typeNmb0.pres == PRSNT_NODEF) {
+               ftdm->cid_num.type = cdPtyNmb->typeNmb0.val;
+       }
+       
+       if (cdPtyNmb->nmbDigits.pres == PRSNT_NODEF) {
+               ftdm_copy_string(ftdm->dnis.digits, (const char*)cdPtyNmb->nmbDigits.val, cdPtyNmb->nmbDigits.len+1);
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t cpy_redir_num_from_sngisdn(ftdm_caller_data_t *ftdm, RedirNmb *redirNmb)
+{
+       if (redirNmb->eh.pres != PRSNT_NODEF) {
+               return FTDM_FAIL;
+       }
+
+       if (redirNmb->nmbPlanId.pres == PRSNT_NODEF) {
+               ftdm->rdnis.plan = redirNmb->nmbPlanId.val;
+       }
+
+       if (redirNmb->typeNmb.pres == PRSNT_NODEF) {
+               ftdm->rdnis.type = redirNmb->typeNmb.val;
+       }
+       
+       if (redirNmb->nmbDigits.pres == PRSNT_NODEF) {
+               ftdm_copy_string(ftdm->rdnis.digits, (const char*)redirNmb->nmbDigits.val, redirNmb->nmbDigits.len+1);
+       }
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t cpy_calling_name_from_sngisdn(ftdm_caller_data_t *ftdm, ConEvnt *conEvnt)
+{
+       if (conEvnt->display.eh.pres && conEvnt->display.dispInfo.pres == PRSNT_NODEF) {
+               ftdm_copy_string(ftdm->cid_name, (const char*)conEvnt->display.dispInfo.val, conEvnt->display.dispInfo.len+1);
+       }
+
+       /* TODO check if caller name is contained in a Facility IE */
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t cpy_calling_num_to_sngisdn(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm)
+{
+       uint8_t len = strlen(ftdm->cid_num.digits);
+       if (!len) {
+               return FTDM_SUCCESS;
+       }
+       cgPtyNmb->eh.pres                       = PRSNT_NODEF;
+
+       cgPtyNmb->screenInd.pres        = PRSNT_NODEF;
+       cgPtyNmb->screenInd.val         = ftdm->screen;
+
+       cgPtyNmb->presInd0.pres     = PRSNT_NODEF;
+       cgPtyNmb->presInd0.val      = ftdm->pres;
+
+       cgPtyNmb->nmbPlanId.pres        = PRSNT_NODEF;
+       cgPtyNmb->nmbPlanId.val         = ftdm->cid_num.plan;
+
+       cgPtyNmb->typeNmb1.pres         = PRSNT_NODEF;
+       cgPtyNmb->typeNmb1.val          = ftdm->cid_num.type;
+
+       cgPtyNmb->nmbDigits.pres        = PRSNT_NODEF;
+       cgPtyNmb->nmbDigits.len         = len;
+
+       memcpy(cgPtyNmb->nmbDigits.val, ftdm->cid_num.digits, len);
+
+       return FTDM_SUCCESS;
+}
+
+ftdm_status_t cpy_called_num_to_sngisdn(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm)
+{
+       uint8_t len = strlen(ftdm->dnis.digits);
+       if (!len) {
+               return FTDM_SUCCESS;
+       }
+       cdPtyNmb->eh.pres           = PRSNT_NODEF;
+
+       cdPtyNmb->nmbPlanId.pres      = PRSNT_NODEF;
+       cdPtyNmb->nmbPlanId.val       = ftdm->dnis.plan;
+
+       cdPtyNmb->typeNmb0.pres       = PRSNT_NODEF;
+       cdPtyNmb->typeNmb0.val        = ftdm->dnis.type;
+
+       cdPtyNmb->nmbDigits.pres = PRSNT_NODEF;
+       cdPtyNmb->nmbDigits.len = len;
+
+       memcpy(cdPtyNmb->nmbDigits.val, ftdm->dnis.digits, len);
+    return FTDM_SUCCESS;
+}
+
+ftdm_status_t cpy_redir_num_to_sngisdn(RedirNmb *redirNmb, ftdm_caller_data_t *ftdm)
+{
+       uint8_t len = strlen(ftdm->rdnis.digits);
+       if (!len) {
+               return FTDM_SUCCESS;
+       }
+
+       redirNmb->eh.pres       = PRSNT_NODEF;
+
+       redirNmb->nmbPlanId.pres        = PRSNT_NODEF;
+       redirNmb->nmbPlanId.val         = ftdm->rdnis.plan;
+
+       redirNmb->typeNmb.pres          = PRSNT_NODEF;
+       redirNmb->typeNmb.val           = ftdm->rdnis.type;
+
+       redirNmb->nmbDigits.pres = PRSNT_NODEF;
+       redirNmb->nmbDigits.len = len;
+
+       memcpy(redirNmb->nmbDigits.val, ftdm->rdnis.digits, len);
+
+       return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t cpy_calling_name_to_sngisdn(ConEvnt *conEvnt, ftdm_channel_t *ftdmchan)
+{
+       uint8_t len;
+       ftdm_caller_data_t *ftdm = &ftdmchan->caller_data;
+       /* sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; */
+       sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+       len = strlen(ftdm->cid_name); 
+       if (!len) {
+               return FTDM_SUCCESS;
+       }
+
+       if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
+               ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+
+               conEvnt->usrUsr.eh.pres = PRSNT_NODEF;
+               conEvnt->usrUsr.protocolDisc.pres = PRSNT_NODEF;
+               conEvnt->usrUsr.protocolDisc.val = PD_IA5; /* IA5 chars */
+               conEvnt->usrUsr.usrInfo.pres = PRSNT_NODEF;
+               conEvnt->usrUsr.usrInfo.len = len;
+               /* in sangoma_brid we used to send usr-usr info as <cid_name>!<calling_number>,
+               change to previous style if current one does not work */
+               memcpy(conEvnt->usrUsr.usrInfo.val, ftdm->cid_name, len);
+       } else {
+               switch (signal_data->switchtype) {
+               case SNGISDN_SWITCH_NI2:
+                       /* TODO: Need to send the caller ID as a facility IE */
+
+                       break;
+               case SNGISDN_SWITCH_EUROISDN:
+                       if (signal_data->signalling != SNGISDN_SIGNALING_NET) {
+                       break;
+                       }
+                       /* follow through */
+               case SNGISDN_SWITCH_5ESS:
+               case SNGISDN_SWITCH_4ESS:
+               case SNGISDN_SWITCH_DMS100:
+                       conEvnt->display.eh.pres = PRSNT_NODEF;
+                       conEvnt->display.dispInfo.pres = PRSNT_NODEF;
+                       conEvnt->display.dispInfo.len = len;
+                       memcpy(conEvnt->display.dispInfo.val, ftdm->cid_name, len);
+                       break;
+               case SNGISDN_SWITCH_QSIG:
+                       /* It seems like QSIG does not support Caller ID Name */
+                       break;
+               case SNGISDN_SWITCH_INSNET:
+                       /* Don't know how to transmit caller ID name on INSNET */
+                       break;
+               }
+       }
+       return FTDM_SUCCESS;
+}
+
+
+
+ftdm_status_t check_for_state_change(ftdm_channel_t *ftdmchan)
+{
+
+#if 0
+    ftdm_log_chan_msg(ftdmchan, "Checking for pending state change\n");
+#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 */
+               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "FTDM_CHANNEL_STATE_CHANGE set for over 500ms\n");
+
+        /* move the state of the channel to RESTART to force a reset */
+        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+
+        return FTDM_FAIL;
+    }
+    return FTDM_SUCCESS;
+}
+
+void get_memory_info(void)
+{
+       U32 availmen = 0;
+       SRegInfoShow(S_REG, &availmen);
+       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_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
new file mode 100644 (file)
index 0000000..0084704
--- /dev/null
@@ -0,0 +1,661 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * David Yat Sin <davidy@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 "ftmod_sangoma_isdn.h"
+#include "ftmod_sangoma_isdn_trace.h"
+
+#define OCTET(x) (ieData[x-1] & 0xFF)
+
+void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end);
+void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len);
+void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len);
+uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset, uint8_t *data, uint16_t index_start);
+
+uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi);
+char* get_code_2_str(int code, struct code2str *pCodeTable);
+
+char* get_code_2_str(int code, struct code2str *pCodeTable)
+{
+       struct code2str* pCode2txt;
+       pCode2txt = pCodeTable; 
+       while(pCode2txt) {
+               if(pCode2txt->code >= 0) {
+                       if (pCode2txt->code == code) {
+                               return pCode2txt->text;
+                       }
+                       pCode2txt++;
+               } else {
+                       /* This is the default value from the table */
+                       return pCode2txt->text;
+               }
+       }
+       return (char*)"unknown";
+}
+
+
+uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi)
+{
+       if (!bitLo || !bitHi) {
+               return 0;
+       }
+       if (bitLo > bitHi) {
+               return 0;
+       }
+
+       bitLo--;
+       bitHi--;
+
+       switch(bitHi - bitLo) {
+               case 0:
+                       return (octet >> bitLo) & 0x01;
+               case 1:
+                       return (octet >> bitLo) & 0x03;
+               case 2:
+                       return (octet >> bitLo) & 0x07;
+               case 3:
+                       return (octet >> bitLo) & 0x0F;
+               case 4:
+                       return (octet >> bitLo) & 0x1F;
+               case 5:
+                       return (octet >> bitLo) & 0x3F;
+               case 6:
+                       return (octet >> bitLo) & 0x7F;
+               case 7:
+                       return (octet >> bitLo) & 0xFF;
+       }
+       return 0;
+}
+
+void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len)
+{
+       int str_len;
+       int i;
+       uint8_t sapi, cr, ea, tei, ns, nr, pf, p, cmd;
+       uint8_t frame_format = 0;
+
+       str_len = 0;
+
+       if(data_len >= 2) {
+               switch ((int)data[2] & 0x03) {
+                       case 0: case 2:
+                               frame_format = I_FRAME;
+                               break;
+                       case 1: 
+                               frame_format = S_FRAME;
+                               break;
+                       case 3:
+                               frame_format = U_FRAME;
+                               break;
+               }
+       }
+
+       str_len+= sprintf(&str[str_len], "  format: %s\n",
+                                                                               get_code_2_str(frame_format, dcodQ921FrameFormatTable));
+                                                                               
+       for(i=0; i < data_len; i++) {
+               switch(i) {
+                       case 0: // Octet 2
+                               sapi = (uint8_t)((data[i]>>2) & 0x3F);
+                               cr = (uint8_t)((data[i]>>1) & 0x1);
+                               ea = (uint8_t)(data[i] & 0x1);
+                               str_len+= sprintf(&str[str_len], "  sapi: %03d  c/r: %01d  ea: %01d\n", sapi, cr, ea);
+                               break;
+                       case 1:
+                               tei = (uint8_t)((data[i]>>1) & 0x7F);
+                               ea = (uint8_t)(data[i] & 0x1);
+                               str_len+= sprintf(&str[str_len], "   tei: %03d          ea: %01d\n", tei, ea);
+                               break;
+                       case 2:
+                               switch(frame_format) {
+                                       case I_FRAME:
+                                               ns = (uint8_t)((data[i]>>1) & 0x7F);
+                                               nr = (uint8_t)((data[i+1]>>1) & 0x7F);
+                                               p = (uint8_t)(data[i+1] & 0x01);
+                                               str_len+= sprintf(&str[str_len], "  n(s): %03d\n  n(r): %03d  p: %01d\n", ns, nr, p);
+                                               break;
+                                       case S_FRAME:
+                                               nr = (uint8_t)((data[i+1]>>1) & 0x7F);
+                                               pf = (uint8_t)(data[i+1] & 0x01);
+                                               str_len+= sprintf(&str[str_len], "  n(r): %03d  p/f: %01d\n", nr, pf);
+
+                                               cmd = (uint8_t)((data[i]>>2) & 0x03);
+                                               str_len+= sprintf(&str[str_len], "   cmd: %s\n", get_code_2_str(cmd, dcodQ921SupervisoryCmdTable));
+                                               
+                                               break;
+                                       case U_FRAME:
+                                               pf = (uint8_t)((data[i]>>4) & 0x01);
+                                               str_len+= sprintf(&str[str_len], "   p/f: %01d\n", pf);
+
+                                               cmd = (uint8_t)((data[i]>>2) & 0x03);
+                                               cmd |= (uint8_t)((data[i]>>5) & 0x07);
+                                               
+                                               str_len+= sprintf(&str[str_len], "   cmd: %s\n", get_code_2_str(cmd, dcodQ921UnnumberedCmdTable));
+                                               break;
+                               }
+                               break;
+               }
+       }
+       return;
+}
+
+void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len)
+{
+       uint32_t str_len;
+       uint8_t  prot_disc, callRefFlag;
+       uint16_t lenCallRef, c, i;
+       uint8_t current_codeset = 0;
+
+       str_len = 0;
+
+       /* Decode Protocol Discrimator */
+       prot_disc = (uint8_t)data[0];
+       str_len += sprintf(&str[str_len], "  Prot Disc:%s (0x%02x)\n", get_code_2_str(prot_disc, dcodQ931ProtDiscTable), prot_disc);
+       
+
+       
+
+       /* Decode Call Reference */
+       lenCallRef = (uint8_t) (data[1] & 0x0F);
+
+       str_len += sprintf(&str[str_len], "  Call Ref:");
+       c=2;
+       callRefFlag = get_bits(data[c], 8,8);
+       for(i=0; i<(2*lenCallRef);i++) {
+               if(i==0) {
+                       str_len += sprintf(&str[str_len], "%s%s",
+                                               get_code_2_str((uint8_t)(data[c] & 0x70), dcodQ931CallRefHiTable),
+                                               get_code_2_str((uint8_t)(data[c] & 0x0F), dcodQ931CallRefLoTable));
+               } else {
+                       str_len += sprintf(&str[str_len], "%s%s",
+                                               get_code_2_str((uint8_t)(data[c] & 0xF0), dcodQ931CallRefHiTable),
+                                               get_code_2_str((uint8_t)(data[c] & 0x0F), dcodQ931CallRefLoTable));
+               }
+
+               i=i+1;
+               c=c+1;
+       }
+       str_len += sprintf(&str[str_len], " (%s side)\n", callRefFlag?"Destination":"Origination");
+
+       /* Decode message type */
+       str_len+= sprintf(&str[str_len], "  Type:%s (0x%x)\n", get_code_2_str((int)(data[2+lenCallRef] & 0xFF), dcodQ931MsgTypeTable), (int)(data[2+lenCallRef] & 0xFF));
+
+       /* go through rest of data and look for important info */
+       for(i=3+lenCallRef; i < data_len; i++) {
+               switch (data[i] & 0xF8) {
+                       case Q931_LOCKING_SHIFT:
+                               current_codeset = (data[i] & 0x7);
+                               str_len+= sprintf(&str[str_len], "Codeset shift to %d (locking)\n", current_codeset);
+                               continue;
+                       case Q931_NON_LOCKING_SHIFT:
+                               current_codeset = (data[i] & 0x7);
+                               str_len+= sprintf(&str[str_len], "Codeset shift to %d (non-locking)\n", current_codeset);
+                               continue;
+               }
+               i+= sngisdn_decode_ie(str, &str_len, current_codeset, data, i);
+       }
+       print_hex_dump(str, &str_len, (uint8_t*) data, 0, data_len);
+       return;
+}
+
+uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset, uint8_t *data, uint16_t index_start)
+{
+       unsigned char* ieData;
+       uint8_t ieId;
+       uint32_t len = 0;
+       int index_end;
+
+       ieData = (unsigned char*) &data[index_start];
+
+       ieId = OCTET(1);
+       len = OCTET(2); 
+       index_end = index_start+len+1;
+
+       *str_len += sprintf(&str[*str_len], "  %s:", get_code_2_str(data[index_start], dcodQ931IEIDTable));
+       switch(ieId) {
+               case PROT_Q931_IE_BEARER_CAP:
+                       {
+                               uint8_t codingStandard, infTransferCap, transferMode, infTransferRate, usrL1Prot;
+                               
+                               codingStandard = get_bits(OCTET(3),6,7);
+                               infTransferCap = get_bits(OCTET(3),1,5);
+                               transferMode = get_bits(OCTET(4),6,7);
+                               infTransferRate = get_bits(OCTET(4),1,5);
+                               usrL1Prot = get_bits(OCTET(5),1,5);
+                               
+                               *str_len+= sprintf(&str[*str_len], "Coding:%s(%d) TransferCap:%s(%d) TransferRate:%s(%d) L1Prot:%s(%d)\n",
+                                                                                                                       get_code_2_str(codingStandard, dcodQ931BcCodingStandardTable), codingStandard,
+                                                                                                                       get_code_2_str(infTransferCap, dcodQ931BcInfTransferCapTable), infTransferCap,
+                                                                                                                       get_code_2_str(infTransferRate, dcodQ931BcInfTransferRateTable), infTransferRate,
+                                                                                                                       get_code_2_str(usrL1Prot, dcodQ931BcusrL1ProtTable), usrL1Prot);
+                       }
+                       break;
+               case PROT_Q931_IE_CAUSE:
+                       {
+                               uint8_t codingStandard, location, cause,diagOct = 5;
+                               codingStandard = get_bits(OCTET(3),6,7);
+                               location = get_bits(OCTET(3),1,4);
+                               
+                               cause = get_bits(OCTET(4),1,7);
+
+                               *str_len+= sprintf(&str[*str_len], "coding:%s(%d) location:%s(%d) val:%s(%d)\n",
+                                                                                       get_code_2_str(codingStandard, dcodQ931BcCodingStandardTable), codingStandard,
+                                                                                       get_code_2_str(location,dcodQ931IelocationTable), location,
+                                                                                       get_code_2_str(cause, dcodQ931CauseCodeTable),
+                                                                                       cause);
+                               switch(cause) {
+                                       case PROT_Q931_RELEASE_CAUSE_IE_NOT_EXIST:
+                                               while(diagOct++ < len) {
+                                                       *str_len+= sprintf(&str[*str_len], "  %d:IE %s(0x%02x)\n",
+                                                                                                                       diagOct,
+                                                                                                                       get_code_2_str(OCTET(diagOct), dcodQ931IEIDTable),
+                                                                                                                       OCTET(diagOct));
+                                               }
+                                               break;
+                                       case PROT_Q931_RELEASE_CAUSE_WRONG_CALL_STATE:
+                                               while(diagOct++ < len) {
+                                                       *str_len+= sprintf(&str[*str_len], "  %d:Message %s(0x%02x)\n",
+                                                                                                                       diagOct,
+                                                                                                                       get_code_2_str(OCTET(diagOct), dcodQ931MsgTypeTable),
+                                                                                                                       OCTET(diagOct));
+                                               }
+                                               break;
+                                       case PROT_Q931_RECOVERY_ON_TIMER_EXPIRE:
+                                               *str_len+= sprintf(&str[*str_len], "  Timer T\n");
+                                               while(diagOct++ < len) {
+                                                       if(OCTET(diagOct) >= ' ' && OCTET(diagOct) < 0x7f) {
+                                                               *str_len+= sprintf(&str[*str_len], "%c", OCTET(diagOct));
+                                                       } else {
+                                                               *str_len+= sprintf(&str[*str_len], ".");
+                                                       }
+                                               }
+                                               break;
+                                       default:
+                                               while(diagOct++ < len) {
+                                                       *str_len+= sprintf(&str[*str_len], " %d: 0x%02x\n",
+                                                                                                                                       diagOct,
+                                                                                                                                       OCTET(diagOct));
+                                               }
+                                               break;
+                               }
+                       }               
+                       break;          
+               case PROT_Q931_IE_CHANNEL_ID:
+                       {
+                               uint8_t infoChannelSelection=0;
+                               uint8_t prefExclusive=0;
+                               uint8_t ifaceIdPresent=0;
+                               uint8_t ifaceIdentifier = 0; /* octet_3_1 */
+                               uint8_t chanType=0, numberMap=0, codingStandard=0;
+                               uint8_t channelNo = 0;
+                               
+                               infoChannelSelection = get_bits(OCTET(3),1,2);
+                               prefExclusive = get_bits(OCTET(3),4,4);
+                               ifaceIdPresent = get_bits(OCTET(3),7,7);
+       
+                               if (ifaceIdPresent) {
+                                       ifaceIdentifier= get_bits(OCTET(4),1,7);
+                                       chanType = get_bits(OCTET(5),1,4);
+                                       numberMap = get_bits(OCTET(5),5,5);
+                                       codingStandard = get_bits(OCTET(5),6,7);
+                                       channelNo = get_bits(OCTET(6),1,7);
+                               } else {
+                                       chanType = get_bits(OCTET(4),1,4);
+                                       numberMap = get_bits(OCTET(4),5,5);
+                                       codingStandard = get_bits(OCTET(4),6,7);
+                                       channelNo = get_bits(OCTET(5),1,7);
+                               }
+                               
+                               if (numberMap) {
+                                       *str_len+= sprintf(&str[*str_len], " MAP\n");
+                               } else {
+                                       *str_len+= sprintf(&str[*str_len], "No:%d ", channelNo);
+                               }
+       
+                               *str_len+= sprintf(&str[*str_len], "Type:%s(%d) %s ", get_code_2_str(chanType,dcodQ931ChanTypeTable), chanType, (numberMap)? "Map":"");
+                               *str_len+= sprintf(&str[*str_len], "%s/%s \n",
+                                                                       (prefExclusive)? "Exclusive":"Preferred", 
+                                                                       (ifaceIdPresent)? "Explicit":"Implicit");
+                       }
+                       break;
+               case PROT_Q931_IE_CALLING_PARTY_NUMBER:
+                       {
+                               uint8_t plan, type, screening = 0, presentation = 0, callingNumOct, j;
+                               uint8_t screeningEnabled = 0, presentationEnabled = 0;
+                               char callingNumDigits[32];
+                               memset(callingNumDigits, 0, sizeof(callingNumDigits));
+                               
+                               plan = get_bits(OCTET(3),1,4);
+                               type = get_bits(OCTET(3),5,7);
+
+                               if(!get_bits(OCTET(3),8,8)) {
+                                       screening = get_bits(OCTET(4),1,2);
+                                       presentation = get_bits(OCTET(4),6,7);
+                                       screeningEnabled = 1;
+                                       presentationEnabled = 1;
+                                       callingNumOct = 4;
+                               } else {
+                                       callingNumOct = 3;
+                               }
+                               if(len >= sizeof(callingNumDigits)) {   
+                                       len = sizeof(callingNumDigits)-1;
+                               }
+                               j = 0;
+                               while(callingNumOct++ <= len+1) {
+                                       callingNumDigits[j++]=ia5[get_bits(OCTET(callingNumOct),1,4)][get_bits(OCTET(callingNumOct),5,8)];
+                               }
+                               callingNumDigits[j]='\0';
+                               *str_len+= sprintf(&str[*str_len], "%s(l:%d) plan:%s(%d) type:%s(%d)",
+                                                                                                                        
+                                                                                                                       callingNumDigits, j,
+                                                                                                                       get_code_2_str(plan, dcodQ931NumberingPlanTable), plan,
+                                                                                                                       get_code_2_str(type, dcodQ931TypeofNumberTable), type);
+                                                                                                                       
+                               if (presentationEnabled||screeningEnabled) {
+                                       *str_len+= sprintf(&str[*str_len], "scr:%s(%d) pres:%s(%d)\n",
+                                                                                                               get_code_2_str(screening, dcodQ931ScreeningTable),      screening,
+                                                                                                               get_code_2_str(presentation, dcodQ931PresentationTable), presentation);
+                               } else {
+                                       *str_len+= sprintf(&str[*str_len], "\n");
+                               }
+                       }
+                       break;
+               
+               case PROT_Q931_IE_CALLED_PARTY_NUMBER:
+                       {
+                               uint8_t plan, type, calledNumOct,j;
+                               char calledNumDigits[32];
+                               memset(calledNumDigits, 0, sizeof(calledNumDigits));
+                               plan = get_bits(OCTET(3),1,4);
+                               type = get_bits(OCTET(3),5,7);
+
+                               if(len >= sizeof(calledNumDigits)) {    
+                                       len = sizeof(calledNumDigits)-1;
+                               }
+                               calledNumOct = 3;
+                               j = 0;
+                               while(calledNumOct++ <= len+1) {
+                                       calledNumDigits[j++]=ia5[get_bits(OCTET(calledNumOct),1,4)][get_bits(OCTET(calledNumOct),5,8)];
+                               }
+                               calledNumDigits[j]='\0';
+                               *str_len+= sprintf(&str[*str_len], "%s(l:%d) plan:%s(%d) type:%s(%d)\n",
+                                                                                                               calledNumDigits, j,
+                                                                                                               get_code_2_str(plan, dcodQ931NumberingPlanTable), plan,
+                                                                                                               get_code_2_str(type, dcodQ931TypeofNumberTable), type);
+                       }
+                       break;
+               case PROT_Q931_IE_REDIRECTING_NUMBER: //rdnis
+                       {
+                               uint8_t plan, type, screening = 0, presentation = 0, reason = 0, rdnisOct,j;
+                               uint8_t screeningEnabled = 0, presentationEnabled = 0, reasonEnabled = 0;
+                               char rdnis_string[32];
+                               memset(rdnis_string, 0, sizeof(rdnis_string));
+                               rdnisOct = 5;
+                               plan = get_bits(OCTET(3),1,4);
+                               type = get_bits(OCTET(3),5,7);
+                       
+                               if(!get_bits(OCTET(3),8,8)) { //Oct 3a exists
+                                       rdnisOct++;
+                                       screening = get_bits(OCTET(4),1,2);
+                                       presentation = get_bits(OCTET(4),6,7);
+                                       screeningEnabled = 1;
+                                       presentationEnabled = 1;
+                                       if (!get_bits(OCTET(4),8,8)) { //Oct 3b exists
+                                               rdnisOct++;
+                                               reason = get_bits(OCTET(5),1,4);
+                                               reasonEnabled = 1;
+                                       }
+                               } 
+       
+                               if(len >= sizeof(rdnis_string)) {       
+                                       len = sizeof(rdnis_string)-1;
+                               }
+                               
+                               j = 0;
+                               while(rdnisOct++ <= len+1) {
+                                       rdnis_string[j++]=ia5[get_bits(OCTET(rdnisOct),1,4)][get_bits(OCTET(rdnisOct),5,8)];
+                               }
+       
+                               rdnis_string[j]='\0';   
+                               *str_len+= sprintf(&str[*str_len], "%s(l:%d) plan:%s(%d) type:%s(%d)",
+                                                                                                                       rdnis_string, j,
+                                                                                                                       get_code_2_str(plan, dcodQ931NumberingPlanTable), plan,
+                                                                                                                       get_code_2_str(type, dcodQ931TypeofNumberTable), type);
+                                                                                                                       
+                               if(presentationEnabled || screeningEnabled) {
+                                       *str_len+= sprintf(&str[*str_len], "scr:%s(%d) pres:%s(%d)",
+                                                                                                               get_code_2_str(screening, dcodQ931ScreeningTable),      screening,
+                                                                                                               get_code_2_str(presentation, dcodQ931PresentationTable), presentation);
+                               }
+       
+                               if(reasonEnabled) {
+                                       *str_len+= sprintf(&str[*str_len], "reason:%s(%d)",
+                                                                                                               get_code_2_str(reason, dcodQ931ReasonTable), reason);
+                               }
+                               *str_len+= sprintf(&str[*str_len], "\n");
+                       }
+                       break;
+               case PROT_Q931_IE_USER_USER:
+                       {
+                               uint8_t protDiscr = 0x00, j, uui_stringOct;
+                               char uui_string[32];
+                               memset(uui_string, 0, sizeof(uui_string));
+                               protDiscr = OCTET(3);
+                               uui_stringOct = 3;
+                               if (protDiscr != 0x04) { /* Non-IA5 */
+                                       *str_len+= sprintf(&str[*str_len], "%s (0x%02x)\n",
+                                                                                                                       get_code_2_str(protDiscr, dcodQ931UuiProtDiscrTable), protDiscr);
+                               } else {
+                                       j = 0;
+                                       
+                                       if(len >= sizeof(uui_string)) { 
+                                               len = sizeof(uui_string)-1;
+                                       }
+                                       while(uui_stringOct++ <= len+1) {
+                                               uui_string[j++]=ia5[get_bits(OCTET(uui_stringOct),1,4)][get_bits(OCTET(uui_stringOct),5,8)];
+                                       }
+                                       uui_string[j]='\0';     
+                                       *str_len+= sprintf(&str[*str_len], "  %s (0x%02x) <%s>\n",
+                                                                                                                       get_code_2_str(protDiscr, dcodQ931UuiProtDiscrTable), protDiscr,
+                                                                                                                       uui_string);
+                               }
+                       }
+                       break;
+               case PROT_Q931_IE_DISPLAY:
+                       {
+                               uint8_t displayStrOct=2, j;
+                               char displayStr[82];
+                               memset(displayStr, 0, sizeof(displayStr));
+                               
+                               if(get_bits(OCTET(3),8,8)) {
+                                       displayStrOct++;
+                               }
+                               j = 0;  
+                               if(len >= sizeof(displayStr)) { 
+                                       len = sizeof(displayStr)-1;
+                               }
+                               while(displayStrOct++ <= len+1) {
+                                       displayStr[j++]=ia5[get_bits(OCTET(displayStrOct),1,4)][get_bits(OCTET(displayStrOct),5,8)];
+                               }
+                               displayStr[j]='\0';
+                               *str_len+= sprintf(&str[*str_len], "%s(l:%d)\n",
+                                                                                                               displayStr, len);
+                       }
+                       break;
+               case PROT_Q931_IE_RESTART_IND:
+                       {
+                               uint8_t indClass;
+                               indClass = get_bits(OCTET(3),1,3);
+                               *str_len+= sprintf(&str[*str_len], "class:%s(%d)\n",
+                                                                                                       get_code_2_str(indClass,dcodQ931RestartIndClassTable), indClass);
+                       }
+                       break;
+               case PROT_Q931_IE_PROGRESS_IND:
+                       {
+                               uint8_t codingStandard, location, progressDescr;
+                               codingStandard = get_bits(OCTET(3),6,7);
+                               location = get_bits(OCTET(3),1,4);
+                               progressDescr = get_bits(OCTET(4),1,7);
+                               *str_len+= sprintf(&str[*str_len], "coding:%s(%d) location:%s(%d) descr:%s(%d)\n",
+                                                                                                       get_code_2_str(codingStandard,dcodQ931BcCodingStandardTable), codingStandard,
+                                                                                                       get_code_2_str(location,dcodQ931IelocationTable), location,
+                                                                                                       get_code_2_str(progressDescr,dcodQ931IeprogressDescrTable), progressDescr);
+                       }
+                       break;
+               case PROT_Q931_IE_KEYPAD_FACILITY:
+                       {
+                               uint8_t keypadFacilityStrOct = 3, j;
+                               char keypadFacilityStr[82];
+                               memset(keypadFacilityStr, 0, sizeof(keypadFacilityStr));
+                               
+                               j = 0;  
+                               if(len >= sizeof(keypadFacilityStr)) {  
+                                       len = sizeof(keypadFacilityStr)-1;
+                               }
+                               while(keypadFacilityStrOct++ < len+1) {
+                                       keypadFacilityStr[j++]=ia5[get_bits(OCTET(keypadFacilityStrOct),1,4)][get_bits(OCTET(keypadFacilityStrOct),5,8)];
+                               }
+                               keypadFacilityStr[j]='\0';
+                               *str_len+= sprintf(&str[*str_len], "  digits:%s(l:%d)\n",
+                                                                                                               keypadFacilityStr, len);
+                       }
+                       break;
+               case PROT_Q931_IE_FACILITY:
+                       {
+                               uint8_t protProfile;
+                               protProfile = get_bits(OCTET(3),1,5);
+                               *str_len+= sprintf(&str[*str_len], "Prot profile:%s(%d)\n",
+                                                                                                       get_code_2_str(protProfile,dcodQ931IeFacilityProtProfileTable), protProfile);
+                       }
+                       break;
+               case PROT_Q931_IE_GENERIC_DIGITS:
+                       {
+                               uint8_t encoding,type;
+                               int value = 0;
+
+                               encoding = get_bits(OCTET(3),6,8);
+                               type = get_bits(OCTET(3),1,5);
+
+                               *str_len+= sprintf(&str[*str_len], "encoding:%s(%d) type:%s(%d) ",
+                                                                                                       get_code_2_str(encoding,dcodQ931GenDigitsEncodingTable), encoding,
+                                                                                                       get_code_2_str(encoding,dcodQ931GenDigitsTypeTable), type);
+
+                               if (len > 1) {
+                                       uint32_t j=0;
+                                       
+                                       while(++j < len) {
+                                               switch(encoding) {
+                                                       case 0: /* BCD even */
+                                                       case 1: /* BCD odd */
+                                                               {
+                                                                       uint8_t byte = OCTET(j+3);
+                                                                       value = (get_bits(byte,1,4)*10) + get_bits(byte,5,8) + (value*10);
+                                                               }
+                                                               break;
+                                                       case 2: /* IA 5 */                                                      
+                                                               value = value*10 + OCTET(j+3)-'0';
+                                                               *str_len+= sprintf(&str[*str_len], "%c", OCTET(j+3));
+                                                               break;
+                                                       case 3: 
+                                                               /* Don't know how to decode binary encoding yet */
+                                                               *str_len+= sprintf(&str[*str_len], "Binary encoded");
+                                                               break;
+                                               }
+                                       }
+                                       *str_len+= sprintf(&str[*str_len], " ");
+                                       switch(type) {
+                                               case 4: /* info digits */
+                                                       *str_len+= sprintf(&str[*str_len], "ani2:%s(%d)", get_code_2_str(value,dcodQ931LineInfoTable), value);
+                                                       break;
+                                               case 5: /* Callid */
+                                                       *str_len+= sprintf(&str[*str_len], "Caller ID not implemented\n");
+                                                       break;
+                                       }
+                               }
+                               *str_len+= sprintf(&str[*str_len], "\n");
+                               print_hex_dump(str, str_len, (uint8_t*) data, index_start, index_end);
+                       }
+                       break;
+               case PROT_Q931_IE_SENDING_COMPLETE:
+                       /* No need to decode sending complete IE, as no additional info is available except that sending is done */
+                       break;
+               case PROT_Q931_IE_CALLED_PARTY_SUBADDRESS:
+               case PROT_Q931_IE_REDIRECTION_NUMBER:
+               case PROT_Q931_IE_NOTIFICATION_IND:
+               case PROT_Q931_IE_DATE_TIME:
+               case PROT_Q931_IE_INFORMATION_REQUEST:
+               case PROT_Q931_IE_SIGNAL:
+               case PROT_Q931_IE_SWITCHOOK:
+               case PROT_Q931_IE_FEATURE_ACT:
+               case PROT_Q931_IE_FEATURE_IND:
+               case PROT_Q931_IE_INFORMATION_RATE:
+               case PROT_Q931_IE_END_TO_END_TRANSIT_DELAY:
+               case PROT_Q931_IE_TRANSIT_DELAY_SELECT_IND:
+               case PROT_Q931_IE_PACKET_LAYER_BINARY_PARAMS:
+               case PROT_Q931_IE_PACKET_LAYER_WINDOW_SIZE:
+               case PROT_Q931_IE_PACKET_LAYER_SIZE:
+               case PROT_Q931_IE_TRANSIT_NETWORK_SELECTION:
+               case PROT_Q931_IE_LOW_LAYER_COMPAT:
+               case PROT_Q931_IE_HIGH_LAYER_COMPAT:
+               case PROT_Q931_IE_ESCAPE_FOR_EXTENSION:
+               case PROT_Q931_IE_CALL_IDENTITY:
+               case PROT_Q931_IE_CALL_STATE:
+               case PROT_Q931_IE_SEGMENTED_MESSAGE:
+               case PROT_Q931_IE_NETWORK_SPF_FACILITY:
+               case PROT_Q931_IE_CALLING_PARTY_SUBADDRESS:
+               default:
+                       {
+                               *str_len += sprintf(&str[*str_len], "Undecoded");
+                               print_hex_dump((char*)str, str_len, data, index_start, index_end);
+                       }
+                       break;
+       }
+
+       return len+1;
+}
+
+void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end)
+{
+       int k;
+       *str_len += sprintf(&str[*str_len], "  [ ");
+       for(k=index_start; k <= index_end; k++) {
+               if (k && !(k%32)) {
+                       *str_len += sprintf(&str[*str_len], "\n    ");
+               }
+               *str_len += sprintf(&str[*str_len], "%02x ", data[k]);
+       }
+       *str_len += sprintf(&str[*str_len], "]\n");
+       return;
+}
+
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h
new file mode 100644 (file)
index 0000000..869b235
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies 
+ * David Yat Sin <davidy@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_SANGOMA_ISDN_TRACE_H__
+#define __FTMOD_SANGOMA_ISDN_TRACE_H__
+
+#define MX_CODE_TXT_LEN 70
+#define Q931_LOCKING_SHIFT                     0x90
+#define Q931_NON_LOCKING_SHIFT         0x98
+
+#define PROT_Q931_RELEASE_CAUSE_MISDIALED_TRUNK_PREFIX 5
+#define PROT_Q931_RELEASE_CAUSE_INVALID_NUMBER_FORMAT  28
+#define PROT_Q931_RELEASE_CAUSE_NO_CHAN_AVAIL                  34
+#define PROT_Q931_RELEASE_CAUSE_DEST_OUT_OF_ORDER              27
+#define PROT_Q931_RELEASE_CAUSE_IE_NOT_EXIST                   99
+#define PROT_Q931_RECOVERY_ON_TIMER_EXPIRE                             102
+#define PROT_Q931_RELEASE_CAUSE_WRONG_CALL_STATE               101
+
+
+#define PROT_Q931_IE_SEGMENTED_MESSAGE                 0x00
+#define PROT_Q931_IE_BEARER_CAP                                        0x04
+#define PROT_Q931_IE_CAUSE                                             0x08
+#define PROT_Q931_IE_CALL_IDENTITY                             0x10
+#define PROT_Q931_IE_CALL_STATE                                        0x14
+#define PROT_Q931_IE_CHANNEL_ID                                        0x18
+#define PROT_Q931_IE_FACILITY                                  0x1c
+#define PROT_Q931_IE_PROGRESS_IND                              0x1e
+#define PROT_Q931_IE_NETWORK_SPF_FACILITY              0x20
+#define PROT_Q931_IE_NOTIFICATION_IND                  0x27
+#define PROT_Q931_IE_DISPLAY                                   0x28
+#define PROT_Q931_IE_DATE_TIME                                 0x29
+#define PROT_Q931_IE_KEYPAD_FACILITY                   0x2c
+#define PROT_Q931_IE_INFORMATION_REQUEST               0x32
+#define PROT_Q931_IE_SIGNAL                                            0x34
+#define PROT_Q931_IE_SWITCHOOK                                 0x36
+#define PROT_Q931_IE_GENERIC_DIGITS                            0x37
+#define PROT_Q931_IE_FEATURE_ACT                               0x38
+#define PROT_Q931_IE_FEATURE_IND                               0x39
+#define PROT_Q931_IE_INFORMATION_RATE                  0x40
+#define PROT_Q931_IE_END_TO_END_TRANSIT_DELAY  0x42
+#define PROT_Q931_IE_TRANSIT_DELAY_SELECT_IND  0x43
+#define PROT_Q931_IE_PACKET_LAYER_BINARY_PARAMS        0x44
+#define PROT_Q931_IE_PACKET_LAYER_WINDOW_SIZE  0x45
+#define PROT_Q931_IE_PACKET_LAYER_SIZE                 0x46
+#define PROT_Q931_IE_CALLING_PARTY_NUMBER              0x6c
+#define PROT_Q931_IE_CALLING_PARTY_SUBADDRESS  0x6d
+#define PROT_Q931_IE_CALLED_PARTY_NUMBER               0x70
+#define PROT_Q931_IE_CALLED_PARTY_SUBADDRESS   0x71
+#define PROT_Q931_IE_REDIRECTING_NUMBER                        0x74
+#define PROT_Q931_IE_REDIRECTION_NUMBER                        0x76
+#define PROT_Q931_IE_TRANSIT_NETWORK_SELECTION 0x78
+#define PROT_Q931_IE_RESTART_IND                               0x79
+#define PROT_Q931_IE_LOW_LAYER_COMPAT                  0x7c
+#define PROT_Q931_IE_HIGH_LAYER_COMPAT                 0x7d
+#define PROT_Q931_IE_USER_USER                                 0x7e
+#define PROT_Q931_IE_SENDING_COMPLETE                  0xa1
+#define PROT_Q931_IE_ESCAPE_FOR_EXTENSION              0x7f
+#define PROT_Q931_IE_SENDING_COMPLETE                  0xa1
+
+#define NULL_CHAR 0
+
+
+struct code2str
+{
+       int code;
+       char text[MX_CODE_TXT_LEN];
+};
+
+enum {
+       I_FRAME = 1,    /* Information frame */
+       S_FRAME,                /* Supervisory frame */
+       U_FRAME,                /* Unnumbered frame */
+};
+
+char ia5[16][8]={{NULL_CHAR,NULL_CHAR,' ','0','@','P','`','p'},
+                               {NULL_CHAR,NULL_CHAR,'!','1','A','Q','a','q'},
+                               {NULL_CHAR,NULL_CHAR,'"','2','B','R','b','r'},
+                               {NULL_CHAR,NULL_CHAR,'#','3','C','S','c','s'},
+                               {NULL_CHAR,NULL_CHAR,'$','4','D','T','d','t'},
+                               {NULL_CHAR,NULL_CHAR,'%','5','E','U','e','u'},
+                               {NULL_CHAR,NULL_CHAR,'&','6','F','V','f','v'},
+                               {NULL_CHAR,NULL_CHAR,'\'','7','G','W','g','w'},
+                               {NULL_CHAR,NULL_CHAR,'(','8','H','X','h','x'},
+                               {NULL_CHAR,NULL_CHAR,')','9','I','Y','i','y'},
+                               {NULL_CHAR,NULL_CHAR,'*',':','J','Z','j','z'},
+                               {NULL_CHAR,NULL_CHAR,'+',';','K','[','k','{'},
+                               {NULL_CHAR,NULL_CHAR,',','<','L','\\','l','|'},
+                               {NULL_CHAR,NULL_CHAR,'-','=','M',']','m','}'},
+                               {NULL_CHAR,NULL_CHAR,'.','>','N','^','n','~'},
+                               {NULL_CHAR,NULL_CHAR,'/','?','O','_','o',NULL_CHAR}};
+
+/* Based on Table 4 - pg 15 of Q.921 Recommendation */
+struct code2str dcodQ921FrameFormatTable[] = {
+       {I_FRAME, "Information"},
+       {S_FRAME, "Supervisory"},
+       {U_FRAME, "Unnumbered"},
+       {-1, "?"},
+};
+
+
+/* Based on Table 5 - pg 15 of Q.921 Recommendation */
+struct code2str dcodQ921SupervisoryCmdTable[] = {
+       {0, "RR - receive ready"},
+       {1, "RNR - receive not ready"},
+       {2, "REJ - reject"},
+       {-1, "Unknown"},
+};
+
+/* Based on Table 5 - pg 15 of Q.921 Recommendation */
+struct code2str dcodQ921UnnumberedCmdTable[] = {
+       {0x0F, "SABME - set async balanced mode extended"},
+       {0x03, "DM - disconnected mode"},
+       {0x00, "UI - unnumbered information"},
+       {0x08, "DISC - disconnect"},
+       {0x0C, "UA - unnumbered acknowledgement"},
+       {0x11, "FRMR - frame reject"},
+       {0x17, "XID - Exchange Identification)"},
+       {-1, "Unknown"},
+};
+
+struct code2str dcodQ931ProtDiscTable[] = {
+       {0x08, "Q.931/I.451"},
+       {0x09, "Q.2931"},
+       {-1, "Unknown"},
+};
+
+struct code2str dcodQ931CallRefHiTable[] = {
+       {0, "0"},
+       {16, "1"},
+       {32, "2"},
+       {48, "3"},
+       {64, "4"},
+       {80, "5"},
+       {96, "6"},
+       {112, "7"},
+       {128, "8"},
+       {144, "9"},
+       {160, "A"},
+       {176, "B"},
+       {192, "C"},
+       {208, "D"},
+       {224, "E"},
+       {240, "F"},
+       {-1,"?"},
+};
+
+struct code2str dcodQ931CallRefLoTable[] = {
+       {0, "0"},
+       {1, "1"},
+       {2, "2"},
+       {3, "3"},
+       {4, "4"},
+       {5, "5"},
+       {6, "6"},
+       {7, "7"},
+       {8, "8"},
+       {9, "9"},
+       {10, "A"},
+       {11, "B"},
+       {12, "C"},
+       {13, "D"},
+       {14, "E"},
+       {15, "F"},
+       {-1,"?"},
+};
+
+struct code2str dcodQ931MsgTypeTable[] = {
+       {1, "Alerting"},
+       {2, "Call Proceeding"},
+       {3, "Progress"},
+       {5, "Setup"},
+       {7, "Connect"},
+       {13, "Setup Ack"},
+       {15, "Connect Ack"},
+       {32, "User Info"},
+       {33, "Suspend Rej"},
+       {34, "Resume Rej"},
+       {37, "Suspend"},
+       {38, "Resume"},
+       {45, "Suspend Ack"},
+       {46, "Resume Ack"},
+       {69, "Disconnect"},
+       {70, "Restart"},
+       {77, "Release"},
+       {78, "Release Ack"},
+       {90, "Release Compl"},
+       {96, "Segment"},
+       {98, "Facility"},
+       {110, "Notify"},
+       {117, "Status Enquiry"},
+       {121, "Congest Cntrl"},
+       {123, "Information"},
+       {125, "Status"},
+       {-1, "Unknown"},
+};
+
+struct code2str dcodQ931CauseCodeTable[] = {
+       {1, "Unallocated (unassigned) number"},
+       {2, "No route to specified network"},
+       {3, "No route to destination"},
+       {4, "Send special information tone"},
+       {5, "Misdialed trunk prefix"},
+       {6, "Channel Unacceptable"},
+       {7, "Call awarded and channel established"},
+       {8, "Pre-emption"},
+       {9, "Pre-emption-circuit reserved"},
+       {16, "Normal call clearing"},
+       {17, "User Busy"},
+       {18, "No User Responding"},
+       {19, "No Answer from User"},
+       {20, "Subscriber Absent"},
+       {21, "Call Rejected"},
+       {22, "Number Changed"},
+       {26, "Non-Selected User Clearing"},
+       {27, "Destination Out-of-Order"},
+       {28, "Invalid Number Format"},
+       {29, "Facility Rejected"},
+       {30, "Response to Status Enquiry"},
+       {31, "Normal, Unspecified"},
+       {34, "No Circuit/Channel Available"},
+       {38, "Network Out-of-Order"},
+       {39, "Permanent Frame Mode OOS"},
+       {40, "Permanent Frame Mode Operational"},
+       {41, "Temporary Failure"},
+       {42, "Switching Equipment Congestion"},
+       {43, "Access Information Discarded"},
+       {44, "Requested Circuit/Channel not available"},
+       {47, "Resource Unavailable, Unspecified"},
+       {49, "Quality of Service not available"},
+       {50, "Requested facility not subscribed"},
+       {53, "Outgoing calls barred within CUG"},
+       {55, "Incoming calls barred within CUG"},
+       {57, "Bearer capability not authorized"},
+       {58, "Bearer capability not presently available"},
+       {62, "Inconsistency in access inf and subscriber"},
+       {63, "Service or Option not available"},
+       {65, "Bearer capability not implemented"},
+       {66, "Channel type not implemented"},
+       {69, "Requested facility not implemented"},
+       {70, "Only restricted digital BC available"},
+       {79, "Service or option not implemented"},
+       {81, "Invalid call reference value"},
+       {82, "Identified channel does not exist"},
+       {83, "Suspended call exists"},
+       {84, "Call identity in use"},
+       {85, "No call suspended"},
+       {86, "Call already cleared"},
+       {87, "User not member of CUG"},
+       {88, "Incompatible destination"},
+       {90, "Non existent CUG"},
+       {91, "Invalid transit network selection"},
+       {95, "Invalid message, unspecified"},
+       {96, "Mandatory IE missing"}, 
+       {97, "Message type non-existent, not implemented"},
+       {98, "Message not compatible with call state"},
+       {99, "An IE or parameter does not exist"},
+       {100, "Invalid IE contents"},
+       {101, "Message not compatible with call state"},
+       {102, "Recovery on timer expired"},
+       {103, "Parameter non-existent, not impl"},
+       {110, "Message with unrecognized parameter"},
+       {111, "Protocol error, unspecified"},
+       {127, "Interworking, unspecified"},
+       {-1, "Unknown"},
+};
+
+struct code2str dcodQ931IEIDTable[] = {
+       {PROT_Q931_IE_SEGMENTED_MESSAGE, "Segmented Message"},
+       {PROT_Q931_IE_BEARER_CAP, "Bearer Capability"},
+       {PROT_Q931_IE_CAUSE, "Cause"},
+       {PROT_Q931_IE_CALL_IDENTITY, "Call Identity"},
+       {PROT_Q931_IE_CALL_STATE, "Call State"},
+       {PROT_Q931_IE_CHANNEL_ID, "Channel Id"},
+       {PROT_Q931_IE_FACILITY, "Facility"},
+       {PROT_Q931_IE_PROGRESS_IND, "Progress Indicator"},
+       {PROT_Q931_IE_NETWORK_SPF_FACILITY, "Network Specific Facilities"},
+       {PROT_Q931_IE_NOTIFICATION_IND, "Notification Indicator"},
+       {PROT_Q931_IE_DISPLAY, "Display"},
+       {PROT_Q931_IE_DATE_TIME, "Date/Time"},
+       {PROT_Q931_IE_KEYPAD_FACILITY, "Keypad Facility"},
+       {PROT_Q931_IE_INFORMATION_REQUEST, "Information Request"},
+       {PROT_Q931_IE_SIGNAL, "Signal"},
+       {PROT_Q931_IE_SWITCHOOK, "Switchhook"},
+       {PROT_Q931_IE_GENERIC_DIGITS, "Generic Digits"},
+       {PROT_Q931_IE_FEATURE_ACT, "Feature Activation"},
+       {PROT_Q931_IE_FEATURE_IND, "Feature Indication"},
+       {PROT_Q931_IE_INFORMATION_RATE, "Information Rate"},
+       {PROT_Q931_IE_END_TO_END_TRANSIT_DELAY, "End-to-end Transit Delay"},
+       {PROT_Q931_IE_TRANSIT_DELAY_SELECT_IND, "Transit Delay Selection and Indication"},
+       {PROT_Q931_IE_PACKET_LAYER_BINARY_PARAMS, "Packet layer binary parameters"},
+       {PROT_Q931_IE_PACKET_LAYER_WINDOW_SIZE, "Packet layer Window Size"},
+       {PROT_Q931_IE_PACKET_LAYER_SIZE, "Packet layer Size"},
+       {PROT_Q931_IE_CALLING_PARTY_NUMBER, "Calling Party Number"},
+       {PROT_Q931_IE_CALLING_PARTY_SUBADDRESS, "Calling Party Subaddress"},
+       {PROT_Q931_IE_CALLED_PARTY_NUMBER, "Called Party Number"},
+       {PROT_Q931_IE_CALLED_PARTY_SUBADDRESS, "Called Party Subaddress"},
+       {PROT_Q931_IE_REDIRECTING_NUMBER, "Redirecting Number"},
+       {PROT_Q931_IE_REDIRECTION_NUMBER, "Redirection Number"},
+       {PROT_Q931_IE_TRANSIT_NETWORK_SELECTION, "Transit Network Selection"},
+       {PROT_Q931_IE_RESTART_IND, "Restart Indicator"},
+       {PROT_Q931_IE_LOW_LAYER_COMPAT, "Low-Layer Compatibility"},
+       {PROT_Q931_IE_HIGH_LAYER_COMPAT, "High-Layer Compatibility"},
+       {PROT_Q931_IE_USER_USER, "User-User"},
+       {PROT_Q931_IE_SENDING_COMPLETE, "Sending complete"},
+       {PROT_Q931_IE_ESCAPE_FOR_EXTENSION, "Escape for extension"},
+       {-1,"Unknown"},
+};
+
+struct code2str dcodQ931NumberingPlanTable[] = {
+       {0, "unknown"},
+       {1, "isdn"},
+       {3, "data"},
+       {4, "telex"},
+       {8, "national"},
+       {9, "private"},
+       {15, "reserved"},
+       {-1, "invalid"},
+};
+
+struct code2str dcodQ931TypeofNumberTable[] = {
+       {0, "unknown"},
+       {1, "international"},
+       {2, "national"},
+       {3, "network spf"},
+       {4, "subscriber"},
+       {6, "abbreviated"},
+       {7, "reserved"},
+       {-1, "invalid" },
+};
+
+struct code2str dcodQ931PresentationTable[] = {
+       {0, "allowed"},
+       {1, "restricted"},
+       {2, "not available"},
+       {-1, "invalid" },
+};
+
+struct code2str dcodQ931ScreeningTable[] = {
+       {0, "user, not screened"},
+       {1, "user, passed"},
+       {2, "user, failed"},
+       {3, "network, provided"},
+       {-1, "invalid" },
+};
+
+struct code2str dcodQ931ReasonTable[] = {
+       {0x0, "Unknown"},
+       {0x1, "Call forwarding busy"},
+       {0x2, "Call forwarding no reply"},
+       {0x4, "Call deflection"},
+       {0x9, "Called DTE out of order"},
+       {0xA, "Call forwarding by the called DTE"},
+       {0xF, "Call forwarding unconditional"},
+       {-1, "reserved" },
+};
+
+struct code2str dcodQ931BcCodingStandardTable[] = {
+       {0x0, "ITU-T"},
+       {0x1, "ISO/IEC"},
+       {0x2, "National"},
+       {0x3, "Defined standard"},
+       {-1, "unknown"},
+};
+
+struct code2str dcodQ931BcInfTransferCapTable[] = {
+       {0x00, "Speech"},
+       {0x08, "Unrestricted digital"},
+       {0x09, "Restricted digital"},
+       {0x10, "3.1Khz audio"},
+       {0x11, "Unrestricted digital w/ tones"},
+       {0x18, "Video"},
+       {-1, "reserved"},       
+};
+
+struct code2str dcodQ931BcInfTransferRateTable[] = {
+       {0x00, "n/a"}, /* for packet-mode calls */
+       {0x10, "64 Kbit/s"},
+       {0x11, "2x64 Kbit/s"},
+       {0x13, "384 Kbit/s"},
+       {0x15, "1536 Kbit/s"},
+       {0x17, "1920 Kbit/s"},
+       {0x18, "Multirate"},
+       {-1, "reserved"},
+};
+
+
+struct code2str dcodQ931BcusrL1ProtTable[] = {
+       {0x01, "ITU-T rate/V.110/I.460/X.30"},  
+       {0x02, "G.711 u-Law"},
+       {0x03, "G.711 A-Law"},
+       {0x04, "G.721/I.460"},
+       {0x05, "H.221/H.242"},
+       {0x06, "H.223/H.245"},
+       {0x07, "Non-ITU-T rate"},       
+       {0x08, "V.120"},
+       {0x09, "X.31 HDLC"},
+       {-1, "reserved"},
+};
+
+struct code2str dcodQ931UuiProtDiscrTable[] = {
+       {0x00, "User-specific"},
+       {0x01, "OSI high layer prot"},
+       {0x02, "Recommendation X.244"},
+       {0x03, "System management"},
+       {0x04, "IA5 Chars"},
+       {0x05, "X.208/X.209"},
+       {0x07, "V.120"},
+       {0x08, "Q.931/I.451"},
+       {0x10, "X.25"},
+       {-1,"reserved"},
+};
+
+struct code2str dcodQ931ChanTypeTable[] = {
+       {0x3,"B-chans"},
+       {0x6,"H0-chans"},
+       {0x8,"H11-chans"},
+       {0x9,"H12-chans"},
+       {-1,"reserved"},
+};
+
+struct code2str dcodQ931RestartIndClassTable[] = {
+       {0x0 ,"Indicated in channel IE"},
+       {0x6 ,"Single interface"},
+       {0x7 ,"All interfaces"},
+       {-1, "reserved"},
+};
+
+struct code2str dcodQ931IelocationTable[] = {
+       {0x0, "User"},
+       {0x1, "Private network, local user"},
+       {0x2, "Public network, local user"},
+       {0x3, "Transit network"},
+       {0x4, "Public network, remote user"},
+       {0x5, "Private network, remote user"},
+       {0xA, "Beyond interworking point"},
+       {-1, "reserved"},
+};
+
+struct code2str dcodQ931IeprogressDescrTable[] = {
+       {0x01, "Further info maybe available"},
+       {0x02, "Destination is non-ISDN"},
+       {0x03, "Origination address is non-ISDN"},
+       {0x04, "Call returned to ISDN"},
+       {0x08, "In-band data ready"},
+       {-1, "reserved"},
+};
+
+struct code2str dcodQ931IeFacilityProtProfileTable[] = {
+       {0x11, "Remote Operations Protocol"},
+       {0x12, "CMIP Protocol"},
+       {0x13, "ACSE Protocol"},
+       {0x16, "GAT Protocol"},
+       {0x1F, "Networking Extensions"},
+       {-1, "reserved"},
+};
+
+//from www.voip-info.org/wiki/ANI2  - NANPA
+struct code2str dcodQ931LineInfoTable[] = {
+       {0,  "Plain Old Telephone Service(POTS)" },
+       {1,  "Multiparty line"},
+       {2,  "ANI Failure"},
+       {6,  "Station Level Rating"},
+       {7,  "Special Operator Handling Required"},
+       {20, "Automatic Identified Outward Dialing (AIOD)"},
+       {23, "Coin or Non-coin"},
+       {24, "Toll free service, POTS originated for non-pay station"},
+       {25, "Toll free service, POTS originated for pay station"},
+       {27, "Pay station with coin control"},
+       {29, "Prison-Inmate service"},
+       {30, "Intercept - blank"},
+       {31, "Intercept - trouble"},
+       {32, "Intercept - regular"},
+       {34, "Telco operator handled call"},
+       {52, "Outward Wide Area Telecommunications Service(OUTWATS)"},
+       {60, "TRS call - from unrestricted line"},
+       {61, "Cellular-Wireless PCS Type 1"},
+       {62, "Cellular-Wireless PCS Type 2"},
+       {63, "Cellular-Wireless PCS Type Roaming"},
+       {66, "TRS call - from hotel/motel"},
+       {67, "TRS call - from restricted line"},
+       {70, "Line connected to pay station"},
+       {93, "Private virtual network call"},
+       {-1, "Unassigned"},
+};
+
+
+struct code2str dcodQ931GenDigitsEncodingTable[] = {
+       {0, "BCD even"},
+       {1, "BCD odd"},
+       {2, "IA5"},
+       {3, "Binary"},
+       {-1, "Invalid"},
+};
+
+
+struct code2str dcodQ931GenDigitsTypeTable[] = {
+       { 0, "Account Code"},
+       { 1, "Auth Code"},
+       { 2, "Customer ID" },
+       { 3, "Universal Access"},
+       { 4, "Info Digits"},
+       { 5, "Callid"},
+       { 6, "Opart"},
+       { 7, "TCN"},
+       { 9, "Adin"},
+       {-1, "Invalid"},
+};
+
+#endif /* __FTMOD_SANGOMA_ISDN_TRACE_H__ */
+