1841 lines
60 KiB
C
1841 lines
60 KiB
C
/*
|
|
* Copyright (c) 2009, Konrad Hammel <konrad@sangoma.com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* * Neither the name of the original author; nor the names of any contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/* INCLUDE ********************************************************************/
|
|
#include "ftmod_sangoma_ss7_main.h"
|
|
/******************************************************************************/
|
|
|
|
/* DEFINES ********************************************************************/
|
|
/******************************************************************************/
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
uint32_t sngss7_id;
|
|
/******************************************************************************/
|
|
|
|
/* PROTOTYPES *****************************************************************/
|
|
int check_for_state_change(ftdm_channel_t *ftdmchan);
|
|
int check_cics_in_range(sngss7_chan_data_t *sngss7_info);
|
|
int check_for_reset(sngss7_chan_data_t *sngss7_info);
|
|
|
|
unsigned long get_unique_id(void);
|
|
|
|
ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan);
|
|
|
|
ftdm_status_t check_if_rx_grs_started(ftdm_span_t *ftdmspan);
|
|
ftdm_status_t check_if_rx_grs_processed(ftdm_span_t *ftdmspan);
|
|
ftdm_status_t check_if_rx_gra_started(ftdm_span_t *ftdmspan);
|
|
ftdm_status_t check_for_res_sus_flag(ftdm_span_t *ftdmspan);
|
|
|
|
ftdm_status_t process_span_ucic(ftdm_span_t *ftdmspan);
|
|
|
|
ftdm_status_t clear_rx_grs_flags(sngss7_chan_data_t *sngss7_info);
|
|
ftdm_status_t clear_tx_grs_flags(sngss7_chan_data_t *sngss7_info);
|
|
ftdm_status_t clear_rx_rsc_flags(sngss7_chan_data_t *sngss7_info);
|
|
ftdm_status_t clear_tx_rsc_flags(sngss7_chan_data_t *sngss7_info);
|
|
ftdm_status_t clear_rx_grs_data(sngss7_chan_data_t *sngss7_info);
|
|
ftdm_status_t clear_rx_gra_data(sngss7_chan_data_t *sngss7_info);
|
|
ftdm_status_t clear_tx_grs_data(sngss7_chan_data_t *sngss7_info);
|
|
|
|
ftdm_status_t encode_subAddrIE_nsap(const char *subAddr, char *subAddrIE, int type);
|
|
ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int type);
|
|
|
|
int find_mtp2_error_type_in_map(const char *err_type);
|
|
int find_link_type_in_map(const char *linkType);
|
|
int find_switch_type_in_map(const char *switchType);
|
|
int find_ssf_type_in_map(const char *ssfType);
|
|
int find_cic_cntrl_in_map(const char *cntrlType);
|
|
|
|
ftdm_status_t check_status_of_all_isup_intf(void);
|
|
ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan);
|
|
|
|
void sngss7_send_signal(sngss7_chan_data_t *sngss7_info, ftdm_signal_event_t event_id);
|
|
void sngss7_set_sig_status(sngss7_chan_data_t *sngss7_info, ftdm_signaling_status_t status);
|
|
ftdm_status_t sngss7_add_var(sngss7_chan_data_t *ss7_info, const char* var, const char* val);
|
|
ftdm_status_t sngss7_add_raw_data(sngss7_chan_data_t *sngss7_info, uint8_t* data, ftdm_size_t data_len);
|
|
/******************************************************************************/
|
|
|
|
FTDM_ENUM_NAMES(CKT_FLAGS_NAMES, CKT_FLAGS_STRING)
|
|
FTDM_STR2ENUM(ftmod_ss7_ckt_state2flag, ftmod_ss7_ckt_flag2str, sng_ckt_flag_t, CKT_FLAGS_NAMES, 31)
|
|
|
|
FTDM_ENUM_NAMES(BLK_FLAGS_NAMES, BLK_FLAGS_STRING)
|
|
FTDM_STR2ENUM(ftmod_ss7_blk_state2flag, ftmod_ss7_blk_flag2str, sng_ckt_block_flag_t, BLK_FLAGS_NAMES, 31)
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
ftdm_status_t copy_cgPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cgPtyNum)
|
|
{
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
ftdm_status_t copy_cgPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cgPtyNum)
|
|
{
|
|
const char *val;
|
|
|
|
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
|
|
|
|
cgPtyNum->eh.pres = PRSNT_NODEF;
|
|
|
|
cgPtyNum->natAddrInd.pres = PRSNT_NODEF;
|
|
cgPtyNum->natAddrInd.val = 0x03;
|
|
|
|
|
|
cgPtyNum->scrnInd.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_screen_ind");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
cgPtyNum->scrnInd.val = atoi(val);
|
|
} else {
|
|
cgPtyNum->scrnInd.val = caller_data->screen;
|
|
}
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Screening Ind %d\n", cgPtyNum->scrnInd.val);
|
|
|
|
cgPtyNum->presRest.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_pres_ind");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
cgPtyNum->presRest.val = atoi(val);
|
|
} else {
|
|
cgPtyNum->presRest.val = caller_data->pres;
|
|
}
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", cgPtyNum->presRest.val);
|
|
|
|
cgPtyNum->numPlan.pres = PRSNT_NODEF;
|
|
cgPtyNum->numPlan.val = 0x01;
|
|
|
|
cgPtyNum->niInd.pres = PRSNT_NODEF;
|
|
cgPtyNum->niInd.val = 0x00;
|
|
|
|
return copy_tknStr_to_sngss7(caller_data->cid_num.digits, &cgPtyNum->addrSig, &cgPtyNum->oddEven);
|
|
}
|
|
|
|
ftdm_status_t copy_cdPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum)
|
|
{
|
|
/* TODO: Implement me */
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
|
|
ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum)
|
|
{
|
|
const char *cld_nadi = NULL;
|
|
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
|
|
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
|
|
|
|
cdPtyNum->eh.pres = PRSNT_NODEF;
|
|
|
|
cdPtyNum->natAddrInd.pres = PRSNT_NODEF;
|
|
cld_nadi = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_nadi");
|
|
if (!ftdm_strlen_zero(cld_nadi)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Called NADI value \"%s\"\n", cld_nadi);
|
|
cdPtyNum->natAddrInd.val = atoi(cld_nadi);
|
|
} else {
|
|
cdPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].cld_nadi;
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for CLD, using \"%d\"\n", cdPtyNum->natAddrInd.val);
|
|
}
|
|
|
|
cdPtyNum->numPlan.pres = PRSNT_NODEF;
|
|
cdPtyNum->numPlan.val = 0x01;
|
|
|
|
cdPtyNum->innInd.pres = PRSNT_NODEF;
|
|
cdPtyNum->innInd.val = 0x01;
|
|
|
|
return copy_tknStr_to_sngss7(caller_data->dnis.digits, &cdPtyNum->addrSig, &cdPtyNum->oddEven);
|
|
}
|
|
|
|
ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb)
|
|
{
|
|
const char *val = NULL;
|
|
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
|
|
SS7_FUNC_TRACE_ENTER(__FUNCTION__);
|
|
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_gn_digits");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Generic Number qualifier \"%s\"\n", val);
|
|
if (copy_tknStr_to_sngss7((char*)val, &genNmb->addrSig, &genNmb->oddEven) != FTDM_SUCCESS) {
|
|
return FTDM_FAIL;
|
|
}
|
|
} else {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Generic Number qualifier \"%s\"\n", val);
|
|
return FTDM_SUCCESS;
|
|
}
|
|
genNmb->eh.pres = PRSNT_NODEF;
|
|
genNmb->addrSig.pres = PRSNT_NODEF;
|
|
|
|
genNmb->nmbQual.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_gn_numqual");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Generic Number \"%s\"\n", val);
|
|
genNmb->nmbQual.val = atoi(val);
|
|
} else {
|
|
genNmb->nmbQual.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].gn_nmbqual;
|
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Generic Number \n");
|
|
}
|
|
genNmb->natAddrInd.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_gn_nadi");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Generic Number \"nature of address\" \"%s\"\n", val);
|
|
genNmb->natAddrInd.val = atoi(val);
|
|
} else {
|
|
genNmb->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].gn_nadi;
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Generic Number \"nature of address\" \"%d\"\n", genNmb->natAddrInd.val);
|
|
}
|
|
genNmb->scrnInd.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_gn_screen_ind");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Generic Number \"screening indicator\" \"%s\"\n", val);
|
|
genNmb->scrnInd.val = atoi(val);
|
|
} else {
|
|
genNmb->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].gn_screen_ind;
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Generic Number \"screening indicator\" \"%d\"\n", genNmb->natAddrInd.val);
|
|
}
|
|
genNmb->presRest.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_gn_pres_ind");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Generic Number \"presentation indicator\" \"%s\"\n", val);
|
|
genNmb->presRest.val = atoi(val);
|
|
} else {
|
|
genNmb->presRest.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].gn_pres_ind;
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Generic Number \"presentation indicator\" \"%d\"\n", genNmb->presRest.val);
|
|
}
|
|
genNmb->numPlan.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_gn_npi");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Generic Number \"numbering plan\" \"%s\"\n", val);
|
|
genNmb->numPlan.val = atoi(val);
|
|
} else {
|
|
genNmb->numPlan.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].gn_npi;
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Generic Number \"numbering plan\" \"%d\"\n", genNmb->numPlan.val);
|
|
}
|
|
genNmb->niInd.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_gn_num_inc_ind");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Generic Number \"number incomplete indicator\" \"%s\"\n", val);
|
|
genNmb->niInd.val = atoi(val);
|
|
} else {
|
|
genNmb->niInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].gn_num_inc_ind;
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Generic Number \"number incomplete indicator\" \"%d\"\n", genNmb->niInd.val);
|
|
}
|
|
SS7_FUNC_TRACE_EXIT(__FUNCTION__);
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
ftdm_status_t copy_genNmb_from_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb)
|
|
{
|
|
char val[64];
|
|
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
|
|
SS7_FUNC_TRACE_ENTER(__FUNCTION__);
|
|
|
|
memset(val, 0, sizeof(val));
|
|
|
|
if (genNmb->eh.pres != PRSNT_NODEF || genNmb->addrSig.pres != PRSNT_NODEF) {
|
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Generic Number available\n");
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
copy_tknStr_from_sngss7(genNmb->addrSig, val, genNmb->oddEven);
|
|
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number:%s\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_gn_digits", val);
|
|
|
|
if (genNmb->nmbQual.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", genNmb->nmbQual.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number \"number qualifier\" \n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_gn_numqual", val);
|
|
}
|
|
|
|
if (genNmb->natAddrInd.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", genNmb->natAddrInd.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number \"nature of address\" \"%s\"\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_gn_nadi", val);
|
|
}
|
|
|
|
if (genNmb->scrnInd.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", genNmb->scrnInd.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number \"screening indicator\" \"%s\"\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_gn_screen_ind", val);
|
|
}
|
|
|
|
if (genNmb->presRest.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", genNmb->presRest.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number \"presentation indicator\" \"%s\"\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_gn_pres_ind", val);
|
|
}
|
|
|
|
if (genNmb->numPlan.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", genNmb->numPlan.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number \"numbering plan\" \"%s\"\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_gn_npi", val);
|
|
}
|
|
|
|
if (genNmb->niInd.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", genNmb->niInd.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Generic Number \"number incomplete indicator\" \"%s\"\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_gn_num_inc_ind", val);
|
|
}
|
|
|
|
SS7_FUNC_TRACE_EXIT(__FUNCTION__);
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum)
|
|
{
|
|
const char* val = NULL;
|
|
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
|
|
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
|
|
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_digits");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", val);
|
|
if (copy_tknStr_to_sngss7((char*)val, &redirgNum->addrSig, &redirgNum->oddEven) != FTDM_SUCCESS) {
|
|
return FTDM_FAIL;
|
|
}
|
|
} else if (!ftdm_strlen_zero(caller_data->rdnis.digits)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", val);
|
|
if (copy_tknStr_to_sngss7(caller_data->rdnis.digits, &redirgNum->addrSig, &redirgNum->oddEven) != FTDM_SUCCESS) {
|
|
return FTDM_FAIL;
|
|
}
|
|
} else {
|
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Number\n");
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
redirgNum->eh.pres = PRSNT_NODEF;
|
|
|
|
/* Nature of address indicator */
|
|
redirgNum->natAddr.pres = PRSNT_NODEF;
|
|
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_nadi");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
redirgNum->natAddr.val = atoi(val);
|
|
} else {
|
|
redirgNum->natAddr.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].rdnis_nadi;
|
|
}
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number NADI:%d\n", redirgNum->natAddr.val);
|
|
|
|
/* Screening indicator */
|
|
redirgNum->scrInd.pres = PRSNT_NODEF;
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_screen_ind");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
redirgNum->scrInd.val = atoi(val);
|
|
} else {
|
|
redirgNum->scrInd.val = FTDM_SCREENING_VERIFIED_PASSED;
|
|
}
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number Screening Ind:%d\n", redirgNum->scrInd.val);
|
|
|
|
/* Address presentation restricted ind */
|
|
redirgNum->presRest.pres = PRSNT_NODEF;
|
|
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_pres_ind");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
redirgNum->presRest.val = atoi(val);
|
|
} else {
|
|
redirgNum->presRest.val = FTDM_PRES_ALLOWED;
|
|
}
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number Address Presentation Restricted Ind:%d\n", redirgNum->presRest.val);
|
|
|
|
/* Numbering plan */
|
|
redirgNum->numPlan.pres = PRSNT_NODEF;
|
|
|
|
val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_plan");
|
|
if (!ftdm_strlen_zero(val)) {
|
|
redirgNum->numPlan.val = atoi(val);
|
|
} else {
|
|
redirgNum->numPlan.val = caller_data->rdnis.plan;
|
|
}
|
|
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number Numbering plan:%d\n", redirgNum->numPlan.val);
|
|
|
|
return copy_tknStr_to_sngss7(caller_data->rdnis.digits, &redirgNum->addrSig, &redirgNum->oddEven);
|
|
}
|
|
|
|
ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum)
|
|
{
|
|
char val[20];
|
|
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
|
|
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
|
|
|
|
if (redirgNum->eh.pres != PRSNT_NODEF || redirgNum->addrSig.pres != PRSNT_NODEF) {
|
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Redirecting Number available\n");
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
copy_tknStr_from_sngss7(redirgNum->addrSig, ftdmchan->caller_data.rdnis.digits, redirgNum->oddEven);
|
|
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number:%s\n", ftdmchan->caller_data.rdnis.digits);
|
|
snprintf(val, sizeof(val), "%s", ftdmchan->caller_data.rdnis.digits);
|
|
sngss7_add_var(sngss7_info, "ss7_rdnis_digits", val);
|
|
|
|
|
|
if (redirgNum->natAddr.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", redirgNum->natAddr.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number NADI:%s\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_rdnis_nadi", val);
|
|
caller_data->rdnis.type = redirgNum->natAddr.val;
|
|
}
|
|
|
|
if (redirgNum->scrInd.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", redirgNum->scrInd.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number Screening Ind:%s\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_rdnis_screen_ind", val);
|
|
}
|
|
|
|
if (redirgNum->presRest.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", redirgNum->presRest.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number Presentation Ind:%s\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_rdnis_pres_ind", val);
|
|
}
|
|
|
|
if (redirgNum->numPlan.pres == PRSNT_NODEF) {
|
|
snprintf(val, sizeof(val), "%d", redirgNum->numPlan.val);
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number Numbering plan:%s\n", val);
|
|
sngss7_add_var(sngss7_info, "ss7_rdnis_plan", val);
|
|
caller_data->rdnis.plan = redirgNum->numPlan.val;
|
|
}
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
ftdm_status_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
|
|
{
|
|
uint8_t i;
|
|
uint8_t j;
|
|
|
|
/* check if the token string is present */
|
|
if (str.pres == 1) {
|
|
j = 0;
|
|
|
|
for (i = 0; i < str.len; i++) {
|
|
sprintf(&ftdm[j], "%X", (str.val[i] & 0x0F));
|
|
j++;
|
|
sprintf(&ftdm[j], "%X", ((str.val[i] & 0xF0) >> 4));
|
|
j++;
|
|
}
|
|
|
|
/* if the odd flag is up the last digit is a fake "0" */
|
|
if ((oddEven.pres == 1) && (oddEven.val == 1)) {
|
|
ftdm[j-1] = '\0';
|
|
} else {
|
|
ftdm[j] = '\0';
|
|
}
|
|
|
|
|
|
} else {
|
|
SS7_ERROR("Asked to copy tknStr that is not present!\n");
|
|
return FTDM_FAIL;
|
|
}
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
/* check if the token string is present */
|
|
if (str.pres == 1) {
|
|
/* find the length of the digits so far */
|
|
j = strlen(ftdm);
|
|
|
|
/* confirm that we found an acceptable length */
|
|
if ( j > 25 ) {
|
|
SS7_ERROR("string length exceeds maxium value...aborting append!\n");
|
|
return FTDM_FAIL;
|
|
} /* if ( j > 25 ) */
|
|
|
|
/* copy in digits */
|
|
for (i = 0; i < str.len; i++) {
|
|
/* convert 4 bit integer to char and copy into lower nibblet*/
|
|
sprintf(&ftdm[j], "%X", (str.val[i] & 0x0F));
|
|
/* move along */
|
|
j++;
|
|
/* convert 4 bit integer to char and copy into upper nibblet */
|
|
sprintf(&ftdm[j], "%X", ((str.val[i] & 0xF0) >> 4));
|
|
/* move along */
|
|
j++;
|
|
} /* for (i = 0; i < str.len; i++) */
|
|
|
|
/* if the odd flag is up the last digit is a fake "0" */
|
|
if ((oddEven.pres == 1) && (oddEven.val == 1)) {
|
|
ftdm[j-1] = '\0';
|
|
} else {
|
|
ftdm[j] = '\0';
|
|
} /* if ((oddEven.pres == 1) && (oddEven.val == 1)) */
|
|
} else {
|
|
SS7_ERROR("Asked to copy tknStr that is not present!\n");
|
|
return FTDM_FAIL;
|
|
} /* if (str.pres == 1) */
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
|
|
ftdm_status_t copy_tknStr_to_sngss7(char* val, TknStr *tknStr, TknU8 *oddEven)
|
|
{
|
|
char tmp[2];
|
|
int k = 0;
|
|
int j = 0;
|
|
uint8_t flag = 0;
|
|
uint8_t odd = 0;
|
|
|
|
uint8_t lower = 0x0;
|
|
uint8_t upper = 0x0;
|
|
|
|
tknStr->pres = PRSNT_NODEF;
|
|
|
|
/* atoi will search through memory starting from the pointer it is given until
|
|
* it finds the \0...since tmp is on the stack it will start going through the
|
|
* possibly causing corruption. Hard code a \0 to prevent this
|
|
*/
|
|
tmp[1] = '\0';
|
|
|
|
while (1) {
|
|
/* grab a digit from the ftdm digits */
|
|
tmp[0] = val[k];
|
|
|
|
/* check if the digit is a number and that is not null */
|
|
while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
|
|
SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
|
|
/* move on to the next value */
|
|
k++;
|
|
tmp[0] = val[k];
|
|
} /* while(!(isdigit(tmp))) */
|
|
|
|
/* check if tmp is null or a digit */
|
|
if (tmp[0] != '\0') {
|
|
/* push it into the lower nibble */
|
|
lower = strtol(&tmp[0], (char **)NULL, 16);
|
|
/* move to the next digit */
|
|
k++;
|
|
/* grab a digit from the ftdm digits */
|
|
tmp[0] = val[k];
|
|
|
|
/* check if the digit is a number and that is not null */
|
|
while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
|
|
SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
|
|
k++;
|
|
tmp[0] = val[k];
|
|
} /* while(!(isdigit(tmp))) */
|
|
|
|
/* check if tmp is null or a digit */
|
|
if (tmp[0] != '\0') {
|
|
/* push the digit into the upper nibble */
|
|
upper = (strtol(&tmp[0], (char **)NULL, 16)) << 4;
|
|
} else {
|
|
/* there is no upper ... fill in 0 */
|
|
upper = 0x0;
|
|
/* throw the odd flag */
|
|
odd = 1;
|
|
/* throw the end flag */
|
|
flag = 1;
|
|
} /* if (tmp != '\0') */
|
|
} else {
|
|
/* keep the odd flag down */
|
|
odd = 0;
|
|
/* break right away since we don't need to write the digits */
|
|
break;
|
|
}
|
|
|
|
/* push the digits into the trillium structure */
|
|
tknStr->val[j] = upper | lower;
|
|
|
|
/* increment the trillium pointer */
|
|
j++;
|
|
|
|
/* if the flag is up we're through all the digits */
|
|
if (flag) break;
|
|
|
|
/* move to the next digit */
|
|
k++;
|
|
} /* while(1) */
|
|
|
|
tknStr->len = j;
|
|
oddEven->pres = PRSNT_NODEF;
|
|
oddEven->val = odd;
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
int check_for_state_change(ftdm_channel_t *ftdmchan)
|
|
{
|
|
|
|
/* check to see if there are any pending state changes on the channel and give them a sec to happen*/
|
|
ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 500);
|
|
|
|
/* check the flag to confirm it is clear now */
|
|
|
|
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
|
/* the flag is still up...so we have a problem */
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "FTDM_CHANNEL_STATE_CHANGE flag set for over 500ms, channel state = %s\n",
|
|
ftdm_channel_state2str (ftdmchan->state));
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
int check_cics_in_range(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
|
|
|
|
#if 0
|
|
ftdm_channel_t *tmp_ftdmchan;
|
|
sngss7_chan_data_t *tmp_sngss7_info;
|
|
int i = 0;
|
|
|
|
/* check all the circuits in the range to see if we are the last ckt to reset */
|
|
for ( i = sngss7_info->grs.circuit; i < ( sngss7_info->grs.range + 1 ); i++ ) {
|
|
if ( g_ftdm_sngss7_data.cfg.isupCircuit[i].siglink == 0 ) {
|
|
|
|
/* get the ftdmchan and ss7_chan_data from the circuit */
|
|
if (extract_chan_data(g_ftdm_sngss7_data.cfg.isupCircuit[i].id, &tmp_sngss7_info, &tmp_ftdmchan)) {
|
|
SS7_ERROR("Failed to extract channel data for circuit = %d!\n", g_ftdm_sngss7_data.cfg.isupCircuit[i].id);
|
|
return 0;
|
|
}
|
|
|
|
/* check if the channel still has the reset flag done is up */
|
|
if (!sngss7_test_ckt_flag(tmp_sngss7_info, FLAG_GRP_RESET_RX_DN)) {
|
|
SS7_DEBUG_CHAN(tmp_ftdmchan, "[CIC:%d] Still processing reset...\n", tmp_sngss7_info->circuit->cic);
|
|
return 0;
|
|
}
|
|
} /* if not siglink */
|
|
} /* for */
|
|
|
|
SS7_DEBUG("All circuits out of reset: circuit=%d, range=%d\n",
|
|
sngss7_info->grs.circuit,
|
|
sngss7_info->grs.range);
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan)
|
|
{
|
|
/*SS7_FUNC_TRACE_ENTER(__FUNCTION__);*/
|
|
|
|
if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj == NULL) {
|
|
SS7_ERROR("sngss7_info is Null for circuit #%d\n", circuit);
|
|
return FTDM_FAIL;
|
|
}
|
|
|
|
ftdm_assert_return(g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj, FTDM_FAIL, "received message on signalling link or non-configured cic\n");
|
|
|
|
*sngss7_info = g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj;
|
|
|
|
ftdm_assert_return((*sngss7_info)->ftdmchan, FTDM_FAIL, "received message on signalling link or non-configured cic\n");
|
|
*ftdmchan = (*sngss7_info)->ftdmchan;
|
|
|
|
/*SS7_FUNC_TRACE_EXIT(__FUNCTION__);*/
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
int check_for_reset(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
|
|
if (sngss7_test_ckt_flag(sngss7_info,FLAG_RESET_RX)) {
|
|
return 1;
|
|
}
|
|
|
|
if (sngss7_test_ckt_flag(sngss7_info,FLAG_RESET_TX)) {
|
|
return 1;
|
|
}
|
|
|
|
if (sngss7_test_ckt_flag(sngss7_info,FLAG_GRP_RESET_RX)) {
|
|
return 1;
|
|
}
|
|
|
|
if (sngss7_test_ckt_flag(sngss7_info,FLAG_GRP_RESET_TX)) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/******************************************************************************/
|
|
unsigned long get_unique_id(void)
|
|
{
|
|
int procId = sng_get_procId();
|
|
|
|
/* id values are between (procId * 1,000,000) and ((procId + 1) * 1,000,000) */
|
|
if (sngss7_id < ((procId + 1) * 1000000) ) {
|
|
sngss7_id++;
|
|
} else {
|
|
sngss7_id = procId * 1000000;
|
|
}
|
|
|
|
return(sngss7_id);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t check_if_rx_grs_started(ftdm_span_t *ftdmspan)
|
|
{
|
|
ftdm_channel_t *ftdmchan = NULL;
|
|
sngss7_chan_data_t *sngss7_info = NULL;
|
|
sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data;
|
|
int i;
|
|
|
|
|
|
SS7_INFO("Rx GRS (%d:%d)\n",
|
|
g_ftdm_sngss7_data.cfg.isupCkt[sngss7_span->rx_grs.circuit].cic,
|
|
(g_ftdm_sngss7_data.cfg.isupCkt[sngss7_span->rx_grs.circuit].cic + sngss7_span->rx_grs.range));
|
|
|
|
for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) {
|
|
|
|
/* confirm this is a voice channel, otherwise we do nothing */
|
|
if (g_ftdm_sngss7_data.cfg.isupCkt[i].type != VOICE) {
|
|
continue;
|
|
}
|
|
|
|
/* extract the channel in question */
|
|
if (extract_chan_data(i, &sngss7_info, &ftdmchan)) {
|
|
SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i);
|
|
continue;
|
|
}
|
|
|
|
/* check if the GRP_RESET_RX flag is already up */
|
|
if (sngss7_test_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX)) {
|
|
/* we have already processed this channel...move along */
|
|
continue;
|
|
}
|
|
|
|
/* lock the channel */
|
|
ftdm_mutex_lock(ftdmchan->mutex);
|
|
|
|
/* clear up any pending state changes */
|
|
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
|
ftdm_sangoma_ss7_process_state_change (ftdmchan);
|
|
}
|
|
|
|
/* flag the channel as having received a reset */
|
|
sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX);
|
|
|
|
switch (ftdmchan->state) {
|
|
/**************************************************************************/
|
|
case FTDM_CHANNEL_STATE_RESTART:
|
|
|
|
/* go to idle so that we can redo the restart state*/
|
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
|
|
|
|
break;
|
|
/**************************************************************************/
|
|
default:
|
|
|
|
/* set the state of the channel to restart...the rest is done by the chan monitor */
|
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
|
|
break;
|
|
/**************************************************************************/
|
|
} /* switch (ftdmchan->state) */
|
|
|
|
/* unlock the channel again before we exit */
|
|
ftdm_mutex_unlock(ftdmchan->mutex);
|
|
|
|
} /* for (chans in GRS */
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t check_if_rx_grs_processed(ftdm_span_t *ftdmspan)
|
|
{
|
|
ftdm_channel_t *ftdmchan = NULL;
|
|
sngss7_chan_data_t *sngss7_info = NULL;
|
|
sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data;
|
|
int i;
|
|
int byte = 0;
|
|
int bit = 0;
|
|
|
|
/* check all the circuits in the range to see if they are done resetting */
|
|
for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) {
|
|
|
|
/* confirm this is a voice channel, otherwise we do nothing */
|
|
if (g_ftdm_sngss7_data.cfg.isupCkt[i].type != VOICE) {
|
|
continue;
|
|
}
|
|
|
|
/* extract the channel in question */
|
|
if (extract_chan_data(i, &sngss7_info, &ftdmchan)) {
|
|
SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i);
|
|
continue;
|
|
}
|
|
|
|
/* lock the channel */
|
|
ftdm_mutex_lock(ftdmchan->mutex);
|
|
|
|
/* check if there is a state change pending on the channel */
|
|
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
|
/* check the state to the GRP_RESET_RX_DN flag */
|
|
if (!sngss7_test_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) {
|
|
/* this channel is still resetting...do nothing */
|
|
goto GRS_UNLOCK_ALL;
|
|
} /* if (!sngss7_test_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) */
|
|
} else {
|
|
/* state change pending */
|
|
goto GRS_UNLOCK_ALL;
|
|
}
|
|
} /* for ( i = circuit; i < (circuit + range + 1); i++) */
|
|
|
|
SS7_DEBUG("All circuits out of reset for GRS: circuit=%d, range=%d\n",
|
|
sngss7_span->rx_grs.circuit,
|
|
sngss7_span->rx_grs.range);
|
|
|
|
/* check all the circuits in the range to see if they are done resetting */
|
|
for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) {
|
|
|
|
/* confirm this is a voice channel, otherwise we do nothing */
|
|
if (g_ftdm_sngss7_data.cfg.isupCkt[i].type != VOICE) {
|
|
continue;
|
|
}
|
|
|
|
/* extract the channel in question */
|
|
if (extract_chan_data(i, &sngss7_info, &ftdmchan)) {
|
|
SS7_ERROR("Failed to extract channel data for circuit = %d!\n",i);
|
|
/* check if we need to die */
|
|
SS7_ASSERT;
|
|
/* move along */
|
|
continue;
|
|
}
|
|
|
|
/* throw the GRP reset flag complete flag */
|
|
sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX_CMPLT);
|
|
|
|
/* move the channel to the down state */
|
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
|
|
|
/* update the status map if the ckt is in blocked state */
|
|
if ((sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) ||
|
|
(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) ||
|
|
(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX)) ||
|
|
(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX))) {
|
|
|
|
sngss7_span->rx_grs.status[byte] = (sngss7_span->rx_grs.status[byte] | (1 << bit));
|
|
} /* if blocked */
|
|
|
|
/* update the bit and byte counter*/
|
|
bit ++;
|
|
if (bit == 8) {
|
|
byte++;
|
|
bit = 0;
|
|
}
|
|
} /* for ( i = circuit; i < (circuit + range + 1); i++) */
|
|
|
|
GRS_UNLOCK_ALL:
|
|
for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) {
|
|
|
|
/* confirm this is a voice channel, otherwise we do nothing */
|
|
if (g_ftdm_sngss7_data.cfg.isupCkt[i].type != VOICE) {
|
|
continue;
|
|
}
|
|
|
|
/* extract the channel in question */
|
|
if (extract_chan_data(i, &sngss7_info, &ftdmchan)) {
|
|
SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i);
|
|
continue;
|
|
}
|
|
|
|
/* unlock the channel */
|
|
ftdm_mutex_unlock(ftdmchan->mutex);
|
|
}
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t check_if_rx_gra_started(ftdm_span_t *ftdmspan)
|
|
{
|
|
ftdm_channel_t *ftdmchan = NULL;
|
|
sngss7_chan_data_t *sngss7_info = NULL;
|
|
sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data;
|
|
int i;
|
|
|
|
SS7_INFO("Rx GRA (%d:%d)\n",
|
|
g_ftdm_sngss7_data.cfg.isupCkt[sngss7_span->rx_gra.circuit].cic,
|
|
(g_ftdm_sngss7_data.cfg.isupCkt[sngss7_span->rx_gra.circuit].cic + sngss7_span->rx_gra.range));
|
|
|
|
for (i = sngss7_span->rx_gra.circuit; i < (sngss7_span->rx_gra.circuit + sngss7_span->rx_gra.range + 1); i++) {
|
|
|
|
/* extract the channel in question */
|
|
if (extract_chan_data(i, &sngss7_info, &ftdmchan)) {
|
|
SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i);
|
|
continue;
|
|
}
|
|
|
|
/* check if the channel is already procoessing the GRA */
|
|
if (sngss7_test_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP)) {
|
|
/* move along */
|
|
continue;
|
|
}
|
|
|
|
/* lock the channel */
|
|
ftdm_mutex_lock(ftdmchan->mutex);
|
|
|
|
/* clear up any pending state changes */
|
|
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
|
ftdm_sangoma_ss7_process_state_change (ftdmchan);
|
|
}
|
|
|
|
|
|
|
|
switch (ftdmchan->state) {
|
|
/**********************************************************************/
|
|
case FTDM_CHANNEL_STATE_RESTART:
|
|
|
|
/* throw the FLAG_RESET_TX_RSP to indicate we have acknowledgement from the remote side */
|
|
sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP);
|
|
|
|
/* go to DOWN */
|
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
|
|
|
break;
|
|
/**********************************************************************/
|
|
case FTDM_CHANNEL_STATE_DOWN:
|
|
|
|
/* do nothing, just drop the message */
|
|
SS7_DEBUG("Receveived GRA in down state, dropping\n");
|
|
|
|
break;
|
|
/**********************************************************************/
|
|
case FTDM_CHANNEL_STATE_TERMINATING:
|
|
case FTDM_CHANNEL_STATE_HANGUP:
|
|
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
|
|
|
|
/* throw the FLAG_RESET_TX_RSP to indicate we have acknowledgement from the remote side */
|
|
sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP);
|
|
|
|
break;
|
|
/**********************************************************************/
|
|
default:
|
|
/* ITU Q764-2.9.5.1.c -> release the circuit */
|
|
if (sngss7_span->rx_gra.cause != 0) {
|
|
ftdmchan->caller_data.hangup_cause = sngss7_span->rx_gra.cause;
|
|
} else {
|
|
ftdmchan->caller_data.hangup_cause = 98; /* Message not compatiable with call state */
|
|
}
|
|
|
|
/* go to terminating to hang up the call */
|
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
|
|
break;
|
|
/**********************************************************************/
|
|
}
|
|
|
|
/* unlock the channel again before we exit */
|
|
ftdm_mutex_unlock(ftdmchan->mutex);
|
|
|
|
} /* for ( circuits in request */
|
|
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t check_for_res_sus_flag(ftdm_span_t *ftdmspan)
|
|
{
|
|
ftdm_channel_t *ftdmchan = NULL;
|
|
sngss7_chan_data_t *sngss7_info = NULL;
|
|
ftdm_sigmsg_t sigev;
|
|
int x;
|
|
|
|
for (x = 1; x < (ftdmspan->chan_count + 1); x++) {
|
|
|
|
/* extract the channel structure and sngss7 channel data */
|
|
ftdmchan = ftdmspan->channels[x];
|
|
|
|
/* if the call data is NULL move on */
|
|
if (ftdmchan->call_data == NULL) continue;
|
|
|
|
sngss7_info = ftdmchan->call_data;
|
|
|
|
/* lock the channel */
|
|
ftdm_mutex_lock(ftdmchan->mutex);
|
|
|
|
memset (&sigev, 0, sizeof (sigev));
|
|
|
|
sigev.chan_id = ftdmchan->chan_id;
|
|
sigev.span_id = ftdmchan->span_id;
|
|
sigev.channel = ftdmchan;
|
|
|
|
/* if we have the PAUSED flag and the sig status is still UP */
|
|
if ((sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) &&
|
|
(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP))) {
|
|
|
|
/* clear up any pending state changes */
|
|
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
|
ftdm_sangoma_ss7_process_state_change (ftdmchan);
|
|
}
|
|
|
|
/* throw the channel into SUSPENDED to process the flag */
|
|
/* after doing this once the sig status will be down */
|
|
ftdm_set_state (ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
}
|
|
|
|
/* if the RESUME flag is up go to SUSPENDED to process the flag */
|
|
/* after doing this the flag will be cleared */
|
|
if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME)) {
|
|
|
|
/* clear up any pending state changes */
|
|
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
|
ftdm_sangoma_ss7_process_state_change (ftdmchan);
|
|
}
|
|
|
|
/* got SUSPENDED state to clear the flag */
|
|
ftdm_set_state (ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
}
|
|
|
|
/* unlock the channel */
|
|
ftdm_mutex_unlock(ftdmchan->mutex);
|
|
|
|
} /* for (x = 1; x < (span->chan_count + 1); x++) */
|
|
|
|
/* signal the core that sig events are queued for processing */
|
|
ftdm_span_trigger_signals(ftdmspan);
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t process_span_ucic(ftdm_span_t *ftdmspan)
|
|
{
|
|
ftdm_channel_t *ftdmchan = NULL;
|
|
sngss7_chan_data_t *sngss7_info = NULL;
|
|
sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data;
|
|
int i;
|
|
|
|
for (i = sngss7_span->ucic.circuit; i < (sngss7_span->ucic.circuit + sngss7_span->ucic.range + 1); i++) {
|
|
|
|
/* extract the channel in question */
|
|
if (extract_chan_data(i, &sngss7_info, &ftdmchan)) {
|
|
SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i);
|
|
continue;
|
|
}
|
|
|
|
/* lock the channel */
|
|
ftdm_mutex_lock(ftdmchan->mutex);
|
|
|
|
SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx UCIC\n", sngss7_info->circuit->cic);
|
|
|
|
/* clear up any pending state changes */
|
|
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
|
ftdm_sangoma_ss7_process_state_change (ftdmchan);
|
|
}
|
|
|
|
/* throw the ckt block flag */
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK);
|
|
|
|
/* set the channel to suspended state */
|
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
|
|
/* unlock the channel again before we exit */
|
|
ftdm_mutex_unlock(ftdmchan->mutex);
|
|
}
|
|
|
|
/* clear out the ucic data since we're done with it */
|
|
memset(&sngss7_span->ucic, 0x0, sizeof(sngss7_group_data_t));
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t clear_rx_grs_flags(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
/* clear all the flags related to an incoming GRS */
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX);
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX_DN);
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX_CMPLT);
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t clear_rx_grs_data(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan;
|
|
sngss7_span_data_t *sngss7_span = ftdmchan->span->signal_data;
|
|
|
|
/* clear the rx_grs data fields */
|
|
memset(&sngss7_span->rx_grs, 0x0, sizeof(sngss7_group_data_t));
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t clear_rx_gra_data(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan;
|
|
sngss7_span_data_t *sngss7_span = ftdmchan->span->signal_data;
|
|
|
|
/* clear the rx_grs data fields */
|
|
memset(&sngss7_span->rx_gra, 0x0, sizeof(sngss7_group_data_t));
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
/******************************************************************************/
|
|
ftdm_status_t clear_tx_grs_flags(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
/* clear all the flags related to an outgoing GRS */
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_GRP_RESET_BASE);
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX);
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_GRP_RESET_SENT);
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP);
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t clear_tx_grs_data(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan;
|
|
sngss7_span_data_t *sngss7_span = ftdmchan->span->signal_data;
|
|
|
|
/* clear the rx_grs data fields */
|
|
memset(&sngss7_span->tx_grs, 0x0, sizeof(sngss7_group_data_t));
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t clear_rx_rsc_flags(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
/* clear all the flags related to an incoming RSC */
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_RESET_RX);
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t clear_tx_rsc_flags(sngss7_chan_data_t *sngss7_info)
|
|
{
|
|
/* clear all the flags related to an outgoing RSC */
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_RESET_TX);
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_RESET_SENT);
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_RESET_TX_RSP);
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t encode_subAddrIE_nsap(const char *subAddr, char *subAddrIE, int type)
|
|
{
|
|
/* Q931 4.5.9
|
|
* 8 7 6 5 4 3 2 1 (octet)
|
|
*
|
|
* 0 1 1 1 0 0 0 1 (spare 8) ( IE id 1-7)
|
|
* X X X X X X X X (length of IE contents)
|
|
* 1 0 0 0 Z 0 0 0 (ext 8) (NSAP type 5-7) (odd/even 4) (spare 1-3)
|
|
* X X X X X X X X (sub address encoded in ia5)
|
|
*/
|
|
|
|
int x = 0;
|
|
int p = 0;
|
|
int len = 0;
|
|
char tmp[2];
|
|
|
|
/* initalize the second element of tmp to \0 so that atoi doesn't go to far */
|
|
tmp[1]='\0';
|
|
|
|
/* set octet 1 aka IE id */
|
|
p = 0;
|
|
switch(type) {
|
|
/**************************************************************************/
|
|
case SNG_CALLED: /* called party sub address */
|
|
subAddrIE[p] = 0x71;
|
|
break;
|
|
/**************************************************************************/
|
|
case SNG_CALLING: /* calling party sub address */
|
|
subAddrIE[p] = 0x6d;
|
|
break;
|
|
/**************************************************************************/
|
|
default: /* not good */
|
|
SS7_ERROR("Sub-Address type is invalid: %d\n", type);
|
|
return FTDM_FAIL;
|
|
break;
|
|
/**************************************************************************/
|
|
} /* switch(type) */
|
|
|
|
/* set octet 3 aka type and o/e */
|
|
p = 2;
|
|
subAddrIE[p] = 0x80;
|
|
|
|
/* set the subAddrIE pointer octet 4 */
|
|
p = 3;
|
|
|
|
/* loop through all digits in subAddr and insert them into subAddrIE */
|
|
while (subAddr[x] != '\0') {
|
|
|
|
/* grab a character */
|
|
tmp[0] = subAddr[x];
|
|
|
|
/* confirm it is a digit */
|
|
if (!isdigit(tmp[0])) {
|
|
SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
|
|
/* move to the next character in subAddr */
|
|
x++;
|
|
|
|
/* restart the loop */
|
|
continue;
|
|
}
|
|
|
|
/* convert the character to IA5 encoding and write into subAddrIE */
|
|
subAddrIE[p] = atoi(&tmp[0]); /* lower nibble is the digit */
|
|
subAddrIE[p] |= 0x3 << 4; /* upper nibble is 0x3 */
|
|
|
|
/* increment address length counter */
|
|
len++;
|
|
|
|
/* increment the subAddrIE pointer */
|
|
p++;
|
|
|
|
/* move to the next character in subAddr */
|
|
x++;
|
|
|
|
} /* while (subAddr[x] != '\0') */
|
|
|
|
/* set octet 2 aka length of subaddr */
|
|
p = 1;
|
|
subAddrIE[p] = len + 1;
|
|
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int type)
|
|
{
|
|
/* Q931 4.5.9
|
|
* 8 7 6 5 4 3 2 1 (octet)
|
|
*
|
|
* 0 1 1 1 0 0 0 1 (spare 8) ( IE id 1-7)
|
|
* X X X X X X X X (length of IE contents)
|
|
* 1 0 0 0 Z 0 0 0 (ext 8) (NSAP type 5-7) (odd/even 4) (spare 1-3)
|
|
* X X X X X X X X (sub address encoded in ia5)
|
|
*/
|
|
|
|
int x = 0;
|
|
int p = 0;
|
|
int len = 0;
|
|
char tmp[2];
|
|
int flag = 0;
|
|
int odd = 0;
|
|
uint8_t lower = 0x0;
|
|
uint8_t upper = 0x0;
|
|
|
|
/* initalize the second element of tmp to \0 so that atoi doesn't go to far */
|
|
tmp[1]='\0';
|
|
|
|
/* set octet 1 aka IE id */
|
|
p = 0;
|
|
switch(type) {
|
|
/**************************************************************************/
|
|
case SNG_CALLED: /* called party sub address */
|
|
subAddrIE[p] = 0x71;
|
|
break;
|
|
/**************************************************************************/
|
|
case SNG_CALLING: /* calling party sub address */
|
|
subAddrIE[p] = 0x6d;
|
|
break;
|
|
/**************************************************************************/
|
|
default: /* not good */
|
|
SS7_ERROR("Sub-Address type is invalid: %d\n", type);
|
|
return FTDM_FAIL;
|
|
break;
|
|
/**************************************************************************/
|
|
} /* switch(type) */
|
|
|
|
/* set the subAddrIE pointer octet 4 */
|
|
p = 3;
|
|
|
|
/* loop through all digits in subAddr and insert them into subAddrIE */
|
|
while (1) {
|
|
|
|
/* grab a character */
|
|
tmp[0] = subAddr[x];
|
|
|
|
/* confirm it is a hex digit */
|
|
while ((!isxdigit(tmp[0])) && (tmp[0] != '\0')) {
|
|
SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
|
|
/* move to the next character in subAddr */
|
|
x++;
|
|
tmp[0] = subAddr[x];
|
|
}
|
|
|
|
/* check if tmp is null or a digit */
|
|
if (tmp[0] != '\0') {
|
|
/* push it into the lower nibble using strtol to allow a-f chars */
|
|
lower = strtol(&tmp[0], (char **)NULL, 16);
|
|
/* move to the next digit */
|
|
x++;
|
|
/* grab a digit from the ftdm digits */
|
|
tmp[0] = subAddr[x];
|
|
|
|
/* check if the digit is a hex digit and that is not null */
|
|
while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
|
|
SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
|
|
x++;
|
|
tmp[0] = subAddr[x];
|
|
} /* while(!(isdigit(tmp))) */
|
|
|
|
/* check if tmp is null or a digit */
|
|
if (tmp[0] != '\0') {
|
|
/* push the digit into the upper nibble using strtol to allow a-f chars */
|
|
upper = (strtol(&tmp[0], (char **)NULL, 16)) << 4;
|
|
} else {
|
|
/* there is no upper ... fill in spare */
|
|
upper = 0x00;
|
|
/* throw the odd flag since we need to buffer */
|
|
odd = 1;
|
|
/* throw the end flag */
|
|
flag = 1;
|
|
} /* if (tmp != '\0') */
|
|
} else {
|
|
/* keep the odd flag down */
|
|
odd = 0;
|
|
|
|
/* throw the flag */
|
|
flag = 1;
|
|
|
|
/* bounce out right away */
|
|
break;
|
|
}
|
|
|
|
/* fill in the octet */
|
|
subAddrIE[p] = upper | lower;
|
|
|
|
/* increment address length counter */
|
|
len++;
|
|
|
|
/* if the flag is we're through all the digits */
|
|
if (flag) break;
|
|
|
|
/* increment the subAddrIE pointer */
|
|
p++;
|
|
|
|
/* move to the next character in subAddr */
|
|
x++;
|
|
|
|
} /* while (subAddr[x] != '\0') */
|
|
|
|
/* set octet 2 aka length of subaddr */
|
|
p = 1;
|
|
subAddrIE[p] = len + 1;
|
|
|
|
/* set octet 3 aka type and o/e */
|
|
p = 2;
|
|
subAddrIE[p] = 0xa0 | (odd << 3);
|
|
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
int find_mtp2_error_type_in_map(const char *err_type)
|
|
{
|
|
int i = 0;
|
|
|
|
while (sng_mtp2_error_type_map[i].init == 1) {
|
|
/* check if string matches the sng_type name */
|
|
if (!strcasecmp(err_type, sng_mtp2_error_type_map[i].sng_type)) {
|
|
/* we've found a match break from the loop */
|
|
break;
|
|
} else {
|
|
/* move on to the next on */
|
|
i++;
|
|
}
|
|
} /* while (sng_mtp2_error_type_map[i].init == 1) */
|
|
|
|
/* check how we exited the loop */
|
|
if (sng_mtp2_error_type_map[i].init == 0) {
|
|
return -1;
|
|
} else {
|
|
return i;
|
|
} /* if (sng_mtp2_error_type_map[i].init == 0) */
|
|
}
|
|
|
|
/******************************************************************************/
|
|
int find_link_type_in_map(const char *linkType)
|
|
{
|
|
int i = 0;
|
|
|
|
while (sng_link_type_map[i].init == 1) {
|
|
/* check if string matches the sng_type name */
|
|
if (!strcasecmp(linkType, sng_link_type_map[i].sng_type)) {
|
|
/* we've found a match break from the loop */
|
|
break;
|
|
} else {
|
|
/* move on to the next on */
|
|
i++;
|
|
}
|
|
} /* while (sng_link_type_map[i].init == 1) */
|
|
|
|
/* check how we exited the loop */
|
|
if (sng_link_type_map[i].init == 0) {
|
|
return -1;
|
|
} else {
|
|
return i;
|
|
} /* if (sng_link_type_map[i].init == 0) */
|
|
}
|
|
|
|
/******************************************************************************/
|
|
int find_switch_type_in_map(const char *switchType)
|
|
{
|
|
int i = 0;
|
|
|
|
while (sng_switch_type_map[i].init == 1) {
|
|
/* check if string matches the sng_type name */
|
|
if (!strcasecmp(switchType, sng_switch_type_map[i].sng_type)) {
|
|
/* we've found a match break from the loop */
|
|
break;
|
|
} else {
|
|
/* move on to the next on */
|
|
i++;
|
|
}
|
|
} /* while (sng_switch_type_map[i].init == 1) */
|
|
|
|
/* check how we exited the loop */
|
|
if (sng_switch_type_map[i].init == 0) {
|
|
return -1;
|
|
} else {
|
|
return i;
|
|
} /* if (sng_switch_type_map[i].init == 0) */
|
|
}
|
|
|
|
/******************************************************************************/
|
|
int find_ssf_type_in_map(const char *ssfType)
|
|
{
|
|
int i = 0;
|
|
|
|
while (sng_ssf_type_map[i].init == 1) {
|
|
/* check if string matches the sng_type name */
|
|
if (!strcasecmp(ssfType, sng_ssf_type_map[i].sng_type)) {
|
|
/* we've found a match break from the loop */
|
|
break;
|
|
} else {
|
|
/* move on to the next on */
|
|
i++;
|
|
}
|
|
} /* while (sng_ssf_type_map[i].init == 1) */
|
|
|
|
/* check how we exited the loop */
|
|
if (sng_ssf_type_map[i].init == 0) {
|
|
return -1;
|
|
} else {
|
|
return i;
|
|
} /* if (sng_ssf_type_map[i].init == 0) */
|
|
}
|
|
|
|
/******************************************************************************/
|
|
int find_cic_cntrl_in_map(const char *cntrlType)
|
|
{
|
|
int i = 0;
|
|
|
|
while (sng_cic_cntrl_type_map[i].init == 1) {
|
|
/* check if string matches the sng_type name */
|
|
if (!strcasecmp(cntrlType, sng_cic_cntrl_type_map[i].sng_type)) {
|
|
/* we've found a match break from the loop */
|
|
break;
|
|
} else {
|
|
/* move on to the next on */
|
|
i++;
|
|
}
|
|
} /* while (sng_cic_cntrl_type_map[i].init == 1) */
|
|
|
|
/* check how we exited the loop */
|
|
if (sng_cic_cntrl_type_map[i].init == 0) {
|
|
return -1;
|
|
} else {
|
|
return i;
|
|
} /* if (sng_cic_cntrl_type_map[i].init == 0) */
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t check_status_of_all_isup_intf(void)
|
|
{
|
|
sng_isup_inf_t *sngss7_intf = NULL;
|
|
uint8_t status = 0xff;
|
|
int x;
|
|
|
|
/* go through all the isupIntfs and ask the stack to give their current state */
|
|
x = 1;
|
|
for (x = 1; x < (MAX_ISUP_INFS); x++) {
|
|
/**************************************************************************/
|
|
|
|
if (g_ftdm_sngss7_data.cfg.isupIntf[x].id == 0) continue;
|
|
|
|
sngss7_intf = &g_ftdm_sngss7_data.cfg.isupIntf[x];
|
|
|
|
if (ftmod_ss7_isup_intf_sta(sngss7_intf->id, &status)) {
|
|
SS7_ERROR("Failed to get status of ISUP intf %d\n", sngss7_intf->id);
|
|
continue;
|
|
}
|
|
|
|
switch (status){
|
|
/**********************************************************************/
|
|
case (SI_INTF_AVAIL):
|
|
SS7_DEBUG("State of ISUP intf %d = AVAIL\n", sngss7_intf->id);
|
|
|
|
/* check the current state for interface that we know */
|
|
if (sngss7_test_flag(sngss7_intf, SNGSS7_PAUSED)) {
|
|
/* we thing the intf is paused...put into resume */
|
|
sngss7_clear_flag(sngss7_intf, SNGSS7_PAUSED);
|
|
} else {
|
|
/* nothing to since we already know that interface is active */
|
|
}
|
|
break;
|
|
/**********************************************************************/
|
|
case (SI_INTF_UNAVAIL):
|
|
SS7_DEBUG("State of ISUP intf %d = UNAVAIL\n", sngss7_intf->id);
|
|
/* check the current state for interface that we know */
|
|
if (sngss7_test_flag(sngss7_intf, SNGSS7_PAUSED)) {
|
|
/* nothing to since we already know that interface is active */
|
|
} else {
|
|
/* put the interface into pause */
|
|
sngss7_set_flag(sngss7_intf, SNGSS7_PAUSED);
|
|
}
|
|
break;
|
|
/**********************************************************************/
|
|
case (SI_INTF_CONG1):
|
|
SS7_DEBUG("State of ISUP intf %d = Congestion 1\n", sngss7_intf->id);
|
|
break;
|
|
/**********************************************************************/
|
|
case (SI_INTF_CONG2):
|
|
SS7_DEBUG("State of ISUP intf %d = Congestion 2\n", sngss7_intf->id);
|
|
break;
|
|
/**********************************************************************/
|
|
case (SI_INTF_CONG3):
|
|
SS7_DEBUG("State of ISUP intf %d = Congestion 3\n", sngss7_intf->id);
|
|
break;
|
|
/**********************************************************************/
|
|
default:
|
|
/* should do something here to handle the possiblity of an unknown case */
|
|
SS7_ERROR("Unknown ISUP intf Status code (%d) for Intf = %d\n", status, sngss7_intf->id);
|
|
break;
|
|
/**********************************************************************/
|
|
} /* switch (status) */
|
|
|
|
/**************************************************************************/
|
|
} /* for (x = 1; x < MAX_ISUP_INFS); i++) */
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t sngss7_add_var(sngss7_chan_data_t *sngss7_info, const char* var, const char* val)
|
|
{
|
|
char *t_name = 0;
|
|
char *t_val = 0;
|
|
|
|
/* confirm the user has sent us a value */
|
|
if (!var || !val) {
|
|
return FTDM_FAIL;
|
|
}
|
|
|
|
if (!sngss7_info->variables) {
|
|
/* initialize on first use */
|
|
sngss7_info->variables = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
|
|
ftdm_assert_return(sngss7_info->variables, FTDM_FAIL, "Failed to create hash table\n");
|
|
}
|
|
|
|
t_name = ftdm_strdup(var);
|
|
t_val = ftdm_strdup(val);
|
|
|
|
hashtable_insert(sngss7_info->variables, t_name, t_val, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_FLAG_FREE_VALUE);
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t sngss7_add_raw_data(sngss7_chan_data_t *sngss7_info, uint8_t* data, ftdm_size_t data_len)
|
|
{
|
|
ftdm_assert_return(!sngss7_info->raw_data, FTDM_FAIL, "Overwriting existing raw data\n");
|
|
|
|
sngss7_info->raw_data = ftdm_calloc(1, data_len);
|
|
ftdm_assert_return(sngss7_info->raw_data, FTDM_FAIL, "Failed to allocate raw data\n");
|
|
|
|
memcpy(sngss7_info->raw_data, data, data_len);
|
|
sngss7_info->raw_data_len = data_len;
|
|
return FTDM_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
void sngss7_send_signal(sngss7_chan_data_t *sngss7_info, ftdm_signal_event_t event_id)
|
|
{
|
|
ftdm_sigmsg_t sigev;
|
|
ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan;
|
|
|
|
memset(&sigev, 0, sizeof(sigev));
|
|
|
|
sigev.chan_id = ftdmchan->chan_id;
|
|
sigev.span_id = ftdmchan->span_id;
|
|
sigev.channel = ftdmchan;
|
|
sigev.event_id = event_id;
|
|
|
|
if (sngss7_info->variables) {
|
|
/*
|
|
* variables now belongs to the ftdm core, and
|
|
* will be cleared after sigev is processed by user. Set
|
|
* local pointer to NULL so we do not attempt to
|
|
* destroy it */
|
|
sigev.variables = sngss7_info->variables;
|
|
sngss7_info->variables = NULL;
|
|
}
|
|
|
|
if (sngss7_info->raw_data) {
|
|
/*
|
|
* raw_data now belongs to the ftdm core, and
|
|
* will be cleared after sigev is processed by user. Set
|
|
* local pointer to NULL so we do not attempt to
|
|
* destroy it */
|
|
|
|
sigev.raw.data = sngss7_info->raw_data;
|
|
sigev.raw.len = sngss7_info->raw_data_len;
|
|
|
|
sngss7_info->raw_data = NULL;
|
|
sngss7_info->raw_data_len = 0;
|
|
}
|
|
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
void sngss7_set_sig_status(sngss7_chan_data_t *sngss7_info, ftdm_signaling_status_t status)
|
|
{
|
|
ftdm_sigmsg_t sig;
|
|
ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan;
|
|
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Signalling link status changed to %s\n",
|
|
ftdm_signaling_status2str(status));
|
|
|
|
memset(&sig, 0, sizeof(sig));
|
|
|
|
sig.chan_id = ftdmchan->chan_id;
|
|
sig.span_id = ftdmchan->span_id;
|
|
sig.channel = ftdmchan;
|
|
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
|
|
sig.ev_data.sigstatus.status = status;
|
|
|
|
if (ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS) {
|
|
SS7_ERROR_CHAN(ftdmchan, "Failed to change channel status to %s\n",
|
|
ftdm_signaling_status2str(status));
|
|
}
|
|
return;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan)
|
|
{
|
|
ftdm_channel_t *ftdmchan = NULL;
|
|
sngss7_chan_data_t *sngss7_info = NULL;
|
|
sng_isup_inf_t *sngss7_intf = NULL;
|
|
uint8_t state;
|
|
uint8_t bits_ab = 0;
|
|
uint8_t bits_cd = 0;
|
|
uint8_t bits_ef = 0;
|
|
int x;
|
|
int ret;
|
|
|
|
for (x = 1; x < (ftdmspan->chan_count + 1); x++) {
|
|
/**************************************************************************/
|
|
/* extract the channel structure and sngss7 channel data */
|
|
ftdmchan = ftdmspan->channels[x];
|
|
|
|
/* if the call data is NULL move on */
|
|
if (ftdmchan->call_data == NULL) {
|
|
SS7_WARN_CHAN(ftdmchan, "Found ftdmchan with no sig module data!%s\n", " ");
|
|
continue;
|
|
}
|
|
|
|
/* grab the private data */
|
|
sngss7_info = ftdmchan->call_data;
|
|
|
|
/* check the reconfig flag */
|
|
if (sngss7_test_ckt_flag(sngss7_info, FLAG_CKT_RECONFIG)) {
|
|
/* confirm the state of all isup interfaces*/
|
|
check_status_of_all_isup_intf();
|
|
|
|
sngss7_intf = &g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId];
|
|
|
|
/* check if the interface is paused or resumed */
|
|
if (sngss7_test_flag(sngss7_intf, SNGSS7_PAUSED)) {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ISUP intf %d is PAUSED\n", sngss7_intf->id);
|
|
/* throw the pause flag */
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_RESUME);
|
|
sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_PAUSED);
|
|
} else {
|
|
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ISUP intf %d is RESUMED\n", sngss7_intf->id);
|
|
/* throw the resume flag */
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED);
|
|
sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_RESUME);
|
|
}
|
|
|
|
/* query for the status of the ckt */
|
|
if (ftmod_ss7_isup_ckt_sta(sngss7_info->circuit->id, &state)) {
|
|
SS7_ERROR("Failed to read isup ckt = %d status\n", sngss7_info->circuit->id);
|
|
continue;
|
|
}
|
|
|
|
/* extract the bit sections */
|
|
bits_ab = (state & (SNG_BIT_A + SNG_BIT_B)) >> 0;
|
|
bits_cd = (state & (SNG_BIT_C + SNG_BIT_D)) >> 2;
|
|
bits_ef = (state & (SNG_BIT_E + SNG_BIT_F)) >> 4;
|
|
|
|
if (bits_cd == 0x0) {
|
|
/* check if circuit is UCIC or transient */
|
|
if (bits_ab == 0x3) {
|
|
/* bit a and bit b are set, unequipped */
|
|
ret = ftmod_ss7_isup_ckt_config(sngss7_info->circuit->id);
|
|
if (ret) {
|
|
SS7_CRITICAL("ISUP CKT %d re-configuration FAILED!\n",x);
|
|
} else {
|
|
SS7_INFO("ISUP CKT %d re-configuration DONE!\n", x);
|
|
}
|
|
|
|
/* reset the circuit to sync states */
|
|
ftdm_mutex_lock(ftdmchan->mutex);
|
|
|
|
/* flag the circuit as active */
|
|
sngss7_set_flag(sngss7_info->circuit, SNGSS7_ACTIVE);
|
|
|
|
/* throw the channel into reset */
|
|
sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX);
|
|
|
|
/* throw the channel to suspend */
|
|
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
|
|
/* unlock the channel */
|
|
ftdm_mutex_unlock(ftdmchan->mutex);
|
|
|
|
} /* if (bits_ab == 0x3) */
|
|
} else {
|
|
/* check the maintenance block status in bits A and B */
|
|
switch (bits_ab) {
|
|
/**************************************************************************/
|
|
case (0):
|
|
/* no maintenace block...do nothing */
|
|
break;
|
|
/**************************************************************************/
|
|
case (1):
|
|
/* locally blocked */
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX);
|
|
|
|
/* set the channel to suspended state */
|
|
SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
break;
|
|
/**************************************************************************/
|
|
case (2):
|
|
/* remotely blocked */
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX);
|
|
|
|
/* set the channel to suspended state */
|
|
SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
break;
|
|
/**************************************************************************/
|
|
case (3):
|
|
/* both locally and remotely blocked */
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX);
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX);
|
|
|
|
/* set the channel to suspended state */
|
|
SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
break;
|
|
/**************************************************************************/
|
|
default:
|
|
break;
|
|
/**************************************************************************/
|
|
} /* switch (bits_ab) */
|
|
|
|
/* check the hardware block status in bits e and f */
|
|
switch (bits_ef) {
|
|
/**************************************************************************/
|
|
case (0):
|
|
/* no maintenace block...do nothing */
|
|
break;
|
|
/**************************************************************************/
|
|
case (1):
|
|
/* locally blocked */
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX);
|
|
|
|
/* set the channel to suspended state */
|
|
SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
break;
|
|
/**************************************************************************/
|
|
case (2):
|
|
/* remotely blocked */
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX);
|
|
|
|
/* set the channel to suspended state */
|
|
SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
break;
|
|
/**************************************************************************/
|
|
case (3):
|
|
/* both locally and remotely blocked */
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX);
|
|
sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX);
|
|
|
|
/* set the channel to suspended state */
|
|
SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
|
|
break;
|
|
/**************************************************************************/
|
|
default:
|
|
break;
|
|
/**************************************************************************/
|
|
} /* switch (bits_ef) */
|
|
}
|
|
|
|
/* clear the re-config flag ... no matter what */
|
|
sngss7_clear_ckt_flag(sngss7_info, FLAG_CKT_RECONFIG);
|
|
|
|
} /* if ((sngss7_test_ckt_flag(sngss7_info, FLAG_CKT_RECONFIG)) */
|
|
} /* for (x = 1; x < (span->chan_count + 1); x++) */
|
|
|
|
return FTDM_SUCCESS;
|
|
}
|
|
/******************************************************************************/
|
|
/* For Emacs:
|
|
* Local Variables:
|
|
* mode:c
|
|
* indent-tabs-mode:t
|
|
* tab-width:4
|
|
* c-basic-offset:4
|
|
* End:
|
|
* For VIM:
|
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
|
*/
|
|
/******************************************************************************/
|