]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: Used channel iterator.
authorDavid Yat Sin <dyatsin@sangoma.com>
Wed, 8 Sep 2010 23:41:34 +0000 (19:41 -0400)
committerDavid Yat Sin <dyatsin@sangoma.com>
Tue, 14 Sep 2010 17:42:50 +0000 (13:42 -0400)
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

12 files changed:
libs/freetdm/mod_freetdm/mod_freetdm.c
libs/freetdm/src/ftdm_io.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c

index c70e0f9a653a2bf988d92d50a5c160afac478b98..b4a40f0bad222a07fc658e7912115ed6e8cd11c9 100755 (executable)
@@ -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);
 
 }
index 49b61eed69aa209976a6bcfdd654c8d9bf33fbcc..6991e9ab9b87a4cbf0fdd66eaeb323a5bef0acfd 100644 (file)
@@ -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;
index e962eceb28f6609066c7ea19759f68f64ecf3d41..08f340dc838f16360a0831770062d83094509e21 100644 (file)
@@ -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 <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();
index 5f2682852915ac51b3b486dba820105d50014471..cd96a18fce58fa500b334891092bb02f10f0736c 100644 (file)
@@ -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__ */
 
index 96eaf051a268058df895566b6d7655810ab5ee66..361b389f96283e093085c5f0a1335d2011942512 100644 (file)
@@ -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;
index 7aba6a66ce7f23ae6d3c617d49f724bfabff41d2..5060cb6bbaf57f10b9def14e489294634e4d9690 100644 (file)
@@ -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
index f84e018f1e1d33620542bc77cb7f804f1c4348a2..942c2e4531bd85d3728c5e44cc59d04086670538 100644 (file)
@@ -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;
index f92eceda5e8a4d8e4ae6cc7176d16ee5def6fcce..cea8ac017385ef9242023a15417b8e4a66c400b0 100644 (file)
@@ -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)
 {
-       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;;
@@ -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");
                                }
                        }
index ff9a53b2949d55fafc4161c4eaf77ca2315eaccb..e2e67eed1929cdf46ead4aea47140b49490e99c8 100644 (file)
@@ -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));
                                
index 6e8e0e81fd3d66557c53de139cd0cffcf8e4aa0f..80a85ceec8a62d8a5c7b02384a5ba654479347e9 100644 (file)
@@ -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)) {
index f921b1be8cc9061856c5d5800f870304a6f6c095..791c6b7d8cb601d54a51d54b39490a6c7dc2fad3 100644 (file)
@@ -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;
 }
 
index 5e37e0c68458941e4ee4eada104dd5d2661073a2..db22fe5ce8c7c19b50357f1947ea222239f092ee 100644 (file)
@@ -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) {
+
+               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;
 }
@@ -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