Added sangoma_isdn

This commit is contained in:
David Yat Sin 2010-06-30 12:42:11 -04:00
parent 53761efdf6
commit c943e641d5
13 changed files with 5929 additions and 1 deletions

View File

@ -257,6 +257,25 @@ ftmod_sangoma_ss7_la_LDFLAGS = -module -avoid-version -lsng_ss7
ftmod_sangoma_ss7_la_LIBADD = $(MYLIB)
endif
if SNGISDN
ftmod_sangoma_isdn_la_SOURCES = $(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_in.c \
$(SRC)/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
ftmod_sangoma_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
ftmod_sangoma_isdn_la_LDFLAGS = -module -avoid-version -lsng_isdn
ftmod_sangoma_isdn_la_LIBADD = $(MYLIB)
endif
if OPENR2
ftmod_r2_la_SOURCES = $(SRC)/ftmod/ftmod_r2/ftmod_r2.c
ftmod_r2_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
@ -264,7 +283,6 @@ ftmod_r2_la_LDFLAGS = -module -avoid-version -lopenr2
ftmod_r2_la_LIBADD = $(MYLIB)
endif
dox doxygen:
cd docs && doxygen $(FT_SRCDIR)/docs/Doxygen.conf

View File

@ -173,6 +173,9 @@ AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"])
AC_CHECK_LIB([sng_ss7], [sng_isup_init], [have_sng_ss7="yes"])
AM_CONDITIONAL([SNGSS7],[test "${have_sng_ss7}" = "yes"])
AC_CHECK_LIB([sng_isdn], [sng_isdn_init], [have_sng_isdn="yes"])
AM_CONDITIONAL([SNGISDN],[test "${have_sng_isdn}" = "yes"])
AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [have_openr2="yes"])
AM_CONDITIONAL([OPENR2],[test "${have_openr2}" = "yes"])

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,259 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* Moises Silva <moy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __FTMOD_SNG_ISDN_H__
#define __FTMOD_SNG_ISDN_H__
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdint.h>
#include <unistd.h>
#include <ctype.h>
#include "private/ftdm_core.h"
#include <sng_isdn.h>
#define MAX_SPANS_PER_NFAS_LINK 8 /* TODO: Confirm this value */
#define NUM_E1_CHANNELS_PER_SPAN 32
#define NUM_T1_CHANNELS_PER_SPAN 24
#define NUM_BRI_CHANNELS_PER_SPAN 2
/* Should never have DEBUG_MODE defined when used in production */
#if 0
#undef DEBUG_MODE
#define FORCE_SEFGAULT
#else
#define DEBUG_MODE
#define FORCE_SEGFAULT *(int *) 0 = 0;
#endif
/* TODO: rename all *_cc_* to *_an_* */
typedef struct sngisdn_glare_data {
int16_t suId;
uint32_t suInstId;
uint32_t spInstId;
int16_t dChan;
ConEvnt setup;
uint8_t ces;
}sngisdn_glare_data_t;
/* Channel specific data */
typedef struct sngisdn_chan_data {
ftdm_channel_t *ftdmchan;
uint32_t flags;
uint8_t ces; /* not used for now */
uint8_t dchan_id;
uint32_t suInstId; /* instance ID generated locally */
uint32_t spInstId; /* instance ID generated by stack */
uint8_t globalFlg;
sngisdn_glare_data_t glare;
} sngisdn_chan_data_t;
/* Span specific data */
typedef struct sngisdn_span_data {
ftdm_span_t *ftdm_span;
uint8_t link_id;
uint8_t switchtype;
uint8_t signalling; /* SNGISDN_SIGNALING_CPE or SNGISDN_SIGNALING_NET */
uint8_t cc_id;
uint8_t dchan_id;
uint8_t span_id;
uint8_t tei;
uint8_t keep_link_up;
uint8_t trace_flags;
} sngisdn_span_data_t;
/* dchan_data can have more than 1 span when running NFAS */
typedef struct sngisdn_dchan_data {
uint8_t num_spans;
sngisdn_span_data_t *spans[MAX_L1_LINKS+1];
uint16_t num_chans;
/* worst case for number of channel is when using NFAS, and NFAS is only used on T1,
so we can use MAX_SPANS_PER_NFAS_LINK*NUM_T1_CHANNELS_PER_SPAN instead of
MAX_SPANS_PER_NFAS_LINK*NUM_E1_CHANNELS_PER_SPAN
*/
/* Never seen NFAS on E1 yet, so use NUM_T1_CHANNELS_PER_SPAN */
/* b-channels are arranged by physical id's not logical */
sngisdn_chan_data_t *channels[MAX_SPANS_PER_NFAS_LINK*NUM_T1_CHANNELS_PER_SPAN];
}sngisdn_dchan_data_t;
typedef struct sngisdn_cc {
/* TODO: use flags instead of config_done and activation_done */
uint8_t config_done;
uint8_t activation_done;
uint8_t switchtype;
ftdm_trunk_type_t trunktype;
uint32_t last_suInstId;
ftdm_mutex_t *request_mutex;
sngisdn_chan_data_t *active_spInstIds[MAX_INSTID];
sngisdn_chan_data_t *active_suInstIds[MAX_INSTID];
}sngisdn_cc_t;
/* Global sngisdn data */
typedef struct ftdm_sngisdn_data {
uint8_t gen_config_done;
uint8_t num_cc; /* 1 ent per switchtype */
struct sngisdn_cc ccs[MAX_VARIANTS+1];
uint8_t num_dchan;
sngisdn_dchan_data_t dchans[MAX_L1_LINKS+1];
}ftdm_sngisdn_data_t;
typedef enum {
FLAG_RESET_RX = (1 << 0),
FLAG_RESET_TX = (1 << 1),
FLAG_REMOTE_REL = (1 << 2),
FLAG_LOCAL_REL = (1 << 3),
FLAG_REMOTE_ABORT = (1 << 4),
FLAG_LOCAL_ABORT = (1 << 4),
FLAG_GLARE = (1 << 5),
FLAG_INFID_RESUME = (1 << 17),
FLAG_INFID_PAUSED = (1 << 18),
FLAG_CKT_MN_BLOCK_RX = (1 << 19),
FLAG_CKT_MN_BLOCK_TX = (1 << 20),
FLAG_CKT_MN_UNBLK_RX = (1 << 21),
FLAG_CKT_MN_UNBLK_TX = (1 << 22),
FLAG_GRP_HW_BLOCK_RX = (1 << 23),
FLAG_GRP_HW_BLOCK_TX = (1 << 24),
FLAG_GRP_MN_BLOCK_RX = (1 << 25),
FLAG_GRP_MN_BLOCK_TX = (1 << 28),
FLAG_GRP_HW_UNBLK_RX = (1 << 27),
FLAG_GRP_HW_UNBLK_TX = (1 << 28),
FLAG_GRP_MN_UNBLK_RX = (1 << 29),
FLAG_GRP_MN_UNBLK_TX = (1 << 30)
} sngisdn_flag_t;
typedef enum {
SNGISDN_SWITCH_INVALID = 0, /* invalid */
SNGISDN_SWITCH_NI2 , /* national isdn-2 */
SNGISDN_SWITCH_5ESS, /* att 5ess */
SNGISDN_SWITCH_4ESS, /* att 4ess */
SNGISDN_SWITCH_DMS100, /* nt dms100 */
SNGISDN_SWITCH_EUROISDN,/* etsi */
SNGISDN_SWITCH_QSIG, /* etsi qsig */
SNGISDN_SWITCH_INSNET, /* int - net */
} sngisdn_switchtype_t;
typedef enum {
SNGISDN_SIGNALING_INVALID = 0, /* invalid */
SNGISDN_SIGNALING_CPE , /* customer side emulation */
SNGISDN_SIGNALING_NET, /* network side emulation */
} sngisdn_signalingtype_t;
typedef enum {
SNGISDN_TRACE_DISABLE = 0,
SNGISDN_TRACE_Q921 = 1,
SNGISDN_TRACE_Q931 = 2,
} sngisdn_tracetype_t;
#define sngisdn_set_flag(obj, flag) ((obj)->flags |= (flag))
#define sngisdn_clear_flag(obj, flag) ((obj)->flags &= ~(flag))
#define sngisdn_test_flag(obj, flag) ((obj)->flags & flag)
#define sngisdn_set_trace_flag(obj, flag) ((obj)->trace_flags |= (flag))
#define sngisdn_clear_trace_flag(obj, flag) ((obj)->trace_flags &= ~(flag))
#define sngisdn_test_trace_flag(obj, flag) ((obj)->trace_flags & flag)
/* TODO implement these 2 functions */
#define ISDN_FUNC_TRACE_ENTER(a)
#define ISDN_FUNC_TRACE_EXIT(a)
/* Configuration functions */
ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span);
/* Support functions */
uint32_t get_unique_suInstId(uint8_t cc_id);
void clear_call_data(sngisdn_chan_data_t *sngisdn_info);
void stack_hdr_init(Header *hdr);
void stack_pst_init(Pst *pst);
ftdm_status_t get_ftdmchan_by_spInstId(uint8_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data);
ftdm_status_t get_ftdmchan_by_suInstId(uint8_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data);
ftdm_status_t check_for_state_change(ftdm_channel_t *ftdmchan);
/* Outbound Call Control functions */
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan);
void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan);
void sngisdn_snd_progress(ftdm_channel_t *ftdmchan);
void sngisdn_snd_alert(ftdm_channel_t *ftdmchan);
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_release(ftdm_channel_t *ftdmchan);
void sngisdn_snd_reset(ftdm_channel_t *ftdmchan);
void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan);
/* Inbound Call Control functions */
void sngisdn_rcv_con_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, signed short dChan, uint8_t ces);
void sngisdn_rcv_con_cfm (signed short suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, signed short dChan, uint8_t ces);
void sngisdn_rcv_cnst_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, uint8_t evntType, signed short dChan, uint8_t ces);
void sngisdn_rcv_disc_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, DiscEvnt *discEvnt);
void sngisdn_rcv_rel_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, RelEvnt *relEvnt);
void sngisdn_rcv_dat_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, InfoEvnt *infoEvnt);
void sngisdn_rcv_sshl_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action);
void sngisdn_rcv_sshl_cfm (signed short suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action);
void sngisdn_rcv_rmrt_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action);
void sngisdn_rcv_rmrt_cfm (signed short suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action);
void sngisdn_rcv_flc_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt);
void sngisdn_rcv_fac_ind (signed short suId, uint32_t suInstId, uint32_t spInstId, FacEvnt *facEvnt, uint8_t evntType, signed short dChan, uint8_t ces);
void sngisdn_rcv_sta_cfm ( signed short suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt);
void sngisdn_rcv_srv_ind ( signed short suId, Srv *srvEvnt, signed short dChan, uint8_t ces);
void sngisdn_rcv_srv_cfm ( signed short suId, Srv *srvEvnt, signed short dChan, uint8_t ces);
void sngisdn_rcv_rst_cfm ( signed short suId, Rst *rstEvnt, signed short dChan, uint8_t ces, uint8_t evtType);
void sngisdn_rcv_rst_ind ( signed short suId, Rst *rstEvnt, signed short dChan, uint8_t ces, uint8_t evtType);
void sngisdn_rcv_phy_ind(SuId suId, Reason reason);
void sngisdn_rcv_q921_ind(BdMngmt *status);
void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf);
void sngisdn_rcv_q931_ind(InMngmt *status);
void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf);
void sngisdn_rcv_cc_ind(CcMngmt *status);
void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...);
void handle_sng_log(uint8_t level, char *fmt,...);
void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status);
/* Stack management functions */
ftdm_status_t sng_isdn_stack_cfg(ftdm_span_t *span);
ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span);
#endif /* __FTMOD_SNG_ISDN_H__ */

View File

