提交 c20f56ba authored 作者: David Yat Sin's avatar David Yat Sin

freetdm - ISDN:Fix for not responding to incoming RESTARTs with RESTART ACK if…

freetdm - ISDN:Fix for not responding to incoming RESTARTs with RESTART ACK if there is an active call on that channel at the time the RESTART was received
上级 9e3c258f
...@@ -1156,8 +1156,7 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init) ...@@ -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_fac_ind = sngisdn_rcv_fac_ind;
g_sngisdn_event_interface.cc.sng_sta_cfm = sngisdn_rcv_sta_cfm; 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_ind;
g_sngisdn_event_interface.cc.sng_srv_ind = sngisdn_rcv_srv_cfm; g_sngisdn_event_interface.cc.sng_srv_cfm = sngisdn_rcv_srv_cfm;
g_sngisdn_event_interface.cc.sng_rst_ind = sngisdn_rcv_rst_cfm;
g_sngisdn_event_interface.cc.sng_rst_ind = sngisdn_rcv_rst_ind; g_sngisdn_event_interface.cc.sng_rst_ind = sngisdn_rcv_rst_ind;
g_sngisdn_event_interface.cc.sng_rst_cfm = sngisdn_rcv_rst_cfm; g_sngisdn_event_interface.cc.sng_rst_cfm = sngisdn_rcv_rst_cfm;
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "ftmod_sangoma_isdn.h" #include "ftmod_sangoma_isdn.h"
static ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn); 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 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 */ /* Remote side transmit a SETUP */
void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) 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) ...@@ -191,8 +192,7 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
strcpy(ftdmchan->caller_data.cid_name, retrieved_str); strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
} }
} }
#endif #endif
if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) { if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
} else { } else {
...@@ -920,36 +920,8 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) ...@@ -920,36 +920,8 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
switch(call_state) { switch(call_state) {
/* Sere ITU-T Q931 for definition of call states */ /* Sere ITU-T Q931 for definition of call states */
case 0: /* Remote switch thinks there are no calls on this channel */ case 0: /* Remote switch thinks there are no calls on this channel */
switch (ftdmchan->state) { if (sngisdn_force_down(ftdmchan) != FTDM_SUCCESS) {
case FTDM_CHANNEL_STATE_COLLECT: 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));
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;
} }
break; break;
case 1: case 1:
...@@ -1159,6 +1131,49 @@ static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan) ...@@ -1159,6 +1131,49 @@ static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan)
return; 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) 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) ...@@ -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]; sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[dChan].spans[1];
if (!signal_data) { 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; return;
} }
if (!rstEvnt->rstInd.eh.pres || !rstEvnt->rstInd.rstClass.pres) { if (rstEvnt->rstInd.eh.pres != PRSNT_NODEF && rstEvnt->rstInd.rstClass.pres != PRSNT_NODEF) {
ftdm_log(FTDM_LOG_DEBUG, "Receved RESTART, but Restart Indicator IE not present\n"); ftdm_log(FTDM_LOG_DEBUG, "Received RESTART, but Restart Indicator IE not present\n");
return; return;
} }
...@@ -1233,8 +1248,11 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event) ...@@ -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) void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
{ {
uint8_t chan_no = 0;
int16_t suId = sngisdn_event->suId; int16_t suId = sngisdn_event->suId;
int16_t dChan = sngisdn_event->dChan; int16_t dChan = sngisdn_event->dChan;
uint8_t ces = sngisdn_event->ces; uint8_t ces = sngisdn_event->ces;
...@@ -1242,15 +1260,82 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event) ...@@ -1242,15 +1260,82 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
ISDN_FUNC_TRACE_ENTER(__FUNCTION__); ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
/* Function does not require any info from ssHlEvnt struct for now */ Rst *rstEvnt = &sngisdn_event->event.rstEvnt;
/*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_DEBUG, "Processing RESTART CFM (suId:%u dChan:%d ces:%d %s)\n", suId, dChan, ces, 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_DWN)?"LNK_DOWN":
(evntType == IN_LNK_UP)?"LNK_UP": (evntType == IN_LNK_UP)?"LNK_UP":
(evntType == IN_INDCHAN)?"b-channel": (evntType == IN_INDCHAN)?"b-channel":
(evntType == IN_LNK_DWN_DM_RLS)?"NFAS service procedures": (evntType == IN_LNK_DWN_DM_RLS)?"NFAS service procedures":
(evntType == IN_SWCHD_BU_DCHAN)?"NFAS switchover to backup":"Unknown"); (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__); ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return; return;
} }
......
...@@ -757,7 +757,7 @@ void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_ ...@@ -757,7 +757,7 @@ void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_
{ {
uint32_t k; uint32_t k;
*str_len += sprintf(&str[*str_len], " [ "); *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)) { if (k && !(k%32)) {
*str_len += sprintf(&str[*str_len], "\n "); *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_ ...@@ -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_USER_INFO:
case PROT_Q931_MSGTYPE_DISCONNECT: case PROT_Q931_MSGTYPE_DISCONNECT:
case PROT_Q931_MSGTYPE_RELEASE: 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_RELEASE_COMPLETE:
case PROT_Q931_MSGTYPE_FACILITY: case PROT_Q931_MSGTYPE_FACILITY:
case PROT_Q931_MSGTYPE_NOTIFY: case PROT_Q931_MSGTYPE_NOTIFY:
......
...@@ -211,7 +211,7 @@ struct code2str dcodQ931CallRefLoTable[] = { ...@@ -211,7 +211,7 @@ struct code2str dcodQ931CallRefLoTable[] = {
#define PROT_Q931_MSGTYPE_DISCONNECT 69 #define PROT_Q931_MSGTYPE_DISCONNECT 69
#define PROT_Q931_MSGTYPE_RESTART 70 #define PROT_Q931_MSGTYPE_RESTART 70
#define PROT_Q931_MSGTYPE_RELEASE 77 #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_RELEASE_COMPLETE 90
#define PROT_Q931_MSGTYPE_SEGMENT 96 #define PROT_Q931_MSGTYPE_SEGMENT 96
#define PROT_Q931_MSGTYPE_FACILITY 98 #define PROT_Q931_MSGTYPE_FACILITY 98
...@@ -240,7 +240,7 @@ struct code2str dcodQ931MsgTypeTable[] = { ...@@ -240,7 +240,7 @@ struct code2str dcodQ931MsgTypeTable[] = {
{PROT_Q931_MSGTYPE_DISCONNECT, "DISCONNECT"}, {PROT_Q931_MSGTYPE_DISCONNECT, "DISCONNECT"},
{PROT_Q931_MSGTYPE_RESTART, "RESTART"}, {PROT_Q931_MSGTYPE_RESTART, "RESTART"},
{PROT_Q931_MSGTYPE_RELEASE, "RELEASE"}, {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_RELEASE_COMPLETE, "RELEASE COMPLETE"},
{PROT_Q931_MSGTYPE_SEGMENT, "SEGMENT"}, {PROT_Q931_MSGTYPE_SEGMENT, "SEGMENT"},
{PROT_Q931_MSGTYPE_FACILITY, "FACILITY"}, {PROT_Q931_MSGTYPE_FACILITY, "FACILITY"},
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论