From c91d81a483232d0592502b94afa3468c26e79123 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 30 Sep 2010 11:41:47 -0400 Subject: [PATCH] Fix for not handling a call state Fix for MSN on BRI --- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.c | 15 ++++-- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.h | 7 ++- .../ftmod_sangoma_isdn_cfg.c | 18 +++++++ .../ftmod_sangoma_isdn_stack_hndl.c | 54 +++++++++++++++---- .../ftmod_sangoma_isdn_stack_rcv.c | 2 +- .../ftmod_sangoma_isdn_support.c | 6 ++- 6 files changed, 83 insertions(+), 19 deletions(-) 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 08f340dc83..0ed5902153 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 @@ -726,7 +726,7 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status) } 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_start(span) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name); @@ -747,9 +747,11 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) } static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) -{ +{ ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *curr = NULL; + unsigned i; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; ftdm_log(FTDM_LOG_INFO, "Stopping span %s\n", span->name); /* throw the STOP_THREAD flag to signal monitor thread stop */ @@ -772,8 +774,13 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) } 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_sched_destroy(&signal_data->sched); + ftdm_queue_destroy(&signal_data->event_queue); + for (i = 0 ; i < signal_data->num_local_numbers ; i++) { + if (signal_data->local_numbers[i] != NULL) { + ftdm_safe_free(signal_data->local_numbers[i]); + } + } ftdm_safe_free(span->signal_data); ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s\n", span->name); 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 ae6c0d92f7..bc928354a7 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 @@ -55,6 +55,7 @@ #define NUM_BRI_CHANNELS_PER_SPAN 2 #define SNGISDN_EVENT_QUEUE_SIZE 100 #define SNGISDN_EVENT_POLL_RATE 100 +#define SNGISDN_NUM_LOCAL_NUMBERS 8 /* TODO: rename all *_cc_* to *_an_* */ @@ -161,7 +162,7 @@ typedef struct sngisdn_chan_data { /* Span specific data */ typedef struct sngisdn_span_data { - ftdm_span_t *ftdm_span; + ftdm_span_t *ftdm_span; uint8_t link_id; uint8_t switchtype; uint8_t signalling; /* SNGISDN_SIGNALING_CPE or SNGISDN_SIGNALING_NET */ @@ -175,7 +176,9 @@ typedef struct sngisdn_span_data { uint8_t setup_arb; uint8_t facility; int8_t facility_timeout; - ftdm_sched_t *sched; + uint8_t num_local_numbers; + char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS]; + ftdm_sched_t *sched; ftdm_queue_t *event_queue; } sngisdn_span_data_t; 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 361b389f96..64d7a2403f 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 @@ -36,9 +36,23 @@ ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span); ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span); +ftdm_status_t add_local_number(const char* val, ftdm_span_t *span); extern ftdm_sngisdn_data_t g_sngisdn_data; +ftdm_status_t add_local_number(const char* val, ftdm_span_t *span) +{ + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; + + if (signal_data->num_local_numbers >= SNGISDN_NUM_LOCAL_NUMBERS) { + ftdm_log(FTDM_LOG_ERROR, "%s: Maximum number of local-numbers exceeded (max:%d)\n", span->name, SNGISDN_NUM_LOCAL_NUMBERS); + return FTDM_FAIL; + } + + signal_data->local_numbers[signal_data->num_local_numbers++] = ftdm_strdup(val); + return FTDM_SUCCESS; +} + ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span) { unsigned i; @@ -253,6 +267,10 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ ftdm_span_set_bearer_capability(val, &span->default_caller_data.bearer_capability); } else if (!strcasecmp(var, "outbound-bearer_layer1")) { ftdm_span_set_bearer_layer1(val, &span->default_caller_data.bearer_layer1); + } else if (!strcasecmp(var, "local-number")) { + if (add_local_number(val, span) != FTDM_SUCCESS) { + return FTDM_FAIL; + } } else if (!strcasecmp(var, "facility-timeout")) { signal_data->facility_timeout = atoi(val); if (signal_data->facility_timeout < 0) { 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 b7af8e98c5..827647f1f6 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 @@ -43,7 +43,7 @@ extern ftdm_status_t cpy_calling_name_from_stack(ftdm_caller_data_t *ftdm, Displ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - + unsigned i; int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -57,7 +57,7 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); - + switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: /* Proper state to receive a SETUP */ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE) || @@ -80,11 +80,35 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_info->suInstId = get_unique_suInstId(suId); sngisdn_info->spInstId = spInstId; + if (conEvnt->cdPtyNmb.eh.pres && signal_data->num_local_numbers) { + uint8_t local_number_matched = 0; + for (i = 0 ; i < signal_data->num_local_numbers ; i++) { + if (!strcmp(signal_data->local_numbers[i], (char*)conEvnt->cdPtyNmb.nmbDigits.val)) { + local_number_matched++; + break; + } + } + if (!local_number_matched) { + ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received SETUP, but local-number %s does not match - ignoring\n", conEvnt->cdPtyNmb.nmbDigits.val); + /* Special case to tell the stack to clear all internal resources about this call. We will no receive any event for this call after sending disconnect request */ + ftdmchan->caller_data.hangup_cause = IN_CCNORTTODEST; + ftdm_sched_timer(signal_data->sched, "delayed_disconnect", 1, sngisdn_delayed_disconnect, (void*) sngisdn_info, NULL); + return; + } + } + /* If this is a glared call that was previously saved, we moved all the info to the current call, so clear the glared saved data */ if (sngisdn_info->glare.spInstId == spInstId) { clear_call_glare_data(sngisdn_info); - } + } + + + if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) { + if (signal_data->signalling == SNGISDN_SIGNALING_NET) { + sngisdn_info->ces = ces; + } + } ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); g_sngisdn_data.ccs[suId].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info; @@ -92,11 +116,6 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND); - if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP && - signal_data->signalling == SNGISDN_SIGNALING_NET) { - sngisdn_info->ces = ces; - } - /* try to open the channel */ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to open channel"); @@ -122,14 +141,13 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdmchan->caller_data.bearer_layer1 = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].usrInfoLyr1Prot.val); ftdmchan->caller_data.bearer_capability = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].infoTranCap.val); } - + if (signal_data->switchtype == SNGISDN_SWITCH_NI2) { if (conEvnt->shift11.eh.pres && conEvnt->ni2OctStr.eh.pres) { if (conEvnt->ni2OctStr.str.len == 4 && conEvnt->ni2OctStr.str.val[0] == 0x37) { snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", conEvnt->ni2OctStr.str.val[3]); } } - if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) { /* Verify whether the Caller Name will come in a subsequent FACILITY message */ @@ -260,6 +278,10 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) case FTDM_CHANNEL_STATE_DIALING: ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); break; + case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: + case FTDM_CHANNEL_STATE_HANGUP: + /* Race condition, we just hung up the call - 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)); @@ -274,7 +296,7 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) /* 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 */ + /* Race condition, We just hung up an incoming call right after we sent a CONNECT - 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)); @@ -923,6 +945,16 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) break; } break; + case 12: /* We received a disconnect indication */ + switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_TERMINATING: + /* We are already waiting for user app to handle the disconnect, do nothing */ + 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; case 22: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: 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 791c6b7d8c..9bf60537fe 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 @@ -706,7 +706,7 @@ void sngisdn_rcv_q931_ind(InMngmt *status) 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); + ftdm_log(FTDM_LOG_INFO, "Received q931 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.suId); return; } ftdmspan = signal_data->ftdm_span; 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 db22fe5ce8..691e3104c0 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 @@ -424,11 +424,15 @@ void sngisdn_delayed_disconnect(void* p_sngisdn_info) sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; ftdm_mutex_lock(ftdmchan->mutex); - if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { + if (ftdmchan->caller_data.hangup_cause == IN_CCNORTTODEST || ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending delayed DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->glare.spInstId, sngisdn_info->glare.suInstId); sngisdn_snd_disconnect(ftdmchan); + if (ftdmchan->caller_data.hangup_cause == IN_CCNORTTODEST) { + ftdm_channel_t *close_chan = ftdmchan; + ftdm_channel_close(&close_chan); + } } ftdm_mutex_unlock(ftdmchan->mutex);