@ -0,0 +1,219 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "ftmod_sangoma_isdn.h"
ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span);
ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span);
extern ftdm_sngisdn_data_t g_sngisdn_data;
ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span)
{
unsigned i;
sngisdn_dchan_data_t *dchan_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
switch(span->trunk_type) {
case FTDM_TRUNK_T1:
if (!strcasecmp(switch_name, "ni2")) {
signal_data->switchtype = SNGISDN_SWITCH_NI2;
} else if (!strcasecmp(switch_name, "5ess")) {
signal_data->switchtype = SNGISDN_SWITCH_5ESS;
} else if (!strcasecmp(switch_name, "4ess")) {
signal_data->switchtype = SNGISDN_SWITCH_4ESS;
} else if (!strcasecmp(switch_name, "dms100")) {
signal_data->switchtype = SNGISDN_SWITCH_DMS100;
} else {
ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
return FTDM_FAIL;
}
break;
case FTDM_TRUNK_E1:
if (!strcasecmp(switch_name, "euroisdn") || strcasecmp(switch_name, "etsi")) {
signal_data->switchtype = SNGISDN_SWITCH_EUROISDN;
} else if (!strcasecmp(switch_name, "qsig")) {
signal_data->switchtype = SNGISDN_SWITCH_QSIG;
} else {
ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
return FTDM_FAIL;
}
break;
case FTDM_TRUNK_BRI:
case FTDM_TRUNK_BRI_PTMP:
if (!strcasecmp(switch_name, "euroisdn") ||
!strcasecmp(switch_name, "etsi")) {
signal_data->switchtype = SNGISDN_SWITCH_EUROISDN;
} else if (!strcasecmp(switch_name, "insnet") ||
!strcasecmp(switch_name, "ntt")) {
signal_data->switchtype = SNGISDN_SWITCH_INSNET;
} else {
ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
return FTDM_FAIL;
}
/* can be > 1 for some BRI variants */
break;
default:
ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
return FTDM_FAIL;
}
/* see if we have profile with this switch_type already */
for (i=1; i <= g_sngisdn_data.num_cc; i++) {
if (g_sngisdn_data.ccs[i].switchtype == signal_data->switchtype &&
g_sngisdn_data.ccs[i].trunktype == span->trunk_type) {
break;
}
}
/* need to create a new switch_type */
if (i > g_sngisdn_data.num_cc) {
g_sngisdn_data.num_cc++;
g_sngisdn_data.ccs[i].switchtype = signal_data->switchtype;
g_sngisdn_data.ccs[i].trunktype = span->trunk_type;
ftdm_log(FTDM_LOG_DEBUG, "%s: New switchtype:%s cc_id:%u\n", span->name, switch_name, i);
}
/* add this span to its ent_cc */
signal_data->cc_id = i;
/* create a new dchan */ /* for NFAS - no-dchan on b-channels only links */
g_sngisdn_data.num_dchan++;
signal_data->dchan_id = g_sngisdn_data.num_dchan;
dchan_data = &g_sngisdn_data.dchans[signal_data->dchan_id];
dchan_data->num_spans++;
signal_data->span_id = dchan_data->num_spans;
dchan_data->spans[signal_data->span_id] = signal_data;
ftdm_log(FTDM_LOG_DEBUG, "%s: cc_id:%d dchan_id:%d span_id:%d\n", span->name, signal_data->cc_id, signal_data->dchan_id, signal_data->span_id);
/* Add the channels to the span */
for (i=1;i<=span->chan_count;i++) {
unsigned chan_id;
ftdm_channel_t *ftdmchan = span->channels[i];
/* NFAS is not supported on E1, so span_id will always be 1 for E1 so this will work for E1 as well */
chan_id = ((signal_data->span_id-1)*NUM_T1_CHANNELS_PER_SPAN)+ftdmchan->physical_chan_id;
dchan_data->channels[chan_id] = (sngisdn_chan_data_t*)ftdmchan->call_data;
dchan_data->num_chans++;
}
return FTDM_SUCCESS;
}
ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
if (!strcasecmp(signalling, "net") ||
!strcasecmp(signalling, "pri_net")||
!strcasecmp(signalling, "bri_net")) {
signal_data->signalling = SNGISDN_SIGNALING_NET;
} else if (!strcasecmp(signalling, "cpe") ||
!strcasecmp(signalling, "pri_cpe")||
!strcasecmp(signalling, "bri_cpe")) {
signal_data->signalling = SNGISDN_SIGNALING_CPE;
} else {
ftdm_log(FTDM_LOG_ERROR, "Unsupported signalling %s\n", signalling);
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span)
{
unsigned paramindex;
const char *var, *val;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
/* Set defaults here */
signal_data->keep_link_up = 1;
signal_data->tei = 0;
for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
ftdm_log(FTDM_LOG_DEBUG, "Sangoma ISDN key=value, %s=%s\n", ftdm_parameters[paramindex].var, ftdm_parameters[paramindex].val);
var = ftdm_parameters[paramindex].var;
val = ftdm_parameters[paramindex].val;
if (!strcasecmp(var, "switchtype")) {
if (parse_switchtype(val, span) != FTDM_SUCCESS) {
return FTDM_FAIL;
}
} else if (!strcasecmp(var, "signalling")) {
if (parse_signalling(val, span) != FTDM_SUCCESS) {
return FTDM_FAIL;
}
} else if (!strcasecmp(var, "tei")) {
uint8_t tei = atoi(val);
if (tei > 127) {
ftdm_log(FTDM_LOG_ERROR, "Invalid TEI %d, valid values are (0-127)", tei);
return FTDM_FAIL;
}
signal_data->tei = tei;
} else if (!strcasecmp(var, "keep_link_up")) {
if (!strcasecmp(val, "yes")) {
signal_data->keep_link_up = 1;
} else if (!strcasecmp(val, "no")) {
signal_data->keep_link_up = 0;
} else {
ftdm_log(FTDM_LOG_ERROR, "Invalid keep_link_up value, valid values are (yes/no)");
return FTDM_FAIL;
}
} else {
ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var);
}
}
signal_data->link_id = span->span_id;
if (signal_data->switchtype == SNGISDN_SWITCH_INVALID) {
ftdm_log(FTDM_LOG_ERROR, "%s: switchtype not specified", span->name);
return FTDM_FAIL;
}
if (signal_data->signalling == SNGISDN_SIGNALING_INVALID) {
ftdm_log(FTDM_LOG_ERROR, "%s: signalling not specified", span->name);
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
/******************************************************************************/
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "ftmod_sangoma_isdn.h"
void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status);
void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
{
ftdm_sigmsg_t sig;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Signalling link status changed to %s\n", ftdm_signaling_status2str(status));
memset(&sig, 0, sizeof(sig));
sig.chan_id = ftdmchan->chan_id;
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
ftdm_span_send_signal(ftdmchan->span, &sig);
return;
}
void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status)
{
unsigned i;
/* TODO: use channel iterator once it is implemented */
for (i=1;i<=ftdmspan->chan_count;i++) {
sngisdn_set_chan_sig_status(ftdmspan->channels[i], status);
}
return;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
/******************************************************************************/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,316 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* Moises Silva <moy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ftmod_sangoma_isdn.h"
void stack_resp_hdr_init(Header *hdr);
ftdm_status_t sng_isdn_cntrl_phy(ftdm_span_t *span);
ftdm_status_t sng_isdn_cntrl_q921(ftdm_span_t *span);
ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span);
ftdm_status_t sng_isdn_cntrl_cc(ftdm_span_t *span);
ftdm_status_t sng_isdn_cntrl_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt);
ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span, uint8_t action, uint8_t subaction);
ftdm_status_t sng_isdn_cntrl_q921(ftdm_span_t *span, uint8_t action, uint8_t subaction);
extern ftdm_sngisdn_data_t g_sngisdn_data;
ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
if (sng_isdn_cntrl_q921(span) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q921\n", span->name);
return FTDM_FAIL;
}
ftdm_log(FTDM_LOG_DEBUG, "%s:Stack q921 activated\n", span->name);
if (!g_sngisdn_data.ccs[signal_data->cc_id].activation_done) {
g_sngisdn_data.ccs[signal_data->cc_id].activation_done = 1;
if (sng_isdn_cntrl_cc(span) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack CC\n", span->name);
return FTDM_FAIL;
}
ftdm_log(FTDM_LOG_DEBUG, "%s:Stack CC activated\n", span->name);
}
if (sng_isdn_cntrl_q931(span) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q931\n", span->name);
return FTDM_FAIL;
}
ftdm_log(FTDM_LOG_DEBUG, "%s:Stack q931 activated\n", span->name);
ftdm_log(FTDM_LOG_INFO, "%s:Stack activated\n",span->name);
return FTDM_SUCCESS;
}
ftdm_status_t sng_isdn_cntrl_phy(ftdm_span_t *span)
{
L1Mngmt cntrl;
Pst pst;
ftdm_log(FTDM_LOG_ERROR, "%s:PHY control not implemented\n", span->name);
return FTDM_SUCCESS;
/* TODO: phy cntrl not implemented yet */
sng_isdn_phy_cntrl(&pst, &cntrl);
return FTDM_SUCCESS;
}
ftdm_status_t sng_isdn_cntrl_q921(ftdm_span_t *span)
{
ftdm_status_t status;
status = sng_isdn_cntrl_q921(span, ABND_ENA, NOTUSED);
/* Try to find an alternative for this */
/* LAPD will call LdUiDatBndCfm before it received a LdLiMacBndCfm from L1,
so we need to give some time before activating q931, as q931 will send a
LdUiDatConReq when activated, and this requires the Mac SAP to be already
bound first */
if (status == FTDM_SUCCESS) {
ftdm_sleep(500);
}
return status;
}
ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span)
{
/* TODO: remove this function later, just call sng_isdn_cntrl_q931 directly */
return sng_isdn_cntrl_q931(span, ABND_ENA, SAELMNT);
}
ftdm_status_t sng_isdn_cntrl_cc(ftdm_span_t *span)
{
CcMngmt cntrl;;
Pst pst;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
/* initalize the post structure */
stack_pst_init(&pst);
/* insert the destination Entity */
pst.dstEnt = ENTCC;
/* initalize the control structure */
memset(&cntrl, 0, sizeof(cntrl));
/* initalize the control header */
stack_hdr_init(&cntrl.hdr);
cntrl.hdr.msgType = TCNTRL; /* configuration */
cntrl.hdr.entId.ent = ENTCC; /* entity */
cntrl.hdr.entId.inst = S_INST; /* instance */
cntrl.hdr.elmId.elmnt = STTSAP; /* physical sap */
cntrl.t.cntrl.action = ABND_ENA;
cntrl.t.cntrl.subAction = SAELMNT;
cntrl.t.cntrl.sapId = signal_data->cc_id;
if (sng_isdn_cc_cntrl(&pst, &cntrl)) {
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
ftdm_status_t sng_isdn_cntrl_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
switch (trace_opt) {
case SNGISDN_TRACE_DISABLE:
if (sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q921)) {
ftdm_log(FTDM_LOG_INFO, "s%d Disabling q921 trace\n", signal_data->link_id);
sngisdn_clear_trace_flag(signal_data, SNGISDN_TRACE_Q921);
if (sng_isdn_cntrl_q921(span, ADISIMM, SAELMNT) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "s%d Failed to disable q921 trace\n");
}
}
if (sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q931)) {
ftdm_log(FTDM_LOG_INFO, "s%d Disabling q931 trace\n", signal_data->link_id);
sngisdn_clear_trace_flag(signal_data, SNGISDN_TRACE_Q931);
if (sng_isdn_cntrl_q931(span, ADISIMM, SATRC) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "s%d Failed to disable q931 trace\n");
}
}
break;
case SNGISDN_TRACE_Q921:
if (!sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q921)) {
ftdm_log(FTDM_LOG_INFO, "s%d Enabling q921 trace\n", signal_data->link_id);
sngisdn_set_trace_flag(signal_data, SNGISDN_TRACE_Q921);
if (sng_isdn_cntrl_q921(span, AENA, SATRC) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "s%d Failed to enable q921 trace\n");
}
}
break;
case SNGISDN_TRACE_Q931:
if (!sngisdn_test_trace_flag(signal_data, SNGISDN_TRACE_Q931)) {
ftdm_log(FTDM_LOG_INFO, "s%d Enabling q931 trace\n", signal_data->link_id);
sngisdn_set_trace_flag(signal_data, SNGISDN_TRACE_Q931);
if (sng_isdn_cntrl_q931(span, AENA, SATRC) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "s%d Failed to enable q931 trace\n");
}
}
break;
}
return FTDM_SUCCESS;
}
ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span, uint8_t action, uint8_t subaction)
{
InMngmt cntrl;;
Pst pst;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
/* initalize the post structure */
stack_pst_init(&pst);
/* insert the destination Entity */
pst.dstEnt = ENTIN;
/* initalize the control structure */
memset(&cntrl, 0, sizeof(cntrl));
/* initalize the control header */
stack_hdr_init(&cntrl.hdr);
cntrl.hdr.msgType = TCNTRL; /* configuration */
cntrl.hdr.entId.ent = ENTIN; /* entity */
cntrl.hdr.entId.inst = S_INST; /* instance */
cntrl.hdr.elmId.elmnt = STDLSAP; /* physical sap */
cntrl.t.cntrl.action = action;
cntrl.t.cntrl.subAction = subaction;
if (action == AENA && subaction == SATRC) {
cntrl.t.cntrl.trcLen = -1; /* Trace the entire message buffer */
}
cntrl.t.cntrl.sapId = signal_data->link_id;
cntrl.t.cntrl.ces = 0;
if(sng_isdn_q931_cntrl(&pst, &cntrl)) {
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
ftdm_status_t sng_isdn_cntrl_q921(ftdm_span_t *span, uint8_t action, uint8_t subaction)
{
BdMngmt cntrl;
Pst pst;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
/* initalize the post structure */
stack_pst_init(&pst);
/* insert the destination Entity */
pst.dstEnt = ENTLD;
/* initalize the control structure */
memset(&cntrl, 0, sizeof(cntrl));
/* initalize the control header */
stack_hdr_init(&cntrl.hdr);
/* build control request */
cntrl.hdr.msgType = TCNTRL;
cntrl.hdr.entId.ent = ENTLD;
cntrl.hdr.entId.inst = S_INST;
#if (SMBD_LMINT3 || BD_LMINT3)
stack_resp_hdr_init(&cntrl.hdr);
#endif /* _LMINT3 */
cntrl.hdr.elmId.elmnt = STMSAP;
cntrl.t.cntrl.action = action;
cntrl.t.cntrl.subAction = subaction;
#if (SMBD_LMINT3 || BD_LMINT3)
cntrl.t.cntrl.lnkNmb = signal_data->link_id;
cntrl.t.cntrl.sapi = NOTUSED;
cntrl.t.cntrl.tei = NOTUSED;
#else /* _LMINT3 */
cntrl.hdr.elmId.elmntInst1 = signal_data->link_id;
cntrl.hdr.elmId.elmntInst2 = NOTUSED;
cntrl.hdr.elmId.elmntInst3 = NOTUSED;
#endif /* _LMINT3 */
cntrl.t.cntrl.logInt = NOTUSED;
cntrl.t.cntrl.trcLen = NOTUSED;
if (action == AENA && subaction == SATRC) {
cntrl.t.cntrl.trcLen = -1; /* Trace the entire message buffer */
}
SGetDateTime(&(cntrl.t.cntrl.dt));
if(sng_isdn_q921_cntrl(&pst, &cntrl)) {
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
void stack_resp_hdr_init(Header *hdr)
{
hdr->response.selector = 0;
hdr->response.mem.region = RTESPEC;
hdr->response.mem.pool = S_POOL;
hdr->response.prior = PRIOR0;
hdr->response.route = RTESPEC;
return;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
/******************************************************************************/

View File

@ -0,0 +1,935 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ftmod_sangoma_isdn.h"
extern ftdm_status_t cpy_calling_num_from_sngisdn(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb);
extern ftdm_status_t cpy_called_num_from_sngisdn(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb);
extern ftdm_status_t cpy_called_name_from_sngisdn(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb);
extern ftdm_status_t cpy_calling_name_from_sngisdn(ftdm_caller_data_t *ftdm, ConEvnt *conEvnt);
extern void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len);
extern void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len);
extern void get_memory_info(void);
extern ftdm_sngisdn_data_t g_sngisdn_data;
#define MAX_DECODE_STR_LEN 2000
/* Remote side transmit a SETUP */
void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
uint8_t bchan_no = 0;
sngisdn_chan_data_t *sngisdn_info;
ftdm_channel_t *ftdmchan;
/*sngisdn_span_data_t *span_info;*/
ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d dChan:%d ces:%d\n", __FUNCTION__, suId, suInstId, spInstId, dChan, ces);
ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n");
ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n");
ftdm_assert(g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] == NULL, "Con Ind on busy spInstId");
if (conEvnt->chanId.eh.pres != PRSNT_NODEF) {
/* TODO: Implement me */
ftdm_log(FTDM_LOG_ERROR, "Incoming call without Channel Id not supported yet\n");
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
if (conEvnt->chanId.chanNmbSlotMap.pres) {
bchan_no = conEvnt->chanId.chanNmbSlotMap.val[0];
} else if (conEvnt->chanId.infoChanSel.pres) {
bchan_no = conEvnt->chanId.infoChanSel.val;
}
if (!bchan_no) {
ftdm_log(FTDM_LOG_ERROR, "Failed to obtain b-channel number from SETUP message\n");
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
if (g_sngisdn_data.dchans[dChan].channels[bchan_no] == NULL) {
ftdm_log(FTDM_LOG_ERROR, "Incoming call on unconfigured b-channel:%d\n", bchan_no);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
sngisdn_info = g_sngisdn_data.dchans[dChan].channels[bchan_no];
ftdmchan = sngisdn_info->ftdmchan;
ftdm_mutex_lock(ftdmchan->mutex);
/* check if there is a pending state change, give it a bit to clear */
if (check_for_state_change(ftdmchan) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received SETUP\n");
switch (ftdmchan->state){
case FTDM_CHANNEL_STATE_DOWN: /* Proper state to receive a SETUP */
sngisdn_info->suInstId = get_unique_suInstId(suId);
sngisdn_info->spInstId = spInstId;
g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
g_sngisdn_data.ccs[suId].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info;
/* try to open the channel */
if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to open channel");
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_REL);
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE;
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
} else {
/* Fill in call information */
cpy_calling_num_from_sngisdn(&ftdmchan->caller_data, &conEvnt->cgPtyNmb);
cpy_called_num_from_sngisdn(&ftdmchan->caller_data, &conEvnt->cdPtyNmb);
cpy_calling_name_from_sngisdn(&ftdmchan->caller_data, conEvnt);
/* Get ani2 */
#if 0
/* TODO: confirm that this works in the field */
if (conEvnt->niOperSysAcc.eh.pres) {
if (conEvnt->niOperSysAcc.typeAcc.pres) {
ftdmchan->caller_data.aniII = (uint8_t)conEvnt->niOperSysAcc.typeAcc.val;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Received ANI: type of access:%x", conEvnt->niOperSysAcc.typeAcc.val);
}
if (conEvnt->niOperSysAcc.typeServ.pres) {
ftdmchan->caller_data.aniII = (uint8_t)conEvnt->niOperSysAcc.typeServ.val;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Received ANI: type of service:%x", conEvnt->niOperSysAcc.typeServ.val);
}
}
#endif
/* set the state of the channel to collecting...the rest is done by the chan monitor */
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
}
break;
case FTDM_CHANNEL_STATE_DIALING: /* glare */
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Received SETUP in DIALING state, glare, queueing incoming call\n");
/* the flag the channel as having a collision */
sngisdn_set_flag(sngisdn_info, FLAG_GLARE);
/* save the SETUP for processing once the channel has gone to DOWN */
memcpy(&sngisdn_info->glare.setup, conEvnt, sizeof(*conEvnt));
sngisdn_info->glare.suId = suId;
sngisdn_info->glare.suInstId = suInstId;
sngisdn_info->glare.spInstId = spInstId;
sngisdn_info->glare.dChan = dChan;
sngisdn_info->glare.ces = ces;
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received SETUP in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
break;
}
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
/* Remote side transmit a CONNECT or CONNECT ACK */
void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, int16_t dChan, uint8_t ces)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
sngisdn_chan_data_t *sngisdn_info;
ftdm_channel_t *ftdmchan;
ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d dChan:%d ces:%d\n", __FUNCTION__, suId, suInstId, spInstId, dChan, ces);
ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n");
ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n");
if (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
ftdmchan = (ftdm_channel_t*)sngisdn_info->ftdmchan;
if (!sngisdn_info->spInstId) {
sngisdn_info->spInstId = spInstId;
g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
}
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received CONNECT/CONNECT ACK\n");
ftdm_mutex_lock(ftdmchan->mutex);
/* check if there is a pending state change, give it a bit to clear */
if (check_for_state_change(ftdmchan) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
((sngisdn_span_data_t*)ftdmchan->span->signal_data)->signalling == SNGISDN_SIGNALING_NET) {
if(sngisdn_info->ces == CES_MNGMNT) {
/* We assign the call to the first TE */
sngisdn_info->ces = ces;
} else {
/* We already assigned this call, do nothing */
ftdm_mutex_unlock(ftdmchan->mutex);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call already assigned, ignoring connect\n");
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_DIALING:
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received CONNECT/CONNECT ACK in an invalid state (%s)\n",
ftdm_channel_state2str(ftdmchan->state));
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
break;
}
} else {
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_UP:
/* This is the only valid state we should get a CONNECT ACK on */
/* do nothing */
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
break;
}
}
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, uint8_t evntType, int16_t dChan, uint8_t ces)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
sngisdn_chan_data_t *sngisdn_info;
ftdm_channel_t *ftdmchan;
ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d dChan:%d ces:%d\n", __FUNCTION__, suId, suInstId, spInstId, dChan, ces);
ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n");
ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n");
if (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
if (!sngisdn_info->spInstId) {
sngisdn_info->spInstId = spInstId;
g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
}
ftdmchan = (ftdm_channel_t*)sngisdn_info->ftdmchan;
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Received %s\n",
(evntType == MI_ALERTING)?"ALERT":
(evntType == MI_CALLPROC)?"PROCEED":
(evntType == MI_PROGRESS)?"PROGRESS":"UNKNOWN");
ftdm_mutex_lock(ftdmchan->mutex);
/* check if there is a pending state change, give it a bit to clear */
if (check_for_state_change(ftdmchan) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_DIALING:
if (evntType == MI_PROGRESS) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
}
break;
case FTDM_CHANNEL_STATE_PROGRESS:
if (evntType == MI_PROGRESS) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
}
break;
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
/* Do nothing */
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received ALERT/PROCEED/PROGRESS in an invalid state (%s)\n",
ftdm_channel_state2str(ftdmchan->state));
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
break;
}
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, DiscEvnt *discEvnt)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
sngisdn_chan_data_t *sngisdn_info;
ftdm_channel_t *ftdmchan = NULL;
ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d\n", __FUNCTION__, suId, suInstId, spInstId);
ftdm_assert(spInstId != 0, "Received DISCONNECT with invalid id");
if (spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) {
ftdmchan = (ftdm_channel_t*)sngisdn_info->ftdmchan;
} else if (suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS) {
ftdmchan = (ftdm_channel_t*)sngisdn_info->ftdmchan;
} else {
ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
return;
}
if (!sngisdn_info->spInstId) {
sngisdn_info->spInstId = spInstId;
g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
}
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received DISCONNECT\n");
ftdm_mutex_lock(ftdmchan->mutex);
/* check if there is a pending state change, give it a bit to clear */
if (check_for_state_change(ftdmchan) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_RING:
case FTDM_CHANNEL_STATE_DIALING:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_COLLECT:
case FTDM_CHANNEL_STATE_UP:
if (discEvnt->causeDgn[0].eh.pres && discEvnt->causeDgn[0].causeVal.pres) {
ftdmchan->caller_data.hangup_cause = discEvnt->causeDgn[0].causeVal.val;
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "DISCONNECT did not have a cause code\n");
ftdmchan->caller_data.hangup_cause = 0;
}
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_REL);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received DISCONNECT in an invalid state (%s)\n",
ftdm_channel_state2str(ftdmchan->state));
/* start reset procedure */
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
break;
}
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_rel_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RelEvnt *relEvnt)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d\n", __FUNCTION__, suId, suInstId, spInstId);
sngisdn_chan_data_t *sngisdn_info ;
ftdm_channel_t *ftdmchan = NULL;
/* get the ftdmchan and ss7_chan_data from the circuit */
if (suInstId && (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) {
ftdmchan = sngisdn_info->ftdmchan;
} else if (spInstId && (get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS)) {
ftdmchan = sngisdn_info->ftdmchan;
}
if (ftdmchan == NULL) {
ftdm_log(FTDM_LOG_CRIT, "Failed to find matching channel suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received RELEASE/RELEASE COMPLETE\n");
/* now that we have the right channel...put a lock on it so no-one else can use it */
ftdm_mutex_lock(ftdmchan->mutex);
/* check if there is a pending state change, give it a bit to clear */
if (check_for_state_change(ftdmchan)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
};
/* check whether the ftdm channel is in a state to accept a call */
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
/* go to DOWN */
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
break;
case FTDM_CHANNEL_STATE_DOWN:
/* do nothing, just drop the message */
break;
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
/* Remote side sent a SETUP, then a RELEASE COMPLETE to abort call - this is an abort */
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
break;
case FTDM_CHANNEL_STATE_DIALING:
/* Remote side rejected our SETUP message on outbound call */
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
break;
case FTDM_CHANNEL_STATE_UP:
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
break;
default:
/* Should just stop the call...but a reset is easier for now (since it does hangup the call) */
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received RELEASE in an invalid state (%s)\n",
ftdm_channel_state2str(ftdmchan->state));
/* go to RESTART */
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
break;
/**************************************************************************/
}
/* unlock the channel */
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_dat_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, InfoEvnt *infoEvnt)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received DATA IND suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_sshl_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received SSHL IND suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received SSHL CFM suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received RESUME/RETRIEVE ind suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received RESUME/RETRIEVE CFM suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received FLOW CONTROL IND suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_fac_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, FacEvnt *facEvnt, uint8_t evntType, int16_t dChan, uint8_t ces)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received FACILITY IND suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_sta_cfm ( int16_t suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_DEBUG, "%s suId:%d suInstId:%d spInstId:%d\n", __FUNCTION__, suId, suInstId, spInstId);
sngisdn_chan_data_t *sngisdn_info ;
ftdm_channel_t *ftdmchan = NULL;
uint8_t call_state = 0;
if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) {
call_state = staEvnt->callSte.callGlblSte.val;
}
/* get the ftdmchan and ss7_chan_data from the circuit */
if (suInstId && (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) {
ftdmchan = sngisdn_info->ftdmchan;
} else if (spInstId && (get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS)) {
ftdmchan = sngisdn_info->ftdmchan;
}
if (ftdmchan == NULL) {
ftdm_log(FTDM_LOG_CRIT, "Failed to find matching channel suId:%d suInstId:%d spInstId:%d\n", suId, suInstId, spInstId);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received STATUS CONFIRM\n");
/* now that we have the right channel...put a lock on it so no-one else can use it */
ftdm_mutex_lock(ftdmchan->mutex);
/* check if there is a pending state change, give it a bit to clear */
if (check_for_state_change(ftdmchan)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to wait for pending state change\n");
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
};
if (staEvnt->causeDgn[0].eh.pres && staEvnt->causeDgn[0].causeVal.pres) {
if (staEvnt->causeDgn[0].causeVal.val != 30) {
if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) {
call_state = staEvnt->callSte.callGlblSte.val;
/* Section 4.3.30 from INT Interface - Service Definition */
ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val;
/* There is incompatibility between local and remote side call states some Q931 msgs probably got lost - initiate disconnect */
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Incompatible call states detected, remote side indicated state:%d our state:%s cause:%d\n", call_state, ftdm_channel_state2str(ftdmchan->state), staEvnt->causeDgn[0].causeVal.val);
switch(call_state) {
/* Sere ITU-T Q931 for definition of call states */
case 0: /* Remote switch thinks there are no calls on this channel */
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_COLLECT:
case FTDM_CHANNEL_STATE_DIALING:
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
break;
case FTDM_CHANNEL_STATE_TERMINATING:
/* We are in the process of clearing local states,
just make sure we will not send any messages to remote switch */
sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
break;
case FTDM_CHANNEL_STATE_HANGUP:
/* This cannot happen, state_advance always sets
ftdmchan to STATE_HANGUP_COMPLETE when in STATE_HANGUP
and we called check_for_state_change earlier so something is very wrong here!!! */
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "How can we we in FTDM_CHANNEL_STATE_HANGUP after checking for state change?\n");
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
/* We were waiting for remote switch to send RELEASE COMPLETE
but this will not happen, so just clear local state */
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
break;
case FTDM_CHANNEL_STATE_DOWN:
/* If our local state is down as well, then there is nothing to do */
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
break;
}
break;
case 8: /* Remote switch is in "Connect Request state" */
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_UP:
/* This is ok. We sent a Connect, and we are waiting for a connect ack */
/* Do nothing */
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
/* We hung up locally, but remote switch doesn't know send disconnect again*/
sngisdn_snd_disconnect(ftdmchan);
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
break;
}
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
break;
}
} else {
ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val;
/* We could not extract the call state */
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Incompatible call states detected, but could not determine call (cause:%d)\n", ftdmchan->caller_data.hangup_cause);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
}
}
/**************************************************************************/
}
/* unlock the channel */
ftdm_mutex_unlock(ftdmchan->mutex);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_srv_ind ( int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received SERVICE IND suId:%d dChan:%d ces:%d\n", suId, dChan, ces);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_srv_cfm ( int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received SERVICE CFM suId:%d dChan:%d ces:%d\n", suId, dChan, ces);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evtType)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received RESTART IND suId:%d dChan:%d ces:%d\n", suId, dChan, ces);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_rst_cfm ( int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evtType)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "Received RESTART CFM suId:%d dChan:%d ces:%d\n", suId, dChan, ces);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_phy_ind(SuId suId, Reason reason)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "[SNGISDN PHY] D-chan %d : %s\n", suId, DECODE_LL1_REASON(reason));
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_q921_ind(BdMngmt *status)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
unsigned j,k;
ftdm_span_t *ftdmspan = NULL;
for(j=1;j<=g_sngisdn_data.num_dchan;j++) {
for(k=1;k<=g_sngisdn_data.dchans[j].num_spans;k++) {
if (g_sngisdn_data.dchans[j].spans[k]->link_id == status->t.usta.lnkNmb) {
ftdmspan = (ftdm_span_t*)g_sngisdn_data.dchans[j].spans[k]->ftdm_span;
}
}
}
if (ftdmspan == NULL) {
ftdm_log(FTDM_LOG_CRIT, "Received q921 status on unconfigured span\n", status->t.usta.lnkNmb);
#ifdef DEBUG_MODE
FORCE_SEGFAULT
#endif
return;
}
switch (status->t.usta.alarm.category) {
case (LCM_CATEGORY_INTERFACE):
ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
ftdmspan->name,
DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
break;
default:
ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
ftdmspan->name,
DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
break;
}
ISDN_FUNC_TRACE_EXIT(__FUNCTION__)
return;
}
void sngisdn_rcv_q931_ind(InMngmt *status)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_span_t *ftdmspan = NULL;
if (status->t.usta.alarm.cause == 287) {
get_memory_info();
return;
}
switch (status->t.usta.alarm.category) {
case (LCM_CATEGORY_INTERFACE):
ftdm_log(FTDM_LOG_WARNING, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n",
status->t.usta.suId,
DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
/* clean this up later */
switch (status->t.usta.alarm.event) {
case LCM_EVENT_UP:
case LCM_EVENT_DOWN:
{
unsigned j,k;
for(j=1;j<=g_sngisdn_data.num_dchan;j++) {
for(k=1;k<=g_sngisdn_data.dchans[j].num_spans;k++) {
if (g_sngisdn_data.dchans[j].spans[k]->link_id == status->t.usta.suId) {
ftdmspan = (ftdm_span_t*)g_sngisdn_data.dchans[j].spans[k]->ftdm_span;
}
}
}
if (ftdmspan == NULL) {
ftdm_log(FTDM_LOG_CRIT, "Received q931 LCM EVENT on unconfigured span (suId:%d)\n", status->t.usta.suId);
return;
}
sngisdn_set_span_sig_status(ftdmspan, (status->t.usta.alarm.event == LCM_EVENT_UP)?FTDM_SIG_STATE_UP:FTDM_SIG_STATE_DOWN);
}
break;
}
break;
default:
ftdm_log(FTDM_LOG_DEBUG, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n",
status->t.usta.suId,
DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
break;
}
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
void sngisdn_rcv_cc_ind(CcMngmt *status)
{
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_log(FTDM_LOG_INFO, "RECEIVED %s\n", __FUNCTION__);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
#define Q931_TRC_EVENT(event) (event == TL3PKTTX)?"TX": \
(event == TL3PKTRX)?"RX":"UNKNOWN"
void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf)
{
MsgLen mlen;
MsgLen i;
int16_t j;
Buffer *tmp;
Data *cptr;
uint8_t data;
uint8_t tdata[1000];
char *data_str = ftdm_calloc(1,MAX_DECODE_STR_LEN); /* TODO Find a proper size */
ftdm_assert(mBuf != NULLP, "Received a Q931 trace with no buffer");
mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len;
if (mlen != 0) {
tmp = mBuf->b_cont;
cptr = tmp->b_rptr;
data = *cptr++;
i = 0;
for(j=0;j<mlen;j++) {
tdata[j]= data;
if (cptr == tmp->b_wptr) {
tmp = tmp->b_cont;
if (tmp) cptr = tmp->b_rptr;
}
data = *cptr++;
}
sngisdn_trace_q931(data_str, tdata, mlen);
ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] FRAME %s:%s\n", Q931_TRC_EVENT(trc->t.trc.evnt), data_str);
}
ftdm_safe_free(data_str);
/* We do not need to free mBuf in this case because stack does it */
/* SPutMsg(mBuf); */
return;
}
#define Q921_TRC_EVENT(event) (event == TL2FRMRX)?"RX": \
(event == TL2FRMTX)?"TX": \
(event == TL2TMR)?"TMR EXPIRED":"UNKNOWN"
void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf)
{
MsgLen mlen;
MsgLen i;
int16_t j;
Buffer *tmp;
Data *cptr;
uint8_t data;
uint8_t tdata[16];
char *data_str = ftdm_calloc(1,200); /* TODO Find a proper size */
if (trc->t.trc.evnt == TL2TMR) {
goto end_of_trace;
}
ftdm_assert(mBuf != NULLP, "Received a Q921 trace with no buffer");
mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len;
if (mlen != 0) {
tmp = mBuf->b_cont;
cptr = tmp->b_rptr;
data = *cptr++;
i = 0;
while (i < mlen) {
j = 0;
for(j=0;j<16;j++) {
if (i<mlen) {
tdata[j]= data;
if (cptr == tmp->b_wptr) {
tmp = tmp->b_cont;
if (tmp) cptr = tmp->b_rptr;
}
i++;
if (i<mlen) data = *cptr++;
}
}
}
sngisdn_trace_q921(data_str, tdata, mlen);
ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] FRAME %s:%s\n", Q921_TRC_EVENT(trc->t.trc.evnt), data_str);
}
end_of_trace:
ftdm_safe_free(data_str);
SPutMsg(mBuf);
return;
}
void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...)
{
char *data;
int ret;
va_list ap;
va_start(ap, fmt);
ret = ftdm_vasprintf(&data, fmt, ap);
if (ret == -1) {
return;
}
switch (level) {
case SNG_LOGLEVEL_DEBUG:
ftdm_log(FTDM_LOG_DEBUG, "sng_isdn->%s", data);
break;
case SNG_LOGLEVEL_WARN:
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
break;
case SNG_LOGLEVEL_INFO:
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
break;
case SNG_LOGLEVEL_STATS:
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
break;
case SNG_LOGLEVEL_ERROR:
ftdm_log(FTDM_LOG_ERROR, "sng_isdn->%s", data);
#ifdef DEBUG_MODE
FORCE_SEGFAULT
#endif
break;
case SNG_LOGLEVEL_CRIT:
ftdm_log(FTDM_LOG_CRIT, "sng_isdn->%s", data);
#ifdef DEBUG_MODE
FORCE_SEGFAULT
#endif
break;
default:
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
break;
}
return;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
/******************************************************************************/

View File

@ -0,0 +1,433 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ftmod_sangoma_isdn.h"
extern ftdm_status_t cpy_calling_num_to_sngisdn(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm);
extern ftdm_status_t cpy_called_num_to_sngisdn(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm);
extern ftdm_status_t cpy_calling_name_to_sngisdn(ConEvnt *conEvnt, ftdm_channel_t *ftdmchan);
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan);
void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan);
void sngisdn_snd_progress(ftdm_channel_t *ftdmchan);
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_release(ftdm_channel_t *ftdmchan);
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
{
ConEvnt conEvnt;
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending SETUP\n");
sngisdn_info->suInstId = get_unique_suInstId(signal_data->cc_id);
sngisdn_info->spInstId = 0;
memset(&conEvnt, 0, sizeof(conEvnt));
conEvnt.bearCap[0].eh.pres = PRSNT_NODEF;
conEvnt.bearCap[0].infoTranCap.pres = PRSNT_NODEF;
conEvnt.bearCap[0].infoTranCap.val = IN_ITC_SPEECH;
conEvnt.bearCap[0].codeStand0.pres = PRSNT_NODEF;
conEvnt.bearCap[0].codeStand0.val = IN_CSTD_CCITT;
conEvnt.bearCap[0].infoTranRate0.pres = PRSNT_NODEF;
conEvnt.bearCap[0].infoTranRate0.val = IN_ITR_64KBIT;
conEvnt.bearCap[0].tranMode.pres = PRSNT_NODEF;
conEvnt.bearCap[0].tranMode.val = IN_TM_CIRCUIT;
conEvnt.chanId.eh.pres = PRSNT_NODEF;
conEvnt.chanId.prefExc.pres = PRSNT_NODEF;
conEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
conEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
conEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
conEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
conEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
conEvnt.chanId.intIdent.pres = NOTPRSNT;
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
/* Trillium stack rejests lyr1Ident on BRI, but Netbricks always sends it.
Check with Trillium if this ever causes calls to fail in the field */
/* BRI only params */
conEvnt.chanId.intType.pres = PRSNT_NODEF;
conEvnt.chanId.intType.val = IN_IT_BASIC;
conEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
conEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
} else {
/* PRI only params */
if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
conEvnt.bearCap[0].usrInfoLyr1Prot.pres = PRSNT_NODEF;
conEvnt.bearCap[0].usrInfoLyr1Prot.val = IN_UIL1_G711ULAW;
} else {
conEvnt.bearCap[0].usrInfoLyr1Prot.pres = PRSNT_NODEF;
conEvnt.bearCap[0].usrInfoLyr1Prot.val = IN_UIL1_G711ALAW;
}
conEvnt.bearCap[0].lyr1Ident.pres = PRSNT_NODEF;
conEvnt.bearCap[0].lyr1Ident.val = IN_L1_IDENT;
conEvnt.chanId.intType.pres = PRSNT_NODEF;
conEvnt.chanId.intType.val = IN_IT_OTHER;
conEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
conEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
conEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
conEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
conEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
conEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
conEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
conEvnt.chanId.chanNmbSlotMap.len = 1;
conEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
}
conEvnt.progInd.eh.pres = PRSNT_NODEF;
conEvnt.progInd.location.pres = PRSNT_NODEF;
conEvnt.progInd.location.val = IN_LOC_USER;
conEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
conEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
conEvnt.progInd.progDesc.pres = PRSNT_NODEF;
conEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN; /* Not end-to-end ISDN */
if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
conEvnt.sndCmplt.eh.pres = PRSNT_NODEF;
}
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
signal_data->signalling == SNGISDN_SIGNALING_NET) {
sngisdn_info->ces = CES_MNGMNT;
}
cpy_calling_num_to_sngisdn(&conEvnt.cgPtyNmb, &ftdmchan->caller_data);
cpy_called_num_to_sngisdn(&conEvnt.cdPtyNmb, &ftdmchan->caller_data);
cpy_calling_name_to_sngisdn(&conEvnt, ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con request on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if (sng_isdn_con_request(signal_data->cc_id, sngisdn_info->suInstId, &conEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused SETUP request\n");
}
return;
}
/* Used only for BRI PTMP */
void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT ACK\n");
cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
/* BRI only params */
cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
cnStEvnt.chanId.intType.val = IN_IT_BASIC;
cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
} else {
cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
cnStEvnt.chanId.intType.val = IN_IT_OTHER;
cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
cnStEvnt.chanId.chanNmbSlotMap.len = 1;
cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
}
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending connect ACK on suId:%d suInstId:%u spInstId:%u ces:%d\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_info->ces);
if(sng_isdn_con_comp(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused CONNECT ACK request\n");
}
return;
}
void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED\n");
cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
/* BRI only params */
cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
cnStEvnt.chanId.intType.val = IN_IT_BASIC;
cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
} else {
cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
cnStEvnt.chanId.intType.val = IN_IT_OTHER;
cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
cnStEvnt.chanId.chanNmbSlotMap.len = 1;
cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
}
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con status on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, MI_CALLPROC, signal_data->dchan_id, sngisdn_info->ces)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused PROCEED request\n");
}
return;
}
void sngisdn_snd_progress(ftdm_channel_t *ftdmchan)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS\n");
cnStEvnt.progInd.eh.pres = PRSNT_NODEF;
cnStEvnt.progInd.location.pres = PRSNT_NODEF;
cnStEvnt.progInd.location.val = IN_LOC_USER;
cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
cnStEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con status on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, signal_data->dchan_id, sngisdn_info->ces)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused PROGRESS request\n");
}
return;
}
void sngisdn_snd_alert(ftdm_channel_t *ftdmchan)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending ALERT\n");
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
cnStEvnt.progInd.eh.pres = PRSNT_NODEF;
cnStEvnt.progInd.location.pres = PRSNT_NODEF;
cnStEvnt.progInd.location.val = IN_LOC_USER;
cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
cnStEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con status on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_ALERTING, signal_data->dchan_id, sngisdn_info->ces)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused ALERT request\n");
}
return;
}
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT\n");
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
/* BRI only params */
cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
cnStEvnt.chanId.intType.val = IN_IT_BASIC;
cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
} else {
cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
cnStEvnt.chanId.intType.val = IN_IT_OTHER;
cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
cnStEvnt.chanId.chanNmbSlotMap.len = 1;
cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
}
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending con response on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused CONNECT request\n");
}
return;
}
void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan)
{
DiscEvnt discEvnt;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending DISCONNECT\n");
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
memset(&discEvnt, 0, sizeof(discEvnt));
/* Fill discEvnt here */
discEvnt.causeDgn[0].eh.pres = PRSNT_NODEF;
discEvnt.causeDgn[0].location.pres = PRSNT_NODEF;
discEvnt.causeDgn[0].location.val = IN_LOC_PRIVNETLU;
discEvnt.causeDgn[0].codeStand3.pres = PRSNT_NODEF;
discEvnt.causeDgn[0].codeStand3.val = IN_CSTD_CCITT;
discEvnt.causeDgn[0].causeVal.pres = PRSNT_NODEF;
discEvnt.causeDgn[0].causeVal.val = ftdmchan->caller_data.hangup_cause;
discEvnt.causeDgn[0].recommend.pres = NOTPRSNT;
discEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending disc request on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused DISCONNECT request\n");
}
return;
}
void sngisdn_snd_release(ftdm_channel_t *ftdmchan)
{
RelEvnt relEvnt;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending RELEASE/RELEASE COMPLETE\n");
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
memset(&relEvnt, 0, sizeof(relEvnt));
/* Fill discEvnt here */
relEvnt.causeDgn[0].eh.pres = PRSNT_NODEF;
relEvnt.causeDgn[0].location.pres = PRSNT_NODEF;
relEvnt.causeDgn[0].location.val = IN_LOC_PRIVNETLU;
relEvnt.causeDgn[0].codeStand3.pres = PRSNT_NODEF;
relEvnt.causeDgn[0].codeStand3.val = IN_CSTD_CCITT;
relEvnt.causeDgn[0].causeVal.pres = PRSNT_NODEF;
relEvnt.causeDgn[0].causeVal.val = ftdmchan->caller_data.hangup_cause;
relEvnt.causeDgn[0].recommend.pres = NOTPRSNT;
relEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending release request on suId:%d suInstId:%u spInstId:%u\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if (sng_isdn_release_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &relEvnt)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused RELEASE/RELEASE COMPLETE request\n");
}
return;
}
void sngisdn_snd_reset(ftdm_channel_t *ftdmchan)
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending RESET\n");
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "%s not implemented\n", __FUNCTION__);
/* TODO: implement me */
return;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
/******************************************************************************/

