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