]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm - ISDN:Fix for not responding to incoming RESTARTs with RESTART ACK if there...
authorDavid Yat Sin <dyatsin@sangoma.com>
Fri, 27 May 2011 16:18:06 +0000 (12:18 -0400)
committerDavid Yat Sin <dyatsin@sangoma.com>
Fri, 27 May 2011 16:19:15 +0000 (12:19 -0400)
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h

index 3cf4876070c3bb8b17eaa49d7ec1eb1ed3fe89fb..94e816e0d0deb13d48f3e5684267acec17a44bea 100644 (file)
@@ -1156,8 +1156,7 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init)
        g_sngisdn_event_interface.cc.sng_fac_ind        = sngisdn_rcv_fac_ind;
        g_sngisdn_event_interface.cc.sng_sta_cfm        = sngisdn_rcv_sta_cfm;
        g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_ind;
-       g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_cfm;
-       g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_cfm;
+       g_sngisdn_event_interface.cc.sng_srv_cfm        = sngisdn_rcv_srv_cfm;
        g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_ind;
        g_sngisdn_event_interface.cc.sng_rst_cfm        = sngisdn_rcv_rst_cfm;
 
index 0789c433f94744a0318334f1217d0bd5481fce94..e9d0fdc58aaa229c7c2b2087ffd6a37dbda5c31e 100644 (file)
@@ -35,6 +35,7 @@
 #include "ftmod_sangoma_isdn.h"
 static ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn);
 static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan);
+static ftdm_status_t sngisdn_force_down(ftdm_channel_t *ftdmchan);
 
 /* Remote side transmit a SETUP */
 void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
@@ -191,8 +192,7 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
                                        strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
                                }
                        }
-#endif
-                       
+#endif                 
                        if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) {
                                ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
                        } else {
@@ -920,36 +920,8 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
                switch(call_state) {
                        /* Sere ITU-T Q931 for definition of call states */
                        case 0: /* Remote switch thinks there are no calls on this channel */
-                               switch (ftdmchan->state) {
-                                       case FTDM_CHANNEL_STATE_COLLECT:
-                                       case FTDM_CHANNEL_STATE_DIALING:
-                                       case FTDM_CHANNEL_STATE_UP:
-                                               sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
-                                               ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
-                                               break;
-                                       case FTDM_CHANNEL_STATE_TERMINATING:
-                                               /* We are in the process of clearing local states,
-                                               just make sure we will not send any messages to remote switch */
-                                               sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
-                                               break;
-                                       case FTDM_CHANNEL_STATE_HANGUP:
-                                               /* This cannot happen, state_advance always sets
-                                               ftdmchan to STATE_HANGUP_COMPLETE when in STATE_HANGUP
-                                               and we called check_for_state_change earlier so something is very wrong here!!! */
-                                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "How can we we in FTDM_CHANNEL_STATE_HANGUP after checking for state change?\n");
-                                               ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
-                                               break;
-                                       case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
-                                               /* We were waiting for remote switch to send RELEASE COMPLETE
-                                               but this will not happen, so just clear local state */
-                                               ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
-                                               break;
-                                       case FTDM_CHANNEL_STATE_DOWN:
-                                               /* If our local state is down as well, then there is nothing to do */
-                                               break;
-                                       default:
-                                               ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
-                                               break;
+                               if (sngisdn_force_down(ftdmchan) != FTDM_SUCCESS) {
+                                       ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
                                }
                                break;
                        case 1:
@@ -1159,6 +1131,49 @@ static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan)
        return;
 }
 