View File

@ -0,0 +1,353 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ftmod_sangoma_isdn.h"
ftdm_status_t cpy_calling_num_from_sngisdn(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb);
ftdm_status_t cpy_called_num_from_sngisdn(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb);
ftdm_status_t cpy_redir_num_from_sngisdn(ftdm_caller_data_t *ftdm, RedirNmb *redirNmb);
ftdm_status_t cpy_calling_name_from_sngisdn(ftdm_caller_data_t *ftdm, ConEvnt *conEvnt);
ftdm_status_t cpy_calling_num_to_sngisdn(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm);
ftdm_status_t cpy_called_num_to_sngisdn(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm);
ftdm_status_t cpy_redir_num_to_sngisdn(RedirNmb *redirNmb, ftdm_caller_data_t *ftdm);
ftdm_status_t cpy_calling_name_to_sngisdn(ConEvnt *conEvnt, ftdm_channel_t *ftdmchan);
extern ftdm_sngisdn_data_t g_sngisdn_data;
void get_memory_info(void);
void clear_call_data(sngisdn_chan_data_t *sngisdn_info)
{
uint32_t cc_id = ((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->cc_id;
g_sngisdn_data.ccs[cc_id].active_spInstIds[sngisdn_info->spInstId]=NULL;
g_sngisdn_data.ccs[cc_id].active_suInstIds[sngisdn_info->suInstId]=NULL;
sngisdn_info->suInstId = 0;
sngisdn_info->spInstId = 0;
sngisdn_info->globalFlg = 0;
sngisdn_info->flags = 0;
return;
}
uint32_t get_unique_suInstId(uint8_t cc_id)
{
uint32_t suInstId;
ftdm_mutex_lock(g_sngisdn_data.ccs[cc_id].request_mutex);
suInstId = g_sngisdn_data.ccs[cc_id].last_suInstId;
while(1) {
if (++suInstId == MAX_INSTID) {
suInstId = 1;
}
if (g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId] == NULL) {
g_sngisdn_data.ccs[cc_id].last_suInstId = suInstId;
ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].request_mutex);
return suInstId;
}
}
/* Should never reach here */
ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].request_mutex);
return 0;
}
ftdm_status_t get_ftdmchan_by_suInstId(uint8_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data)
{
ftdm_assert_return(g_sngisdn_data.ccs[cc_id].activation_done, FTDM_FAIL, "Trying to find call on unconfigured CC\n");
if (g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId] == NULL) {
return FTDM_FAIL;
}
*sngisdn_data = g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId];
return FTDM_SUCCESS;
}
ftdm_status_t get_ftdmchan_by_spInstId(uint8_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data)
{
ftdm_assert_return(g_sngisdn_data.ccs[cc_id].activation_done, FTDM_FAIL, "Trying to find call on unconfigured CC\n");
if (g_sngisdn_data.ccs[cc_id].active_spInstIds[spInstId] == NULL) {
return FTDM_FAIL;
}
*sngisdn_data = g_sngisdn_data.ccs[cc_id].active_spInstIds[spInstId];
return FTDM_SUCCESS;
}
ftdm_status_t cpy_calling_num_from_sngisdn(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb)
{
if (cgPtyNmb->eh.pres != PRSNT_NODEF) {
return FTDM_FAIL;
}
if (cgPtyNmb->screenInd.pres == PRSNT_NODEF) {
ftdm->screen = cgPtyNmb->screenInd.val;
}
if (cgPtyNmb->presInd0.pres == PRSNT_NODEF) {
ftdm->pres = cgPtyNmb->presInd0.val;
}
if (cgPtyNmb->nmbPlanId.pres == PRSNT_NODEF) {
ftdm->cid_num.plan = cgPtyNmb->nmbPlanId.val;
}
if (cgPtyNmb->typeNmb1.pres == PRSNT_NODEF) {
ftdm->cid_num.type = cgPtyNmb->typeNmb1.val;
}
if (cgPtyNmb->nmbDigits.pres == PRSNT_NODEF) {
ftdm_copy_string(ftdm->cid_num.digits, (const char*)cgPtyNmb->nmbDigits.val, cgPtyNmb->nmbDigits.len+1);
}
return FTDM_SUCCESS;
}
ftdm_status_t cpy_called_num_from_sngisdn(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb)
{
if (cdPtyNmb->eh.pres != PRSNT_NODEF) {
return FTDM_FAIL;
}
if (cdPtyNmb->nmbPlanId.pres == PRSNT_NODEF) {
ftdm->cid_num.plan = cdPtyNmb->nmbPlanId.val;
}
if (cdPtyNmb->typeNmb0.pres == PRSNT_NODEF) {
ftdm->cid_num.type = cdPtyNmb->typeNmb0.val;
}
if (cdPtyNmb->nmbDigits.pres == PRSNT_NODEF) {
ftdm_copy_string(ftdm->dnis.digits, (const char*)cdPtyNmb->nmbDigits.val, cdPtyNmb->nmbDigits.len+1);
}
return FTDM_SUCCESS;
}
ftdm_status_t cpy_redir_num_from_sngisdn(ftdm_caller_data_t *ftdm, RedirNmb *redirNmb)
{
if (redirNmb->eh.pres != PRSNT_NODEF) {
return FTDM_FAIL;
}
if (redirNmb->nmbPlanId.pres == PRSNT_NODEF) {
ftdm->rdnis.plan = redirNmb->nmbPlanId.val;
}
if (redirNmb->typeNmb.pres == PRSNT_NODEF) {
ftdm->rdnis.type = redirNmb->typeNmb.val;
}
if (redirNmb->nmbDigits.pres == PRSNT_NODEF) {
ftdm_copy_string(ftdm->rdnis.digits, (const char*)redirNmb->nmbDigits.val, redirNmb->nmbDigits.len+1);
}
return FTDM_SUCCESS;
}
ftdm_status_t cpy_calling_name_from_sngisdn(ftdm_caller_data_t *ftdm, ConEvnt *conEvnt)
{
if (conEvnt->display.eh.pres && conEvnt->display.dispInfo.pres == PRSNT_NODEF) {
ftdm_copy_string(ftdm->cid_name, (const char*)conEvnt->display.dispInfo.val, conEvnt->display.dispInfo.len+1);
}
/* TODO check if caller name is contained in a Facility IE */
return FTDM_SUCCESS;
}
ftdm_status_t cpy_calling_num_to_sngisdn(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm)
{
uint8_t len = strlen(ftdm->cid_num.digits);
if (!len) {
return FTDM_SUCCESS;
}
cgPtyNmb->eh.pres = PRSNT_NODEF;
cgPtyNmb->screenInd.pres = PRSNT_NODEF;
cgPtyNmb->screenInd.val = ftdm->screen;
cgPtyNmb->presInd0.pres = PRSNT_NODEF;
cgPtyNmb->presInd0.val = ftdm->pres;
cgPtyNmb->nmbPlanId.pres = PRSNT_NODEF;
cgPtyNmb->nmbPlanId.val = ftdm->cid_num.plan;
cgPtyNmb->typeNmb1.pres = PRSNT_NODEF;
cgPtyNmb->typeNmb1.val = ftdm->cid_num.type;
cgPtyNmb->nmbDigits.pres = PRSNT_NODEF;
cgPtyNmb->nmbDigits.len = len;
memcpy(cgPtyNmb->nmbDigits.val, ftdm->cid_num.digits, len);
return FTDM_SUCCESS;
}
ftdm_status_t cpy_called_num_to_sngisdn(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm)
{
uint8_t len = strlen(ftdm->dnis.digits);
if (!len) {
return FTDM_SUCCESS;
}
cdPtyNmb->eh.pres = PRSNT_NODEF;
cdPtyNmb->nmbPlanId.pres = PRSNT_NODEF;
cdPtyNmb->nmbPlanId.val = ftdm->dnis.plan;
cdPtyNmb->typeNmb0.pres = PRSNT_NODEF;
cdPtyNmb->typeNmb0.val = ftdm->dnis.type;
cdPtyNmb->nmbDigits.pres = PRSNT_NODEF;
cdPtyNmb->nmbDigits.len = len;
memcpy(cdPtyNmb->nmbDigits.val, ftdm->dnis.digits, len);
return FTDM_SUCCESS;
}
ftdm_status_t cpy_redir_num_to_sngisdn(RedirNmb *redirNmb, ftdm_caller_data_t *ftdm)
{
uint8_t len = strlen(ftdm->rdnis.digits);
if (!len) {
return FTDM_SUCCESS;
}
redirNmb->eh.pres = PRSNT_NODEF;
redirNmb->nmbPlanId.pres = PRSNT_NODEF;
redirNmb->nmbPlanId.val = ftdm->rdnis.plan;
redirNmb->typeNmb.pres = PRSNT_NODEF;
redirNmb->typeNmb.val = ftdm->rdnis.type;
redirNmb->nmbDigits.pres = PRSNT_NODEF;
redirNmb->nmbDigits.len = len;
memcpy(redirNmb->nmbDigits.val, ftdm->rdnis.digits, len);
return FTDM_SUCCESS;
}
ftdm_status_t cpy_calling_name_to_sngisdn(ConEvnt *conEvnt, ftdm_channel_t *ftdmchan)
{
uint8_t len;
ftdm_caller_data_t *ftdm = &ftdmchan->caller_data;
/* sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; */
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
len = strlen(ftdm->cid_name);
if (!len) {
return FTDM_SUCCESS;
}
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
conEvnt->usrUsr.eh.pres = PRSNT_NODEF;
conEvnt->usrUsr.protocolDisc.pres = PRSNT_NODEF;
conEvnt->usrUsr.protocolDisc.val = PD_IA5; /* IA5 chars */
conEvnt->usrUsr.usrInfo.pres = PRSNT_NODEF;
conEvnt->usrUsr.usrInfo.len = len;
/* in sangoma_brid we used to send usr-usr info as <cid_name>!<calling_number>,
change to previous style if current one does not work */
memcpy(conEvnt->usrUsr.usrInfo.val, ftdm->cid_name, len);
} else {
switch (signal_data->switchtype) {
case SNGISDN_SWITCH_NI2:
/* TODO: Need to send the caller ID as a facility IE */
break;
case SNGISDN_SWITCH_EUROISDN:
if (signal_data->signalling != SNGISDN_SIGNALING_NET) {
break;
}
/* follow through */
case SNGISDN_SWITCH_5ESS:
case SNGISDN_SWITCH_4ESS:
case SNGISDN_SWITCH_DMS100:
conEvnt->display.eh.pres = PRSNT_NODEF;
conEvnt->display.dispInfo.pres = PRSNT_NODEF;
conEvnt->display.dispInfo.len = len;
memcpy(conEvnt->display.dispInfo.val, ftdm->cid_name, len);
break;
case SNGISDN_SWITCH_QSIG:
/* It seems like QSIG does not support Caller ID Name */
break;
case SNGISDN_SWITCH_INSNET:
/* Don't know how to transmit caller ID name on INSNET */
break;
}
}
return FTDM_SUCCESS;
}
ftdm_status_t check_for_state_change(ftdm_channel_t *ftdmchan)
{
#if 0
ftdm_log_chan_msg(ftdmchan, "Checking for pending state change\n");
#endif
/* check to see if there are any pending state changes on the channel and give them a sec to happen*/
ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 5000);
/* check the flag to confirm it is clear now */
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
/* the flag is still up...so we have a problem */
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "FTDM_CHANNEL_STATE_CHANGE set for over 500ms\n");
/* move the state of the channel to RESTART to force a reset */
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
void get_memory_info(void)
{
U32 availmen = 0;
SRegInfoShow(S_REG, &availmen);
return;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
/******************************************************************************/

View File

@ -0,0 +1,661 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ftmod_sangoma_isdn.h"
#include "ftmod_sangoma_isdn_trace.h"
#define OCTET(x) (ieData[x-1] & 0xFF)
void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end);
void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len);
void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len);
uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset, uint8_t *data, uint16_t index_start);
uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi);
char* get_code_2_str(int code, struct code2str *pCodeTable);
char* get_code_2_str(int code, struct code2str *pCodeTable)
{
struct code2str* pCode2txt;
pCode2txt = pCodeTable;
while(pCode2txt) {
if(pCode2txt->code >= 0) {
if (pCode2txt->code == code) {
return pCode2txt->text;
}
pCode2txt++;
} else {
/* This is the default value from the table */
return pCode2txt->text;
}
}
return (char*)"unknown";
}
uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi)
{
if (!bitLo || !bitHi) {
return 0;
}
if (bitLo > bitHi) {
return 0;
}
bitLo--;
bitHi--;
switch(bitHi - bitLo) {
case 0:
return (octet >> bitLo) & 0x01;
case 1:
return (octet >> bitLo) & 0x03;
case 2:
return (octet >> bitLo) & 0x07;
case 3:
return (octet >> bitLo) & 0x0F;
case 4:
return (octet >> bitLo) & 0x1F;
case 5:
return (octet >> bitLo) & 0x3F;
case 6:
return (octet >> bitLo) & 0x7F;
case 7:
return (octet >> bitLo) & 0xFF;
}
return 0;
}
void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len)
{
int str_len;
int i;
uint8_t sapi, cr, ea, tei, ns, nr, pf, p, cmd;
uint8_t frame_format = 0;
str_len = 0;
if(data_len >= 2) {
switch ((int)data[2] & 0x03) {
case 0: case 2:
frame_format = I_FRAME;
break;
case 1:
frame_format = S_FRAME;
break;
case 3:
frame_format = U_FRAME;
break;
}
}
str_len+= sprintf(&str[str_len], " format: %s\n",
get_code_2_str(frame_format, dcodQ921FrameFormatTable));
for(i=0; i < data_len; i++) {
switch(i) {
case 0: // Octet 2
sapi = (uint8_t)((data[i]>>2) & 0x3F);
cr = (uint8_t)((data[i]>>1) & 0x1);
ea = (uint8_t)(data[i] & 0x1);
str_len+= sprintf(&str[str_len], " sapi: %03d c/r: %01d ea: %01d\n", sapi, cr, ea);
break;
case 1:
tei = (uint8_t)((data[i]>>1) & 0x7F);
ea = (uint8_t)(data[i] & 0x1);
str_len+= sprintf(&str[str_len], " tei: %03d ea: %01d\n", tei, ea);
break;
case 2:
switch(frame_format) {
case I_FRAME:
ns = (uint8_t)((data[i]>>1) & 0x7F);
nr = (uint8_t)((data[i+1]>>1) & 0x7F);
p = (uint8_t)(data[i+1] & 0x01);
str_len+= sprintf(&str[str_len], " n(s): %03d\n n(r): %03d p: %01d\n", ns, nr, p);
break;
case S_FRAME:
nr = (uint8_t)((data[i+1]>>1) & 0x7F);
pf = (uint8_t)(data[i+1] & 0x01);
str_len+= sprintf(&str[str_len], " n(r): %03d p/f: %01d\n", nr, pf);
cmd = (uint8_t)((data[i]>>2) & 0x03);
str_len+= sprintf(&str[str_len], " cmd: %s\n", get_code_2_str(cmd, dcodQ921SupervisoryCmdTable));
break;
case U_FRAME:
pf = (uint8_t)((data[i]>>4) & 0x01);
str_len+= sprintf(&str[str_len], " p/f: %01d\n", pf);
cmd = (uint8_t)((data[i]>>2) & 0x03);
cmd |= (uint8_t)((data[i]>>5) & 0x07);
str_len+= sprintf(&str[str_len], " cmd: %s\n", get_code_2_str(cmd, dcodQ921UnnumberedCmdTable));
break;
}
break;
}
}
return;
}
void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len)
{
uint32_t str_len;
uint8_t prot_disc, callRefFlag;
uint16_t lenCallRef, c, i;
uint8_t current_codeset = 0;
str_len = 0;
/* Decode Protocol Discrimator */
prot_disc = (uint8_t)data[0];
str_len += sprintf(&str[str_len], " Prot Disc:%s (0x%02x)\n", get_code_2_str(prot_disc, dcodQ931ProtDiscTable), prot_disc);
/* Decode Call Reference */
lenCallRef = (uint8_t) (data[1] & 0x0F);
str_len += sprintf(&str[str_len], " Call Ref:");
c=2;
callRefFlag = get_bits(data[c], 8,8);
for(i=0; i<(2*lenCallRef);i++) {
if(i==0) {
str_len += sprintf(&str[str_len], "%s%s",
get_code_2_str((uint8_t)(data[c] & 0x70), dcodQ931CallRefHiTable),
get_code_2_str((uint8_t)(data[c] & 0x0F), dcodQ931CallRefLoTable));
} else {
str_len += sprintf(&str[str_len], "%s%s",
get_code_2_str((uint8_t)(data[c] & 0xF0), dcodQ931CallRefHiTable),
get_code_2_str((uint8_t)(data[c] & 0x0F), dcodQ931CallRefLoTable));
}
i=i+1;
c=c+1;
}
str_len += sprintf(&str[str_len], " (%s side)\n", callRefFlag?"Destination":"Origination");
/* Decode message type */
str_len+= sprintf(&str[str_len], " Type:%s (0x%x)\n", get_code_2_str((int)(data[2+lenCallRef] & 0xFF), dcodQ931MsgTypeTable), (int)(data[2+lenCallRef] & 0xFF));
/* go through rest of data and look for important info */
for(i=3+lenCallRef; i < data_len; i++) {
switch (data[i] & 0xF8) {
case Q931_LOCKING_SHIFT:
current_codeset = (data[i] & 0x7);
str_len+= sprintf(&str[str_len], "Codeset shift to %d (locking)\n", current_codeset);
continue;
case Q931_NON_LOCKING_SHIFT:
current_codeset = (data[i] & 0x7);
str_len+= sprintf(&str[str_len], "Codeset shift to %d (non-locking)\n", current_codeset);
continue;
}
i+= sngisdn_decode_ie(str, &str_len, current_codeset, data, i);
}
print_hex_dump(str, &str_len, (uint8_t*) data, 0, data_len);
return;
}
uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset, uint8_t *data, uint16_t index_start)
{
unsigned char* ieData;
uint8_t ieId;
uint32_t len = 0;
int index_end;
ieData = (unsigned char*) &data[index_start];
ieId = OCTET(1);
len = OCTET(2);
index_end = index_start+len+1;
*str_len += sprintf(&str[*str_len], " %s:", get_code_2_str(data[index_start], dcodQ931IEIDTable));
switch(ieId) {
case PROT_Q931_IE_BEARER_CAP:
{
uint8_t codingStandard, infTransferCap, transferMode, infTransferRate, usrL1Prot;
codingStandard = get_bits(OCTET(3),6,7);
infTransferCap = get_bits(OCTET(3),1,5);
transferMode = get_bits(OCTET(4),6,7);
infTransferRate = get_bits(OCTET(4),1,5);
usrL1Prot = get_bits(OCTET(5),1,5);
*str_len+= sprintf(&str[*str_len], "Coding:%s(%d) TransferCap:%s(%d) TransferRate:%s(%d) L1Prot:%s(%d)\n",
get_code_2_str(codingStandard, dcodQ931BcCodingStandardTable), codingStandard,
get_code_2_str(infTransferCap, dcodQ931BcInfTransferCapTable), infTransferCap,
get_code_2_str(infTransferRate, dcodQ931BcInfTransferRateTable), infTransferRate,
get_code_2_str(usrL1Prot, dcodQ931BcusrL1ProtTable), usrL1Prot);
}
break;
case PROT_Q931_IE_CAUSE:
{
uint8_t codingStandard, location, cause,diagOct = 5;
codingStandard = get_bits(OCTET(3),6,7);
location = get_bits(OCTET(3),1,4);
cause = get_bits(OCTET(4),1,7);
*str_len+= sprintf(&str[*str_len], "coding:%s(%d) location:%s(%d) val:%s(%d)\n",
get_code_2_str(codingStandard, dcodQ931BcCodingStandardTable), codingStandard,
get_code_2_str(location,dcodQ931IelocationTable), location,
get_code_2_str(cause, dcodQ931CauseCodeTable),
cause);
switch(cause) {
case PROT_Q931_RELEASE_CAUSE_IE_NOT_EXIST:
while(diagOct++ < len) {
*str_len+= sprintf(&str[*str_len], " %d:IE %s(0x%02x)\n",
diagOct,
get_code_2_str(OCTET(diagOct), dcodQ931IEIDTable),
OCTET(diagOct));
}
break;
case PROT_Q931_RELEASE_CAUSE_WRONG_CALL_STATE:
while(diagOct++ < len) {
*str_len+= sprintf(&str[*str_len], " %d:Message %s(0x%02x)\n",
diagOct,
get_code_2_str(OCTET(diagOct), dcodQ931MsgTypeTable),
OCTET(diagOct));
}
break;
case PROT_Q931_RECOVERY_ON_TIMER_EXPIRE:
*str_len+= sprintf(&str[*str_len], " Timer T\n");
while(diagOct++ < len) {
if(OCTET(diagOct) >= ' ' && OCTET(diagOct) < 0x7f) {
*str_len+= sprintf(&str[*str_len], "%c", OCTET(diagOct));
} else {
*str_len+= sprintf(&str[*str_len], ".");
}
}
break;
default:
while(diagOct++ < len) {
*str_len+= sprintf(&str[*str_len], " %d: 0x%02x\n",
diagOct,
OCTET(diagOct));
}
break;
}
}
break;
case PROT_Q931_IE_CHANNEL_ID:
{
uint8_t infoChannelSelection=0;
uint8_t prefExclusive=0;
uint8_t ifaceIdPresent=0;
uint8_t ifaceIdentifier = 0; /* octet_3_1 */
uint8_t chanType=0, numberMap=0, codingStandard=0;
uint8_t channelNo = 0;
infoChannelSelection = get_bits(OCTET(3),1,2);
prefExclusive = get_bits(OCTET(3),4,4);
ifaceIdPresent = get_bits(OCTET(3),7,7);
if (ifaceIdPresent) {
ifaceIdentifier= get_bits(OCTET(4),1,7);
chanType = get_bits(OCTET(5),1,4);
numberMap = get_bits(OCTET(5),5,5);
codingStandard = get_bits(OCTET(5),6,7);
channelNo = get_bits(OCTET(6),1,7);
} else {
chanType = get_bits(OCTET(4),1,4);
numberMap = get_bits(OCTET(4),5,5);
codingStandard = get_bits(OCTET(4),6,7);
channelNo = get_bits(OCTET(5),1,7);
}
if (numberMap) {
*str_len+= sprintf(&str[*str_len], " MAP\n");
} else {
*str_len+= sprintf(&str[*str_len], "No:%d ", channelNo);
}
*str_len+= sprintf(&str[*str_len], "Type:%s(%d) %s ", get_code_2_str(chanType,dcodQ931ChanTypeTable), chanType, (numberMap)? "Map":"");
*str_len+= sprintf(&str[*str_len], "%s/%s \n",
(prefExclusive)? "Exclusive":"Preferred",
(ifaceIdPresent)? "Explicit":"Implicit");
}
break;
case PROT_Q931_IE_CALLING_PARTY_NUMBER:
{
uint8_t plan, type, screening = 0, presentation = 0, callingNumOct, j;
uint8_t screeningEnabled = 0, presentationEnabled = 0;
char callingNumDigits[32];
memset(callingNumDigits, 0, sizeof(callingNumDigits));
plan = get_bits(OCTET(3),1,4);
type = get_bits(OCTET(3),5,7);
if(!get_bits(OCTET(3),8,8)) {
screening = get_bits(OCTET(4),1,2);
presentation = get_bits(OCTET(4),6,7);
screeningEnabled = 1;
presentationEnabled = 1;
callingNumOct = 4;
} else {
callingNumOct = 3;
}
if(len >= sizeof(callingNumDigits)) {
len = sizeof(callingNumDigits)-1;
}
j = 0;
while(callingNumOct++ <= len+1) {
callingNumDigits[j++]=ia5[get_bits(OCTET(callingNumOct),1,4)][get_bits(OCTET(callingNumOct),5,8)];
}
callingNumDigits[j]='\0';
*str_len+= sprintf(&str[*str_len], "%s(l:%d) plan:%s(%d) type:%s(%d)",
callingNumDigits, j,
get_code_2_str(plan, dcodQ931NumberingPlanTable), plan,
get_code_2_str(type, dcodQ931TypeofNumberTable), type);
if (presentationEnabled||screeningEnabled) {
*str_len+= sprintf(&str[*str_len], "scr:%s(%d) pres:%s(%d)\n",
get_code_2_str(screening, dcodQ931ScreeningTable), screening,
get_code_2_str(presentation, dcodQ931PresentationTable), presentation);
} else {
*str_len+= sprintf(&str[*str_len], "\n");
}
}
break;
case PROT_Q931_IE_CALLED_PARTY_NUMBER:
{
uint8_t plan, type, calledNumOct,j;
char calledNumDigits[32];
memset(calledNumDigits, 0, sizeof(calledNumDigits));
plan = get_bits(OCTET(3),1,4);
type = get_bits(OCTET(3),5,7);
if(len >= sizeof(calledNumDigits)) {
len = sizeof(calledNumDigits)-1;
}
calledNumOct = 3;
j = 0;
while(calledNumOct++ <= len+1) {
calledNumDigits[j++]=ia5[get_bits(OCTET(calledNumOct),1,4)][get_bits(OCTET(calledNumOct),5,8)];
}
calledNumDigits[j]='\0';
*str_len+= sprintf(&str[*str_len], "%s(l:%d) plan:%s(%d) type:%s(%d)\n",
calledNumDigits, j,
get_code_2_str(plan, dcodQ931NumberingPlanTable), plan,
get_code_2_str(type, dcodQ931TypeofNumberTable), type);
}
break;
case PROT_Q931_IE_REDIRECTING_NUMBER: //rdnis
{
uint8_t plan, type, screening = 0, presentation = 0, reason = 0, rdnisOct,j;
uint8_t screeningEnabled = 0, presentationEnabled = 0, reasonEnabled = 0;
char rdnis_string[32];
memset(rdnis_string, 0, sizeof(rdnis_string));
rdnisOct = 5;
plan = get_bits(OCTET(3),1,4);
type = get_bits(OCTET(3),5,7);
if(!get_bits(OCTET(3),8,8)) { //Oct 3a exists
rdnisOct++;
screening = get_bits(OCTET(4),1,2);
presentation = get_bits(OCTET(4),6,7);
screeningEnabled = 1;
presentationEnabled = 1;
if (!get_bits(OCTET(4),8,8)) { //Oct 3b exists
rdnisOct++;
reason = get_bits(OCTET(5),1,4);
reasonEnabled = 1;
}
}
if(len >= sizeof(rdnis_string)) {
len = sizeof(rdnis_string)-1;
}
j = 0;
while(rdnisOct++ <= len+1) {
rdnis_string[j++]=ia5[get_bits(OCTET(rdnisOct),1,4)][get_bits(OCTET(rdnisOct),5,8)];
}
rdnis_string[j]='\0';
*str_len+= sprintf(&str[*str_len], "%s(l:%d) plan:%s(%d) type:%s(%d)",
rdnis_string, j,
get_code_2_str(plan, dcodQ931NumberingPlanTable), plan,
get_code_2_str(type, dcodQ931TypeofNumberTable), type);
if(presentationEnabled || screeningEnabled) {
*str_len+= sprintf(&str[*str_len], "scr:%s(%d) pres:%s(%d)",
get_code_2_str(screening, dcodQ931ScreeningTable), screening,
get_code_2_str(presentation, dcodQ931PresentationTable), presentation);
}
if(reasonEnabled) {
*str_len+= sprintf(&str[*str_len], "reason:%s(%d)",
get_code_2_str(reason, dcodQ931ReasonTable), reason);
}
*str_len+= sprintf(&str[*str_len], "\n");
}
break;
case PROT_Q931_IE_USER_USER:
{
uint8_t protDiscr = 0x00, j, uui_stringOct;
char uui_string[32];
memset(uui_string, 0, sizeof(uui_string));
protDiscr = OCTET(3);
uui_stringOct = 3;
if (protDiscr != 0x04) { /* Non-IA5 */
*str_len+= sprintf(&str[*str_len], "%s (0x%02x)\n",
get_code_2_str(protDiscr, dcodQ931UuiProtDiscrTable), protDiscr);
} else {
j = 0;
if(len >= sizeof(uui_string)) {
len = sizeof(uui_string)-1;
}
while(uui_stringOct++ <= len+1) {
uui_string[j++]=ia5[get_bits(OCTET(uui_stringOct),1,4)][get_bits(OCTET(uui_stringOct),5,8)];
}
uui_string[j]='\0';
*str_len+= sprintf(&str[*str_len], " %s (0x%02x) <%s>\n",
get_code_2_str(protDiscr, dcodQ931UuiProtDiscrTable), protDiscr,
uui_string);
}
}
break;
case PROT_Q931_IE_DISPLAY:
{
uint8_t displayStrOct=2, j;
char displayStr[82];
memset(displayStr, 0, sizeof(displayStr));
if(get_bits(OCTET(3),8,8)) {
displayStrOct++;
}
j = 0;
if(len >= sizeof(displayStr)) {
len = sizeof(displayStr)-1;
}
while(displayStrOct++ <= len+1) {
displayStr[j++]=ia5[get_bits(OCTET(displayStrOct),1,4)][get_bits(OCTET(displayStrOct),5,8)];
}
displayStr[j]='\0';
*str_len+= sprintf(&str[*str_len], "%s(l:%d)\n",
displayStr, len);
}
break;
case PROT_Q931_IE_RESTART_IND:
{
uint8_t indClass;
indClass = get_bits(OCTET(3),1,3);
*str_len+= sprintf(&str[*str_len], "class:%s(%d)\n",
get_code_2_str(indClass,dcodQ931RestartIndClassTable), indClass);
}
break;
case PROT_Q931_IE_PROGRESS_IND:
{
uint8_t codingStandard, location, progressDescr;
codingStandard = get_bits(OCTET(3),6,7);
location = get_bits(OCTET(3),1,4);
progressDescr = get_bits(OCTET(4),1,7);
*str_len+= sprintf(&str[*str_len], "coding:%s(%d) location:%s(%d) descr:%s(%d)\n",
get_code_2_str(codingStandard,dcodQ931BcCodingStandardTable), codingStandard,
get_code_2_str(location,dcodQ931IelocationTable), location,
get_code_2_str(progressDescr,dcodQ931IeprogressDescrTable), progressDescr);
}
break;
case PROT_Q931_IE_KEYPAD_FACILITY:
{
uint8_t keypadFacilityStrOct = 3, j;
char keypadFacilityStr[82];
memset(keypadFacilityStr, 0, sizeof(keypadFacilityStr));
j = 0;
if(len >= sizeof(keypadFacilityStr)) {
len = sizeof(keypadFacilityStr)-1;
}
while(keypadFacilityStrOct++ < len+1) {
keypadFacilityStr[j++]=ia5[get_bits(OCTET(keypadFacilityStrOct),1,4)][get_bits(OCTET(keypadFacilityStrOct),5,8)];
}
keypadFacilityStr[j]='\0';
*str_len+= sprintf(&str[*str_len], " digits:%s(l:%d)\n",
keypadFacilityStr, len);
}
break;
case PROT_Q931_IE_FACILITY:
{
uint8_t protProfile;
protProfile = get_bits(OCTET(3),1,5);
*str_len+= sprintf(&str[*str_len], "Prot profile:%s(%d)\n",
get_code_2_str(protProfile,dcodQ931IeFacilityProtProfileTable), protProfile);
}
break;
case PROT_Q931_IE_GENERIC_DIGITS:
{
uint8_t encoding,type;
int value = 0;
encoding = get_bits(OCTET(3),6,8);
type = get_bits(OCTET(3),1,5);
*str_len+= sprintf(&str[*str_len], "encoding:%s(%d) type:%s(%d) ",
get_code_2_str(encoding,dcodQ931GenDigitsEncodingTable), encoding,
get_code_2_str(encoding,dcodQ931GenDigitsTypeTable), type);
if (len > 1) {
uint32_t j=0;
while(++j < len) {
switch(encoding) {
case 0: /* BCD even */
case 1: /* BCD odd */
{
uint8_t byte = OCTET(j+3);
value = (get_bits(byte,1,4)*10) + get_bits(byte,5,8) + (value*10);
}
break;
case 2: /* IA 5 */
value = value*10 + OCTET(j+3)-'0';
*str_len+= sprintf(&str[*str_len], "%c", OCTET(j+3));
break;
case 3:
/* Don't know how to decode binary encoding yet */
*str_len+= sprintf(&str[*str_len], "Binary encoded");
break;
}
}
*str_len+= sprintf(&str[*str_len], " ");
switch(type) {
case 4: /* info digits */
*str_len+= sprintf(&str[*str_len], "ani2:%s(%d)", get_code_2_str(value,dcodQ931LineInfoTable), value);
break;
case 5: /* Callid */
*str_len+= sprintf(&str[*str_len], "Caller ID not implemented\n");
break;
}
}
*str_len+= sprintf(&str[*str_len], "\n");
print_hex_dump(str, str_len, (uint8_t*) data, index_start, index_end);
}
break;
case PROT_Q931_IE_SENDING_COMPLETE:
/* No need to decode sending complete IE, as no additional info is available except that sending is done */
break;
case PROT_Q931_IE_CALLED_PARTY_SUBADDRESS:
case PROT_Q931_IE_REDIRECTION_NUMBER:
case PROT_Q931_IE_NOTIFICATION_IND:
case PROT_Q931_IE_DATE_TIME:
case PROT_Q931_IE_INFORMATION_REQUEST:
case PROT_Q931_IE_SIGNAL:
case PROT_Q931_IE_SWITCHOOK:
case PROT_Q931_IE_FEATURE_ACT:
case PROT_Q931_IE_FEATURE_IND:
case PROT_Q931_IE_INFORMATION_RATE:
case PROT_Q931_IE_END_TO_END_TRANSIT_DELAY:
case PROT_Q931_IE_TRANSIT_DELAY_SELECT_IND:
case PROT_Q931_IE_PACKET_LAYER_BINARY_PARAMS:
case PROT_Q931_IE_PACKET_LAYER_WINDOW_SIZE:
case PROT_Q931_IE_PACKET_LAYER_SIZE:
case PROT_Q931_IE_TRANSIT_NETWORK_SELECTION:
case PROT_Q931_IE_LOW_LAYER_COMPAT:
case PROT_Q931_IE_HIGH_LAYER_COMPAT:
case PROT_Q931_IE_ESCAPE_FOR_EXTENSION:
case PROT_Q931_IE_CALL_IDENTITY:
case PROT_Q931_IE_CALL_STATE:
case PROT_Q931_IE_SEGMENTED_MESSAGE:
case PROT_Q931_IE_NETWORK_SPF_FACILITY:
case PROT_Q931_IE_CALLING_PARTY_SUBADDRESS:
default:
{
*str_len += sprintf(&str[*str_len], "Undecoded");
print_hex_dump((char*)str, str_len, data, index_start, index_end);
}
break;
}
return len+1;
}
void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end)
{
int k;
*str_len += sprintf(&str[*str_len], " [ ");
for(k=index_start; k <= index_end; k++) {
if (k && !(k%32)) {
*str_len += sprintf(&str[*str_len], "\n ");
}
*str_len += sprintf(&str[*str_len], "%02x ", data[k]);
}
*str_len += sprintf(&str[*str_len], "]\n");
return;
}

