diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index 35f1cecd1e..b54069a508 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -248,6 +248,14 @@ ftmod_r2_la_LDFLAGS = -shared -module -avoid-version -lopenr2 ftmod_r2_la_LIBADD = libfreetdm.la endif +if HAVE_WAT +mod_LTLIBRARIES += ftmod_gsm.la +ftmod_gsm_la_SOURCES = $(SRC)/ftmod/ftmod_gsm/ftmod_gsm.c +ftmod_gsm_la_CFLAGS = $(FTDM_CFLAGS) $(AM_CFLAGS) +ftmod_gsm_la_LDFLAGS = -shared -module -avoid-version -lwat +ftmod_gsm_la_LIBADD = libfreetdm.la +endif + if HAVE_MISDN mod_LTLIBRARIES += ftmod_misdn.la ftmod_misdn_la_SOURCES = $(SRC)/ftmod/ftmod_misdn/ftmod_misdn.c diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index 292c1e7cfa..cb254da56b 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -189,6 +189,14 @@ AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [HAVE_OPENR2="yes"]) AC_MSG_RESULT([checking whether to build ftmod_r2... ${HAVE_OPENR2}]) AM_CONDITIONAL([HAVE_OPENR2], [test "${HAVE_OPENR2}" = "yes"]) +## +# WAT GSM stack +# +HAVE_WAT="no" +AC_CHECK_LIB([wat], [wat_version], [HAVE_WAT="yes"]) +AC_MSG_RESULT([checking whether to build ftmod_wat... ${HAVE_WAT}]) +AM_CONDITIONAL([HAVE_WAT], [test "${HAVE_WAT}" = "yes"]) + ## # Digium libpri (TODO: add checks) # @@ -450,6 +458,7 @@ AC_MSG_RESULT([ ftmod_sangoma_isdn................. ${HAVE_SNG_ISDN} ftmod_sangoma_ss7.................. ${HAVE_SNG_SS7} ftmod_r2........................... ${HAVE_OPENR2} + ftmod_gsm.......................... ${HAVE_WAT} ftmod_pritap....................... ${HAVE_PRITAP} I/O: ftmod_wanpipe...................... ${HAVE_LIBSANGOMA} diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 0fc7906331..3f461e8ab1 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2820,6 +2820,95 @@ static int add_profile_parameters(switch_xml_t cfg, const char *profname, ftdm_c return paramindex; } +static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans) +{ + switch_xml_t myspan, param; + + for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { + ftdm_status_t zstatus = FTDM_FAIL; + const char *context = "default"; + const char *dialplan = "XML"; + ftdm_conf_parameter_t spanparameters[30]; + char *id = (char *) switch_xml_attr(myspan, "id"); + char *name = (char *) switch_xml_attr(myspan, "name"); + char *configname = (char *) switch_xml_attr(myspan, "cfgprofile"); + ftdm_span_t *span = NULL; + uint32_t span_id = 0; + unsigned paramindex = 0; + + if (!name && !id) { + CONFIG_ERROR("sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); + continue; + } + + if (name) { + zstatus = ftdm_span_find_by_name(name, &span); + } else { + if (switch_is_number(id)) { + span_id = atoi(id); + zstatus = ftdm_span_find(span_id, &span); + } + + if (zstatus != FTDM_SUCCESS) { + zstatus = ftdm_span_find_by_name(id, &span); + } + } + + if (zstatus != FTDM_SUCCESS) { + CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + continue; + } + + if (!span_id) { + span_id = ftdm_span_get_id(span); + } + + memset(spanparameters, 0, sizeof(spanparameters)); + paramindex = 0; + + if (configname) { + paramindex = add_profile_parameters(cfg, configname, spanparameters, ftdm_array_len(spanparameters)); + if (paramindex) { + ftdm_log(FTDM_LOG_DEBUG, "Added %d parameters from profile %s for span %d\n", paramindex, configname, span_id); + } + } + + for (param = switch_xml_child(myspan, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (ftdm_array_len(spanparameters) - 1 == paramindex) { + CONFIG_ERROR("Too many parameters for GSM span, ignoring any parameter after %s\n", var); + break; + } + + if (!strcasecmp(var, "context")) { + context = val; + } else if (!strcasecmp(var, "dialplan")) { + dialplan = val; + } else { + spanparameters[paramindex].var = var; + spanparameters[paramindex].val = val; + paramindex++; + } + } + + if (ftdm_configure_span_signaling(span, + "gsm", + on_clear_channel_signal, + spanparameters) != FTDM_SUCCESS) { + CONFIG_ERROR("Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); + continue; + } + SPAN_CONFIG[span_id].span = span; + switch_copy_string(SPAN_CONFIG[span_id].context, context, sizeof(SPAN_CONFIG[span_id].context)); + switch_copy_string(SPAN_CONFIG[span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span_id].dialplan)); + switch_copy_string(SPAN_CONFIG[span_id].type, "GSM", sizeof(SPAN_CONFIG[span_id].type)); + ftdm_log(FTDM_LOG_DEBUG, "Configured GSM FreeTDM span %d\n", span_id); + ftdm_span_start(span); + } +} + static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) { switch_xml_t myspan, param; @@ -2997,6 +3086,10 @@ static switch_status_t load_config(void) parse_bri_pri_spans(cfg, spans); } + if ((spans = switch_xml_child(cfg, "gsm_spans"))) { + parse_gsm_spans(cfg, spans); + } + switch_core_hash_init(&globals.ss7_configs, module_pool); if ((spans = switch_xml_child(cfg, "sangoma_ss7_spans"))) { for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { diff --git a/libs/freetdm/src/ftmod/ftmod_gsm/ftmod_gsm.c b/libs/freetdm/src/ftmod/ftmod_gsm/ftmod_gsm.c new file mode 100644 index 0000000000..8337a3829e --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_gsm/ftmod_gsm.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2011, Sangoma Technologies + * 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. + * + * Contributors: + * + * Gideon Sadan <gsadan@sangoma.com> + * Moises Silva <moy@sangoma.com> + * + */ + +#include <stdio.h> +#include <libwat.h> +#include <freetdm.h> +#include <private/ftdm_core.h> + +/* span monitor thread */ +static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj); + +/* IO interface for the command API */ +static ftdm_io_interface_t g_ftdm_gsm_interface; + +static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(gsm_outgoing_call) +{ + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "GSM place call not implemented yet!\n"); + return FTDM_FAIL; +} + +static ftdm_status_t ftdm_gsm_start(ftdm_span_t *span) +{ + return ftdm_thread_create_detached(ftdm_gsm_run, span); +} + +static ftdm_status_t ftdm_gsm_stop(ftdm_span_t *span) +{ + ftdm_log(FTDM_LOG_CRIT, "STOP not implemented yet!\n"); + return FTDM_FAIL; +} + +static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_gsm_get_channel_sig_status) +{ + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "get sig status not implemented yet!\n"); + return FTDM_FAIL; +} + +static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_gsm_set_channel_sig_status) +{ + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "set sig status not implemented yet!\n"); + return FTDM_FAIL; +} + +static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_gsm_get_span_sig_status) +{ + ftdm_log(FTDM_LOG_CRIT, "span get sig status not implemented yet!\n"); + return FTDM_FAIL; +} + +static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_gsm_set_span_sig_status) +{ + ftdm_log(FTDM_LOG_CRIT, "span set sig status not implemented yet!\n"); + return FTDM_FAIL; +} + +static ftdm_state_map_t gsm_state_map = { + { + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_ANY_STATE, FTDM_END}, + {FTDM_CHANNEL_STATE_RESET, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RESET, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + {FTDM_CHANNEL_STATE_RING, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RING, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, 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_PROGRESS_MEDIA, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, 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}, + }, + + /* Outbound states */ + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_ANY_STATE, FTDM_END}, + {FTDM_CHANNEL_STATE_RESET, FTDM_END} + }, + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RESET, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, 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_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END} + }, + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, 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_PROGRESS_MEDIA, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, 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} + }, + } +}; + +static ftdm_status_t ftdm_gsm_state_advance(ftdm_channel_t *ftdmchan) +{ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); + return FTDM_SUCCESS; +} + +static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling) +{ + unsigned paramindex = 0; + const char *var = NULL; + const char *val = NULL; + + ftdm_assert_return(sig_cb != NULL, FTDM_FAIL, "No signaling cb provided\n"); + + if (span->signal_type) { + snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling."); + return FTDM_FAIL; + } + + for (; ftdm_parameters[paramindex].var; paramindex++) { + var = ftdm_parameters[paramindex].var; + val = ftdm_parameters[paramindex].val; + ftdm_log(FTDM_LOG_DEBUG, "Reading GSM parameter %s for span %d\n", var, span->span_id); + if (!strcasecmp(var, "moduletype")) { + if (!val) { + break; + } + if (ftdm_strlen_zero_buf(val)) { + ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty moduletype parameter\n"); + continue; + } + ftdm_log(FTDM_LOG_DEBUG, "Configuring GSM span %d for moduletype %s\n", span->span_id, val); + } else { + snprintf(span->last_error, sizeof(span->last_error), "Unknown GSM parameter [%s]", var); + return FTDM_FAIL; + } + } + + /* Bind function pointers for control operations */ + span->start = ftdm_gsm_start; + span->stop = ftdm_gsm_stop; + span->sig_read = NULL; + span->sig_write = NULL; + + span->signal_cb = sig_cb; + span->signal_type = FTDM_SIGTYPE_GSM; + span->signal_data = NULL; /* Gideon, plz fill me with gsm span specific data (you allocate and free) */ + span->outgoing_call = gsm_outgoing_call; + span->get_span_sig_status = ftdm_gsm_get_span_sig_status; + span->set_span_sig_status = ftdm_gsm_set_span_sig_status; + span->get_channel_sig_status = ftdm_gsm_get_channel_sig_status; + span->set_channel_sig_status = ftdm_gsm_set_channel_sig_status; + + span->state_map = &gsm_state_map; + span->state_processor = ftdm_gsm_state_advance; + + /* use signals queue */ + ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE); + + /* we can skip states (going straight from RING to UP) */ + ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES); + +#if 0 + /* setup the scheduler (create if needed) */ + snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name); + ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n"); + spanpvt->sched = r2data->sched; +#endif + + return FTDM_SUCCESS; + +} + +static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj) +{ + ftdm_channel_t *ftdmchan = NULL; + ftdm_span_t *span = (ftdm_span_t *) obj; + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *citer = NULL; + int waitms = 10; + + ftdm_log(FTDM_LOG_DEBUG, "GSM monitor thread for span %s started\n", span->name); + + chaniter = ftdm_span_get_chan_iterator(span, NULL); + if (!chaniter) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + goto done; + } + while (ftdm_running()) { + +#if 0 + /* run any span timers */ + ftdm_sched_run(r2data->sched); + +#endif + /* deliver the actual channel events to the user now without any channel locking */ + ftdm_span_trigger_signals(span); +#if 0 + /* figure out what event to poll each channel for. POLLPRI when the channel is down, + * POLLPRI|POLLIN|POLLOUT otherwise */ + memset(poll_events, 0, sizeof(short)*span->chan_count); + citer = ftdm_span_get_chan_iterator(span, chaniter); + if (!citer) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + goto done; + } + for (i = 0; citer; citer = ftdm_iterator_next(citer), i++) { + ftdmchan = ftdm_iterator_current(citer); + r2chan = R2CALL(ftdmchan)->r2chan; + poll_events[i] = FTDM_EVENTS; + if (openr2_chan_get_read_enabled(r2chan)) { + poll_events[i] |= FTDM_READ; + } + } + status = ftdm_span_poll_event(span, waitms, poll_events); + + /* run any span timers */ + ftdm_sched_run(r2data->sched); +#endif + ftdm_sleep(waitms); + + + /* this main loop takes care of MF and CAS signaling during call setup and tear down + * for every single channel in the span, do not perform blocking operations here! */ + citer = ftdm_span_get_chan_iterator(span, chaniter); + for ( ; citer; citer = ftdm_iterator_next(citer)) { + ftdmchan = ftdm_iterator_current(citer); + + ftdm_channel_lock(ftdmchan); + + ftdm_channel_advance_states(ftdmchan); + + ftdm_channel_unlock(ftdmchan); + } + } + +done: + ftdm_iterator_free(chaniter); + + ftdm_log(FTDM_LOG_DEBUG, "GSM thread ending.\n"); + + return NULL; +} + +#define FT_SYNTAX "USAGE:\n" \ +"--------------------------------------------------------------------------------\n" \ +"ftdm gsm status <span_id|span_name>\n" \ +"--------------------------------------------------------------------------------\n" +static FIO_API_FUNCTION(ftdm_gsm_api) +{ + char *mycmd = NULL, *argv[10] = { 0 }; + int argc = 0; + + if (data) { + mycmd = ftdm_strdup(data); + argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } + + if (argc == 1) { + if (!strcasecmp(argv[0], "version")) { + stream->write_function(stream, "libwat GSM version: implement me!!\n"); + stream->write_function(stream, "+OK.\n"); + goto done; + } + } + + stream->write_function(stream, "%s", FT_SYNTAX); + +done: + + ftdm_safe_free(mycmd); + + return FTDM_SUCCESS; + +} + +static FIO_IO_LOAD_FUNCTION(ftdm_gsm_io_init) +{ + assert(fio != NULL); + memset(&g_ftdm_gsm_interface, 0, sizeof(g_ftdm_gsm_interface)); + + g_ftdm_gsm_interface.name = "gsm"; + g_ftdm_gsm_interface.api = ftdm_gsm_api; + + *fio = &g_ftdm_gsm_interface; + + return FTDM_SUCCESS; +} + +static FIO_SIG_LOAD_FUNCTION(ftdm_gsm_init) +{ + /* this is called on module load */ + return FTDM_SUCCESS; +} + +static FIO_SIG_UNLOAD_FUNCTION(ftdm_gsm_destroy) +{ + /* this is called on module unload */ + return FTDM_SUCCESS; +} + +EX_DECLARE_DATA ftdm_module_t ftdm_module = { + /* .name */ "gsm", + /* .io_load */ ftdm_gsm_io_init, + /* .io_unload */ NULL, + /* .sig_load */ ftdm_gsm_init, + /* .sig_configure */ NULL, + /* .sig_unload */ ftdm_gsm_destroy, + /* .configure_span_signaling */ ftdm_gsm_configure_span_signaling +}; + + +/* 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/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 585a5d72ae..81f31e4ff8 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -472,9 +472,10 @@ typedef enum { FTDM_TRUNK_FXO, FTDM_TRUNK_FXS, FTDM_TRUNK_EM, + FTDM_TRUNK_GSM, FTDM_TRUNK_NONE } ftdm_trunk_type_t; -#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE" +#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "GSM", "NONE" /*! \brief Move from string to ftdm_trunk_type_t and viceversa */ FTDM_STR2ENUM_P(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t) diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 6df25fe4d2..5bacaaf9ba 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -163,7 +163,8 @@ typedef enum { FTDM_SIGTYPE_SANGOMABOOST, FTDM_SIGTYPE_M3UA, FTDM_SIGTYPE_R2, - FTDM_SIGTYPE_SS7 + FTDM_SIGTYPE_SS7, + FTDM_SIGTYPE_GSM } ftdm_signal_type_t; typedef enum {