+static ftdm_status_t sngisdn_force_down(ftdm_channel_t *ftdmchan)
+{
+       sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
+       
+       ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Forcing channel to DOWN state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
+       
+       ftdm_status_t status = FTDM_SUCCESS;
+       switch (ftdmchan->state) {
+               case FTDM_CHANNEL_STATE_DOWN:
+                       /* Do nothing */
+                       break;
+               case FTDM_CHANNEL_STATE_RESET:
+                       ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+                       break;
+               case FTDM_CHANNEL_STATE_COLLECT:
+               case FTDM_CHANNEL_STATE_DIALING:
+               case FTDM_CHANNEL_STATE_UP:
+                       sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT);
+                       ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+                       break;
+               case FTDM_CHANNEL_STATE_TERMINATING:
+                       /* We are already waiting for usr to respond to SIGEVENT stop.
+                               FreeTDM already scheduled a timout in case the User does respond to
+                               SIGEVENT_STOP, no need to do anything here */                   
+                       break;
+               case FTDM_CHANNEL_STATE_HANGUP:
+                       /* This cannot happen, state_advance always sets
+                       ftdmchan to STATE_HANGUP_COMPLETE when in STATE_HANGUP
+                       and we called check_for_state_change earlier so something is very wrong here!!! */
+                       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "How can we we in FTDM_CHANNEL_STATE_HANGUP after checking for state change?\n");
+                       ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+                       break;
+               case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+                       /* We were waiting for remote switch to send RELEASE COMPLETE
+                       but this will not happen, so just clear local state */
+                       ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+                       break;
+               default:
+                       status = FTDM_FAIL;
+
+       }
+       return status;
+}
 
 void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
 {
@@ -1171,12 +1186,12 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
        
        sngisdn_span_data_t     *signal_data = g_sngisdn_data.dchans[dChan].spans[1];
        if (!signal_data) {
-               ftdm_log(FTDM_LOG_CRIT, "Received RESTART on unconfigured span (suId:%d)\n", suId);
+               ftdm_log(FTDM_LOG_CRIT, "Received RESTART CFM on unconfigured span (suId:%d)\n", suId);
                return;
        }
        
-       if (!rstEvnt->rstInd.eh.pres || !rstEvnt->rstInd.rstClass.pres) {
-               ftdm_log(FTDM_LOG_DEBUG, "Receved RESTART, but Restart Indicator IE not present\n");
+       if (rstEvnt->rstInd.eh.pres != PRSNT_NODEF && rstEvnt->rstInd.rstClass.pres != PRSNT_NODEF) {
+               ftdm_log(FTDM_LOG_DEBUG, "Received RESTART, but Restart Indicator IE not present\n");
                return;
        }
                
@@ -1233,8 +1248,11 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
 }
 
 
+/* The remote side sent us a RESTART Msg. Trillium automatically acks with RESTART ACK, but
+       we need to clear our call states if there is a call on this channel */
 void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
 {
+       uint8_t chan_no = 0;
        int16_t suId = sngisdn_event->suId;
        int16_t dChan = sngisdn_event->dChan;
        uint8_t ces = sngisdn_event->ces;
@@ -1242,15 +1260,82 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
 
        ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
 
-       /* Function does not require any info from ssHlEvnt struct for now */
-       /*Rst *rstEvnt = &sngisdn_event->event.rstEvnt;*/
-               
-       ftdm_log(FTDM_LOG_DEBUG, "Processing RESTART CFM (suId:%u dChan:%d ces:%d %s)\n", suId, dChan, ces,
+       Rst *rstEvnt = &sngisdn_event->event.rstEvnt;
+       sngisdn_span_data_t     *signal_data = g_sngisdn_data.dchans[dChan].spans[1];
+       if (!signal_data) {
+               ftdm_log(FTDM_LOG_CRIT, "Received RESTART IND on unconfigured span (suId:%d)\n", suId);
+               return;
+       }
+       
+       ftdm_log(FTDM_LOG_DEBUG, "Processing RESTART IND (suId:%u dChan:%d ces:%d %s)\n", suId, dChan, ces,
                                                                                                        (evntType == IN_LNK_DWN)?"LNK_DOWN":
                                                                                                        (evntType == IN_LNK_UP)?"LNK_UP":
                                                                                                        (evntType == IN_INDCHAN)?"b-channel":
                                                                                                        (evntType == IN_LNK_DWN_DM_RLS)?"NFAS service procedures":
                                                                                                        (evntType == IN_SWCHD_BU_DCHAN)?"NFAS switchover to backup":"Unknown");
+
+       if (!rstEvnt->rstInd.eh.pres || !rstEvnt->rstInd.rstClass.pres) {
+               ftdm_log(FTDM_LOG_DEBUG, "Received RESTART IND, but Restart Indicator IE not present\n");
+               return;
+       }
+
+       switch(rstEvnt->rstInd.rstClass.val) {
+               case IN_CL_INDCHAN: /* Indicated b-channel */
+                       if (rstEvnt->chanId.eh.pres) {
+                               if (rstEvnt->chanId.intType.val == IN_IT_BASIC) {
+                                       if (rstEvnt->chanId.infoChanSel.pres == PRSNT_NODEF) {
+                                               chan_no = rstEvnt->chanId.infoChanSel.val;
+                                       }
+                               } else if (rstEvnt->chanId.intType.val == IN_IT_OTHER) {
+                                       if (rstEvnt->chanId.chanNmbSlotMap.pres == PRSNT_NODEF) {
+                                               chan_no = rstEvnt->chanId.chanNmbSlotMap.val[0];
+                                       }
+                               }
+                       }
+                       if (!chan_no) {
+                               ftdm_log(FTDM_LOG_CRIT, "Failed to determine channel from RESTART\n");
+                               return;
+                       }
+                       break;
+               case IN_CL_SNGINT: /* Single interface */
+               case IN_CL_ALLINT: /* All interfaces */
+                       /* In case restart class indicates all interfaces, we will duplicate
+                                       this event on each span associated to this d-channel in sngisdn_rcv_rst_cfm,
+                                       so treat it as a single interface anyway */
+                       break;
+               default:
+                       ftdm_log(FTDM_LOG_CRIT, "Invalid restart indicator class:%d\n", rstEvnt->rstInd.rstClass.val);
+                       return;
+       }
+
+       if (chan_no) { /* For a single channel */
+               if (chan_no > ftdm_span_get_chan_count(signal_data->ftdm_span)) {
+                       ftdm_log(FTDM_LOG_CRIT, "Received RESTART IND on invalid channel:%d\n", chan_no);
+               } else {
+                       ftdm_iterator_t *chaniter = NULL;
+                       ftdm_iterator_t *curr = NULL;
+                       
+                       chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
+                       for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {                  
+                               ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
+                               if (ftdmchan->physical_chan_id == chan_no) {
+                                       sngisdn_force_down(ftdmchan);
+                               }
+                       }
+                       ftdm_iterator_free(chaniter);
+               }
+       } else { /* for all channels */
+               ftdm_iterator_t *chaniter = NULL;
+               ftdm_iterator_t *curr = NULL;
+
+               chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
+               for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
+                       sngisdn_force_down((ftdm_channel_t*)ftdm_iterator_current(curr));
+               }
+               ftdm_iterator_free(chaniter);
+       }
+
+       
        ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
        return;
 }
index d455fc06d04bb9e4de9ee248296d3b8b8e7939e1..f44f1032a3db54a7241f05ce11cc672cd6cade19 100644 (file)
@@ -757,7 +757,7 @@ void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_
 {
        uint32_t k;
        *str_len += sprintf(&str[*str_len], "  [ ");
-       for(k=index_start; k <= index_end; k++) {
+       for(k=index_start; k < index_end; k++) {
                if (k && !(k%32)) {
                        *str_len += sprintf(&str[*str_len], "\n    ");
                }
@@ -917,7 +917,7 @@ static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_
                case PROT_Q931_MSGTYPE_USER_INFO:
                case PROT_Q931_MSGTYPE_DISCONNECT:
                case PROT_Q931_MSGTYPE_RELEASE:
-               case PROT_Q931_MSGTYPE_RELEASE_ACK:
+               case PROT_Q931_MSGTYPE_RESTART_ACK:
                case PROT_Q931_MSGTYPE_RELEASE_COMPLETE:
                case PROT_Q931_MSGTYPE_FACILITY:
                case PROT_Q931_MSGTYPE_NOTIFY:
index db33cf8083b617c41053a6446bf45bddeef3b403..ca6683d4e343570012f9984deebf4da6c0f38186 100644 (file)
@@ -211,7 +211,7 @@ struct code2str dcodQ931CallRefLoTable[] = {
 #define PROT_Q931_MSGTYPE_DISCONNECT           69
 #define PROT_Q931_MSGTYPE_RESTART                      70
 #define PROT_Q931_MSGTYPE_RELEASE                      77
-#define PROT_Q931_MSGTYPE_RELEASE_ACK          78
+#define PROT_Q931_MSGTYPE_RESTART_ACK          78
 #define PROT_Q931_MSGTYPE_RELEASE_COMPLETE     90
 #define PROT_Q931_MSGTYPE_SEGMENT                      96
 #define PROT_Q931_MSGTYPE_FACILITY                     98
@@ -240,7 +240,7 @@ struct code2str dcodQ931MsgTypeTable[] = {
        {PROT_Q931_MSGTYPE_DISCONNECT, "DISCONNECT"},
        {PROT_Q931_MSGTYPE_RESTART, "RESTART"},
        {PROT_Q931_MSGTYPE_RELEASE, "RELEASE"},
-       {PROT_Q931_MSGTYPE_RELEASE_ACK, "RELEASR ACK"},
+       {PROT_Q931_MSGTYPE_RESTART_ACK, "RESTART ACK"},
        {PROT_Q931_MSGTYPE_RELEASE_COMPLETE, "RELEASE COMPLETE"},
        {PROT_Q931_MSGTYPE_SEGMENT, "SEGMENT"},
        {PROT_Q931_MSGTYPE_FACILITY, "FACILITY"},