View File

@ -0,0 +1,540 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* David Yat Sin <davidy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __FTMOD_SANGOMA_ISDN_TRACE_H__
#define __FTMOD_SANGOMA_ISDN_TRACE_H__
#define MX_CODE_TXT_LEN 70
#define Q931_LOCKING_SHIFT 0x90
#define Q931_NON_LOCKING_SHIFT 0x98
#define PROT_Q931_RELEASE_CAUSE_MISDIALED_TRUNK_PREFIX 5
#define PROT_Q931_RELEASE_CAUSE_INVALID_NUMBER_FORMAT 28
#define PROT_Q931_RELEASE_CAUSE_NO_CHAN_AVAIL 34
#define PROT_Q931_RELEASE_CAUSE_DEST_OUT_OF_ORDER 27
#define PROT_Q931_RELEASE_CAUSE_IE_NOT_EXIST 99
#define PROT_Q931_RECOVERY_ON_TIMER_EXPIRE 102
#define PROT_Q931_RELEASE_CAUSE_WRONG_CALL_STATE 101
#define PROT_Q931_IE_SEGMENTED_MESSAGE 0x00
#define PROT_Q931_IE_BEARER_CAP 0x04
#define PROT_Q931_IE_CAUSE 0x08
#define PROT_Q931_IE_CALL_IDENTITY 0x10
#define PROT_Q931_IE_CALL_STATE 0x14
#define PROT_Q931_IE_CHANNEL_ID 0x18
#define PROT_Q931_IE_FACILITY 0x1c
#define PROT_Q931_IE_PROGRESS_IND 0x1e
#define PROT_Q931_IE_NETWORK_SPF_FACILITY 0x20
#define PROT_Q931_IE_NOTIFICATION_IND 0x27
#define PROT_Q931_IE_DISPLAY 0x28
#define PROT_Q931_IE_DATE_TIME 0x29
#define PROT_Q931_IE_KEYPAD_FACILITY 0x2c
#define PROT_Q931_IE_INFORMATION_REQUEST 0x32
#define PROT_Q931_IE_SIGNAL 0x34
#define PROT_Q931_IE_SWITCHOOK 0x36
#define PROT_Q931_IE_GENERIC_DIGITS 0x37
#define PROT_Q931_IE_FEATURE_ACT 0x38
#define PROT_Q931_IE_FEATURE_IND 0x39
#define PROT_Q931_IE_INFORMATION_RATE 0x40
#define PROT_Q931_IE_END_TO_END_TRANSIT_DELAY 0x42
#define PROT_Q931_IE_TRANSIT_DELAY_SELECT_IND 0x43
#define PROT_Q931_IE_PACKET_LAYER_BINARY_PARAMS 0x44
#define PROT_Q931_IE_PACKET_LAYER_WINDOW_SIZE 0x45
#define PROT_Q931_IE_PACKET_LAYER_SIZE 0x46
#define PROT_Q931_IE_CALLING_PARTY_NUMBER 0x6c
#define PROT_Q931_IE_CALLING_PARTY_SUBADDRESS 0x6d
#define PROT_Q931_IE_CALLED_PARTY_NUMBER 0x70
#define PROT_Q931_IE_CALLED_PARTY_SUBADDRESS 0x71
#define PROT_Q931_IE_REDIRECTING_NUMBER 0x74
#define PROT_Q931_IE_REDIRECTION_NUMBER 0x76
#define PROT_Q931_IE_TRANSIT_NETWORK_SELECTION 0x78
#define PROT_Q931_IE_RESTART_IND 0x79
#define PROT_Q931_IE_LOW_LAYER_COMPAT 0x7c
#define PROT_Q931_IE_HIGH_LAYER_COMPAT 0x7d
#define PROT_Q931_IE_USER_USER 0x7e
#define PROT_Q931_IE_SENDING_COMPLETE 0xa1
#define PROT_Q931_IE_ESCAPE_FOR_EXTENSION 0x7f
#define PROT_Q931_IE_SENDING_COMPLETE 0xa1
#define NULL_CHAR 0
struct code2str
{
int code;
char text[MX_CODE_TXT_LEN];
};
enum {
I_FRAME = 1, /* Information frame */
S_FRAME, /* Supervisory frame */
U_FRAME, /* Unnumbered frame */
};
char ia5[16][8]={{NULL_CHAR,NULL_CHAR,' ','0','@','P','`','p'},
{NULL_CHAR,NULL_CHAR,'!','1','A','Q','a','q'},
{NULL_CHAR,NULL_CHAR,'"','2','B','R','b','r'},
{NULL_CHAR,NULL_CHAR,'#','3','C','S','c','s'},
{NULL_CHAR,NULL_CHAR,'$','4','D','T','d','t'},
{NULL_CHAR,NULL_CHAR,'%','5','E','U','e','u'},
{NULL_CHAR,NULL_CHAR,'&','6','F','V','f','v'},
{NULL_CHAR,NULL_CHAR,'\'','7','G','W','g','w'},
{NULL_CHAR,NULL_CHAR,'(','8','H','X','h','x'},
{NULL_CHAR,NULL_CHAR,')','9','I','Y','i','y'},
{NULL_CHAR,NULL_CHAR,'*',':','J','Z','j','z'},
{NULL_CHAR,NULL_CHAR,'+',';','K','[','k','{'},
{NULL_CHAR,NULL_CHAR,',','<','L','\\','l','|'},
{NULL_CHAR,NULL_CHAR,'-','=','M',']','m','}'},
{NULL_CHAR,NULL_CHAR,'.','>','N','^','n','~'},
{NULL_CHAR,NULL_CHAR,'/','?','O','_','o',NULL_CHAR}};
/* Based on Table 4 - pg 15 of Q.921 Recommendation */
struct code2str dcodQ921FrameFormatTable[] = {
{I_FRAME, "Information"},
{S_FRAME, "Supervisory"},
{U_FRAME, "Unnumbered"},
{-1, "?"},
};
/* Based on Table 5 - pg 15 of Q.921 Recommendation */
struct code2str dcodQ921SupervisoryCmdTable[] = {
{0, "RR - receive ready"},
{1, "RNR - receive not ready"},
{2, "REJ - reject"},
{-1, "Unknown"},
};
/* Based on Table 5 - pg 15 of Q.921 Recommendation */
struct code2str dcodQ921UnnumberedCmdTable[] = {
{0x0F, "SABME - set async balanced mode extended"},
{0x03, "DM - disconnected mode"},
{0x00, "UI - unnumbered information"},
{0x08, "DISC - disconnect"},
{0x0C, "UA - unnumbered acknowledgement"},
{0x11, "FRMR - frame reject"},
{0x17, "XID - Exchange Identification)"},
{-1, "Unknown"},
};
struct code2str dcodQ931ProtDiscTable[] = {
{0x08, "Q.931/I.451"},
{0x09, "Q.2931"},
{-1, "Unknown"},
};
struct code2str dcodQ931CallRefHiTable[] = {
{0, "0"},
{16, "1"},
{32, "2"},
{48, "3"},
{64, "4"},
{80, "5"},
{96, "6"},
{112, "7"},
{128, "8"},
{144, "9"},
{160, "A"},
{176, "B"},
{192, "C"},
{208, "D"},
{224, "E"},
{240, "F"},
{-1,"?"},
};
struct code2str dcodQ931CallRefLoTable[] = {
{0, "0"},
{1, "1"},
{2, "2"},
{3, "3"},
{4, "4"},
{5, "5"},
{6, "6"},
{7, "7"},
{8, "8"},
{9, "9"},
{10, "A"},
{11, "B"},
{12, "C"},
{13, "D"},
{14, "E"},
{15, "F"},
{-1,"?"},
};
struct code2str dcodQ931MsgTypeTable[] = {
{1, "Alerting"},
{2, "Call Proceeding"},
{3, "Progress"},
{5, "Setup"},
{7, "Connect"},
{13, "Setup Ack"},
{15, "Connect Ack"},
{32, "User Info"},
{33, "Suspend Rej"},
{34, "Resume Rej"},
{37, "Suspend"},
{38, "Resume"},
{45, "Suspend Ack"},
{46, "Resume Ack"},
{69, "Disconnect"},
{70, "Restart"},
{77, "Release"},
{78, "Release Ack"},
{90, "Release Compl"},
{96, "Segment"},
{98, "Facility"},
{110, "Notify"},
{117, "Status Enquiry"},
{121, "Congest Cntrl"},
{123, "Information"},
{125, "Status"},
{-1, "Unknown"},
};
struct code2str dcodQ931CauseCodeTable[] = {
{1, "Unallocated (unassigned) number"},
{2, "No route to specified network"},
{3, "No route to destination"},
{4, "Send special information tone"},
{5, "Misdialed trunk prefix"},
{6, "Channel Unacceptable"},
{7, "Call awarded and channel established"},
{8, "Pre-emption"},
{9, "Pre-emption-circuit reserved"},
{16, "Normal call clearing"},
{17, "User Busy"},
{18, "No User Responding"},
{19, "No Answer from User"},
{20, "Subscriber Absent"},
{21, "Call Rejected"},
{22, "Number Changed"},
{26, "Non-Selected User Clearing"},
{27, "Destination Out-of-Order"},
{28, "Invalid Number Format"},
{29, "Facility Rejected"},
{30, "Response to Status Enquiry"},
{31, "Normal, Unspecified"},
{34, "No Circuit/Channel Available"},
{38, "Network Out-of-Order"},
{39, "Permanent Frame Mode OOS"},
{40, "Permanent Frame Mode Operational"},
{41, "Temporary Failure"},
{42, "Switching Equipment Congestion"},
{43, "Access Information Discarded"},
{44, "Requested Circuit/Channel not available"},
{47, "Resource Unavailable, Unspecified"},
{49, "Quality of Service not available"},
{50, "Requested facility not subscribed"},
{53, "Outgoing calls barred within CUG"},
{55, "Incoming calls barred within CUG"},
{57, "Bearer capability not authorized"},
{58, "Bearer capability not presently available"},
{62, "Inconsistency in access inf and subscriber"},
{63, "Service or Option not available"},
{65, "Bearer capability not implemented"},
{66, "Channel type not implemented"},
{69, "Requested facility not implemented"},
{70, "Only restricted digital BC available"},
{79, "Service or option not implemented"},
{81, "Invalid call reference value"},
{82, "Identified channel does not exist"},
{83, "Suspended call exists"},
{84, "Call identity in use"},
{85, "No call suspended"},
{86, "Call already cleared"},
{87, "User not member of CUG"},
{88, "Incompatible destination"},
{90, "Non existent CUG"},
{91, "Invalid transit network selection"},
{95, "Invalid message, unspecified"},
{96, "Mandatory IE missing"},
{97, "Message type non-existent, not implemented"},
{98, "Message not compatible with call state"},
{99, "An IE or parameter does not exist"},
{100, "Invalid IE contents"},
{101, "Message not compatible with call state"},
{102, "Recovery on timer expired"},
{103, "Parameter non-existent, not impl"},
{110, "Message with unrecognized parameter"},
{111, "Protocol error, unspecified"},
{127, "Interworking, unspecified"},
{-1, "Unknown"},
};
struct code2str dcodQ931IEIDTable[] = {
{PROT_Q931_IE_SEGMENTED_MESSAGE, "Segmented Message"},
{PROT_Q931_IE_BEARER_CAP, "Bearer Capability"},
{PROT_Q931_IE_CAUSE, "Cause"},
{PROT_Q931_IE_CALL_IDENTITY, "Call Identity"},
{PROT_Q931_IE_CALL_STATE, "Call State"},
{PROT_Q931_IE_CHANNEL_ID, "Channel Id"},
{PROT_Q931_IE_FACILITY, "Facility"},
{PROT_Q931_IE_PROGRESS_IND, "Progress Indicator"},
{PROT_Q931_IE_NETWORK_SPF_FACILITY, "Network Specific Facilities"},
{PROT_Q931_IE_NOTIFICATION_IND, "Notification Indicator"},
{PROT_Q931_IE_DISPLAY, "Display"},
{PROT_Q931_IE_DATE_TIME, "Date/Time"},
{PROT_Q931_IE_KEYPAD_FACILITY, "Keypad Facility"},
{PROT_Q931_IE_INFORMATION_REQUEST, "Information Request"},
{PROT_Q931_IE_SIGNAL, "Signal"},
{PROT_Q931_IE_SWITCHOOK, "Switchhook"},
{PROT_Q931_IE_GENERIC_DIGITS, "Generic Digits"},
{PROT_Q931_IE_FEATURE_ACT, "Feature Activation"},
{PROT_Q931_IE_FEATURE_IND, "Feature Indication"},
{PROT_Q931_IE_INFORMATION_RATE, "Information Rate"},
{PROT_Q931_IE_END_TO_END_TRANSIT_DELAY, "End-to-end Transit Delay"},
{PROT_Q931_IE_TRANSIT_DELAY_SELECT_IND, "Transit Delay Selection and Indication"},
{PROT_Q931_IE_PACKET_LAYER_BINARY_PARAMS, "Packet layer binary parameters"},
{PROT_Q931_IE_PACKET_LAYER_WINDOW_SIZE, "Packet layer Window Size"},
{PROT_Q931_IE_PACKET_LAYER_SIZE, "Packet layer Size"},
{PROT_Q931_IE_CALLING_PARTY_NUMBER, "Calling Party Number"},
{PROT_Q931_IE_CALLING_PARTY_SUBADDRESS, "Calling Party Subaddress"},
{PROT_Q931_IE_CALLED_PARTY_NUMBER, "Called Party Number"},
{PROT_Q931_IE_CALLED_PARTY_SUBADDRESS, "Called Party Subaddress"},
{PROT_Q931_IE_REDIRECTING_NUMBER, "Redirecting Number"},
{PROT_Q931_IE_REDIRECTION_NUMBER, "Redirection Number"},
{PROT_Q931_IE_TRANSIT_NETWORK_SELECTION, "Transit Network Selection"},
{PROT_Q931_IE_RESTART_IND, "Restart Indicator"},
{PROT_Q931_IE_LOW_LAYER_COMPAT, "Low-Layer Compatibility"},
{PROT_Q931_IE_HIGH_LAYER_COMPAT, "High-Layer Compatibility"},
{PROT_Q931_IE_USER_USER, "User-User"},
{PROT_Q931_IE_SENDING_COMPLETE, "Sending complete"},
{PROT_Q931_IE_ESCAPE_FOR_EXTENSION, "Escape for extension"},
{-1,"Unknown"},
};
struct code2str dcodQ931NumberingPlanTable[] = {
{0, "unknown"},
{1, "isdn"},
{3, "data"},
{4, "telex"},
{8, "national"},
{9, "private"},
{15, "reserved"},
{-1, "invalid"},
};
struct code2str dcodQ931TypeofNumberTable[] = {
{0, "unknown"},
{1, "international"},
{2, "national"},
{3, "network spf"},
{4, "subscriber"},
{6, "abbreviated"},
{7, "reserved"},
{-1, "invalid" },
};
struct code2str dcodQ931PresentationTable[] = {
{0, "allowed"},
{1, "restricted"},
{2, "not available"},
{-1, "invalid" },
};
struct code2str dcodQ931ScreeningTable[] = {
{0, "user, not screened"},
{1, "user, passed"},
{2, "user, failed"},
{3, "network, provided"},
{-1, "invalid" },
};
struct code2str dcodQ931ReasonTable[] = {
{0x0, "Unknown"},
{0x1, "Call forwarding busy"},
{0x2, "Call forwarding no reply"},
{0x4, "Call deflection"},
{0x9, "Called DTE out of order"},
{0xA, "Call forwarding by the called DTE"},
{0xF, "Call forwarding unconditional"},
{-1, "reserved" },
};
struct code2str dcodQ931BcCodingStandardTable[] = {
{0x0, "ITU-T"},
{0x1, "ISO/IEC"},
{0x2, "National"},
{0x3, "Defined standard"},
{-1, "unknown"},
};
struct code2str dcodQ931BcInfTransferCapTable[] = {
{0x00, "Speech"},
{0x08, "Unrestricted digital"},
{0x09, "Restricted digital"},
{0x10, "3.1Khz audio"},
{0x11, "Unrestricted digital w/ tones"},
{0x18, "Video"},
{-1, "reserved"},
};
struct code2str dcodQ931BcInfTransferRateTable[] = {
{0x00, "n/a"}, /* for packet-mode calls */
{0x10, "64 Kbit/s"},
{0x11, "2x64 Kbit/s"},
{0x13, "384 Kbit/s"},
{0x15, "1536 Kbit/s"},
{0x17, "1920 Kbit/s"},
{0x18, "Multirate"},
{-1, "reserved"},
};
struct code2str dcodQ931BcusrL1ProtTable[] = {
{0x01, "ITU-T rate/V.110/I.460/X.30"},
{0x02, "G.711 u-Law"},
{0x03, "G.711 A-Law"},
{0x04, "G.721/I.460"},
{0x05, "H.221/H.242"},
{0x06, "H.223/H.245"},
{0x07, "Non-ITU-T rate"},
{0x08, "V.120"},
{0x09, "X.31 HDLC"},
{-1, "reserved"},
};
struct code2str dcodQ931UuiProtDiscrTable[] = {
{0x00, "User-specific"},
{0x01, "OSI high layer prot"},
{0x02, "Recommendation X.244"},
{0x03, "System management"},
{0x04, "IA5 Chars"},
{0x05, "X.208/X.209"},
{0x07, "V.120"},
{0x08, "Q.931/I.451"},
{0x10, "X.25"},
{-1,"reserved"},
};
struct code2str dcodQ931ChanTypeTable[] = {
{0x3,"B-chans"},
{0x6,"H0-chans"},
{0x8,"H11-chans"},
{0x9,"H12-chans"},
{-1,"reserved"},
};
struct code2str dcodQ931RestartIndClassTable[] = {
{0x0 ,"Indicated in channel IE"},
{0x6 ,"Single interface"},
{0x7 ,"All interfaces"},
{-1, "reserved"},
};
struct code2str dcodQ931IelocationTable[] = {
{0x0, "User"},
{0x1, "Private network, local user"},
{0x2, "Public network, local user"},
{0x3, "Transit network"},
{0x4, "Public network, remote user"},
{0x5, "Private network, remote user"},
{0xA, "Beyond interworking point"},
{-1, "reserved"},
};
struct code2str dcodQ931IeprogressDescrTable[] = {
{0x01, "Further info maybe available"},
{0x02, "Destination is non-ISDN"},
{0x03, "Origination address is non-ISDN"},
{0x04, "Call returned to ISDN"},
{0x08, "In-band data ready"},
{-1, "reserved"},
};
struct code2str dcodQ931IeFacilityProtProfileTable[] = {
{0x11, "Remote Operations Protocol"},
{0x12, "CMIP Protocol"},
{0x13, "ACSE Protocol"},
{0x16, "GAT Protocol"},
{0x1F, "Networking Extensions"},
{-1, "reserved"},
};
//from www.voip-info.org/wiki/ANI2 - NANPA
struct code2str dcodQ931LineInfoTable[] = {
{0, "Plain Old Telephone Service(POTS)" },
{1, "Multiparty line"},
{2, "ANI Failure"},
{6, "Station Level Rating"},
{7, "Special Operator Handling Required"},
{20, "Automatic Identified Outward Dialing (AIOD)"},
{23, "Coin or Non-coin"},
{24, "Toll free service, POTS originated for non-pay station"},
{25, "Toll free service, POTS originated for pay station"},
{27, "Pay station with coin control"},
{29, "Prison-Inmate service"},
{30, "Intercept - blank"},
{31, "Intercept - trouble"},
{32, "Intercept - regular"},
{34, "Telco operator handled call"},
{52, "Outward Wide Area Telecommunications Service(OUTWATS)"},
{60, "TRS call - from unrestricted line"},
{61, "Cellular-Wireless PCS Type 1"},
{62, "Cellular-Wireless PCS Type 2"},
{63, "Cellular-Wireless PCS Type Roaming"},
{66, "TRS call - from hotel/motel"},
{67, "TRS call - from restricted line"},
{70, "Line connected to pay station"},
{93, "Private virtual network call"},
{-1, "Unassigned"},
};
struct code2str dcodQ931GenDigitsEncodingTable[] = {
{0, "BCD even"},
{1, "BCD odd"},
{2, "IA5"},
{3, "Binary"},
{-1, "Invalid"},
};
struct code2str dcodQ931GenDigitsTypeTable[] = {
{ 0, "Account Code"},
{ 1, "Auth Code"},
{ 2, "Customer ID" },
{ 3, "Universal Access"},
{ 4, "Info Digits"},
{ 5, "Callid"},
{ 6, "Opart"},
{ 7, "TCN"},
{ 9, "Adin"},
{-1, "Invalid"},
};
#endif /* __FTMOD_SANGOMA_ISDN_TRACE_H__ */