Removed assert when we cannot find a call on RelInd, it seems like Trillium as a bug where they sometimes send release twice
Fixes to some memory leaks
Fix for bug in q921 trace disable command
Fix for not recognizing etsi switchtype
Fix for sending RESTART when we are not supposed to in EUROISDN NETWORK mode
Support for l1 stats
Fix for deadlocks/segfaults on shutdown
Added index per link_id, support for show_spans
Added progress-ind when sending CONNECT message
Fix for sending CONNECT ACK when configured as TE
if (switch_vasprintf(&data, fmt, ap) != -1) {
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, (char *)func, line, NULL, level, "%s", data);
- free(data);
}
-
+ if (data) free(data);
va_end(ap);
}
status = FTDM_FAIL;
}
ftdm_safe_free(span->type);
+ ftdm_safe_free(span->name);
ftdm_safe_free(span->dtmf_hangup);
}
} else {
globals.spans = span;
}
- hashtable_insert(globals.span_hash, (void *)span->name, span, HASHTABLE_FLAG_NONE);
+ hashtable_insert(globals.span_hash, (void *)span->name, span, HASHTABLE_FLAG_FREE_VALUE);
ftdm_mutex_unlock(globals.span_mutex);
}
FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan, ftdm_iterator_t *iter)
{
+ ftdm_hash_iterator_t *hashiter = NULL;
+ ftdm_channel_lock(ftdmchan);
+ hashiter = ftdmchan->variable_hash == NULL ? NULL : hashtable_first(ftdmchan->variable_hash);
+ ftdm_channel_unlock(ftdmchan);
+
+
+ if (hashiter == NULL) {
+ return NULL;
+ }
+
if (!(iter = get_iterator(FTDM_ITERATOR_VARS, iter))) {
return NULL;
}
- ftdm_channel_lock(ftdmchan);
- iter->pvt.hashiter = ftdmchan->variable_hash == NULL ? NULL : hashtable_first(ftdmchan->variable_hash);
- ftdm_channel_unlock(ftdmchan);
+ iter->pvt.hashiter = hashiter;
return iter;
}
ftdm_mutex_lock(globals.mutex);
hashtable_destroy(globals.interface_hash);
- hashtable_destroy(globals.module_hash);
+ hashtable_destroy(globals.module_hash);
hashtable_destroy(globals.span_hash);
+ hashtable_destroy(globals.group_hash);
ftdm_mutex_unlock(globals.mutex);
ftdm_mutex_destroy(&globals.mutex);
ftdm_mutex_destroy(&globals.span_mutex);
+ ftdm_mutex_destroy(&globals.group_mutex);
memset(&globals, 0, sizeof(globals));
return FTDM_SUCCESS;
case FTDM_CHANNEL_STATE_RING: /* incoming call request */
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending incoming call from %s to %s to FTDM core\n", ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.dnis.digits);
- ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1");
- ftdm_channel_add_var(ftdmchan, "isdn_crap", "morecrap");
- ftdm_channel_add_var(ftdmchan, "isdn_stuff", "s");
- ftdm_channel_add_var(ftdmchan, "isdn_d", "asdsadasdasdsad");
+
/* we have enough information to inform FTDM of the call*/
sigev.event_id = FTDM_SIGEVENT_START;
ftdm_span_send_signal(ftdmchan->span, &sigev);
return status;
}
-static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_sig_status)
+static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_chan_sig_status)
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
*status = FTDM_SIG_STATE_UP;
return FTDM_SUCCESS;
}
-static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_sig_status)
+static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_chan_sig_status)
{
ftdm_log(FTDM_LOG_ERROR,"Cannot set channel status in this module\n");
return FTDM_NOTIMPL;
}
+static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_span_sig_status)
+{
+ if (ftdm_test_flag(span->channels[1], FTDM_CHANNEL_SIG_UP)) {
+ *status = FTDM_SIG_STATE_UP;
+ } else {
+ *status = FTDM_SIG_STATE_DOWN;
+ }
+
+ return FTDM_SUCCESS;
+}
+
+static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status)
+{
+ ftdm_log(FTDM_LOG_ERROR,"Cannot set span status in this module\n");
+ return FTDM_NOTIMPL;
+}
+
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
{
ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id);
- if (sng_isdn_stack_activate(span) != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_CRIT, "Failed to activate span %s\n", span->name);
+ if (sng_isdn_stack_start(span) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name);
return FTDM_FAIL;
}
/* clear the monitor thread stop flag */
static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span)
{
- unsigned i;
+ ftdm_iterator_t *chaniter = NULL;
+ ftdm_iterator_t *curr = NULL;
ftdm_log(FTDM_LOG_INFO, "Stopping span %s\n", span->name);
/* throw the STOP_THREAD flag to signal monitor thread stop */
ftdm_sleep(10);
}
- /* FIXME: deconfigure any links, attached to this span */
- /* TODO: Use Moy's channel Iterator when its implemented */
- for (i=1;i<=span->chan_count;i++) {
- ftdm_safe_free(span->channels[i]->call_data);
+ if (sng_isdn_stack_stop(span) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s\n", span->name);
+ }
+
+ chaniter = ftdm_span_get_chan_iterator(span, NULL);
+ for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
+ ftdm_safe_free(((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data);
+ ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = NULL;
}
+ ftdm_iterator_free(chaniter);
+
+ ftdm_sched_destroy(&((sngisdn_span_data_t*)span->signal_data)->sched);
+ ftdm_queue_destroy(&((sngisdn_span_data_t*)span->signal_data)->event_queue);
ftdm_safe_free(span->signal_data);
ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s\n", span->name);
static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
{
+ ftdm_iterator_t *chaniter = NULL;
+ ftdm_iterator_t *curr = NULL;
+
sngisdn_span_data_t *span_data;
ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_isdn span = %s\n", span->name);
span_data = ftdm_calloc(1, sizeof(sngisdn_span_data_t));
span_data->ftdm_span = span;
span->signal_data = span_data;
-
- unsigned i;
- for (i=1;i <= span->chan_count; i++) {
+
+ chaniter = ftdm_span_get_chan_iterator(span, NULL);
+ for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
sngisdn_chan_data_t *chan_data = ftdm_calloc(1, sizeof(sngisdn_chan_data_t));
- chan_data->ftdmchan = span->channels[i];
- span->channels[i]->call_data = chan_data;
+ chan_data->ftdmchan = ((ftdm_channel_t*)ftdm_iterator_current(curr));
+ ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = chan_data;
+
}
+ ftdm_iterator_free(chaniter);
if (ftmod_isdn_parse_cfg(ftdm_parameters, span) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Failed to parse configuration\n");
span->outgoing_call = ftdm_sangoma_isdn_outgoing_call;
span->channel_request = NULL;
span->signal_cb = sig_cb;
- span->get_channel_sig_status = ftdm_sangoma_isdn_get_sig_status;
- span->set_channel_sig_status = ftdm_sangoma_isdn_set_sig_status;
+ span->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status;
+ span->set_channel_sig_status = ftdm_sangoma_isdn_set_chan_sig_status;
+ span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
+ span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status;
span->state_map = &sangoma_isdn_state_map;
ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
for(i=1;i<=MAX_VARIANTS;i++) {
ftdm_mutex_create(&g_sngisdn_data.ccs[i].mutex);
}
-
+
/* initalize sng_isdn library */
sng_isdn_init(&g_sngisdn_event_interface);
return FTDM_SUCCESS;
if (!strcasecmp(argv[0], "l1_stats")) {
ftdm_span_t *span;
if (argc < 2) {
- ftdm_log(FTDM_LOG_ERROR, "Usage: ftdm sangoma_isdn l1_stats <span name>\n");
+ stream->write_function(stream, "Usage: ftdm sangoma_isdn l1_stats <span name>\n");
status = FTDM_FAIL;
goto done;
}
status = ftdm_span_find_by_name(argv[1], &span);
if (FTDM_SUCCESS != status) {
- stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[2]);
+ stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]);
+ /* Return SUCCESS because we do not want to print the general FTDM usage list */
+ status = FTDM_SUCCESS;
+ goto done;
+ }
+ sngisdn_print_phy_stats(stream, span);
+ }
+
+ if (!strcasecmp(argv[0], "show_spans")) {
+ ftdm_span_t *span = NULL;
+ if (argc == 2) {
+ status = ftdm_span_find_by_name(argv[1], &span);
+ if (FTDM_SUCCESS != status) {
+ stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]);
+ /* Return SUCCESS because we do not want to print the general FTDM usage list */
+ status = FTDM_SUCCESS;
+ goto done;
+ }
+ sngisdn_print_span(stream, span);
+ status = FTDM_SUCCESS;
goto done;
}
- /* TODO: implement PHY stats */
+ sngisdn_print_spans(stream);
}
if (!strcasecmp(argv[0], "check_ids")) {
sngisdn_check_free_ids();
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];
+ sngisdn_dchan_data_t dchans[MAX_L1_LINKS+1];
+ sngisdn_span_data_t *spans[MAX_L1_LINKS+1]; /* spans are indexed by link_id */
}ftdm_sngisdn_data_t;
/* 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);
-
+ftdm_status_t sng_isdn_stack_start(ftdm_span_t *span);
+ftdm_status_t sng_isdn_stack_stop(ftdm_span_t *span);
+void sngisdn_print_phy_stats(ftdm_stream_handle_t *stream, ftdm_span_t *span);
+void sngisdn_print_spans(ftdm_stream_handle_t *stream);
+void sngisdn_print_span(ftdm_stream_handle_t *stream, ftdm_span_t *span);
#endif /* __FTMOD_SNG_ISDN_H__ */
}
break;
case FTDM_TRUNK_E1:
- if (!strcasecmp(switch_name, "euroisdn") || strcasecmp(switch_name, "etsi")) {
+ 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;
signal_data->span_id = dchan_data->num_spans;
dchan_data->spans[signal_data->span_id] = signal_data;
+
+ g_sngisdn_data.spans[signal_data->link_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);
signal_data->overlap_dial = SNGISDN_OPT_DEFAULT;
signal_data->setup_arb = SNGISDN_OPT_DEFAULT;
+ signal_data->link_id = span->span_id;
span->default_caller_data.bearer_capability = IN_ITC_SPEECH;
/* Cannot set default bearer_layer1 yet, as we do not know the switchtype */
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;
#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)
return;
}
+void sngisdn_set_span_sig_status(ftdm_span_t *span, ftdm_signaling_status_t status)
+{
+ ftdm_iterator_t *chaniter = NULL;
+ ftdm_iterator_t *curr = NULL;
-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);
+ chaniter = ftdm_span_get_chan_iterator(span, NULL);
+ for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
+ sngisdn_set_chan_sig_status(((ftdm_channel_t*)ftdm_iterator_current(curr)), status);
}
+ ftdm_iterator_free(chaniter);
return;
}
-
-
-
/* For Emacs:
* Local Variables:
* mode:c
cfg.t.cfg.s.inDLSAP.ctldInt[1] = 1;
}
- cfg.t.cfg.s.inDLSAP.numRstInd = 255;
- cfg.t.cfg.s.inDLSAP.ackOpt = TRUE;
+ cfg.t.cfg.s.inDLSAP.numRstInd = 255;
cfg.t.cfg.s.inDLSAP.relOpt = TRUE;
#ifdef ISDN_SRV
cfg.t.cfg.s.inDLSAP.bcas = FALSE;
#endif /* ISDN_SRV */
if (signal_data->signalling == SNGISDN_SIGNALING_NET) {
+ cfg.t.cfg.s.inDLSAP.ackOpt = TRUE;
cfg.t.cfg.s.inDLSAP.intType = NETWORK;
cfg.t.cfg.s.inDLSAP.clrGlr = FALSE; /* in case of glare, do not clear local call */
cfg.t.cfg.s.inDLSAP.statEnqOpt = TRUE;
- if (span->trunk_type == FTDM_TRUNK_BRI ||
- span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+
+ if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN ||
+ signal_data->switchtype == SNGISDN_SWITCH_INSNET) {
cfg.t.cfg.s.inDLSAP.rstOpt = FALSE;
} else {
cfg.t.cfg.s.inDLSAP.rstOpt = TRUE;
}
} else {
+ cfg.t.cfg.s.inDLSAP.ackOpt = FALSE;
cfg.t.cfg.s.inDLSAP.intType = USER;
cfg.t.cfg.s.inDLSAP.clrGlr = TRUE; /* in case of glare, clear local call */
cfg.t.cfg.s.inDLSAP.statEnqOpt = FALSE;
void stack_resp_hdr_init(Header *hdr);
ftdm_status_t sng_isdn_activate_phy(ftdm_span_t *span);
-ftdm_status_t sng_isdn_activate_q921(ftdm_span_t *span);
-ftdm_status_t sng_isdn_activate_q931(ftdm_span_t *span);
+ftdm_status_t sng_isdn_deactivate_phy(ftdm_span_t *span);
+
ftdm_status_t sng_isdn_activate_cc(ftdm_span_t *span);
ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt);
ftdm_status_t sng_isdn_stack_stop(ftdm_span_t *span);
-ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span)
+ftdm_status_t sng_isdn_stack_start(ftdm_span_t *span)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
- if (sng_isdn_activate_q921(span) != FTDM_SUCCESS) {
+
+ if (sng_isdn_cntrl_q921(span, ABND_ENA, NOTUSED) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q921\n", span->name);
return FTDM_FAIL;
}
+
+ /* 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 */
+ ftdm_sleep(500);
+
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;
ftdm_log(FTDM_LOG_DEBUG, "%s:Stack CC activated\n", span->name);
}
- if (sng_isdn_activate_q931(span) != FTDM_SUCCESS) {
+
+ if (sng_isdn_cntrl_q931(span, ABND_ENA, SAELMNT) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q931\n", span->name);
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
-ftdm_status_t sng_isdn_stack_stop(ftdm_span_t *span)
+ftdm_status_t sng_isdn_stack_stop(ftdm_span_t *span)
{
+ /* Stop L1 first, so we do not receive any more frames */
+ if (sng_isdn_deactivate_phy(span) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "%s:Failed to deactivate stack phy\n", span->name);
+ return FTDM_FAIL;
+ }
+ if (sng_isdn_cntrl_q931(span, AUBND_DIS, SAELMNT) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "%s:Failed to deactivate stack q931\n", span->name);
+ return FTDM_FAIL;
+ }
+
+ if (sng_isdn_cntrl_q921(span, AUBND_DIS, SAELMNT) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_CRIT, "%s:Failed to deactivate stack q921\n", span->name);
+ return FTDM_FAIL;
+ }
+
+ ftdm_log(FTDM_LOG_INFO, "%s:Signalling stopped\n", span->name);
return FTDM_SUCCESS;
}
ftdm_status_t sng_isdn_activate_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);
+ /* There is no need to start phy, as it will Q921 will send a activate request to phy when it starts */
+
return FTDM_SUCCESS;
}
-
-ftdm_status_t sng_isdn_activate_q921(ftdm_span_t *span)
+ftdm_status_t sng_isdn_deactivate_phy(ftdm_span_t *span)
{
- ftdm_status_t status;
- status = sng_isdn_cntrl_q921(span, ABND_ENA, NOTUSED);
+ L1Mngmt cntrl;
+ Pst pst;
- /* 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;
-}
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
-ftdm_status_t sng_isdn_activate_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);
+ /* initalize the post structure */
+ stack_pst_init(&pst);
+
+ /* insert the destination Entity */
+ pst.dstEnt = ENTL1;
+
+ /* 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 = ENTL1; /* entity */
+ cntrl.hdr.entId.inst = S_INST; /* instance */
+ cntrl.hdr.elmId.elmnt = STTSAP; /* SAP Specific cntrl */
+
+ cntrl.t.cntrl.action = AUBND_DIS;
+ cntrl.t.cntrl.subAction = SAELMNT;
+ cntrl.t.cntrl.sapId = signal_data->link_id;
+
+ if (sng_isdn_phy_cntrl(&pst, &cntrl)) {
+ return FTDM_FAIL;
+ }
+ return FTDM_SUCCESS;
}
+
ftdm_status_t sng_isdn_activate_cc(ftdm_span_t *span)
{
CcMngmt cntrl;;
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) {
+ if (sng_isdn_cntrl_q921(span, ADISIMM, SATRC) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "s%d Failed to disable q921 trace\n");
}
}
break;
}
+#if 0
+ /* Export ftdmchan variables here if we need to */
+ ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1");
+ ftdm_channel_add_var(ftdmchan, "isdn_crap", "morecrap");
+ ftdm_channel_add_var(ftdmchan, "isdn_stuff", "s");
+ ftdm_channel_add_var(ftdmchan, "isdn_d", "asdsadasdasdsad");
+#endif
/* Fill in call information */
cpy_calling_num_from_stack(&ftdmchan->caller_data, &conEvnt->cgPtyNmb);
cpy_called_num_from_stack(&ftdmchan->caller_data, &conEvnt->cdPtyNmb);
/* This is the only valid state we should get a CONNECT ACK on */
/* do nothing */
break;
+ case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+ /* We just hung up an incoming call right after we sent a CONNECT so ignore this message */
+ break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
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;
- if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending CONNECT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
cnStEvnt.chanId.chanNmbSlotMap.len = 1;
cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
}
+
+ 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; /* Not end-to-end ISDN */
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
!(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) {
ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId);
- ftdm_assert(0, "Inconsistent call states\n");
+ /* It seems that Trillium has a bug where they sometimes send release twice on a call, so do not crash on these for now */
+ /* ftdm_assert(0, "Inconsistent call states\n"); */
return;
}
/* Enqueue the event to each span within the dChan */
for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) {
signal_data = g_sngisdn_data.dchans[dChan].spans[i];
+
sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event));
ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n");
memset(sngisdn_event, 0, sizeof(*sngisdn_event));
void sngisdn_rcv_phy_ind(SuId suId, Reason reason)
{
- ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
if (reason != LL1_REASON_CON_REQ_FAIL) {
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;
- }
- }
+{
+ ftdm_span_t *ftdmspan;
+ sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[status->t.usta.lnkNmb];
+ if (!signal_data) {
+ ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb);
+ return;
}
- if (ftdmspan == NULL) {
- ftdm_log(FTDM_LOG_WARNING, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb);
+ ftdmspan = signal_data->ftdm_span;
+
+ if (!ftdmspan) {
+ ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb);
return;
}
}
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:%u)\n", status->t.usta.suId);
- return;
- }
-
- if (status->t.usta.alarm.event == LCM_EVENT_UP) {
- sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP);
- sng_isdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_UP);
- } else {
- sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN);
- sng_isdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING);
- }
- }
- break;
+ switch (status->t.usta.alarm.event) {
+ case LCM_EVENT_UP:
+ case LCM_EVENT_DOWN:
+ {
+ ftdm_span_t *ftdmspan;
+ sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[status->t.usta.suId];
+ if (!signal_data) {
+ ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.suId);
+ return;
}
- break;
+ ftdmspan = signal_data->ftdm_span;
+
+ if (status->t.usta.alarm.event == LCM_EVENT_UP) {
+ ftdm_log(FTDM_LOG_INFO, "[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);
+
+ sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP);
+ sng_isdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_UP);
+ } else {
+ 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);
+
+ sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN);
+ sng_isdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING);
+ }
+ }
+ 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;
+ 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);
}
-
-
+
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
break;
case SNG_LOGLEVEL_CRIT:
ftdm_log(FTDM_LOG_CRIT, "sng_isdn->%s", data);
- /*ftdm_assert(0, "Got an error from stack");*/
+ /* ftdm_assert(0, "Got an error from stack"); */
break;
default:
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
break;
}
+ ftdm_safe_free(data);
return;
}
return FTDM_SUCCESS;
}
-ftdm_status_t sng_isdn_set_avail_rate(ftdm_span_t *ftdmspan, sngisdn_avail_t avail)
+ftdm_status_t sng_isdn_set_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail)
{
- unsigned i;
- if (ftdmspan->trunk_type == FTDM_TRUNK_BRI ||
- ftdmspan->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+
+ if (span->trunk_type == FTDM_TRUNK_BRI ||
+ span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+
+ ftdm_iterator_t *chaniter = NULL;
+ ftdm_iterator_t *curr = NULL;
- for(i=1; i<=ftdmspan->chan_count; i++) {
- ftdm_log_chan(ftdmspan->channels[i], FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail);
- ftdmspan->channels[i]->availability_rate = avail;
+
+ chaniter = ftdm_span_get_chan_iterator(span, NULL);
+ for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
+ ftdm_log_chan(((ftdm_channel_t*)ftdm_iterator_current(curr)), FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail);
+ ((ftdm_channel_t*)ftdm_iterator_current(curr))->availability_rate = avail;
}
+ ftdm_iterator_free(chaniter);
}
return FTDM_SUCCESS;
}
return FTDM_USER_LAYER1_PROT_ULAW;
}
+void sngisdn_print_phy_stats(ftdm_stream_handle_t *stream, ftdm_span_t *span)
+{
+ L1Mngmt sts;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
+
+ memset(&sts, 0, sizeof(sts));
+ sng_isdn_phy_stats(signal_data->link_id , &sts);
+
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, " Span:%s", span->name);
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, " Performance Counters");
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, "RX Packets:\t%u\tTX Packets:\t%u\tEvents:%u\n", sts.t.sts.rx_packets, sts.t.sts.tx_packets, sts.t.sts.rx_events);
+ stream->write_function(stream, "RX Bytes:\t%u\tTX Bytes:\t%u\n\n", sts.t.sts.rx_bytes, sts.t.sts.tx_bytes);
+ stream->write_function(stream, "TX Queue:\t%u/%u\tRX Queue:\t%u/%u\tEvents Queue:\t%u/%u\n",
+ sts.t.sts.num_frames_in_tx_queue,sts.t.sts.tx_queue_len,
+ sts.t.sts.num_frames_in_rx_queue, sts.t.sts.rx_queue_len,
+ sts.t.sts.rx_events_in_queue, sts.t.sts.event_queue_len);
+
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, " Errors");
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, "RX Errors:\t%u\tTX Errors:\t%u\n", sts.t.sts.rx_errors, sts.t.sts.tx_errors);
+ stream->write_function(stream, "RX Dropped:\t%u\tTX Dropped:\t%u\tEvents Dropped:\t%u\n", sts.t.sts.rx_dropped, sts.t.sts.tx_dropped,sts.t.sts.rx_events_dropped);
+
+
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, " RX Errors Details");
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, "CRC:\t\t%u\tFrame:\t\t%u\tOverruns:\t%u\n", sts.t.sts.rx_crc_errors, sts.t.sts.rx_frame_errors, sts.t.sts.rx_over_errors);
+ stream->write_function(stream, "Fifo:\t\t%u\tAborts:\t\t%u\tMissed:\t\t%u\n", sts.t.sts.rx_fifo_errors, sts.t.sts.rx_hdlc_abort_counter, sts.t.sts.rx_missed_errors);
+ stream->write_function(stream, "Length:\t\t%u\n", sts.t.sts.rx_length_errors);
+
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, " TX Errors Details");
+ stream->write_function(stream, "\n---------------------------------------------------------------------\n");
+ stream->write_function(stream, "Aborted:\t%u\tFifo:\t\t%u\tCarrier:\t%u\n", sts.t.sts.tx_aborted_errors, sts.t.sts.tx_fifo_errors, sts.t.sts.tx_carrier_errors);
+ return;
+}
+
+
+void sngisdn_print_span(ftdm_stream_handle_t *stream, ftdm_span_t *span)
+{
+ ftdm_signaling_status_t sigstatus;
+ ftdm_alarm_flag_t alarmbits;
+ ftdm_channel_t *fchan;
+ alarmbits = FTDM_ALARM_NONE;
+ fchan = ftdm_span_get_channel(span, 1);
+ if (fchan) {
+ ftdm_channel_get_alarms(fchan, &alarmbits);
+ }
+
+ ftdm_span_get_sig_status(span, &sigstatus);
+ stream->write_function(stream, "span:%s physical:%s signalling:%s\n",
+ span->name, alarmbits ? "ALARMED" : "OK",
+ ftdm_signaling_status2str(sigstatus));
+ return;
+}
+
+void sngisdn_print_spans(ftdm_stream_handle_t *stream)
+{
+ int i;
+ for(i=1;i<=MAX_L1_LINKS;i++) {
+ if (g_sngisdn_data.spans[i]) {
+ sngisdn_print_span(stream, g_sngisdn_data.spans[i]->ftdm_span);
+ }
+ }
+ return;
+}
+
/* For Emacs:
* Local Variables:
* mode:c