From a082c9e913bb3d777d29e4692a8a6e8afcd552e2 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Thu, 16 Dec 2010 17:01:06 -0200 Subject: [PATCH 1/5] freetdm: ftmod_r2 - implemented ftdm_r2_get_span_sig_status() and ftdm_r2_set_span_sig_status() mod_freetdm - created sigstatus api command --- libs/freetdm/mod_freetdm/mod_freetdm.c | 78 +++++++++++++++++++++- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 71 +++++++++++++++++++- 2 files changed, 147 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 38197bb2f0..daddc9abc1 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -3542,7 +3542,83 @@ SWITCH_STANDARD_API(ft_function) goto end; } - if (!strcasecmp(argv[0], "dump")) { + if (!strcasecmp(argv[0], "sigstatus")) { + ftdm_span_t *span = NULL; + ftdm_signaling_status_t sigstatus; + + if (argc < 3) { + stream->write_function(stream, "-ERR Usage: ftdm sigstatus get|set [] [] []\n"); + goto end; + } + if (!strcasecmp(argv[1], "get") && argc < 3) { + stream->write_function(stream, "-ERR sigstatus get usage: get \n"); + goto end; + } + if (!strcasecmp(argv[1], "set") && argc != 5) { + stream->write_function(stream, "-ERR sigstatus set usage: set |all \n"); + goto end; + } + + ftdm_span_find_by_name(argv[2], &span); + if (!span) { + stream->write_function(stream, "-ERR invalid span\n"); + goto end; + } + + if (!strcasecmp(argv[1], "get")) { + if (argc == 4) { + uint32_t chan_id = atol(argv[3]); + ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id); + if (!fchan) { + stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id); + goto end; + } + + if ((FTDM_SUCCESS == ftdm_channel_get_sig_status(fchan, &sigstatus))) { + stream->write_function(stream, "channel %d signaling status: %s\n", chan_id, ftdm_signaling_status2str(sigstatus)); + } else { + stream->write_function(stream, "-ERR failed to get channel sigstatus\n"); + } + goto end; + } else { + if ((FTDM_SUCCESS == ftdm_span_get_sig_status(span, &sigstatus))) { + stream->write_function(stream, "signaling_status: %s\n", ftdm_signaling_status2str(sigstatus)); + } else { + stream->write_function(stream, "-ERR failed to read span status: %s\n", ftdm_span_get_last_error(span)); + } + } + goto end; + } + if (!strcasecmp(argv[1], "set")) { + sigstatus = ftdm_str2ftdm_signaling_status(argv[4]); + + if (!strcasecmp(argv[3], "all")) { + if ((FTDM_SUCCESS == ftdm_span_set_sig_status(span, sigstatus))) { + stream->write_function(stream, "Signaling status of all channels from span %s set to %s\n", + ftdm_span_get_name(span), ftdm_signaling_status2str(sigstatus)); + } else { + stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus)); + } + goto end; + } else { + uint32_t chan_id = atol(argv[3]); + ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id); + if (!fchan) { + stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id); + goto end; + } + + if ((FTDM_SUCCESS == ftdm_channel_set_sig_status(fchan, sigstatus))) { + stream->write_function(stream, "Signaling status of channel %d set to %s\n", chan_id, + ftdm_signaling_status2str(sigstatus)); + } else { + stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus)); + } + goto end; + } + } + + } else if (!strcasecmp(argv[0], "dump")) { if (argc < 2) { stream->write_function(stream, "-ERR Usage: ftdm dump []\n"); goto end; diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index ef9201bbe6..b4e9e138cc 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -461,12 +461,79 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status) openr2_chan_set_idle(r2chan); break; default: - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%s'\n", status); + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status); return FTDM_FAIL; } return FTDM_SUCCESS; } +static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status) +{ + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *citer = NULL; + uint32_t i; + + 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); + return FTDM_FAIL; + } + /* if ALL channels are non-idle, report SUSPENDED. UP otherwise. */ + *status = FTDM_SIG_STATE_SUSPENDED; + for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) { + ftdm_channel_t *fchan = ftdm_iterator_current(citer); + + if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) { + *status = FTDM_SIG_STATE_UP; + break; + } + } + ftdm_iterator_free(chaniter); + return FTDM_SUCCESS; +} + +static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status) +{ + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *citer = NULL; + uint32_t span_opr = -1; + uint32_t i; + + /* we either set the channels to BLOCK or IDLE */ + switch(status) { + case FTDM_SIG_STATE_DOWN: + case FTDM_SIG_STATE_SUSPENDED: + span_opr = 0; + break; + case FTDM_SIG_STATE_UP: + span_opr = 1; + break; + default: + ftdm_log(FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status); + return FTDM_FAIL; + } + + 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); + return FTDM_FAIL; + } + /* iterate over all channels, setting them to the requested state */ + for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) { + ftdm_channel_t *fchan = ftdm_iterator_current(citer); + openr2_chan_t *r2chan = R2CALL(fchan)->r2chan; + if (span_opr == 0) { + openr2_chan_set_blocked(r2chan); + ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel blocked\n"); + } else { + openr2_chan_set_idle(r2chan); + ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel idle\n"); + } + } + ftdm_iterator_free(chaniter); + return FTDM_SUCCESS; +} + /* always called from the monitor thread */ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) { @@ -1441,6 +1508,8 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) span->signal_type = FTDM_SIGTYPE_R2; span->signal_data = r2data; span->outgoing_call = r2_outgoing_call; + span->get_span_sig_status = ftdm_r2_get_span_sig_status; + span->set_span_sig_status = ftdm_r2_set_span_sig_status; span->get_channel_sig_status = ftdm_r2_get_channel_sig_status; span->set_channel_sig_status = ftdm_r2_set_channel_sig_status; From 6b66a0516bcc4d7bd9461366ea7bf958b4ef9aeb Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Thu, 16 Dec 2010 18:19:50 -0200 Subject: [PATCH 2/5] freetdm: ftmod_r2 - fixed infinite loop on span stop --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index d1b24da1b8..952b94b63f 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -55,10 +55,13 @@ static int32_t g_thread_count = 0; typedef int openr2_call_status_t; -/* when the users kills a span we clear this flag to kill the signaling thread */ +/* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread + * knows it must stop, and we wait for FTDM_R2_RUNNING to be clear, which tells us the + * signaling thread is done. */ /* FIXME: what about the calls that are already up-and-running? */ typedef enum { FTDM_R2_RUNNING = (1 << 0), + FTDM_R2_SPAN_STARTED = (1 << 1), } ftdm_r2_flag_t; /* private call information stored in ftdmchan->call_data void* ptr, @@ -424,13 +427,14 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) static ftdm_status_t ftdm_r2_start(ftdm_span_t *span) { ftdm_r2_data_t *r2_data = span->signal_data; - ftdm_set_flag(r2_data, FTDM_R2_RUNNING); + ftdm_set_flag(r2_data, FTDM_R2_SPAN_STARTED); return ftdm_thread_create_detached(ftdm_r2_run, span); } static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span) { ftdm_r2_data_t *r2_data = span->signal_data; + ftdm_clear_flag(r2_data, FTDM_R2_SPAN_STARTED); while (ftdm_test_flag(r2_data, FTDM_R2_RUNNING)) { ftdm_log(FTDM_LOG_DEBUG, "Waiting for R2 span %s\n", span->name); ftdm_sleep(100); @@ -1759,6 +1763,9 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) uint32_t txqueue_size = 4; short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); + /* as long as this thread is running, this flag is set */ + ftdm_set_flag(r2data, FTDM_R2_RUNNING); + #ifdef __linux__ r2data->monitor_thread_id = syscall(SYS_gettid); #endif @@ -1781,7 +1788,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) memset(&start, 0, sizeof(start)); memset(&end, 0, sizeof(end)); - while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) { + while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_SPAN_STARTED)) { res = gettimeofday(&end, NULL); if (res) { ftdm_log(FTDM_LOG_CRIT, "Failure gettimeofday [%s]\n", strerror(errno)); From 43dd86fb96f8a20b405df6f6fda932ad6cc2e017 Mon Sep 17 00:00:00 2001 From: Arnaldo Pereira Date: Thu, 16 Dec 2010 18:47:40 -0200 Subject: [PATCH 3/5] freetdm: ftmod_r2 - small code clean --- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 952b94b63f..9f35971abb 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -473,20 +473,16 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status) static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status) { - ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *citer = NULL; - uint32_t i; - - chaniter = ftdm_span_get_chan_iterator(span, NULL); + ftdm_iterator_t *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); return FTDM_FAIL; } /* if ALL channels are non-idle, report SUSPENDED. UP otherwise. */ *status = FTDM_SIG_STATE_SUSPENDED; - for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) { + for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { ftdm_channel_t *fchan = ftdm_iterator_current(citer); - if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) { *status = FTDM_SIG_STATE_UP; break; @@ -501,7 +497,6 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status) ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *citer = NULL; uint32_t span_opr = -1; - uint32_t i; /* we either set the channels to BLOCK or IDLE */ switch(status) { @@ -523,7 +518,7 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status) return FTDM_FAIL; } /* iterate over all channels, setting them to the requested state */ - for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) { + for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { ftdm_channel_t *fchan = ftdm_iterator_current(citer); openr2_chan_t *r2chan = R2CALL(fchan)->r2chan; if (span_opr == 0) { From d6ec16804a62e15aad034d6c6e226748ca522817 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 16 Dec 2010 15:57:46 -0500 Subject: [PATCH 4/5] freetdm: added trace type to raw traces --- libs/freetdm/src/ftdm_io.c | 10 +++++----- .../ftmod_sangoma_isdn_stack_rcv.c | 8 ++++---- .../ftmod_sangoma_isdn_trace.c | 8 ++++---- libs/freetdm/src/include/freetdm.h | 20 ++++++++++++++----- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 1750d6d7d9..8755d73875 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -281,7 +281,10 @@ FTDM_ENUM_NAMES(SIGNALING_STATUS_NAMES, SIGSTATUS_STRINGS) FTDM_STR2ENUM(ftdm_str2ftdm_signaling_status, ftdm_signaling_status2str, ftdm_signaling_status_t, SIGNALING_STATUS_NAMES, FTDM_SIG_STATE_INVALID) FTDM_ENUM_NAMES(TRACE_DIR_NAMES, TRACE_DIR_STRINGS) -FTDM_STR2ENUM(ftdm_str2ftdm_trace_dir, ftdm_trace_dir2str, ftdm_trace_dir_t, TRACE_DIR_NAMES, FTDM_TRACE_INVALID) +FTDM_STR2ENUM(ftdm_str2ftdm_trace_dir, ftdm_trace_dir2str, ftdm_trace_dir_t, TRACE_DIR_NAMES, FTDM_TRACE_DIR_INVALID) + +FTDM_ENUM_NAMES(TRACE_TYPE_NAMES, TRACE_TYPE_STRINGS) +FTDM_STR2ENUM(ftdm_str2ftdm_trace_type, ftdm_trace_type2str, ftdm_trace_type_t, TRACE_TYPE_NAMES, FTDM_TRACE_TYPE_INVALID) FTDM_ENUM_NAMES(TON_NAMES, TON_STRINGS) FTDM_STR2ENUM(ftdm_str2ftdm_ton, ftdm_ton2str, ftdm_ton_t, TON_NAMES, FTDM_TON_INVALID) @@ -2475,12 +2478,9 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char UNREFERENCED_PARAMETER(func); UNREFERENCED_PARAMETER(line); #endif - - ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100); - ftdm_call_set_call_id(&ftdmchan->caller_data); + ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100); ftdm_channel_unlock(ftdmchan); - return status; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index 3afdaa599e..a90968f64b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -790,9 +790,9 @@ void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf) mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len; if (trc->t.trc.evnt == TL3PKTTX) { - dir = FTDM_TRACE_OUTGOING; + dir = FTDM_TRACE_DIR_OUTGOING; } else { - dir = FTDM_TRACE_INCOMING; + dir = FTDM_TRACE_DIR_INCOMING; } if (mlen) { @@ -837,9 +837,9 @@ void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf) } if (trc->t.trc.evnt == TL2FRMTX) { - dir = FTDM_TRACE_OUTGOING; + dir = FTDM_TRACE_DIR_OUTGOING; } else { - dir = FTDM_TRACE_INCOMING; + dir = FTDM_TRACE_DIR_INCOMING; } ftdm_assert(mBuf != NULLP, "Received a Q921 trace with no buffer"); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c index c03976a1c2..fd9edeba8d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c @@ -118,8 +118,8 @@ void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d sigev.channel = signal_data->dchan; sigev.event_id = FTDM_SIGEVENT_TRACE_RAW; - sigev.ev_data.logevent.dir = dir; - sigev.ev_data.logevent.level = 2; + sigev.ev_data.trace.dir = dir; + sigev.ev_data.trace.type = FTDM_TRACE_TYPE_Q921; /* TODO: Map trace to call ID here */ sigev.call_id = 0; @@ -226,8 +226,8 @@ void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d sigev.channel = signal_data->dchan; sigev.event_id = FTDM_SIGEVENT_TRACE_RAW; - sigev.ev_data.logevent.dir = dir; - sigev.ev_data.logevent.level = 3; + sigev.ev_data.trace.dir = dir; + sigev.ev_data.trace.type = FTDM_TRACE_TYPE_Q931; /* TODO: Map trace to call ID here */ diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 41bf819a1c..b75df1eca1 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -390,21 +390,31 @@ typedef struct { typedef enum { /* This is an received frame */ - FTDM_TRACE_INCOMING, + FTDM_TRACE_DIR_INCOMING, /* This is a transmitted frame */ - FTDM_TRACE_OUTGOING, + FTDM_TRACE_DIR_OUTGOING, /* Invalid */ - FTDM_TRACE_INVALID, + FTDM_TRACE_DIR_INVALID, } ftdm_trace_dir_t; #define TRACE_DIR_STRINGS "INCOMING", "OUTGOING", "INVALID" /*! \brief Move string to ftdm_trace_dir_t and viceversa */ FTDM_STR2ENUM_P(ftdm_str2ftdm_trace_dir, ftdm_trace_dir2str, ftdm_trace_dir_t) +typedef enum { + FTDM_TRACE_TYPE_Q931, + FTDM_TRACE_TYPE_Q921, + FTDM_TRACE_TYPE_INVALID, +} ftdm_trace_type_t; +#define TRACE_TYPE_STRINGS "Q931", "Q921", "INVALID" + +/*! \brief Move string to ftdm_trace_type_t and viceversa */ +FTDM_STR2ENUM_P(ftdm_str2ftdm_trace_type, ftdm_trace_type2str, ftdm_trace_type_t) + typedef struct { /* Direction - incoming or outgoing */ ftdm_trace_dir_t dir; - uint8_t level; /* 1 for phy layer, 2 for q921/mtp2, 3 for q931/mtp3 */ + ftdm_trace_type_t type; } ftdm_event_trace_t; /*! \brief Generic signaling message */ @@ -418,7 +428,7 @@ struct ftdm_sigmsg { uint32_t call_id; /*!< unique call id for this call */ union { ftdm_event_sigstatus_t sigstatus; /*!< valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED */ - ftdm_event_trace_t logevent; /*!< valid if event_id is FTDM_SIGEVENT_TRACE or FTDM_SIGEVENT_TRACE_RAW */ + ftdm_event_trace_t trace; /*!< valid if event_id is FTDM_SIGEVENT_TRACE or FTDM_SIGEVENT_TRACE_RAW */ }ev_data; }; From 4144d518c60cd215915d9ab07a49425bbe701286 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 20 Dec 2010 17:06:36 -0500 Subject: [PATCH 5/5] Freetdm: Support for mapped raw traces --- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 4 + .../ftmod_sangoma_isdn_stack_hndl.c | 8 +- .../ftmod_sangoma_isdn_support.c | 26 ++ .../ftmod_sangoma_isdn_trace.c | 258 ++++++++++++++++-- .../ftmod_sangoma_isdn_trace.h | 84 ++++-- 5 files changed, 327 insertions(+), 53 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index 6a440e4f66..9e54788464 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -233,6 +233,7 @@ typedef struct sngisdn_chan_data { uint32_t flags; uint8_t ces; /* used only for BRI, otherwise always 0 */ uint8_t dchan_id; + uint16_t call_ref; /* Q.931 call reference, only valid for ETSI/INSNET/QSIG */ uint32_t suInstId; /* instance ID generated locally */ uint32_t spInstId; /* instance ID generated by stack */ @@ -446,6 +447,9 @@ void sngisdn_rcv_cc_ind(CcMngmt *status); void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...); void sngisdn_rcv_sng_assert(char *message); +#ifdef NETBORDER_CALL_REF +ftdm_status_t get_callref(ftdm_channel_t *ftdmchan, BCCallRef* callRef); +#endif ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb); ftdm_status_t get_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb); ftdm_status_t get_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index 7e9e360c6d..67bc6e9661 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -71,13 +71,12 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_info->glare.suInstId = suInstId; /* Do not generate a suInstId now, we will generate when glared call gets extracted */ sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; - sngisdn_info->glare.ces = ces; + sngisdn_info->glare.ces = ces; break; } sngisdn_info->suInstId = get_unique_suInstId(suId); sngisdn_info->spInstId = spInstId; - if (conEvnt->cdPtyNmb.eh.pres && signal_data->num_local_numbers) { uint8_t local_number_matched = 0; @@ -125,6 +124,9 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) } /* Fill in call information */ +#ifdef NETBORDER_CALL_REF + get_callref(ftdmchan, &conEvnt->callRef); +#endif get_calling_num(ftdmchan, &conEvnt->cgPtyNmb); get_calling_num2(ftdmchan, &conEvnt->cgPtyNmb2); get_called_num(ftdmchan, &conEvnt->cdPtyNmb); @@ -282,6 +284,7 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_DIALING: + get_callref(ftdmchan, &cnStEvnt->callRef); get_prog_ind_ie(ftdmchan, &cnStEvnt->progInd); get_facility_ie(ftdmchan, &cnStEvnt->facilityStr); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); @@ -354,6 +357,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) case MI_CALLPROC: case MI_PROGRESS: case MI_ALERTING: + get_callref(ftdmchan, &cnStEvnt->callRef); get_prog_ind_ie(ftdmchan, &cnStEvnt->progInd); get_facility_ie(ftdmchan, &cnStEvnt->facilityStr); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index 28768a1f09..6fd613b306 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -161,6 +161,32 @@ ftdm_status_t sngisdn_set_span_avail_rate(ftdm_span_t *span, sngisdn_avail_t ava return FTDM_SUCCESS; } +#ifdef NETBORDER_CALL_REF +ftdm_status_t get_callref(ftdm_channel_t *ftdmchan, BCCallRef* callRef) +{ + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; + sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; + + if (signal_data->raw_trace_q931) { + if (callRef->eh.pres != PRSNT_NODEF || callRef->reference.pres != PRSNT_NODEF) { + /* Netborder only supports BRI, so we only care for BRI for now */ + if (FTDM_SPAN_IS_BRI(ftdmchan->span) && !sngisdn_info->call_ref) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to obtain call reference\n"); + } + return FTDM_FAIL; + } + if (FTDM_SPAN_IS_BRI(ftdmchan->span)) { + sngisdn_info->call_ref = 0x7F & callRef->reference.val; + } else { + sngisdn_info->call_ref = 0x7FFF & callRef->reference.val; + } + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Call reference:%04x\n", sngisdn_info->call_ref); + } + return FTDM_SUCCESS; +} +#endif + ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c index fd9edeba8d..e7488c72ab 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c @@ -38,14 +38,26 @@ #define OCTET(x) (ieData[x-1] & 0xFF) #define MAX_DECODE_STR_LEN 2000 +typedef struct sngisdn_trace_info +{ + uint8_t call_ref_flag; + uint16_t call_ref; + uint8_t msgtype; + uint8_t bchan_no; + ftdm_trace_dir_t dir; +} sngisdn_frame_info_t; + void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end); uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset, uint8_t *data, uint16_t index_start); +static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_frame_info_t frame_info, ftdm_channel_t **found); +static ftdm_status_t sngisdn_get_frame_info(uint8_t *data, uint32_t data_len, ftdm_trace_dir_t dir, sngisdn_frame_info_t *frame_info); uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi); char* get_code_2_str(int code, struct code2str *pCodeTable); void sngisdn_decode_q921(char* str, uint8_t* data, uint32_t data_len); void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len); + char* get_code_2_str(int code, struct code2str *pCodeTable) { struct code2str* pCode2txt; @@ -120,10 +132,7 @@ void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d sigev.ev_data.trace.dir = dir; sigev.ev_data.trace.type = FTDM_TRACE_TYPE_Q921; - - /* TODO: Map trace to call ID here */ - sigev.call_id = 0; - + raw_data = ftdm_malloc(data_len); ftdm_assert(raw_data, "Failed to malloc"); @@ -218,26 +227,33 @@ void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d { uint8_t *raw_data; ftdm_sigmsg_t sigev; + ftdm_channel_t *ftdmchan; + sngisdn_frame_info_t frame_info; memset(&sigev, 0, sizeof(sigev)); - sigev.span_id = signal_data->ftdm_span->span_id; - sigev.chan_id = signal_data->dchan->chan_id; - sigev.channel = signal_data->dchan; - sigev.event_id = FTDM_SIGEVENT_TRACE_RAW; + /* Note: Mapped raw trace assume only exclusive b-channel selection is used. i.e the b-channel selected on outgoing SETUP is always used for the call */ + + if (sngisdn_get_frame_info(data, data_len, dir, &frame_info) == FTDM_SUCCESS) { + if (sngisdn_map_call(signal_data, frame_info, &ftdmchan) == FTDM_SUCCESS) { + sigev.call_id = ftdmchan->caller_data.call_id; + sigev.span_id = ftdmchan->physical_span_id; + sigev.chan_id = ftdmchan->physical_chan_id; + sigev.channel = ftdmchan; + } + sigev.event_id = FTDM_SIGEVENT_TRACE_RAW; - sigev.ev_data.trace.dir = dir; - sigev.ev_data.trace.type = FTDM_TRACE_TYPE_Q931; - - /* TODO: Map trace to call ID here */ - - raw_data = ftdm_malloc(data_len); - ftdm_assert(raw_data, "Failed to malloc"); - - memcpy(raw_data, data, data_len); - sigev.raw_data = raw_data; - sigev.raw_data_len = data_len; - ftdm_span_send_signal(signal_data->ftdm_span, &sigev); + sigev.ev_data.trace.dir = dir; + sigev.ev_data.trace.type = FTDM_TRACE_TYPE_Q931; + + raw_data = ftdm_malloc(data_len); + ftdm_assert(raw_data, "Failed to malloc"); + + memcpy(raw_data, data, data_len); + sigev.raw_data = raw_data; + sigev.raw_data_len = data_len; + ftdm_span_send_signal(signal_data->ftdm_span, &sigev); + } } void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len) @@ -253,9 +269,6 @@ void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len) prot_disc = (uint8_t)data[0]; str_len += sprintf(&str[str_len], " Prot Disc:%s (0x%02x)\n", get_code_2_str(prot_disc, dcodQ931ProtDiscTable), prot_disc); - - - /* Decode Call Reference */ lenCallRef = (uint8_t) (data[1] & 0x0F); @@ -747,4 +760,203 @@ void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_ return; } +static ftdm_status_t sngisdn_get_frame_info(uint8_t *data, uint32_t data_len, ftdm_trace_dir_t dir, sngisdn_frame_info_t *target) +{ + uint8_t pos = 0; + uint8_t flag; + uint16_t ref = 0; + uint8_t ref_len = 0; + uint8_t bchan_no = 0; + uint8_t msgtype; + + /* First octet is protocol discriminator */ + pos++; + /* Second octet contains length of call reference */ + ref_len = data[pos++] & 0x0F; + + /* third octet is call reference */ + flag = (data[pos] & 0x80) >> 7; + if (ref_len == 2) { + ref = (data[pos++] & 0x7F) << 8; + ref |= (data[pos++] & 0xFF) ; + } else { + ref = (data[pos++] & 0x7F); + } + + /* Next octet is the message type */ + msgtype = data[pos++] & 0x7F; + + /* + ftdm_log(FTDM_LOG_DEBUG, "Raw frame:call_ref:0x%04x flag:%d msgtype:%d\n", ref, flag, msgtype); + */ + if (!ref) { + /* This is not a call specific message (RESTART for example and we do not care about it) */ + return FTDM_FAIL; + } + + /* Look for the b-channel */ + if (msgtype == PROT_Q931_MSGTYPE_SETUP) { + /* Try to find the b-channel no*/ + + for(; pos < data_len; pos++) { + uint8_t ie_id = data[pos]; + uint8_t ie_len = data[pos+1]; + + switch(ie_id) { + case PROT_Q931_IE_SENDING_COMPLETE: + /* Single octet ie's do not have a length */ + ie_len = 0; + break; + case PROT_Q931_IE_CHANNEL_ID: + { + /* Try to obtain the b-channel */ + uint8_t ie_pos = pos+2; + //ifaceIdPresent = get_bits(OCTET(3),7,7); + if (data[ie_pos] & 0x20) { + /* Interface type is Primary Rate */ + ie_pos+=2; + bchan_no = data[ie_pos] & 0x7F; + } else { + /* Interface type is Basic Interface */ + /* Get the channel number from info channel selection */ + bchan_no = data[ie_pos] & 0x03; + } + ftdm_log(FTDM_LOG_DEBUG, "Found b-channel:%d\n", bchan_no); + goto parse_ies_done; + } + break; + default: + pos = pos+ie_len+1; + } + //ftdm_log(FTDM_LOG_DEBUG, "Decoded IE:%s\n", get_code_2_str(ie_id, dcodQ931IEIDTable)); + } + if (!bchan_no) { + char tmp[1000]; + print_hex_dump(tmp, 0, data, 0, data_len); + ftdm_log(FTDM_LOG_WARNING, "Failed to determine b-channel on SETUP message\n%s\n", tmp); + } + } + +parse_ies_done: + + target->call_ref = ref; + target->call_ref_flag = flag; + target->msgtype = msgtype; + target->bchan_no = bchan_no; + target->dir = dir; + + return FTDM_SUCCESS; +} + +static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_frame_info_t frame_info, ftdm_channel_t **found) +{ + ftdm_channel_t *ftdmchan; + sngisdn_chan_data_t *sngisdn_info; + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; + ftdm_status_t status = FTDM_FAIL; + uint8_t outbound_call = 0; + + if ((!frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_OUTGOING) || + (frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_INCOMING)) { + + /* If this is an outgoing frame and this frame was sent by the originating side + of the call (frame_info.call_ref_flag == 0), then this is an outbound call */ + outbound_call = 1; + } else { + outbound_call = 0; + } + + switch (frame_info.msgtype) { + case PROT_Q931_MSGTYPE_SETUP: + /* We initiated this outgoing call try to match the call reference with our internal call-id*/ + if (!frame_info.bchan_no) { + /* We were not able to determine the bchannel on this call, so we will not be able to match it anyway */ + status = FTDM_FAIL; + } + + chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr)); + ftdm_channel_lock(ftdmchan); + + if (outbound_call) { + sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data; + if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (ftdmchan->caller_data.call_id && ftdmchan->physical_chan_id == frame_info.bchan_no) { + + sngisdn_info->call_ref = frame_info.call_ref; + *found = ftdmchan; + status = FTDM_SUCCESS; + } + } + } else { + if (ftdmchan->physical_chan_id == frame_info.bchan_no) { + *found = ftdmchan; + status = FTDM_SUCCESS; + } + } + ftdm_channel_unlock(ftdmchan); + } + ftdm_iterator_free(chaniter); + break; + case PROT_Q931_MSGTYPE_ALERTING: + case PROT_Q931_MSGTYPE_PROCEEDING: + case PROT_Q931_MSGTYPE_PROGRESS: + case PROT_Q931_MSGTYPE_CONNECT: + case PROT_Q931_MSGTYPE_SETUP_ACK: + case PROT_Q931_MSGTYPE_CONNECT_ACK: + case PROT_Q931_MSGTYPE_USER_INFO: + case PROT_Q931_MSGTYPE_DISCONNECT: + case PROT_Q931_MSGTYPE_RELEASE: + case PROT_Q931_MSGTYPE_RELEASE_ACK: + case PROT_Q931_MSGTYPE_RELEASE_COMPLETE: + case PROT_Q931_MSGTYPE_FACILITY: + case PROT_Q931_MSGTYPE_NOTIFY: + case PROT_Q931_MSGTYPE_STATUS_ENQUIRY: + case PROT_Q931_MSGTYPE_INFORMATION: + case PROT_Q931_MSGTYPE_STATUS: + /* Look for an outbound call on that span and and try to match the call-id */ + chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr)); + ftdm_channel_lock(ftdmchan); + sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data; + if (outbound_call) { + if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (sngisdn_info->call_ref == frame_info.call_ref) { + + *found = ftdmchan; + status = FTDM_SUCCESS; + } + } + } else { + if (sngisdn_info && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (sngisdn_info->call_ref && sngisdn_info->call_ref == frame_info.call_ref) { + + *found = ftdmchan; + status = FTDM_SUCCESS; + } + } + } + ftdm_channel_unlock(ftdmchan); + } + ftdm_iterator_free(chaniter); + break; + default: + /* This frame is not call specific, ignore */ + break; + } + if (status == FTDM_SUCCESS) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Mapped %s with Call Ref:%04x to call-id:%d\n", get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref, (*found)->caller_data.call_id); + } else { + /* We could not map this frame to a call-id */ + ftdm_log(FTDM_LOG_DEBUG, "Failed to map %s with Call Ref:%04x to local call\n", + get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref); + } + + return status; +} + + diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h index f054de9377..db33cf8083 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h @@ -191,37 +191,65 @@ struct code2str dcodQ931CallRefLoTable[] = { {13, "D"}, {14, "E"}, {15, "F"}, - {-1,"?"}, + {-1, "?"}, }; +#define PROT_Q931_MSGTYPE_ALERTING 1 +#define PROT_Q931_MSGTYPE_PROCEEDING 2 +#define PROT_Q931_MSGTYPE_PROGRESS 3 +#define PROT_Q931_MSGTYPE_SETUP 5 +#define PROT_Q931_MSGTYPE_CONNECT 7 +#define PROT_Q931_MSGTYPE_SETUP_ACK 13 +#define PROT_Q931_MSGTYPE_CONNECT_ACK 15 +#define PROT_Q931_MSGTYPE_USER_INFO 32 +#define PROT_Q931_MSGTYPE_SUSPEND_REJ 33 +#define PROT_Q931_MSGTYPE_RESUME_REJ 34 +#define PROT_Q931_MSGTYPE_SUSPEND 37 +#define PROT_Q931_MSGTYPE_RESUME 38 +#define PROT_Q931_MSGTYPE_SUSPEND_ACK 45 +#define PROT_Q931_MSGTYPE_RESUME_ACK 46 +#define PROT_Q931_MSGTYPE_DISCONNECT 69 +#define PROT_Q931_MSGTYPE_RESTART 70 +#define PROT_Q931_MSGTYPE_RELEASE 77 +#define PROT_Q931_MSGTYPE_RELEASE_ACK 78 +#define PROT_Q931_MSGTYPE_RELEASE_COMPLETE 90 +#define PROT_Q931_MSGTYPE_SEGMENT 96 +#define PROT_Q931_MSGTYPE_FACILITY 98 +#define PROT_Q931_MSGTYPE_NOTIFY 110 +#define PROT_Q931_MSGTYPE_STATUS_ENQUIRY 117 +#define PROT_Q931_MSGTYPE_CONGESTION_CNTRL 121 +#define PROT_Q931_MSGTYPE_INFORMATION 123 +#define PROT_Q931_MSGTYPE_STATUS 125 + + struct code2str dcodQ931MsgTypeTable[] = { - {1, "Alerting"}, - {2, "Call Proceeding"}, - {3, "Progress"}, - {5, "Setup"}, - {7, "Connect"}, - {13, "Setup Ack"}, - {15, "Connect Ack"}, - {32, "User Info"}, - {33, "Suspend Rej"}, - {34, "Resume Rej"}, - {37, "Suspend"}, - {38, "Resume"}, - {45, "Suspend Ack"}, - {46, "Resume Ack"}, - {69, "Disconnect"}, - {70, "Restart"}, - {77, "Release"}, - {78, "Release Ack"}, - {90, "Release Compl"}, - {96, "Segment"}, - {98, "Facility"}, - {110, "Notify"}, - {117, "Status Enquiry"}, - {121, "Congest Cntrl"}, - {123, "Information"}, - {125, "Status"}, - {-1, "Unknown"}, + {PROT_Q931_MSGTYPE_ALERTING, "ALERT"}, + {PROT_Q931_MSGTYPE_PROCEEDING, "PROCEED"}, + {PROT_Q931_MSGTYPE_PROGRESS, "PROGRESS"}, + {PROT_Q931_MSGTYPE_SETUP, "SETUP"}, + {PROT_Q931_MSGTYPE_CONNECT, "CONNECT"}, + {PROT_Q931_MSGTYPE_SETUP_ACK, "SETUP ACK"}, + {PROT_Q931_MSGTYPE_CONNECT_ACK, "CONNECT ACK"}, + {PROT_Q931_MSGTYPE_USER_INFO, "USER INFO"}, + {PROT_Q931_MSGTYPE_SUSPEND_REJ, "SUSPEND REJ"}, + {PROT_Q931_MSGTYPE_RESUME_REJ, "RESUME REJ"}, + {PROT_Q931_MSGTYPE_SUSPEND, "SUSPEND"}, + {PROT_Q931_MSGTYPE_RESUME, "RESUME"}, + {PROT_Q931_MSGTYPE_SUSPEND_ACK, "SUSPEND ACK"}, + {PROT_Q931_MSGTYPE_RESUME_ACK, "RESUME ACK"}, + {PROT_Q931_MSGTYPE_DISCONNECT, "DISCONNECT"}, + {PROT_Q931_MSGTYPE_RESTART, "RESTART"}, + {PROT_Q931_MSGTYPE_RELEASE, "RELEASE"}, + {PROT_Q931_MSGTYPE_RELEASE_ACK, "RELEASR ACK"}, + {PROT_Q931_MSGTYPE_RELEASE_COMPLETE, "RELEASE COMPLETE"}, + {PROT_Q931_MSGTYPE_SEGMENT, "SEGMENT"}, + {PROT_Q931_MSGTYPE_FACILITY, "FACILITY"}, + {PROT_Q931_MSGTYPE_NOTIFY, "NOTIFY"}, + {PROT_Q931_MSGTYPE_STATUS_ENQUIRY, "STATUS ENQ"}, + {PROT_Q931_MSGTYPE_CONGESTION_CNTRL, "CONGESTION CTRL"}, + {PROT_Q931_MSGTYPE_INFORMATION, "INFO"}, + {PROT_Q931_MSGTYPE_STATUS, "STATUS"}, + {-1, "UNKNOWN"}, }; struct code2str dcodQ931CauseCodeTable[] = {