diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index c70e0f9a65..b4a40f0bad 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2182,9 +2182,8 @@ static void ftdm_logger(const char *file, const char *func, int line, int level, 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); } diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 49b61eed69..6991e9ab9b 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -463,6 +463,7 @@ static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span) status = FTDM_FAIL; } ftdm_safe_free(span->type); + ftdm_safe_free(span->name); ftdm_safe_free(span->dtmf_hangup); } @@ -536,7 +537,7 @@ static void ftdm_span_add(ftdm_span_t *span) } 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); } @@ -3550,12 +3551,20 @@ static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t 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; } @@ -4837,11 +4846,13 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void) 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; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c index e962eceb28..08f340dc83 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -472,10 +472,7 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) 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); @@ -694,7 +691,7 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_isdn_outgoing_call) 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; @@ -705,17 +702,34 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_sig_status) 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 */ @@ -734,7 +748,8 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) 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 */ @@ -746,11 +761,19 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) 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); @@ -760,6 +783,9 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) 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); @@ -767,13 +793,15 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) 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"); @@ -792,8 +820,10 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) 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); @@ -855,7 +885,7 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init) 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; @@ -923,16 +953,35 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api) if (!strcasecmp(argv[0], "l1_stats")) { ftdm_span_t *span; if (argc < 2) { - ftdm_log(FTDM_LOG_ERROR, "Usage: ftdm sangoma_isdn l1_stats \n"); + stream->write_function(stream, "Usage: ftdm sangoma_isdn l1_stats \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; } - /* TODO: implement PHY stats */ + 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; + } + sngisdn_print_spans(stream); } if (!strcasecmp(argv[0], "check_ids")) { sngisdn_check_free_ids(); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index 5f26828529..cd96a18fce 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -243,7 +243,8 @@ typedef struct ftdm_sngisdn_data { 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; @@ -363,9 +364,12 @@ void sngisdn_facility_timeout(void* p_sngisdn_info); /* 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__ */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index 96eaf051a2..361b389f96 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -62,7 +62,8 @@ ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span) } 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; @@ -116,6 +117,8 @@ ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span) 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); @@ -163,6 +166,7 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ 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 */ @@ -258,7 +262,7 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ 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; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c index 7aba6a66ce..5060cb6bba 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c @@ -35,7 +35,6 @@ #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) @@ -53,23 +52,21 @@ void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_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 diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c index f84e018f1e..942c2e4531 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c @@ -656,8 +656,7 @@ ftdm_status_t sng_isdn_stack_cfg_q931_dlsap(ftdm_span_t *span) 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; @@ -666,16 +665,19 @@ ftdm_status_t sng_isdn_stack_cfg_q931_dlsap(ftdm_span_t *span) #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; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c index f92eceda5e..cea8ac0173 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c @@ -38,8 +38,8 @@ 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); @@ -52,14 +52,23 @@ extern ftdm_sngisdn_data_t g_sngisdn_data; 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; @@ -70,7 +79,8 @@ ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span) 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; } @@ -80,50 +90,72 @@ ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span) 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) +{ + + /* 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_deactivate_phy(ftdm_span_t *span) { L1Mngmt cntrl; - Pst pst; + Pst pst; - ftdm_log(FTDM_LOG_ERROR, "%s:PHY control not implemented\n", span->name); - return FTDM_SUCCESS; - /* TODO: phy cntrl not implemented yet */ + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; - sng_isdn_phy_cntrl(&pst, &cntrl); + /* 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_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_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); -} - ftdm_status_t sng_isdn_activate_cc(ftdm_span_t *span) { CcMngmt cntrl;; @@ -167,7 +199,7 @@ ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t tra 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"); } } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index ff9a53b294..e2e67eed19 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -106,6 +106,13 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) 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); @@ -267,6 +274,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) /* 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)); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c index 6e8e0e81fd..80a85ceec8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c @@ -409,7 +409,7 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan) 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); @@ -450,6 +450,14 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan) 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)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index f921b1be8c..791c6b7d8c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -239,7 +239,8 @@ void sngisdn_rcv_rel_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Re !(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; } @@ -591,6 +592,7 @@ void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces /* 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)); @@ -640,30 +642,24 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces 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; } @@ -694,69 +690,56 @@ void sngisdn_rcv_q921_ind(BdMngmt *status) } 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; } @@ -902,12 +885,13 @@ void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...) 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; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index 5e37e0c684..db22fe5ce8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -134,16 +134,22 @@ ftdm_status_t __inline__ get_ftdmchan_by_spInstId(uint8_t cc_id, uint32_t spInst 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) { - 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; + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; + + + 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; } @@ -554,6 +560,77 @@ ftdm_user_layer1_prot_t sngisdn_get_usrInfoLyr1Prot_from_user(uint8_t layer1_pro 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