From c943e641d57fb694b210ed7e80b00cda3d9e0e88 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 30 Jun 2010 12:42:11 -0400 Subject: [PATCH] Added sangoma_isdn --- libs/freetdm/Makefile.am | 20 +- libs/freetdm/configure.ac | 3 + .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.c | 1071 +++++++++++++++++ .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 259 ++++ .../ftmod_sangoma_isdn_cfg.c | 219 ++++ .../ftmod_sangoma_isdn_cntrl.c | 85 ++ .../ftmod_sangoma_isdn_stack_cfg.c | 1035 ++++++++++++++++ .../ftmod_sangoma_isdn_stack_cntrl.c | 316 +++++ .../ftmod_sangoma_isdn_stack_in.c | 935 ++++++++++++++ .../ftmod_sangoma_isdn_stack_out.c | 433 +++++++ .../ftmod_sangoma_isdn_support.c | 353 ++++++ .../ftmod_sangoma_isdn_trace.c | 661 ++++++++++ .../ftmod_sangoma_isdn_trace.h | 540 +++++++++ 13 files changed, 5929 insertions(+), 1 deletion(-) create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_in.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c create mode 100644 libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index c86d00203e..1c878e6cb4 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -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 diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index cad37c3705..567be44587 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -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 index 0000000000..1872d4adab --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -0,0 +1,1071 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * Moises Silva + * 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 \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 \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 index 0000000000..d3877defd3 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * Moises Silva + * 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 +#include +#include +#include +#include +#include + +#include "private/ftdm_core.h" + +#include + +#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 index 0000000000..d0254fd714 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * 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 index 0000000000..5299c91b44 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + + * 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 index 0000000000..c44228d033 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c @@ -0,0 +1,1035 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * 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;isignal_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 index 0000000000..ab2f1a38d9 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * Moises Silva + * 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 index 0000000000..04430cf0f0 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_in.c @@ -0,0 +1,935 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * 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;jb_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 (ib_wptr) { + tmp = tmp->b_cont; + if (tmp) cptr = tmp->b_rptr; + } + i++; + if (it.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 index 0000000000..c5e986bea3 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * 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 index 0000000000..b922efc809 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * 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 !, + 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 index 0000000000..0084704322 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c @@ -0,0 +1,661 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * 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 index 0000000000..869b235f2a --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * David Yat Sin + * 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__ */ +