diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index ed9d6197e1..be16cd5383 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -37,7 +37,10 @@ libdir = @libdir@ library_includedir = $(PREFIX)/include INCS = -I$(FT_SRCDIR)/$(SRC)/include -I$(FT_SRCDIR)/$(SRC)/isdn/include -I$(FT_SRCDIR)/$(SRC)/include/private -INCS += -I$(FT_SRCDIR)/$(SRC)/ftmod/ftmod_sangoma_boost +INCS += -I$(FT_SRCDIR)/$(SRC)/ftmod/ftmod_sangoma_boost +if SNGSS7 +INCS += -I/usr/include/wanpipe/sng_ss7/ +endif MY_CFLAGS = $(INCS) $(FTDM_CFLAGS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@ COMPILE = $(CC) $(MY_CFLAGS) $(INCS) LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(COMPILE) @@ -164,6 +167,10 @@ if LIBPRI mod_LTLIBRARIES += ftmod_libpri.la endif +if SNGSS7 +mod_LTLIBRARIES += ftmod_sangoma_ss7.la +endif + if OPENR2 mod_LTLIBRARIES += ftmod_r2.la endif @@ -236,6 +243,20 @@ ftmod_libpri_la_LDFLAGS = -module -avoid-version -lpri ftmod_libpri_la_LIBADD = $(MYLIB) endif +if SNGSS7 +ftmod_sangoma_ss7_la_SOURCES = $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +ftmod_sangoma_ss7_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE +ftmod_sangoma_ss7_la_LDFLAGS = -module -avoid-version -lsng_ss7 +ftmod_sangoma_ss7_la_LIBADD = $(MYLIB) +endif + if OPENR2 ftmod_r2_la_SOURCES = $(SRC)/ftmod/ftmod_r2/ftmod_r2.c ftmod_r2_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index fc141e888e..cad37c3705 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -170,6 +170,9 @@ AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"]) AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"]) +AC_CHECK_LIB([sng_ss7], [sng_isup_init], [have_sng_ss7="yes"]) +AM_CONDITIONAL([SNGSS7],[test "${have_sng_ss7}" = "yes"]) + AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [have_openr2="yes"]) AM_CONDITIONAL([OPENR2],[test "${have_openr2}" = "yes"]) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c new file mode 100644 index 0000000000..eaf36cffab --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -0,0 +1,1023 @@ +/* + * Copyright (c) 2009|Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms|with or without + * modification|are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice|this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice|this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES|INCLUDING|BUT NOT + * LIMITED TO|THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT|INDIRECT|INCIDENTAL|SPECIAL, + * EXEMPLARY|OR CONSEQUENTIAL DAMAGES (INCLUDING|BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE|DATA|OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY|WHETHER IN CONTRACT|STRICT LIABILITY|OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE|EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data); + +static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream); + +static ftdm_status_t handle_set_function_trace(ftdm_stream_handle_t *stream, int on, int level); +static ftdm_status_t handle_set_message_trace(ftdm_stream_handle_t *stream, int on, int level); +static ftdm_status_t handle_set_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_set_unblks(ftdm_stream_handle_t *stream, int span, int chan, int verbose); + +static ftdm_status_t handle_show_free(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_show_inuse(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_show_inreset(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_show_flags(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_show_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, int chan, int verbose); + +static ftdm_status_t handle_status_link(ftdm_stream_handle_t *stream, char *name); +static ftdm_status_t handle_status_linkset(ftdm_stream_handle_t *stream, char *name); + +static ftdm_status_t extract_span_chan(char *argv[10], int pos, int *span, int *chan); +static ftdm_status_t check_arg_count(int args, int min); +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ +ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data) +{ + char *mycmd = NULL; + char *argv[10] = { 0 }; + int argc = 0; + int span = 0; + int chan = 0; + int trace = 0; + int trace_level = 7; + int verbose = 1; + int c = 0; + + if (data) { + mycmd = ftdm_strdup(data); + argc = ftdm_separate_string(mycmd,' ',argv,(sizeof(argv) / sizeof(argv[0]))); + } + + if (check_arg_count(argc, 1)) goto handle_cli_error_argc; + + if (!strcasecmp(argv[c], "show")) { + /**************************************************************************/ + if (check_arg_count(argc, 4)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "status")) { + /**********************************************************************/ + c++; + + if (!strcasecmp(argv[c], "link")) { + /******************************************************************/ + c++; + handle_status_link(stream, argv[c]); + /******************************************************************/ + } else if (!strcasecmp(argv[c], "linkset")) { + /******************************************************************/ + c++; + handle_status_linkset(stream, argv[c]); + /******************************************************************/ + } else if (!strcasecmp(argv[c], "span")) { + /******************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_show_status(stream, span, chan, verbose); + /******************************************************************/ + } else { + /******************************************************************/ + stream->write_function(stream, "Unknown \"status\" command\n"); + goto handle_cli_error; + /******************************************************************/ + } + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "inuse")) { + /**********************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /******************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_show_inuse(stream, span, chan, verbose); + /******************************************************************/ + } else { + /******************************************************************/ + stream->write_function(stream, "Unknown \"inuse\" command\n"); + goto handle_cli_error; + /******************************************************************/ + } + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "inreset")) { + /**********************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /******************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_show_inreset(stream, span, chan, verbose); + /******************************************************************/ + } else { + /******************************************************************/ + stream->write_function(stream, "Unknown \"inreset\" command\n"); + goto handle_cli_error; + /******************************************************************/ + } + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "free")) { + /**********************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /******************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_show_free(stream, span, chan, verbose); + /******************************************************************/ + } else { + /******************************************************************/ + stream->write_function(stream, "Unknown \"free\" command\n"); + goto handle_cli_error; + /******************************************************************/ + } + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "blocks")) { + /**********************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /******************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_show_blocks(stream, span, chan, verbose); + /******************************************************************/ + } else { + /******************************************************************/ + stream->write_function(stream, "Unknown \"blocks\" command\n"); + goto handle_cli_error; + /******************************************************************/ + } + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "flags")) { + /**********************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /******************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_show_flags(stream, span, chan, verbose); + /******************************************************************/ + } else { + /******************************************************************/ + stream->write_function(stream, "Unknown \"flags\" command\n"); + goto handle_cli_error; + /******************************************************************/ + } + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"show\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "set")) { + /**************************************************************************/ + if (check_arg_count(argc, 4)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "ftrace")) { + /**********************************************************************/ + c++; + trace = atoi(argv[c]); + c++; + trace_level = atoi(argv[c]); + c++; + handle_set_function_trace(stream, trace, trace_level); + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "mtrace")) { + /**********************************************************************/ + c++; + trace = atoi(argv[c]); + c++; + trace_level = atoi(argv[c]); + c++; + handle_set_message_trace(stream, trace, trace_level); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"set\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "block")) { + /**************************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /**********************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_set_blocks(stream, span, chan, verbose); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"block\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "unblock")) { + /**************************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /**********************************************************************/ + if (check_arg_count(argc, 6)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_set_unblks(stream, span, chan, verbose); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"unblock\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else { + /**************************************************************************/ + goto handle_cli_error; + /**************************************************************************/ + } + + return FTDM_SUCCESS; + +handle_cli_error_argc: + stream->write_function(stream, "Invalid # of arguments in command\n"); + handle_print_usuage(stream); + return FTDM_SUCCESS; + +handle_cli_error_span_chan: + stream->write_function(stream, "Unknown \"span\\chan\" command\n"); + handle_print_usuage(stream); + return FTDM_SUCCESS; + +handle_cli_error: + stream->write_function(stream, "Unknown command requested\n"); + handle_print_usuage(stream); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream) +{ + stream->write_function(stream, "Sangoma SS7 CLI usuage:\n\n"); + + stream->write_function(stream, "Ftmod_sangoma_ss7 general control:\n"); + stream->write_function(stream, "ftdm ss7 set ftace X Y\n"); + stream->write_function(stream, "ftdm ss7 set mtace X Y\n"); + stream->write_function(stream, "\n"); + stream->write_function(stream, "Ftmod_sangoma_ss7 information:\n"); + stream->write_function(stream, "ftdm ss7 show status link X\n"); + stream->write_function(stream, "ftdm ss7 show status linkset X\n"); + stream->write_function(stream, "ftdm ss7 show status span X chan Y\n"); + stream->write_function(stream, "ftdm ss7 show free span X chan Y\n"); + stream->write_function(stream, "ftdm ss7 show inuse span X chan Y\n"); + stream->write_function(stream, "ftdm ss7 show inreset span X chan Y\n"); + stream->write_function(stream, "\n"); + stream->write_function(stream, "Ftmod_sangoma_ss7 circuit control:\n"); + stream->write_function(stream, "ftdm ss7 set block span X chan Y\n"); + stream->write_function(stream, "ftdm ss7 set unblk span X chan Y\n"); + stream->write_function(stream, "\n"); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_set_function_trace(ftdm_stream_handle_t *stream, int on, int level) +{ + stream->write_function(stream, "ftmod_sangoma_ss7 Function Trace was %s, level = %d\n", + (g_ftdm_sngss7_data.function_trace == 1) ? "ON" : "OFF", + g_ftdm_sngss7_data.function_trace_level); + + g_ftdm_sngss7_data.function_trace = on; + g_ftdm_sngss7_data.function_trace_level = level; + + stream->write_function(stream, "ftmod_sangoma_ss7 Function Trace now is %s, level = %d\n", + (g_ftdm_sngss7_data.function_trace == 1) ? "ON" : "OFF", + g_ftdm_sngss7_data.function_trace_level); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_set_message_trace(ftdm_stream_handle_t *stream, int on, int level) +{ + stream->write_function(stream, "ftmod_sangoma_ss7 Message Trace was %s, level = %d\n", + (g_ftdm_sngss7_data.message_trace == 1) ? "ON" : "OFF", + g_ftdm_sngss7_data.message_trace_level); + + g_ftdm_sngss7_data.message_trace = on; + g_ftdm_sngss7_data.message_trace_level = level; + + stream->write_function(stream, "ftmod_sangoma_ss7 Message Trace now is %s, level = %d\n", + (g_ftdm_sngss7_data.message_trace == 1) ? "ON" : "OFF", + g_ftdm_sngss7_data.message_trace_level); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_show_free(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + int free; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + + x=1; + free = 0; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + switch (ftdmchan->state) { + /******************************************************************/ + case (FTDM_CHANNEL_STATE_DOWN): + if (verbose) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|state=%s\n", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id, + ss7_info->circuit->cic, + ftdm_channel_state2str(ftdmchan->state)); + } /* if (verbose) */ + + /*increment the count of circuits in reset */ + free++; + break; + /******************************************************************/ + default: + break; + /******************************************************************/ + } /* switch (ftdmchan->state) */ + } /* if ( span and chan) */ + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */ + + stream->write_function(stream, "\nTotal # of CICs free = %d\n",free); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_show_inuse(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + int in_use; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + + x=1; + in_use = 0; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + switch (ftdmchan->state) { + /******************************************************************/ + case (FTDM_CHANNEL_STATE_COLLECT): + case (FTDM_CHANNEL_STATE_RING): + case (FTDM_CHANNEL_STATE_DIALING): + case (FTDM_CHANNEL_STATE_PROGRESS): + case (FTDM_CHANNEL_STATE_PROGRESS_MEDIA): + case (FTDM_CHANNEL_STATE_UP): + case (FTDM_CHANNEL_STATE_TERMINATING): + case (FTDM_CHANNEL_STATE_HANGUP): + if (verbose) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|state=%s\n", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id, + ss7_info->circuit->cic, + ftdm_channel_state2str(ftdmchan->state)); + } /* if (verbose) */ + + /*increment the count of circuits in reset */ + in_use++; + break; + /******************************************************************/ + default: + break; + /******************************************************************/ + } /* switch (ftdmchan->state) */ + } /* if ( span and chan) */ + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */ + + stream->write_function(stream, "\nTotal # of CICs in use = %d\n",in_use); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_show_inreset(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + int in_reset; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + + x=1; + in_reset = 0; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + if ((sngss7_test_flag(ss7_info, FLAG_RESET_RX)) || (sngss7_test_flag(ss7_info, FLAG_RESET_TX))) { + if (verbose) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|in_reset=Y\n", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id, + ss7_info->circuit->cic); + } /* if (verbose) */ + + /*increment the count of circuits in reset */ + in_reset++; + } /* if ((sngss7_test_flag(ss7_info, FLAG_RESET_RX) ... */ + } /* if ( span and chan) */ + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */ + + stream->write_function(stream, "\nTotal # of CICs in reset = %d\n",in_reset); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_show_flags(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + int bit; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id, + ss7_info->circuit->cic); + + for (bit = 0; bit < 33; bit++) { + stream->write_function(stream, "|"); + if (ss7_info->flags & ( 0x1 << bit)) { + stream->write_function(stream, "%2d=1", bit); + } else { + stream->write_function(stream, "%2d=0", bit); + } + } + + stream->write_function(stream, "\n"); + } /* if ( span and chan) */ + + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */ + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_show_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id, + ss7_info->circuit->cic); + + if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX))) { + stream->write_function(stream, "l_mn=Y|"); + }else { + stream->write_function(stream, "l_mn=N|"); + } + + if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_RX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_RX))) { + stream->write_function(stream, "r_mn=Y|"); + }else { + stream->write_function(stream, "r_mn=N|"); + } + + if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) { + stream->write_function(stream, "l_hw=Y|"); + }else { + stream->write_function(stream, "l_hw=N|"); + } + + if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_RX)) { + stream->write_function(stream, "r_hw=Y\n"); + }else { + stream->write_function(stream, "r_hw=N\n"); + } + } /* if ( span and chan) */ + + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */ + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + ftdm_signaling_status_t sigstatus = FTDM_SIG_STATE_DOWN; + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + /* grab the signaling_status */ + ftdm_channel_get_sig_status(ftdmchan, &sigstatus); + + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|sig_status=%s|state=%s|", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id, + ss7_info->circuit->cic, + ftdm_signaling_status2str(sigstatus), + ftdm_channel_state2str(ftdmchan->state)); + + if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX))) { + stream->write_function(stream, "l_mn=Y|"); + }else { + stream->write_function(stream, "l_mn=N|"); + } + + if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_RX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_RX))) { + stream->write_function(stream, "r_mn=Y|"); + }else { + stream->write_function(stream, "r_mn=N|"); + } + + if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) { + stream->write_function(stream, "l_hw=Y|"); + }else { + stream->write_function(stream, "l_hw=N|"); + } + + if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_RX)) { + stream->write_function(stream, "r_hw=Y\n"); + }else { + stream->write_function(stream, "r_hw=N\n"); + } + } /* if ( span and chan) */ + + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */ + + return FTDM_SUCCESS; + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static ftdm_status_t handle_set_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change|give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); + } else { + /* throw the ckt block flag */ + sngss7_set_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); + + /* set the channel to suspended state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + } /* if ( span and chan) */ + + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */ + + handle_show_blocks(stream, span, chan, verbose); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_set_unblks(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +{ + int x; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink != 1) { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCircuit[x].obj; + ftdmchan = ss7_info->ftdmchan; + + /* if span == 0 then all spans should be printed */ + if (span == 0) { + lspan = ftdmchan->physical_span_id; + } else { + lspan = span; + } + + /* if chan == 0 then all chans should be printed */ + if (chan == 0) { + lchan = ftdmchan->physical_chan_id; + } else { + lchan = chan; + } + + if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change|give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); + } else { + /* throw the ckt block flag */ + sngss7_set_flag(ss7_info, FLAG_CKT_MN_UNBLK_TX); + + /* clear the block flag */ + sngss7_clear_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); + + /* set the channel to suspended state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + } /* if ( span and chan) */ + + } /* if ( cic != 0) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x]id != 0) */ + + handle_show_blocks(stream, span, chan, verbose); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_status_link(ftdm_stream_handle_t *stream, char *name) +{ + int x; + sng_mtp3Link_sta_t sta; + + /* find the link request by it's name */ + x = 1; + while(g_ftdm_sngss7_data.cfg.mtp3Link[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtp3Link[x].name, name)) { + /* send the status request */ + if (sng_sta_mtp3_link(&g_ftdm_sngss7_data.cfg, x, &sta)) { + stream->write_function(stream, "Failed to read link=%s status\n", name); + return FTDM_FAIL; + } + + /* print the results */ + stream->write_function(stream, "%s|state=%s|l_blk=%s|r_blk=%s|l_inhbt=%s|r_inhbt=%s\n", + name, + DECODE_LSN_LINK_STATUS(sta.state), + (sta.lblkd) ? "Y":"N", + (sta.rblkd) ? "Y":"N", + (sta.linhbt) ? "Y":"N", + (sta.rinhbt) ? "Y":"N"); + break; + } + + /* move to the next link */ + x++; + } /* while (id != 0) */ + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_status_linkset(ftdm_stream_handle_t *stream, char *name) +{ + int x; + sng_mtp3LinkSet_sta_t sta; + + /* find the linkset request by it's name */ + x = 1; + while(g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].name, name)) { + /* send the status request */ + if (sng_sta_mtp3_linkset(&g_ftdm_sngss7_data.cfg, x, 0, &sta)) { + stream->write_function(stream, "Failed to read linkset=%s status\n", name); + return FTDM_FAIL; + } + + /* print the results */ + stream->write_function(stream, "%s|state=%s|nmbActLnk=%d\n", + name, + DECODE_LSN_LINKSET_STATUS(sta.state), + sta.nmbActLnks); + break; + } + + /* move to the next linkset */ + x++; + } /* while (id != 0) */ + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t extract_span_chan(char *argv[10], int pos, int *span, int *chan) +{ + + if (!strcasecmp(argv[pos], "span")) { + /**************************************************************************/ + pos++; + *span = atoi(argv[pos]); + + pos++; + if (!strcasecmp(argv[pos], "chan")) { + /**********************************************************************/ + pos++; + *chan = atoi(argv[pos]); + /**********************************************************************/ + } else { + /**********************************************************************/ + return FTDM_FAIL; + /**********************************************************************/ + } + /**************************************************************************/ + } else { + /**************************************************************************/ + *span = atoi(argv[pos]); + + pos++; + if (!strcasecmp(argv[pos], "chan")) { + /**********************************************************************/ + pos++; + *chan = atoi(argv[pos]); + /**********************************************************************/ + } else { + /**********************************************************************/ + return FTDM_FAIL; + /**********************************************************************/ + } + /**************************************************************************/ + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t check_arg_count(int args, int min) +{ + if ( args < min ) { + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ +/******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c new file mode 100644 index 0000000000..f0c1572e6c --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c @@ -0,0 +1,732 @@ +/* + * Copyright (c) 2009, Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +void handle_sng_log(uint8_t level, char *fmt,...); +void handle_sng_alarm(sng_alrm_t t_alarm); + +static void handle_entsi_alarm(sng_alrm_t t_alarm); + +int ft_to_sngss7_cfg(void); +int ft_to_sngss7_activate_all(void); + +static int ftmod_ss7_general_configuration(void); + +static int ftmod_ss7_configure_mtp1_link(int id); + +static int ftmod_ss7_configure_mtp2_link(int id); + +static int ftmod_ss7_configure_mtp3_link(int id); +static int ftmod_ss7_configure_mtp3_linkset(int id); +static int ftmod_ss7_configure_mtp3_route(int id); +static int ftmod_ss7_configure_mtp3_isup(int id); + +static int ftmod_ss7_configure_isup_mtp3(int id); +static int ftmod_ss7_configure_isup_interface(int id); +static int ftmod_ss7_configure_isup_circuit(int id); +static int ftmod_ss7_configure_isup_cc(int id); + +static int ftmod_ss7_configure_cc_isup(int id); + +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ + +/* LOGGIGING ******************************************************************/ +void handle_sng_log(uint8_t level, char *fmt,...) +{ + char *data; + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vasprintf(&data, fmt, ap); + if (ret == -1) { + return; + } + + switch (level) { + /**************************************************************************/ + case SNG_LOGLEVEL_DEBUG: + ftdm_log(FTDM_LOG_DEBUG, "sng_ss7->%s", data); + break; + /**************************************************************************/ + case SNG_LOGLEVEL_WARN: + ftdm_log(FTDM_LOG_INFO, "sng_ss7->%s", data); + break; + /**************************************************************************/ + case SNG_LOGLEVEL_INFO: + ftdm_log(FTDM_LOG_INFO, "sng_ss7->%s", data); + break; + /**************************************************************************/ + case SNG_LOGLEVEL_STATS: + ftdm_log(FTDM_LOG_INFO, "sng_ss7->%s", data); + break; + /**************************************************************************/ + case SNG_LOGLEVEL_ERROR: + ftdm_log(FTDM_LOG_ERROR, "sng_ss7->%s", data); + break; + /**************************************************************************/ + case SNG_LOGLEVEL_CRIT: + printf("%s",data); + /*ftdm_log(FTDM_LOG_CRIT, "sng_ss7->%s", data);*/ + break; + /**************************************************************************/ + default: + ftdm_log(FTDM_LOG_INFO, "sng_ss7->%s", data); + break; + /**************************************************************************/ + } + + return; +} + +/******************************************************************************/ +void handle_sng_alarm(sng_alrm_t t_alarm) +{ + + switch (t_alarm.entity) { + /**************************************************************************/ + case (ENTL1): + ftdm_log(FTDM_LOG_WARNING,"[SNG-MTP1] %s : %s : %s \n", + DECODE_LL1_EVENT(t_alarm.event), + DECODE_LL1_CAUSE(t_alarm.cause), + DECODE_LL1_PARM(t_alarm.eventParm[0])); + break; + /**************************************************************************/ + case (ENTSD): + ftdm_log(FTDM_LOG_WARNING,"[SNG-MTP2] %s : %s \n", + DECODE_LSD_EVENT(t_alarm.event), + DECODE_LSD_CAUSE(t_alarm.cause)); + break; + /**************************************************************************/ + case (ENTSN): + ftdm_log(FTDM_LOG_WARNING,"[SNG-MTP3] %s on %d: %s \n", + DECODE_LSN_EVENT(t_alarm.event), + t_alarm.id, + DECODE_LSN_CAUSE(t_alarm.cause)); + break; + /**************************************************************************/ + case (ENTSI): + handle_entsi_alarm(t_alarm); + break; + /**************************************************************************/ + case (ENTCC): + ftdm_log(FTDM_LOG_DEBUG,"[SNG-CC] %s : %s \n", + DECODE_LCC_EVENT(t_alarm.event), + DECODE_LCC_CAUSE(t_alarm.cause)); + break; + /**************************************************************************/ + default: + ftdm_log(FTDM_LOG_WARNING,"Received alarm from unknown entity"); + break; + /**************************************************************************/ + } /* switch (t_alarm.entity) */ + + return; +} + +/******************************************************************************/ +static void handle_entsi_alarm(sng_alrm_t alarm) +{ + + switch (alarm.event) { + /**************************************************************************/ + case (LCM_EVENT_TIMEOUT): + /* this event always has the circuit value embedded */ + SS7_WARN("[ISUP] Timer %d expired on CIC %d\n", + (alarm.eventParm[1] > 0 ) ? alarm.eventParm[1] : alarm.eventParm[8], + g_ftdm_sngss7_data.cfg.isupCircuit[alarm.eventParm[0]].cic); + break; + /**************************************************************************/ + case (LSI_EVENT_REMOTE): + SS7_WARN("[ISUP] %s received on CIC %d\n", + DECODE_LSI_CAUSE(alarm.cause), + g_ftdm_sngss7_data.cfg.isupCircuit[alarm.eventParm[0]].cic); + break; + /**************************************************************************/ + case (LSI_EVENT_LOCAL): + SS7_WARN("[ISUP] %s transmitted on CIC %d\n", + DECODE_LSI_CAUSE(alarm.cause), + g_ftdm_sngss7_data.cfg.isupCircuit[alarm.eventParm[0]].cic); + break; + /**************************************************************************/ + case (LSI_EVENT_MTP): + SS7_WARN("[ISUP] Received %s on %d\n", + DECODE_LSI_CAUSE(alarm.cause), + g_ftdm_sngss7_data.cfg.mtp3_isup[alarm.eventParm[2]].id); + break; + /**************************************************************************/ + case (LCM_EVENT_UI_INV_EVT): + switch (alarm.cause) { + /**********************************************************************/ + case (LSI_CAUSE_INV_CIRCUIT): + SS7_WARN("[ISUP] Invalid circuit = %d (CIC = %d)\n", + alarm.eventParm[0], + g_ftdm_sngss7_data.cfg.isupCircuit[alarm.eventParm[0]].cic); + break; + /**********************************************************************/ + } + break; + /**************************************************************************/ + case (LCM_EVENT_LI_INV_EVT): + switch (alarm.cause) { + /**********************************************************************/ + case (LCM_CAUSE_INV_SAP): + SS7_WARN("[ISUP] Invalid spId = %d\n", + alarm.eventParm[3]); + break; + /**********************************************************************/ + } + break; + /**************************************************************************/ + default: + SS7_WARN("[ISUP] %s : %s \n", DECODE_LSI_EVENT(alarm.event), DECODE_LSI_CAUSE(alarm.cause)); + break; + /**************************************************************************/ + } /* switch (alarm.event) */ + return; +} + +/* ACTIVATION *****************************************************************/ +int ft_to_sngss7_activate_all(void) +{ + sng_isup_cc_t *cc_isup = NULL; + sng_mtp3_isup_t *isup_mtp3 = NULL; + sng_mtp3LinkSet_t *mtp3_linkset = NULL; + int x; + + /* CC to ISUP *************************************************************/ + x = 1; + cc_isup = &g_ftdm_sngss7_data.cfg.isup_cc[x]; + while (cc_isup->id != 0) { + if (sngss7_test_flag(cc_isup, SNGSS7_FLAG_ACTIVE)) { + SS7_DEBUG("CC-ISUP interface already active = %d\n", cc_isup->id); + } else { + if (sng_activate_cc_isup_inf(cc_isup->ccId)) { + SS7_ERROR("Failed to activate CC-ISUP = %d\n",cc_isup->id); + return FTDM_FAIL; + } else { + SS7_INFO("Started CC-ISUP interface = %d\n", cc_isup->id); + sngss7_set_flag(cc_isup, SNGSS7_FLAG_ACTIVE); + } + } /* if (sngss7_test_flag(cc_isup, SNGSS7_FLAG_ACTIVE) */ + + x++; + cc_isup = &g_ftdm_sngss7_data.cfg.isup_cc[x]; + } /* while (cc_isup->id != 0) */ + + /* ISUP - MTP3 ************************************************************/ + x = 1; + isup_mtp3 = &g_ftdm_sngss7_data.cfg.mtp3_isup[x]; + while (isup_mtp3->id != 0) { + if (sngss7_test_flag(isup_mtp3, SNGSS7_FLAG_ACTIVE)) { + SS7_DEBUG("ISUP-MTP3 interface already active = %d\n", isup_mtp3->id); + } else { + if (sng_activate_isup_mtp3_inf(isup_mtp3->id)) { + SS7_ERROR("Failed to activate ISUP-MTP3 = %d\n",isup_mtp3->id); + return FTDM_FAIL; + } else { + SS7_INFO("Started ISUP-MTP3interface = %d\n", isup_mtp3->id); + sngss7_set_flag(isup_mtp3, SNGSS7_FLAG_ACTIVE); + } + } /* if (sngss7_test_flag(isup_mtp3, SNGSS7_FLAG_ACTIVE) */ + + x++; + isup_mtp3 = &g_ftdm_sngss7_data.cfg.mtp3_isup[x]; + } /* while (isup_mtp3->id != 0) */ + + /* MTP3 Linkset (MTP3 - MTP2 - MTP1) **************************************/ + x = 1; + mtp3_linkset = &g_ftdm_sngss7_data.cfg.mtp3LinkSet[x]; + while (mtp3_linkset->id != 0) { + if (sngss7_test_flag(mtp3_linkset, SNGSS7_FLAG_ACTIVE)) { + SS7_DEBUG("MTP3 Linkset already active = %s\n", mtp3_linkset->name); + } else { + if (sng_activate_mtp3_linkset(mtp3_linkset->id)) { + SS7_ERROR("Failed to activate MTP3 Linkset = %s\n",mtp3_linkset->name); + return FTDM_FAIL; + } else { + SS7_INFO("Started MTP3 Linkset = %s\n", mtp3_linkset->name); + sngss7_set_flag(mtp3_linkset, SNGSS7_FLAG_ACTIVE); + } + } /* if (sngss7_test_flag(mtp3_linkset, SNGSS7_FLAG_ACTIVE) */ + + x++; + mtp3_linkset = &g_ftdm_sngss7_data.cfg.mtp3LinkSet[x]; + } /* while (mtp3_linkset->id != 0) */ + + return FTDM_SUCCESS; +} + +/* CONFIGURATION **************************************************************/ +int ft_to_sngss7_cfg(void) +{ + sng_mtp1Link_t *mtp1_link = NULL; + sng_mtp2Link_t *mtp2_link = NULL; + sng_mtp3Link_t *mtp3_link = NULL; + sng_mtp3LinkSet_t *mtp3_linkset = NULL; + sng_mtp3Route_t *mtp3_route = NULL; + sng_mtp3_isup_t *mtp3_isup = NULL; + sng_mtp3_isup_t *isup_mtp3 = NULL; + sng_isupInterface_t *isup_interface = NULL; + sng_isupCircuit_t *isup_circuit = NULL; + sng_isup_cc_t *isup_cc = NULL; + sng_isup_cc_t *cc_isup = NULL; + int x; + + SS7_DEBUG("Starting LibSngSS7 configuration...\n"); + + if (g_ftdm_sngss7_data.gen_config_done == 0) { + /* perform general configuration */ + if(ftmod_ss7_general_configuration()) { + SS7_ERROR("Failed to run general configuration!\n"); + return FTDM_FAIL; + } else { + SS7_INFO("General Configuration was successful\n"); + g_ftdm_sngss7_data.gen_config_done = 1; + } + } else { + SS7_DEBUG("General configuration already done.\n"); + } + + /* MTP1 *******************************************************************/ + x=1; + mtp1_link = &g_ftdm_sngss7_data.cfg.mtp1Link[x]; + while (mtp1_link->id != 0) { + + if (sngss7_test_flag(mtp1_link, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("MTP1 Link already configured = %s\n",mtp1_link->name); + } else { + if (ftmod_ss7_configure_mtp1_link(x)) { + SS7_ERROR("Failed to configure MTP1 link = %s\n!", mtp1_link->name); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured MTP1 link = %s\n", mtp1_link->name); + sngss7_set_flag(mtp1_link, SNGSS7_FLAG_CONFIGURED); + } + } + + /* next link */ + x++; + mtp1_link = &g_ftdm_sngss7_data.cfg.mtp1Link[x]; + } /* while (g_ftdm_sngss7_data.cfg.mtp1Link[x]->id != 0) */ + + /* MTP2 *******************************************************************/ + x=1; + mtp2_link = &g_ftdm_sngss7_data.cfg.mtp2Link[x]; + while (mtp2_link->id != 0) { + if (sngss7_test_flag(mtp2_link, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("MTP2 Link already configured = %s\n",mtp2_link->name); + } else { + if (ftmod_ss7_configure_mtp2_link(x)) { + SS7_ERROR("Failed to configure MTP2 link = %s\n!", mtp2_link->name); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured MTP2 link = %s\n", mtp2_link->name); + sngss7_set_flag(mtp2_link, SNGSS7_FLAG_CONFIGURED); + } + } + /* next link */ + x++; + mtp2_link = &g_ftdm_sngss7_data.cfg.mtp2Link[x]; + } /* while (g_ftdm_sngss7_data.cfg.mtp2Link[x]->id != 0) */ + + /* MTP3 *******************************************************************/ + x=1; + mtp3_link = &g_ftdm_sngss7_data.cfg.mtp3Link[x]; + while (mtp3_link->id != 0) { + if (sngss7_test_flag(mtp3_link, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("MTP3 Link already configured = %s\n", mtp3_link->name); + } else { + if (ftmod_ss7_configure_mtp3_link(x)) { + SS7_ERROR("Failed to configure MTP3 link = %s\n!", mtp3_link->name); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured MTP3 link = %s\n", mtp3_link->name); + sngss7_set_flag(mtp3_link, SNGSS7_FLAG_CONFIGURED); + } + } + /* next link */ + x++; + mtp3_link = &g_ftdm_sngss7_data.cfg.mtp3Link[x]; + } /* while (g_ftdm_sngss7_data.cfg.mtp3Link[x]->id != 0) */ + + x=1; + mtp3_linkset = &g_ftdm_sngss7_data.cfg.mtp3LinkSet[x]; + while (mtp3_linkset->id != 0) { + if (sngss7_test_flag(mtp3_linkset, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("MTP3 LinkSet already configured = %s\n", mtp3_linkset->name); + } else { + if (ftmod_ss7_configure_mtp3_linkset(x)) { + SS7_ERROR("Failed to configure MTP3 link = %s\n!", mtp3_linkset->name); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured MTP3 link = %s\n", mtp3_linkset->name); + sngss7_set_flag(mtp3_linkset, SNGSS7_FLAG_CONFIGURED); + } + } + /* next link */ + x++; + mtp3_linkset = &g_ftdm_sngss7_data.cfg.mtp3LinkSet[x]; + } /* while (g_ftdm_sngss7_data.cfg.mtp1Link[x]->id != 0) */ + + x=1; + mtp3_route = &g_ftdm_sngss7_data.cfg.mtp3Route[x]; + while (mtp3_route->id != 0) { + if (sngss7_test_flag(mtp3_route, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("MTP3 Route already configured = %s\n", mtp3_route->name); + } else { + if (ftmod_ss7_configure_mtp3_route(x)) { + SS7_ERROR("Failed to configure MTP3 route = %s\n!", mtp3_route->name); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured MTP3 route = %s\n", mtp3_route->name); + sngss7_set_flag(mtp3_route, SNGSS7_FLAG_CONFIGURED); + } + } + /* next link */ + x++; + mtp3_route = &g_ftdm_sngss7_data.cfg.mtp3Route[x]; + } /* while (g_ftdm_sngss7_data.cfg.mtp3Route[x]->id != 0) */ + + mtp3_route = &g_ftdm_sngss7_data.cfg.mtp3Route[0]; + if (sngss7_test_flag(mtp3_route, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("MTP3 Self Route already configured\n"); + } else { + if (ftmod_ss7_configure_mtp3_route(0)) { + SS7_ERROR("Failed to configure MTP3 Route = SelfRoute\n!"); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured MTP3 Route = SelfRoute\n"); + sngss7_set_flag(mtp3_route, SNGSS7_FLAG_CONFIGURED); + } + } + + x=1; + mtp3_isup = &g_ftdm_sngss7_data.cfg.mtp3_isup[x]; + while (mtp3_isup->id != 0) { + if (sngss7_test_flag(mtp3_isup, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("MTP3-ISUP interface already configured = %d\n", mtp3_isup->id); + } else { + if (ftmod_ss7_configure_mtp3_isup(x)) { + SS7_ERROR("Failed to configure MTP3-ISUP interface = %d\n!", mtp3_isup->id); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured MTP3-ISUP interface = %d\n", mtp3_isup->id); + } + } + /* next link */ + x++; + mtp3_isup = &g_ftdm_sngss7_data.cfg.mtp3_isup[x]; + } /* while (g_ftdm_sngss7_data.cfg.mtp3_isup[x]->id != 0) */ + + /* ISUP *******************************************************************/ + x=1; + isup_mtp3 = &g_ftdm_sngss7_data.cfg.mtp3_isup[x]; + while (isup_mtp3->id != 0) { + if (sngss7_test_flag(isup_mtp3, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("ISUP-MTP3 interface already configured = %d\n", isup_mtp3->id); + } else { + if (ftmod_ss7_configure_isup_mtp3(x)) { + SS7_ERROR("Failed to configure ISUP-MTP3 interface = %d\n!", isup_mtp3->id); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured ISUP-MTP3 interface = %d\n", isup_mtp3->id); + sngss7_set_flag(isup_mtp3, SNGSS7_FLAG_CONFIGURED); + } + } + /* next link */ + x++; + isup_mtp3 = &g_ftdm_sngss7_data.cfg.mtp3_isup[x]; + } /* while (g_ftdm_sngss7_data.cfg.isup_mtp3[x]->id != 0) */ + + x=1; + isup_cc = &g_ftdm_sngss7_data.cfg.isup_cc[x]; + while (isup_cc->id != 0) { + if (sngss7_test_flag(isup_cc, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("ISUP-CC interface already configured = %d\n", isup_cc->id); + } else { + if (ftmod_ss7_configure_isup_cc(x)) { + SS7_ERROR("Failed to configure ISUP-CC interface = %d\n!", isup_cc->id); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured ISUP-CC interface = %d\n", isup_cc->id); + } + } + /* next link */ + x++; + isup_cc = &g_ftdm_sngss7_data.cfg.isup_cc[x]; + } /* while (g_ftdm_sngss7_data.cfg.isup_cc[x]->id != 0) */ + + x=1; + isup_interface = &g_ftdm_sngss7_data.cfg.isupInterface[x]; + while (isup_interface->id != 0) { + if (sngss7_test_flag(isup_interface, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("ISUP interface already configured = %s\n", isup_interface->name); + } else { + if (ftmod_ss7_configure_isup_interface(x)) { + SS7_ERROR("Failed to configure ISUP interface = %s\n!", isup_interface->name); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured ISUP interface = %s\n", isup_interface->name); + sngss7_set_flag(isup_interface, SNGSS7_FLAG_CONFIGURED); + } + } + /* next link */ + x++; + isup_interface = &g_ftdm_sngss7_data.cfg.isupInterface[x]; + } /* while (g_ftdm_sngss7_data.cfg.isup_interface[x]->id != 0) */ + + x=1; + isup_circuit = &g_ftdm_sngss7_data.cfg.isupCircuit[x]; + while (isup_circuit->id != 0) { + if (isup_circuit->cic != 0) { + if (sngss7_test_flag(isup_circuit, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("ISUP Circuit already configured = %d\n", isup_circuit->id); + } else { + if (ftmod_ss7_configure_isup_circuit(x)) { + SS7_ERROR("Failed to configure ISUP circuit = %d\n!", isup_circuit->id); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured ISUP circuit = %d\n", isup_circuit->id); + sngss7_set_flag(isup_circuit, SNGSS7_FLAG_CONFIGURED); + } + } + } + /* next link */ + x++; + isup_circuit = &g_ftdm_sngss7_data.cfg.isupCircuit[x]; + } /* while (g_ftdm_sngss7_data.cfg.isup_circuit[x]->id != 0) */ + + /* CC *********************************************************************/ + + x=1; + cc_isup = &g_ftdm_sngss7_data.cfg.isup_cc[x]; + while (cc_isup->id != 0) { + if (sngss7_test_flag(cc_isup, SNGSS7_FLAG_CONFIGURED)) { + SS7_DEBUG("CC-ISUP interface already configured = %d\n", cc_isup->id); + } else { + if (ftmod_ss7_configure_cc_isup(x)) { + SS7_ERROR("Failed to configure CC-ISUP interface = %d\n!", cc_isup->id); + return FTDM_FAIL; + } else { + SS7_INFO("Successfully configured CC-ISUP interface = %d\n", cc_isup->id); + sngss7_set_flag(cc_isup, SNGSS7_FLAG_CONFIGURED); + } + } + /* next link */ + x++; + cc_isup = &g_ftdm_sngss7_data.cfg.isup_cc[x]; + } /* while (g_ftdm_sngss7_data.cfg.cc_isup[x]->id != 0) */ + + SS7_DEBUG("Finished LibSngSS7 configuration...\n"); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_general_configuration(void) +{ + + if(sng_cfg_mtp1_gen(&g_ftdm_sngss7_data.cfg)) { + SS7_ERROR("General configuration for MTP1 failed!\n"); + return FTDM_FAIL; + } else { + SS7_INFO("General configuration for MTP1 was successful\n"); + } + + if(sng_cfg_mtp2_gen(&g_ftdm_sngss7_data.cfg)) { + SS7_ERROR("General configuration for MTP2 failed!\n"); + return FTDM_FAIL; + } else { + SS7_INFO("General configuration for MTP2 was successful\n"); + } + + if(sng_cfg_mtp3_gen(&g_ftdm_sngss7_data.cfg)) { + SS7_ERROR("General configuration for MTP3 failed!\n"); + return FTDM_FAIL; + } else { + SS7_INFO("General configuration for MTP3 was successful\n"); + } + + if(sng_cfg_isup_gen(&g_ftdm_sngss7_data.cfg)) { + SS7_ERROR("General configuration for ISUP failed!\n"); + return FTDM_FAIL; + } else { + SS7_INFO("General configuration for ISUP was successful\n"); + } + + if(sng_cfg_cc_gen(&g_ftdm_sngss7_data.cfg)) { + SS7_ERROR("General configuration for Call-Control failed!\n"); + return FTDM_FAIL; + } else { + SS7_INFO("General configuration for Call-Control was successful\n"); + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_configure_mtp1_link(int id) +{ + if(sng_cfg_mtp1_link(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_mtp2_link(int id) +{ + if(sng_cfg_mtp2_link(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_mtp3_link(int id) +{ + if(sng_cfg_mtp3_link(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_mtp3_linkset(int id) +{ + if(sng_cfg_mtp3_linkset(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_mtp3_route(int id) +{ + if(sng_cfg_mtp3_route(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_mtp3_isup(int id) +{ + if(sng_cfg_mtp3_isup_interface(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_isup_mtp3(int id) +{ + if(sng_cfg_isup_mtp3_interface(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_isup_interface(int id) +{ + if(sng_cfg_isup_interface(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_isup_circuit(int id) +{ + if(sng_cfg_isup_circuit(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_isup_cc(int id) +{ + if(sng_cfg_isup_cc_interface(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + +/******************************************************************************/ +static int ftmod_ss7_configure_cc_isup(int id) +{ + if(sng_cfg_cc_isup_interface(&g_ftdm_sngss7_data.cfg, id)){ + return FTDM_FAIL; + } else { + return FTDM_SUCCESS; + } +} + + +/******************************************************************************/ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ +/******************************************************************************/ + diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c new file mode 100644 index 0000000000..d720e70bc2 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c @@ -0,0 +1,1482 @@ +/* + * Copyright (c) 2009, Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); +void sngss7_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); +void sngss7_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCnStEvnt *siCnStEvnt, uint8_t evntType); +void sngss7_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt); +void sngss7_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt); +void sngss7_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiInfoEvnt *siInfoEvnt); +void sngss7_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); +void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); +void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit); + +static ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_pause(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_resume(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); + +static ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_cot_stop(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_cot(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); + +static ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_local_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); + +static ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_blo_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +static ftdm_status_t handle_ubl_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); + + + +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ +void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info ; + ftdm_channel_t *ftdmchan; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + }; + + SS7_MSG_TRACE("Received IAM on CIC # %d\n", sngss7_info->circuit->cic); + + /* check whether the ftdm channel is in a state to accept a call */ + switch (ftdmchan->state) { + /**************************************************************************/ + case (FTDM_CHANNEL_STATE_DOWN): /* only state it is fully valid to get IAM */ + + /* fill in the channels SS7 Stack information */ + sngss7_info->suInstId = get_unique_id(); + sngss7_info->spInstId = spInstId; + + /* try to open the ftdm channel */ + if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { + SS7_ERROR("Failed to open span: %d, chan: %d\n", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id); + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL); + + ftdmchan->caller_data.hangup_cause = 41; + + /* move the state to CANCEL */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + + } else { + + /* fill in cid/ani number */ + if (siConEvnt->cgPtyNum.addrSig.pres) { + copy_tknStr_from_sngss7(siConEvnt->cgPtyNum.addrSig, + ftdmchan->caller_data.cid_num.digits, + siConEvnt->cgPtyNum.oddEven); + + /* fill in cid Name */ + ftdm_set_string(ftdmchan->caller_data.cid_name, ftdmchan->caller_data.cid_num.digits); + + ftdm_set_string(ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.cid_num.digits); + + } else { + SS7_INFO("No Calling party (ANI) information in IAM!\n"); + } + + /* fill in dnis */ + if (siConEvnt->cdPtyNum.addrSig.pres) { + copy_tknStr_from_sngss7(siConEvnt->cdPtyNum.addrSig, + ftdmchan->caller_data.dnis.digits, + siConEvnt->cdPtyNum.oddEven); + } else { + SS7_INFO("No Called party (DNIS) information in IAM!\n"); + } + + /* fill in rdnis */ + if (siConEvnt->redirgNum.addrSig.pres) { + copy_tknStr_from_sngss7(siConEvnt->redirgNum.addrSig, + ftdmchan->caller_data.rdnis.digits, + siConEvnt->cgPtyNum.oddEven); + } else { + SS7_INFO("No RDNIS party information in IAM!\n"); + } + + /* fill in screening/presentation */ + ftdmchan->caller_data.screen = siConEvnt->cgPtyNum.scrnInd.val; + ftdmchan->caller_data.pres = siConEvnt->cgPtyNum.presRest.val; + + /* set the state of the channel to collecting...the rest is done by the chan monitor */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); + + } /* if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) */ + + break; + /**************************************************************************/ + case (FTDM_CHANNEL_STATE_DIALING): /* glare */ + SS7_ERROR("Got IAM in DIALING state...glare... queueing incoming call\n"); + + /* the flag the channel as having a collision */ + sngss7_set_flag(sngss7_info, FLAG_GLARE); + + /* save the IAM for processing once the channel has gone to DOWN */ + memcpy(&sngss7_info->glare.iam, siConEvnt, sizeof(*siConEvnt)); + sngss7_info->glare.suInstId = suInstId; + sngss7_info->glare.spInstId = spInstId; + sngss7_info->glare.circuit = circuit; + + break; + /**************************************************************************/ + default: /* should not have gotten an IAM while in this state */ + SS7_ERROR("Got IAM in an invalid state!\n"); + + /* move the state of the channel to RESTART to force a reset */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + + break; + /**************************************************************************/ + } /* switch (ftdmchan->state) */ + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void sngss7_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info ; + ftdm_channel_t *ftdmchan; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + }; + + SS7_MSG_TRACE("Received ANM on CIC # %d\n", sngss7_info->circuit->cic); + + /* check whether the ftdm channel is in a state to accept a call */ + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + + /* go to UP */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + + break; + /**************************************************************************/ + default: /* incorrect state...reset the CIC */ + + /* go to RESTART */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); + + break; + /**************************************************************************/ + } + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void sngss7_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCnStEvnt *siCnStEvnt, uint8_t evntType) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info ; + ftdm_channel_t *ftdmchan; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + switch (evntType) { + /**************************************************************************/ + case (ADDRCMPLT): + SS7_MSG_TRACE("Received ACM on CIC # %d\n", sngss7_info->circuit->cic); + switch (ftdmchan->state) { + /**********************************************************************/ + case FTDM_CHANNEL_STATE_DIALING: + /* KONRAD: should we confirm the instance ids ? */ + + /* need to grab the sp instance id */ + sngss7_info->spInstId = spInstId; + + /* go to PROGRESS */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); + break; + /**********************************************************************/ + default: /* incorrect state...reset the CIC */ + /* go to RESTART */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); + break; + /**********************************************************************/ + } /* switch (ftdmchan->state) */ + /**************************************************************************/ + case (MODIFY): + SS7_MSG_TRACE("Received MODIFY on CIC # %d\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MODCMPLT): + SS7_MSG_TRACE( "Received MODIFY_COMPLETE on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (MODREJ): + SS7_MSG_TRACE( "Received MODIFY_REJECT on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (PROGRESS): + SS7_MSG_TRACE( "Received CPG on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (FRWDTRSFR): + SS7_MSG_TRACE( "Received FOT on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (INFORMATION): + SS7_MSG_TRACE( "Received INF on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (INFORMATREQ): + SS7_MSG_TRACE( "Received INR on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (SUBSADDR): + SS7_MSG_TRACE( "Received SAM on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (EXIT): + SS7_MSG_TRACE( "Received EXIT on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (NETRESMGT): + SS7_MSG_TRACE( "Received NRM on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (IDENTREQ): + SS7_MSG_TRACE( "Received IDR on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (IDENTRSP): + SS7_MSG_TRACE( "Received IRS on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (MALCLLPRNT): + SS7_MSG_TRACE( "Received MALICIOUS CALL on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (CHARGE): + SS7_MSG_TRACE( "Received CRG on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (TRFFCHGE): + SS7_MSG_TRACE( "Received CRG-Tariff Change on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (CHARGEACK): + SS7_MSG_TRACE( "Received CRG-Acknowledge on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (CALLOFFMSG): + SS7_MSG_TRACE( "Received CALL_OFFER on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (LOOPPRVNT): + SS7_MSG_TRACE( "Received LOP on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (TECT_TIMEOUT): + SS7_MSG_TRACE( "Received ECT Timeout on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (RINGSEND): + SS7_MSG_TRACE( "Received Ringing Send on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (CALLCLEAR): + SS7_MSG_TRACE( "Received Call_Line_clear on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (PRERELEASE): + SS7_MSG_TRACE( "Received PRI on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (APPTRANSPORT): + SS7_MSG_TRACE( "Received APM on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (OPERATOR): + SS7_MSG_TRACE( "Received Operator on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (METPULSE): + SS7_MSG_TRACE( "Received Metering Pulse on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (CLGPTCLR): + SS7_MSG_TRACE( "Received Calling_Party_Clear on circuit # %d\n", circuit); + break; + /**************************************************************************/ + case (SUBDIRNUM): + SS7_MSG_TRACE( "Received subsequent directory number on circuit # %d\n", circuit); + break; + /**************************************************************************/ + default: + ftdm_log(FTDM_LOG_ERROR, "Received Unknown message on circuit # %d\n", circuit); + break; + /**************************************************************************/ + } + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void sngss7_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info ; + ftdm_channel_t *ftdmchan; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + }; + + SS7_MSG_TRACE("Received REL on CIC # %d\n", sngss7_info->circuit->cic); + + /* check whether the ftdm channel is in a state to release a call */ + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_RING: + case FTDM_CHANNEL_STATE_DIALING: + case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + case FTDM_CHANNEL_STATE_UP: + + /* pass the release code up to FTDM */ + if (siRelEvnt->causeDgn.causeVal.pres) { + ftdmchan->caller_data.hangup_cause = siRelEvnt->causeDgn.causeVal.val; + } else { + SS7_ERROR("REL does not have a cause code!\n"); + ftdmchan->caller_data.hangup_cause = 0; + } + + /* move the state of the channel to TERMINATING to end the call */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + + break; + /**************************************************************************/ + default: + + /* fill in the channels SS7 Stack information */ + sngss7_info->suInstId = get_unique_id(); + sngss7_info->spInstId = spInstId; + + /* throw the reset flag */ + sngss7_set_flag(sngss7_info, FLAG_RESET_RX); + + /* set the state to RESTART */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + break; + /**************************************************************************/ + } /* switch (ftdmchan->state) */ + + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + + +/******************************************************************************/ +void sngss7_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info ; + ftdm_channel_t *ftdmchan; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + }; + + SS7_MSG_TRACE("Received RLC on CIC # %d\n", sngss7_info->circuit->cic); + + /* check whether the ftdm channel is in a state to accept a call */ + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: + + /* go to DOWN */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_DOWN: + /* do nothing, just drop the message */ + break; + /**************************************************************************/ + default: + /* KONRAD: should just stop the call...but a reset is easier for now (since it does hangup the call) */ + + /* go to RESTART */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + + break; + /**************************************************************************/ + } + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void sngss7_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiInfoEvnt *siInfoEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + SS7_MSG_TRACE( "Received DATA indication on circuit # %d\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void sngss7_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + SS7_MSG_TRACE( "Received FAC request on circuit # %d\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + SS7_MSG_TRACE( "Received FAC confirm on circuit # %d\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + SS7_MSG_TRACE( "Received User to User message on circuit # %d\n", circuit); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/* GENERAL STATUS *************************************************************/ +void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + SS7_MSG_TRACE("[SNG-CC] Received %s indicaton on cic = %d\n", + DECODE_LCC_EVENT(evntType), + g_ftdm_sngss7_data.cfg.isupCircuit[circuit].cic); + + switch (evntType) { + /**************************************************************************/ + case SIT_STA_REATTEMPT: /* reattempt indication */ + handle_reattempt(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_ERRORIND: /* error indication */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CONTCHK: /* continuity check */ + handle_cot_start(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CONTREP: /* continuity report */ + handle_cot(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_STPCONTIN: /* stop continuity */ + handle_cot_stop(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CGQRYRSP: /* circuit grp query response from far end forwarded to upper layer by ISUP */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CONFUSION: /* confusion */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_LOOPBACKACK: /* loop-back acknowledge */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CIRRSRVREQ: /* circuit reservation request */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CIRRSRVACK: /* circuit reservation acknowledgement */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CIRBLOREQ: /* circuit blocking request */ + handle_blo_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CIRBLORSP: /* circuit blocking response */ + handle_blo_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CIRUBLREQ: /* circuit unblocking request */ + handle_ubl_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CIRUBLRSP: /* circuit unblocking response */ + handle_ubl_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CIRRESREQ: /* circuit reset request - RSC */ + handle_rsc_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CIRLOCRES: /* reset initiated locally by the software */ + handle_local_rsc_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CIRRESRSP: /* circuit reset response */ + handle_rsc_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_CGBREQ: /* CGB request */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CGUREQ: /* CGU request */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CGQRYREQ: /* circuit group query request */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CGBRSP: /* mntc. oriented CGB response */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CGURSP: /* mntc. oriented CGU response */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_GRSREQ: /* circuit group reset request */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CIRUNEQPD: /* circuit unequipped indication */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_GRSRSP: /* circuit group reset response */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_PAUSEIND: /* pause indication */ + handle_pause(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_RESUMEIND: /* resume indication */ + handle_resume(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); + break; + /**************************************************************************/ + case SIT_STA_USRPARTA: /* user part available */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_RMTUSRUNAV: /* remote user not available */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_MTPCONG0: /* congestion indication level 0 */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_MTPCONG1: /* congestion indication level 1 */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_MTPCONG2: /* congestion indication level 2 */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_MTPCONG3: /* congestion indication level 3 */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_MTPSTPCONG: /* stop congestion indication level 0 */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CIRLOCALBLOIND: /* Mngmt local blocking */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CIRLOCALUBLIND: /* Mngmt local unblocking */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_OVERLOAD: /* Overload */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_LMCGBREQ: /* when LM requests ckt grp blocking */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_LMCGUREQ: /* when LM requests ckt grp unblocking */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_LMGRSREQ: /* when LM requests ckt grp reset */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CGBINFOIND: /* circuit grp blking ind , no resp req */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_LMCQMINFOREQ: /* when LM requests ckt grp query */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_CIRLOCGRS: /* group reset initiated locally by the software */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_GRSRSPIND: /* indication to IW to idle the RM */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + case SIT_STA_RLCIND: /* RLC indicattion to IW to idle the RM */ + SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + break; + /**************************************************************************/ + default: + SS7_INFO("[SNG-CC] Received Unknown indication %d\n", evntType); + break; + } /* switch (evntType) */ + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +static ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for ISUP circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_DIALING: + /* glare, go to down state*/ + + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + + break; + /**************************************************************************/ + default: + /* fuck...this shouldn't happen */ + SS7_ERROR("Received reattempt indication on CIC %d in invalid state %s\n", + sngss7_info->circuit->cic, + ftdm_channel_state2str(ftdmchan->state)); + + /* throw the channel into reset */ + sngss7_set_flag(sngss7_info, FLAG_RESET_TX); + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + + break; + /**************************************************************************/ + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_pause(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + int infId; + int i; + + /* extract the affect infId from the circuit structure */ + infId = g_ftdm_sngss7_data.cfg.isupCircuit[circuit].infId; + + /* go through all the circuits now and find any other circuits on this infId */ + i = 1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[i].id != 0) { + + /* check that the infId matches and that this is not a siglink */ + if ((g_ftdm_sngss7_data.cfg.isupCircuit[i].infId == infId) && + (g_ftdm_sngss7_data.cfg.isupCircuit[i].siglink == 0)) { + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + i++; + continue; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + i++; + continue; + }; + + /* set the pause flag on the channel */ + sngss7_set_flag(sngss7_info, FLAG_INFID_PAUSED); + + /* set the statet o SUSPENDED to bring the sig status down */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + } /* if (g_ftdm_sngss7_data.cfg.isupCircuit[i].infId == infId) */ + + /* move to the next circuit */ + i++; + + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[i].id != 0) */ + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_resume(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + int infId; + int i; + + /* extract the affect infId from the circuit structure */ + infId = g_ftdm_sngss7_data.cfg.isupCircuit[circuit].infId; + + /* go through all the circuits now and find any other circuits on this infId */ + i = 1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[i].id != 0) { + + /* check that the infId matches and that this is not a siglink */ + if ((g_ftdm_sngss7_data.cfg.isupCircuit[i].infId == infId) && + (g_ftdm_sngss7_data.cfg.isupCircuit[i].siglink == 0)) { + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + i++; + continue; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + i++; + continue; + }; + + /* set the resume flag on the channel */ + sngss7_set_flag(sngss7_info, FLAG_INFID_RESUME); + + /* clear the paused flag */ + sngss7_clear_flag(sngss7_info, FLAG_INFID_PAUSED); + + /* set the statet to SUSPENDED to bring the sig status up */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + } /* if (g_ftdm_sngss7_data.cfg.isupCircuit[i].infId == infId) */ + + /* move to the next circuit */ + i++; + + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[i].id != 0) */ + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + /* open the channel if it is not open */ + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { + if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { + SS7_ERROR("Failed to open CIC %d for COT test!\n", sngss7_info->circuit->cic); + /* KONRAD FIX ME */ + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + } + + /* tell the core to loop the channel */ + ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_LOOP, NULL); + + /* switch to the IN_LOOP state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP); + + /* store the sngss7 ids */ + if (suInstId == 0) { + sngss7_info->suInstId = get_unique_id(); + } else { + sngss7_info->suInstId = suInstId; + } + sngss7_info->spInstId = spInstId; + sngss7_info->globalFlg = globalFlg; + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_cot_stop(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + /* tell the core to stop looping the channel */ + ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL); + + /* exit out of the LOOP state to the last state */ + ftdm_set_state_locked(ftdmchan, ftdmchan->last_state); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_cot(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + if ( (siStaEvnt->contInd.eh.pres > 0) && (siStaEvnt->contInd.contInd.pres > 0)) { + SS7_INFO("Continuity Test result for CIC = %d (span %d, chan %d) is: \"%s\"\n", + g_ftdm_sngss7_data.cfg.isupCircuit[circuit].cic, + g_ftdm_sngss7_data.cfg.isupCircuit[circuit].span, + g_ftdm_sngss7_data.cfg.isupCircuit[circuit].chan, + (siStaEvnt->contInd.contInd.val) ? "PASS" : "FAIL"); + } else { + SS7_ERROR("Recieved Continuity report containing no results!\n"); + } + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_RESTART: + /* since we are already in RESTART, the channel is already free... + * just waitng for the other side to clean up it's channel. + * just send an acknowledge to this reset, don't go through the master + * state handler....bad but... + */ + + sngss7_info->spInstId = 0; + sngss7_info->suInstId = 0; + sngss7_info->globalFlg = globalFlg; + + ft_to_sngss7_rsca(ftdmchan); + break; + /**************************************************************************/ + default: + /* throw the channels RESET_RX flag */ + sngss7_set_flag(sngss7_info, FLAG_RESET_RX); + + sngss7_info->spInstId = 0; + sngss7_info->suInstId = 0; + sngss7_info->globalFlg = globalFlg; + + /* set the state of the channel to restart...the rest is done by the chan monitor */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + break; + /**************************************************************************/ + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_local_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + /* the stack is sending out a RSC for us */ + sngss7_set_flag(sngss7_info, FLAG_RESET_RX); + + sngss7_info->spInstId = 0; + sngss7_info->suInstId = 0; + sngss7_info->globalFlg = globalFlg; + + /* set the state of the channel to restart...the rest is done by the chan monitor */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + switch (ftdmchan->state) { + /**********************************************************************/ + case FTDM_CHANNEL_STATE_RESTART: + + /* go to DOWN */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + + break; + /**********************************************************************/ + case FTDM_CHANNEL_STATE_DOWN: + /* do nothing, just drop the message */ + break; + /**********************************************************************/ + case FTDM_CHANNEL_STATE_TERMINATING: + case FTDM_CHANNEL_STATE_HANGUP: + case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: + /**********************************************************************/ + /* go to DOWN */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + + break; + /**********************************************************************/ + default: + /* ITU Q764-2.9.5.1.c -> release the circuit */ + if ((siStaEvnt != NULL) && + (siStaEvnt->causeDgn.eh.pres ==PRSNT_NODEF) && + (siStaEvnt->causeDgn.causeVal.pres == PRSNT_NODEF)) { + ftdmchan->caller_data.hangup_cause = siStaEvnt->causeDgn.causeVal.val; + } else { + ftdmchan->caller_data.hangup_cause = 98; /* Message not compatiable with call state */ + } + + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + break; + /**********************************************************************/ + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + /* check if the circuit is already blocked or not */ + if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) { + SS7_WARN("Received BLO on circuit that is already blocked!\n"); + } + + /* throw the ckt block flag */ + sngss7_set_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + + /* set the channel to suspended state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_blo_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + /* KONRAD FIX ME */ + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + /* check if the channel is blocked */ + if (!(sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX))) { + SS7_WARN("Received UBL on circuit that is not blocked!\n"); + } + + /* throw the unblock flag */ + sngss7_set_flag(sngss7_info, FLAG_CKT_MN_UNBLK_RX); + + /* clear the block flag */ + sngss7_clear_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + + /* set the channel to suspended state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_ubl_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + /* KONRAD FIX ME */ + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +#if 0 +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a pending state change, give it a bit to clear */ + if (check_for_state_change(ftdmchan)) { + SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + }; + + /* fill in here */ + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +#endif +/******************************************************************************/ +/******************************************************************************/ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ +/******************************************************************************/ + diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c new file mode 100644 index 0000000000..55c6e6a842 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -0,0 +1,1188 @@ +/* + * Copyright (c) 2009, Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ +static sng_isup_event_interface_t sng_event; +static ftdm_io_interface_t g_ftdm_sngss7_interface; +ftdm_sngss7_data_t g_ftdm_sngss7_data; +ftdm_sched_t *sngss7_sched; +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +static void *ftdm_ss7_run(ftdm_thread_t *me, void *obj); +static void ftdm_ss7_process_state_change(ftdm_channel_t *ftdmchan); + +static ftdm_status_t ftdm_ss7_stop(ftdm_span_t *span); +static ftdm_status_t ftdm_ss7_start(ftdm_span_t *span); +/******************************************************************************/ + +/* STATE MAP ******************************************************************/ +ftdm_state_map_t sangoma_ss7_state_map = { + { + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_ANY_STATE, FTDM_END}, + {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RESTART, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_CANCEL, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_DIALING, + FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, + FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + {FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_COLLECT, FTDM_END}, + {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}, + {FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_DOWN, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RING, FTDM_END}, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_UP, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + }, + /**************************************************************************/ + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_ANY_STATE, FTDM_END}, + {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END} + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RESTART, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_END} + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_CANCEL, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END} + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_DIALING, + FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, + FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END} + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + {FTDM_CHANNEL_STATE_DIALING, FTDM_END} + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_DIALING, FTDM_END}, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_DOWN, FTDM_END} + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END}, + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_UP, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}, + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + } + } +}; +/******************************************************************************/ + +/* MONITIOR THREADS ***********************************************************/ +static void *ftdm_ss7_run(ftdm_thread_t *me, void *obj) +{ + ftdm_interrupt_t *ftdm_ss7_int = NULL; + ftdm_span_t *span = (ftdm_span_t *) obj; + ftdm_channel_t *ftdmchan = NULL; + + ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u started.\n", span->span_id); + + /* set IN_THREAD flag so that we know this thread is running */ + ftdm_set_flag(span, FTDM_SPAN_IN_THREAD); + + /* get an interrupt queue for this span */ + if(ftdm_queue_get_interrupt(span->pendingchans, &ftdm_ss7_int) != FTDM_SUCCESS) { + SS7_CRITICAL("Failed to get a ftdm_interrupt for span = %d!\n", span->span_id); + goto ftdm_ss7_run_exit; + } + + while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) { + + /* find out why we returned from the interrupt queue */ + switch ((ftdm_interrupt_wait(ftdm_ss7_int, 100))) { + /**********************************************************************/ + case FTDM_SUCCESS: /* there was a state change on the span */ + /* process all pending state changes */ + while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) { + /* double check that this channel has a state change pending */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_ss7_process_state_change(ftdmchan); + } else { + SS7_ERROR("ftdm_core reported state change, but state change flag not set on ft-span = %d, ft-chan = %d\n", + ftdmchan->span_id, + ftdmchan->chan_id); + } + } /* while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) */ + + break; + /**********************************************************************/ + case FTDM_TIMEOUT: + SS7_DEVEL_DEBUG("ftdm_interrupt_wait timed-out on span = %d\n", span->span_id); + break; + /**********************************************************************/ + case FTDM_FAIL: + SS7_ERROR("ftdm_interrupt_wait returned error!\non span = %d\n", span->span_id); + break; + /**********************************************************************/ + default: + SS7_ERROR("ftdm_interrupt_wait returned with unknown code on span = %d\n", span->span_id); + break; + /**********************************************************************/ + } /* switch ((ftdm_interrupt_wait(ftdm_ss7_int, 100))) */ + + } /* master while loop */ + + /* clear the IN_THREAD flag so that we know the thread is done */ + ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD); + + ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u stopping.\n", span->span_id); + + return NULL; + +ftdm_ss7_run_exit: + + /* clear the IN_THREAD flag so that we know the thread is done */ + ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD); + + ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u stopping due to error.\n", span->span_id); + + ftdm_ss7_stop(span); + + return NULL; +} + +/******************************************************************************/ +static void ftdm_ss7_process_state_change(ftdm_channel_t *ftdmchan) +{ + ftdm_sigmsg_t sigev; + ftdm_signaling_status_t status; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset(&sigev, 0, sizeof(sigev)); + + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + + /*first lock the channel*/ + ftdm_mutex_lock(ftdmchan->mutex); + + /*clear the state change flag...since we might be setting a new state*/ + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); + + /*check what state we are supposed to be in*/ + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_COLLECT: /* IAM received but wating on digits */ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + int i = 0; + + while (ftdmchan->caller_data.cid_num.digits[i] != '\0') { + i++; + } + + /* check if the end of pulsing character has arrived or the right number of digits */ + if (ftdmchan->caller_data.cid_num.digits[i] == 0xF) { + SS7_DEBUG("Received the end of pulsing character\n"); + + /*now go to the RING state*/ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING); + } else if (i >= g_ftdm_sngss7_data.min_digits) { + SS7_DEBUG("Received %d digits (min digits = %d)\n", i, g_ftdm_sngss7_data.min_digits); + + /*now go to the RING state*/ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING); + } else { + SS7_INFO("Received %d out of %d so far: %s...starting T35\n", + i, + g_ftdm_sngss7_data.min_digits, + ftdmchan->caller_data.cid_num.digits); + + /* start ISUP t35 */ + if (ftdm_sched_timer(sngss7_info->t35.sched, + "t35", + sngss7_info->t35.beat, + sngss7_info->t35.callback, + &sngss7_info->t35, + &sngss7_info->t35.heartbeat_timer)) { + + SS7_ERROR("Unable to schedule timer, hanging up call!\n"); + + ftdmchan->caller_data.hangup_cause = 41; + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL); + + /* end the call */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + } else { + if(ftdm_sched_free_run(sngss7_info->t35.sched)) { + SS7_ERROR("Unable to run timer, hanging up call!\n"); + + ftdmchan->caller_data.hangup_cause = 41; + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL); + + /* end the call */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + } /* if(ftdm_sched_free_run(sngss7_info->t35.sched)) */ + } /* if (ftdm_sched_timer(sngss7_info->t35.sched, */ + + } /* checking ST/#digits */ + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_RING: /*incoming call request*/ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + SS7_DEBUG("Sending incoming call from %s to %s to FTDM core\n", + ftdmchan->caller_data.ani.digits, + ftdmchan->caller_data.dnis.digits); + + + /* we have enough information to inform FTDM of the call*/ + sigev.event_id = FTDM_SIGEVENT_START; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_DIALING: /*outgoing call request*/ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + /*call sangoma_ss7_dial to make outgoing call*/ + ft_to_sngss7_iam(ftdmchan); + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_PROGRESS: + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + /*check if the channel is inbound or outbound*/ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + /*OUTBOUND...so we were told by the line of this so noifiy the user*/ + sigev.event_id = FTDM_SIGEVENT_PROGRESS; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + + } else { + /* inbound call so we need to send out ACM */ + ft_to_sngss7_acm(ftdmchan); + } + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + /* nothing to do at this time */ + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_UP: /*call is accpeted...both incoming and outgoing*/ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + /*check if the channel is inbound or outbound*/ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + /*OUTBOUND...so we were told by the line that the other side answered*/ + sigev.event_id = FTDM_SIGEVENT_UP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + } else { + /*INBOUND...so FS told us it was going to answer...tell the stack*/ + ft_to_sngss7_anm(ftdmchan); + } + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_CANCEL: + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + SS7_ERROR("Hanging up call before informing user on span = %d, chan = %d!\n", ftdmchan->span_id,ftdmchan->chan_id); + + /*now go to the HANGUP complete state*/ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_TERMINATING: /*call is hung up remotely*/ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + /* set the flag to indicate this hangup is started from the remote side */ + sngss7_set_flag(sngss7_info, FLAG_REMOTE_REL); + + /*this state is set when the line is hanging up*/ + sigev.event_id = FTDM_SIGEVENT_STOP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_HANGUP: /*call is hung up locally*/ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + /* check for remote hangup flag */ + if (sngss7_test_flag(sngss7_info, FLAG_REMOTE_REL)) { + SS7_DEBUG("Hanging up remotely requested call!\n"); + } else { + SS7_DEBUG("Hanging up Locally requested call!\n"); + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL); + + /*this state is set when FS is hanging up...so tell the stack*/ + ft_to_sngss7_rel(ftdmchan); + } + + /*now go to the HANGUP complete state*/ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + if (sngss7_test_flag(sngss7_info, FLAG_REMOTE_REL)) { + + /* check if this hangup is from a tx RSC */ + if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX)) { + + /* go to RESTART State until RSCa is received */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } else { + if (!(sngss7_test_flag(sngss7_info, FLAG_RESET_RX))) { + /* send out the release complete */ + ft_to_sngss7_rlc(ftdmchan); + } + /*now go to the DOWN state*/ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } + + SS7_DEBUG("Completing remotely requested hangup!\n"); + } else { + SS7_DEBUG("Completing locally requested hangup!\n"); + } + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_DOWN: /*the call is finished and removed*/ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + + /* check if there is a reset response that needs to be sent */ + if (sngss7_test_flag(sngss7_info, FLAG_RESET_RX)) { + /* send a RLC */ + ft_to_sngss7_rsca(ftdmchan); + + /* inform Ftdm that the "sig" is up now for this channel */ + status = FTDM_SIG_STATE_UP; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.raw_data = &status; + ftdm_span_send_signal(ftdmchan->span, &sigev); + } + + /* check if we got the reset response */ + if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX)) { + /* inform Ftdm that the "sig" is up now for this channel */ + status = FTDM_SIG_STATE_UP; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.raw_data = &status; + ftdm_span_send_signal(ftdmchan->span, &sigev); + } + + /* check if the circuit has the glare flag up */ + if (sngss7_test_flag(sngss7_info, FLAG_GLARE)) { + SS7_DEBUG("Glare flag is up....spoofing incoming call on span=%, chan=%d\n", + ftdmchan->span_id,ftdmchan->chan_id); + /* clear all the call specific data */ + sngss7_info->suInstId = 0; + sngss7_info->spInstId = 0; + sngss7_info->globalFlg = 0; + sngss7_info->spId = 0; + sngss7_info->flags = 0; + + /* close the channel */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { + ftdm_channel_t *close_chan = ftdmchan; + /* close the channel */ + ftdm_channel_close(&close_chan); + } + + /* spoof an incoming call */ + sngss7_con_ind(sngss7_info->glare.suInstId, + sngss7_info->glare.spInstId, + sngss7_info->glare.circuit, + &sngss7_info->glare.iam); + } else { + /* clear all of the call specific data store in the channel structure */ + sngss7_info->suInstId = 0; + sngss7_info->spInstId = 0; + sngss7_info->globalFlg = 0; + sngss7_info->spId = 0; + sngss7_info->flags = 0; + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { + ftdm_channel_t *close_chan = ftdmchan; + /* close the channel */ + ftdm_channel_close(&close_chan); + } + } + + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_RESTART: /* CICs needs a Reset */ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) { + /* bring the call down first...then process the rest of the reset */ + switch (ftdmchan->last_state) { + /******************************************************************/ + case(FTDM_CHANNEL_STATE_TERMINATING): + case(FTDM_CHANNEL_STATE_HANGUP): + case(FTDM_CHANNEL_STATE_HANGUP_COMPLETE): + /* go back to the last state after taking care of the rest of the restart state */ + ftdm_set_state_locked(ftdmchan, ftdmchan->last_state); + break; + /******************************************************************/ + default: + /* KONRAD: find out what the cause code should be */ + ftdmchan->caller_data.hangup_cause = 41; + + /* change the state to terminatting, it will throw us back here + * once the call is done + */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + break; + /******************************************************************/ + } + } else { + + /* check if this an incoming RSC */ + if (sngss7_test_flag(sngss7_info, FLAG_RESET_RX)) { + /* go to a down state to clear the channel and send RSCa */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } /* if (sngss7_test_flag(sngss7_info, FLAG_RESET_RX)) */ + } /* if (inuse) */ + + /* check if this is an outgoing RSC */ + if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX)) { + + /* make sure we aren't coming from hanging up a call */ + if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP_COMPLETE) { + /* send a reset request */ + ft_to_sngss7_rsc(ftdmchan); + } + + /* don't change to the DOWN state as we need to wait for the RSCa */ + } /* if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX)) */ + + /* send a sig event to the core to disable the channel */ + status = FTDM_SIG_STATE_DOWN; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.raw_data = &status; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_SUSPENDED: /* circuit has been blocked */ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + /**********************************************************************/ + if (sngss7_test_flag(sngss7_info, FLAG_INFID_PAUSED)) { + SS7_DEBUG("processing pause for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id); + /* bring the channel signaling status to down */ + status = FTDM_SIG_STATE_DOWN; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.raw_data = &status; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* check the last state and return to it to allow the call to finish */ + ftdm_set_state_locked(ftdmchan, ftdmchan->last_state); + } + if (sngss7_test_flag(sngss7_info, FLAG_INFID_RESUME)) { + SS7_DEBUG("processing resume for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id); + /* we just resumed...throw the channel into reset */ + sngss7_set_flag(sngss7_info, FLAG_RESET_TX); + + /* clear the resume flag */ + sngss7_clear_flag(sngss7_info, FLAG_INFID_RESUME); + + /* go to restart state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } + /**********************************************************************/ + if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) { + SS7_DEBUG("processing rx Mn ckt block for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id); + /* bring the channel signaling status to down */ + status = FTDM_SIG_STATE_DOWN; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.raw_data = &status; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* send a BLA */ + ft_to_sngss7_bla(ftdmchan); + + /* check the last state and return to it to allow the call to finish */ + ftdm_set_state_locked(ftdmchan, ftdmchan->last_state); + } + if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_UNBLK_RX)) { + SS7_DEBUG("processing rx Mn ckt unblock for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id); + /* bring the channel signaling status to up */ + status = FTDM_SIG_STATE_UP; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.raw_data = &status; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* clear the unblock flag */ + sngss7_clear_flag(sngss7_info, FLAG_CKT_MN_UNBLK_RX); + + /* send a uba */ + ft_to_sngss7_uba(ftdmchan); + + /* check the last state and return to it to allow the call to finish */ + ftdm_set_state_locked(ftdmchan, ftdmchan->last_state); + } + /**********************************************************************/ + if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) { + SS7_DEBUG("processing tx Mn ckt block for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id); + /* bring the channel signaling status to down */ + status = FTDM_SIG_STATE_DOWN; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.raw_data = &status; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* send a blo */ + ft_to_sngss7_blo(ftdmchan); + + /* check the last state and return to it to allow the call to finish */ + ftdm_set_state_locked(ftdmchan, ftdmchan->last_state); + } + if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX)) { + SS7_DEBUG("processing tx Mn ckt unblock for span = %, chan = %d\n",ftdmchan->span_id,ftdmchan->chan_id); + /* bring the channel signaling status to up */ + status = FTDM_SIG_STATE_UP; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.raw_data = &status; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* clear the unblock flag */ + sngss7_clear_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + + /* send a ubl */ + ft_to_sngss7_ubl(ftdmchan); + + /* check the last state and return to it to allow the call to finish */ + ftdm_set_state_locked(ftdmchan, ftdmchan->last_state); + } + /**********************************************************************/ + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_IN_LOOP: /* COT test */ + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 processing state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + + /* send the lpa */ + ft_to_sngss7_lpa(ftdmchan); + + break; + /**************************************************************************/ + case FTDM_CHANNEL_STATE_HOLD: + case FTDM_CHANNEL_STATE_DIALTONE: + case FTDM_CHANNEL_STATE_BUSY: + case FTDM_CHANNEL_STATE_ATTN: + case FTDM_CHANNEL_STATE_GENRING: + case FTDM_CHANNEL_STATE_GET_CALLERID: + case FTDM_CHANNEL_STATE_CALLWAITING: + case FTDM_CHANNEL_STATE_IDLE: + case FTDM_CHANNEL_STATE_INVALID: + ftdm_log(FTDM_LOG_DEBUG, "ftmod_sangoma_ss7 does not support state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + break; + /**************************************************************************/ + default: + /*this is bad...we're in an unknown state...should we kill this channel???*/ + ftdm_log(FTDM_LOG_ERROR, "ftmod_sangoma_ss7 in unknown state %s on span=%u,chan=%u\n", + ftdm_channel_state2str(ftdmchan->state),ftdmchan->span_id,ftdmchan->chan_id); + break; + } /*switch (ftdmchan->state)*/ + + /*unlock*/ + ftdm_mutex_unlock(ftdmchan->mutex); + + return; +} +/******************************************************************************/ + +/******************************************************************************/ +static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_ss7_outgoing_call) +{ + sngss7_chan_data_t *sngss7_info; + int c; + + /* lock the channel while we check whether it is availble */ + ftdm_mutex_lock(ftdmchan->mutex); + + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_DOWN: + /* inform the monitor thread that we want to make a call */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING); + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* now we have to wait for either the stack to reject the call because of + * glare or for the network to acknowledge the call + */ + c = 0; + while (c < 20) { + + /* lock the channel while we check whether it is availble */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* extract the sngss7_chan_data structure */ + sngss7_info = (sngss7_chan_data_t *)ftdmchan->call_data; + + if (sngss7_test_flag(sngss7_info, FLAG_GLARE)) { + SS7_ERROR("Glare flag on span=%d, chan=%d\n", + ftdmchan->span_id,ftdmchan->chan_id); + + /* move the channel to DOWN to clear the existing channel allocations */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + goto outgoing_glare; + } + + switch (ftdmchan->state) { + /******************************************************************/ + case FTDM_CHANNEL_STATE_DIALING: + break; + /******************************************************************/ + case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + case FTDM_CHANNEL_STATE_UP: + SS7_DEBUG("Outgoing call request successful on span=%d, chan=%d\n", + ftdmchan->span_id,ftdmchan->chan_id); + goto outgoing_successful; + break; + /******************************************************************/ + default: + SS7_ERROR("Channel in invalid state (%s) on span=%d, chan=%d...should not happen\n", + ftdm_channel_state2str(ftdmchan->state), + ftdmchan->span_id, + ftdmchan->chan_id); + goto outgoing_fail; + break; + /******************************************************************/ + } + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* sleep for a bit to let the state change */ + ftdm_sleep(50); + + /* increment the timeout counter */ + c++; + + } /* while (c < 4) */ + + /* if we got here we have timed-out waiting for acknowledgment, kill the call */ + SS7_DEBUG("Timeout waiting for outgoing call to be accepted by network, ok'ing outgoing call on span=%d, chan=%d\n", + ftdmchan->span_id,ftdmchan->chan_id); + + /* consider the call good .... for now */ + goto outgoing_successful; + + break; + /**************************************************************************/ + default: + /* the channel is already used...this can't be, end the request */ + SS7_ERROR("Outgoing call requested channel in already in use...indicating glare on span=%d, chan=%d\n", + ftdmchan->span_id,ftdmchan->chan_id); + goto outgoing_glare; + break; + /**************************************************************************/ + } + + /* we should not get to this here...all exit points above use goto */ + SS7_ERROR("WE SHOULD NOT HERE HERE!!!!\n"); + +outgoing_fail: + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + return FTDM_FAIL; + +outgoing_glare: + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + return FTDM_BREAK; + +outgoing_successful: + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + return FTDM_SUCCESS; +} +/******************************************************************************/ +#if 0 +static FIO_CHANNEL_REQUEST_FUNCTION(ftdm_ss7_request_chan) +{ + SS7_INFO("KONRAD-> I got called %s\n",__FUNCTION__); + return FTDM_SUCCESS; +} +#endif + +/******************************************************************************/ + +/* FT-CORE SIG STATUS FUNCTIONS ***********************************************/ +static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_ss7_get_sig_status) +{ + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { + *status = FTDM_SIG_STATE_UP; + } else { + *status = FTDM_SIG_STATE_DOWN; + } + + return FTDM_SUCCESS; +} + +static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_ss7_set_sig_status) +{ + SS7_ERROR("Cannot set channel status in this module\n"); + + return FTDM_NOTIMPL; +} + +/* FT-CORE SIG FUNCTIONS *******************************************************/ +static ftdm_status_t ftdm_ss7_start(ftdm_span_t *span) +{ + SS7_INFO("Starting span %s:%u.\n",span->name,span->span_id); + + /* clear the monitor thread stop flag */ + ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD); + ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD); + + /* activate all the configured ss7 links */ + if (ft_to_sngss7_activate_all()) { + SS7_CRITICAL("Failed to activate LibSngSS7!\n"); + return FTDM_FAIL; + } + + /*start the span monitor thread*/ + if(ftdm_thread_create_detached(ftdm_ss7_run, span) != FTDM_SUCCESS) { + SS7_CRITICAL("Failed to start Span Monitor Thread!\n"); + return FTDM_FAIL; + } + + SS7_DEBUG("Finished starting span %s:%u.\n",span->name,span->span_id); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t ftdm_ss7_stop(ftdm_span_t *span) +{ + /*this function is called by the FT-Core to stop this span*/ + + ftdm_log(FTDM_LOG_INFO, "Stopping span %s:%u.\n",span->name,span->span_id); + + /* throw the STOP_THREAD flag to signal monitor thread stop */ + ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD); + + /* wait for the thread to stop */ + while(ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) { + ftdm_log(FTDM_LOG_DEBUG, "Waiting for monitor thread to end for %s:%u.\n",span->name,span->span_id); + ftdm_sleep(1); + } + + /* KONRAD FIX ME - deconfigure any circuits, links, attached to this span */ + + ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s:%u.\n",span->name,span->span_id); + + return FTDM_SUCCESS; +} +/******************************************************************************/ + +/* SIG_FUNCTIONS ***************************************************************/ +static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_ss7_span_config) +{ + ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_ss7 span = %s(%d)...\n", + span->name, + span->span_id); + + /* parse the configuration and apply to the global config structure */ + if (ftmod_ss7_parse_xml(ftdm_parameters, span)) { + ftdm_log(FTDM_LOG_CRIT, "Failed to parse configuration!\n"); + + return FTDM_FAIL; + } + + /* configure libsngss7 */ + if (ft_to_sngss7_cfg()) { + ftdm_log(FTDM_LOG_CRIT, "Failed to configure LibSngSS7!\n"); + return FTDM_FAIL; + } + + /*setup the span structure with the info so far*/ + g_ftdm_sngss7_data.sig_cb = sig_cb; + + span->start = ftdm_ss7_start; + span->stop = ftdm_ss7_stop; + span->signal_type = FTDM_SIGTYPE_SANGOMASS7; + span->signal_data = NULL; + span->outgoing_call = ftdm_ss7_outgoing_call; + span->channel_request = NULL; + span->signal_cb = sig_cb; + span->get_channel_sig_status = ftdm_ss7_get_sig_status; + span->set_channel_sig_status = ftdm_ss7_set_sig_status; + span->state_map = &sangoma_ss7_state_map; + ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE); + + ftdm_log(FTDM_LOG_INFO, "Finished configuring ftmod_sangoma_ss7 span = %s(%d)...\n", + span->name, + span->span_id); +#if 0 + /* start the span up */ + ftdm_ss7_start(span); +#endif + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static FIO_SIG_LOAD_FUNCTION(ftdm_ss7_init) +{ + /*this function is called by the FT-core to load the signaling module*/ + + ftdm_log(FTDM_LOG_INFO, "Loading ftmod_sangoma_ss7...\n"); + + /* default the global structure */ + memset(&g_ftdm_sngss7_data, 0x0, sizeof(ftdm_sngss7_data_t)); + + sngss7_id = 0; + + /* global flag indicating that general configuration has been done */ + g_ftdm_sngss7_data.gen_config_done = 0; + + /* min. number of digitis to wait for */ + g_ftdm_sngss7_data.min_digits = 7; + + /* function trace initizalation */ + g_ftdm_sngss7_data.function_trace = 1; + g_ftdm_sngss7_data.function_trace_level = 7; + + /* message (IAM, ACM, ANM, etc) trace initizalation */ + g_ftdm_sngss7_data.message_trace = 1; + g_ftdm_sngss7_data.message_trace_level = 7; + + /* create a timer schedule */ + if (ftdm_sched_create(&sngss7_sched, "SngSS7_Schedule")) { + SS7_CRITICAL("Unable to create timer schedule!\n"); + return FTDM_FAIL; + } + + /* setup the call backs needed by Sangoma_SS7 library */ + sng_event.cc.sng_con_ind = sngss7_con_ind; + sng_event.cc.sng_con_cfm = sngss7_con_cfm; + sng_event.cc.sng_con_sta = sngss7_con_sta; + sng_event.cc.sng_rel_ind = sngss7_rel_ind; + sng_event.cc.sng_rel_cfm = sngss7_rel_cfm; + sng_event.cc.sng_dat_ind = sngss7_dat_ind; + sng_event.cc.sng_fac_ind = sngss7_fac_ind; + sng_event.cc.sng_fac_cfm = sngss7_fac_cfm; + sng_event.cc.sng_sta_ind = sngss7_sta_ind; + sng_event.cc.sng_umsg_ind = sngss7_umsg_ind; + sng_event.cc.sng_susp_ind = NULL; + sng_event.cc.sng_resm_ind = NULL; + sng_event.cc.sng_ssp_sta_cfm = NULL; + + sng_event.sm.sng_log = handle_sng_log; + sng_event.sm.sng_mtp1_alarm = handle_sng_alarm; + sng_event.sm.sng_mtp2_alarm = handle_sng_alarm; + sng_event.sm.sng_mtp3_alarm = handle_sng_alarm; + sng_event.sm.sng_isup_alarm = handle_sng_alarm; + sng_event.sm.sng_cc_alarm = handle_sng_alarm; + + /* initalize sng_ss7 library */ + sng_isup_init(&sng_event); + + /* crash on assert fail */ + ftdm_global_set_crash_policy(FTDM_CRASH_ON_ASSERT); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static FIO_SIG_UNLOAD_FUNCTION(ftdm_ss7_unload) +{ + /*this function is called by the FT-core to unload the signaling module*/ + + ftdm_log(FTDM_LOG_INFO, "Starting ftmod_sangoma_ss7 unload...\n"); + + sng_isup_free(); + + ftdm_log(FTDM_LOG_INFO, "Finished ftmod_sangoma_ss7 unload!\n"); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static FIO_API_FUNCTION(ftdm_ss7_api) +{ + /* handle this in it's own file....so much to do */ + return (ftdm_sngss7_handle_cli_cmd(stream, data)); +} + +/******************************************************************************/ +static FIO_IO_LOAD_FUNCTION(ftdm_ss7_io_init) +{ + assert(fio != NULL); + memset(&g_ftdm_sngss7_interface, 0, sizeof(g_ftdm_sngss7_interface)); + + g_ftdm_sngss7_interface.name = "ss7"; + g_ftdm_sngss7_interface.api = ftdm_ss7_api; + + *fio = &g_ftdm_sngss7_interface; + + return FTDM_SUCCESS; +} + +/******************************************************************************/ + + +/* START **********************************************************************/ +ftdm_module_t ftdm_module = +{ + "sangoma_ss7", /*char name[256]; */ + ftdm_ss7_io_init, /*fio_io_load_t */ + NULL, /*fio_io_unload_t */ + ftdm_ss7_init, /*fio_sig_load_t */ + NULL, /*fio_sig_configure_t */ + ftdm_ss7_unload, /*fio_sig_unload_t */ + ftdm_ss7_span_config /*fio_configure_span_signaling_t */ +}; +/******************************************************************************/ + +/*****************************************************************************/ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + +/******************************************************************************/ + + diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h new file mode 100644 index 0000000000..5f4aacada1 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2009, Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/******************************************************************************/ +#ifndef __FTMOD_SNG_SS7_H__ +#define __FTMOD_SNG_SS7_H__ +/******************************************************************************/ + +/* INCLUDE ********************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "private/ftdm_core.h" + +#include "sng_sit.h" +#include "sng_ss7.h" +#include "sng_ss7_error.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +#define MAX_CIC_LENGTH 5 +#define MAX_CIC_MAP_LENGTH 256 +#define MAX_MTP_LINKS MAX_SN_LINKSETS + +#if 0 +#define SS7_HARDCODED +#endif +#define SNG_BASE 1 + +typedef enum { + SNG_IAM = 1, + SNG_ACM, + SNG_CPG, + SNG_ANM, + SNG_REL, + SNG_RLC +}sng_msg_type_t; + +typedef struct ftdm_sngss7_data { + sng_config_t cfg; + int gen_config_done; + int min_digits; + int function_trace; + int function_trace_level; + int message_trace; + int message_trace_level; + fio_signal_cb_t sig_cb; +}ftdm_sngss7_data_t; + +typedef struct sngss7_timer_data { + ftdm_timer_t *heartbeat_timer; + int beat; + int counter; + ftdm_sched_callback_t callback; + ftdm_sched_t *sched; + void *sngss7_info; +}sngss7_timer_data_t; + +typedef struct sngss7_glare_data { + uint32_t suInstId; + uint32_t spInstId; + uint32_t circuit; + SiConEvnt iam; +}sngss7_glare_data_t; + +typedef struct sngss7_chan_data { + ftdm_channel_t *ftdmchan; + sng_isupCircuit_t *circuit; + uint32_t suInstId; + uint32_t spInstId; + uint32_t spId; + uint8_t globalFlg; + uint32_t flags; + sngss7_glare_data_t glare; + sngss7_timer_data_t t35; +}sngss7_chan_data_t; + + + +typedef enum { + FLAG_RESET_RX = (1 << 0), + FLAG_RESET_TX = (1 << 1), + FLAG_REMOTE_REL = (1 << 2), + FLAG_LOCAL_REL = (1 << 3), + FLAG_GLARE = (1 << 4), + FLAG_INFID_RESUME = (1 << 17), + FLAG_INFID_PAUSED = (1 << 18), + FLAG_CKT_MN_BLOCK_RX = (1 << 19), + FLAG_CKT_MN_BLOCK_TX = (1 << 20), + FLAG_CKT_MN_UNBLK_RX = (1 << 21), + FLAG_CKT_MN_UNBLK_TX = (1 << 22), + FLAG_GRP_HW_BLOCK_RX = (1 << 23), + FLAG_GRP_HW_BLOCK_TX = (1 << 24), + FLAG_GRP_MN_BLOCK_RX = (1 << 25), + FLAG_GRP_MN_BLOCK_TX = (1 << 28), + FLAG_GRP_HW_UNBLK_RX = (1 << 27), + FLAG_GRP_HW_UNBLK_TX = (1 << 28), + FLAG_GRP_MN_UNBLK_RX = (1 << 29), + FLAG_GRP_MN_UNBLK_TX = (1 << 30) +} flag_t; +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ +extern ftdm_sngss7_data_t g_ftdm_sngss7_data; +extern uint32_t sngss7_id; +extern ftdm_sched_t *sngss7_sched; +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +extern void handle_sng_log(uint8_t level, char *fmt,...); +extern void handle_sng_alarm(sng_alrm_t t_alarm); + +extern int ft_to_sngss7_cfg(void); +extern int ft_to_sngss7_activate_all(void); + +extern void ft_to_sngss7_iam(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_acm(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_anm(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_rel(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_rlc(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_rsc(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_rsca(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_blo(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_bla(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_ubl(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_uba(ftdm_channel_t *ftdmchan); +extern void ft_to_sngss7_lpa(ftdm_channel_t *ftdmchan); + +extern void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +extern void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); +extern void sngss7_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); +extern void sngss7_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCnStEvnt *siCnStEvnt, uint8_t evntType); +extern void sngss7_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt); +extern void sngss7_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiRelEvnt *siRelEvnt); +extern void sngss7_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiInfoEvnt *siInfoEvnt); +extern void sngss7_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); +extern void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); +extern void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +extern void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit); + +extern uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); +extern uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); +extern uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum); +extern uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum); +extern uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); +extern int check_for_state_change(ftdm_channel_t *ftdmchan); +extern ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan); +extern unsigned long get_unique_id(void); + +extern int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span); + +extern void handle_isup_t35(void *userdata); + +extern ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data); +/******************************************************************************/ + +/* MACROS *********************************************************************/ +#define SS7_DEBUG(a,...) ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ ); +#define SS7_INFO(a,...) ftdm_log(FTDM_LOG_INFO,a,##__VA_ARGS__ ); +#define SS7_WARN(a,...) ftdm_log(FTDM_LOG_WARNING,a,##__VA_ARGS__ ); +#define SS7_ERROR(a,...) ftdm_log(FTDM_LOG_ERROR,a,##__VA_ARGS__ ); +#define SS7_CRITICAL(a,...) ftdm_log(FTDM_LOG_CRIT,a,##__VA_ARGS__ ); + +#ifdef KONRAD_DEVEL +#define SS7_DEVEL_DEBUG(a,...) ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ ); +#else +#define SS7_DEVEL_DEBUG(a,...) +#endif + +#define SS7_FUNC_TRACE_ENTER(a) if (g_ftdm_sngss7_data.function_trace) { \ + switch (g_ftdm_sngss7_data.function_trace_level) { \ + case 0: \ + ftdm_log(FTDM_LOG_EMERG,"Entering %s\n", a); \ + break; \ + case 1: \ + ftdm_log(FTDM_LOG_ALERT,"Entering %s\n", a); \ + break; \ + case 2: \ + ftdm_log(FTDM_LOG_CRIT,"Entering %s\n", a); \ + break; \ + case 3: \ + ftdm_log(FTDM_LOG_ERROR,"Entering %s\n", a); \ + break; \ + case 4: \ + ftdm_log(FTDM_LOG_WARNING,"Entering %s\n", a); \ + break; \ + case 5: \ + ftdm_log(FTDM_LOG_NOTICE,"Entering %s\n", a); \ + break; \ + case 6: \ + ftdm_log(FTDM_LOG_INFO,"Entering %s\n", a); \ + break; \ + case 7: \ + ftdm_log(FTDM_LOG_DEBUG,"Entering %s\n", a); \ + break; \ + default: \ + ftdm_log(FTDM_LOG_INFO,"Entering %s\n", a); \ + break; \ + } /* switch (g_ftdm_sngss7_data.function_trace_level) */ \ + } /* if(g_ftdm_sngss7_data.function_trace) */ + +#define SS7_FUNC_TRACE_EXIT(a) if (g_ftdm_sngss7_data.function_trace) { \ + switch (g_ftdm_sngss7_data.function_trace_level) { \ + case 0: \ + ftdm_log(FTDM_LOG_EMERG,"Exitting %s\n", a); \ + break; \ + case 1: \ + ftdm_log(FTDM_LOG_ALERT,"Exitting %s\n", a); \ + break; \ + case 2: \ + ftdm_log(FTDM_LOG_CRIT,"Exitting %s\n", a); \ + break; \ + case 3: \ + ftdm_log(FTDM_LOG_ERROR,"Exitting %s\n", a); \ + break; \ + case 4: \ + ftdm_log(FTDM_LOG_WARNING,"Exitting %s\n", a); \ + break; \ + case 5: \ + ftdm_log(FTDM_LOG_NOTICE,"Exitting %s\n", a); \ + break; \ + case 6: \ + ftdm_log(FTDM_LOG_INFO,"Exitting %s\n", a); \ + break; \ + case 7: \ + ftdm_log(FTDM_LOG_DEBUG,"Exitting %s\n", a); \ + break; \ + default: \ + ftdm_log(FTDM_LOG_INFO,"Exitting %s\n", a); \ + break; \ + } /* switch (g_ftdm_sngss7_data.function_trace_level) */ \ + } /* if(g_ftdm_sngss7_data.function_trace) */ + +#define SS7_MSG_TRACE(a,...) if (g_ftdm_sngss7_data.message_trace) { \ + switch (g_ftdm_sngss7_data.message_trace_level) { \ + case 0: \ + ftdm_log(FTDM_LOG_EMERG,a,##__VA_ARGS__ ); \ + break; \ + case 1: \ + ftdm_log(FTDM_LOG_ALERT,a,##__VA_ARGS__ ); \ + break; \ + case 2: \ + ftdm_log(FTDM_LOG_CRIT,a,##__VA_ARGS__ ); \ + break; \ + case 3: \ + ftdm_log(FTDM_LOG_ERROR,a,##__VA_ARGS__ ); \ + break; \ + case 4: \ + ftdm_log(FTDM_LOG_WARNING,a,##__VA_ARGS__ ); \ + break; \ + case 5: \ + ftdm_log(FTDM_LOG_NOTICE,a,##__VA_ARGS__ ); \ + break; \ + case 6: \ + ftdm_log(FTDM_LOG_INFO,a,##__VA_ARGS__ ); \ + break; \ + case 7: \ + ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ ); \ + break; \ + default: \ + ftdm_log(FTDM_LOG_INFO,a,##__VA_ARGS__ ); \ + break; \ + } /* switch (g_ftdm_sngss7_data.message_trace_level) */ \ + } /* if(g_ftdm_sngss7_data.message_trace) */ + +#define sngss7_test_flag(obj, flag) ((obj)->flags & flag) +#define sngss7_clear_flag(obj, flag) ((obj)->flags &= ~(flag)) +#define sngss7_set_flag(obj, flag) ((obj)->flags |= (flag)) + +/******************************************************************************/ + +/******************************************************************************/ +#endif /* __FTMOD_SNG_SS7_H__ */ +/******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c new file mode 100644 index 0000000000..c592933647 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2009, Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +void ft_to_sngss7_iam(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_acm(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_anm(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_rel(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_rlc(ftdm_channel_t *ftdmchan); + +void ft_to_sngss7_rsc(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_rsca(ftdm_channel_t *ftdmchan); + +void ft_to_sngss7_blo(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_bla(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_ubl(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_uba(ftdm_channel_t *ftdmchan); + +void ft_to_sngss7_lpa(ftdm_channel_t *ftdmchan); + +/* FUNCTIONS ******************************************************************/ +void ft_to_sngss7_iam(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; + SiConEvnt iam; + + sngss7_info->suInstId = get_unique_id(); + sngss7_info->spInstId = 0; + sngss7_info->spId = 1; + + memset(&iam, 0x0, sizeof(iam)); + + /* copy down the nature of connection indicators */ + iam.natConInd.eh.pres = PRSNT_NODEF; + iam.natConInd.satInd.pres = PRSNT_NODEF; + iam.natConInd.satInd.val = 0; + iam.natConInd.contChkInd.pres = PRSNT_NODEF; + iam.natConInd.contChkInd.val = 0x00; + iam.natConInd.echoCntrlDevInd.pres = PRSNT_NODEF; + iam.natConInd.echoCntrlDevInd.val = 0x01; + + /* copy down the forward call indicators */ + iam.fwdCallInd.eh.pres = PRSNT_NODEF; + iam.fwdCallInd.natIntCallInd.pres = PRSNT_NODEF; + iam.fwdCallInd.natIntCallInd.val = 0x00; + iam.fwdCallInd.end2EndMethInd.pres = PRSNT_NODEF; + iam.fwdCallInd.end2EndMethInd.val = 0x00; + iam.fwdCallInd.intInd.pres = PRSNT_NODEF; + iam.fwdCallInd.intInd.val = 0x01; + iam.fwdCallInd.end2EndInfoInd.pres = PRSNT_NODEF; + iam.fwdCallInd.end2EndInfoInd.val = 0x00; + iam.fwdCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; + iam.fwdCallInd.isdnUsrPrtInd.val = 0x01; + iam.fwdCallInd.isdnUsrPrtPrfInd.pres = PRSNT_NODEF; + iam.fwdCallInd.isdnUsrPrtPrfInd.val = 0x02; + iam.fwdCallInd.isdnAccInd.pres = PRSNT_NODEF; + iam.fwdCallInd.isdnAccInd.val = 0x01; + iam.fwdCallInd.sccpMethInd.pres = PRSNT_NODEF; + iam.fwdCallInd.sccpMethInd.val = 0x00; + + /* copy down the calling number information */ + iam.cgPtyCat.eh.pres = PRSNT_NODEF; + iam.cgPtyCat.cgPtyCat.pres = PRSNT_NODEF; + iam.cgPtyCat.cgPtyCat.val = 0x0a; + + /* copy down the transmission medium requirements */ + iam.txMedReq.eh.pres = PRSNT_NODEF; + iam.txMedReq.trMedReq.pres = PRSNT_NODEF; + iam.txMedReq.trMedReq.val = 0; /* SPEECH = 0, 3.1Khz = 3, 64k unres = 2 */ + + /* copy down the called number information */ + copy_cdPtyNum_to_sngss7(&ftdmchan->caller_data, &iam.cdPtyNum); + + /* copy down the calling number information */ + copy_cgPtyNum_to_sngss7(&ftdmchan->caller_data, &iam.cgPtyNum); + + sng_cc_con_request(sngss7_info->spId, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &iam, + 0); + + SS7_MSG_TRACE("Transmitted IAM on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} +/******************************************************************************/ + +void ft_to_sngss7_acm(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + SiCnStEvnt acm; + + memset(&acm, 0x0, sizeof(acm)); + + /* fill in the needed information for the ACM */ + acm.bckCallInd.eh.pres = PRSNT_NODEF; + acm.bckCallInd.chrgInd.pres = PRSNT_NODEF; + acm.bckCallInd.chrgInd.val = 0x00; + acm.bckCallInd.cadPtyStatInd.pres = PRSNT_NODEF; + acm.bckCallInd.cadPtyStatInd.val = 0x01; + acm.bckCallInd.cadPtyCatInd.pres = PRSNT_NODEF; + acm.bckCallInd.cadPtyCatInd.val = 0x00; + acm.bckCallInd.end2EndMethInd.pres = PRSNT_NODEF; + acm.bckCallInd.end2EndMethInd.val = 0x00; + acm.bckCallInd.intInd.pres = PRSNT_NODEF; + acm.bckCallInd.intInd.val = 0x00; + acm.bckCallInd.end2EndInfoInd.pres = PRSNT_NODEF; + acm.bckCallInd.end2EndInfoInd.val = 0x00; + acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; + acm.bckCallInd.isdnUsrPrtInd.val = 0x0; + acm.bckCallInd.holdInd.pres = PRSNT_NODEF; + acm.bckCallInd.holdInd.val = 0x00; + acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF; + acm.bckCallInd.isdnAccInd.val = 0x0; + acm.bckCallInd.echoCtrlDevInd.pres = PRSNT_NODEF; + acm.bckCallInd.echoCtrlDevInd.val = 0x0; + acm.bckCallInd.sccpMethInd.pres = PRSNT_NODEF; + acm.bckCallInd.sccpMethInd.val = 0x00; + + /* send the ACM request to LibSngSS7 */ + sng_cc_con_status(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &acm, + ADDRCMPLT); + + SS7_MSG_TRACE("Transmitted ACM on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} +/******************************************************************************/ + +void ft_to_sngss7_anm(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + SiConEvnt anm; + + memset(&anm, 0x0, sizeof(anm)); + + /* send the ANM request to LibSngSS7 */ + sng_cc_con_response(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &anm, + 5); + + SS7_MSG_TRACE("Transmitted ANM on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_rel(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + SiRelEvnt rel; + + memset(&rel, 0x0, sizeof(rel)); + + rel.causeDgn.eh.pres = PRSNT_NODEF; + rel.causeDgn.location.pres = PRSNT_NODEF; + rel.causeDgn.location.val = 0x01; + rel.causeDgn.cdeStand.pres = PRSNT_NODEF; + rel.causeDgn.cdeStand.val = 0x00; + rel.causeDgn.recommend.pres = NOTPRSNT; + rel.causeDgn.causeVal.pres = PRSNT_NODEF; + rel.causeDgn.causeVal.val = (uint8_t)ftdmchan->caller_data.hangup_cause; + rel.causeDgn.dgnVal.pres = NOTPRSNT; + + /* send the REL request to LibSngSS7 */ + sng_cc_rel_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &rel); + + SS7_MSG_TRACE("Transmitted REL on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_rlc(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + SiRelEvnt rlc; + + memset(&rlc, 0x0, sizeof(rlc)); + + /* send the RLC request to LibSngSS7 */ + sng_cc_rel_response(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &rlc); + + SS7_MSG_TRACE("Transmitted RLC on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_rsc(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + sng_cc_sta_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + sngss7_info->globalFlg, + SIT_STA_CIRRESREQ, + NULL); + + SS7_MSG_TRACE("Transmitted RSC on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_rsca(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + sng_cc_sta_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + sngss7_info->globalFlg, + SIT_STA_CIRRESRSP, + NULL); + + SS7_MSG_TRACE("Transmitted RSC-RLC on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_blo(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + sng_cc_sta_request(1, + 0, + 0, + sngss7_info->circuit->id, + sngss7_info->globalFlg, + SIT_STA_CIRBLOREQ, + NULL); + + SS7_MSG_TRACE("Transmitted BLO on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_bla(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + sng_cc_sta_request(1, + 0, + 0, + sngss7_info->circuit->id, + sngss7_info->globalFlg, + SIT_STA_CIRBLORSP, + NULL); + + SS7_MSG_TRACE("Transmitted BLA on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_ubl(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + sng_cc_sta_request(1, + 0, + 0, + sngss7_info->circuit->id, + sngss7_info->globalFlg, + SIT_STA_CIRUBLREQ, + NULL); + + SS7_MSG_TRACE("Transmitted UBL on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_uba(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + sng_cc_sta_request(1, + 0, + 0, + sngss7_info->circuit->id, + sngss7_info->globalFlg, + SIT_STA_CIRUBLRSP, + NULL); + + SS7_MSG_TRACE("Transmitted UBA on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_lpa(ftdm_channel_t *ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + sng_cc_sta_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + sngss7_info->globalFlg, + SIT_STA_LOOPBACKACK, + NULL); + + SS7_MSG_TRACE("Transmitted LPA on CIC # %d\n", sngss7_info->circuit->cic); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} +/******************************************************************************/ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ +/******************************************************************************/ + diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_suppport.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_suppport.c new file mode 100644 index 0000000000..85c29f269f --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_suppport.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2009, Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ +uint32_t sngss7_id; +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); +uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); +uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); +uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum); +uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum); + +int check_for_state_change(ftdm_channel_t *ftdmchan); +unsigned long get_unique_id(void); + +ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan); + +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ +uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum) +{ + + return 0; +} + +/******************************************************************************/ +uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum) +{ + int k; + int j; + int flag; + char tmp; + unsigned char lower; + unsigned char upper; + + /**************************************************************************/ + cgPtyNum->eh.pres = PRSNT_NODEF; + /**************************************************************************/ + cgPtyNum->natAddrInd.pres = PRSNT_NODEF; + cgPtyNum->natAddrInd.val = 0x03; + /**************************************************************************/ + cgPtyNum->scrnInd.pres = PRSNT_NODEF; + cgPtyNum->scrnInd.val = ftdm->screen; + /**************************************************************************/ + cgPtyNum->presRest.pres = PRSNT_NODEF; + cgPtyNum->presRest.val = ftdm->pres; + /**************************************************************************/ + cgPtyNum->numPlan.pres = PRSNT_NODEF; + cgPtyNum->numPlan.val = 0x01; + /**************************************************************************/ + cgPtyNum->niInd.pres = PRSNT_NODEF; + cgPtyNum->niInd.val = 0x00; + /**************************************************************************/ + cgPtyNum->addrSig.pres = PRSNT_NODEF; + + k = 0; + j = 0; + flag = 0; + while (1) { + tmp = ftdm->cid_num.digits[k]; + if (tmp != '\0') { + if (isdigit(tmp)) { + lower = atoi(&tmp); + k++; + tmp = ftdm->cid_num.digits[k]; + } else { + while (!(isdigit(tmp)) && (tmp != '\0')) { + k++; + tmp = ftdm->cid_num.digits[k]; + } /* while(!(isdigit(tmp))) */ + + if (tmp != '\0') { + lower = atoi(&tmp); + k++; + tmp = ftdm->cid_num.digits[k]; + } else { + flag = 1; + lower = 0xf; + } /* if (tmp != '\0') */ + } /* (isdigit(tmp)) */ + } else { + flag = 1; + lower = 0xf; + } /* if (tmp != '\0') */ + + tmp = ftdm->cid_num.digits[k]; + if (tmp != '\0') { + if (isdigit(tmp)) { + upper = (atoi(&tmp)) << 4; + } else { + while (!(isdigit(tmp)) && (tmp != '\0')) { + k++; + tmp = ftdm->cid_num.digits[k]; + } /* while(!(isdigit(tmp))) */ + + if (tmp != '\0') { + upper = (atoi(&tmp)) << 4; + k++; + } else { + flag = 1; + upper = 0xf; + } /* if (tmp != '\0') */ + } /* if (isdigit(tmp)) */ + } else { + if (flag == 1){ + upper = 0x0; + } else { + flag = 1; + upper = 0xf; + } /* if (flag == 1) */ + } /* if (tmp != '\0') */ + + cgPtyNum->addrSig.val[j] = upper | lower; + j++; + + if (flag) { + break; + } else { + k++; + } + } /* while(1) */ + + cgPtyNum->addrSig.len = j; + /**************************************************************************/ + cgPtyNum->oddEven.pres = PRSNT_NODEF; + cgPtyNum->oddEven.val = ((cgPtyNum->addrSig.val[j] >>4) == 0x0 ) ? 0x01 : 0x00; + /**************************************************************************/ + return 0; +} + +/******************************************************************************/ +uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum) +{ + + return 0; +} + +/******************************************************************************/ +uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum) +{ + int k; + int j; + int flag; + char tmp; + unsigned char lower; + unsigned char upper; + + /**************************************************************************/ + cdPtyNum->eh.pres = PRSNT_NODEF; + /**************************************************************************/ + cdPtyNum->natAddrInd.pres = PRSNT_NODEF; + cdPtyNum->natAddrInd.val = 0x03; + /**************************************************************************/ + cdPtyNum->numPlan.pres = PRSNT_NODEF; + cdPtyNum->numPlan.val = 0x01; + /**************************************************************************/ + cdPtyNum->innInd.pres = PRSNT_NODEF; + cdPtyNum->innInd.val = 0x01; + /**************************************************************************/ + cdPtyNum->addrSig.pres = PRSNT_NODEF; + + k = 0; + j = 0; + flag = 0; + while (1) { + tmp = ftdm->dnis.digits[k]; + if (tmp != '\0') { + if (isdigit(tmp)) { + lower = atoi(&tmp); + k++; + tmp = ftdm->dnis.digits[k]; + } else { + while (!(isdigit(tmp)) && (tmp != '\0')) { + k++; + tmp = ftdm->dnis.digits[k]; + } /* while(!(isdigit(tmp))) */ + + if (tmp != '\0') { + lower = atoi(&tmp); + k++; + tmp = ftdm->dnis.digits[k]; + } else { + flag = 1; + lower = 0xf; + } /* if (tmp != '\0') */ + } /* (isdigit(tmp)) */ + } else { + flag = 1; + lower = 0xf; + } /* if (tmp != '\0') */ + + tmp = ftdm->dnis.digits[k]; + if (tmp != '\0') { + if (isdigit(tmp)) { + upper = (atoi(&tmp)) << 4; + } else { + while (!(isdigit(tmp)) && (tmp != '\0')) { + k++; + tmp = ftdm->dnis.digits[k]; + } /* while(!(isdigit(tmp))) */ + + if (tmp != '\0') { + upper = (atoi(&tmp)) << 4; + k++; + } else { + flag = 1; + upper = 0xf; + } /* if (tmp != '\0') */ + } /* if (isdigit(tmp)) */ + } else { + if (flag == 1){ + upper = 0x0; + } else { + flag = 1; + upper = 0xf; + } /* if (flag == 1) */ + } /* if (tmp != '\0') */ + + cdPtyNum->addrSig.val[j] = upper | lower; + j++; + + if (flag) { + break; + } else { + k++; + } + } /* while(1) */ + + cdPtyNum->addrSig.len = j; + /**************************************************************************/ + cdPtyNum->oddEven.pres = PRSNT_NODEF; + cdPtyNum->oddEven.val = ((cdPtyNum->addrSig.val[j] >>4) == 0x0 ) ? 0x01 : 0x00; + /**************************************************************************/ + return 0; +} + +/******************************************************************************/ +uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven) +{ + uint8_t i; + uint8_t j; + + /* check if the token string is present */ + if (str.pres == 1) { + j=0; + + for (i=0; i < str.len; i++) { + sprintf(&ftdm[j], "%d", (str.val[i] & 0x0F)); + j++; + sprintf(&ftdm[j], "%d", ((str.val[i] & 0xF0) >> 4)); + j++; + } + + /* if the odd flag is up the last digit is a fake "0" */ + if ((oddEven.pres == 1) && (oddEven.val == 1)) { + ftdm[j-1] = '\0'; + } else { + ftdm[j] = '\0'; + } + } else { + SS7_ERROR("Asked to copy tknStr that is not present!\n"); + return 1; + } + + return 0; +} + +/******************************************************************************/ +int check_for_state_change(ftdm_channel_t *ftdmchan) +{ + +#if 0 + SS7_DEBUG("Checking for pending state change on span: %d, chan: %d\n!", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id); +#endif + /* check to see if there are any pending state changes on the channel and give them a sec to happen*/ + ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 5000); + + /* check the flag to confirm it is clear now */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + /* the flag is still up...so we have a problem */ + SS7_ERROR("FTDM_CHANNEL_STATE_CHANGE set for over 500ms on span: %d, chan: %d\n", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id); + + /* move the state of the channel to RESTART to force a reset */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + + return 1; + } + return 0; +} + +/******************************************************************************/ +ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + if (g_ftdm_sngss7_data.cfg.isupCircuit[circuit].obj == NULL) { + SS7_ERROR("sngss7_info is Null for circuit #%d\n", circuit); + return FTDM_FAIL; + } + + ftdm_assert_return(g_ftdm_sngss7_data.cfg.isupCircuit[circuit].obj,FTDM_FAIL,"received message on signalling link or non-configured cic\n"); + *sngss7_info = g_ftdm_sngss7_data.cfg.isupCircuit[circuit].obj; + + ftdm_assert_return((*sngss7_info)->ftdmchan,FTDM_FAIL,"received message on signalling link or non-configured cic\n"); + *ftdmchan = (*sngss7_info)->ftdmchan; + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +unsigned long get_unique_id(void) +{ + + if (sngss7_id < 420000000) { + sngss7_id++; + } else { + sngss7_id = 1; + } + + return(sngss7_id); +} + +/******************************************************************************/ + +/******************************************************************************/ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ +/******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c new file mode 100644 index 0000000000..5185ffcc62 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009, Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ + +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +void handle_isup_t35(void *userdata); +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ +void handle_isup_t35(void *userdata) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_timer_data_t *timer = userdata; + sngss7_chan_data_t *sngss7_info = timer->sngss7_info; + ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan; + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + SS7_ERROR("[Call-Control] Timer 35 expired on CIC = %d\n", sngss7_info->circuit->cic); + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL); + + /* hang up on timer expiry */ + ftdmchan->caller_data.hangup_cause = 102; + + /* end the call */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + + /*unlock*/ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; +} +/******************************************************************************/ +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ +/******************************************************************************/ + diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c new file mode 100644 index 0000000000..31856f4896 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -0,0 +1,1867 @@ +/* + * Copyright (c) 2009, Konrad Hammel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +/* GLOBALS ********************************************************************/ +typedef struct sng_timeslot +{ + int channel; + int siglink; + int gap; + int hole; +}sng_timeslot_t; +/******************************************************************************/ + +/* PROTOTYPES *****************************************************************/ +int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span); + +static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup); + +static int ftmod_ss7_parse_mtp_linksets(ftdm_conf_node_t *mtp_linksets); +static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset); +static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp1Link_t *mtp1_link, + sng_mtp2Link_t *mtp2_link, sng_mtp3Link_t *mtp3_link); + +static int ftmod_ss7_parse_mtp_routes(ftdm_conf_node_t *mtp_routes); +static int ftmod_ss7_parse_mtp_route(ftdm_conf_node_t *mtp_route); + +static int ftmod_ss7_parse_isup_interfaces(ftdm_conf_node_t *isup_interfaces); +static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface); + +static int ftmod_ss7_fill_in_mtp1_link(sng_mtp1Link_t *mtp1_link); +static int ftmod_ss7_fill_in_mtp2_link(sng_mtp2Link_t *mtp2_link); +static int ftmod_ss7_fill_in_mtp3_link(sng_mtp3Link_t *mtp3_link); +static int ftmod_ss7_fill_in_mtp3_linkset(sng_mtp3LinkSet_t *mtp3_linkset); +static int ftmod_ss7_fill_in_mtp3_route(sng_mtp3Route_t *mtp3_route); +static int ftmod_ss7_fill_in_mtp3_isup_interface(sng_mtp3Route_t *mtp3_route); +static int ftmod_ss7_fill_in_isup_interface(sng_isupInterface_t *sng_isup); +static int ftmod_ss7_fill_in_isup_cc_interface(sng_isup_cc_t *sng_cc); + +static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, int ssf); + +static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, int isup_id, ftdm_span_t *span); +static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot); + +/******************************************************************************/ + +/* FUNCTIONS ******************************************************************/ +int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span) +{ + int i = 0; + int x = 0; + const char *var = NULL; + const char *val = NULL; + ftdm_conf_node_t *ptr = NULL; + sng_mtp3Route_t self_route; + char ch_map[MAX_CIC_MAP_LENGTH]; + int typeCntrl = 0; + int cicbase = 0; + + /* clean out the self route */ + memset(&self_route, 0x0, sizeof(sng_mtp3Route_t)); + + var = ftdm_parameters[i].var; + val = ftdm_parameters[i].val; + ptr = (ftdm_conf_node_t *)ftdm_parameters[i].ptr; + + /* confirm that the first parameter is the "confnode" */ + if (!strcasecmp(var, "confnode")) { + /* parse the confnode and fill in the global libsng_ss7 config structure */ + if (ftmod_ss7_parse_sng_isup(ptr)) { + SS7_ERROR("Failed to parse the \"confnode\"!\n"); + goto ftmod_ss7_parse_xml_error; + } + } else { + /* ERROR...exit */ + SS7_ERROR("The \"confnode\" configuration was not the first parameter!\n"); + SS7_ERROR("\tFound \"%s\" in the first slot\n", var); + goto ftmod_ss7_parse_xml_error; + } + + i++; + while (ftdm_parameters[i].var != NULL) { + + var = ftdm_parameters[i].var; + val = ftdm_parameters[i].val; + + if (!strcasecmp(var, "ch_map")) { + /**********************************************************************/ + strcpy(ch_map, val); + SS7_DEBUG("\tFound channel map \"%s\"\n", ch_map); + /**********************************************************************/ + } else if (!strcasecmp(var, "typeCntrl")) { + if (!strcasecmp(val, "bothway")) { + typeCntrl = SNG_BOTHWAY; + SS7_DEBUG("\tFound control type \"bothway\"\n"); + } else if (!strcasecmp(val, "incoming")) { + typeCntrl = SNG_INCOMING; + SS7_DEBUG("\tFound control type \"incoming\"\n"); + } else if (!strcasecmp(val, "outgoing")) { + typeCntrl = SNG_OUTGOING; + SS7_DEBUG("\tFound control type \"outgoing\"\n"); + } else if (!strcasecmp(val, "controlled")) { + typeCntrl = SNG_CONTROLLED; + SS7_DEBUG("\tFound control type \"controlled\"\n"); + } else if (!strcasecmp(val, "controlling")) { + typeCntrl = SNG_CONTROLLING; + SS7_DEBUG("\tFound control type \"controlling\"\n"); + } else { + SS7_ERROR("Found invalid circuit control type \"%s\"!", val); + goto ftmod_ss7_parse_xml_error; + } + /**********************************************************************/ + } else if (!strcasecmp(var, "cicbase")) { + cicbase = atoi(val); + SS7_DEBUG("\tFound cicbase = %d\n", cicbase); + /**********************************************************************/ + } else if (!strcasecmp(var, "dialplan")) { + /* do i give a shit about this??? */ + /**********************************************************************/ + } else if (!strcasecmp(var, "context")) { + /* do i give a shit about this??? */ + /**********************************************************************/ + } else if (!strcasecmp(var, "isup_interface")) { + /* go through all the existing interfaces and see if we find a match */ + x = 1; + while (g_ftdm_sngss7_data.cfg.isupInterface[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.isupInterface[x].name, val)) { + /* we have a match so break out of this loop */ + break; + } + /* move on to the next one */ + x++; + } + SS7_DEBUG("\tFound isup_interface = %s\n",g_ftdm_sngss7_data.cfg.isupInterface[x].name ); + /**********************************************************************/ + } else { + SS7_ERROR("Unknown parameter found =\"%s\"...ignoring it!\n", var); + /**********************************************************************/ + } + + i++; + } /* while (ftdm_parameters[i].var != NULL) */ + + /* setup the self mtp3 route */ + i = g_ftdm_sngss7_data.cfg.isupInterface[x].mtp3RouteId; + + if(ftmod_ss7_fill_in_self_route(g_ftdm_sngss7_data.cfg.spc, + g_ftdm_sngss7_data.cfg.mtp3Route[i].linkType, + g_ftdm_sngss7_data.cfg.isupInterface[x].switchType, + g_ftdm_sngss7_data.cfg.mtp3Route[i].ssf)) { + SS7_ERROR("Failed to fill in self route structure!\n"); + goto ftmod_ss7_parse_xml_error; + } + + + /* setup the circuits structure */ + if(ftmod_ss7_fill_in_circuits(ch_map, + cicbase, + typeCntrl, + g_ftdm_sngss7_data.cfg.isupInterface[x].id, + span)) { + SS7_ERROR("Failed to fill in circuits structure!\n"); + goto ftmod_ss7_parse_xml_error; + } + + return FTDM_SUCCESS; + +ftmod_ss7_parse_xml_error: + return FTDM_FAIL; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) +{ + ftdm_conf_node_t *mtp_linksets = NULL; + ftdm_conf_node_t *mtp_routes = NULL; + ftdm_conf_node_t *isup_interfaces = NULL; + ftdm_conf_node_t *tmp_node = NULL; + + /* confirm that we are looking at sng_isup */ + if (strcasecmp(sng_isup->name, "sng_isup")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"sng_isup\"!\n",sng_isup->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"sng_isup\"...\n"); + } + + /* extract the 3 main sections of the sng_isup block */ + tmp_node = sng_isup->child; + while (tmp_node != NULL) { + + if (!strcasecmp(tmp_node->name, "mtp_linksets")) { + if (mtp_linksets == NULL) { + mtp_linksets = tmp_node; + SS7_DEBUG("\tFound a \"mtp_linksets section!\n"); + } else { + SS7_ERROR("\tFound a second \"mtp_linksets\" section!\n"); + return FTDM_FAIL; + } + } else if (!strcasecmp(tmp_node->name, "mtp_routes")) { + if (mtp_routes == NULL) { + mtp_routes = tmp_node; + SS7_DEBUG("\tFound a \"mtp_routes\" section!\n"); + } else { + SS7_ERROR("\tFound a second \"mtp_routes\" section!\n"); + return FTDM_FAIL; + } + } else if (!strcasecmp(tmp_node->name, "isup_interfaces")) { + if (isup_interfaces == NULL) { + isup_interfaces = tmp_node; + SS7_DEBUG("\tFound a \"isup_interfaces\" section!\n"); + } else { + SS7_ERROR("\tFound a second \"isup_interfaces\" section\n!"); + return FTDM_FAIL; + } + } else { + SS7_ERROR("\tFound an unknown section \"%s\"!\n", tmp_node->name); + return FTDM_FAIL; + } + + /* go to the next sibling */ + tmp_node = tmp_node->next; + + } /* while (tmp_node != NULL) */ + + /* now try to parse the sections */ + if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) { + SS7_ERROR("Failed to parse \"mtp_linksets\"!\n"); + return FTDM_FAIL; + } + + if (ftmod_ss7_parse_mtp_routes(mtp_routes)) { + SS7_ERROR("Failed to parse \"mtp_routes\"!\n"); + return FTDM_FAIL; + } + + if (ftmod_ss7_parse_isup_interfaces(isup_interfaces)) { + SS7_ERROR("Failed to parse \"isup_interfaces\"!\n"); + return FTDM_FAIL; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_mtp_linksets(ftdm_conf_node_t *mtp_linksets) +{ + ftdm_conf_node_t *mtp_linkset = NULL; + + /* confirm that we are looking at mtp_linksets */ + if (strcasecmp(mtp_linksets->name, "mtp_linksets")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_linksets\"!\n",mtp_linksets->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"mtp_linksets\"...\n"); + } + + /* extract the mtp_links */ + mtp_linkset = mtp_linksets->child; + + /* run through all of the mtp_linksets found */ + while (mtp_linkset != NULL) { + /* try to the parse mtp_linkset */ + if (ftmod_ss7_parse_mtp_linkset(mtp_linkset)) { + SS7_ERROR("Failed to parse \"mtp_linkset\"!\n"); + return FTDM_FAIL; + } + + /* move on to the next linkset */ + mtp_linkset = mtp_linkset->next; + + } /* while (mtp_linkset != NULL) */ + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset) +{ + ftdm_conf_parameter_t *parm = mtp_linkset->parameters; + int num_parms = mtp_linkset->n_parameters; + ftdm_conf_node_t *mtp_link = NULL; + sng_mtp1Link_t mtp1_link[MAX_MTP_LINKS]; + sng_mtp2Link_t mtp2_link[MAX_MTP_LINKS]; + sng_mtp3Link_t mtp3_link[MAX_MTP_LINKS]; + sng_mtp3LinkSet_t mtp3_linkset; + int count; + int i; + + /* initialize the mtp_link structures */ + for (i = 0; i < MAX_MTP_LINKS; i++) { + memset(&mtp1_link[i], 0x0, sizeof(mtp1_link[i])); + memset(&mtp2_link[i], 0x0, sizeof(mtp2_link[i])); + memset(&mtp3_link[i], 0x0, sizeof(mtp3_link[i])); + } + memset(&mtp3_linkset, 0x0, sizeof(mtp3_linkset)); + + /* confirm that we are looking at mtp_linkset */ + if (strcasecmp(mtp_linkset->name, "mtp_linkset")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_linkset\"!\n",mtp_linkset->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"mtp_linkset\"...\n"); + } + + /* extract all the information from the parameters */ + for (i = 0; i < num_parms; i++) { + /**********************************************************************/ + if (!strcasecmp(parm->var, "name")) { + strcpy((char *)mtp3_linkset.name, parm->val); + SS7_DEBUG("\tFound an \"mtp_linkset\" named = %s\n", mtp3_linkset.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "apc")) { + mtp3_linkset.apc = atoi(parm->val); + SS7_DEBUG("\tFound mtp3_linkSet->apc = %d\n", mtp3_linkset.apc); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "minActive")) { + mtp3_linkset.minActive = atoi(parm->val); + SS7_DEBUG("\tFound mtp3_linkSet->minActive = %d\n", mtp3_linkset.minActive); + /**********************************************************************/ + } else { + SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); + return FTDM_FAIL; + } + + /* move to the next parmeter */ + parm = parm + 1; + + } /* for (i = 0; i < num_parms; i++) */ + + /* grab the first mtp-link (which sits below the mtp_links section) */ + mtp_link = mtp_linkset->child->child; + + /* initalize the link counter */ + count = 0; + + /* run through all of the mtp_links found */ + while (mtp_link != NULL) { + /* try to the parse mtp_linkset */ + if (ftmod_ss7_parse_mtp_link(mtp_link, &mtp1_link[count], &mtp2_link[count], &mtp3_link[count] )) { + SS7_ERROR("Failed to parse \"mtp_link\"!\n"); + return FTDM_FAIL; + } + + /* incremenet the link counter */ + count++; + + /* move on to the next link */ + mtp_link = mtp_link->next; + + } /* while (mtp_link != NULL) */ + + /* confirm we have the right number of links */ + if (count < 1 || count > 15 ) { + SS7_ERROR("Invalid number of mtp_links found (%d)\n", count); + return FTDM_FAIL; + } else { + mtp3_linkset.numLinks = count; + } + + /* now we need to see if this linkset exists already or not and grab an Id */ + i = 1; + while (g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].id != 0) { + if (!strcasecmp((const char *)g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].name, (const char *)mtp3_linkset.name)) { + /* we've found the linkset...so it has already been configured */ + break; + } + i++; + /* add in error check to make sure we don't go out-of-bounds */ + } + + /* if the id value is 0 that means we didn't find the linkset */ + if (g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].id == 0) { + mtp3_linkset.id = i; + SS7_DEBUG("found new mtp3_linkset, id is = %d\n", mtp3_linkset.id); + } else { + mtp3_linkset.id = i; + SS7_DEBUG("found existing mtp3_linkset, id is = %d\n", mtp3_linkset.id); + } + + /* we now have all the information to fill in the Libsng_ss7 structures */ + i = 0; + count = 0; + while (mtp1_link[i].span != 0 ){ + /* fill in the mtp1 link structure */ + mtp2_link[i].spId = ftmod_ss7_fill_in_mtp1_link(&mtp1_link[i]); + /* fill in the mtp2 link structure */ + mtp3_link[i].mtp2LinkId = ftmod_ss7_fill_in_mtp2_link(&mtp2_link[i]); + /* have to grab a couple of values from the linkset */ + mtp3_link[i].apc = mtp3_linkset.apc; + mtp3_link[i].linkSetId = mtp3_linkset.id; + /* fill in the mtp3 link structure */ + mtp3_linkset.links[count] = ftmod_ss7_fill_in_mtp3_link(&mtp3_link[i]); + /* increment the links counter */ + count++; + /* increment the index value */ + i++; + } + + ftmod_ss7_fill_in_mtp3_linkset(&mtp3_linkset); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp1Link_t *mtp1_link, + sng_mtp2Link_t *mtp2_link, sng_mtp3Link_t *mtp3_link) +{ + ftdm_conf_parameter_t *parm = mtp_link->parameters; + int num_parms = mtp_link->n_parameters; + int i; + + /* confirm that we are looking at an mtp_link */ + if (strcasecmp(mtp_link->name, "mtp_link")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_link\"!\n",mtp_link->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"mtp_link\"...\n"); + } + + for (i = 0; i < num_parms; i++) { + /* try to match the parameter to what we expect */ + /**********************************************************************/ + if (!strcasecmp(parm->var, "name")) { + strcpy((char *)mtp1_link->name, parm->val); + strcpy((char *)mtp2_link->name, parm->val); + strcpy((char *)mtp3_link->name, parm->val); + SS7_DEBUG("\tFound an \"mtp_link\" named = %s\n", mtp1_link->name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "span")) { + mtp1_link->span = atoi(parm->val); + SS7_DEBUG("\tFound mtp1_link->span = %d\n", mtp1_link->span); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "chan")) { + mtp1_link->chan = atoi(parm->val); + SS7_DEBUG("\tFound mtp1_link->chan = %d\n", mtp1_link->chan); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "span")) { + mtp1_link->span = atoi(parm->val); + SS7_DEBUG("\tFound mtp1_link->span = %d\n", mtp1_link->span); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "errorType")) { + if (!strcasecmp(parm->val, "basic")) { + mtp2_link->errorType = SNG_BASIC_ERR; + } else if (!strcasecmp(parm->val, "pcr")) { + mtp2_link->errorType = SNG_PCR_ERR; + } else { + SS7_ERROR("\tFound an invalid \"errorType\" = %s\n", parm->var); + return FTDM_FAIL; + } + SS7_DEBUG("\tFound mtp2_link->errorType=%s\n", parm->val); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "lssuLength")) { + mtp2_link->lssuLength = atoi(parm->val); + if ((mtp2_link->lssuLength != 1) && (mtp2_link->lssuLength != 2)) { + SS7_ERROR("\tFound an invalid \"lssuLength\" = %d\n", mtp2_link->lssuLength); + return FTDM_FAIL; + } else { + SS7_DEBUG("\tFound mtp2_link->lssuLength=%d\n", mtp2_link->lssuLength); + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "priority")) { + mtp3_link->priority = atoi(parm->val); + if ((mtp3_link->priority == 0) || (mtp3_link->priority == 1) || + (mtp3_link->priority == 2) || (mtp3_link->priority == 3)) { + SS7_DEBUG("\tFound mtp3_link->priority = %d\n",mtp3_link->priority); + } else { + SS7_ERROR("\tFound an invalid \"priority\"=%d\n", mtp3_link->priority); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "linkType")) { + if (!strcasecmp(parm->val, "itu92")) { + mtp2_link->linkType = SNG_MTP2_ITU92; + mtp3_link->linkType = SNG_MTP3_ITU92; + SS7_DEBUG("\tFound mtp3_link->linkType = \"ITU92\"\n"); + } else if (!strcasecmp(parm->val, "itu88")) { + mtp2_link->linkType = SNG_MTP2_ITU88; + mtp3_link->linkType = SNG_MTP3_ITU88; + SS7_DEBUG("\tFound mtp3_link->linkType = \"ITU88\"\n"); + } else { + SS7_ERROR("\tFound an invalid linktype of \"%s\"!\n", parm->val); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "switchType")) { + if (!strcasecmp(parm->val, "itu97")) { + mtp3_link->switchType = SNG_ISUP_ITU97; + SS7_DEBUG("\tFound mtp3_link->switchType = \"ITU97\"\n"); + } else if (!strcasecmp(parm->val, "itu88")) { + mtp3_link->switchType = SNG_ISUP_ITU88; + SS7_DEBUG("\tFound mtp3_link->switchType = \"ITU88\"\n"); + } else if (!strcasecmp(parm->val, "itu92")) { + mtp3_link->switchType = SNG_ISUP_ITU92; + SS7_DEBUG("\tFound mtp3_link->switchType = \"ITU92\"\n"); + } else if (!strcasecmp(parm->val, "itu00")) { + mtp3_link->switchType = SNG_ISUP_ITU00; + SS7_DEBUG("\tFound mtp3_link->switchType = \"ITU00\"\n"); + } else if (!strcasecmp(parm->val, "ETSIV2")) { + mtp3_link->switchType = SNG_ISUP_ETSIV2; + SS7_DEBUG("\tFound mtp3_link->switchType = \"ETSIV2\"\n"); + } else if (!strcasecmp(parm->val, "ETSIV3")) { + mtp3_link->switchType = SNG_ISUP_ETSIV3; + SS7_DEBUG("\tFound mtp3_link->switchType = \"ETSIV3\"\n"); + } else if (!strcasecmp(parm->val, "UK")) { + mtp3_link->switchType = SNG_ISUP_UK; + SS7_DEBUG("\tFound mtp3_link->switchType = \"UK\"\n"); + } else if (!strcasecmp(parm->val, "RUSSIA")) { + mtp3_link->switchType = SNG_ISUP_RUSSIA; + SS7_DEBUG("\tFound mtp3_link->switchType = \"RUSSIA\"\n"); + } else if (!strcasecmp(parm->val, "INDIA")) { + mtp3_link->switchType = SNG_ISUP_INDIA; + SS7_DEBUG("\tFound mtp3_link->switchType = \"INDIA\"\n"); + } else { + SS7_ERROR("\tFound an invalid linktype of \"%s\"!\n", parm->val); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "ssf")) { + if (!strcasecmp(parm->val, "nat")) { + mtp3_link->ssf = SNG_SSF_NAT; + } else if (!strcasecmp(parm->val, "int")) { + mtp3_link->ssf = SNG_SSF_INTER; + } else { + SS7_ERROR("\tFound an invalid ssf of \"%s\"!\n", parm->val); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "slc")) { + mtp3_link->lnkTstSLC = atoi(parm->val); + SS7_DEBUG("\tFound mtp3_link->slc = \"%d\"\n",mtp3_link->lnkTstSLC); + /**********************************************************************/ + } else { + SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); + return FTDM_FAIL; + } + + /* move to the next parameter */ + parm = parm + 1; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_mtp_routes(ftdm_conf_node_t *mtp_routes) +{ + ftdm_conf_node_t *mtp_route = NULL; + + /* confirm that we are looking at an mtp_routes */ + if (strcasecmp(mtp_routes->name, "mtp_routes")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_routes\"!\n",mtp_routes->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"mtp_routes\"...\n"); + } + + /* extract the mtp_routes */ + mtp_route = mtp_routes->child; + + while (mtp_route != NULL) { + /* parse the found mtp_route */ + if (ftmod_ss7_parse_mtp_route(mtp_route)) { + SS7_ERROR("Failed to parse \"mtp_route\"\n"); + return FTDM_FAIL; + } + + /* go to the next mtp_route */ + mtp_route = mtp_route->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_mtp_route(ftdm_conf_node_t *mtp_route) +{ + sng_mtp3Route_t mtp3_route; + ftdm_conf_parameter_t *parm = mtp_route->parameters; + int num_parms = mtp_route->n_parameters; + int i; + + memset(&mtp3_route, 0x0, sizeof(sng_mtp3Route_t)); + + /* confirm that we are looking at an mtp_link */ + if (strcasecmp(mtp_route->name, "mtp_route")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"mtp_route\"!\n",mtp_route->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"mtp_route\"...\n"); + } + + for (i = 0; i < num_parms; i++) { + /* try to match the parameter to what we expect */ + /**********************************************************************/ + if (!strcasecmp(parm->var, "name")) { + strcpy((char *)mtp3_route.name, parm->val); + SS7_DEBUG("\tFound an \"mtp_route\" named = %s\n", mtp3_route.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "dpc")) { + mtp3_route.dpc = atoi(parm->val); + SS7_DEBUG("\tFound mtp3_route->dpc = %d\n", mtp3_route.dpc); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp_linkset")) { + /* find the linkset by it's name */ + int x = 1; + while (g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].id != 0) { + /* check if the name matches */ + if (!strcasecmp((char *)g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].name, parm->val)) { + /* grab the mtp3_link id value first*/ + int id = g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].links[0]; + /* now, harvest the required infomormation from the global structure */ + mtp3_route.linkType = g_ftdm_sngss7_data.cfg.mtp3Link[id].linkType; + mtp3_route.switchType = g_ftdm_sngss7_data.cfg.mtp3Link[id].switchType; + mtp3_route.ssf = g_ftdm_sngss7_data.cfg.mtp3Link[id].ssf; + mtp3_route.cmbLinkSetId = g_ftdm_sngss7_data.cfg.mtp3LinkSet[x].id; + break; + } + x++; + } + + /* check why we exited the wile loop ... and react accordingly */ + if (mtp3_route.cmbLinkSetId == 0) { + SS7_ERROR("\tFailed to find the linkset = \"%s\"!\n", parm->val); + return FTDM_FAIL; + } else { + SS7_DEBUG("\tFound mtp3_route->linkset = %s\n", parm->val); + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isSTP")) { + if (!strcasecmp(parm->val, "no")) { + mtp3_route.isSTP = 0; + SS7_DEBUG("\tFound mtp3_route->isSTP = no\n"); + } else if (!strcasecmp(parm->val, "yes")) { + mtp3_route.isSTP = 1; + SS7_DEBUG("\tFound mtp3_route->isSTP = yes\n"); + } else { + SS7_ERROR("\tFound an invalid parameter for isSTP \"%s\"!\n", parm->val); + return FTDM_FAIL; + } + /**********************************************************************/ + } else { + SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); + return FTDM_FAIL; + + } + + /* move to the next parameter */ + parm = parm + 1; + } + + ftmod_ss7_fill_in_mtp3_route(&mtp3_route); + + ftmod_ss7_fill_in_mtp3_isup_interface(&mtp3_route); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_isup_interfaces(ftdm_conf_node_t *isup_interfaces) +{ + ftdm_conf_node_t *isup_interface = NULL; + + /* confirm that we are looking at isup_interfaces */ + if (strcasecmp(isup_interfaces->name, "isup_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"isup_interfaces\"!\n",isup_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"isup_interfaces\"...\n"); + } + + /* extract the isup_interfaces */ + isup_interface = isup_interfaces->child; + + while (isup_interface != NULL) { + /* parse the found mtp_route */ + if (ftmod_ss7_parse_isup_interface(isup_interface)) { + SS7_ERROR("Failed to parse \"isup_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next mtp_route */ + isup_interface = isup_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) +{ + sng_isupInterface_t sng_isup; + sng_isup_cc_t sng_cc; + ftdm_conf_parameter_t *parm = isup_interface->parameters; + int num_parms = isup_interface->n_parameters; + int i; + + memset(&sng_isup, 0x0, sizeof(sng_isupInterface_t)); + memset(&sng_cc, 0x0, sizeof(sng_isup_cc_t)); + + /* confirm that we are looking at an mtp_link */ + if (strcasecmp(isup_interface->name, "isup_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"isup_interface\"!\n",isup_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"isup_interface\"...\n"); + } + + + for (i = 0; i < num_parms; i++) { + /* try to match the parameter to what we expect */ + /**********************************************************************/ + if (!strcasecmp(parm->var, "name")) { + strcpy((char *)sng_isup.name, parm->val); + SS7_DEBUG("\tFound an \"isup_interface\" named = %s\n", sng_isup.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "spc")) { + g_ftdm_sngss7_data.cfg.spc = atoi(parm->val); + SS7_DEBUG("\tFound SPC = %d\n", g_ftdm_sngss7_data.cfg.spc); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp_route")) { + /* find the route by it's name */ + int x = 1; + while (g_ftdm_sngss7_data.cfg.mtp3Route[x].id != 0) { + /* check if the name matches */ + if (!strcasecmp((char *)g_ftdm_sngss7_data.cfg.mtp3Route[x].name, parm->val)) { + /* now, harvest the required information from the global structure */ + sng_isup.mtp3RouteId = g_ftdm_sngss7_data.cfg.mtp3Route[x].id; + sng_isup.dpc = g_ftdm_sngss7_data.cfg.mtp3Route[x].dpc; + sng_isup.switchType = g_ftdm_sngss7_data.cfg.mtp3Route[x].switchType; + sng_cc.switchType = g_ftdm_sngss7_data.cfg.mtp3Route[x].switchType; + + /* find the nwID from the mtp3_isup_interface */ + int y = 1; + while (g_ftdm_sngss7_data.cfg.mtp3_isup[y].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtp3_isup[y].linkType == g_ftdm_sngss7_data.cfg.mtp3Route[x].linkType && + g_ftdm_sngss7_data.cfg.mtp3_isup[y].switchType == g_ftdm_sngss7_data.cfg.mtp3Route[x].switchType && + g_ftdm_sngss7_data.cfg.mtp3_isup[y].ssf == g_ftdm_sngss7_data.cfg.mtp3Route[x].ssf) { + + /* we have a match so break out of this loop */ + break; + } + /* move on to the next one */ + y++; + } /* while (g_ftdm_sngss7_data.cfg.mtp3_isup[y].id != 0) */ + + /* check how we exited the last while loop */ + if (g_ftdm_sngss7_data.cfg.mtp3_isup[y].id == 0) { + SS7_ERROR("\tFailed to find the nwID for = \"%s\"!\n", parm->val); + return FTDM_FAIL; + } else { + sng_isup.nwId = g_ftdm_sngss7_data.cfg.mtp3_isup[y].nwId; + } + + break; + } + x++; + } /* while (g_ftdm_sngss7_data.cfg.mtp3Route[x].id != 0) */ + + /* check why we exited the while loop ... and react accordingly */ + if (sng_isup.mtp3RouteId == 0) { + SS7_ERROR("\tFailed to find the MTP3 Route = \"%s\"!\n", parm->val); + return FTDM_FAIL; + } else { + SS7_DEBUG("\tFound MTP3 Route = %s\n", parm->val); + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "ssf")) { + if (!strcasecmp(parm->val, "nat")) { + sng_isup.ssf = SNG_SSF_NAT; + sng_cc.ssf = SNG_SSF_NAT; + } else if (!strcasecmp(parm->val, "int")) { + sng_isup.ssf = SNG_SSF_INTER; + sng_cc.ssf = SNG_SSF_INTER; + } else { + SS7_ERROR("\tFound an invalid ssf of \"%s\"!\n", parm->val); + return FTDM_FAIL; + } + /**********************************************************************/ + } else { + SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); + return FTDM_FAIL; + + } + + /* move to the next parameter */ + parm = parm + 1; + } + + ftmod_ss7_fill_in_isup_interface(&sng_isup); + + ftmod_ss7_fill_in_isup_cc_interface(&sng_cc); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_mtp1_link(sng_mtp1Link_t *mtp1_link) +{ + int i; + + /* go through all the existing links and see if we find a match */ + i = 1; + while (g_ftdm_sngss7_data.cfg.mtp1Link[i].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtp1Link[i].span == mtp1_link->span && + g_ftdm_sngss7_data.cfg.mtp1Link[i].chan == mtp1_link->chan) { + + /* we have a match so break out of this loop */ + break; + } + /* move on to the next one */ + i++; + } + + /* if the id value is 0 that means we didn't find the link */ + if (g_ftdm_sngss7_data.cfg.mtp1Link[i].id == 0) { + mtp1_link->id = i; + SS7_DEBUG("found new mtp1_link on span=%d, chan=%d, id = %d\n", + mtp1_link->span, + mtp1_link->chan, + mtp1_link->id); + } else { + mtp1_link->id = i; + SS7_DEBUG("found existing mtp1_link on span=%d, chan=%d, id = %d\n", + mtp1_link->span, + mtp1_link->chan, + mtp1_link->id); + } + + /* fill in the information */ + + strcpy((char *)g_ftdm_sngss7_data.cfg.mtp1Link[i].name, (char *)mtp1_link->name); + + g_ftdm_sngss7_data.cfg.mtp1Link[i].id = mtp1_link->id; + g_ftdm_sngss7_data.cfg.mtp1Link[i].span = mtp1_link->span; + g_ftdm_sngss7_data.cfg.mtp1Link[i].chan = mtp1_link->chan; + + return (mtp1_link->id); +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_mtp2_link(sng_mtp2Link_t *mtp2_link) +{ + /* the mtp2link->spId is also the index value */ + + int i = mtp2_link->spId; + + mtp2_link->id = i; + + if (g_ftdm_sngss7_data.cfg.mtp2Link[i].id == 0) { + SS7_DEBUG("found new mtp2_link, id is = %d\n", mtp2_link->id); + } else { + SS7_DEBUG("found existing mtp2_link, id is = %d\n", mtp2_link->id); + } + + strcpy((char *)g_ftdm_sngss7_data.cfg.mtp2Link[i].name, (char *)mtp2_link->name); + + g_ftdm_sngss7_data.cfg.mtp2Link[i].id = mtp2_link->id; + g_ftdm_sngss7_data.cfg.mtp2Link[i].spId = mtp2_link->spId; + g_ftdm_sngss7_data.cfg.mtp2Link[i].linkType = mtp2_link->linkType; + g_ftdm_sngss7_data.cfg.mtp2Link[i].errorType = mtp2_link->errorType; + g_ftdm_sngss7_data.cfg.mtp2Link[i].lssuLength = mtp2_link->lssuLength; + + if ( mtp2_link->t1 != 0 ) { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t1 = mtp2_link->t1; + }else { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t1 = 500; + } + if ( mtp2_link->t2 != 0 ) { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t2 = mtp2_link->t2; + }else { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t2 = 250; + } + if ( mtp2_link->t3 != 0 ) { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t3 = mtp2_link->t3; + }else { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t3 = 20; + } + if ( mtp2_link->t4n != 0 ) { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t4n = mtp2_link->t4n; + }else { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t4n = 80; + } + if ( mtp2_link->t4e != 0 ) { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t4e = mtp2_link->t4e; + }else { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t4e = 5; + } + if ( mtp2_link->t5 != 0 ) { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t5 = mtp2_link->t5; + }else { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t5 = 1; + } + if ( mtp2_link->t6 != 0 ) { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t6 = mtp2_link->t6; + }else { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t6 = 60; + } + if ( mtp2_link->t7 != 0 ) { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t7 = mtp2_link->t7; + }else { + g_ftdm_sngss7_data.cfg.mtp2Link[i].t7 = 20; + } + + return(mtp2_link->id); +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_mtp3_link(sng_mtp3Link_t *mtp3_link) +{ + int i = mtp3_link->mtp2LinkId; + + mtp3_link->id = i; + + if (g_ftdm_sngss7_data.cfg.mtp3Link[i].id == 0) { + SS7_DEBUG("found new mtp3_link, id is = %d\n", mtp3_link->id); + } else { + SS7_DEBUG("found existing mtp3_link, id is = %d\n", mtp3_link->id); + } + + strcpy((char *)g_ftdm_sngss7_data.cfg.mtp3Link[i].name, (char *)mtp3_link->name); + + g_ftdm_sngss7_data.cfg.mtp3Link[i].id = mtp3_link->id; + g_ftdm_sngss7_data.cfg.mtp3Link[i].mtp2LinkId = mtp3_link->mtp2LinkId; + g_ftdm_sngss7_data.cfg.mtp3Link[i].linkSetId = mtp3_link->linkSetId; + g_ftdm_sngss7_data.cfg.mtp3Link[i].priority = mtp3_link->priority; + g_ftdm_sngss7_data.cfg.mtp3Link[i].linkType = mtp3_link->linkType; + g_ftdm_sngss7_data.cfg.mtp3Link[i].switchType = mtp3_link->switchType; + g_ftdm_sngss7_data.cfg.mtp3Link[i].apc = mtp3_link->apc; + g_ftdm_sngss7_data.cfg.mtp3Link[i].ssf = mtp3_link->ssf; + g_ftdm_sngss7_data.cfg.mtp3Link[i].lnkTstSLC = mtp3_link->lnkTstSLC; + if (mtp3_link->t1 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t1 = mtp3_link->t1; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t1 = 8; + } + if (mtp3_link->t2 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t2 = mtp3_link->t2; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t2 = 14; + } + if (mtp3_link->t3 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t3 = mtp3_link->t3; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t3 = 8; + } + if (mtp3_link->t4 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t4 = mtp3_link->t4; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t4 = 8; + } + if (mtp3_link->t5 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t5 = mtp3_link->t5; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t5 = 8; + } + if (mtp3_link->t7 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t7 = mtp3_link->t7; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t7 = 15; + } + if (mtp3_link->t12 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t12 = mtp3_link->t12; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t12 = 15; + } + if (mtp3_link->t13 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t13 = mtp3_link->t13; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t13 = 15; + } + if (mtp3_link->t14 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t14 = mtp3_link->t14; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t14 = 30; + } + if (mtp3_link->t17 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t17 = mtp3_link->t17; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t17 = 15; + } + if (mtp3_link->t22 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t22 = mtp3_link->t22; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t22 = 1800; + } + if (mtp3_link->t23 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t23 = mtp3_link->t23; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t23 = 1800; + } + if (mtp3_link->t24 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t24 = mtp3_link->t24; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t24 = 5; + } + if (mtp3_link->t31 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t31 = mtp3_link->t31; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t31 = 50; + } + if (mtp3_link->t32 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t32 = mtp3_link->t32; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t32 = 120; + } + if (mtp3_link->t33 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t33 = mtp3_link->t33; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t33 = 3000; + } + if (mtp3_link->t34 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t34 = mtp3_link->t34; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].t34 = 600; + } + if (mtp3_link->tflc != 0) { + g_ftdm_sngss7_data.cfg.mtp3Link[i].tflc = mtp3_link->tflc; + } else { + g_ftdm_sngss7_data.cfg.mtp3Link[i].tflc = 300; + } + + return(mtp3_link->id); +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_mtp3_linkset(sng_mtp3LinkSet_t *mtp3_linkset) +{ + int count; + int i = mtp3_linkset->id; + + strcpy((char *)g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].name, (char *)mtp3_linkset->name); + + g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].id = mtp3_linkset->id; + g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].apc = mtp3_linkset->apc; + g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].minActive = mtp3_linkset->minActive; + g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].numLinks = mtp3_linkset->numLinks; + + for (count = 0; count < mtp3_linkset->numLinks; count++) { + g_ftdm_sngss7_data.cfg.mtp3LinkSet[i].links[count] = mtp3_linkset->links[count]; + } + + return 0; +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_mtp3_route(sng_mtp3Route_t *mtp3_route) +{ + int i; + + /* go through all the existing routes and see if we find a match */ + i = 1; + while (g_ftdm_sngss7_data.cfg.mtp3Route[i].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtp3Route[i].dpc == mtp3_route->dpc) { + + /* we have a match so break out of this loop */ + break; + } + /* move on to the next one */ + i++; + } + + if (g_ftdm_sngss7_data.cfg.mtp3Route[i].id == 0) { + mtp3_route->id = i; + SS7_DEBUG("found new mtp3_route, id is = %d\n", mtp3_route->id); + } else { + mtp3_route->id = i; + SS7_DEBUG("found existing mtp3_route, id is = %d\n", mtp3_route->id); + } + + strcpy((char *)g_ftdm_sngss7_data.cfg.mtp3Route[i].name, (char *)mtp3_route->name); + + g_ftdm_sngss7_data.cfg.mtp3Route[i].id = mtp3_route->id; + g_ftdm_sngss7_data.cfg.mtp3Route[i].dpc = mtp3_route->dpc; + g_ftdm_sngss7_data.cfg.mtp3Route[i].linkType = mtp3_route->linkType; + g_ftdm_sngss7_data.cfg.mtp3Route[i].switchType = mtp3_route->switchType; + g_ftdm_sngss7_data.cfg.mtp3Route[i].cmbLinkSetId = 1; /* mtp3_route->cmbLinkSetId;*/ + g_ftdm_sngss7_data.cfg.mtp3Route[i].isSTP = mtp3_route->isSTP; + g_ftdm_sngss7_data.cfg.mtp3Route[i].ssf = mtp3_route->ssf; + if (mtp3_route->t6 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t6 = mtp3_route->t6; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t6 = 8; + } + if (mtp3_route->t8 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t8 = mtp3_route->t8; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t8 = 12; + } + if (mtp3_route->t10 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t10 = mtp3_route->t10; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t10 = 300; + } + if (mtp3_route->t11 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t11 = mtp3_route->t11; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t11 = 300; + } + if (mtp3_route->t15 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t15 = mtp3_route->t15; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t15 = 30; + } + if (mtp3_route->t16 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t16 = mtp3_route->t16; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t16 = 20; + } + if (mtp3_route->t18 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t18 = mtp3_route->t18; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t18 = 200; + } + if (mtp3_route->t19 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t19 = mtp3_route->t19; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t19 = 690; + } + if (mtp3_route->t21 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t21 = mtp3_route->t21; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t21 = 650; + } + if (mtp3_route->t25 != 0) { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t25 = mtp3_route->t25; + } else { + g_ftdm_sngss7_data.cfg.mtp3Route[i].t25 = 100; + } + + return 0; +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_mtp3_isup_interface(sng_mtp3Route_t *mtp3_route) +{ + + int i; + + /* go through all the existing interfaces and see if we find a match */ + i = 1; + while (g_ftdm_sngss7_data.cfg.mtp3_isup[i].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtp3_isup[i].linkType == mtp3_route->linkType && + g_ftdm_sngss7_data.cfg.mtp3_isup[i].switchType == mtp3_route->switchType && + g_ftdm_sngss7_data.cfg.mtp3_isup[i].ssf == mtp3_route->ssf) { + + /* we have a match so break out of this loop */ + break; + } + /* move on to the next one */ + i++; + } + + if (g_ftdm_sngss7_data.cfg.mtp3_isup[i].id == 0) { + g_ftdm_sngss7_data.cfg.mtp3_isup[i].id = i; + SS7_DEBUG("found new mtp3_isup interface, id is = %d\n", g_ftdm_sngss7_data.cfg.mtp3_isup[i].id); + } else { + g_ftdm_sngss7_data.cfg.mtp3_isup[i].id = i; + SS7_DEBUG("found existing mtp3_isup interface, id is = %d\n", g_ftdm_sngss7_data.cfg.mtp3_isup[i].id); + } + + g_ftdm_sngss7_data.cfg.mtp3_isup[i].nwId = g_ftdm_sngss7_data.cfg.mtp3_isup[i].id; + g_ftdm_sngss7_data.cfg.mtp3_isup[i].linkType = mtp3_route->linkType; + g_ftdm_sngss7_data.cfg.mtp3_isup[i].switchType = mtp3_route->switchType; + g_ftdm_sngss7_data.cfg.mtp3_isup[i].ssf = mtp3_route->ssf; + + return 0; +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_isup_interface(sng_isupInterface_t *sng_isup) +{ + + int i; + + /* go through all the existing interfaces and see if we find a match */ + i = 1; + while (g_ftdm_sngss7_data.cfg.isupInterface[i].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupInterface[i].nwId == sng_isup->nwId) { + + /* we have a match so break out of this loop */ + break; + } + /* move on to the next one */ + i++; + } + + if (g_ftdm_sngss7_data.cfg.isupInterface[i].id == 0) { + sng_isup->id = i; + SS7_DEBUG("found new isup interface, id is = %d\n", sng_isup->id); + } else { + sng_isup->id = i; + SS7_DEBUG("found existing isup interface, id is = %d\n", sng_isup->id); + } + + strcpy((char *)g_ftdm_sngss7_data.cfg.isupInterface[i].name, (char *)sng_isup->name); + + g_ftdm_sngss7_data.cfg.isupInterface[i].id = sng_isup->id; + g_ftdm_sngss7_data.cfg.isupInterface[i].mtp3RouteId = sng_isup->mtp3RouteId; + g_ftdm_sngss7_data.cfg.isupInterface[i].nwId = sng_isup->nwId; + g_ftdm_sngss7_data.cfg.isupInterface[i].dpc = sng_isup->dpc; + g_ftdm_sngss7_data.cfg.isupInterface[i].switchType = sng_isup->switchType; + g_ftdm_sngss7_data.cfg.isupInterface[i].ssf = sng_isup->ssf; + if (sng_isup->t4 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t4 = sng_isup->t4; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t4 = 3000; + } + if (sng_isup->t10 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t10 = sng_isup->t10; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t10 = 50; + } + if (sng_isup->t11 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t11 = sng_isup->t11; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t11 = 170; + } + if (sng_isup->t18 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t18 = sng_isup->t18; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t18 = 300; + } + if (sng_isup->t19 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t19 = sng_isup->t19; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t19 = 3000; + } + if (sng_isup->t20 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t20 = sng_isup->t20; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t20 = 300; + } + if (sng_isup->t21 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t21 = sng_isup->t21; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t21 = 3000; + } + if (sng_isup->t22 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t22 = sng_isup->t22; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t22 = 300; + } + if (sng_isup->t23 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t23 = sng_isup->t23; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t23 = 3000; + } + if (sng_isup->t24 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t24 = sng_isup->t24; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t24 = 10; + } + if (sng_isup->t25 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t25 = sng_isup->t25; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t25 = 20; + } + if (sng_isup->t26 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t26 = sng_isup->t26; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t26 = 600; + } + if (sng_isup->t28 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t28 = sng_isup->t28; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t28 = 100; + } + if (sng_isup->t29 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t29 = sng_isup->t29; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t29 = 6; + } + if (sng_isup->t30 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t30 = sng_isup->t30; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t30 = 50; + } + if (sng_isup->t32 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t32 = sng_isup->t32; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t32 = 30; + } + if (sng_isup->t35 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t35 = sng_isup->t35; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t35 = 170; + } + if (sng_isup->t37 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t37 = sng_isup->t37; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t37 = 20; + } + if (sng_isup->t38 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t38 = sng_isup->t38; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t38 = 1200; + } + if (sng_isup->t39 != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].t39 = sng_isup->t39; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].t39 = 300; + } + if (sng_isup->tfgr != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].tfgr = sng_isup->tfgr; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].tfgr = 50; + } + if (sng_isup->tpause != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].tpause = sng_isup->tpause; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].tpause = 150; + } + if (sng_isup->tstaenq != 0) { + g_ftdm_sngss7_data.cfg.isupInterface[i].tstaenq = sng_isup->tstaenq; + } else { + g_ftdm_sngss7_data.cfg.isupInterface[i].tstaenq = 5000; + } + + return 0; +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_isup_cc_interface(sng_isup_cc_t *sng_cc) +{ + + int i; + + /* go through all the existing interfaces and see if we find a match */ + i = 1; + while (g_ftdm_sngss7_data.cfg.isup_cc[i].id != 0) { + if (g_ftdm_sngss7_data.cfg.isup_cc[i].switchType == sng_cc->switchType) { + + /* we have a match so break out of this loop */ + break; + } + /* move on to the next one */ + i++; + } + + if (g_ftdm_sngss7_data.cfg.isup_cc[i].id == 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].id = i; + SS7_DEBUG("found new isup to cc interface, id is = %d\n", g_ftdm_sngss7_data.cfg.isup_cc[i].id); + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].id = i; + SS7_DEBUG("found existing isup to cc interface, id is = %d\n", g_ftdm_sngss7_data.cfg.isup_cc[i].id); + } + + SS7_ERROR("KONRAD -> you're hard coding the CC id....fix me!!!!\n"); + g_ftdm_sngss7_data.cfg.isup_cc[i].ccId = 1; /*KONRAD FIX ME */ + g_ftdm_sngss7_data.cfg.isup_cc[i].switchType = sng_cc->switchType; + g_ftdm_sngss7_data.cfg.isup_cc[i].ssf = sng_cc->ssf; + if (sng_cc->t1 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t1 = sng_cc->t1; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t1 = 200; + } + if (sng_cc->t2 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t2 = sng_cc->t2; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t2 = 1800; + } + if (sng_cc->t5 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t5 = sng_cc->t5; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t5 = 3000; + } + if (sng_cc->t6 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t6 = sng_cc->t6; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t6 = 200; + } + if (sng_cc->t7 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t7 = sng_cc->t7; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t7 = 250; + } + if (sng_cc->t8 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t8 = sng_cc->t8; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t8 = 120; + } + if (sng_cc->t9 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t9 = sng_cc->t9; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t9 = 1800; + } + if (sng_cc->t27 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t27 = sng_cc->t27; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t27 = 2400; + } + if (sng_cc->t31 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t31 = sng_cc->t31; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t31 = 3650; + } + if (sng_cc->t33 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t33 = sng_cc->t33; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t33 = 120; + } + if (sng_cc->t34 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t34 = sng_cc->t34; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t34 = 40; + } + if (sng_cc->t36 != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].t36 = sng_cc->t36; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].t36 = 120; + } + if (sng_cc->tccr != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].tccr = sng_cc->tccr; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].tccr = 200; + } + if (sng_cc->tccrt != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].tccrt = sng_cc->tccrt; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].tccrt = 20; + } + if (sng_cc->tex != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].tex = sng_cc->tex; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].tex = 10; + } + if (sng_cc->tcrm != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].tcrm = sng_cc->tcrm; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].tcrm = 30; + } + if (sng_cc->tcra != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].tcra = sng_cc->tcra; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].tcra = 100; + } + if (sng_cc->tect != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].tect = sng_cc->tect; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].tect = 10; + } + if (sng_cc->trelrsp != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].trelrsp = sng_cc->trelrsp; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].trelrsp = 10; + } + if (sng_cc->tfnlrelrsp != 0) { + g_ftdm_sngss7_data.cfg.isup_cc[i].tfnlrelrsp= sng_cc->tfnlrelrsp; + } else { + g_ftdm_sngss7_data.cfg.isup_cc[i].tfnlrelrsp= 10; + } + + return 0; +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, int ssf) +{ + + if (g_ftdm_sngss7_data.cfg.mtp3Route[0].dpc == 0){ + SS7_DEBUG("found new mtp3 self route\n"); + } else if (g_ftdm_sngss7_data.cfg.mtp3Route[0].dpc == spc) { + SS7_DEBUG("found existing mtp3 self route\n"); + return FTDM_SUCCESS; + } else { + SS7_ERROR("found new mtp3 self route but it does not much the route already configured\n"); + return FTDM_FAIL; + } + + g_ftdm_sngss7_data.cfg.mtp3Route[0].id = 0; + g_ftdm_sngss7_data.cfg.mtp3Route[0].dpc = spc; + g_ftdm_sngss7_data.cfg.mtp3Route[0].linkType = linkType; + g_ftdm_sngss7_data.cfg.mtp3Route[0].switchType = switchType; + g_ftdm_sngss7_data.cfg.mtp3Route[0].cmbLinkSetId = 0; + g_ftdm_sngss7_data.cfg.mtp3Route[0].isSTP = 0; + g_ftdm_sngss7_data.cfg.mtp3Route[0].ssf = 0; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t6 = 8; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t8 = 12; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t10 = 300; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t11 = 300; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t15 = 30; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t16 = 20; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t18 = 200; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t19 = 690; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t21 = 650; + g_ftdm_sngss7_data.cfg.mtp3Route[0].t25 = 100; + + + return 0; +} + +/******************************************************************************/ +static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, int isup_id, ftdm_span_t *span) +{ + sngss7_chan_data_t *ss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + sng_timeslot_t timeslot; + int count; + int i; + int x; + + count = 1; + + while (ch_map[0] != '\0') { + + /* pull out the next timeslot */ + if (ftmod_ss7_next_timeslot(ch_map, ×lot)) { + SS7_ERROR("Failed to parse the channel map!\n"); + return FTDM_FAIL; + } + + if ((timeslot.siglink) || (timeslot.gap)) { + /* try to find the channel in the circuits structure*/ + x = 1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if ((g_ftdm_sngss7_data.cfg.isupCircuit[x].chan == count) && + (g_ftdm_sngss7_data.cfg.isupCircuit[x].span == span->channels[1]->physical_span_id)) { + + SS7_DEVEL_DEBUG("Circuit for span=%d, chan=%d is already exists...id=%d\n", + span->channels[1]->physical_span_id, + count, + x); + + /* we have a match so this circuit already exists in the structure */ + break; + } + /* move to the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) */ + + /* check why we exited the while loop */ + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) { + SS7_DEVEL_DEBUG("Circuit for span=%d, chan=%d is new...id=%d\n", + span->channels[1]->physical_span_id, + count, + x); + + /* prepare the global info sturcture */ + ss7_info = ftdm_calloc(1, sizeof(sngss7_chan_data_t)); + ss7_info->ftdmchan = NULL; + ss7_info->circuit = &g_ftdm_sngss7_data.cfg.isupCircuit[x]; + + /* circuit is new so fill in the needed information */ + g_ftdm_sngss7_data.cfg.isupCircuit[x].id = x; + g_ftdm_sngss7_data.cfg.isupCircuit[x].span = span->channels[1]->physical_span_id; + g_ftdm_sngss7_data.cfg.isupCircuit[x].chan = count; + if (timeslot.siglink) { + g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink = 1; + } else { + g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink = 0; + } + if (timeslot.channel) { + g_ftdm_sngss7_data.cfg.isupCircuit[x].hole = 0; + g_ftdm_sngss7_data.cfg.isupCircuit[x].cic = cicbase; + cicbase++; + } else { + g_ftdm_sngss7_data.cfg.isupCircuit[x].hole = 1; + g_ftdm_sngss7_data.cfg.isupCircuit[x].cic = 0; + } + g_ftdm_sngss7_data.cfg.isupCircuit[x].infId = isup_id; + g_ftdm_sngss7_data.cfg.isupCircuit[x].typeCntrl = typeCntrl; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t3 = 1200; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t12 = 300; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t13 = 3000; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t14 = 300; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t15 = 3000; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t16 = 300; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t17 = 3000; + g_ftdm_sngss7_data.cfg.isupCircuit[x].tval = 10; + g_ftdm_sngss7_data.cfg.isupCircuit[x].obj = ss7_info; + + } /* if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) */ + } else { /* if ((timeslot.siglink) || (timeslot.gap)) */ + /* find the ftdm the channel structure for this channel*/ + i = 1; + while (span->channels[i] != NULL) { + if (span->channels[i]->physical_chan_id == timeslot.channel) { + break; + } + i++; + } /* while (span->channels[i] != NULL) */ + + if (span->channels[i] == NULL) { + /* we weren't able to find the channel in the ftdm channels */ + SS7_ERROR("Unable to find the requested channel %d in the FreeTDM channels!\n", timeslot.channel); + return FTDM_FAIL; + } else { + ftdmchan = span->channels[i]; + } + + /* try to find a match for the physical span and chan */ + x = 1; + while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) { + if ((g_ftdm_sngss7_data.cfg.isupCircuit[x].chan == ftdmchan->physical_chan_id) + && (g_ftdm_sngss7_data.cfg.isupCircuit[x].span == ftdmchan->physical_span_id)) { + + /* we have a match so this circuit already exists in the structure */ + break; + } + /* move to the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCircuit[x].id != 0) */ + + /* check why we exited the while loop */ + if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) { + SS7_DEVEL_DEBUG("Circuit for span=%d, chan=%d is new...id=%d\n", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id, + x); + + /* prepare the global info sturcture */ + ss7_info = ftdm_calloc(1, sizeof(sngss7_chan_data_t)); + ss7_info->ftdmchan = ftdmchan; + ss7_info->circuit = &g_ftdm_sngss7_data.cfg.isupCircuit[x]; + ftdmchan->call_data = ss7_info; + + /* prepare the timer structures */ + ss7_info->t35.sched = sngss7_sched; + ss7_info->t35.counter = 1; + ss7_info->t35.beat = g_ftdm_sngss7_data.cfg.isupInterface[isup_id].t35*100; /* beat is in ms, t35 is in 100ms */ + ss7_info->t35.callback = handle_isup_t35; + ss7_info->t35.sngss7_info = ss7_info; + + /* circuit is new so fill in the needed information */ + g_ftdm_sngss7_data.cfg.isupCircuit[x].id = x; + g_ftdm_sngss7_data.cfg.isupCircuit[x].span = ftdmchan->physical_span_id; + g_ftdm_sngss7_data.cfg.isupCircuit[x].chan = ftdmchan->physical_chan_id; + g_ftdm_sngss7_data.cfg.isupCircuit[x].siglink = 0; + g_ftdm_sngss7_data.cfg.isupCircuit[x].hole = 0; + g_ftdm_sngss7_data.cfg.isupCircuit[x].cic = cicbase; + g_ftdm_sngss7_data.cfg.isupCircuit[x].infId = isup_id; + g_ftdm_sngss7_data.cfg.isupCircuit[x].typeCntrl = typeCntrl; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t3 = 1200; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t12 = 300; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t13 = 3000; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t14 = 300; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t15 = 3000; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t16 = 300; + g_ftdm_sngss7_data.cfg.isupCircuit[x].t17 = 3000; + g_ftdm_sngss7_data.cfg.isupCircuit[x].tval = 10; + g_ftdm_sngss7_data.cfg.isupCircuit[x].obj = ss7_info; + + /* increment the cicbase */ + cicbase++; + } else { /* if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) */ + SS7_DEBUG("Circuit for span=%d, chan=%d is new...id=%d\n", + ftdmchan->physical_span_id, + ftdmchan->physical_chan_id, + x); + + /* for now make sure ss7_info is set to null */ + ss7_info = NULL; + + /* KONRAD FIX ME -> confirm that it is the same circuit */ + } /* if (g_ftdm_sngss7_data.cfg.isupCircuit[x].id == 0) */ + + /* increment the span channel count */ + count++; + } /* if ((timeslot.siglink) || (timeslot.gap)) */ + + if (ss7_info == NULL) { + SS7_ERROR("KONRAD -> circuit was not configured !\n"); + return FTDM_FAIL; + } + + if (ss7_info->ftdmchan == NULL) { + SS7_INFO("Added span = %d, chan = %d, cic = %d, FTDM chan = %d, ISUP cirId = %d\n", + g_ftdm_sngss7_data.cfg.isupCircuit[x].span, + g_ftdm_sngss7_data.cfg.isupCircuit[x].chan, + g_ftdm_sngss7_data.cfg.isupCircuit[x].cic, + 0, + g_ftdm_sngss7_data.cfg.isupCircuit[x].id); + } else { + SS7_INFO("Added span = %d, chan = %d, cic = %d, FTDM chan = %d, ISUP cirId = %d\n", + g_ftdm_sngss7_data.cfg.isupCircuit[x].span, + g_ftdm_sngss7_data.cfg.isupCircuit[x].chan, + g_ftdm_sngss7_data.cfg.isupCircuit[x].cic, + ss7_info->ftdmchan->chan_id, + g_ftdm_sngss7_data.cfg.isupCircuit[x].id); + } + + } /* while (ch_map[0] != '\0') */ + + return 0; +} + +/******************************************************************************/ +static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot) +{ + int i; + int x; + int lower; + int upper; + char tmp[5]; /*KONRAD FIX ME*/ + char new_ch_map[MAX_CIC_LENGTH]; + + memset(&tmp[0], '\0', sizeof(tmp)); + memset(&new_ch_map[0], '\0', sizeof(new_ch_map)); + memset(timeslot, 0x0, sizeof(sng_timeslot_t)); + + SS7_DEVEL_DEBUG("Old channel map = \"%s\"\n", ch_map); + + /* start at the beginning of the ch_map */ + x = 0; + + switch (ch_map[x]) { + /**************************************************************************/ + case 'S': + case 's': /* we have a sig link */ + timeslot->siglink = 1; + + /* check what comes next either a comma or a number */ + x++; + if (ch_map[x] == ',') { + timeslot->hole = 1; + SS7_DEVEL_DEBUG(" Found a siglink in the channel map with a hole in the cic map\n"); + } else if (isdigit(ch_map[x])) { + /* consume all digits until a comma as this is the channel */ + SS7_DEVEL_DEBUG(" Found a siglink in the channel map with out a hole in the cic map\n"); + } else { + SS7_ERROR("Found an illegal channel map character after signal link flag = \"%c\"!\n", ch_map[x]); + return FTDM_FAIL; + } + break; + /**************************************************************************/ + case 'G': + case 'g': /* we have a channel gap */ + timeslot->gap = 1; + + /* check what comes next either a comma or a number */ + x++; + if (ch_map[x] == ',') { + timeslot->hole = 1; + SS7_DEVEL_DEBUG(" Found a gap in the channel map with a hole in the cic map\n"); + } else if (isdigit(ch_map[x])) { + SS7_DEVEL_DEBUG(" Found a gap in the channel map with out a hole in the cic map\n"); + /* consume all digits until a comma as this is the channel */ + } else { + SS7_ERROR("Found an illegal channel map character after signal link flag = \"%c\"!\n", ch_map[x]); + return FTDM_FAIL; + } + break; + /**************************************************************************/ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': /* we have a channel */ + /* consume all digits until a comma or a dash */ + SS7_DEVEL_DEBUG("Found a starting channel in the channel map\n"); + break; + /**************************************************************************/ + default: + SS7_ERROR("Found an illegal channel map character = \"%c\"!\n", ch_map[x]); + return FTDM_FAIL; + /**************************************************************************/ + } /* switch (ch_map[x]) */ + + /* grab the first number in the string */ + i = 0; + while ((ch_map[x] != '\0') && (ch_map[x] != '-') && (ch_map[x] != ',')) { + tmp[i] = ch_map[x]; + i++; + x++; + } + tmp[i] = '\0'; + timeslot->channel = atoi(tmp); + lower = timeslot->channel + 1; + + /* check the next value in the list */ + if (ch_map[x] == '-') { + /* consume the number after the dash */ + x++; + i = 0; + while ((ch_map[x] != '\0') && (ch_map[x] != '-') && (ch_map[x] != ',')) { + tmp[i] = ch_map[x]; + i++; + x++; + } + tmp[i] = '\0'; + upper = atoi(tmp); + + /* check if the upper end of the range is the same as the lower end of the range */ + if (upper == lower) { + /* the range is completed, eat the next comma or \0 and write it */ + sprintf(new_ch_map, "%d", lower); + } else if ( upper > lower) { + /* the list continues, add 1 from the channel map value and re-insert it to the list */ + sprintf(new_ch_map, "%d-%d", lower, upper); + } else { + SS7_ERROR("The upper is less then the lower end of the range...should not happen!\n"); + return FTDM_FAIL; + } + + /* the the rest of ch_map to new_ch_map */ + strncat(new_ch_map, &ch_map[x], strlen(&ch_map[x])); + + /* set the new cic map to ch_map*/ + strcpy(ch_map, new_ch_map); + + } else if (ch_map[x] == ',') { + /* move past the comma */ + x++; + + /* copy the rest of the list to new_ch_map */ + strcpy(new_ch_map, &ch_map[x]); + + /* copy the new_ch_map over the old one */ + strcpy(ch_map, new_ch_map); + + } else if (ch_map[x] == '\0') { + /* we're at the end of the string...copy the rest of the list to new_ch_map */ + strcpy(new_ch_map, &ch_map[x]); + + /* set the new cic map to ch_map*/ + strcpy(ch_map, new_ch_map); + } else { + /* nothing to do */ + } + + SS7_DEVEL_DEBUG("New channel map = \"%s\"\n", ch_map); + + return FTDM_SUCCESS; +} + +/******************************************************************************/