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 3cf4876070..94e816e0d0 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 @@ -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; 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 0789c433f9..e9d0fdc58a 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 @@ -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; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c index d455fc06d0..f44f1032a3 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c @@ -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: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h index db33cf8083..ca6683d4e3 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h @@ -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"},