diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index 03477ad359..2c779fe0f7 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -214,6 +214,8 @@ ftmod_sangoma_ss7_la_SOURCES = \ $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c \ $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sts.c \ $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c \ + $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c \ $(SRC)/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c ftmod_sangoma_ss7_la_CFLAGS = $(FTDM_CFLAGS) $(AM_CFLAGS) -D_GNU_SOURCE diff --git a/libs/freetdm/conf/freetdm.conf b/libs/freetdm/conf/freetdm.conf index eb506bef8d..0d53992979 100644 --- a/libs/freetdm/conf/freetdm.conf +++ b/libs/freetdm/conf/freetdm.conf @@ -13,7 +13,7 @@ cpu_monitoring_interval => 1000 cpu_set_alarm_threshold => 80 ; At what CPU percentage stop the CPU alarm -cpu_reset_alarm_threshold => 70 +cpu_clear_alarm_threshold => 70 ; Which action to take when the CPU alarm is raised ; it can be warn and/or reject calls diff --git a/libs/freetdm/docs/ss7-native-bridge.txt b/libs/freetdm/docs/ss7-native-bridge.txt new file mode 100644 index 0000000000..d44b067b0a --- /dev/null +++ b/libs/freetdm/docs/ss7-native-bridge.txt @@ -0,0 +1,43 @@ +SS7 Native Bridge + +Native bridge is enabled on 2 conditions: + +* The SIP header FreeTDM-TransUUID is set in the originating leg and matches a freetdm channel +* The variable freetdm_native_sigbridge is true and the originating leg is also a freetdm channel + +Some coding rules apply to this feature: + +- Each channel is responsible for clearning its own peer_data and event queue + at the end of the call (when moving to DOWN state) + +- Each channel dequeues messages only from its own queue and enqueues messages + in the peer's queue, with the only exception being messages received before + the bridge is stablished (IAM for sure and possible SAM messages) because + if the bridge is not yet stablished the messages must be queued by the channel + in its own queue temporarily until the bridge is ready + +- When the bridge is ready it is the responsibility of the incoming channel to + move the messages that stored temporarily in its own queue to the bridged peer queue + +- During hangup, each channel is responsible for moving itself to DOWN. The procedure + however differs slightly depending on the hangup conditions + + If the user requests hangup (ie, FreeSWITCH) the request will be noted by setting the + FTDM_CHANNEL_USER_HANGUP flag but will not be processed yet because call control is + driven only by the link messages (so no hangup from ESL or command line allowed) + + When REL message comes, the channel receiving it must move to TERMINATING state and: + + - If the user has not hangup yet (FTDM_CHANNEL_USER_HANGUP flag not set) then + notify the user via SIGEVENT_STOP and wait for the user to move to HANGUP + state by calling ftdm_channel_call_hangup() before sending RLC + + - If the user did hangup already (FTDM_CHANNEL_USER_HANGUP flag is set) then + skip user notification and move to HANGUP state directly where the RLC message + will be sent + +- On HANGUP state the RLC is sent and the channel is moved to DOWN, final state + The peer channel will forward the REL message and wait for RLC from the network, when + RLC is received the channel can move straight to DOWN itself because the peer channel + is completing its own shutdown procedure when it received the REL message + diff --git a/libs/freetdm/mod_freetdm/Makefile.in b/libs/freetdm/mod_freetdm/Makefile.in index ceea0dfbba..33ca03b440 100644 --- a/libs/freetdm/mod_freetdm/Makefile.in +++ b/libs/freetdm/mod_freetdm/Makefile.in @@ -4,6 +4,7 @@ BASE=../../.. FT_DIR=.. VERBOSE=1 FTLA=$(FT_DIR)/libfreetdm.la +LOCAL_OBJS=tdm.o LOCAL_CFLAGS=-I$(FT_DIR)/src/include -I$(FT_DIR)/src/isdn/include $(FT_CFLAGS) LOCAL_LDFLAGS=-L$(FT_DIR) -lfreetdm include $(BASE)/build/modmake.rules diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index f38ededc8e..da6fb095b0 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -26,6 +26,7 @@ * Anthony Minessale II * Moises Silva * David Yat Sin + * James Zhang * Gideon Sadan * * mod_freetdm.c -- FreeTDM Endpoint Module @@ -47,6 +48,8 @@ /* How many consecutive IO errors before giving up */ #define FTDM_MAX_READ_WRITE_ERRORS 10 +#define get_ss7_config_node(_cfg, _confname) _get_ss7_config_node(cfg, confname, "ISUP") + SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown); SWITCH_MODULE_DEFINITION(mod_freetdm, mod_freetdm_load, mod_freetdm_shutdown, NULL); @@ -117,6 +120,8 @@ struct private_object { ftdm_channel_t *ftdmchan; uint32_t write_error; uint32_t read_error; + char network_peer_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1]; + }; /* private data attached to FTDM channels (only FXS for now) */ @@ -166,6 +171,7 @@ static const char* channel_get_variable(switch_core_session_t *session, switch_e ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session_t **sp); void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream); void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream); +void ctdm_init(switch_loadable_module_interface_t *module_interface); static switch_core_session_t *ftdm_channel_get_session(ftdm_channel_t *channel, int32_t id) { @@ -569,6 +575,34 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) } #endif + name = switch_channel_get_name(channel); + + span_id = tech_pvt->ftdmchan ? ftdm_channel_get_span_id(tech_pvt->ftdmchan) : 0; + chan_id = tech_pvt->ftdmchan ? ftdm_channel_get_id(tech_pvt->ftdmchan) : 0; + + + /* Now verify the device is still attached to this call :-) + * Sometimes the FS core takes too long (more than 3 seconds) in calling + * channel_on_hangup() and the FreeTDM core decides to take the brute + * force approach and hangup and detach themselves from the call. Later + * when FS finally comes around, we might end up hanging up the device + * attached to another call, this verification avoids that. */ + uuid = switch_core_session_get_uuid(session); + tokencnt = ftdm_channel_get_token_count(tech_pvt->ftdmchan); + for (t = 0; t < tokencnt; t++) { + token = ftdm_channel_get_token(tech_pvt->ftdmchan, t); + if (!zstr(token) && !strcasecmp(uuid, token)) { + uuid_found = 1; + break; + } + } + + if (!uuid_found) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s. Nothing to do.\n", span_id, chan_id, name); + goto end; + } + + ftdm_channel_clear_token(tech_pvt->ftdmchan, switch_core_session_get_uuid(session)); chantype = ftdm_channel_get_type(tech_pvt->ftdmchan); @@ -594,11 +628,20 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) case FTDM_CHAN_TYPE_CAS: case FTDM_CHAN_TYPE_B: { + const char *var = NULL; ftdm_call_cause_t hcause = switch_channel_get_cause_q850(channel); if (hcause < 1 || hcause > 127) { hcause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER; } - ftdm_channel_call_hangup_with_cause(tech_pvt->ftdmchan, hcause); + var = switch_channel_get_variable(channel, "ss7_rel_loc"); + if (var) { + ftdm_usrmsg_t usrmsg; + memset(&usrmsg, 0, sizeof(ftdm_usrmsg_t)); + ftdm_usrmsg_add_var(&usrmsg, "ss7_rel_loc", var); + ftdm_channel_call_hangup_with_cause_ex(tech_pvt->ftdmchan, hcause, &usrmsg); + } else { + ftdm_channel_call_hangup_with_cause(tech_pvt->ftdmchan, hcause); + } } break; default: @@ -1272,10 +1315,15 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi int argc = 0; const char *var; const char *dest_num = NULL, *callerid_num = NULL; + const char *network_peer_uuid = NULL; + char sigbridge_peer[255]; + switch_channel_t *peer_chan = NULL; + switch_channel_t *our_chan = NULL; ftdm_hunting_scheme_t hunting; ftdm_usrmsg_t usrmsg; memset(&usrmsg, 0, sizeof(ftdm_usrmsg_t)); + memset(sigbridge_peer, 0, sizeof(sigbridge_peer)); if (!outbound_profile) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n"); @@ -1359,9 +1407,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi chan_id = 0; } - if (session && globals.sip_headers) { + if (session && globals.sip_headers && !switch_core_session_check_interface (session,freetdm_endpoint_interface) ) { switch_channel_t *channel = switch_core_session_get_channel(session); const char *sipvar; + + network_peer_uuid = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-TransUUID"); + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-CallerName"); if (sipvar) { ftdm_set_string(caller_data.cid_name, sipvar); @@ -1403,6 +1454,31 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi ftdm_set_string(caller_data.dnis.digits, sipvar); } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC"); + if (sipvar) { + ftdm_set_string(caller_data.loc.digits, sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Access-Transport-URLENC"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_access_transport_urlenc", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Screen"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_screen_ind", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-Presentation"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_pres_ind", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-LOC-NADI"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_loc_nadi", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-TON"); if (sipvar) { caller_data.dnis.type = (uint8_t)atoi(sipvar); @@ -1416,7 +1492,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi /* Used by ftmod_sangoma_ss7 only */ sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-NADI"); if (sipvar) { - ftdm_usrmsg_add_var(&usrmsg, "ss7_clg_nadi", sipvar); + ftdm_usrmsg_add_var(&usrmsg, "ss7_cld_nadi", sipvar); } sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS"); @@ -1499,6 +1575,50 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi if (sipvar) { ftdm_usrmsg_add_var(&usrmsg, "ss7_iam", sipvar); } + + /* redirection information */ + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDINF-Indicator"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_indicator", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDINF-OrigReason"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_orig", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDINF-Count"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_count", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDINF-Reason"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_rdinfo_reason", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-NADI"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_nadi", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-Plan"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_plan", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-OCN-Presentation"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_ocn_pres", sipvar); + } + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-IAM-FWD-IND-HEX"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_iam_fwd_ind_hex", sipvar); + } + + sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-IAM-NATURE-CONN-HEX"); + if (sipvar) { + ftdm_usrmsg_add_var(&usrmsg, "ss7_iam_nature_connection_hex", sipvar); + } } if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) { @@ -1509,6 +1629,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi caller_data.pres = FTDM_PRES_RESTRICTED; } + if ((var = channel_get_variable(session, var_event, "freetdm_iam_fwd_ind_isdn_access_ind"))) { + ftdm_usrmsg_add_var(&usrmsg, "iam_fwd_ind_isdn_access_ind", var); + } + if ((var = channel_get_variable(session, var_event, "freetdm_bearer_capability"))) { caller_data.bearer_capability = (uint8_t)atoi(var); } @@ -1595,6 +1719,36 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } + our_chan = switch_core_session_get_channel(*new_session); + + /* Figure out if there is a native bridge requested through SIP x headers */ + if (network_peer_uuid) { + switch_core_session_t *network_peer = switch_core_session_locate(network_peer_uuid); + if (network_peer) { + const char *my_uuid = switch_core_session_get_uuid(*new_session); + private_t *peer_private = switch_core_session_get_private(network_peer); + peer_chan = switch_core_session_get_channel(network_peer); + switch_set_string(tech_pvt->network_peer_uuid, network_peer_uuid); + switch_set_string(peer_private->network_peer_uuid, my_uuid); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session %s is network-bridged with %s\n", + my_uuid, network_peer_uuid); + + snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", + ftdm_channel_get_span_id(peer_private->ftdmchan), ftdm_channel_get_id(peer_private->ftdmchan)); + switch_core_session_rwunlock(network_peer); + } + /* Figure out if there is a native bridge requested through dial plan variable and the originating channel is also freetdm (not going through SIP) */ + } else if (session + && (var = channel_get_variable(session, var_event, FREETDM_VAR_PREFIX "native_sigbridge")) + && switch_true(var) + && switch_core_session_compare(*new_session, session)) { + private_t *peer_pvt = switch_core_session_get_private(session); + peer_chan = switch_core_session_get_channel(session); + snprintf(sigbridge_peer, sizeof(sigbridge_peer), "%u:%u", + ftdm_channel_get_span_id(peer_pvt->ftdmchan), ftdm_channel_get_id(peer_pvt->ftdmchan)); + } + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); caller_profile->destination_number = switch_core_strdup(caller_profile->pool, switch_str_nil(dest_num)); caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, switch_str_nil(callerid_num)); @@ -1606,6 +1760,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi hunt_data.tech_pvt = tech_pvt; caller_data.priv = &hunt_data; + if (session && !zstr(sigbridge_peer)) { + peer_chan = switch_core_session_get_channel(session); + ftdm_usrmsg_add_var(&usrmsg, "sigbridge_peer", sigbridge_peer); + } + if ((status = ftdm_call_place_ex(&caller_data, &hunting, &usrmsg)) != FTDM_SUCCESS) { if (tech_pvt->read_codec.implementation) { switch_core_codec_destroy(&tech_pvt->read_codec); @@ -1623,6 +1782,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi goto fail; } + if (our_chan && peer_chan) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Bridging native signaling of channel %s to channel %s\n", + switch_channel_get_name(peer_chan), switch_channel_get_name(our_chan)); + } + return SWITCH_CAUSE_SUCCESS; } @@ -1748,6 +1913,8 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session if (globals.sip_headers) { switch_channel_set_variable(channel, "sip_h_X-FreeTDM-SpanName", ftdm_channel_get_span_name(sigmsg->channel)); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-SpanNumber", "%d", spanid); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-TransUUID", "%s",switch_core_session_get_uuid(session)); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-SpanNumber", "%d", spanid); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-ChanNumber", "%d", chanid); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CallerName", "%s", channel_caller_data->cid_name); @@ -1767,53 +1934,94 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CPC", "%s", ftdm_calling_party_category2str(channel_caller_data->cpc)); + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_iam_nature_connection_hex"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-IAM-NATURE-CONN-HEX", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_iam_fwd_ind_hex"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-IAM-FWD-IND-HEX", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_access_transport_urlenc"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Access-Transport-URLENC", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_indicator"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-Indicator", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_orig"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-OrigReason", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_count"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-Count", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdinfo_reason"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDINF-Reason", "%s", var_value); + } + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_clg_nadi"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-NADI", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-NADI", "%s", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-ANI-NADI", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_cld_nadi"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-DNIS-NADI", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_screen_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Screen", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Screen", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_rdnis_pres_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Presentation", "%d", channel_caller_data->rdnis.plan); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Presentation", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_digits"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN", "%s", var_value); var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_numqual"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumQual", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumQual", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_nadi"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NADI", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NADI", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_screen_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Screen", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Screen", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_pres_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Presentation", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Presentation", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_npi"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Plan", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-Plan", "%s", var_value); } var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_num_inc_ind"); if (!ftdm_strlen_zero(var_value)) { - switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumInComp", "%d", var_value); + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-GN-NumInComp", "%s", var_value); } } /* End - var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_gn_digits"); */ @@ -1835,6 +2043,46 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session if (!ftdm_strlen_zero(var_value)) { switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OPC", "%s", var_value); } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_digits"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_screen_ind"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-Screen", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_pres_ind"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-Presentation", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_loc_nadi"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-LOC-NADI", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_nadi"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-NADI", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_plan"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-Plan", "%s", var_value); + } + + var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_ocn_pres"); + if (!ftdm_strlen_zero(var_value)) { + switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-OCN-Presentation", "%s", var_value); + } } /* Add any call variable to the dial plan */ @@ -2578,7 +2826,7 @@ static uint32_t enable_analog_option(const char *str, uint32_t current_options) return current_options; } -#define CONFIG_ERROR(...) { \ +#define LOAD_ERROR(...) { \ ftdm_log(FTDM_LOG_ERROR, __VA_ARGS__); \ globals.config_error = 1; \ } @@ -2639,11 +2887,83 @@ static int add_config_list_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode return 0; } -static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confname) +/* create ftdm_conf_node_t tree based on a fixed pattern XML configuration list + * last arg is to specify if we have any sublist for e.g. + * + * + * + * + * + * + * + * + * */ +static int add_config_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode, + const char *list_name, const char *list_element_name, const char *sub_list_name) +{ + char *var, *val; + switch_xml_t list; + switch_xml_t sub_list; + switch_xml_t element; + switch_xml_t param; + + ftdm_conf_node_t *n_list; + ftdm_conf_node_t *n_element; + + list = switch_xml_child(swnode, list_name); + if (!list) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no list %s found\n", list_name); + return -1; + } + + if ((FTDM_SUCCESS != ftdm_conf_node_create(list_name, &n_list, rootnode))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create %s node\n", list_name); + return -1; + } + + for (element = switch_xml_child(list, list_element_name); element; element = element->next) { + char *element_name = (char *) switch_xml_attr(element, "name"); + + if (!element_name) { + continue; + } + + if ((FTDM_SUCCESS != ftdm_conf_node_create(list_element_name, &n_element, n_list))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create %s node for %s\n", list_element_name, element_name); + return -1; + } + ftdm_conf_node_add_param(n_element, "name", element_name); + + for (param = switch_xml_child(element, "param"); param; param = param->next) { + var = (char *) switch_xml_attr_soft(param, "name"); + val = (char *) switch_xml_attr_soft(param, "value"); + ftdm_conf_node_add_param(n_element, var, val); + } + + /*If we have single node list */ + if (sub_list_name ) { + sub_list = switch_xml_child(element, sub_list_name); + if (!sub_list) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no sub_list %s found\n", sub_list_name); + return -1; + } + for (param = switch_xml_child(sub_list, "param"); param; param = param->next) { + var = (char *) switch_xml_attr_soft(param, "name"); + val = (char *) switch_xml_attr_soft(param, "value"); + ftdm_conf_node_add_param(n_element, var, val); + } + } + } + + return 0; +} + +static ftdm_conf_node_t *_get_ss7_config_node(switch_xml_t cfg, const char *confname, const char *operating_mode) { switch_xml_t signode, ss7configs, isup, gen, param; ftdm_conf_node_t *rootnode, *list; char *var, *val; + int is_isup = 0x00; /* try to find the conf in the hash first */ rootnode = switch_core_hash_find(globals.ss7_configs, confname); @@ -2665,8 +2985,11 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn return NULL; } - /* search the isup config */ - for (isup = switch_xml_child(ss7configs, "sng_isup"); isup; isup = isup->next) { + /* sng_isup and ss7config xml childs are treated the same way. sng_isup was used initially, but does not make sense + * for configurations that do not have an ISUP layer, sng_isup is kept for backward compatibility */ + + /* search the ss7config */ + for (isup = switch_xml_child(ss7configs, "sngss7_config"); isup; isup = isup->next) { char *name = (char *) switch_xml_attr(isup, "name"); if (!name) { continue; @@ -2675,10 +2998,23 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn break; } } - + if (!isup) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found '%s' sng_isup XML config section\n", confname); - return NULL; + /* search the isup config */ + for (isup = switch_xml_child(ss7configs, "sng_isup"); isup; isup = isup->next) { + char *name = (char *) switch_xml_attr(isup, "name"); + if (!name) { + continue; + } + if (!strcasecmp(name, confname)) { + break; + } + } + + if (!isup) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found '%s' ss7config or sng_isup XML config section\n", confname); + return NULL; + } } /* found our XML chunk, create the root node */ @@ -2687,6 +3023,23 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn return NULL; } + /* operating mode , M2UA or ISUP */ + if(operating_mode && ('\0' != operating_mode[0])) { + if(!strcasecmp(operating_mode, "ISUP")) { + is_isup = 0x01; + } + else if(!strcasecmp(operating_mode, "M2UA_SG")) { + is_isup = 0x00; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid operating Mode[%s] \n", operating_mode); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Operating mode not specified, default to ISUP \n"); + is_isup = 0x01; + } + /* add sng_gen */ gen = switch_xml_child(isup, "sng_gen"); if (gen == NULL) { @@ -2728,39 +3081,72 @@ static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confn return NULL; } - /* add mtp3 links */ - if (add_config_list_nodes(isup, rootnode, "mtp3_links", "mtp3_link", NULL, NULL)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp3_links for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; - } + if(is_isup) { + /* add mtp3 links */ + if (add_config_list_nodes(isup, rootnode, "mtp3_links", "mtp3_link", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp3_links for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } - /* add mtp linksets */ - if (add_config_list_nodes(isup, rootnode, "mtp_linksets", "mtp_linkset", NULL, NULL)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_linksets for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; - } + /* add mtp linksets */ + if (add_config_list_nodes(isup, rootnode, "mtp_linksets", "mtp_linkset", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_linksets for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } - /* add mtp routes */ - if (add_config_list_nodes(isup, rootnode, "mtp_routes", "mtp_route", "linksets", "linkset")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_routes for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; - } + /* add mtp routes */ + if (add_config_list_nodes(isup, rootnode, "mtp_routes", "mtp_route", "linksets", "linkset")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_routes for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } - /* add isup interfaces */ - if (add_config_list_nodes(isup, rootnode, "isup_interfaces", "isup_interface", NULL, NULL)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process isup_interfaces for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; - } + /* add isup interfaces */ + if (add_config_list_nodes(isup, rootnode, "isup_interfaces", "isup_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process isup_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } - /* add cc spans */ - if (add_config_list_nodes(isup, rootnode, "cc_spans", "cc_span", NULL, NULL)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process cc_spans for sng_isup config %s\n", confname); - ftdm_conf_node_destroy(rootnode); - return NULL; + /* add cc spans */ + if (add_config_list_nodes(isup, rootnode, "cc_spans", "cc_span", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process cc_spans for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + } else { + /* add sctp links */ + if (add_config_nodes(isup, rootnode, "sng_sctp_interfaces", "sng_sctp_interface", "sng_source_addresses")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_sctp_interface for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + if (add_config_list_nodes(isup, rootnode, "sng_nif_interfaces", "sng_nif_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_nif_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + if (add_config_list_nodes(isup, rootnode, "sng_m2ua_interfaces", "sng_m2ua_interface", NULL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + if (add_config_nodes(isup, rootnode, "sng_m2ua_peer_interfaces", "sng_m2ua_peer_interface", "sng_destination_addresses")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_peer_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } + + if (add_config_nodes(isup, rootnode, "sng_m2ua_cluster_interfaces", "sng_m2ua_cluster_interface", "sng_m2ua_peers")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process sng_m2ua_cluster_interfaces for sng_isup config %s\n", confname); + ftdm_conf_node_destroy(rootnode); + return NULL; + } } switch_core_hash_insert(globals.ss7_configs, confname, rootnode); @@ -2776,7 +3162,7 @@ static int add_profile_parameters(switch_xml_t cfg, const char *profname, ftdm_c profnode = switch_xml_child(cfg, "config_profiles"); if (!profnode) { - CONFIG_ERROR("cannot find profile '%s', there is no 'config_profiles' XML section\n", profname); + LOAD_ERROR("cannot find profile '%s', there is no 'config_profiles' XML section\n", profname); return 0; } @@ -2792,7 +3178,7 @@ static int add_profile_parameters(switch_xml_t cfg, const char *profname, ftdm_c } if (!profile) { - CONFIG_ERROR("failed to find profile '%s'\n", profname); + LOAD_ERROR("failed to find profile '%s'\n", profname); return 0; } @@ -2827,7 +3213,7 @@ static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans) unsigned paramindex = 0; if (!name && !id) { - CONFIG_ERROR("GSM span missing required attribute 'id' or 'name', skipping ...\n"); + LOAD_ERROR("GSM span missing required attribute 'id' or 'name', skipping ...\n"); continue; } @@ -2845,7 +3231,7 @@ static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -2868,7 +3254,7 @@ static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for GSM span, ignoring any parameter after %s\n", var); + LOAD_ERROR("Too many parameters for GSM span, ignoring any parameter after %s\n", var); break; } @@ -2887,7 +3273,7 @@ static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans) "gsm", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring Sangoma GSM FreeTDM span %d\n", span_id); + LOAD_ERROR("Error configuring Sangoma GSM FreeTDM span %d\n", span_id); continue; } SPAN_CONFIG[span_id].span = span; @@ -2916,7 +3302,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) unsigned paramindex = 0; if (!name && !id) { - CONFIG_ERROR("sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); + LOAD_ERROR("sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); continue; } @@ -2934,7 +3320,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -2962,7 +3348,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); + LOAD_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); break; } @@ -2992,10 +3378,10 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) int calls; int seconds; if (sscanf(val, "%d/%d", &calls, &seconds) != 2) { - CONFIG_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); + LOAD_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); } else { if (calls < 1 || seconds < 1) { - CONFIG_ERROR("Invalid %s parameter value, minimum call limit must be 1 per second\n", var); + LOAD_ERROR("Invalid %s parameter value, minimum call limit must be 1 per second\n", var); } else { SPAN_CONFIG[span_id].limit_calls = calls; SPAN_CONFIG[span_id].limit_seconds = seconds; @@ -3005,7 +3391,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) if (!strcasecmp(val, "answer")) { SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_ANSWER; } else { - CONFIG_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); + LOAD_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); } } else { spanparameters[paramindex].var = var; @@ -3018,7 +3404,7 @@ static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) "sangoma_isdn", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); + LOAD_ERROR("Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); continue; } SPAN_CONFIG[span_id].span = span; @@ -3090,15 +3476,16 @@ static switch_status_t load_config(void) char *id = (char *) switch_xml_attr(myspan, "id"); char *name = (char *) switch_xml_attr(myspan, "name"); char *configname = (char *) switch_xml_attr(myspan, "cfgprofile"); + char *operating_mode = (char *) switch_xml_attr(myspan, "operating_mode"); ftdm_span_t *span = NULL; uint32_t span_id = 0; unsigned paramindex = 0; if (!name && !id) { - CONFIG_ERROR("ss7 span missing required attribute 'id' or 'name', skipping ...\n"); + LOAD_ERROR("ss7 span missing required attribute 'id' or 'name', skipping ...\n"); continue; } if (!configname) { - CONFIG_ERROR("ss7 span missing required attribute, skipping ...\n"); + LOAD_ERROR("ss7 span missing required attribute, skipping ...\n"); continue; } if (name) { @@ -3115,7 +3502,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3123,14 +3510,19 @@ static switch_status_t load_config(void) span_id = ftdm_span_get_id(span); } - ss7confnode = get_ss7_config_node(cfg, configname); + ss7confnode = _get_ss7_config_node(cfg, configname, operating_mode); if (!ss7confnode) { - CONFIG_ERROR("Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); + LOAD_ERROR("Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id)); continue; } memset(spanparameters, 0, sizeof(spanparameters)); paramindex = 0; + if(operating_mode){ + spanparameters[paramindex].var = "operating-mode"; + spanparameters[paramindex].val = operating_mode; + paramindex++; + } spanparameters[paramindex].var = "confnode"; spanparameters[paramindex].ptr = ss7confnode; paramindex++; @@ -3139,7 +3531,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); + LOAD_ERROR("Too many parameters for ss7 span, ignoring any parameter after %s\n", var); break; } @@ -3158,7 +3550,7 @@ static switch_status_t load_config(void) "sangoma_ss7", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring ss7 FreeTDM span %d\n", span_id); + LOAD_ERROR("Error configuring ss7 FreeTDM span %d\n", span_id); continue; } SPAN_CONFIG[span_id].span = span; @@ -3166,7 +3558,10 @@ static switch_status_t load_config(void) switch_copy_string(SPAN_CONFIG[span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span_id].dialplan)); switch_copy_string(SPAN_CONFIG[span_id].type, "Sangoma (SS7)", sizeof(SPAN_CONFIG[span_id].type)); ftdm_log(FTDM_LOG_DEBUG, "Configured ss7 FreeTDM span %d with config node %s\n", span_id, configname); - ftdm_span_start(span); + if(FTDM_SUCCESS != ftdm_span_start(span)){ + LOAD_ERROR("Error Starting ss7 FreeTDM span %d\n", span_id); + continue; + } } } @@ -3210,7 +3605,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3244,10 +3639,10 @@ static switch_status_t load_config(void) int calls; int seconds; if (sscanf(val, "%d/%d", &calls, &seconds) != 2) { - CONFIG_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); + LOAD_ERROR("Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); } else { if (calls < 1 || seconds < 1) { - CONFIG_ERROR("Invalid %s parameter value, minimum call limit must be 1 per second\n", var); + LOAD_ERROR("Invalid %s parameter value, minimum call limit must be 1 per second\n", var); } else { SPAN_CONFIG[span_id].limit_calls = calls; SPAN_CONFIG[span_id].limit_seconds = seconds; @@ -3257,7 +3652,7 @@ static switch_status_t load_config(void) if (!strcasecmp(val, "answer")) { SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_ANSWER; } else { - CONFIG_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); + LOAD_ERROR("Invalid %s parameter value, only accepted event is 'answer'\n", var); } } else if (!strcasecmp(var, "dial-regex")) { dial_regex = val; @@ -3287,7 +3682,7 @@ static switch_status_t load_config(void) } if (!id && !name) { - CONFIG_ERROR("span missing required param 'id'\n"); + LOAD_ERROR("span missing required param 'id'\n"); continue; } @@ -3317,7 +3712,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3338,7 +3733,7 @@ static switch_status_t load_config(void) "callwaiting", &callwaiting, "wait_dialtone_timeout", &dialtone_timeout, FTDM_TAG_END) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); + LOAD_ERROR("Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); continue; } @@ -3414,7 +3809,7 @@ static switch_status_t load_config(void) } if (!id && !name) { - CONFIG_ERROR("span missing required param 'id'\n"); + LOAD_ERROR("span missing required param 'id'\n"); continue; } @@ -3445,7 +3840,7 @@ static switch_status_t load_config(void) } if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + LOAD_ERROR("Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); continue; } @@ -3459,7 +3854,7 @@ static switch_status_t load_config(void) "digit_timeout", &to, "max_dialstr", &max, FTDM_TAG_END) != FTDM_SUCCESS) { - CONFIG_ERROR("Error starting FreeTDM span %d\n", span_id); + LOAD_ERROR("Error starting FreeTDM span %d\n", span_id); continue; } @@ -3496,7 +3891,7 @@ static switch_status_t load_config(void) uint32_t span_id = 0; if (!name) { - CONFIG_ERROR("span missing required attribute 'name'\n"); + LOAD_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3507,7 +3902,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for pri span '%s', ignoring everything after '%s'\n", name, var); + LOAD_ERROR("Too many parameters for pri span '%s', ignoring everything after '%s'\n", name, var); break; } @@ -3529,13 +3924,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span %s\n", name); + LOAD_ERROR("Error finding FreeTDM span %s\n", name); continue; } span_id = ftdm_span_get_id(span); if (ftdm_configure_span_signaling(span, "isdn", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); + LOAD_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3562,7 +3957,7 @@ static switch_status_t load_config(void) int span_id = 0; if (!name) { - CONFIG_ERROR("span missing required attribute 'name'\n"); + LOAD_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3573,7 +3968,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for pritap span '%s', ignoring everything after '%s'\n", name, var); + LOAD_ERROR("Too many parameters for pritap span '%s', ignoring everything after '%s'\n", name, var); break; } @@ -3590,13 +3985,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span %s\n", name); + LOAD_ERROR("Error finding FreeTDM span %s\n", name); continue; } span_id = ftdm_span_get_id(span); if (ftdm_configure_span_signaling(span, "pritap", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); + LOAD_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3622,7 +4017,7 @@ static switch_status_t load_config(void) uint32_t span_id = 0; if (!name) { - CONFIG_ERROR("span missing required attribute 'name'\n"); + LOAD_ERROR("span missing required attribute 'name'\n"); continue; } @@ -3633,7 +4028,7 @@ static switch_status_t load_config(void) char *val = (char *) switch_xml_attr_soft(param, "value"); if (ftdm_array_len(spanparameters) - 1 == paramindex) { - CONFIG_ERROR("Too many parameters for libpri span, ignoring everything after '%s'\n", var); + LOAD_ERROR("Too many parameters for libpri span, ignoring everything after '%s'\n", var); break; } @@ -3655,13 +4050,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM span %s\n", name); + LOAD_ERROR("Error finding FreeTDM span %s\n", name); continue; } span_id = ftdm_span_get_id(span); if (ftdm_configure_span_signaling(span, "libpri", on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring FreeTDM span %s\n", name); + LOAD_ERROR("Error configuring FreeTDM span %s\n", name); continue; } @@ -3692,7 +4087,7 @@ static switch_status_t load_config(void) unsigned paramindex = 0; if (!name) { - CONFIG_ERROR("'name' attribute required for R2 spans!\n"); + LOAD_ERROR("'name' attribute required for R2 spans!\n"); continue; } @@ -3727,13 +4122,13 @@ static switch_status_t load_config(void) zstatus = ftdm_span_find_by_name(name, &span); if (zstatus != FTDM_SUCCESS) { - CONFIG_ERROR("Error finding FreeTDM R2 Span '%s'\n", name); + LOAD_ERROR("Error finding FreeTDM R2 Span '%s'\n", name); continue; } span_id = ftdm_span_get_id(span); if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, spanparameters) != FTDM_SUCCESS) { - CONFIG_ERROR("Error configuring FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); + LOAD_ERROR("Error configuring FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); continue; } @@ -3751,7 +4146,7 @@ static switch_status_t load_config(void) switch_copy_string(SPAN_CONFIG[span_id].type, "R2", sizeof(SPAN_CONFIG[span_id].type)); if (ftdm_span_start(span) == FTDM_FAIL) { - CONFIG_ERROR("Error starting FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); + LOAD_ERROR("Error starting FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span)); continue; } } @@ -4802,7 +5197,8 @@ static ftdm_cli_entry_t ftdm_cli_options[] = /* Fake handlers as they are handled within freetdm library, * we should provide a way inside freetdm to query for completions from signaling modules */ { "core state", "[!]", "", NULL }, - { "core flag", "[!]", "", NULL }, + { "core flag", "[!] [] []", "", NULL }, + { "core spanflag", "[!] []", "", NULL }, { "core calls", "", "", NULL }, }; @@ -4978,6 +5374,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load) SWITCH_ADD_APP(app_interface, "disable_dtmf", "Disable DTMF Detection", "Disable DTMF Detection", disable_dtmf_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "enable_dtmf", "Enable DTMF Detection", "Enable DTMF Detection", enable_dtmf_function, "", SAF_NONE); + ctdm_init(*module_interface); + /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c new file mode 100644 index 0000000000..0f8b5814c1 --- /dev/null +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -0,0 +1,712 @@ +/* +* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* Copyright (C) 2005-2011, Anthony Minessale II +* +* Version: MPL 1.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* +* The Initial Developer of the Original Code is +* Anthony Minessale II +* Portions created by the Initial Developer are Copyright (C) +* the Initial Developer. All Rights Reserved. +* +* Contributor(s): +* +* Mathieu Rene +* +* tdm.c -- FreeTDM Controllable Channel Module +* +*/ + +#include +#include "freetdm.h" + +void ctdm_init(switch_loadable_module_interface_t *module_interface); + +/* Parameters */ + +#define kSPAN_ID "span" +#define kCHAN_ID "chan" +#define kSPAN_NAME "span_name" +#define kPREBUFFER_LEN "prebuffer_len" +#define kECHOCANCEL "echo_cancel" + + +static struct { + switch_memory_pool_t *pool; + switch_endpoint_interface_t *endpoint_interface; +} ctdm; + +typedef struct { + int span_id; + int chan_id; + ftdm_channel_t *ftdm_channel; + switch_core_session_t *session; + switch_codec_t read_codec, write_codec; + switch_frame_t read_frame; + int prebuffer_len; + + unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; +} ctdm_private_t; + +static switch_status_t channel_on_init(switch_core_session_t *session); +static switch_status_t channel_on_destroy(switch_core_session_t *session); +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event); +static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); + + +static ftdm_status_t ctdm_span_prepare(ftdm_span_t *span); + +switch_state_handler_table_t ctdm_state_handlers = { + .on_init = channel_on_init, + .on_destroy = channel_on_destroy +}; + +switch_io_routines_t ctdm_io_routines = { + .send_dtmf = channel_send_dtmf, + .outgoing_channel = channel_outgoing_channel, + .read_frame = channel_read_frame, + .write_frame = channel_write_frame, + .receive_message = channel_receive_message, + .receive_event = channel_receive_event +}; + +static void ctdm_report_alarms(ftdm_channel_t *channel) +{ + switch_event_t *event = NULL; + ftdm_alarm_flag_t alarmflag = 0; + + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to create alarms events\n"); + return; + } + + if (ftdm_channel_get_alarms(channel, &alarmflag) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve alarms %s:%d\n", ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + return; + } + + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(channel)); + + if (alarmflag) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); + } + + if (alarmflag & FTDM_ALARM_RED) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red"); + } + if (alarmflag & FTDM_ALARM_YELLOW) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow"); + } + if (alarmflag & FTDM_ALARM_RAI) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai"); + } + if (alarmflag & FTDM_ALARM_BLUE) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue"); + } + if (alarmflag & FTDM_ALARM_AIS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais"); + } + if (alarmflag & FTDM_ALARM_GENERAL) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general"); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Reporting [%s] alarms for %s:%d\n", + (alarmflag?"ftdm-alarm-trap":"ftdm-alarm-clear"), ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + + switch_event_fire(&event); + return; +} + +static ftdm_channel_t *ctdm_get_channel_from_event(switch_event_t *event, ftdm_span_t *span) +{ + uint32_t chan_id = 0; + const char *chan_number = NULL; + + chan_number = switch_event_get_header(event, "chan-number"); + + if (zstr(chan_number)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No channel number specified\n"); + return NULL; + } + chan_id = atoi(chan_number); + if (!chan_id) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid channel number:%s\n", chan_number); + return NULL; + } + + return ftdm_span_get_channel_ph(span, chan_id); +} + + +static void ctdm_event_handler(switch_event_t *event) +{ + ftdm_status_t status = FTDM_FAIL; + switch(event->event_id) { + case SWITCH_EVENT_TRAP: + { + ftdm_span_t *span = NULL; + ftdm_channel_t *channel = NULL; + const char *span_name = NULL; + + const char *cond = switch_event_get_header(event, "condition"); + const char *command = switch_event_get_header(event, "command"); + if (zstr(cond)) { + return; + } + + span_name = switch_event_get_header(event, "span-name"); + + if (ftdm_span_find_by_name(span_name, &span) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n", span_name); + return; + } + + if (!strcmp(cond, "mg-tdm-prepare")) { + status = ctdm_span_prepare(span); + if (status == FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s:prepared successfully\n", span_name); + } else if (status != FTDM_EINVAL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s:Failed to prepare span\n", span_name); + } + } else if (!strcmp(cond, "mg-tdm-check")) { + channel = ctdm_get_channel_from_event(event, span); + if (!channel) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find channel\n"); + return; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting alarm status for %s:%d\n", + ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + + ctdm_report_alarms(channel); + } else if (!strcmp(cond, "mg-tdm-dtmfremoval")) { + uint8_t enable = 0; + channel = ctdm_get_channel_from_event(event, span); + if (!channel) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find channel\n"); + return; + } + + if (zstr(command)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s:No command specified for mg-tdm-dtmfremoval\n", span_name); + return; + } + + if (!strcmp(command, "enable")) { + enable = 1; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s DTMF-removal for %s:%d\n", + enable ? "Enabling" : "Disabling", ftdm_channel_get_span_name(channel), ftdm_channel_get_id(channel)); + + ftdm_channel_command(channel, enable ? FTDM_COMMAND_ENABLE_DTMF_REMOVAL : FTDM_COMMAND_DISABLE_DTMF_REMOVAL, 0); + } + } + break; + default: + break; + } + return; +} + +void ctdm_init(switch_loadable_module_interface_t *module_interface) +{ + switch_endpoint_interface_t *endpoint_interface; + ctdm.pool = module_interface->pool; + endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); + endpoint_interface->interface_name = "tdm"; + endpoint_interface->io_routines = &ctdm_io_routines; + endpoint_interface->state_handler = &ctdm_state_handlers; + ctdm.endpoint_interface = endpoint_interface; + + switch_event_bind("mod_freetdm", SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, ctdm_event_handler, NULL); +} + +static FIO_SIGNAL_CB_FUNCTION(on_signal_cb) +{ + uint32_t chanid, spanid; + switch_event_t *event = NULL; + ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE; + + chanid = ftdm_channel_get_id(sigmsg->channel); + spanid = ftdm_channel_get_span_id(sigmsg->channel); + + switch(sigmsg->event_id) { + case FTDM_SIGEVENT_ALARM_CLEAR: + case FTDM_SIGEVENT_ALARM_TRAP: + { + if (ftdm_channel_get_alarms(sigmsg->channel, &alarmbits) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to retrieve alarms\n"); + return FTDM_FAIL; + } + + if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to create alarms events\n"); + return FTDM_FAIL; + } + if (sigmsg->event_id == FTDM_SIGEVENT_ALARM_CLEAR) { + ftdm_log(FTDM_LOG_NOTICE, "Alarm cleared on channel %d:%d\n", spanid, chanid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear"); + } else { + ftdm_log(FTDM_LOG_NOTICE, "Alarm raised on channel %d:%d\n", spanid, chanid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap"); + } + } + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unhandled event %d\n", sigmsg->event_id); + break; + } + + if (event) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(sigmsg->channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(sigmsg->channel)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(sigmsg->channel)); + + if (alarmbits & FTDM_ALARM_RED) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red"); + } + if (alarmbits & FTDM_ALARM_YELLOW) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow"); + } + if (alarmbits & FTDM_ALARM_RAI) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai"); + } + if (alarmbits & FTDM_ALARM_BLUE) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue"); + } + if (alarmbits & FTDM_ALARM_AIS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais"); + } + if (alarmbits & FTDM_ALARM_GENERAL) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general"); + } + + switch_event_fire(&event); + } + return FTDM_SUCCESS; +} + +static ftdm_status_t ctdm_span_prepare(ftdm_span_t *span) +{ + if (ftdm_span_register_signal_cb(span, on_signal_cb) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register signal CB\n"); + return FTDM_FAIL; + } + return ftdm_span_start(span); +} + +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) +{ + const char *szchanid = switch_event_get_header(var_event, kCHAN_ID), + *span_name = switch_event_get_header(var_event, kSPAN_NAME), + *szprebuffer_len = switch_event_get_header(var_event, kPREBUFFER_LEN); + int chan_id; + int span_id; + switch_caller_profile_t *caller_profile; + ftdm_span_t *span; + ftdm_channel_t *chan; + switch_channel_t *channel; + char name[128]; + const char *dname; + ftdm_codec_t codec; + uint32_t interval; + ctdm_private_t *tech_pvt = NULL; + + if (zstr(szchanid) || zstr(span_name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both ["kSPAN_ID"] and ["kCHAN_ID"] have to be set.\n"); + goto fail; + } + + chan_id = atoi(szchanid); + + if (ftdm_span_find_by_name(span_name, &span) == FTDM_SUCCESS) { + span_id = ftdm_span_get_id(span); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n", span_name); + goto fail; + } + + if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n"); + goto fail; + } + + channel = switch_core_session_get_channel(*new_session); + + if (ftdm_channel_open_ph(span_id, chan_id, &chan) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open span or channel.\n"); + goto fail; + } + + span = ftdm_channel_get_span(chan); + + tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt); + tech_pvt->chan_id = chan_id; + tech_pvt->span_id = span_id; + tech_pvt->ftdm_channel = chan; + tech_pvt->session = *new_session; + tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); + tech_pvt->read_frame.data = tech_pvt->databuf; + tech_pvt->prebuffer_len = zstr(szprebuffer_len) ? 0 : atoi(szprebuffer_len); + switch_core_session_set_private(*new_session, tech_pvt); + + + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); + switch_channel_set_caller_profile(channel, caller_profile); + + snprintf(name, sizeof(name), "tdm/%d:%d", span_id, chan_id); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name); + switch_channel_set_name(channel, name); + + switch_channel_set_state(channel, CS_INIT); + + if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_GET_CODEC, &codec)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel codec.\n"); + return SWITCH_STATUS_GENERR; + } + + if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_GET_INTERVAL, &interval)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel interval.\n"); + return SWITCH_STATUS_GENERR; + } + + if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tech_pvt->prebuffer_len)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set channel pre buffer size.\n"); + return SWITCH_STATUS_GENERR; + } + + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to set enable echo cancellation.\n"); + } + + switch(codec) { + case FTDM_CODEC_ULAW: + { + dname = "PCMU"; + } + break; + case FTDM_CODEC_ALAW: + { + dname = "PCMA"; + } + break; + case FTDM_CODEC_SLIN: + { + dname = "L16"; + } + break; + default: + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec value retrieved from channel, codec value: %d\n", codec); + goto fail; + } + } + + + if (switch_core_codec_init(&tech_pvt->read_codec, + dname, + NULL, + 8000, + interval, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + goto fail; + } else { + if (switch_core_codec_init(&tech_pvt->write_codec, + dname, + NULL, + 8000, + interval, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_core_codec_destroy(&tech_pvt->read_codec); + goto fail; + } + } + + if (switch_core_session_set_read_codec(*new_session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n"); + goto fail; + } + + if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + } + + if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); + goto fail; + } + + switch_channel_mark_answered(channel); + + return SWITCH_CAUSE_SUCCESS; + +fail: + + if (tech_pvt) { + if (tech_pvt->ftdm_channel) { + ftdm_channel_close(&tech_pvt->ftdm_channel); + } + + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + } + + if (*new_session) { + switch_core_session_destroy(new_session); + } + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; +} + +static switch_status_t channel_on_init(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + + switch_channel_set_state(channel, CS_CONSUME_MEDIA); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_destroy(switch_core_session_t *session) +{ + ctdm_private_t *tech_pvt = switch_core_session_get_private(session); + + if ((tech_pvt = switch_core_session_get_private(session))) { + + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to enable echo cancellation.\n"); + } + + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + + ftdm_channel_close(&tech_pvt->ftdm_channel); + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) +{ + ftdm_wait_flag_t wflags = FTDM_READ; + ftdm_status_t status; + ctdm_private_t *tech_pvt; + const char *name; + switch_channel_t *channel; + int chunk; + uint32_t span_id, chan_id; + ftdm_size_t len; + char dtmf[128] = ""; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + name = switch_channel_get_name(channel); + +top: + wflags = FTDM_READ; + chunk = ftdm_channel_get_io_interval(tech_pvt->ftdm_channel) * 2; + status = ftdm_channel_wait(tech_pvt->ftdm_channel, &wflags, chunk); + + + span_id = ftdm_channel_get_span_id(tech_pvt->ftdm_channel); + chan_id = ftdm_channel_get_id(tech_pvt->ftdm_channel); + + if (status == FTDM_FAIL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id); + goto fail; + } + + if (status == FTDM_TIMEOUT) { + goto top; + } + + if (!(wflags & FTDM_READ)) { + goto top; + } + + len = tech_pvt->read_frame.buflen; + if (ftdm_channel_read(tech_pvt->ftdm_channel, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id); + } + + *frame = &tech_pvt->read_frame; + tech_pvt->read_frame.datalen = (uint32_t)len; + tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen; + tech_pvt->read_frame.codec = &tech_pvt->read_codec; + + if (ftdm_channel_get_codec(tech_pvt->ftdm_channel) == FTDM_CODEC_SLIN) { + tech_pvt->read_frame.samples /= 2; + } + + while (ftdm_channel_dequeue_dtmf(tech_pvt->ftdm_channel, dtmf, sizeof(dtmf))) { + switch_dtmf_t _dtmf = { 0, switch_core_default_dtmf_duration(0) }; + char *p; + for (p = dtmf; p && *p; p++) { + if (is_dtmf(*p)) { + _dtmf.digit = *p; + ftdm_log(FTDM_LOG_DEBUG, "Queuing DTMF [%c] in channel %s device %d:%d\n", *p, name, span_id, chan_id); + switch_channel_queue_dtmf(channel, &_dtmf); + } + } + } + + return SWITCH_STATUS_SUCCESS; + +fail: + return SWITCH_STATUS_GENERR; +} + +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +{ + ftdm_wait_flag_t wflags = FTDM_WRITE; + ctdm_private_t *tech_pvt; + const char *name; + switch_channel_t *channel; + uint32_t span_id, chan_id; + ftdm_size_t len; + unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0}; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + span_id = ftdm_channel_get_span_id(tech_pvt->ftdm_channel); + chan_id = ftdm_channel_get_id(tech_pvt->ftdm_channel); + + name = switch_channel_get_name(channel); + + if (switch_test_flag(frame, SFF_CNG)) { + frame->data = data; + frame->buflen = sizeof(data); + if ((frame->datalen = tech_pvt->write_codec.implementation->encoded_bytes_per_packet) > frame->buflen) { + goto fail; + } + memset(data, 255, frame->datalen); + } + + wflags = FTDM_WRITE; + ftdm_channel_wait(tech_pvt->ftdm_channel, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdm_channel) * 10); + + if (!(wflags & FTDM_WRITE)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id); + return SWITCH_STATUS_SUCCESS; + } + + len = frame->datalen; + if (ftdm_channel_write(tech_pvt->ftdm_channel, frame->data, frame->buflen, &len) != FTDM_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Failed to write to channel %s device %d:%d!\n", name, span_id, chan_id); + } + + return SWITCH_STATUS_SUCCESS; + +fail: + return SWITCH_STATUS_GENERR; +} + +static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) +{ + ctdm_private_t *tech_pvt = NULL; + char tmp[2] = ""; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + tmp[0] = dtmf->digit; + ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_SEND_DTMF, tmp); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event) +{ + const char *command = switch_event_get_header(event, "command"); + ctdm_private_t *tech_pvt = switch_core_session_get_private(session); + + if (!zstr(command)) { + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeTDM received %s command \n",command); + + if (!strcasecmp(command, kPREBUFFER_LEN)) { + const char *szval = switch_event_get_header(event, kPREBUFFER_LEN); + int val = !zstr(szval) ? atoi(szval) : 0; + + if (tech_pvt->prebuffer_len == val) { + tech_pvt->prebuffer_len = val; + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tech_pvt->prebuffer_len)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set channel pre buffer size.\n"); + return SWITCH_STATUS_GENERR; + } + } + } else if (!strcasecmp(command, kECHOCANCEL)) { + const char *szval = switch_event_get_header(event, kECHOCANCEL); + int enabled = !!switch_true(szval); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeTDM sending echo cancel [%s] command \n",enabled ? "enable" : "disable"); + + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, enabled ? FTDM_COMMAND_ENABLE_ECHOCANCEL : FTDM_COMMAND_DISABLE_ECHOCANCEL, NULL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to %s echo cancellation.\n", enabled ? "enable" : "disable"); + } + + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeTDM received unknown command [%s] \n",command); + } + } + + return SWITCH_STATUS_SUCCESS; +} + diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 6986804753..5d03ba4076 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -36,10 +36,10 @@ * David Yat Sin * */ - #define _GNU_SOURCE #include "private/ftdm_core.h" #include +#include #ifdef WIN32 #include #endif @@ -52,9 +52,7 @@ struct tm *localtime_r(const time_t *clock, struct tm *result); #endif -#define FORCE_HANGUP_TIMER 3000 -#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 -#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 +#define FORCE_HANGUP_TIMER 30000 #define FTDM_READ_TRACE_INDEX 0 #define FTDM_WRITE_TRACE_INDEX 1 #define MAX_CALLIDS 6000 @@ -64,11 +62,78 @@ struct tm *localtime_r(const time_t *clock, struct tm *result); ftdm_time_t time_last_throttle_log = 0; ftdm_time_t time_current_throttle_log = 0; +typedef struct val_str { + const char *str; + unsigned long long val; +} val_str_t; + +static val_str_t channel_flag_strs[] = { + { "configured" , FTDM_CHANNEL_CONFIGURED}, + { "ready", FTDM_CHANNEL_READY}, + { "open", FTDM_CHANNEL_OPEN}, + { "dtmf-detect", FTDM_CHANNEL_DTMF_DETECT}, + { "suppress-dtmf", FTDM_CHANNEL_SUPRESS_DTMF}, + { "transcode", FTDM_CHANNEL_TRANSCODE}, + { "buffer", FTDM_CHANNEL_BUFFER}, + { "in-thread", FTDM_CHANNEL_INTHREAD}, + { "wink", FTDM_CHANNEL_WINK}, + { "flash", FTDM_CHANNEL_FLASH}, + { "state-change", FTDM_CHANNEL_STATE_CHANGE}, + { "hold", FTDM_CHANNEL_HOLD}, + { "in-use", FTDM_CHANNEL_INUSE}, + { "off-hook", FTDM_CHANNEL_OFFHOOK}, + { "ringing", FTDM_CHANNEL_RINGING}, + { "progress-detect", FTDM_CHANNEL_PROGRESS_DETECT}, + { "callerid-detect", FTDM_CHANNEL_CALLERID_DETECT}, + { "outbound", FTDM_CHANNEL_OUTBOUND}, + { "suspended", FTDM_CHANNEL_SUSPENDED}, + { "3-way", FTDM_CHANNEL_3WAY}, + { "progress", FTDM_CHANNEL_PROGRESS}, + { "media", FTDM_CHANNEL_MEDIA}, + { "answered", FTDM_CHANNEL_ANSWERED}, + { "mute", FTDM_CHANNEL_MUTE}, + { "use-rx-gain", FTDM_CHANNEL_USE_RX_GAIN}, + { "use-tx-gain", FTDM_CHANNEL_USE_TX_GAIN}, + { "in-alarm", FTDM_CHANNEL_IN_ALARM}, + { "sig-up", FTDM_CHANNEL_SIG_UP}, + { "user-hangup", FTDM_CHANNEL_USER_HANGUP}, + { "rx-disabled", FTDM_CHANNEL_RX_DISABLED}, + { "tx-disabled", FTDM_CHANNEL_TX_DISABLED}, + { "call-started", FTDM_CHANNEL_CALL_STARTED}, + { "non-block", FTDM_CHANNEL_NONBLOCK}, + { "ind-ack-pending", FTDM_CHANNEL_IND_ACK_PENDING}, + { "blocking", FTDM_CHANNEL_BLOCKING}, + { "media", FTDM_CHANNEL_DIGITAL_MEDIA}, + { "native-sigbridge", FTDM_CHANNEL_NATIVE_SIGBRIDGE}, + { "invalid", FTDM_CHANNEL_MAX_FLAG}, +}; + +static val_str_t span_flag_strs[] = { + { "configured", FTDM_SPAN_CONFIGURED}, + { "started", FTDM_SPAN_STARTED}, + { "state-change", FTDM_SPAN_STATE_CHANGE}, + { "suspended", FTDM_SPAN_SUSPENDED}, + { "in-thread", FTDM_SPAN_IN_THREAD}, + { "stop-thread", FTDM_SPAN_STOP_THREAD}, + { "use-chan-queue", FTDM_SPAN_USE_CHAN_QUEUE}, + { "suggest-chan-id", FTDM_SPAN_SUGGEST_CHAN_ID}, + { "use-av-rate", FTDM_SPAN_USE_AV_RATE}, + { "power-saving", FTDM_SPAN_PWR_SAVING}, + { "signals-queue", FTDM_SPAN_USE_SIGNALS_QUEUE}, + { "proceed-state", FTDM_SPAN_USE_PROCEED_STATE}, + { "skip-state", FTDM_SPAN_USE_SKIP_STATES}, + { "non-stoppable", FTDM_SPAN_NON_STOPPABLE}, + { "use-transfer", FTDM_SPAN_USE_TRANSFER}, +}; + static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan); static ftdm_status_t ftdm_channel_sig_indicate(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication, ftdm_usrmsg_t *usrmsg); +static const char *ftdm_val2str(unsigned long long val, val_str_t *val_str_table, ftdm_size_t array_size, const char *default_str); +static unsigned long long ftdm_str2val(const char *str, val_str_t *val_str_table, ftdm_size_t array_size, unsigned long long default_val); + static int time_is_init = 0; @@ -171,7 +236,7 @@ static void stop_chan_io_dump(ftdm_io_dump_t *dump) return; } ftdm_safe_free(dump->buffer); - memset(dump, 0, sizeof(dump)); + memset(dump, 0, sizeof(*dump)); } static ftdm_status_t start_chan_io_dump(ftdm_channel_t *chan, ftdm_io_dump_t *dump, ftdm_size_t size) @@ -223,7 +288,7 @@ typedef struct { uint32_t interval; uint8_t alarm_action_flags; uint8_t set_alarm_threshold; - uint8_t reset_alarm_threshold; + uint8_t clear_alarm_threshold; ftdm_interrupt_t *interrupt; } cpu_monitor_t; @@ -1060,7 +1125,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t i++; } - ftdm_set_flag(new_chan, FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY); + ftdm_set_flag(new_chan, FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY); new_chan->state = FTDM_CHANNEL_STATE_DOWN; new_chan->state_status = FTDM_STATE_STATUS_COMPLETED; *chan = new_chan; @@ -1413,13 +1478,24 @@ FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint static __inline__ int chan_is_avail(ftdm_channel_t *check) { - if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || - !ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) || - ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || - ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || - ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || - check->state != FTDM_CHANNEL_STATE_DOWN) { - return 0; + if ((check->span->signal_type == FTDM_SIGTYPE_M2UA) || + (check->span->signal_type == FTDM_SIGTYPE_NONE)) { + if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || + ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || + ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || + ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || + check->state != FTDM_CHANNEL_STATE_DOWN) { + return 0; + } + } else { + if (!ftdm_test_flag(check, FTDM_CHANNEL_READY) || + !ftdm_test_flag(check, FTDM_CHANNEL_SIG_UP) || + ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || + ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || + ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) || + check->state != FTDM_CHANNEL_STATE_DOWN) { + return 0; + } } return 1; } @@ -1825,7 +1901,7 @@ done: return status; } -static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) +static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan, uint8_t physical) { ftdm_channel_t *check = NULL; ftdm_span_t *span = NULL; @@ -1854,14 +1930,46 @@ static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm goto done; } - if (chan_id < 1 || chan_id > span->chan_count) { - ftdm_log(FTDM_LOG_ERROR, "Invalid channel %d to open in span %d\n", chan_id, span_id); - goto done; - } + if (physical) { /* Open by physical */ + ftdm_channel_t *fchan = NULL; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *curr = NULL; - if (!(check = span->channels[chan_id])) { - ftdm_log(FTDM_LOG_CRIT, "Wow, no channel %d in span %d\n", chan_id, span_id); - goto done; + if (chan_id < 1) { + ftdm_log(FTDM_LOG_ERROR, "Invalid physical channel %d to open in span %d\n", chan_id, span_id); + status = FTDM_FAIL; + goto done; + } + + citer = ftdm_span_get_chan_iterator(span, NULL); + if (!citer) { + status = ENOMEM; + goto done; + } + + for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); + if (fchan->physical_chan_id == chan_id) { + check = fchan; + break; + } + } + + ftdm_iterator_free(citer); + if (!check) { + ftdm_log(FTDM_LOG_CRIT, "Wow, no physical channel %d in span %d\n", chan_id, span_id); + goto done; + } + } else { /* Open by logical */ + if (chan_id < 1 || chan_id > span->chan_count) { + ftdm_log(FTDM_LOG_ERROR, "Invalid channel %d to open in span %d\n", chan_id, span_id); + goto done; + } + + if (!(check = span->channels[chan_id])) { + ftdm_log(FTDM_LOG_CRIT, "Wow, no channel %d in span %d\n", chan_id, span_id); + goto done; + } } ftdm_channel_lock(check); @@ -1932,7 +2040,18 @@ done: FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) { ftdm_status_t status; - status = _ftdm_channel_open(span_id, chan_id, ftdmchan); + status = _ftdm_channel_open(span_id, chan_id, ftdmchan, 0); + if (status == FTDM_SUCCESS) { + ftdm_channel_t *fchan = *ftdmchan; + ftdm_channel_unlock(fchan); + } + return status; +} + +FT_DECLARE(ftdm_status_t) ftdm_channel_open_ph(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan) +{ + ftdm_status_t status; + status = _ftdm_channel_open(span_id, chan_id, ftdmchan, 1); if (status == FTDM_SUCCESS) { ftdm_channel_t *fchan = *ftdmchan; ftdm_channel_unlock(fchan); @@ -2229,6 +2348,15 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char * { ftdm_status_t status = FTDM_SUCCESS; + /* In native sigbridge mode we ignore hangup requests from the user and hangup only when the signaling module decides it */ + if (ftdm_test_flag(chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE) && chan->state != FTDM_CHANNEL_STATE_TERMINATING) { + + ftdm_log_chan_ex(chan, file, func, line, FTDM_LOG_LEVEL_DEBUG, + "Ignoring hangup in channel in state %s (native bridge enabled)\n", ftdm_channel_state2str(chan->state)); + ftdm_set_flag(chan, FTDM_CHANNEL_USER_HANGUP); + goto done; + } + if (chan->state != FTDM_CHANNEL_STATE_DOWN) { if (chan->state == FTDM_CHANNEL_STATE_HANGUP) { /* make user's life easier, and just ignore double hangup requests */ @@ -2255,6 +2383,8 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char * ftdm_channel_close(&chan); } } + +done: return status; } @@ -2313,6 +2443,39 @@ FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel(const ftdm_span_t *span, uint return chan; } +FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel_ph(const ftdm_span_t *span, uint32_t chanid) +{ + ftdm_channel_t *chan = NULL; + ftdm_channel_t *fchan = NULL; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *curr = NULL; + + ftdm_mutex_lock(span->mutex); + if (chanid == 0) { + ftdm_mutex_unlock(span->mutex); + return NULL; + } + + citer = ftdm_span_get_chan_iterator(span, NULL); + if (!citer) { + ftdm_mutex_unlock(span->mutex); + return NULL; + } + + for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); + if (fchan->physical_chan_id == chanid) { + chan = fchan; + break; + } + } + + ftdm_iterator_free(citer); + + ftdm_mutex_unlock(span->mutex); + return chan; +} + FT_DECLARE(uint32_t) ftdm_span_get_chan_count(const ftdm_span_t *span) { uint32_t count; @@ -2350,6 +2513,15 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch ftdm_channel_lock(ftdmchan); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, + "Ignoring indication %s in channel in state %s (native bridge enabled)\n", + ftdm_channel_indication2str(indication), + ftdm_channel_state2str(ftdmchan->state)); + status = FTDM_SUCCESS; + goto done; + } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IND_ACK_PENDING)) { ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Cannot indicate %s in channel with indication %s still pending in state %s\n", ftdm_channel_indication2str(indication), @@ -2450,10 +2622,56 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func return FTDM_SUCCESS; } +FT_DECLARE(ftdm_status_t) ftdm_get_channel_from_string(const char *string_id, ftdm_span_t **out_span, ftdm_channel_t **out_channel) +{ + ftdm_status_t status = FTDM_SUCCESS; + int rc = 0; + ftdm_span_t *span = NULL; + ftdm_channel_t *ftdmchan = NULL; + unsigned span_id = 0; + unsigned chan_id = 0; + + *out_span = NULL; + *out_channel = NULL; + + if (!string_id) { + ftdm_log(FTDM_LOG_ERROR, "Cannot parse NULL channel id string\n"); + status = FTDM_EINVAL; + goto done; + } + + rc = sscanf(string_id, "%u:%u", &span_id, &chan_id); + if (rc != 2) { + ftdm_log(FTDM_LOG_ERROR, "Failed to parse channel id string '%s'\n", string_id); + status = FTDM_EINVAL; + goto done; + } + + status = ftdm_span_find(span_id, &span); + if (status != FTDM_SUCCESS || !span) { + ftdm_log(FTDM_LOG_ERROR, "Failed to find span for channel id string '%s'\n", string_id); + status = FTDM_EINVAL; + goto done; + } + + if (chan_id > (FTDM_MAX_CHANNELS_SPAN+1) || !(ftdmchan = span->channels[chan_id])) { + ftdm_log(FTDM_LOG_ERROR, "Invalid channel id string '%s'\n", string_id); + status = FTDM_EINVAL; + goto done; + } + + status = FTDM_SUCCESS; + *out_span = span; + *out_channel = ftdmchan; +done: + return status; +} + /* this function MUST be called with the channel lock held with lock recursivity of 1 exactly, * and the caller must be aware we might unlock the channel for a brief period of time and then lock it again */ static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_usrmsg_t *usrmsg) { + const char *var = NULL; ftdm_status_t status = FTDM_FAIL; ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel"); @@ -2489,6 +2707,16 @@ static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *f ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED); ftdm_call_set_call_id(ftdmchan, &ftdmchan->caller_data); + var = ftdm_usrmsg_get_var(usrmsg, "sigbridge_peer"); + if (var) { + ftdm_span_t *peer_span = NULL; + ftdm_channel_t *peer_chan = NULL; + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE); + ftdm_get_channel_from_string(var, &peer_span, &peer_chan); + if (peer_chan) { + ftdm_set_flag(peer_chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE); + } + } /* if the signaling stack left the channel in state down on success, is expecting us to move to DIALING */ if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) { @@ -2544,7 +2772,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_call_place(const char *file, const char *func, i status = _ftdm_channel_open_by_group(hunting->mode_data.group.group_id, hunting->mode_data.group.direction, caller_data, &fchan); } else if (hunting->mode == FTDM_HUNT_CHAN) { - status = _ftdm_channel_open(hunting->mode_data.chan.span_id, hunting->mode_data.chan.chan_id, &fchan); + status = _ftdm_channel_open(hunting->mode_data.chan.span_id, hunting->mode_data.chan.chan_id, &fchan, 0); } else { ftdm_log(FTDM_LOG_ERROR, "Cannot make outbound call with invalid hunting mode %d\n", hunting->mode); return FTDM_EINVAL; @@ -2692,6 +2920,7 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_ANSWERED); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DIGITAL_MEDIA); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE); ftdm_mutex_lock(ftdmchan->pre_buffer_mutex); ftdm_buffer_destroy(&ftdmchan->pre_buffer); ftdmchan->pre_buffer_size = 0; @@ -4291,7 +4520,7 @@ static struct { ftdm_io_interface_t *pika_interface; } interfaces; -static void print_channels_by_flag(ftdm_stream_handle_t *stream, int32_t flagval, int not, int *count) +static void print_channels_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *inspan, uint32_t inchan_id, int32_t flagval, int not, int *count) { ftdm_hash_iterator_t *i = NULL; ftdm_span_t *span; @@ -4301,40 +4530,147 @@ static void print_channels_by_flag(ftdm_stream_handle_t *stream, int32_t flagval const void *key = NULL; void *val = NULL; uint32_t flag = (1 << flagval); + int mycount = 0; *count = 0; ftdm_mutex_lock(globals.mutex); - for (i = hashtable_first(globals.span_hash); i; i = hashtable_next(i)) { - hashtable_this(i, &key, NULL, &val); - if (!key || !val) { - break; - } - span = val; - citer = ftdm_span_get_chan_iterator(span, NULL); + if (inspan) { + citer = ftdm_span_get_chan_iterator(inspan, NULL); if (!citer) { - continue; + goto end; } for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { fchan = ftdm_iterator_current(curr); - if (not && !ftdm_test_flag(fchan, flag)) { - stream->write_function(stream, "[s%dc%d][%d:%d] has not flag %d\n", - fchan->span_id, fchan->chan_id, - fchan->physical_span_id, fchan->physical_chan_id, - flagval); - (*count)++; - } else if (!not && ftdm_test_flag(fchan, flag)) { - stream->write_function(stream, "[s%dc%d][%d:%d] has flag %d\n", - fchan->span_id, fchan->chan_id, - fchan->physical_span_id, fchan->physical_chan_id, - flagval); - (*count)++; + if (!inchan_id || inchan_id == fchan->chan_id) { + if (not) { + if (!ftdm_test_flag(fchan, flag)) { + stream->write_function(stream, "[s%dc%d][%d:%d] flag !%d(!%s) ON \n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + + mycount++; + } else { + stream->write_function(stream, "[s%dc%d][%d:%d] flag !%d(!%s) OFF \n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + } + } else { + if (ftdm_test_flag(fchan, flag)) { + stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s) ON\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + + mycount++; + } else { + stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s) OFF \n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + } + } } } ftdm_iterator_free(citer); - } + } else { + for (i = hashtable_first(globals.span_hash); i; i = hashtable_next(i)) { + hashtable_this(i, &key, NULL, &val); + if (!key || !val) { + break; + } + span = val; + citer = ftdm_span_get_chan_iterator(span, NULL); + if (!citer) { + continue; + } + for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); + if (not && !ftdm_test_flag(fchan, flag)) { + stream->write_function(stream, "[s%dc%d][%d:%d] flag !%d(!%s)\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + mycount++; + } else if (!not && ftdm_test_flag(fchan, flag)) { + stream->write_function(stream, "[s%dc%d][%d:%d] flag %d(%s)\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, + flagval, ftdm_val2str(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), "invalid")); + mycount++; + } + } + ftdm_iterator_free(citer); + } + } + *count = mycount; +end: + ftdm_mutex_unlock(globals.mutex); +} + +static void print_spans_by_flag(ftdm_stream_handle_t *stream, ftdm_span_t *inspan, int32_t flagval, int not, int *count) +{ + ftdm_hash_iterator_t *i = NULL; + ftdm_span_t *span; + const void *key = NULL; + void *val = NULL; + uint32_t flag = (1 << flagval); + int mycount = 0; + + *count = 0; + + ftdm_mutex_lock(globals.mutex); + + if (inspan) { + if (not) { + if (!ftdm_test_flag(inspan, flag)) { + stream->write_function(stream, "[s%d] flag !%d(!%s) ON \n", + inspan->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + + mycount++; + } else { + stream->write_function(stream, "[s%d] flag !%d(!%s) OFF \n", + inspan->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + } + } else { + if (ftdm_test_flag(inspan, flag)) { + stream->write_function(stream, "[s%d] flag %d(%s) ON \n", + inspan->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + mycount++; + } else { + stream->write_function(stream, "[s%d] flag %d(%s) OFF \n", + inspan->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + } + } + } else { + for (i = hashtable_first(globals.span_hash); i; i = hashtable_next(i)) { + hashtable_this(i, &key, NULL, &val); + if (!key || !val) { + break; + } + span = val; + if (not && !ftdm_test_flag(span, flag)) { + stream->write_function(stream, "[s%d] flag !%d(!%s)\n", + span->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + mycount++; + } else if (!not && ftdm_test_flag(span, flag)) { + stream->write_function(stream, "[s%d] flag %d(%s)\n", + span->span_id, + flagval, ftdm_val2str(flag, span_flag_strs, ftdm_array_len(span_flag_strs), "invalid")); + mycount++; + } + } + } + *count = mycount; ftdm_mutex_unlock(globals.mutex); } @@ -4386,12 +4722,52 @@ static void print_core_usage(ftdm_stream_handle_t *stream) { stream->write_function(stream, "--------------------------------------------------------------------------------\n" - "ftdm core state [!] - List all channels in or not in the given state\n" - "ftdm core flag - List all channels with the given flag value set\n" + "ftdm core state [!] - List all channels in or not in the given state\n" + "ftdm core flag [!] [] [] - List all channels with the given flag value set\n" + "ftdm core spanflag [!] [] - List all spans with the given span flag value set\n" "ftdm core calls - List all known calls to the FreeTDM core\n" "--------------------------------------------------------------------------------\n"); } + +static unsigned long long ftdm_str2val(const char *str, val_str_t *val_str_table, ftdm_size_t array_size, unsigned long long default_val) +{ + int i; + for (i = 0; i < array_size; i++) { + if (!strcasecmp(val_str_table[i].str, str)) { + return val_str_table[i].val; + } + } + return default_val; +} + +static const char *ftdm_val2str(unsigned long long val, val_str_t *val_str_table, ftdm_size_t array_size, const char *default_str) +{ + int i; + for (i = 0; i < array_size; i++) { + if (val_str_table[i].val == val) { + return val_str_table[i].str; + } + } + return default_str; +} + +static void print_channel_flag_values(ftdm_stream_handle_t *stream) +{ + int i; + for (i = 0; i < ftdm_array_len(channel_flag_strs); i++) { + stream->write_function(stream, "%s\n", channel_flag_strs[i].str); + } +} + +static void print_span_flag_values(ftdm_stream_handle_t *stream) +{ + int i; + for (i = 0; i < ftdm_array_len(span_flag_strs); i++) { + stream->write_function(stream, "%s\n", span_flag_strs[i].str); + } +} + static char *handle_core_command(const char *cmd) { char *mycmd = NULL; @@ -4401,11 +4777,12 @@ static char *handle_core_command(const char *cmd) char *argv[10] = { 0 }; char *state = NULL; char *flag = NULL; - uint32_t flagval = 0; + unsigned long long flagval = 0; uint32_t current_call_id = 0; ftdm_caller_data_t *calldata = NULL; ftdm_channel_t *fchan = NULL; ftdm_channel_state_t i = FTDM_CHANNEL_STATE_INVALID; + ftdm_span_t *fspan = NULL; ftdm_stream_handle_t stream = { 0 }; FTDM_STANDARD_STREAM(stream); @@ -4446,6 +4823,7 @@ static char *handle_core_command(const char *cmd) print_channels_by_state(&stream, i, not, &count); stream.write_function(&stream, "\nTotal channels %s %s: %d\n", not ? "not in state" : "in state", ftdm_channel_state2str(i), count); } else if (!strcasecmp(argv[0], "flag")) { + uint32_t chan_id = 0; if (argc < 2) { stream.write_function(&stream, "core flag command requires an argument\n"); print_core_usage(&stream); @@ -4456,9 +4834,77 @@ static char *handle_core_command(const char *cmd) not = 1; flag++; } - flagval = atoi(flag); - print_channels_by_flag(&stream, flagval, not, &count); + + if (isalpha(flag[0])) { + flagval = ftdm_str2val(flag, channel_flag_strs, ftdm_array_len(channel_flag_strs), FTDM_CHANNEL_MAX_FLAG); + if (flagval == FTDM_CHANNEL_MAX_FLAG) { + stream.write_function(&stream, "\nInvalid channel flag value. Possible channel flags\n"); + print_channel_flag_values(&stream); + goto done; + } + flagval = flagval >> 1; + } else { + flagval = atoi(flag); + } + + /* Specific span specified */ + if (argv[2]) { + ftdm_span_find_by_name(argv[2], &fspan); + if (!fspan) { + stream.write_function(&stream, "-ERR span:%s not found\n", argv[2]); + goto done; + } + } + + /* Specific channel specified */ + if (argv[3]) { + chan_id = atoi(argv[3]); + if (chan_id >= ftdm_span_get_chan_count(fspan)) { + stream.write_function(&stream, "-ERR invalid channel %d\n", chan_id); + goto done; + } + } + + print_channels_by_flag(&stream, fspan, chan_id, flagval, not, &count); stream.write_function(&stream, "\nTotal channels %s %d: %d\n", not ? "without flag" : "with flag", flagval, count); + } else if (!strcasecmp(argv[0], "spanflag")) { + if (argc < 2) { + stream.write_function(&stream, "core spanflag command requires an argument\n"); + print_core_usage(&stream); + goto done; + } + + flag = argv[1]; + if (argv[1][0] == '!') { + not = 1; + flag++; + } + + if (isalpha(flag[0])) { + flagval = ftdm_str2val(flag, span_flag_strs, ftdm_array_len(span_flag_strs), FTDM_SPAN_MAX_FLAG); + if (flagval == FTDM_SPAN_MAX_FLAG) { + stream.write_function(&stream, "\nInvalid span flag value. Possible span flags\n"); + print_span_flag_values(&stream); + goto done; + } + flagval = flagval >> 1; + } else { + flagval = atoi(flag); + } + + /* Specific span specified */ + if (argv[2]) { + ftdm_span_find_by_name(argv[2], &fspan); + if (!fspan) { + stream.write_function(&stream, "-ERR span:%s not found\n", argv[2]); + goto done; + } + } + + print_spans_by_flag(&stream, fspan, flagval, not, &count); + if (!fspan) { + stream.write_function(&stream, "\nTotal spans %s %d: %d\n", not ? "without flag" : "with flag", flagval, count); + } } else if (!strcasecmp(argv[0], "calls")) { ftdm_mutex_lock(globals.call_id_mutex); current_call_id = globals.last_call_id; @@ -4923,14 +5369,15 @@ static ftdm_status_t load_config(void) } else { ftdm_log(FTDM_LOG_ERROR, "Invalid cpu alarm set threshold %s\n", val); } - } else if (!strncasecmp(var, "cpu_reset_alarm_threshold", sizeof("cpu_reset_alarm_threshold")-1)) { + } else if (!strncasecmp(var, "cpu_reset_alarm_threshold", sizeof("cpu_reset_alarm_threshold")-1) || + !strncasecmp(var, "cpu_clear_alarm_threshold", sizeof("cpu_clear_alarm_threshold")-1)) { intparam = atoi(val); if (intparam > 0 && intparam < 100) { - globals.cpu_monitor.reset_alarm_threshold = (uint8_t)intparam; - if (globals.cpu_monitor.reset_alarm_threshold > globals.cpu_monitor.set_alarm_threshold) { - globals.cpu_monitor.reset_alarm_threshold = globals.cpu_monitor.set_alarm_threshold - 10; - ftdm_log(FTDM_LOG_ERROR, "Cpu alarm reset threshold must be lower than set threshold" - ", setting threshold to %d\n", globals.cpu_monitor.reset_alarm_threshold); + globals.cpu_monitor.clear_alarm_threshold = (uint8_t)intparam; + if (globals.cpu_monitor.clear_alarm_threshold > globals.cpu_monitor.set_alarm_threshold) { + globals.cpu_monitor.clear_alarm_threshold = globals.cpu_monitor.set_alarm_threshold - 10; + ftdm_log(FTDM_LOG_ERROR, "Cpu alarm clear threshold must be lower than set threshold, " + "setting clear threshold to %d\n", globals.cpu_monitor.clear_alarm_threshold); } } else { ftdm_log(FTDM_LOG_ERROR, "Invalid cpu alarm reset threshold %s\n", val); @@ -5298,16 +5745,68 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const return status; } +static void *ftdm_span_service_events(ftdm_thread_t *me, void *obj) +{ + int i; + unsigned waitms; + ftdm_event_t *event; + ftdm_status_t status = FTDM_SUCCESS; + ftdm_span_t *span = (ftdm_span_t*) obj; + short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); + + memset(poll_events, 0, sizeof(short) * span->chan_count); + + for(i = 1; i <= span->chan_count; i++) { + poll_events[i] |= FTDM_EVENTS; + } + + while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) { + waitms = 1000; + status = ftdm_span_poll_event(span, waitms, poll_events); + switch (status) { + case FTDM_FAIL: + ftdm_log(FTDM_LOG_CRIT, "%s:Failed to poll span for events\n", span->name); + break; + case FTDM_TIMEOUT: + break; + case FTDM_SUCCESS: + /* Check if there are any channels that have events available */ + while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS); + break; + default: + ftdm_log(FTDM_LOG_CRIT, "%s:Unhandled IO event\n", span->name); + } + } + return NULL; +} + +FT_DECLARE(ftdm_status_t) ftdm_span_register_signal_cb(ftdm_span_t *span, fio_signal_cb_t sig_cb) +{ + span->signal_cb = sig_cb; + return FTDM_SUCCESS; +} + FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) { ftdm_status_t status = FTDM_FAIL; - ftdm_mutex_lock(span->mutex); if (ftdm_test_flag(span, FTDM_SPAN_STARTED)) { status = FTDM_EINVAL; goto done; } + if (span->signal_type == FTDM_SIGTYPE_NONE) { + /* If there is no signalling component, start a thread to poll events */ + status = ftdm_thread_create_detached(ftdm_span_service_events, span); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT,"Failed to start span event monitor thread!\n"); + goto done; + } + + //ftdm_report_initial_channels_alarms(span); + ftdm_set_flag_locked(span, FTDM_SPAN_STARTED); + goto done; + } if (!span->start) { status = FTDM_ENOSYS; @@ -5331,7 +5830,6 @@ FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) if (status == FTDM_SUCCESS) { ftdm_set_flag_locked(span, FTDM_SPAN_STARTED); } - done: ftdm_mutex_unlock(span->mutex); return status; @@ -5516,8 +6014,10 @@ FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *na static ftdm_status_t ftdm_span_trigger_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) { - ftdm_status_t status = span->signal_cb(sigmsg); - return status; + if (!span->signal_cb) { + return FTDM_FAIL; + } + return span->signal_cb(sigmsg); } static ftdm_status_t ftdm_span_queue_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) @@ -5551,7 +6051,7 @@ static void execute_safety_hangup(void *data) ftdm_channel_lock(fchan); fchan->hangup_timer = 0; if (fchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER); + ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER); _ftdm_channel_call_hangup_nl(__FILE__, __FUNCTION__, __LINE__, fchan, NULL); } else { ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Not performing safety hangup, channel state is %s\n", ftdm_channel_state2str(fchan->state)); @@ -5682,28 +6182,32 @@ static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj) { cpu_monitor_t *monitor = (cpu_monitor_t *)obj; struct ftdm_cpu_monitor_stats *cpu_stats = ftdm_new_cpu_monitor(); + + ftdm_log(FTDM_LOG_DEBUG, "CPU monitor thread is now running\n"); if (!cpu_stats) { - return NULL; + goto done; } monitor->running = 1; - while(ftdm_running()) { - double time; - if (ftdm_cpu_get_system_idle_time(cpu_stats, &time)) { + while (ftdm_running()) { + double idle_time = 0.0; + int cpu_usage = 0; + + if (ftdm_cpu_get_system_idle_time(cpu_stats, &idle_time)) { break; } + cpu_usage = (int)(100 - idle_time); if (monitor->alarm) { - if ((int)time >= (100 - monitor->set_alarm_threshold)) { - ftdm_log(FTDM_LOG_DEBUG, "CPU alarm OFF (idle:%d)\n", (int) time); + if (cpu_usage <= monitor->clear_alarm_threshold) { + ftdm_log(FTDM_LOG_DEBUG, "CPU alarm is now OFF (cpu usage: %d)\n", cpu_usage); monitor->alarm = 0; - } - if (monitor->alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN) { - ftdm_log(FTDM_LOG_WARNING, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time)); + } else if (monitor->alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN) { + ftdm_log(FTDM_LOG_WARNING, "CPU alarm is still ON (cpu usage: %d)\n", cpu_usage); } } else { - if ((int)time <= (100-monitor->reset_alarm_threshold)) { - ftdm_log(FTDM_LOG_DEBUG, "CPU alarm ON (idle:%d)\n", (int) time); + if (cpu_usage >= monitor->set_alarm_threshold) { + ftdm_log(FTDM_LOG_WARNING, "CPU alarm is now ON (cpu usage: %d)\n", cpu_usage); monitor->alarm = 1; } } @@ -5712,7 +6216,11 @@ static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj) ftdm_delete_cpu_monitor(cpu_stats); monitor->running = 0; + +done: + ftdm_log(FTDM_LOG_DEBUG, "CPU monitor thread is now terminating\n"); return NULL; + #ifdef __WINDOWS__ UNREFERENCED_PARAMETER(me); #endif @@ -5814,8 +6322,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void) globals.cpu_monitor.enabled = 0; globals.cpu_monitor.interval = 1000; globals.cpu_monitor.alarm_action_flags = 0; - globals.cpu_monitor.set_alarm_threshold = 80; - globals.cpu_monitor.reset_alarm_threshold = 70; + globals.cpu_monitor.set_alarm_threshold = 92; + globals.cpu_monitor.clear_alarm_threshold = 82; if (load_config() != FTDM_SUCCESS) { globals.running = 0; @@ -5824,10 +6332,10 @@ FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void) } if (globals.cpu_monitor.enabled) { - ftdm_log(FTDM_LOG_INFO, "CPU Monitor is running interval:%d lo-thres:%d hi-thres:%d\n", + ftdm_log(FTDM_LOG_INFO, "CPU Monitor is running interval:%d set-thres:%d clear-thres:%d\n", globals.cpu_monitor.interval, globals.cpu_monitor.set_alarm_threshold, - globals.cpu_monitor.reset_alarm_threshold); + globals.cpu_monitor.clear_alarm_threshold); if (ftdm_cpu_monitor_start() != FTDM_SUCCESS) { return FTDM_FAIL; diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c index db4097e84b..614044ac3b 100644 --- a/libs/freetdm/src/ftdm_state.c +++ b/libs/freetdm/src/ftdm_state.c @@ -48,9 +48,26 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c ftdm_time_t diff = 0; ftdm_channel_state_t state = fchan->state; +#if 0 + /* I could not perform this sanity check without more disruptive changes. Ideally we should check here if the signaling module completing the state + executed a state processor (called ftdm_channel_advance_states() which call fchan->span->state_processor(fchan)) for the state. That is just a + sanity check, as in the past we had at least one bug where the signaling module set the state and then accidentally changed the state to a new one + without calling ftdm_channel_advance_states(), meaning the state processor for the first state was not executed and that lead to unexpected behavior. + + If we want to be able to perform this kind of sanity check it would be nice to add a new state status (FTDM_STATE_STATUS_PROCESSING), the function + ftdm_channel_advance_states() would set the state_status to PROCESSING and then the check below for STATUS_NEW would be valid. Currently is not + valid because the signaling module may be completing the state at the end of the state_processor callback and therefore the state will still be + in STATUS_NEW, and is perfectly valid ... */ + + if (fchan->state_status == FTDM_STATE_STATUS_NEW) { + ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_CRIT, + "Asking to complete state change from %s to %s in %llums, but the state is still unprocessed (this might be a bug!)\n", + ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff); + } +#endif + if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) { - ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, - "State change flag set but state is not completed\n"); + ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, "State change flag set but state is already completed\n"); return FTDM_SUCCESS; } @@ -87,6 +104,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c ftdm_assert(!fchan->history[hindex].end_time, "End time should be zero!\n"); fchan->history[hindex].end_time = ftdm_current_time_in_ms(); + fchan->last_state_change_time = ftdm_current_time_in_ms(); fchan->state_status = FTDM_STATE_STATUS_COMPLETED; @@ -262,6 +280,9 @@ static ftdm_status_t ftdm_core_set_state(const char *file, const char *func, int } } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + goto perform_state_change; + } if (ftdmchan->span->state_map) { ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map); @@ -353,6 +374,8 @@ end: goto done; } +perform_state_change: + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); ftdmchan->last_state = ftdmchan->state; ftdmchan->state = state; 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 40a89a80c8..cc4d1108f6 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 @@ -288,6 +288,7 @@ typedef struct sngisdn_span_data { uint8_t force_sending_complete; uint8_t cid_name_method; uint8_t send_cid_name; + uint8_t send_connect_ack; int32_t timer_t301; int32_t timer_t302; @@ -305,7 +306,6 @@ typedef struct sngisdn_span_data { int32_t timer_t318; int32_t timer_t319; int32_t timer_t322; - char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS]; ftdm_timer_id_t timers[SNGISDN_NUM_SPAN_TIMERS]; ftdm_sched_t *sched; 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 47da32d865..8356932ce6 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 @@ -433,6 +433,7 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ signal_data->cid_name_method = SNGISDN_CID_NAME_AUTO; signal_data->send_cid_name = SNGISDN_OPT_DEFAULT; + signal_data->send_connect_ack = SNGISDN_OPT_DEFAULT; span->default_caller_data.dnis.plan = FTDM_NPI_INVALID; span->default_caller_data.dnis.type = FTDM_TON_INVALID; @@ -615,6 +616,8 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ parse_timer(val, &signal_data->timer_t322); } else if (!strcasecmp(var, "trunkgroup")) { /* Do nothing, we already parsed this parameter */ + } else if (!strcasecmp(var, "send-connect-ack")) { + parse_yesno(var, val, &signal_data->send_connect_ack); } else { ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c index 946b9769b0..862d4d5584 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c @@ -738,6 +738,14 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span) } } + if (signal_data->send_connect_ack != SNGISDN_OPT_DEFAULT) { + if (signal_data->send_connect_ack == SNGISDN_OPT_TRUE) { + cfg.t.cfg.s.inDLSAP.ackOpt = TRUE; + } else { + cfg.t.cfg.s.inDLSAP.ackOpt = FALSE; + } + } + /* Override the restart options if user selected that option */ if (signal_data->restart_opt != SNGISDN_OPT_DEFAULT) { if (signal_data->restart_opt == SNGISDN_OPT_TRUE) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index dd1058f420..1600e71016 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -77,7 +77,9 @@ int ft_to_sngss7_cfg_all(void) int ret = 0; /* check if we have done gen_config already */ - if (!(g_ftdm_sngss7_data.gen_config)) { + if (g_ftdm_sngss7_data.gen_config == SNG_GEN_CFG_STATUS_INIT) { + /* update the global gen_config so we don't do it again */ + g_ftdm_sngss7_data.gen_config = SNG_GEN_CFG_STATUS_PENDING; /* start of by checking if the license and sig file are valid */ if (sng_validate_license(g_ftdm_sngss7_data.cfg.license, @@ -92,7 +94,7 @@ int ft_to_sngss7_cfg_all(void) /* set the desired procID value */ sng_set_procId((uint16_t)g_ftdm_sngss7_data.cfg.procId); } - + /* start up the stack manager */ if (sng_isup_init_sm()) { SS7_CRITICAL("Failed to start Stack Manager\n"); @@ -207,30 +209,22 @@ int ft_to_sngss7_cfg_all(void) } } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_MTP2)) */ - /* update the global gen_config so we don't do it again */ - g_ftdm_sngss7_data.gen_config = 1; + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + if(FTDM_SUCCESS != ftmod_ss7_m2ua_init()){ + ftdm_log (FTDM_LOG_ERROR, "ftmod_ss7_m2ua_init FAILED \n"); + return FTDM_FAIL; + } + } + + g_ftdm_sngss7_data.gen_config = SNG_GEN_CFG_STATUS_DONE; + } /* if (!(g_ftdm_sngss7_data.gen_config)) */ - /* go through all the relays channels and configure it */ - x = 1; - while (x < (MAX_RELAY_CHANNELS)) { - /* check if this relay channel has been configured already */ - if ((g_ftdm_sngss7_data.cfg.relay[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.relay[x].flags & SNGSS7_CONFIGURED))) { - /* send the specific configuration */ - if (ftmod_ss7_relay_chan_config(x)) { - SS7_CRITICAL("Relay Channel %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("Relay Channel %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.relay[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - x++; - } /* while (x < (MAX_RELAY_CHANNELS)) */ + if (g_ftdm_sngss7_data.gen_config != SNG_GEN_CFG_STATUS_DONE) { + SS7_CRITICAL("General configuration FAILED!\n"); + return 1; + } x = 1; while (x < (MAX_MTP_LINKS)) { @@ -272,160 +266,203 @@ int ft_to_sngss7_cfg_all(void) x++; } /* while (x < (MAX_MTP_LINKS+1)) */ - x = 1; - while (x < (MAX_MTP_LINKS)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtp3Link[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtp3Link[x].flags & SNGSS7_CONFIGURED))) { - - /* configure mtp3 */ - if (ftmod_ss7_mtp3_dlsap_config(x)) { - SS7_CRITICAL("MTP3 DLSAP %d configuration FAILED!\n", x); - return 1;; - } else { - SS7_INFO("MTP3 DLSAP %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtp3Link[x].flags |= SNGSS7_CONFIGURED; - } - - x++; - } /* while (x < (MAX_MTP_LINKS+1)) */ - - x = 1; - while (x < (MAX_NSAPS)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.nsap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_CONFIGURED))) { - - ret = ftmod_ss7_mtp3_nsap_config(x); - if (ret) { - SS7_CRITICAL("MTP3 NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); - return 1; - } else { - SS7_INFO("MTP3 NSAP %d configuration DONE!\n", x); - } - - ret = ftmod_ss7_isup_nsap_config(x); - if (ret) { - SS7_CRITICAL("ISUP NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); - return 1; - } else { - SS7_INFO("ISUP NSAP %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.nsap[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_NSAPS)) */ - - x = 1; - while (x < (MAX_MTP_LINKSETS+1)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_mtp3_linkset_config(x)) { - SS7_CRITICAL("MTP3 LINKSET %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("MTP3 LINKSET %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_MTP_LINKSETS+1)) */ - - x = 1; - while (x < (MAX_MTP_ROUTES+1)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.mtpRoute[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtpRoute[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_mtp3_route_config(x)) { - SS7_CRITICAL("MTP3 ROUTE %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("MTP3 ROUTE %d configuration DONE!\n",x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.mtpRoute[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_MTP_ROUTES+1)) */ - - x = 1; - while (x < (MAX_ISAPS)) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.isap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.isap[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_isup_isap_config(x)) { - SS7_CRITICAL("ISUP ISAP %d configuration FAILED!\n", x); - return 1; - } else { - SS7_INFO("ISUP ISAP %d configuration DONE!\n", x); - } - - /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.isap[x].flags |= SNGSS7_CONFIGURED; - } /* if !SNGSS7_CONFIGURED */ - - x++; - } /* while (x < (MAX_ISAPS)) */ - - if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_STARTED)) { + /* no configs above mtp2 for relay */ + if (g_ftdm_sngss7_data.cfg.procId == 1) { x = 1; - while (x < (MAX_ISUP_INFS)) { + while (x < (MAX_MTP_LINKS)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.mtp3Link[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtp3Link[x].flags & SNGSS7_CONFIGURED))) { + + /* configure mtp3 */ + if (ftmod_ss7_mtp3_dlsap_config(x)) { + SS7_CRITICAL("MTP3 DLSAP %d configuration FAILED!\n", x); + return 1;; + } else { + SS7_INFO("MTP3 DLSAP %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtp3Link[x].flags |= SNGSS7_CONFIGURED; + } + + x++; + } /* while (x < (MAX_MTP_LINKS+1)) */ + + /* in M2UA_SG mode there will not be any MTP3 layer */ + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ + x = 1; + while (x < (MAX_NSAPS)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.nsap[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_CONFIGURED))) { + + ret = ftmod_ss7_mtp3_nsap_config(x); + if (ret) { + SS7_CRITICAL("MTP3 NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); + return 1; + } else { + SS7_INFO("MTP3 NSAP %d configuration DONE!\n", x); + } + + ret = ftmod_ss7_isup_nsap_config(x); + if (ret) { + SS7_CRITICAL("ISUP NSAP %d configuration FAILED!(%s)\n", x, DECODE_LCM_REASON(ret)); + return 1; + } else { + SS7_INFO("ISUP NSAP %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.nsap[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_NSAPS)) */ + } + + /* in M2UA_SG mode there will not be any MTP3 layer */ + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ + x = 1; + while (x < (MAX_MTP_LINKSETS+1)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_mtp3_linkset_config(x)) { + SS7_CRITICAL("MTP3 LINKSET %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("MTP3 LINKSET %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_MTP_LINKSETS+1)) */ + } + + /* in M2UA_SG mode there will not be any MTP3 layer */ + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ + x = 1; + while (x < (MAX_MTP_ROUTES+1)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.mtpRoute[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtpRoute[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_mtp3_route_config(x)) { + SS7_CRITICAL("MTP3 ROUTE %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("MTP3 ROUTE %d configuration DONE!\n",x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.mtpRoute[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_MTP_ROUTES+1)) */ + } + + x = 1; + while (x < (MAX_ISAPS)) { /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.isupIntf[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.isupIntf[x].flags & SNGSS7_CONFIGURED))) { - - if (ftmod_ss7_isup_intf_config(x)) { - SS7_CRITICAL("ISUP INTF %d configuration FAILED!\n", x); + if ((g_ftdm_sngss7_data.cfg.isap[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.isap[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_isup_isap_config(x)) { + SS7_CRITICAL("ISUP ISAP %d configuration FAILED!\n", x); return 1; } else { - SS7_INFO("ISUP INTF %d configuration DONE!\n", x); - /* set the interface to paused */ - sngss7_set_flag(&g_ftdm_sngss7_data.cfg.isupIntf[x], SNGSS7_PAUSED); + SS7_INFO("ISUP ISAP %d configuration DONE!\n", x); } - + /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.isupIntf[x].flags |= SNGSS7_CONFIGURED; + g_ftdm_sngss7_data.cfg.isap[x].flags |= SNGSS7_CONFIGURED; } /* if !SNGSS7_CONFIGURED */ x++; - } /* while (x < (MAX_ISUP_INFS)) */ - } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP)) */ + } /* while (x < (MAX_ISAPS)) */ - x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; - while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { - /* check if this link has been configured already */ - if ((g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.isupCkt[x].flags & SNGSS7_CONFIGURED))) { + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP_STARTED)) { + x = 1; + while (x < (MAX_ISUP_INFS)) { + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.isupIntf[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.isupIntf[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_isup_intf_config(x)) { + SS7_CRITICAL("ISUP INTF %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("ISUP INTF %d configuration DONE!\n", x); + /* set the interface to paused */ + sngss7_set_flag(&g_ftdm_sngss7_data.cfg.isupIntf[x], SNGSS7_PAUSED); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.isupIntf[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (x < (MAX_ISUP_INFS)) */ + } /* if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_ISUP)) */ - if (ftmod_ss7_isup_ckt_config(x)) { - SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", x); + x = (g_ftdm_sngss7_data.cfg.procId * 1000) + 1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + + if (g_ftdm_sngss7_data.cfg.procId > 1) { + break; + } + + /* check if this link has been configured already */ + if ((g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.isupCkt[x].flags & SNGSS7_CONFIGURED))) { + + if (ftmod_ss7_isup_ckt_config(x)) { + SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", x); + return 1; + } else { + SS7_INFO("ISUP CKT %d configuration DONE!\n", x); + } + + /* set the SNGSS7_CONFIGURED flag */ + g_ftdm_sngss7_data.cfg.isupCkt[x].flags |= SNGSS7_CONFIGURED; + } /* if !SNGSS7_CONFIGURED */ + + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) */ + } + + /* go through all the relays channels and configure it */ + x = 1; + while (x < (MAX_RELAY_CHANNELS)) { + /* check if this relay channel has been configured already */ + if ((g_ftdm_sngss7_data.cfg.relay[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.relay[x].flags & SNGSS7_CONFIGURED))) { + + /* send the specific configuration */ + if (ftmod_ss7_relay_chan_config(x)) { + SS7_CRITICAL("Relay Channel %d configuration FAILED!\n", x); return 1; } else { - SS7_INFO("ISUP CKT %d configuration DONE!\n", x); + SS7_INFO("Relay Channel %d configuration DONE!\n", x); } /* set the SNGSS7_CONFIGURED flag */ - g_ftdm_sngss7_data.cfg.isupCkt[x].flags |= SNGSS7_CONFIGURED; + g_ftdm_sngss7_data.cfg.relay[x].flags |= SNGSS7_CONFIGURED; } /* if !SNGSS7_CONFIGURED */ - x++; - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) */ + } /* while (x < (MAX_RELAY_CHANNELS)) */ + + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + return ftmod_ss7_m2ua_cfg(); + } + return 0; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 9eb737a7f3..c1595c39dd 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -35,7 +35,7 @@ * */ -#if 0 +#if 0 #define SMG_RELAY_DBG #endif @@ -119,6 +119,15 @@ static ftdm_status_t cli_ss7_show_all_channels_of_span(ftdm_stream_handle_t *str static ftdm_status_t cli_ss7_show_span_by_id(ftdm_stream_handle_t *stream, char *span_id); static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream); static ftdm_status_t cli_ss7_show_all_spans_detail(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char* sctp_profile_name); +static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name); +static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name); +static ftdm_status_t handle_show_m2ua_cluster_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name); +static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream); +static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* profile_name); +int get_assoc_resp_buf(char* buf,SbMgmt* cfm); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -383,14 +392,87 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha } else if (!strcasecmp(argv[c], "procid")) { /**********************************************************************/ handle_show_procId(stream); + /**********************************************************************/ - } else { - /**********************************************************************/ + } else{ + /**********************************************************************/ stream->write_function(stream, "Unknown \"show\" command\n"); goto handle_cli_error; - /**********************************************************************/ } /**************************************************************************/ + } else if (!strcasecmp(argv[c], "xmlshow")) { + /**************************************************************************/ + + if (check_arg_count(argc, 2)) { + stream->write_function(stream, "Unknown \"xmlshow\" command\n"); + goto handle_cli_error; + } + c++; + /**************************************************************************/ + if (!strcasecmp(argv[c], "m2ua")) { + /**************************************************************************/ + switch(argc) + { + case 2: /* show m2ua */ + { + handle_show_m2ua_profiles(stream); + break; + } + case 3: /* show m2ua */ + { + c++; + handle_show_m2ua_profile(stream, argv[c]); + break; + } + case 4: + { + char* profile_name = argv[++c]; + c++; + /***************************************************************/ + if(!strcasecmp(argv[c],"peerstatus")){ + /***************************************************************/ + handle_show_m2ua_peer_status(stream, profile_name); + /***************************************************************/ + }else if(!strcasecmp(argv[c],"clusterstatus")){ + /***************************************************************/ + handle_show_m2ua_cluster_status(stream, profile_name); + /***************************************************************/ + } else{ + /***************************************************************/ + stream->write_function(stream, "Unknown \"show m2ua \" command..\n"); + goto handle_cli_error_argc; + } + break; + } + default: + goto handle_cli_error_argc; + } + + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "nif")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)){ + handle_show_nif_profiles(stream); + }else{ + c++; + handle_show_nif_profile(stream, argv[c]); + } + /**********************************************************************/ + } else if (!strcasecmp(argv[c], "sctp")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)){ + handle_show_sctp_profiles(stream); + }else{ + c++; + handle_show_sctp_profile(stream, argv[c]); + } + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"xmlshow\" command\n"); + goto handle_cli_error; + } + /**********************************************************************/ } else if (!strcasecmp(argv[c], "set")) { /**************************************************************************/ if (check_arg_count(argc, 4)) goto handle_cli_error_argc; @@ -460,7 +542,6 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha } /**************************************************************************/ } else if (!strcasecmp(argv[c], "blo")) { - /**************************************************************************/ if (check_arg_count(argc, 2)) goto handle_cli_error_argc; c++; @@ -752,6 +833,28 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha /**********************************************************************/ } /**************************************************************************/ + } else if (!strcasecmp(argv[c], "m2ua")) { + /**************************************************************************/ + if (check_arg_count(argc, 3)) { + stream->write_function(stream, "Invalid \"m2ua option\", please use \"m2ua logging [enable|disable] \n"); + goto handle_cli_error_argc; + } + c++; + if(!strcasecmp(argv[c],"logging")){ + c++; + if(!strcasecmp(argv[c],"enable")){ + ftmod_ss7_enable_m2ua_sg_logging(); + }else if(!strcasecmp(argv[c],"disable")){ + ftmod_ss7_disable_m2ua_sg_logging(); + } else{ + stream->write_function(stream, "Unknown \"m2ua logging %s option\", supported values enable/disable\n",argv[c]); + goto handle_cli_error_argc; + } + }else{ + stream->write_function(stream, "Unknown \"m2ua %s option\", supported values \"logging\"\n",argv[c]); + goto handle_cli_error_argc; + } + /**************************************************************************/ } else { /**************************************************************************/ goto handle_cli_error; @@ -785,16 +888,24 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 set ftrace X Y\n"); stream->write_function(stream, "ftdm ss7 set mtrace X Y\n"); stream->write_function(stream, "\n"); - stream->write_function(stream, "ftmod_sangoma_ss7 information:\n"); - stream->write_function(stream, "ftdm ss7 show status mtp3 X\n"); + + stream->write_function(stream, "ftmod_sangoma_ss7 signaling information:\n"); + stream->write_function(stream, "ftdm ss7 show \n"); stream->write_function(stream, "ftdm ss7 show status mtp2 X\n"); + stream->write_function(stream, "ftdm ss7 show status mtp3 X\n"); + stream->write_function(stream, "ftdm ss7 show status linkset X\n"); + stream->write_function(stream, "\n"); + + stream->write_function(stream, "ftmod_sangoma_ss7 circuit information:\n"); + stream->write_function(stream, "ftdm ss7 show span all\n"); + stream->write_function(stream, "ftdm ss7 show span X\n"); stream->write_function(stream, "ftdm ss7 show status span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show free span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show blocks span X chan Y\n"); - stream->write_function(stream, "ftdm ss7 show inuse span X chan Y\n"); stream->write_function(stream, "ftdm ss7 show inreset span X chan Y\n"); stream->write_function(stream, "\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 circuit control:\n"); stream->write_function(stream, "ftdm ss7 blo span X chan Y\n"); stream->write_function(stream, "ftdm ss7 ubl span X chan Y\n"); @@ -803,9 +914,12 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 cgb span X chan Y range Z\n"); stream->write_function(stream, "ftdm ss7 cgu span X chan Y range Z\n"); stream->write_function(stream, "\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 link control:\n"); + /* stream->write_function(stream, "ftdm ss7 inhibit link X\n"); stream->write_function(stream, "ftdm ss7 uninhibit link X\n"); + */ stream->write_function(stream, "ftdm ss7 activate link X\n"); stream->write_function(stream, "ftdm ss7 deactivate link X\n"); stream->write_function(stream, "ftdm ss7 activate linkset X\n"); @@ -821,6 +935,21 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 show relay\n"); stream->write_function(stream, "\n"); + stream->write_function(stream, "ftmod_sangoma_ss7 M2UA :\n"); + stream->write_function(stream, "ftdm ss7 xmlshow sctp \n"); + stream->write_function(stream, "ftdm ss7 xmlshow sctp \n"); + stream->write_function(stream, "ftdm ss7 xmlshow m2ua \n"); + stream->write_function(stream, "ftdm ss7 xmlshow m2ua \n"); + stream->write_function(stream, "ftdm ss7 xmlshow m2ua peerstatus\n"); + stream->write_function(stream, "ftdm ss7 xmlshow m2ua clusterstatus\n"); + stream->write_function(stream, "ftdm ss7 xmlshow nif \n"); + stream->write_function(stream, "ftdm ss7 xmlshow nif \n"); + stream->write_function(stream, "\n"); + + + stream->write_function(stream, "ftmod_sangoma_ss7 M2UA logging:\n"); + stream->write_function(stream, "ftdm ss7 m2ua logging [enable|disable] \n"); + stream->write_function(stream, "\n"); return FTDM_SUCCESS; @@ -1315,10 +1444,14 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, }else { stream->write_function(stream, "relay=N"); } + +#ifdef SMG_RELAY_DBG + stream->write_function(stream, "| flag=0x%llx", ftdmchan->flags); +#endif } #ifdef SMG_RELAY_DBG - stream->write_function(stream," blk_flag=%x | ckt_flag=%x | chan_flag=%x", ss7_info->blk_flags, ss7_info->ckt_flags, ftdmchan->flags); + stream->write_function(stream," | blk_flag=%x | ckt_flag=%x", ss7_info->blk_flags, ss7_info->ckt_flags); #endif stream->write_function(stream, "\n"); } /* if ( hole, sig, voice) */ @@ -1327,6 +1460,33 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, x++; } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + /* Look spans that are being used by M2UA SG links */ + for (x = 1; x < ftdm_array_len(g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif); x++) { + if (g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].id) { + if (g_ftdm_sngss7_data.cfg.mtp2Link[g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].mtp2LnkNmb].id) { + uint32_t mtp1_id = g_ftdm_sngss7_data.cfg.mtp2Link[g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[x].mtp2LnkNmb].id; + if (g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].id) { + if (g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].span == span) { + if (chan) { + if (chan == g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].chan) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|SIGNALING LINK\n", + g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].span, + g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].chan, + 0); + } + } else { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|SIGNALING LINK\n", + g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].span, + g_ftdm_sngss7_data.cfg.mtp1Link[mtp1_id].chan, + 0); + } + } + } + + } + } + } + return FTDM_SUCCESS; } @@ -1360,36 +1520,26 @@ static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int c } if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { - /* now that we have the right channel...put a lock on it so no-one else can use it */ ftdm_mutex_lock(ftdmchan->mutex); /* check if there is a pending state change|give it a bit to clear */ if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); - /* check if we need to die */ ftdm_assert(0, "State change not completed\n"); - /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); - /* move to the next channel */ continue; } else { - /* throw the ckt block flag */ sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); - - /* 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); + } - } /* if ( span and chan) */ + } - } /* if ( cic != 0) */ - - /* go the next circuit */ x++; - } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + } handle_show_blocks(stream, span, chan, verbose); @@ -1426,33 +1576,22 @@ static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int c } if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { - /* now that we have the right channel...put a lock on it so no-one else can use it */ ftdm_mutex_lock(ftdmchan->mutex); /* check if there is a pending state change|give it a bit to clear */ if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); - /* check if we need to die */ ftdm_assert(0, "State change not completed\n"); - /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); - /* move to the next channel */ continue; } else { - /* throw the ckt block flag */ sngss7_set_ckt_blk_flag(ss7_info, FLAG_CKT_MN_UNBLK_TX); - - /* clear the block flag */ sngss7_clear_ckt_blk_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); - - /* check group blocking */ sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX); - /* 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); } @@ -1632,7 +1771,9 @@ static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int c ftdm_mutex_lock(ftdmchan->mutex); /* throw the reset flag */ - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + sngss7_clear_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + sngss7_tx_reset_restart(sngss7_info); switch (ftdmchan->state) { /**************************************************************************/ @@ -1796,6 +1937,8 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c /* throw the grp maint. block flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + /* bring the sig status down */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); @@ -1929,6 +2072,7 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c /* bring the sig status up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); /* if this is the first channel in the range */ if (!main_chan) { @@ -2719,20 +2863,22 @@ static ftdm_status_t cli_ss7_show_general(ftdm_stream_handle_t *stream) stream->write_function(stream, "MTP2 status: \n"); cli_ss7_show_all_mtp2link(stream); - stream->write_function(stream, "\nMTP3 status: \n"); - cli_ss7_show_all_mtp3link(stream); + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ + stream->write_function(stream, "\nMTP3 status: \n"); + cli_ss7_show_all_mtp3link(stream); - stream->write_function(stream, "\nMTP3 linkset status: \n"); - cli_ss7_show_all_linkset(stream); + stream->write_function(stream, "\nMTP3 linkset status: \n"); + cli_ss7_show_all_linkset(stream); #if 0 - stream->write_function(stream, "\nMTP3 link route status: \n"); + stream->write_function(stream, "\nMTP3 link route status: \n"); - stream->write_function(stream, "\nISUP status: \n"); + stream->write_function(stream, "\nISUP status: \n"); #endif - stream->write_function(stream, "\nRelay status: \n"); - cli_ss7_show_all_relay(stream); + stream->write_function(stream, "\nRelay status: \n"); + cli_ss7_show_all_relay(stream); + } return FTDM_SUCCESS; } @@ -2949,6 +3095,904 @@ static ftdm_status_t cli_ss7_show_all_spans_general(ftdm_stream_handle_t *stream return FTDM_FAIL; } + +/****************************************************************************** +* Fun: handle_show_m2ua_profiles() +* Desc: display all m2ua profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ + +static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream) +{ + MwMgmt cfm; + MwMgmt rsp; + char buf[2048]; + char* xmlhdr = (char*)""; + int x = 0x00; + int idx = 0x00; + int len = 0x00; + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&rsp, 0, sizeof(MwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + len = len + sprintf(buf + len, "\n"); + + if(ftmod_m2ua_ssta_req(STMWGEN, 0x00, &cfm)) { + stream->write_function(stream," Request to layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); +#ifdef BIT_64 + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.memAlloc); +#else + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.genSta.memAlloc); +#endif + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbClusters); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbPeers); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.genSta.nmbIntf); + len = len + sprintf(buf + len, "\n"); + } + + /*iterate through all the m2ua links and prints all information */ + x = 1; + while(x\n"); + len = len + sprintf(buf + len, " %s \n", g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].name); + + if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.dlSapSta.state)); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_LINK_STATE(cfm.t.ssta.s.dlSapSta.lnkState)); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.rpoEnable); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.lpoEnable); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.congLevel); + len = len + sprintf(buf + len, "\n"); + } + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + if(ftmod_m2ua_ssta_req(STMWCLUSTER,g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId,&cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_CLUSTER_STATE(cfm.t.ssta.s.clusterSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbPeer); + len = len + sprintf(buf + len, "\n"); + for(idx = 0; idx < cfm.t.ssta.s.clusterSta.nmbPeer; idx++) + { + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.clusterSta.peerSt[idx].peerId); + len = len + sprintf(buf + len, " %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.clusterSta.peerSt[idx].peerState)); + } + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbActPeer); + + len = len + sprintf(buf + len, "\n"); + + memset((U8 *)&rsp, 0, sizeof(MwMgmt)); + memcpy(&rsp, &cfm, sizeof(MwMgmt)); + + + /* loop through configured peers */ + for(idx = 0; idx < rsp.t.ssta.s.clusterSta.nmbPeer; idx++) + { + int peer_id = rsp.t.ssta.s.clusterSta.peerSt[idx].peerId; + + memset(&cfm, 0, sizeof(MwMgmt)); + + if(LMW_PEER_DOWN != rsp.t.ssta.s.clusterSta.peerSt[idx].peerState){ + + if(ftmod_m2ua_ssta_req(STMWPEER, peer_id, &cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id].name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); + len = len + sprintf(buf + len, " %d \n", (int)cfm.t.ssta.s.peerSta.assocSta.spAssocId); + len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + + len = len + sprintf(buf + len, "\n"); + } + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id].name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(rsp.t.ssta.s.clusterSta.peerSt[idx].peerState)); + len = len + sprintf(buf + len, "\n"); + } + } + } + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); + len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); + len = len + sprintf(buf + len," %d \n", (int) cfm.t.ssta.s.sctSapSta.spEndpId); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); + len = len + sprintf(buf + len, "\n"); + } + + len = len + sprintf(buf + len, "\n"); + } + x++; + } + + len = len + sprintf(buf + len, "\n"); + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; + +} + +/****************************************************************************** +* Fun: handle_show_m2ua_profile() +* Desc: display requested m2ua profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ + +static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[4096]; + int x = 0x00; + int idx = 0x00; + int found = 0x00; + int len = 0x00; + MwMgmt cfm; + MwMgmt rsp; + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&rsp, 0, sizeof(MwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the m2ua links and get required profile */ + x = 1; + while(xwrite_function(stream,"Requested M2UA profile[%s] not configured\n", m2ua_profile_name); + return FTDM_FAIL; + } + + + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n", m2ua_profile_name); + + if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.dlSapSta.state)); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_LINK_STATE(cfm.t.ssta.s.dlSapSta.lnkState)); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.rpoEnable); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.lpoEnable); + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.congLevel); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_m2ua_ssta_req(STMWCLUSTER, g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId, &cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_CLUSTER_STATE(cfm.t.ssta.s.clusterSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbPeer); + len = len + sprintf(buf + len, "\n"); + for(idx = 0; idx < cfm.t.ssta.s.clusterSta.nmbPeer; idx++) + { + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.clusterSta.peerSt[idx].peerId); + len = len + sprintf(buf + len, " %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.clusterSta.peerSt[idx].peerState)); + } + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbActPeer); + + len = len + sprintf(buf + len, "\n"); + } + + memcpy((U8 *)&rsp, &cfm, sizeof(MwMgmt)); + + /* loop through configured peers */ + for(idx = 0; idx < rsp.t.ssta.s.clusterSta.nmbPeer; idx++) + { + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + + if(ftmod_m2ua_ssta_req(STMWPEER, rsp.t.ssta.s.clusterSta.peerSt[idx].peerId, &cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[rsp.t.ssta.s.clusterSta.peerSt[idx].peerId].name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.retryCount); +#ifdef BIT_64 + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.peerSta.assocSta.spAssocId); +#else + len = len + sprintf(buf + len, " %ld \n", cfm.t.ssta.s.peerSta.assocSta.spAssocId); +#endif + len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED"); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcInProg); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.flcLevel); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.sctpHBeatEnb); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.peerSta.assocSta.locOutStrms); + + len = len + sprintf(buf + len, "\n"); + } + } + + if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state)); + len = len + sprintf(buf + len," %s \n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN"); +#ifdef BIT_64 + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.spEndpId); +#else + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.sctSapSta.spEndpId); +#endif + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry); + len = len + sprintf(buf + len, "\n"); + } + + len = len + sprintf(buf + len, "\n"); + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; + +} + +/****************************************************************************** +* Fun: handle_show_sctp_profiles() +* Desc: display all sctp profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ +static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream) +{ + char* xmlhdr = (char*)""; + char buf[4096]; + int x = 0x00; + int len = 0x00; + SbMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(SbMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + len = len + sprintf(buf + len, "\n"); + + if(ftmod_sctp_ssta_req(STSBGEN, 0x00, &cfm)) { + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); +#ifdef BIT_64 + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); +#else + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); +#endif + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbAssoc); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbEndp); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbLocalAddr); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.nmbPeerAddr); + len = len + sprintf(buf + len, "\n"); + } + +#ifdef LSB12 + if(ftmod_sctp_ssta_req(STSBTMR, 0x00, &cfm)) { + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.lifetimeTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.ackDelayTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.cookieTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.keyTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.freezeTmr); +#ifdef LSB4 + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.bundleTmr); +#endif + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.t1InitTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.t2ShutdownTmr); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.hbeat); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.t3rtx); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.tmrSta.tIntTmr); + } + +#endif + + + /*iterate through all the sctp links and prints all information */ + x = 1; + while(x\n"); + + if(ftmod_sctp_ssta_req(STSBSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_SAP_STATE(cfm.t.ssta.s.sapSta.hlSt)); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_PROTO_SWITCH(cfm.t.ssta.s.sapSta.swtch)); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_sctp_ssta_req(STSBTSAP,x,&cfm)) { + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_SAP_STATE(cfm.t.ssta.s.sapSta.hlSt)); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_PROTO_SWITCH(cfm.t.ssta.s.sapSta.swtch)); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_sctp_ssta_req(STSBASSOC,x,&cfm)) { + if(LCM_REASON_INVALID_PAR_VAL == cfm.cfm.reason){ + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); + len = len + sprintf(buf + len, "\n"); + }else{ + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } + } else { + len = len + sprintf(buf + len, "\n"); + len = len + get_assoc_resp_buf(buf + len, &cfm); + len = len + sprintf(buf + len, "\n"); + } + + /* TODO - STSBDTA */ + + len = len + sprintf(buf + len, "\n"); + } + x++; + } + + len = len + sprintf(buf + len, "\n"); + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + +int get_assoc_resp_buf(char* buf,SbMgmt* cfm) +{ + int len = 0x00; + int idx = 0x00; + char *asciiAddr; + CmInetIpAddr ip; + +#ifdef BIT_64 + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.assocId); +#else + len = len + sprintf(buf + len, " %ld \n", cfm->t.ssta.s.assocSta.assocId); +#endif + len = len + sprintf(buf + len, " %s \n", PRNT_SCTP_ASSOC_STATE(cfm->t.ssta.s.assocSta.assocState)); + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.dstPort); + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.srcPort); + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.dstNAddrLst.nmb); + for(idx =0; idx < cfm->t.ssta.s.assocSta.dstNAddrLst.nmb; idx++) + { + len = len + sprintf(buf + len, " \n"); + len = len + sprintf(buf + len, " %s \n", PRNT_CM_ADDR_TYPE(cfm->t.ssta.s.assocSta.dstNAddrLst.nAddr[idx].type)); + if(cfm->t.ssta.s.assocSta.dstNAddrLst.nAddr[idx].type == CM_IPV4ADDR_TYPE) + { + ip = ntohl(cfm->t.ssta.s.assocSta.dstNAddrLst.nAddr[idx].u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(buf + len, " %s \n",asciiAddr); + } + else + { + len = len + sprintf(buf + len, " %s \n", cfm->t.ssta.s.assocSta.dstNAddrLst.nAddr[idx].u.ipv6NetAddr); + } + len = len + sprintf(buf + len, " \n"); + } + + len = len + sprintf(buf + len, " %d \n", cfm->t.ssta.s.assocSta.srcNAddrLst.nmb); + for(idx =0; idx < cfm->t.ssta.s.assocSta.srcNAddrLst.nmb; idx++) + { + len = len + sprintf(buf + len, " \n"); + len = len + sprintf(buf + len, " %s \n", PRNT_CM_ADDR_TYPE(cfm->t.ssta.s.assocSta.srcNAddrLst.nAddr[idx].type)); + if(cfm->t.ssta.s.assocSta.srcNAddrLst.nAddr[idx].type == CM_IPV4ADDR_TYPE) + { + ip = ntohl(cfm->t.ssta.s.assocSta.srcNAddrLst.nAddr[idx].u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(buf + len, " %s \n", asciiAddr); + } + else + { + len = len + sprintf(buf + len, " %s \n", cfm->t.ssta.s.assocSta.srcNAddrLst.nAddr[idx].u.ipv6NetAddr); + } + len = len + sprintf(buf + len, " \n"); + } + + len = len + sprintf(buf + len, "\n %s \n", PRNT_CM_ADDR_TYPE(cfm->t.ssta.s.assocSta.priNAddr.type)); + + if(cfm->t.ssta.s.assocSta.priNAddr.type == CM_IPV4ADDR_TYPE) + { + ip = ntohl(cfm->t.ssta.s.assocSta.priNAddr.u.ipv4NetAddr); + cmInetNtoa(ip, &asciiAddr); + len = len + sprintf(buf + len, " %s \n",asciiAddr); + } + else + { + len = len + sprintf(buf + len, " %s \n", cfm->t.ssta.s.assocSta.priNAddr.u.ipv6NetAddr); + } + +#ifdef LSB11 + /* TODO - this flag is not enable as of now.. so later on will convert below prints to XML tags */ + len = len + sprintf(buf + len, " The number of unsent datagrams : %d\n", cfm->t.ssta.s.assocSta.nmbUnsentDgms); + len = len + sprintf(buf + len, " The number of unack datagrams : %d\n", cfm->t.ssta.s.assocSta.nmbUnackDgms); + len = len + sprintf(buf + len, " The number of undelivered datagrams : %d\n", cfm->t.ssta.s.assocSta.nmbUndelDgms); + len = len + sprintf(buf + len, " The number of retransmissions count : %d\n", cfm->t.ssta.s.assocSta.rtxCnt); + len = len + sprintf(buf + len, " The receive window size is: %d\n\n", cfm->t.ssta.s.assocSta.SctWinSize); + for(idx =0; idx < LSB_MAX_TMRS ; idx++) + { + len = len + sprintf(buf + len, " %d) Timer state is %d\n", idx, cfm->t.ssta.s.assocSta.tmr[idx].state); + len = len + sprintf(buf + len, " %d) Timer value is %d\n", idx, cfm->t.ssta.s.assocSta.tmr[idx].tmrVal); + len = len + sprintf(buf + len, " %d) No of paths is %d\n", idx, cfm->t.ssta.s.assocSta.tmr[idx].numPaths); + for(idx1 =0; idx1 < cfm->t.ssta.s.assocSta.tmr[idx].numPaths; idx1++) + { + if( cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].localAddr.type == CM_IPV4ADDR_TYPE) + { + len = len + sprintf(buf + len, " %d) the local Addr is %d\n", idx1, + cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].localAddr.u.ipv4NetAddr); + } + else + { + len = len + sprintf(buf + len, " %d) the local Addr is %s\n", idx1, + cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].localAddr.u.ipv6NetAddr); + } + + if( cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].peerAddr.type == CM_IPV4ADDR_TYPE) + { + len = len + sprintf(buf + len, " %d) the peer Addr is %d\n", idx1, + cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].peerAddr.u.ipv4NetAddr); + } + else + { + len = len + sprintf(buf + len, " %d) the peer Addr is %s\n", idx1, + cfm->t.ssta.s.assocSta.tmr[idx].path[idx1].peerAddr.u.ipv6NetAddr); + } + } /* Loop for paths */ + } /* Loop for timers */ +#endif + + return len; +} + +/****************************************************************************** +* Fun: handle_show_sctp_profile() +* Desc: display requested sctp profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ +static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char* sctp_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[4096]; + int x = 0x00; + int len = 0x00; + SbMgmt cfm; + int found = 0x00; + + memset((U8 *)&cfm, 0, sizeof(SbMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the sctp links and prints all information */ + x = 1; + while(xwrite_function(stream,"Requested SCTP profile[%s] not configured\n", sctp_profile_name); + return FTDM_FAIL; + } + + len = len + sprintf(buf + len, "\n"); + + if(ftmod_sctp_ssta_req(STSBSCTSAP,x,&cfm)) { + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_SAP_STATE(cfm.t.ssta.s.sapSta.hlSt)); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_PROTO_SWITCH(cfm.t.ssta.s.sapSta.swtch)); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_sctp_ssta_req(STSBTSAP,x,&cfm)) { + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_SAP_STATE(cfm.t.ssta.s.sapSta.hlSt)); + len = len + sprintf(buf + len," %s \n", PRNT_SCTP_PROTO_SWITCH(cfm.t.ssta.s.sapSta.swtch)); + len = len + sprintf(buf + len, "\n"); + } + + if(ftmod_sctp_ssta_req(STSBASSOC,x,&cfm)) { + /* it means assoc id not yet allocated */ + if(LCM_REASON_INVALID_PAR_VAL == cfm.cfm.reason){ + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); + len = len + sprintf(buf + len, "\n"); + }else{ + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } + } else { + len = len + sprintf(buf + len, "\n"); + len = len + get_assoc_resp_buf(buf + len, &cfm); + len = len + sprintf(buf + len, "\n"); + } + + /* TODO - STSBDTA */ + + len = len + sprintf(buf + len, "\n"); + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + +/****************************************************************************** +* Fun: handle_show_nif_profiles() +* Desc: display all nif profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ +static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream) +{ + char* xmlhdr = (char*)""; + char buf[4096]; + int x = 0x00; + int len = 0x00; + NwMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(NwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + len = len + sprintf(buf + len, "\n"); + + if(ftmod_nif_ssta_req(STNWGEN, 0x00, &cfm)) { + stream->write_function(stream," Request to NIF layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); +#ifdef BIT_64 + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.genSta.memAlloc); +#else + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memSize); + len = len + sprintf(buf + len, " %ld \n",cfm.t.ssta.s.genSta.memAlloc); +#endif + len = len + sprintf(buf + len, "\n"); + } + + /*iterate through all the NIF links and prints all information */ + x = 1; + while(x\n"); + + if(ftmod_nif_ssta_req(STNWDLSAP,x,&cfm)) { + stream->write_function(stream," Request to NIF layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); + len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); +#ifdef BIT_64 + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); +#else + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.dlSapSta.nmbRetry); +#endif + len = len + sprintf(buf + len, "\n"); + } + + len = len + sprintf(buf + len, "\n"); + } + x++; + } + + len = len + sprintf(buf + len, "\n"); + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + +/****************************************************************************** +* Fun: handle_show_nif_profile() +* Desc: display requested nif profile information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ +static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* nif_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[4096]; + int x = 0x00; + int found = 0x00; + int len = 0x00; + NwMgmt cfm; + + memset((U8 *)&cfm, 0, sizeof(NwMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the m2ua links and get required profile */ + x = 1; + while(xwrite_function(stream,"Requested NIF profile[%s] not configured\n", nif_profile_name); + return FTDM_FAIL; + } + + + len = len + sprintf(buf + len, "\n"); + + if(ftmod_nif_ssta_req(STNWDLSAP,x,&cfm)) { + stream->write_function(stream," Request to NIF layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.m2uaState)); + len = len + sprintf(buf + len," %s \n", PRNT_NIF_SAP_STATE(cfm.t.ssta.s.dlSapSta.mtp2State)); +#ifdef BIT_64 + len = len + sprintf(buf + len," %d \n", cfm.t.ssta.s.dlSapSta.nmbRetry); +#else + len = len + sprintf(buf + len," %ld \n", cfm.t.ssta.s.dlSapSta.nmbRetry); +#endif + len = len + sprintf(buf + len, "\n"); + } + + len = len + sprintf(buf + len, "\n"); + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +/****************************************************************************** +* Fun: handle_show_m2ua_peer_status() +* Desc: display requested m2ua profile peer information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ + +static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[4096]; + int x = 0x00; + int found = 0x00; + int len = 0x00; + MwMgmt cfm; + SbMgmt sctp_cfm; + sng_m2ua_cluster_cfg_t* clust = NULL; + sng_m2ua_cfg_t* m2ua = NULL; + sng_m2ua_peer_cfg_t* peer = NULL; + int peer_id = 0; + int sctp_id = 0; + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&sctp_cfm, 0, sizeof(SbMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the m2ua links and get required profile */ + x = 1; + while(xwrite_function(stream,"Requested M2UA profile[%s] not configured\n", m2ua_profile_name); + return FTDM_FAIL; + } + + m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x]; + clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + + for(x = 0; x < clust->numOfPeers;x++){ + peer_id = clust->peerIdLst[x]; + peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id]; + + if(ftmod_m2ua_ssta_req(STMWPEER, peer_id, &cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",peer->name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state)); + /*len = len + sprintf(buf + len, " %s \n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED");*/ + len = len + sprintf(buf + len, "\n"); + } + + sctp_id = peer->sctpId; + + if(ftmod_sctp_ssta_req(STSBASSOC, sctp_id, &sctp_cfm)) { + if(LMW_PEER_DOWN == cfm.t.ssta.s.peerSta.state){ + /* If there is no association established so far, it will return fail..*/ + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " SCT_ASSOC_STATE_CLOSED \n"); + len = len + sprintf(buf + len, "\n"); + }else{ + stream->write_function(stream," Request to SCTP layer failed \n"); + return FTDM_FAIL; + } + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n", PRNT_SCTP_ASSOC_STATE(sctp_cfm.t.ssta.s.assocSta.assocState)); + len = len + sprintf(buf + len, "\n"); + } + } + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + +/****************************************************************************** +* Fun: handle_show_m2ua_cluster_status() +* Desc: display requested m2ua profile cluster information +* Ret: FTDM_SUCCESS | FTDM_FAIL +* Note: +* author: Kapil Gupta +*******************************************************************************/ + +static ftdm_status_t handle_show_m2ua_cluster_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name) +{ + char* xmlhdr = (char*)""; + char buf[4096]; + int x = 0x00; + int found = 0x00; + int len = 0x00; + int idx = 0x00; + MwMgmt cfm; + SbMgmt sctp_cfm; + sng_m2ua_cluster_cfg_t* clust = NULL; + sng_m2ua_cfg_t* m2ua = NULL; + + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&sctp_cfm, 0, sizeof(SbMgmt)); + memset(&buf[0], 0, sizeof(buf)); + + len = len + sprintf(buf + len, "%s\n", xmlhdr); + + /*iterate through all the m2ua links and get required profile */ + x = 1; + while(xwrite_function(stream,"Requested M2UA profile[%s] not configured\n", m2ua_profile_name); + return FTDM_FAIL; + } + + m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x]; + clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + + if(ftmod_m2ua_ssta_req(STMWCLUSTER,g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId,&cfm)) { + stream->write_function(stream," Request to M2UA layer failed \n"); + return FTDM_FAIL; + } else { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n",clust->name); + len = len + sprintf(buf + len," %s \n", PRNT_M2UA_CLUSTER_STATE(cfm.t.ssta.s.clusterSta.state)); + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbPeer); + for(idx = 0; idx < cfm.t.ssta.s.clusterSta.nmbPeer; idx++) + { + len = len + sprintf(buf + len, "\n"); + len = len + sprintf(buf + len, " %s \n", g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[cfm.t.ssta.s.clusterSta.peerSt[idx].peerId].name); + len = len + sprintf(buf + len, " %d \n", cfm.t.ssta.s.clusterSta.peerSt[idx].peerId); + len = len + sprintf(buf + len, " %s \n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.clusterSta.peerSt[idx].peerState)); + len = len + sprintf(buf + len, "\n"); + } + len = len + sprintf(buf + len, " %d \n",cfm.t.ssta.s.clusterSta.nmbActPeer); + + len = len + sprintf(buf + len, "\n"); + } + + stream->write_function(stream,"\n%s\n",buf); + + return FTDM_SUCCESS; +} + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c index b0a2163fdd..0fcef7d90b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c @@ -48,35 +48,7 @@ static int ftmod_ss7_enable_isap(int suId); static int ftmod_ss7_enable_nsap(int suId); static int ftmod_ss7_enable_mtpLinkSet(int lnkSetId); -int ftmod_ss7_inhibit_mtp3link(uint32_t id); -int ftmod_ss7_uninhibit_mtp3link(uint32_t id); -int ftmod_ss7_bind_mtp3link(uint32_t id); -int ftmod_ss7_unbind_mtp3link(uint32_t id); -int ftmod_ss7_activate_mtp3link(uint32_t id); -int ftmod_ss7_deactivate_mtp3link(uint32_t id); -int ftmod_ss7_deactivate2_mtp3link(uint32_t id); - -int ftmod_ss7_activate_mtplinkSet(uint32_t id); -int ftmod_ss7_deactivate_mtplinkSet(uint32_t id); -int ftmod_ss7_deactivate2_mtplinkSet(uint32_t id); - -int ftmod_ss7_lpo_mtp3link(uint32_t id); -int ftmod_ss7_lpr_mtp3link(uint32_t id); - -int ftmod_ss7_shutdown_isup(void); -int ftmod_ss7_shutdown_mtp3(void); -int ftmod_ss7_shutdown_mtp2(void); -int ftmod_ss7_shutdown_relay(void); -int ftmod_ss7_disable_relay_channel(uint32_t chanId); - -int ftmod_ss7_disable_grp_mtp3Link(uint32_t procId); -int ftmod_ss7_enable_grp_mtp3Link(uint32_t procId); - -int ftmod_ss7_disable_grp_mtp2Link(uint32_t procId); - -int ftmod_ss7_block_isup_ckt(uint32_t cktId); -int ftmod_ss7_unblock_isup_ckt(uint32_t cktId); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -88,7 +60,7 @@ int ft_to_sngss7_activate_all(void) while (x < (MAX_ISAPS)) { /* check if this link has already been actived */ if ((g_ftdm_sngss7_data.cfg.isap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.isap[x].flags & SNGSS7_ACTIVE))) { + (!(g_ftdm_sngss7_data.cfg.isap[x].flags & SNGSS7_ACTIVE))) { if (ftmod_ss7_enable_isap(x)) { SS7_CRITICAL("ISAP %d Enable: NOT OK\n", x); @@ -100,15 +72,16 @@ int ft_to_sngss7_activate_all(void) /* set the SNGSS7_ACTIVE flag */ g_ftdm_sngss7_data.cfg.isap[x].flags |= SNGSS7_ACTIVE; } /* if !SNGSS7_ACTIVE */ - + x++; } /* while (x < (MAX_ISAPS)) */ + if(SNG_SS7_OPR_MODE_M2UA_SG != g_ftdm_operating_mode){ x = 1; while (x < (MAX_NSAPS)) { /* check if this link has already been actived */ if ((g_ftdm_sngss7_data.cfg.nsap[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_ACTIVE))) { + (!(g_ftdm_sngss7_data.cfg.nsap[x].flags & SNGSS7_ACTIVE))) { if (ftmod_ss7_enable_nsap(x)) { SS7_CRITICAL("NSAP %d Enable: NOT OK\n", x); @@ -120,30 +93,35 @@ int ft_to_sngss7_activate_all(void) /* set the SNGSS7_ACTIVE flag */ g_ftdm_sngss7_data.cfg.nsap[x].flags |= SNGSS7_ACTIVE; } /* if !SNGSS7_ACTIVE */ - + x++; } /* while (x < (MAX_NSAPS)) */ - if (g_ftdm_sngss7_data.cfg.mtpRoute[1].id != 0) { - x = 1; - while (x < (MAX_MTP_LINKSETS+1)) { - /* check if this link has already been actived */ - if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && - (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_ACTIVE))) { - - if (ftmod_ss7_enable_mtpLinkSet(x)) { - SS7_CRITICAL("LinkSet \"%s\" Enable: NOT OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); - return 1; - } else { - SS7_INFO("LinkSet \"%s\" Enable: OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); - } - - /* set the SNGSS7_ACTIVE flag */ - g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_ACTIVE; - } /* if !SNGSS7_ACTIVE */ - - x++; - } /* while (x < (MAX_MTP_LINKSETS+1)) */ + if (g_ftdm_sngss7_data.cfg.mtpRoute[1].id != 0) { + x = 1; + while (x < (MAX_MTP_LINKSETS+1)) { + /* check if this link has already been actived */ + if ((g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) && + (!(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags & SNGSS7_ACTIVE))) { + + if (ftmod_ss7_enable_mtpLinkSet(x)) { + SS7_CRITICAL("LinkSet \"%s\" Enable: NOT OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); + return 1; + } else { + SS7_INFO("LinkSet \"%s\" Enable: OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); + } + + /* set the SNGSS7_ACTIVE flag */ + g_ftdm_sngss7_data.cfg.mtpLinkSet[x].flags |= SNGSS7_ACTIVE; + } /* if !SNGSS7_ACTIVE */ + + x++; + } /* while (x < (MAX_MTP_LINKSETS+1)) */ + } + } + + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + return ftmod_ss7_m2ua_start(); } return 0; @@ -779,7 +757,14 @@ int ftmod_ss7_disable_grp_mtp3Link(uint32_t procId) cntrl.t.cntrl.action = AUBND_DIS; /* disable and unbind */ cntrl.t.cntrl.subAction = SAGR_DSTPROCID; /* specificed element */ - return (sng_cntrl_mtp3(&pst, &cntrl)); + if (g_ftdm_sngss7_data.cfg.procId == procId) { + SS7_DEBUG("Executing MTP3 cntrl command local pid =%i\n",procId); + return (sng_cntrl_mtp3(&pst, &cntrl)); + } else { + SS7_WARN("Executing MTP3 cntrl command different local=%i target=%i\n", + g_ftdm_sngss7_data.cfg.procId,procId); + return (sng_cntrl_mtp3_nowait(&pst, &cntrl)); + } } @@ -811,7 +796,14 @@ int ftmod_ss7_enable_grp_mtp3Link(uint32_t procId) cntrl.t.cntrl.action = ABND_ENA; /* bind and enable */ cntrl.t.cntrl.subAction = SAGR_DSTPROCID; /* specificed element */ - return (sng_cntrl_mtp3(&pst, &cntrl)); + if (g_ftdm_sngss7_data.cfg.procId == procId) { + SS7_DEBUG("Executing MTP3 cntrl command local pid =%i\n",procId); + return (sng_cntrl_mtp3(&pst, &cntrl)); + } else { + SS7_WARN("Executing MTP3 cntrl command different local=%i target=%i\n", + g_ftdm_sngss7_data.cfg.procId,procId); + return (sng_cntrl_mtp3_nowait(&pst, &cntrl)); + } } @@ -848,7 +840,7 @@ int ftmod_ss7_disable_grp_mtp2Link(uint32_t procId) } /******************************************************************************/ -int ftmod_ss7_block_isup_ckt(uint32_t cktId) +int __ftmod_ss7_block_isup_ckt(uint32_t cktId, ftdm_bool_t wait) { SiMngmt cntrl; Pst pst; @@ -876,7 +868,11 @@ int ftmod_ss7_block_isup_ckt(uint32_t cktId) cntrl.t.cntrl.action = ADISIMM; /* block via BLO */ cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ - return (sng_cntrl_isup(&pst, &cntrl)); + if (wait == FTDM_TRUE) { + return (sng_cntrl_isup(&pst, &cntrl)); + } else { + return (sng_cntrl_isup_nowait(&pst, &cntrl)); + } } /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 24ea92e6db..c94b53d880 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -33,6 +33,7 @@ * Contributors: * * Ricardo Barroetaveña + * James Zhang * */ @@ -87,6 +88,8 @@ ftdm_status_t handle_olm_msg(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* FUNCTIONS ******************************************************************/ +#define ftdm_running_return(var) if (!ftdm_running()) { SS7_ERROR("Error: ftdm_running is not set! Ignoring\n"); return var; } + ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt) { SS7_FUNC_TRACE_ENTER(__FUNCTION__); @@ -94,9 +97,11 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; char var[FTDM_DIGITS_LIMIT]; - + memset(var, '\0', sizeof(var)); + ftdm_running_return(FTDM_FAIL); + /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); @@ -118,11 +123,24 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* as per Q.764, 2.8.2.3 xiv ... remove the block from this channel */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX_DN); /* KONRAD FIX ME : check in case there is a ckt and grp block */ } + + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX_DN); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_SENT); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX_DN); + sngss7_clear_ckt_flag(sngss7_info, FLAG_FULL_NUMBER); /* check whether the ftdm channel is in a state to accept a call */ switch (ftdmchan->state) { @@ -167,6 +185,12 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* fill in ANI */ ftdm_set_string(ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.cid_num.digits); } + else { + if (g_ftdm_sngss7_data.cfg.force_inr) { + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT); + } + } if (siConEvnt->cgPtyNum.scrnInd.pres) { /* fill in the screening indication value */ @@ -178,6 +202,11 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdmchan->caller_data.pres = siConEvnt->cgPtyNum.presRest.val; } } else { + if (g_ftdm_sngss7_data.cfg.force_inr) { + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT); + } + SS7_INFO_CHAN(ftdmchan,"No Calling party (ANI) information in IAM!%s\n", " "); } @@ -192,12 +221,16 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } else { SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in IAM!%s\n", " "); } - + copy_NatureOfConnection_from_sngss7(ftdmchan, &siConEvnt->natConInd); + copy_fwdCallInd_hex_from_sngss7(ftdmchan, &siConEvnt->fwdCallInd); + copy_access_transport_from_sngss7(ftdmchan, &siConEvnt->accTrnspt); + copy_ocn_from_sngss7(ftdmchan, &siConEvnt->origCdNum); copy_redirgNum_from_sngss7(ftdmchan, &siConEvnt->redirgNum); - + copy_redirgInfo_from_sngss7(ftdmchan, &siConEvnt->redirInfo); copy_genNmb_from_sngss7(ftdmchan, &siConEvnt->genNmb); copy_cgPtyCat_from_sngss7(ftdmchan, &siConEvnt->cgPtyCat); + copy_cdPtyNum_from_sngss7(ftdmchan, &siConEvnt->cdPtyNum); /* fill in the TMR/bearer capability */ if (siConEvnt->txMedReq.eh.pres) { @@ -213,9 +246,6 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sprintf(var, "%d", siConEvnt->cgPtyNum.natAddrInd.val); sngss7_add_var(sngss7_info, "ss7_clg_nadi", var); - sprintf(var, "%d", siConEvnt->cdPtyNum.natAddrInd.val); - sngss7_add_var(sngss7_info, "ss7_cld_nadi", var); - /* Retrieve the Location Number if present (see ITU Q.763, 3.30) */ if (siConEvnt->cgPtyNum1.eh.pres) { if (siConEvnt->cgPtyNum1.addrSig.pres) { @@ -247,7 +277,8 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sprintf(var, "%d", sngss7_info->circuit->cic); sngss7_add_var(sngss7_info, "ss7_cic", var); - sprintf(var, "%d", g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc ); + + sprintf(var, "%d", g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ); sngss7_add_var(sngss7_info, "ss7_opc", var); if (siConEvnt->callRef.callId.pres) { @@ -308,24 +339,26 @@ handle_glare: /* setup the hangup cause */ ftdmchan->caller_data.hangup_cause = 34; /* Circuit Congrestion */ - - /* this is a remote hangup request */ - sngss7_set_ckt_flag(sngss7_info, FLAG_REMOTE_REL); - - /* move the state of the channel to Terminating to end the call */ + + /* move the state of the channel to Terminating to end the call + in TERMINATING state, the release cause is set to REMOTE_REL + in any means. So we don't have to set the release reason here. + */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); - } /* if (!(sngss7_test_ckt_flag(sngss7_info, FLAG_GLARE))) */ + } break; /**************************************************************************/ default: /* should not have gotten an IAM while in this state */ SS7_ERROR_CHAN(ftdmchan, "Got IAM on channel in invalid state(%s)...reset!\n", ftdm_channel_state2str (ftdmchan->state)); - /* reset the cic */ - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); - - /* move the state of the channel to RESTART to force a reset */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* throw the TX reset flag */ + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_tx_reset_restart(sngss7_info); + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ } /* switch (ftdmchan->state) */ @@ -344,6 +377,8 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -389,11 +424,14 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ SS7_ERROR_CHAN(ftdmchan, "RX ACM in invalid state :%s...resetting CIC\n", ftdm_channel_state2str (ftdmchan->state)); - /* reset the cic */ - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + /* throw the TX reset flag */ + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_tx_reset_restart(sngss7_info); + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - /* go to RESTART */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**********************************************************************/ } /* switch (ftdmchan->state) */ @@ -422,10 +460,26 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ case (INFORMATION): SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INF\n", sngss7_info->circuit->cic); + + SS7_DEBUG_CHAN (ftdmchan, "Cancelling T.39 timer %s\n", " "); + /* check if t39 is active */ + if (sngss7_info->t39.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id); + SS7_DEBUG_CHAN (ftdmchan, "T.39 timer has been cancelled upon receiving INF message %s\n", " "); + } + + sngss7_set_ckt_flag(sngss7_info, FLAG_INF_RX_DN); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_IDLE); + break; /**************************************************************************/ case (INFORMATREQ): SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INR\n", sngss7_info->circuit->cic); + + ft_to_sngss7_inf(ftdmchan, siCnStEvnt); + + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_RX); + break; /**************************************************************************/ case (SUBSADDR): @@ -599,6 +653,8 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -651,10 +707,13 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx ANM/CON\n", sngss7_info->circuit->cic); /* throw the TX reset flag */ - sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX); + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_tx_reset_restart(sngss7_info); + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); - /* go to RESTART */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ @@ -674,6 +733,8 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -750,6 +811,10 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* send out the release complete */ ft_to_sngss7_rlc (ftdmchan); + } else { + SS7_DEBUG_CHAN(ftdmchan, "Collision of REL messages - resetting state.\n", " "); + ft_to_sngss7_rlc (ftdmchan); + goto rel_ind_reset; } break; /**************************************************************************/ @@ -772,11 +837,15 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ default: - /* throw the reset flag */ - sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_RX); +rel_ind_reset: + /* throw the TX reset flag */ + if (!sngss7_tx_reset_status_pending(sngss7_info)) { + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + sngss7_tx_reset_restart(sngss7_info); - /* set the state to RESTART */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* go to RESTART */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ } /* switch (ftdmchan->state) */ @@ -796,6 +865,8 @@ ftdm_status_t handle_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -847,6 +918,8 @@ ftdm_status_t handle_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -874,6 +947,8 @@ ftdm_status_t handle_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -901,6 +976,8 @@ ftdm_status_t handle_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -928,6 +1005,8 @@ ftdm_status_t handle_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -955,6 +1034,8 @@ ftdm_status_t handle_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -982,6 +1063,8 @@ ftdm_status_t handle_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir sngss7_chan_data_t *sngss7_info ; ftdm_channel_t *ftdmchan; + + ftdm_running_return(FTDM_FAIL); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -1006,6 +1089,8 @@ ftdm_status_t handle_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) { SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is active on our side otherwise move to the next circuit */ if (!sngss7_test_flag(&g_ftdm_sngss7_data.cfg.isupCkt[circuit], SNGSS7_ACTIVE)) { @@ -1098,11 +1183,12 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ break; /**************************************************************************/ case SIT_STA_CGBRSP: /* mntc. oriented CGB response */ - /*handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);*/ + SS7_INFO(" Rx CGBA \n"); break; /**************************************************************************/ case SIT_STA_CGURSP: /* mntc. oriented CGU response */ /*SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));*/ + SS7_INFO(" Rx CGUA \n"); break; /**************************************************************************/ case SIT_STA_GRSREQ: /* circuit group reset request */ @@ -1206,6 +1292,8 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1235,6 +1323,7 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci /* the glare flag is already up so it was caught ... do nothing */ SS7_DEBUG_CHAN(ftdmchan, "Glare flag is already up...nothing to do!%s\n", " "); } else { + int bHangup = 0; SS7_DEBUG_CHAN(ftdmchan, "Glare flag is not up yet...indicating glare from reattempt!%s\n", " "); /* glare, throw the flag */ sngss7_set_ckt_flag(sngss7_info, FLAG_GLARE); @@ -1242,14 +1331,45 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci /* clear any existing glare data from the channel */ memset(&sngss7_info->glare, 0x0, sizeof(sngss7_glare_data_t)); + if (g_ftdm_sngss7_data.cfg.glareResolution == SNGSS7_GLARE_DOWN) { + /* If I'm in DOWN mode, I will always hangup my call. */ + bHangup = 1; + } + else if (g_ftdm_sngss7_data.cfg.glareResolution == SNGSS7_GLARE_PC) { + /* I'm in PointCode mode. + Case 1: My point code is higher than the other side. + If the CIC number is even, I'm trying to control. + If the CIC number is odd, I'll hangup my call and back off. + Case 2: My point code is lower than the other side. + If the CIC number is odd, I'm trying to control. + If the CIC number is even, I'll hangup my call and back off. + */ + if( g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc > g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ) + { + if ((sngss7_info->circuit->cic % 2) == 1 ) { + bHangup = 1; + } + } else { + if( (sngss7_info->circuit->cic % 2) == 0 ) { + bHangup = 1; + } + } + } + else { + /* If I'm in CONTROL mode, I will not hangup my call. */ + bHangup = 0; + } + + if (bHangup) { /* setup the hangup cause */ ftdmchan->caller_data.hangup_cause = 34; /* Circuit Congrestion */ - /* this is a remote hangup request */ - sngss7_set_ckt_flag(sngss7_info, FLAG_REMOTE_REL); - - /* move the state of the channel to Terminating to end the call */ - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + /* move the state of the channel to Terminating to end the call + in TERMINATING state, the release cause is set to REMOTE_REL + in any means. So we don't have to set the release reason here. + */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + } } /* unlock the channel again before we exit */ @@ -1269,6 +1389,8 @@ ftdm_status_t handle_pause(uint32_t suInstId, uint32_t spInstId, uint32_t circui int infId; int i; + ftdm_running_return(FTDM_FAIL); + /* extract the affected infId from the circuit structure */ infId = g_ftdm_sngss7_data.cfg.isupCkt[circuit].infId; @@ -1333,6 +1455,8 @@ ftdm_status_t handle_resume(uint32_t suInstId, uint32_t spInstId, uint32_t circu ftdm_channel_t *ftdmchan = NULL; int infId; int i; + + ftdm_running_return(FTDM_FAIL); /* extract the affect infId from the circuit structure */ infId = g_ftdm_sngss7_data.cfg.isupCkt[circuit].infId; @@ -1397,6 +1521,8 @@ ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t ci sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1452,6 +1578,8 @@ ftdm_status_t handle_cot_stop(uint32_t suInstId, uint32_t spInstId, uint32_t cir sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1497,6 +1625,8 @@ ftdm_status_t handle_cot(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1565,6 +1695,8 @@ ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1597,6 +1729,7 @@ ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* throw the ckt block flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); /* set the channel to suspended state */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -1615,6 +1748,8 @@ ftdm_status_t handle_blo_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1656,6 +1791,8 @@ ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1744,6 +1881,8 @@ ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1784,6 +1923,7 @@ ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ default: /* set the state of the channel to restart...the rest is done by the chan monitor */ + sngss7_set_ckt_flag(sngss7_info, FLAG_REMOTE_REL); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; /**************************************************************************/ @@ -1803,6 +1943,8 @@ ftdm_status_t handle_local_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1861,6 +2003,8 @@ ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -1917,7 +2061,7 @@ ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX_RSP); /* go to DOWN */ - /*ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);*/ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; /**********************************************************************/ @@ -1951,6 +2095,8 @@ ftdm_status_t handle_grs_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_channel_t *ftdmchan = NULL; sngss7_span_data_t *sngss7_span = NULL; int range = 0; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2008,6 +2154,8 @@ ftdm_status_t handle_grs_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_channel_t *ftdmchan = NULL; sngss7_span_data_t *sngss7_span = NULL; int range = 0; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2072,6 +2220,8 @@ ftdm_status_t handle_local_blk(uint32_t suInstId, uint32_t spInstId, uint32_t ci sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2122,6 +2272,8 @@ ftdm_status_t handle_local_ubl(uint32_t suInstId, uint32_t spInstId, uint32_t ci sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2177,6 +2329,7 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit sngss7_span_data_t *sngss7_span = NULL; ftdm_channel_t *ftdmchan = NULL; + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { @@ -2215,6 +2368,8 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit cinfo->ucic.range = cinfo->tx_grs.range; ftdm_set_flag(sngss7_span, SNGSS7_UCIC_PENDING); + SS7_WARN("Set span SNGSS7_UCIC_PENDING for ISUP circuit = %d!\n", circuit); + ftdm_channel_unlock(fchan); goto done; @@ -2227,6 +2382,7 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit ftdm_mutex_lock(ftdmchan->mutex); /* throw the ckt block flag */ + SS7_DEBUG("Set FLAG_CKT_UCIC_BLOCK for ISUP circuit = %d!\n", circuit); sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK); /* set the channel to suspended state */ @@ -2256,7 +2412,10 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ int blockType = 0; int byte = 0; int bit = 0; - int x; + int x; + int loop_range=0; + + ftdm_running_return(FTDM_FAIL); memset(&status[0], '\0', sizeof(status)); @@ -2321,61 +2480,56 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } /* loop over the cics starting from circuit until range+1 */ - for (x = circuit; x < (circuit + range + 1); x++) { - /* confirm this is a voice channel */ - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) continue; - - /* grab the circuit in question */ - if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); - break; + loop_range = circuit + range + 1; + x = circuit; + while( x < loop_range ) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) { + loop_range++; } - - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); + else { + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + } else { + ftdm_mutex_lock(ftdmchan->mutex); + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } + } -#if 0 - SS7_ERROR("KONRAD -> circuit=%d, byte=%d, bit=%d, status[byte]=%d, math=%d\n", - x, - byte, - bit, - status[byte], - (status[byte] & (1 << bit))); -#endif - if (status[byte] & (1 << bit)) { - switch (blockType) { - /**********************************************************************/ - case 0: /* maintenance oriented */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); - break; - /**********************************************************************/ - case 1: /* hardware failure oriented */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); - break; - /**********************************************************************/ - case 2: /* reserved for national use */ - break; - /**********************************************************************/ - default: - break; - /**********************************************************************/ - } /* switch (blockType) */ + /* bring the sig status down */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + } } + x++; + } - /* bring the sig status down */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - - /* update the bit and byte counter*/ - bit ++; - if (bit == 8) { - byte++; - bit = 0; - } - - } /* for (x = circuit; x < (circuit + range + 1); x++) */ /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -2402,8 +2556,11 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ int blockType = 0; int byte = 0; int bit = 0; - int x; + int x; + int loop_range=0; ftdm_sigmsg_t sigev; + + ftdm_running_return(FTDM_FAIL); memset(&sigev, 0, sizeof (sigev)); memset(&status[0], '\0', sizeof(status)); @@ -2470,57 +2627,62 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ } /* loop over the cics starting from circuit until range+1 */ - for (x = circuit; x < (circuit + range + 1); x++) { - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) continue; - /* grab the circuit in question */ - if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); - break; + loop_range = circuit + range + 1; + x = circuit; + while( x < loop_range ) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) { + loop_range++; + } else { + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + } + else { + ftdm_mutex_lock(ftdmchan->mutex); + + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } /* switch (blockType) */ + } /* if (status[byte] & (1 << bit)) */ + + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + + /* bring the sig status down */ + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + } } - - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); - - if (status[byte] & (1 << bit)) { - switch (blockType) { - /**********************************************************************/ - case 0: /* maintenance oriented */ - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); - break; - /**********************************************************************/ - case 1: /* hardware failure oriented */ - sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); - break; - /**********************************************************************/ - case 2: /* reserved for national use */ - break; - /**********************************************************************/ - default: - break; - /**********************************************************************/ - } /* switch (blockType) */ - } /* if (status[byte] & (1 << bit)) */ - - sigev.chan_id = ftdmchan->chan_id; - sigev.span_id = ftdmchan->span_id; - sigev.channel = ftdmchan; - - /* bring the sig status down */ - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - - /* update the bit and byte counter*/ - bit ++; - if (bit == 8) { - byte++; - bit = 0; - } - - } /* for (x = circuit; x < (circuit + range + 1); x++) */ + x++; + } /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -2541,6 +2703,8 @@ ftdm_status_t handle_olm_msg(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + + ftdm_running_return(FTDM_FAIL); /* confirm that the circuit is voice channel */ if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].type != SNG_CKT_VOICE) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c index b13c98b1e6..92931c4b8d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c @@ -81,6 +81,7 @@ void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCo /* initalize the sngss7_event */ sngss7_event = ftdm_malloc(sizeof(*sngss7_event)); + if (sngss7_event == NULL) { SS7_ERROR("Failed to allocate memory for sngss7_event!\n"); SS7_FUNC_TRACE_EXIT(__FUNCTION__); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index cdedf791ce..6d87738ceb 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -114,6 +114,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) { char buf[50]; int x = 1; + int log_level = FTDM_LOG_LEVEL_DEBUG; memset(buf, '\0', sizeof(buf)); @@ -158,11 +159,22 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) break; case (LCM_CAUSE_UNKNOWN): default: - ftdm_log(FTDM_LOG_DEBUG,"[MTP2]%s cause:%s event:%s\n", - buf, - DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), - DECODE_LSD_EVENT(sta->t.usta.alarm.event)); - break; + { + if ((LSD_EVENT_ALIGN_LOST == sta->t.usta.alarm.event) || + (LSD_EVENT_PROT_ST_DN == sta->t.usta.alarm.event)) { + log_level = FTDM_LOG_LEVEL_WARNING; + } else if ((LSD_EVENT_LINK_ALIGNED == sta->t.usta.alarm.event) || + (LSD_EVENT_PROT_ST_UP == sta->t.usta.alarm.event)){ + log_level = FTDM_LOG_LEVEL_INFO; + } else { + log_level = FTDM_LOG_LEVEL_WARNING; + } + ftdm_log(FTDM_PRE, log_level,"[MTP2]%s cause:%s event:%s\n", + buf, + DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), + DECODE_LSD_EVENT(sta->t.usta.alarm.event)); + break; + } /******************************************************************/ } /* switch (sta->t.usta.alarm.cause) */ break; @@ -184,7 +196,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : %s\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_LSD_CAUSE(sta->t.usta.alarm.cause)); @@ -207,7 +219,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_DEBUG,"[MTP2]%s %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : %s\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_DISC_REASON(sta->t.usta.evntParm[1])); @@ -231,7 +243,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : RTB Queue Len(%d)|Oldest BSN(%d)|Tx Queue Len(%d)|Outstanding Frames(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : RTB Queue Len(%d)|Oldest BSN(%d)|Tx Queue Len(%d)|Outstanding Frames(%d)\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.evntParm[1], @@ -257,7 +269,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : RTB Queue Len(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : RTB Queue Len(%d)\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.evntParm[1]); @@ -280,7 +292,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtp2Link[x].name); } - ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2]%s %s : %d\n", buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_DISC_REASON(sta->t.usta.evntParm[1])); @@ -288,7 +300,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) /**********************************************************************/ case (LCM_EVENT_UI_INV_EVT): case (LCM_EVENT_LI_INV_EVT): - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s(%d) : %s(%d) : Primitive (%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s(%d) : %s(%d) : Primitive (%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), @@ -302,14 +314,14 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) /******************************************************************/ case (LCM_CAUSE_UNKNOWN): case (LCM_CAUSE_SWVER_NAVAIL): - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s : %s : Event (%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s : %s : Event (%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), sta->t.usta.evntParm[0]); break; /******************************************************************/ case (LCM_CAUSE_DECODE_ERR): - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s : %s : Primitive (%d)|Version (%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s : %s : Primitive (%d)|Version (%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_LCM_CAUSE(sta->t.usta.alarm.cause), sta->t.usta.evntParm[0], @@ -317,7 +329,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) break; /******************************************************************/ default: - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s(%d) : %s(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s(%d) : %s(%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, DECODE_LSD_CAUSE(sta->t.usta.alarm.cause), @@ -328,7 +340,7 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) break; /**********************************************************************/ default: - ftdm_log(FTDM_LOG_ERROR,"[MTP2] %s(%d) : %s(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP2] %s(%d) : %s(%d)\n", DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, DECODE_LSD_CAUSE(sta->t.usta.alarm.cause), @@ -381,7 +393,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) /**********************************************************************/ case (LSN_EVENT_INV_OPC_OTHER_END): - ftdm_log(FTDM_LOG_ERROR,"[MTP3]%s %s : %s : OPC(0x%X%X%X%X)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3]%s %s : %s : OPC(0x%X%X%X%X)\n", buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), DECODE_LSN_CAUSE(sta->t.usta.alarm.cause), @@ -392,7 +404,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**********************************************************************/ case (LSN_EVENT_INV_SLC_OTHER_END): - ftdm_log(FTDM_LOG_ERROR,"[MTP3]%s %s : %s : SLC(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3]%s %s : %s : SLC(%d)\n", buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), DECODE_LSN_CAUSE(sta->t.usta.alarm.cause), @@ -400,7 +412,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**********************************************************************/ default: - ftdm_log(FTDM_LOG_DEBUG,"[MTP3]%s %s(%d) : %s(%d)\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3]%s %s(%d) : %s(%d)\n", buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, @@ -412,7 +424,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**************************************************************************/ case (STNSAP): - ftdm_log(FTDM_LOG_ERROR,"[MTP3][SAPID:%d] %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3][SAPID:%d] %s : %s\n", sta->hdr.elmId.elmntInst1, DECODE_LSN_EVENT(sta->t.usta.alarm.event), DECODE_LSN_CAUSE(sta->t.usta.alarm.cause)); @@ -463,7 +475,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**********************************************************************/ default: - ftdm_log(FTDM_LOG_ERROR,"[MTP3][DPC:0x%X%X%X%X] %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"[MTP3][DPC:0x%X%X%X%X] %s : %s\n", sta->t.usta.evntParm[0], sta->t.usta.evntParm[1], sta->t.usta.evntParm[2], @@ -733,7 +745,7 @@ void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta) } /* switch (sta->t.usta.dgn.dgnVal[x].t.type) */ } /* for (x = 0; x < 5; x++) */ - ftdm_log(FTDM_LOG_ERROR,"%s %s : %s\n", + ftdm_log(FTDM_LOG_WARNING,"%s %s : %s\n", msg, DECODE_LSI_EVENT(sta->t.usta.alarm.event), DECODE_LSI_CAUSE(sta->t.usta.alarm.cause)); @@ -759,7 +771,7 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) switch (sta->hdr.elmId.elmnt) { /**************************************************************************/ case (LRY_USTA_ERR): /* ERROR */ - ftdm_log(FTDM_LOG_ERROR,"[RELAY] Error: tx procId %d: err procId %d: channel %d: seq %s: reason %s\n", + ftdm_log(FTDM_LOG_WARNING,"[RELAY] Error: tx procId %d: err procId %d: channel %d: seq %s: reason %s\n", sta->t.usta.s.ryErrUsta.sendPid, sta->t.usta.s.ryErrUsta.errPid, sta->t.usta.s.ryErrUsta.id, @@ -783,7 +795,7 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ case (LRY_USTA_CNG): /* Congestion */ - ftdm_log(FTDM_LOG_ERROR,"[RELAY] Congestion: tx procId %d: rem procId %d: channel %d: %s\n", + ftdm_log(FTDM_LOG_WARNING,"[RELAY] Congestion: tx procId %d: rem procId %d: channel %d: %s\n", sta->t.usta.s.ryCongUsta.sendPid, sta->t.usta.s.ryCongUsta.remPid, sta->t.usta.s.ryCongUsta.id, @@ -791,7 +803,7 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ case (LRY_USTA_UP): /* channel up */ - ftdm_log(FTDM_LOG_ERROR,"[RELAY] Channel UP: tx procId %d: channel %d\n", + ftdm_log(FTDM_LOG_INFO,"[RELAY] Channel UP: tx procId %d: channel %d\n", sta->t.usta.s.ryUpUsta.sendPid, sta->t.usta.s.ryUpUsta.id); @@ -801,7 +813,7 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ case (LRY_USTA_DN): /* channel down */ - ftdm_log(FTDM_LOG_ERROR,"[RELAY] Channel DOWN: tx procId %d: channel %d\n", + ftdm_log(FTDM_LOG_WARNING,"[RELAY] Channel DOWN: tx procId %d: channel %d\n", sta->t.usta.s.ryUpUsta.sendPid, sta->t.usta.s.ryUpUsta.id); @@ -810,6 +822,11 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) break; /**************************************************************************/ + case (LRY_USTA_TCP_CONN_FAILED): + ftdm_log(FTDM_LOG_WARNING,"[RELAY] TCP connection failed \n" ); + + break; + /**************************************************************************/ default: ftdm_log(FTDM_LOG_ERROR,"Unknown Relay Alram\n"); break; @@ -819,6 +836,311 @@ void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta) return; } +/******************************************************************************/ +void handle_sng_m2ua_alarm(Pst *pst, MwMgmt *sta) +{ + /* To print the general information */ + ftdm_log(FTDM_LOG_INFO, "Recieved a status indication from M2UA layer \n\n"); + ftdm_log(FTDM_LOG_INFO," Category = %d , event = %d , cause = %d\n", + sta->t.usta.alarm.category, sta->t.usta.alarm.event, sta->t.usta.alarm.cause); + + + /* To print the affected element value */ + switch(sta->hdr.elmId.elmnt) + { + case STMWDLSAP: + { + ftdm_log(FTDM_LOG_INFO," STMWDLSAP: with lnkNmb (%d) \n\n", + sta->t.usta.s.lnkNmb); + break; + } + case STMWSCTSAP: + { + ftdm_log(FTDM_LOG_INFO," STMWSCTSAP: suId (%d) \n\n", + sta->t.usta.s.suId); + break; + } + case STMWPEER: + { + ftdm_log(FTDM_LOG_INFO," STMWPEER: peerId (%d) \n\n", + sta->t.usta.s.peerId); + break; + } + case STMWCLUSTER: + { + ftdm_log(FTDM_LOG_INFO," STMWCLUSTER: clusterId (%d) \n\n", + sta->t.usta.s.peerId); + break; + } + default: + { + ftdm_log(FTDM_LOG_ERROR, "[MW_USTA]: Invalid element \n\n"); + break; + } + } + + /* To print the event specific information */ + switch(sta->t.usta.alarm.event) + { + case LMW_EVENT_TERM_OK: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_TERM_OK: Association Terminated with PeerId[%d] \n",sta->t.usta.s.peerId); + break; + } + case LMW_EVENT_ENDPOPEN_OK: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ENDPOPEN_OK: \n"); + break; + } + case LMW_EVENT_ESTABLISH_OK: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ESTABLISH_OK Event raised on peerId[%d]\n",sta->t.usta.s.peerId); + break; + } + case LMW_EVENT_ESTABLISH_FAIL: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ESTABLISH_FAIL Event raised on peerId[%d]\n",sta->t.usta.s.peerId); + break; + } + case LMW_EVENT_ASPM: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_ASPM Event raised with peerId (%d), aspId (%d)," + " msgType (%d)\n\n",sta->t.usta.s.peerId, + sta->t.usta.t.aspm.msgType); + break; + } + case LMW_EVENT_CLUSTER: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_CLUSTER Event raised on clusterId (%d), state (%d)\n\n", + sta->t.usta.s.clusterId, sta->t.usta.t.cluster.state); + + break; + } + case LMW_EVENT_NOTIFY: + { + ftdm_log(FTDM_LOG_INFO," M2UA : LMW_EVENT_NOTIFY: peerId (%d), aspId (%d), ntfy status type (%d)," + " ntfy status id (%d)\n\n", sta->t.usta.s.peerId, + sta->t.usta.t.ntfy.aspId, sta->t.usta.t.ntfy.stType, + sta->t.usta.t.ntfy.stId); + + break; + } + + + case LMW_EVENT_M2UA_PROTO_ERROR: + { + ftdm_log(FTDM_LOG_ERROR, " M2UA : LMW_EVENT_M2UA_PROTO_ERROR with errorCode (%d)\n\n", + sta->t.usta.t.error.errCode); + break; + } + default: + break; + } + +} /* handle_sng_m2ua_alarm */ + +/******************************************************************************/ +void handle_sng_nif_alarm(Pst *pst, NwMgmt *sta) +{ + /* To print the general information */ + ftdm_log(FTDM_LOG_INFO," Recieved a status indication from NIF layer\n"); + ftdm_log(FTDM_LOG_INFO," Category = %d , event = %d , cause = %d\n", sta->t.usta.alarm.category, + sta->t.usta.alarm.event, sta->t.usta.alarm.cause); + + switch(sta->hdr.elmId.elmnt) + { + case STNWDLSAP: + { + ftdm_log(FTDM_LOG_INFO," Recieved STNWDLSAP status indication for suId (%d) \n", sta->t.usta.suId); + switch(sta->t.usta.alarm.event) + { + case LCM_EVENT_LI_INV_EVT: + { + switch(sta->t.usta.alarm.cause) + { + case LCM_CAUSE_INV_SAP: + { + ftdm_log(FTDM_LOG_ERROR, " LCM_CAUSE_INV_SAP Alarm \n"); + break; + } + case LCM_CAUSE_INV_STATE: + { + ftdm_log(FTDM_LOG_ERROR, " LCM_CAUSE_INV_STATE Alarm \n"); + break; + } + default: + break; + } + break; + } + case LCM_EVENT_BND_OK: + { + ftdm_log(FTDM_LOG_INFO," NIF: LCM_EVENT_BND_OK Alarm \n"); + break; + } + case LCM_EVENT_BND_FAIL: + { + ftdm_log(FTDM_LOG_INFO," NIF: LCM_EVENT_BND_FAIL Alarm \n"); + break; + } + default: + break; + } + break; + } + default: + break; + } +} /* handle_sng_nif_alarm */ + +/******************************************************************************/ +void handle_sng_tucl_alarm(Pst *pst, HiMngmt *sta) +{ + /* To print the general information */ + ftdm_log(FTDM_LOG_INFO, "Recieved a status indication from TUCL layer \n\n"); + ftdm_log(FTDM_LOG_INFO, " Category = %d , event = %d , cause = %d\n", + sta->t.usta.alarm.category, + sta->t.usta.alarm.event, sta->t.usta.alarm.cause); + + switch(sta->t.usta.alarm.event) + { + case LCM_EVENT_INV_EVT: + { + ftdm_log(FTDM_LOG_INFO," [HI_USTA]: LCM_EVENT_INV_EVT with type (%d)\n\n", + sta->t.usta.info.type); + break; + } + case LHI_EVENT_BNDREQ: + { + ftdm_log(FTDM_LOG_INFO," [HI_USTA]: LHI_EVENT_BNDREQ with type (%d) spId (%d)\n\n", + sta->t.usta.info.type, sta->t.usta.info.spId); + break; + } + case LHI_EVENT_SERVOPENREQ: + case LHI_EVENT_DATREQ: + case LHI_EVENT_UDATREQ: + case LHI_EVENT_CONREQ: + case LHI_EVENT_DISCREQ: +#if(defined(HI_TLS) && defined(HI_TCP_TLS)) + case LHI_EVENT_TLS_ESTREQ: +#endif + { + ftdm_log(FTDM_LOG_INFO," [HI_USTA]: partype (%d) type(%d)\n\n", + sta->t.usta.info.inf.parType, sta->t.usta.info.type); + break; + } + case LCM_EVENT_DMEM_ALLOC_FAIL: + case LCM_EVENT_SMEM_ALLOC_FAIL: + { + ftdm_log(FTDM_LOG_ERROR," [HI_USTA]: MEM_ALLOC_FAIL with region(%d) pool (%d) type(%d)\n\n", + sta->t.usta.info.inf.mem.region, sta->t.usta.info.inf.mem.pool, + sta->t.usta.info.type); + break; + } + default: + break; + } + +} /* handle_sng_tucl_alarm */ + +/******************************************************************************/ +void handle_sng_sctp_alarm(Pst *pst, SbMgmt *sta) +{ + ftdm_log(FTDM_LOG_INFO, "Recieved a status indication from SCTP layer \n\n"); + ftdm_log(FTDM_LOG_INFO," Category = %d , event = %d , cause = %d " + " [SB_USTA]: sapId (%d) and swtch (%d)\n", + sta->t.usta.alarm.category, + sta->t.usta.alarm.event, sta->t.usta.alarm.cause, + sta->t.usta.sapId, sta->t.usta.swtch); + + switch(sta->t.usta.alarm.category) + { + case LCM_CATEGORY_INTERFACE: + { + switch(sta->t.usta.alarm.cause) + { + case LCM_CAUSE_INV_SPID: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_INV_SPID Alarm \n"); + break; + } + case LCM_CAUSE_SWVER_NAVAIL: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_SWVER_NAVAIL Alarm\n"); + break; + } + case LCM_CAUSE_INV_PAR_VAL: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_INV_PAR_VAL Alarm\n"); + break; + } + case LCM_CAUSE_INV_SUID: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_INV_SUID Alarm\n"); + break; + } + case LCM_CAUSE_INV_SAP: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_INV_SAP Alarm\n"); + break; + } + default: + break; + } + + break; + } + case LCM_CATEGORY_RESOURCE: + { + switch(sta->t.usta.alarm.cause) + { + case LCM_CAUSE_MEM_ALLOC_FAIL: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LCM_CAUSE_MEM_ALLOC_FAIL Alarm \n"); + break; + } + case LSB_CAUSE_NUM_ADDR_EXCEED: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LSB_CAUSE_NUM_ADDR_EXCEED Alarm\n"); + break; + } + default: + break; + } + break; + } + case LCM_CATEGORY_PROTOCOL: + { + switch(sta->t.usta.alarm.cause) + { + case LSB_CAUSE_PATH_FAILURE: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LSB_CAUSE_PATH_FAILURE Alarm \n"); + break; + } + case LSB_CAUSE_PATH_ACTIVE: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LSB_CAUSE_PATH_ACTIVE Alarm \n"); + break; + } + case LSB_CAUSE_UNRSLVD_ADDR: + { + ftdm_log(FTDM_LOG_ERROR, "SCTP : LSB_CAUSE_UNRSLVD_ADDR Alarm \n"); + break; + } + default: + break; + } + break; + } + default: + break; + } + +} /* handle_sng_sctp_alarm */ +/******************************************************************************/ + + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c new file mode 100644 index 0000000000..810c5a2902 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c @@ -0,0 +1,1773 @@ +/* + * Copyright (c) 2012, Kapil Gupta + * 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. + * + * + * Contributors: + * + * + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ +/* FUNCTION PROTOTYPES ********************************************************/ +static int ftmod_tucl_gen_config(void); +static int ftmod_tucl_sap_config(int id); +static int ftmod_sctp_gen_config(void); +static int ftmod_cfg_sctp(void); +static int ftmod_sctp_config(int id); +static ftdm_status_t ftmod_sctp_sap_config(int id); +static ftdm_status_t ftmod_sctp_tsap_config(int id); +static int ftmod_m2ua_gen_config(void); +static int ftmod_m2ua_sctsap_config(int sct_sap_id, int sctp_id); +static int ftmod_m2ua_peer_config(int id); +static int ftmod_m2ua_peer_config1(int m2ua_inf_id, int peer_id); +static int ftmod_m2ua_cluster_config(int idx); +static int ftmod_m2ua_dlsap_config(int idx); +static int ftmod_nif_gen_config(void); +static int ftmod_nif_dlsap_config(int idx); +static int ftmod_sctp_tucl_tsap_bind(int idx); +static int ftmod_m2ua_sctp_sctsap_bind(int idx); +static int ftmod_open_endpoint(int idx); +static int ftmod_init_sctp_assoc(int peer_id); +static int ftmod_nif_m2ua_dlsap_bind(int id); +static int ftmod_nif_mtp2_dlsap_bind(int id); +static int ftmod_m2ua_debug(int action); +static int ftmod_tucl_debug(int action); +static int ftmod_sctp_debug(int action); + +static int ftmod_ss7_sctp_shutdown(void); +static int ftmod_ss7_m2ua_shutdown(void); +static int ftmod_ss7_tucl_shutdown(void); + + +/******************************************************************************/ +ftdm_status_t ftmod_ss7_m2ua_init(void) +{ + /****************************************************************************************************/ + if (sng_isup_init_nif()) { + ftdm_log (FTDM_LOG_ERROR , "Failed to start NIF\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"Started NIF!\n"); + } + /****************************************************************************************************/ + + if (sng_isup_init_m2ua()) { + ftdm_log (FTDM_LOG_ERROR ,"Failed to start M2UA\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"Started M2UA!\n"); + } + /****************************************************************************************************/ + + if (sng_isup_init_sctp()) { + ftdm_log (FTDM_LOG_ERROR ,"Failed to start SCTP\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"Started SCTP!\n"); + } + /****************************************************************************************************/ + + if (sng_isup_init_tucl()) { + ftdm_log (FTDM_LOG_ERROR ,"Failed to start TUCL\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"Started TUCL!\n"); + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_TUCL_PRESENT); + } + /****************************************************************************************************/ + + if(ftmod_tucl_gen_config()){ + ftdm_log (FTDM_LOG_ERROR ,"TUCL GEN configuration: NOT OK\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"TUCL GEN configuration: OK\n"); + } + /****************************************************************************************************/ + if(ftmod_sctp_gen_config()){ + ftdm_log (FTDM_LOG_ERROR ,"SCTP GEN configuration: NOT OK\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"SCTP GEN configuration: OK\n"); + } + /****************************************************************************************************/ + if(ftmod_m2ua_gen_config()) { + ftdm_log (FTDM_LOG_ERROR ,"M2UA General configuration: NOT OK\n"); + return FTDM_FAIL; + }else { + ftdm_log (FTDM_LOG_INFO ,"M2UA General configuration: OK\n"); + } + /****************************************************************************************************/ + if(ftmod_nif_gen_config()){ + ftdm_log (FTDM_LOG_ERROR ,"NIF General configuration: NOT OK\n"); + return FTDM_FAIL; + }else { + ftdm_log (FTDM_LOG_INFO ,"NIF General configuration: OK\n"); + } + /****************************************************************************************************/ + + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +void ftmod_ss7_m2ua_free() +{ + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_M2UA_PRESENT)) { + ftmod_ss7_m2ua_shutdown(); + sng_isup_free_m2ua(); + } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SCTP_PRESENT)) { + ftmod_ss7_sctp_shutdown(); + sng_isup_free_sctp(); + } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_TUCL_PRESENT)) { + ftmod_ss7_tucl_shutdown(); + sng_isup_free_tucl(); + } +} + +/******************************************************************************/ +static int ftmod_ss7_tucl_shutdown() +{ + Pst pst; + HiMngmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(HiMngmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTHI; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTHI; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ASHUTDOWN; + + return (sng_cntrl_tucl (&pst, &cntrl)); +} +/******************************************************************************/ +static int ftmod_ss7_m2ua_shutdown() +{ + Pst pst; + MwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ASHUTDOWN; + + return (sng_cntrl_m2ua (&pst, &cntrl)); +} +/***********************************************************************************************************************/ +static int ftmod_ss7_sctp_shutdown() +{ + Pst pst; + SbMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(SbMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTSB; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTSB; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STSBGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ASHUTDOWN; + + return (sng_cntrl_sctp (&pst, &cntrl)); +} + +/******************************************************************************/ + + + +ftdm_status_t ftmod_ss7_m2ua_cfg(void) +{ + int x=0; + + /* SCTP configuration */ + if(ftmod_cfg_sctp()){ + ftdm_log (FTDM_LOG_ERROR ,"SCTP Configuration : NOT OK\n"); + return FTDM_FAIL; + } else { + ftdm_log (FTDM_LOG_INFO ,"SCTP Configuration : OK\n"); + } + + /****************************************************************************************************/ + /* M2UA SCTP SAP configurations */ + x = 1; + while(xspId = k->id ; /* each SCTP link there will be one tucl sap */ + pCfg->uiSel = 0x00; /*loosley coupled */ + pCfg->flcEnb = TRUE; + pCfg->txqCongStrtLim = HI_SAP_TXN_QUEUE_CONG_START_LIMIT; + pCfg->txqCongDropLim = HI_SAP_TXN_QUEUE_CONG_DROP_LIMIT; + pCfg->txqCongStopLim = HI_SAP_TXN_QUEUE_CONG_STOP_LIMIT; + pCfg->numBins = 10; + + pCfg->uiMemId.region = S_REG; + pCfg->uiMemId.pool = S_POOL; + pCfg->uiPrior = PRIOR0; + pCfg->uiRoute = RTESPEC; + + return(sng_cfg_tucl(&pst, &cfg)); +} + +/****************************************************************************************************/ + +static int ftmod_sctp_gen_config(void) +{ + SbMgmt cfg; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSB; + + /* clear the configuration structure */ + memset(&cfg, 0, sizeof(cfg)); + + /* fill in the post structure */ + smPstInit(&cfg.t.cfg.s.genCfg.smPst); + /*fill in the specific fields of the header */ + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTSB; + cfg.hdr.entId.inst = S_INST; + cfg.hdr.elmId.elmnt = STSBGEN; + +#ifdef SB_IPV6_SUPPORTED + /* U8 ipv6SrvcReqdFlg; */ /* IPV6 service required for sctp */ +#endif + + cfg.t.cfg.s.genCfg.serviceType = HI_SRVC_RAW_SCTP; /* Usr packetized TCP Data */ /* TUCL transport protocol (IP/UDP) */ + cfg.t.cfg.s.genCfg.maxNmbSctSaps = SB_MAX_SCT_SAPS; /* max no. SCT SAPS */ + cfg.t.cfg.s.genCfg.maxNmbTSaps = SB_MAX_T_SAPS; /* max no. Transport SAPS */ + cfg.t.cfg.s.genCfg.maxNmbEndp = SB_MAX_NUM_OF_ENDPOINTS; /* max no. endpoints */ + cfg.t.cfg.s.genCfg.maxNmbAssoc = SB_MAX_NUM_OF_ASSOC; /* max no. associations */ + cfg.t.cfg.s.genCfg.maxNmbDstAddr = SB_MAX_NUM_OF_DST_ADDR; /* max no. dest. addresses */ + cfg.t.cfg.s.genCfg.maxNmbSrcAddr = SB_MAX_NUM_OF_SRC_ADDR; /* max no. src. addresses */ + cfg.t.cfg.s.genCfg.maxNmbTxChunks = SB_MAX_NUM_OF_TX_CHUNKS; + cfg.t.cfg.s.genCfg.maxNmbRxChunks = SB_MAX_NUM_OF_RX_CHUNKS; + cfg.t.cfg.s.genCfg.maxNmbInStrms = SB_MAX_INC_STREAMS; + cfg.t.cfg.s.genCfg.maxNmbOutStrms = SB_MAX_OUT_STREAMS; + cfg.t.cfg.s.genCfg.initARwnd = SB_MAX_RWND_SIZE; + cfg.t.cfg.s.genCfg.mtuInitial = SB_MTU_INITIAL; + cfg.t.cfg.s.genCfg.mtuMinInitial = SB_MTU_MIN_INITIAL; + cfg.t.cfg.s.genCfg.mtuMaxInitial = SB_MTU_MAX_INITIAL; + cfg.t.cfg.s.genCfg.performMtu = FALSE; + cfg.t.cfg.s.genCfg.timeRes = 1; + sprintf((char*)cfg.t.cfg.s.genCfg.hostname, "www.sangoma.com"); /* DAVIDY - Fix this later, probably ignored */ + cfg.t.cfg.s.genCfg.useHstName = FALSE; /* Flag whether hostname is to be used in INIT and INITACK msg */ + cfg.t.cfg.s.genCfg.reConfig.maxInitReTx = 8; + cfg.t.cfg.s.genCfg.reConfig.maxAssocReTx = 10; + cfg.t.cfg.s.genCfg.reConfig.maxPathReTx = 10; + cfg.t.cfg.s.genCfg.reConfig.altAcceptFlg = TRUE; + cfg.t.cfg.s.genCfg.reConfig.keyTm = 600; /* initial value for MD5 Key expiry timer */ + cfg.t.cfg.s.genCfg.reConfig.alpha = 12; + cfg.t.cfg.s.genCfg.reConfig.beta = 25; +#ifdef SB_ECN + cfg.t.cfg.s.genCfg.reConfig.ecnFlg = TRUE; +#endif + + return(sng_cfg_sctp(&pst, &cfg)); +} + +/****************************************************************************************************/ +static int ftmod_cfg_sctp(void) +{ + int x=0; + + x = 1; + while(xid; + + c = &cfg.t.cfg.s.tSapCfg; + c->swtch = LSB_SW_RFC_REL0; + c->suId = k->id; + c->sel = 0; + c->ent = ENTHI; + c->inst = S_INST; + c->procId = g_ftdm_sngss7_data.cfg.procId; + c->memId.region = S_REG; + c->memId.pool = S_POOL; + c->prior = PRIOR1; + c->route = RTESPEC; + c->srcNAddrLst.nmb = k->numSrcAddr; + for (i=0; i <= (k->numSrcAddr-1); i++) { + c->srcNAddrLst.nAddr[i].type = CM_NETADDR_IPV4; + c->srcNAddrLst.nAddr[i].u.ipv4NetAddr = k->srcAddrList[i+1]; + } + + c->reConfig.spId = k->id; + c->reConfig.maxBndRetry = 3; + c->reConfig.tIntTmr = 200; + + ret = sng_cfg_sctp(&pst, &cfg); + if (0 == ret) { + SS7_INFO("SCTP TSAP [%d] configuration DONE!\n", id); + return FTDM_SUCCESS; + } else { + SS7_CRITICAL("SCTP TSAP [%d] configuration FAILED!\n", id); + return FTDM_FAIL; + } +} + +/****************************************************************************************************/ + +ftdm_status_t ftmod_sctp_sap_config(int id) +{ + Pst pst; + SbMgmt cfg; + SbSctSapCfg *c; + + int ret = -1; + sng_sctp_link_t *k = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[id]; + + smPstInit(&pst); + pst.dstEnt = ENTSB; + + memset(&cfg, 0x0, sizeof(cfg)); + smHdrInit(&cfg.hdr); + + cfg.hdr.msgType = TCFG; + cfg.hdr.entId.ent = ENTSB; + cfg.hdr.entId.inst = S_INST; + cfg.hdr.elmId.elmnt = STSBSCTSAP; + cfg.hdr.elmId.elmntInst1 = k->id; + + c = &cfg.t.cfg.s.sctSapCfg; + c->swtch = LSB_SW_RFC_REL0; + c->spId = k->id; /* Service Provider SAP Id */ + c->sel = 0; + c->memId.region = S_REG; + c->memId.pool = S_POOL; + c->prior = PRIOR1; + c->route = RTESPEC; + + /* Maximum time to wait before the SCTP layer must send a Selective Acknowledgement (SACK) message. Valid range is 1 -165535. */ + c->reConfig.maxAckDelayTm = 200; + /* Maximum number of messages to receive before the SCTP layer must send a SACK message. Valid range is 1 - 165535. */ + c->reConfig.maxAckDelayDg = 2; + /* Initial value of the retransmission timer (RTO). The SCTP layer retransmits data after waiting for feedback during this time period. Valid range is 1 - 65535. */ + c->reConfig.rtoInitial = 3000; + /* Minimum value used for the RTO. If the computed value of RTO is less than rtoMin, the computed value is rounded up to this value. */ + c->reConfig.rtoMin = 1000; + /* Maxiumum value used for RTO. If the computed value of RTO is greater than rtoMax, the computed value is rounded down to this value. */ + c->reConfig.rtoMax = 10000; + /* Default Freeze timer value */ + c->reConfig.freezeTm = 3000; + /* Base cookie lifetime for the cookie in the Initiation Acknowledgement (INIT ACK) message. */ + c->reConfig.cookieLife = 60000; + /* Default heartbeat interval timer. Valid range is 1 - 65535. */ + c->reConfig.intervalTm = 3000; + /* Maximum burst value. Valid range is 1 - 65535. */ + c->reConfig.maxBurst = 4; + /*Maximum number of heartbeats sent at each retransmission timeout (RTO). Valid range is 1 - 65535. */ + c->reConfig.maxHbBurst = 1; + /*Shutdown guard timer value for graceful shutdowns. */ + c->reConfig.t5SdownGrdTm = 15000; + /* Action to take when the receiver's number of incoming streams is less than the sender's number of outgoing streams. Valid values are: + TRUE = Accept incoming stream and continue association. + FALSE = Abort the association. + */ + c->reConfig.negAbrtFlg = FALSE; + /* Whether to enable or disable heartbeat by default. Valid values are: + TRUE = Enable heartbeat. + FALSE = Disable heartbeat. + */ + c->reConfig.hBeatEnable = TRUE; + /* Flow control start threshold. When the number of messages in SCTP’s message queue reaches this value, flow control starts. */ + c->reConfig.flcUpThr = 8; + /* Flow control stop threshold. When the number of messages in SCTP’s message queue reaches this value, flow control stops. */ + c->reConfig.flcLowThr = 6; + + c->reConfig.handleInitFlg = FALSE; + + ret = sng_cfg_sctp(&pst, &cfg); + if (0 == ret) { + SS7_INFO("SCTP SAP [%d] configuration DONE!\n", id); + return FTDM_SUCCESS; + } else { + SS7_CRITICAL("SCTP SAP [%d] configuration FAILED!\n", id); + return FTDM_FAIL; + } +} + +/**********************************************************************************************/ +/* M2UA - General configuration */ +static int ftmod_m2ua_gen_config(void) +{ + Pst pst; + MwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWGEN; /* General */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + + cfg.t.cfg.s.genCfg.nodeType = LMW_TYPE_SGP; /* NodeType == SGP or ASP */ + cfg.t.cfg.s.genCfg.maxNmbIntf = MW_MAX_NUM_OF_INTF; + cfg.t.cfg.s.genCfg.maxNmbCluster = MW_MAX_NUM_OF_CLUSTER; + cfg.t.cfg.s.genCfg.maxNmbPeer = MW_MAX_NUM_OF_PEER; + cfg.t.cfg.s.genCfg.maxNmbSctSap = MW_MAX_NUM_OF_SCT_SAPS; + cfg.t.cfg.s.genCfg.timeRes = 1; /* timer resolution */ + cfg.t.cfg.s.genCfg.maxClusterQSize = MW_MAX_CLUSTER_Q_SIZE; + cfg.t.cfg.s.genCfg.maxIntfQSize = MW_MAX_INTF_Q_SIZE; + +#ifdef LCMWMILMW + cfg.t.cfg.s.genCfg.reConfig.smPst.selector = 0; /* selector */ +#else /* LCSBMILSB */ + cfg.t.cfg.s.genCfg.reConfig.smPst.selector = 1; /* selector */ +#endif /* LCSBMILSB */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.region = S_REG; /* region */ + cfg.t.cfg.s.genCfg.reConfig.smPst.pool = S_POOL; /* pool */ + cfg.t.cfg.s.genCfg.reConfig.smPst.prior = PRIOR0; /* priority */ + cfg.t.cfg.s.genCfg.reConfig.smPst.route = RTESPEC; /* route */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.dstEnt = ENTSM; /* dst entity */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstInst = S_INST; /* dst inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstProcId = SFndProcId(); /* src proc id */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.srcEnt = ENTMW; /* src entity */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcInst = S_INST; /* src inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcProcId = SFndProcId(); /* src proc id */ + + cfg.t.cfg.s.genCfg.reConfig.tmrFlcPoll.enb = TRUE; /* SCTP Flc Poll timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrFlcPoll.val = 10; + +#ifdef MWASP + cfg.t.cfg.s.genCfg.reConfig.tmrAspm.enb = TRUE; /* ASPM timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrAspm.val = 10; + cfg.t.cfg.s.genCfg.reConfig.tmrHeartBeat.enb = TRUE; /* Heartbeat timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrHeartBeat.val = 10; +#endif + +#ifdef MWSG + cfg.t.cfg.s.genCfg.reConfig.tmrAsPend.enb = TRUE; /* AS-PENDING timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrAsPend.val = 10; + cfg.t.cfg.s.genCfg.reConfig.tmrCongPoll.enb = TRUE; /* SS7 Congestion poll timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrCongPoll.val = 10; + cfg.t.cfg.s.genCfg.reConfig.tmrHeartBeat.enb = FALSE; /* HBtimer only at ASP */ +#endif + cfg.t.cfg.s.genCfg.reConfig.aspmRetry = 5; + + return (sng_cfg_m2ua (&pst, &cfg)); +} + +/**********************************************************************************************/ +static int ftmod_m2ua_peer_config(int id) +{ + int x = 0; + int peer_id = 0; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + sng_m2ua_peer_cfg_t* peer = NULL; + + if((clust->flags & SNGSS7_CONFIGURED)){ + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config: Cluster [%s] is already configured \n", clust->name); + return 0x00; + } + + /*NOTE : SCTSAP is based on per source address , so if we have same Cluster / peer shared across many then + * we dont have do configuration for each time */ + + /* loop through peer list from cluster to configure SCTSAP */ + + for(x = 0; x < clust->numOfPeers;x++){ + peer_id = clust->peerIdLst[x]; + peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id]; + if(ftmod_m2ua_sctsap_config(id, peer->sctpId)){ + ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config FAILED \n", id); + return 0x01; + }else{ + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config SUCCESS \n", id); + } + if(ftmod_m2ua_peer_config1(id, peer_id)){ + ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer[%d] configuration for M2UA Intf Id[%d] config FAILED \n", peer_id, id); + return 0x01; + }else{ + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config1: M2UA Peer[%d] configuration for M2UA Intf Id[%d] config SUCCESS \n", peer_id, id); + } + + clust->sct_sap_id = id; + + /* set configured flag for cluster and peer */ + clust->flags |= SNGSS7_CONFIGURED; + peer->flags |= SNGSS7_CONFIGURED; + } + + return 0x0;; +} + + +static int ftmod_m2ua_sctsap_config(int sct_sap_id, int sctp_id) +{ + int i; + int ret; + Pst pst; + MwMgmt cfg; + MwMgmt cfm; + sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[sctp_id]; + + + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&cfm, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + /* check is sct_sap is already configured */ + if(!ftmod_m2ua_ssta_req(STMWSCTSAP, sct_sap_id, &cfm )){ + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: SCT SAP [%s] is already configured \n", sctp->name); + return 0x00; + } + + if(LCM_REASON_INVALID_SAP == cfm.cfm.reason){ + ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: SCT SAP [%s] is not configured..configuring now \n", sctp->name); + } + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWSCTSAP; /* SCTSAP */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + cfg.t.cfg.s.sctSapCfg.reConfig.selector = 0; + + /* service user SAP ID */ + cfg.t.cfg.s.sctSapCfg.suId = sct_sap_id; + /* service provider ID */ + cfg.t.cfg.s.sctSapCfg.spId = sctp_id; + /* source port number */ + cfg.t.cfg.s.sctSapCfg.srcPort = sctp->port; + /* interface address */ + /*For multiple IP address support */ +#ifdef SCT_ENDP_MULTI_IPADDR + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nmb = sctp->numSrcAddr; + for (i=0; i <= (sctp->numSrcAddr-1); i++) { + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[i].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.sctSapCfg.srcAddrLst.nAddr[i].u.ipv4NetAddr = sctp->srcAddrList[i+1]; + } +#else + /* for single ip support ,src address will always be one */ + cfg.t.cfg.s.sctSapCfg.intfAddr.type = CM_NETADDR_IPV4; + cfg.t.cfg.s.sctSapCfg.intfAddr.u.ipv4NetAddr = sctp->srcAddrList[1]; +#endif + + /* lower SAP primitive timer */ + cfg.t.cfg.s.sctSapCfg.reConfig.tmrPrim.enb = TRUE; + cfg.t.cfg.s.sctSapCfg.reConfig.tmrPrim.val = 10; + /* Association primitive timer */ + cfg.t.cfg.s.sctSapCfg.reConfig.tmrAssoc.enb = TRUE; + cfg.t.cfg.s.sctSapCfg.reConfig.tmrAssoc.val = 10; + /* maxnumber of retries */ + cfg.t.cfg.s.sctSapCfg.reConfig.nmbMaxPrimRetry = 5; + /* Life Time of Packets */ + cfg.t.cfg.s.sctSapCfg.reConfig.lifeTime = 200; + /* priority */ + cfg.t.cfg.s.sctSapCfg.reConfig.prior = PRIOR0; + /* route */ + cfg.t.cfg.s.sctSapCfg.reConfig.route = RTESPEC; + cfg.t.cfg.s.sctSapCfg.reConfig.ent = ENTSB; + cfg.t.cfg.s.sctSapCfg.reConfig.inst = 0; + cfg.t.cfg.s.sctSapCfg.reConfig.procId = SFndProcId(); + /* memory region and pool ID */ + cfg.t.cfg.s.sctSapCfg.reConfig.mem.region = S_REG; + cfg.t.cfg.s.sctSapCfg.reConfig.mem.pool = S_POOL; + + if (0 == (ret = sng_cfg_m2ua (&pst, &cfg))){ + sctp->flags |= SNGSS7_CONFIGURED; + } + + return ret; +} + +/****************************************************************************************************/ + +/* M2UA - Peer configuration */ +static int ftmod_m2ua_peer_config1(int m2ua_inf_id, int peer_id) +{ + int i; + Pst pst; + MwMgmt cfg; + sng_m2ua_peer_cfg_t* peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id]; + sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[peer->sctpId]; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWPEER; /* Peer */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + + cfg.t.cfg.s.peerCfg.peerId = peer->id; /* peer id */ + cfg.t.cfg.s.peerCfg.aspIdFlag = peer->aspIdFlag; /* aspId flag */ +#ifdef MWASP + cfg.t.cfg.s.peerCfg.selfAspId = peer->selfAspId; /* aspId */ +#endif + cfg.t.cfg.s.peerCfg.assocCfg.suId = peer->sctpId; /* SCTSAP ID */ + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nmb = peer->numDestAddr; + for (i=0; i <= (peer->numDestAddr); i++) { + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[i].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[i].u.ipv4NetAddr = peer->destAddrList[i]; + } +#ifdef MW_CFG_DSTPORT + cfg.t.cfg.s.peerCfg.assocCfg.dstPort = peer->port; /* Port on which M2UA runs */ +#endif + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nmb = sctp->numSrcAddr; /* source address list */ + for (i=0; i <= (sctp->numSrcAddr-1); i++) { + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[i].type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.srcAddrLst.nAddr[i].u.ipv4NetAddr = sctp->srcAddrList[i+1]; + } + + cfg.t.cfg.s.peerCfg.assocCfg.priDstAddr.type = CM_NETADDR_IPV4; + cfg.t.cfg.s.peerCfg.assocCfg.priDstAddr.u.ipv4NetAddr = cfg.t.cfg.s.peerCfg.assocCfg.dstAddrLst.nAddr[0].u.ipv4NetAddr; + + cfg.t.cfg.s.peerCfg.assocCfg.locOutStrms = peer->locOutStrms; +#ifdef SCT3 + cfg.t.cfg.s.peerCfg.assocCfg.tos = 0; +#endif + + return (sng_cfg_m2ua (&pst, &cfg)); +} +/**********************************************************************************************/ +/* M2UA - Cluster configuration */ +static int ftmod_m2ua_cluster_config(int id) +{ + int i; + Pst pst; + MwMgmt cfg; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWCLUSTER; /* Cluster */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + cfg.t.cfg.s.clusterCfg.clusterId = clust->id; + cfg.t.cfg.s.clusterCfg.trfMode = clust->trfMode; + cfg.t.cfg.s.clusterCfg.loadshareMode = clust->loadShareAlgo; + cfg.t.cfg.s.clusterCfg.reConfig.nmbPeer = clust->numOfPeers; + for(i=0; i<(clust->numOfPeers);i++) { + cfg.t.cfg.s.clusterCfg.reConfig.peer[i] = clust->peerIdLst[i]; + } + + return (sng_cfg_m2ua (&pst, &cfg)); +} + +/**********************************************************************************************/ + +/* M2UA - DLSAP configuration */ +static int ftmod_m2ua_dlsap_config(int id) +{ + Pst pst; + MwMgmt cfg; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + + memset((U8 *)&cfg, 0, sizeof(MwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTMW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STMWDLSAP; /* DLSAP */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + + cfg.t.cfg.s.dlSapCfg.lnkNmb = id; /* SapId */ + cfg.t.cfg.s.dlSapCfg.intfId.type = LMW_INTFID_INT; + cfg.t.cfg.s.dlSapCfg.intfId.id.intId = m2ua->iid; + + cfg.t.cfg.s.dlSapCfg.swtch = LMW_SAP_ITU; + + cfg.t.cfg.s.dlSapCfg.reConfig.clusterId = m2ua->clusterId; + cfg.t.cfg.s.dlSapCfg.reConfig.selector = 0; /* Loosely couple mode */ + /* memory region and pool id*/ + cfg.t.cfg.s.dlSapCfg.reConfig.mem.region = S_REG; + cfg.t.cfg.s.dlSapCfg.reConfig.mem.pool = S_POOL; + /* priority */ + cfg.t.cfg.s.dlSapCfg.reConfig.prior = PRIOR0; + /* route */ + cfg.t.cfg.s.dlSapCfg.reConfig.route = RTESPEC; + + return (sng_cfg_m2ua (&pst, &cfg)); + +} +/*****************************************************************************/ +/* NIF - General configuration */ +static int ftmod_nif_gen_config(void) +{ + Pst pst; + NwMgmt cfg; + + memset((U8 *)&cfg, 0, sizeof(NwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTNW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STNWGEN; /* DLSAP */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + + cfg.t.cfg.s.genCfg.maxNmbDlSap = NW_MAX_NUM_OF_DLSAPS; + cfg.t.cfg.s.genCfg.timeRes = 1; /* timer resolution */ + + cfg.t.cfg.s.genCfg.reConfig.maxNmbRetry = NW_MAX_NUM_OF_RETRY; + cfg.t.cfg.s.genCfg.reConfig.tmrRetry.enb = TRUE; /* SS7 Congestion poll timer */ + cfg.t.cfg.s.genCfg.reConfig.tmrRetry.val = NW_RETRY_TMR_VALUE; + +#ifdef LCNWMILNW + cfg.t.cfg.s.genCfg.reConfig.smPst.selector = 0; /* selector */ +#else /* LCSBMILSB */ + cfg.t.cfg.s.genCfg.reConfig.smPst.selector = 1; /* selector */ +#endif /* LCSBMILSB */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.region = S_REG; /* region */ + cfg.t.cfg.s.genCfg.reConfig.smPst.pool = S_POOL; /* pool */ + cfg.t.cfg.s.genCfg.reConfig.smPst.prior = PRIOR0; /* priority */ + cfg.t.cfg.s.genCfg.reConfig.smPst.route = RTESPEC; /* route */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.dstEnt = ENTSM; /* dst entity */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstInst = 0; /* dst inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.dstProcId = SFndProcId(); /* src proc id */ + + cfg.t.cfg.s.genCfg.reConfig.smPst.srcEnt = ENTNW; /* src entity */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcInst = 0; /* src inst */ + cfg.t.cfg.s.genCfg.reConfig.smPst.srcProcId = SFndProcId(); /* src proc id */ + + return (sng_cfg_nif (&pst, &cfg)); + +} + +/*****************************************************************************/ + +/* NIF - DLSAP configuration */ +static int ftmod_nif_dlsap_config(int id) +{ + Pst pst; + NwMgmt cfg; + sng_nif_cfg_t* nif = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[id]; + + memset((U8 *)&cfg, 0, sizeof(NwMgmt)); + memset((U8 *)&pst, 0, sizeof(Pst)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + cfg.hdr.msgType = TCFG; /* message type */ + cfg.hdr.entId.ent = ENTNW; /* entity */ + cfg.hdr.entId.inst = 0; /* instance */ + cfg.hdr.elmId.elmnt = STNWDLSAP; /* DLSAP */ + cfg.hdr.transId = 0; /* transaction identifier */ + + cfg.hdr.response.selector = 0; + cfg.hdr.response.prior = PRIOR0; + cfg.hdr.response.route = RTESPEC; + cfg.hdr.response.mem.region = S_REG; + cfg.hdr.response.mem.pool = S_POOL; + cfg.t.cfg.s.dlSapCfg.suId = nif->id; + cfg.t.cfg.s.dlSapCfg.m2uaLnkNmb = nif->m2uaLnkNmb; + cfg.t.cfg.s.dlSapCfg.mtp2LnkNmb = nif->mtp2LnkNmb; + + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.selector = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.region = S_REG; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.pool = S_POOL; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.route = RTESPEC; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.prior = PRIOR0; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.srcEnt = ENTNW; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.srcInst = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.srcProcId = SFndProcId(); + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.dstEnt = ENTMW; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.dstInst = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.m2uaPst.dstProcId = SFndProcId(); + + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.selector = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.region = S_REG; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.pool = S_POOL; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.route = RTESPEC; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.prior = PRIOR0; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.srcEnt = ENTNW; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.srcInst = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.srcProcId = SFndProcId(); + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.dstEnt = ENTSD; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.dstInst = 0; + cfg.t.cfg.s.dlSapCfg.reConfig.mtp2Pst.dstProcId = SFndProcId(); + + return (sng_cfg_nif (&pst, &cfg)); +} + +/*****************************************************************************/ +uint32_t iptoul(const char *ip) +{ + char i,*tmp; + int strl; + char strIp[16]; + unsigned long val=0, cvt; + if (!ip) + return 0; + + memset(strIp, 0, sizeof(char)*16); + strl = strlen(ip); + strncpy(strIp, ip, strl>=15?15:strl); + + + tmp=strtok(strIp, "."); + for (i=0;i<4;i++) + { + sscanf(tmp, "%lu", &cvt); + val <<= 8; + val |= (unsigned char)cvt; + tmp=strtok(NULL,"."); + } + return (uint32_t)val; +} +/***********************************************************************************************************************/ +void ftmod_ss7_enable_m2ua_sg_logging(void){ + + /* Enable DEBUGs*/ + ftmod_sctp_debug(AENA); + ftmod_m2ua_debug(AENA); + ftmod_tucl_debug(AENA); +} + +/***********************************************************************************************************************/ +void ftmod_ss7_disable_m2ua_sg_logging(void){ + + /* DISABLE DEBUGs*/ + ftmod_sctp_debug(ADISIMM); + ftmod_m2ua_debug(ADISIMM); + ftmod_tucl_debug(ADISIMM); +} + +/***********************************************************************************************************************/ +int ftmod_ss7_m2ua_start(void){ + int x=0; + +/***********************************************************************************************************************/ + x = 1; + while(xclusterId]; + + if(clust->flags & SNGSS7_M2UA_EP_OPENED) { + ftdm_log (FTDM_LOG_INFO ," END-POINT already opened\n"); + return ret; + } + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWSCTSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + + cntrl.t.cntrl.action = AMWENDPOPEN; + cntrl.t.cntrl.s.suId = m2ua->id; /* M2UA sct sap Id */ + + + if(0 == (ret = sng_cntrl_m2ua (&pst, &cntrl))){ + clust->flags |= SNGSS7_M2UA_EP_OPENED; + } + return ret; + +} + +/***********************************************************************************************************************/ +static int ftmod_init_sctp_assoc(int peer_id) +{ + + Pst pst; + MwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWPEER; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + + cntrl.t.cntrl.action = AMWESTABLISH; + /*cntrl.t.cntrl.s.suId = 1;*/ + + cntrl.t.cntrl.s.peerId = (MwPeerId) peer_id; + + return (sng_cntrl_m2ua (&pst, &cntrl)); +} + +/***********************************************************************************************************************/ +static int ftmod_sctp_tucl_tsap_bind(int id) +{ + Pst pst; + SbMgmt cntrl; + sng_sctp_link_t *k = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[id]; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(SbMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTSB; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTSB; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STSBTSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ABND_ENA; + cntrl.t.cntrl.sapId = k->id; /* SCT sap id configured at SCTP layer */ + + return (sng_cntrl_sctp (&pst, &cntrl)); +} +/***********************************************************************************************************************/ + +static int ftmod_m2ua_sctp_sctsap_bind(int id) +{ + int ret = 0x00; + Pst pst; + MwMgmt cntrl; + sng_m2ua_cfg_t* m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + sng_m2ua_cluster_cfg_t* clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + + if(clust->flags & SNGSS7_ACTIVE) { + ftdm_log (FTDM_LOG_INFO ," SCT-SAP is already enabled\n"); + return ret; + } + + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWSCTSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ABND; + cntrl.t.cntrl.s.suId = m2ua->id; + + if(0 == (ret = sng_cntrl_m2ua (&pst, &cntrl))){ + clust->flags |= SNGSS7_ACTIVE; + } + return ret; +} +/***********************************************************************************************************************/ +static int ftmod_nif_m2ua_dlsap_bind(int id) +{ + Pst pst; + NwMgmt cntrl; + sng_nif_cfg_t* nif = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[id]; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(NwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTNW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STNWDLSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ABND; + cntrl.t.cntrl.suId = nif->id; /* NIF DL sap Id */ + cntrl.t.cntrl.entity = ENTMW; /* M2UA */ + + return (sng_cntrl_nif (&pst, &cntrl)); + +} + +/***********************************************************************************************************************/ +static int ftmod_nif_mtp2_dlsap_bind(int id) +{ + Pst pst; + NwMgmt cntrl; + sng_nif_cfg_t* nif = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[id]; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(NwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTNW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STNWDLSAP; /* General */ + cntrl.hdr.transId = 1; /* transaction identifier */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = ABND; + cntrl.t.cntrl.suId = nif->id; /* NIF DL sap Id */ + cntrl.t.cntrl.entity = ENTSD; /* MTP2 */ + + return (sng_cntrl_nif (&pst, &cntrl)); + +} + +/***********************************************************************************************************************/ +static int ftmod_sctp_debug(int action) +{ + Pst pst; + SbMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(SbMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTSB; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTSB; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STSBGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = action; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.dbgMask = 0xFFFF; + + return (sng_cntrl_sctp (&pst, &cntrl)); +} +/***********************************************************************************************************************/ + +static int ftmod_m2ua_debug(int action) +{ + Pst pst; + MwMgmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTMW; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STMWGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = action; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.s.dbgMask = 0xFFFF; + + return (sng_cntrl_m2ua (&pst, &cntrl)); +} +/***********************************************************************************************************************/ +static int ftmod_tucl_debug(int action) +{ + Pst pst; + HiMngmt cntrl; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&cntrl, 0, sizeof(HiMngmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTHI; + + /* prepare header */ + cntrl.hdr.msgType = TCNTRL; /* message type */ + cntrl.hdr.entId.ent = ENTHI; /* entity */ + cntrl.hdr.entId.inst = 0; /* instance */ + cntrl.hdr.elmId.elmnt = STGEN; /* General */ + + cntrl.hdr.response.selector = 0; + cntrl.hdr.response.prior = PRIOR0; + cntrl.hdr.response.route = RTESPEC; + cntrl.hdr.response.mem.region = S_REG; + cntrl.hdr.response.mem.pool = S_POOL; + + cntrl.t.cntrl.action = action; + cntrl.t.cntrl.subAction = SADBG; + cntrl.t.cntrl.ctlType.hiDbg.dbgMask = 0xFFFF; + + return (sng_cntrl_tucl (&pst, &cntrl)); +} +/***********************************************************************************************************************/ + +/***********************************************************************************************************************/ +int ftmod_sctp_ssta_req(int elemt, int id, SbMgmt* cfm) +{ + SbMgmt ssta; + Pst pst; + sng_sctp_link_t *k = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[id]; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&ssta, 0, sizeof(SbMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTSB; + + /* prepare header */ + ssta.hdr.msgType = TSSTA; /* message type */ + ssta.hdr.entId.ent = ENTSB; /* entity */ + ssta.hdr.entId.inst = 0; /* instance */ + ssta.hdr.elmId.elmnt = elemt; /* STSBGEN */ /* Others are STSBTSAP, STSBSCTSAP, STSBASSOC, STSBDTA, STSBTMR */ + ssta.hdr.transId = 1; /* transaction identifier */ + + ssta.hdr.response.selector = 0; + ssta.hdr.response.prior = PRIOR0; + ssta.hdr.response.route = RTESPEC; + ssta.hdr.response.mem.region = S_REG; + ssta.hdr.response.mem.pool = S_POOL; + + if((ssta.hdr.elmId.elmnt == STSBSCTSAP) || (ssta.hdr.elmId.elmnt == STSBTSAP)) + { + ssta.t.ssta.sapId = k->id; /* SapId */ + } + if(ssta.hdr.elmId.elmnt == STSBASSOC) + { + /*TODO - how to get assoc Id*/ + ssta.t.ssta.s.assocSta.assocId = 0; /* association id */ + } + return(sng_sta_sctp(&pst,&ssta,cfm)); +} + +int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm) +{ + MwMgmt ssta; + Pst pst; + sng_m2ua_cfg_t* m2ua = NULL; + sng_m2ua_cluster_cfg_t* clust = NULL; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&ssta, 0, sizeof(MwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTMW; + + /* prepare header */ + ssta.hdr.msgType = TSSTA; /* message type */ + ssta.hdr.entId.ent = ENTMW; /* entity */ + ssta.hdr.entId.inst = 0; /* instance */ + ssta.hdr.elmId.elmnt = elemt; /*STMWGEN */ /* Others are STMWSCTSAP, STMWCLUSTER, STMWPEER,STMWSID, STMWDLSAP */ + ssta.hdr.transId = 1; /* transaction identifier */ + + ssta.hdr.response.selector = 0; + ssta.hdr.response.prior = PRIOR0; + ssta.hdr.response.route = RTESPEC; + ssta.hdr.response.mem.region = S_REG; + ssta.hdr.response.mem.pool = S_POOL; + + switch(ssta.hdr.elmId.elmnt) + { + case STMWSCTSAP: + { + m2ua = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[id]; + clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId]; + ssta.t.ssta.id.suId = clust->sct_sap_id ; /* lower sap Id */ + break; + } + case STMWDLSAP: + { + ssta.t.ssta.id.lnkNmb = id ; /* upper sap Id */ + break; + } + case STMWPEER: + { + ssta.t.ssta.id.peerId = id ; /* peer Id */ + break; + } + case STMWCLUSTER: + { + clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[id]; + ssta.t.ssta.id.clusterId = clust->id ; /* cluster Id */ + break; + } + default: + break; + } + + return(sng_sta_m2ua(&pst,&ssta,cfm)); +} + +int ftmod_nif_ssta_req(int elemt, int id, NwMgmt* cfm) +{ + NwMgmt ssta; + Pst pst; + sng_nif_cfg_t* nif = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[id]; + + memset((U8 *)&pst, 0, sizeof(Pst)); + memset((U8 *)&ssta, 0, sizeof(NwMgmt)); + + smPstInit(&pst); + + pst.dstEnt = ENTNW; + + /* prepare header */ + ssta.hdr.msgType = TSSTA; /* message type */ + ssta.hdr.entId.ent = ENTNW; /* entity */ + ssta.hdr.entId.inst = 0; /* instance */ + ssta.hdr.elmId.elmnt = elemt; + + ssta.hdr.response.selector = 0; + ssta.hdr.response.prior = PRIOR0; + ssta.hdr.response.route = RTESPEC; + ssta.hdr.response.mem.region = S_REG; + ssta.hdr.response.mem.pool = S_POOL; + ssta.t.ssta.suId = nif->id; /* Lower sapId */ + + return(sng_sta_nif(&pst,&ssta,cfm)); +} diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h new file mode 100644 index 0000000000..8bb564d284 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2012, Kapil Gupta + * 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. + * + * + * Contributors: + * + */ +/******************************************************************************/ +#ifndef __FTMOD_SNG_SS7_M2UA_H__ +#define __FTMOD_SNG_SS7_M2UA_H__ +/******************************************************************************/ +#include "private/ftdm_core.h" + +#define MAX_NAME_LEN 25 + +typedef struct sng_nif_cfg{ + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; + uint32_t m2uaLnkNmb; + uint32_t mtp2LnkNmb; +}sng_nif_cfg_t; + +typedef enum{ + SNG_M2UA_NODE_TYPE_SGP = 1, /* type SG */ + SNG_M2UA_NODE_TYPE_ASP = 2, /* type ASP */ +}sng_m2ua_node_types_e; + +typedef struct sng_m2ua_cfg{ + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; /* ID */ + uint32_t iid; /* ID */ + uint8_t nodeType; /*Node Type SG/ASP */ + uint8_t end_point_opened; /* flag to check is end-point already opened */ + uint16_t clusterId; /* idx to m2ua_cluster profile */ +}sng_m2ua_cfg_t; + +typedef struct sng_m2ua_peer_cfg{ + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; /* ID */ + uint8_t aspIdFlag; /* Flag used to indicate whether include the ASP ID in the ASP UP message */ + uint16_t selfAspId; /* Self ASP ID. ASP identifier for this ASP node if the aspIdFlag is TRUE. */ + uint32_t numDestAddr; /* Number of destination address defined */ + uint16_t sctpId; /* idx to sctp profile */ + uint16_t port; + uint32_t destAddrList[SCT_MAX_NET_ADDRS+1]; /* Destination adddress list */ + uint16_t locOutStrms; /*Number of outgoing streams supported by this association*/ + int init_sctp_assoc; /* flag to tell if we need to initiate SCTP association */ +}sng_m2ua_peer_cfg_t; + +typedef enum{ + SNG_M2UA_LOAD_SHARE_ALGO_RR = 0x1, /* Round Robin Mode*/ + SNG_M2UA_LOAD_SHARE_ALGO_LS = 0x2, /* Link Specified */ + SNG_M2UA_LOAD_SHARE_ALGO_CS = 0x3, /* Customer Specified */ +}sng_m2ua_load_share_algo_types_e; + + +/* Possible values of Traffic mode */ +typedef enum{ + SNG_M2UA_TRF_MODE_OVERRIDE = 0x1, /* Override Mode */ + SNG_M2UA_TRF_MODE_LOADSHARE = 0x2, /* Loadshare Mode */ + SNG_M2UA_TRF_MODE_BROADCAST = 0x3, /* Broadcast Mode */ + SNG_M2UA_TRF_MODE_ANY = 0x0, /* ANY Mode */ +}sng_m2ua_traffic_mode_types_e; + +typedef struct sng_m2ua_cluster_cfg{ + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; /* ID */ + uint32_t sct_sap_id; /* Internal - sct_sap_id */ + uint8_t trfMode; /* Traffic mode. This parameter defines the mode in which this m2ua cluster is supposed to work */ + uint8_t loadShareAlgo; /* This parameter defines the M2UA load share algorithm which is used to distribute the traffic */ + uint16_t numOfPeers; /* idx to m2ua_peer profile */ + uint16_t peerIdLst[MW_MAX_NUM_OF_PEER]; /* idx to m2ua_peer profile */ +}sng_m2ua_cluster_cfg_t; + +typedef struct sng_m2ua_gbl_cfg{ + sng_nif_cfg_t nif[MW_MAX_NUM_OF_INTF+1]; + sng_m2ua_cfg_t m2ua[MW_MAX_NUM_OF_INTF+1]; + sng_m2ua_peer_cfg_t m2ua_peer[MW_MAX_NUM_OF_PEER+1]; + sng_m2ua_cluster_cfg_t m2ua_clus[MW_MAX_NUM_OF_CLUSTER+1]; +}sng_m2ua_gbl_cfg_t; + +/* m2ua xml parsing APIs */ +int ftmod_ss7_parse_nif_interfaces(ftdm_conf_node_t *nif_interfaces); +int ftmod_ss7_parse_m2ua_interfaces(ftdm_conf_node_t *m2ua_interfaces); +int ftmod_ss7_parse_m2ua_peer_interfaces(ftdm_conf_node_t *m2ua_peer_interfaces); +int ftmod_ss7_parse_m2ua_clust_interfaces(ftdm_conf_node_t *m2ua_clust_interfaces); +int ftmod_ss7_parse_sctp_links(ftdm_conf_node_t *node); +uint32_t iptoul(const char *ip); + +int ftmod_ss7_m2ua_start(void); +void ftmod_ss7_m2ua_free(void); + +ftdm_status_t ftmod_ss7_m2ua_cfg(void); +ftdm_status_t ftmod_ss7_m2ua_init(void); + +int ftmod_sctp_ssta_req(int elemt, int id, SbMgmt* cfm); +int ftmod_m2ua_ssta_req(int elemt, int id, MwMgmt* cfm); +int ftmod_nif_ssta_req(int elemt, int id, NwMgmt* cfm); +void ftmod_ss7_enable_m2ua_sg_logging(void); +void ftmod_ss7_disable_m2ua_sg_logging(void); + + +#endif /*__FTMOD_SNG_SS7_M2UA_H__*/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c new file mode 100644 index 0000000000..bb011c364e --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua_xml.c @@ -0,0 +1,690 @@ +/* + * Copyright (c) 2012, Kapil Gupta + * 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. + * + * + * Contributors: + * + * + */ + +/* INCLUDE ********************************************************************/ +#include "ftmod_sangoma_ss7_main.h" +/******************************************************************************/ + +/* DEFINES ********************************************************************/ +/******************************************************************************/ + +static int ftmod_ss7_parse_nif_interface(ftdm_conf_node_t *nif_interface); +static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface); +static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_interface); +static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_clust_interface); +static int ftmod_ss7_fill_in_nif_interface(sng_nif_cfg_t *nif_iface); +static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface); +static int ftmod_ss7_fill_in_m2ua_peer_interface(sng_m2ua_peer_cfg_t *m2ua_peer_face); +static int ftmod_ss7_fill_in_m2ua_clust_interface(sng_m2ua_cluster_cfg_t *m2ua_cluster_face); + +static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node); + +/******************************************************************************/ +int ftmod_ss7_parse_nif_interfaces(ftdm_conf_node_t *nif_interfaces) +{ + ftdm_conf_node_t *nif_interface = NULL; + + /* confirm that we are looking at sng_nif_interfaces */ + if (strcasecmp(nif_interfaces->name, "sng_nif_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"sng_nif_interfaces\"!\n",nif_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"nif_interfaces\"...\n"); + } + + /* extract the isup_interfaces */ + nif_interface = nif_interfaces->child; + + while (nif_interface != NULL) { + /* parse the found mtp_route */ + if (ftmod_ss7_parse_nif_interface(nif_interface)) { + SS7_ERROR("Failed to parse \"nif_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next nif_interface */ + nif_interface = nif_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_nif_interface(ftdm_conf_node_t *nif_interface) +{ + sng_nif_cfg_t sng_nif; + ftdm_conf_parameter_t *parm = nif_interface->parameters; + int num_parms = nif_interface->n_parameters; + int i; + + /* initalize the nif intf and isap structure */ + memset(&sng_nif, 0x0, sizeof(sng_nif)); + + if(!nif_interface){ + SS7_ERROR("ftmod_ss7_parse_nif_interface: Null XML Node pointer \n"); + return FTDM_FAIL; + } + + /* confirm that we are looking at an nif_interface */ + if (strcasecmp(nif_interface->name, "sng_nif_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"nif_interface\"!\n",nif_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"nif_interface\"...\n"); + } + + + for (i = 0; i < num_parms; i++) { + /**************************************************************************/ + + /* try to match the parameter to what we expect */ + if (!strcasecmp(parm->var, "name")) { + /**********************************************************************/ + strcpy((char *)sng_nif.name, parm->val); + SS7_DEBUG("Found an nif_interface named = %s\n", sng_nif.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "id")) { + /**********************************************************************/ + sng_nif.id = atoi(parm->val); + SS7_DEBUG("Found an nif id = %d\n", sng_nif.id); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "m2ua-interface-id")) { + /**********************************************************************/ + sng_nif.m2uaLnkNmb = atoi(parm->val); + SS7_DEBUG("Found an nif m2ua-interface-id = %d\n", sng_nif.m2uaLnkNmb); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2-interface-id")) { + /**********************************************************************/ + sng_nif.mtp2LnkNmb=atoi(parm->val); + + SS7_DEBUG("Found an nif mtp2-interface-id = %d\n", sng_nif.mtp2LnkNmb); + /**********************************************************************/ + } else { + /**********************************************************************/ + SS7_ERROR("Found an invalid parameter %s!\n", parm->var); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + /* fill in the nif interface */ + ftmod_ss7_fill_in_nif_interface(&sng_nif); + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static int ftmod_ss7_fill_in_nif_interface(sng_nif_cfg_t *nif_iface) +{ + int i = nif_iface->id; + + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].name, (char *)nif_iface->name, MAX_NAME_LEN-1); + + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].id = nif_iface->id; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].m2uaLnkNmb = nif_iface->m2uaLnkNmb; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.nif[i].mtp2LnkNmb = nif_iface->mtp2LnkNmb; + + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_NIF_PRESENT); + + return 0; +} + +/******************************************************************************/ +int ftmod_ss7_parse_m2ua_interfaces(ftdm_conf_node_t *m2ua_interfaces) +{ + ftdm_conf_node_t *m2ua_interface = NULL; + + /* confirm that we are looking at sng_m2ua_interfaces */ + if (strcasecmp(m2ua_interfaces->name, "sng_m2ua_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_nif_interfaces\"!\n",m2ua_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_interfaces\"...\n"); + } + + /* extract the isup_interfaces */ + m2ua_interface = m2ua_interfaces->child; + + while (m2ua_interface != NULL) { + /* parse the found mtp_route */ + if (ftmod_ss7_parse_m2ua_interface(m2ua_interface)) { + SS7_ERROR("Failed to parse \"m2ua_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next m2ua_interface */ + m2ua_interface = m2ua_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_m2ua_interface(ftdm_conf_node_t *m2ua_interface) +{ + sng_m2ua_cfg_t sng_m2ua; + ftdm_conf_parameter_t *parm = m2ua_interface->parameters; + int num_parms = m2ua_interface->n_parameters; + int i; + + /* initalize the m2ua intf */ + memset(&sng_m2ua, 0x0, sizeof(sng_m2ua)); + + if(!m2ua_interface){ + SS7_ERROR("ftmod_ss7_parse_m2ua_interface: Null XML Node pointer \n"); + return FTDM_FAIL; + } + + /* confirm that we are looking at an nif_interface */ + if (strcasecmp(m2ua_interface->name, "sng_m2ua_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_interface\"!\n",m2ua_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_interface\"...\n"); + } + + + for (i = 0; i < num_parms; i++) { + /**************************************************************************/ + + /* try to match the parameter to what we expect */ + if (!strcasecmp(parm->var, "name")) { + /**********************************************************************/ + strcpy((char *)sng_m2ua.name, parm->val); + SS7_DEBUG("Found an m2ua_interface named = %s\n", sng_m2ua.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "id")) { + /**********************************************************************/ + sng_m2ua.id = atoi(parm->val); + SS7_DEBUG("Found an m2ua id = %d\n", sng_m2ua.id); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "m2ua-cluster-interface-id")) { + /**********************************************************************/ + sng_m2ua.clusterId=atoi(parm->val); + + SS7_DEBUG("Found an m2ua cluster_id = %d\n", sng_m2ua.clusterId); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "interface-identifier")) { + /**********************************************************************/ + sng_m2ua.iid=atoi(parm->val); + + SS7_DEBUG("Found an m2ua interface-identifier = %d\n", sng_m2ua.iid); + /**********************************************************************/ + } else { + /**********************************************************************/ + SS7_ERROR("Found an invalid parameter %s!\n", parm->var); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + sng_m2ua.nodeType = SNG_M2UA_NODE_TYPE_SGP; + + /* fill in the nif interface */ + ftmod_ss7_fill_in_m2ua_interface(&sng_m2ua); + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static int ftmod_ss7_fill_in_m2ua_interface(sng_m2ua_cfg_t *m2ua_iface) +{ + int i = m2ua_iface->id; + + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].name, (char *)m2ua_iface->name, MAX_NAME_LEN-1); + + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].id = m2ua_iface->id; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].nodeType = m2ua_iface->nodeType; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].clusterId = m2ua_iface->clusterId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[i].iid = m2ua_iface->iid; + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_M2UA_PRESENT); + + return 0; +} + +/******************************************************************************/ +int ftmod_ss7_parse_m2ua_peer_interfaces(ftdm_conf_node_t *m2ua_peer_interfaces) +{ + ftdm_conf_node_t *m2ua_peer_interface = NULL; + + /* confirm that we are looking at m2ua_peer_interfaces */ + if (strcasecmp(m2ua_peer_interfaces->name, "sng_m2ua_peer_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_peer_interfaces\"!\n",m2ua_peer_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_peer_interfaces\"...\n"); + } + + /* extract the m2ua_peer_interfaces */ + m2ua_peer_interface = m2ua_peer_interfaces->child; + + while (m2ua_peer_interface != NULL) { + /* parse the found mtp_route */ + if (ftmod_ss7_parse_m2ua_peer_interface(m2ua_peer_interface)) { + SS7_ERROR("Failed to parse \"m2ua_peer_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next m2ua_peer_interface */ + m2ua_peer_interface = m2ua_peer_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_m2ua_peer_interface(ftdm_conf_node_t *m2ua_peer_interface) +{ + sng_m2ua_peer_cfg_t sng_m2ua_peer; + ftdm_conf_parameter_t *parm = m2ua_peer_interface->parameters; + int num_parms = m2ua_peer_interface->n_parameters; + int i; + + /* initalize the m2ua intf */ + memset(&sng_m2ua_peer, 0x0, sizeof(sng_m2ua_peer)); + + if(!m2ua_peer_interface){ + SS7_ERROR("ftmod_ss7_parse_m2ua_peer_interface: Null XML Node pointer \n"); + return FTDM_FAIL; + } + + /* confirm that we are looking at an m2ua_peer_interface */ + if (strcasecmp(m2ua_peer_interface->name, "sng_m2ua_peer_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_peer_interface\"!\n",m2ua_peer_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_peer_interface\"...\n"); + } + + for (i = 0; i < num_parms; i++) { + /**************************************************************************/ + + /* try to match the parameter to what we expect */ + if (!strcasecmp(parm->var, "name")) { + /**********************************************************************/ + strcpy((char *)sng_m2ua_peer.name, parm->val); + SS7_DEBUG("Found an sng_m2ua_peer named = %s\n", sng_m2ua_peer.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "id")) { + /**********************************************************************/ + sng_m2ua_peer.id = atoi(parm->val); + SS7_DEBUG("Found an sng_m2ua_peer id = %d\n", sng_m2ua_peer.id); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "include-asp-identifier")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "TRUE")){ + sng_m2ua_peer.aspIdFlag = 0x01; + } else if(!strcasecmp(parm->val, "FALSE")){ + sng_m2ua_peer.aspIdFlag = 0x00; + } else { + SS7_ERROR("Found an invalid aspIdFlag Parameter Value[%s]\n", parm->val); + return FTDM_FAIL; + } + SS7_DEBUG("Found an sng_m2ua_peer aspIdFlag = %d\n", sng_m2ua_peer.aspIdFlag); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "asp-identifier")) { + /**********************************************************************/ + sng_m2ua_peer.selfAspId=atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer self_asp_id = %d\n", sng_m2ua_peer.selfAspId); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "sctp-interface-id")) { + /**********************************************************************/ + sng_m2ua_peer.sctpId = atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer sctp_id = %d\n", sng_m2ua_peer.sctpId); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "destination-port")) { + /**********************************************************************/ + sng_m2ua_peer.port = atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer port = %d\n", sng_m2ua_peer.port); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "address")) { + /**********************************************************************/ + if (sng_m2ua_peer.numDestAddr < SCT_MAX_NET_ADDRS) { + sng_m2ua_peer.destAddrList[sng_m2ua_peer.numDestAddr] = iptoul (parm->val); + sng_m2ua_peer.numDestAddr++; + SS7_DEBUG("sng_m2ua_peer - Parsing with dest IP Address = %s \n", parm->val); + } else { + SS7_ERROR("sng_m2ua_peer - too many dest address configured. dropping %s \n", parm->val); + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "number-of-outgoing-streams")) { + /**********************************************************************/ + sng_m2ua_peer.locOutStrms=atoi(parm->val); + + SS7_DEBUG("Found an sng_m2ua_peer number-of-outgoing-streams = %d\n", sng_m2ua_peer.locOutStrms); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "init-sctp-association")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "TRUE")){ + sng_m2ua_peer.init_sctp_assoc = 0x01; + } else if(!strcasecmp(parm->val, "FALSE")){ + sng_m2ua_peer.init_sctp_assoc = 0x00; + } else { + SS7_ERROR("Found an invalid init_sctp_assoc Parameter Value[%s]\n", parm->val); + return FTDM_FAIL; + } + + SS7_DEBUG("Found an sng_m2ua_peer init_sctp_assoc = %d\n", sng_m2ua_peer.init_sctp_assoc); + /**********************************************************************/ + } else { + /**********************************************************************/ + SS7_ERROR("Found an invalid parameter %s!\n", parm->var); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + /* fill in the sng_m2ua_peer interface */ + ftmod_ss7_fill_in_m2ua_peer_interface(&sng_m2ua_peer); + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static int ftmod_ss7_fill_in_m2ua_peer_interface(sng_m2ua_peer_cfg_t *m2ua_peer_iface) +{ + int k = 0x00; + int i = m2ua_peer_iface->id; + + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].name, (char *)m2ua_peer_iface->name, MAX_NAME_LEN-1); + + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].id = m2ua_peer_iface->id; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].aspIdFlag = m2ua_peer_iface->aspIdFlag; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].selfAspId = m2ua_peer_iface->selfAspId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].locOutStrms = m2ua_peer_iface->locOutStrms; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].numDestAddr = m2ua_peer_iface->numDestAddr; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].sctpId = m2ua_peer_iface->sctpId; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].port = m2ua_peer_iface->port; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].init_sctp_assoc = m2ua_peer_iface->init_sctp_assoc; + for (k=0; knumDestAddr; k++) { + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[i].destAddrList[k] = m2ua_peer_iface->destAddrList[k]; + } + + + return 0; +} + +/******************************************************************************/ +int ftmod_ss7_parse_m2ua_clust_interfaces(ftdm_conf_node_t *m2ua_cluster_interfaces) +{ + ftdm_conf_node_t *m2ua_cluster_interface = NULL; + + /* confirm that we are looking at m2ua_cluster_interfaces */ + if (strcasecmp(m2ua_cluster_interfaces->name, "sng_m2ua_cluster_interfaces")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_cluster_interfaces\"!\n",m2ua_cluster_interfaces->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_cluster_interfaces\"...\n"); + } + + /* extract the m2ua_cluster_interfaces */ + m2ua_cluster_interface = m2ua_cluster_interfaces->child; + + while (m2ua_cluster_interface != NULL) { + /* parse the found m2ua_cluster_interface */ + if (ftmod_ss7_parse_m2ua_clust_interface(m2ua_cluster_interface)) { + SS7_ERROR("Failed to parse \"m2ua_cluster_interface\"\n"); + return FTDM_FAIL; + } + + /* go to the next m2ua_cluster_interface */ + m2ua_cluster_interface = m2ua_cluster_interface->next; + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_m2ua_clust_interface(ftdm_conf_node_t *m2ua_cluster_interface) +{ + sng_m2ua_cluster_cfg_t sng_m2ua_cluster; + ftdm_conf_parameter_t *parm = m2ua_cluster_interface->parameters; + int num_parms = m2ua_cluster_interface->n_parameters; + int i; + + /* initalize the m2ua_cluster_interface */ + memset(&sng_m2ua_cluster, 0x0, sizeof(sng_m2ua_cluster)); + + if (!m2ua_cluster_interface){ + SS7_ERROR("ftmod_ss7_parse_m2ua_clust_interface - NULL XML Node pointer \n"); + return FTDM_FAIL; + } + + /* confirm that we are looking at an m2ua_cluster_interface */ + if (strcasecmp(m2ua_cluster_interface->name, "sng_m2ua_cluster_interface")) { + SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"m2ua_cluster_interface\"!\n",m2ua_cluster_interface->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("Parsing \"m2ua_cluster_interface\"...\n"); + } + + + for (i = 0; i < num_parms; i++) { + /**************************************************************************/ + + /* try to match the parameter to what we expect */ + if (!strcasecmp(parm->var, "name")) { + /**********************************************************************/ + strcpy((char *)sng_m2ua_cluster.name, parm->val); + SS7_DEBUG("Found an sng_m2ua_cluster named = %s\n", sng_m2ua_cluster.name); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "id")) { + /**********************************************************************/ + sng_m2ua_cluster.id = atoi(parm->val); + SS7_DEBUG("Found an sng_m2ua_cluster id = %d\n", sng_m2ua_cluster.id); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "traffic-mode")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "loadshare")){ + sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_LOADSHARE; + } else if(!strcasecmp(parm->val, "override")){ + sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_OVERRIDE; + } else if(!strcasecmp(parm->val, "broadcast")){ + sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_BROADCAST; + } else { + SS7_ERROR("Found an invalid trfMode Parameter Value[%s]..adding default one[ANY]\n", parm->val); + sng_m2ua_cluster.trfMode = SNG_M2UA_TRF_MODE_ANY; + } + SS7_DEBUG("Found an sng_m2ua_cluster.trfMode = %d\n", sng_m2ua_cluster.trfMode); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "load-share-algorithm")) { + /**********************************************************************/ + if(!strcasecmp(parm->val, "roundrobin")){ + sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_RR; + } else if(!strcasecmp(parm->val, "linkspecified")){ + sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_LS; + } else if(!strcasecmp(parm->val, "customerspecified")){ + sng_m2ua_cluster.loadShareAlgo = SNG_M2UA_LOAD_SHARE_ALGO_CS; + } else { + SS7_ERROR("Found an invalid loadShareAlgo Parameter Value[%s]\n", parm->val); + return FTDM_FAIL; + } + + SS7_DEBUG("Found an sng_m2ua_cluster.loadShareAlgo = %d\n", sng_m2ua_cluster.loadShareAlgo); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "m2ua-peer-interface-id")) { + /**********************************************************************/ + if(sng_m2ua_cluster.numOfPeers < MW_MAX_NUM_OF_PEER) { + sng_m2ua_cluster.peerIdLst[sng_m2ua_cluster.numOfPeers] = atoi(parm->val); + SS7_DEBUG("Found an sng_m2ua_cluster peerId[%d], Total numOfPeers[%d] \n", + sng_m2ua_cluster.peerIdLst[sng_m2ua_cluster.numOfPeers], + sng_m2ua_cluster.numOfPeers+1); + sng_m2ua_cluster.numOfPeers++; + }else{ + SS7_ERROR("Peer List excedding max[%d] limit \n", MW_MAX_NUM_OF_PEER); + return FTDM_FAIL; + } + /**********************************************************************/ + } else { + /**********************************************************************/ + SS7_ERROR("Found an invalid parameter %s!\n", parm->var); + return FTDM_FAIL; + /**********************************************************************/ + } + + /* move to the next parameter */ + parm = parm + 1; + /**************************************************************************/ + } /* for (i = 0; i < num_parms; i++) */ + + /* fill in the sng_m2ua_peer interface */ + ftmod_ss7_fill_in_m2ua_clust_interface(&sng_m2ua_cluster); + + return FTDM_SUCCESS; +} +/******************************************************************************/ +static int ftmod_ss7_fill_in_m2ua_clust_interface(sng_m2ua_cluster_cfg_t *m2ua_cluster_iface) +{ + int k = 0x00; + int i = m2ua_cluster_iface->id; + + strncpy((char *)g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].name, (char *)m2ua_cluster_iface->name, MAX_NAME_LEN-1); + + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].id = m2ua_cluster_iface->id; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].trfMode = m2ua_cluster_iface->trfMode; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].loadShareAlgo = m2ua_cluster_iface->loadShareAlgo; + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].numOfPeers = m2ua_cluster_iface->numOfPeers; + for(k=0;knumOfPeers;k++){ + g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[i].peerIdLst[k] = m2ua_cluster_iface->peerIdLst[k]; + } + + return 0; +} + +/******************************************************************************/ +int ftmod_ss7_parse_sctp_links(ftdm_conf_node_t *node) +{ + ftdm_conf_node_t *node_sctp_link = NULL; + + if (!node) + return FTDM_FAIL; + + if (strcasecmp(node->name, "sng_sctp_interfaces")) { + SS7_ERROR("SCTP - We're looking at <%s>...but we're supposed to be looking at !\n", node->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("SCTP - Parsing configurations\n"); + } + + for (node_sctp_link = node->child; node_sctp_link != NULL; node_sctp_link = node_sctp_link->next) { + if (ftmod_ss7_parse_sctp_link(node_sctp_link) != FTDM_SUCCESS) { + SS7_ERROR("SCTP - Failed to parse . \n"); + return FTDM_FAIL; + } + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static int ftmod_ss7_parse_sctp_link(ftdm_conf_node_t *node) +{ + ftdm_conf_parameter_t *param = NULL; + int num_params = 0; + int i=0; + + if (!node){ + SS7_ERROR("SCTP - NULL XML Node pointer \n"); + return FTDM_FAIL; + } + + param = node->parameters; + num_params = node->n_parameters; + + sng_sctp_link_t t_link; + memset (&t_link, 0, sizeof(sng_sctp_link_t)); + + if (strcasecmp(node->name, "sng_sctp_interface")) { + SS7_ERROR("SCTP - We're looking at <%s>...but we're supposed to be looking at !\n", node->name); + return FTDM_FAIL; + } else { + SS7_DEBUG("SCTP - Parsing configurations\n"); + } + + for (i=0; ivar, "name")) { + int n_strlen = strlen(param->val); + strncpy((char*)t_link.name, param->val, (n_strlen>MAX_NAME_LEN)?MAX_NAME_LEN:n_strlen); + SS7_DEBUG("SCTP - Parsing with name = %s\n", param->val); + } + else if (!strcasecmp(param->var, "id")) { + t_link.id = atoi(param->val); + SS7_DEBUG("SCTP - Parsing with id = %s\n", param->val); + } + else if (!strcasecmp(param->var, "address")) { + if (t_link.numSrcAddr < SCT_MAX_NET_ADDRS) { + t_link.srcAddrList[t_link.numSrcAddr+1] = iptoul (param->val); + t_link.numSrcAddr++; + SS7_DEBUG("SCTP - Parsing with source IP Address = %s\n", param->val); + } else { + SS7_ERROR("SCTP - too many source address configured. dropping %s \n", param->val); + } + } else if (!strcasecmp(param->var, "source-port")) { + t_link.port = atoi(param->val); + SS7_DEBUG("SCTP - Parsing with port = %s\n", param->val); + } + else { + SS7_ERROR("SCTP - Found an unknown parameter <%s>. Skipping it.\n", param->var); + } + } + + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].id = t_link.id; + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].port = t_link.port; + strncpy((char*)g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].name, t_link.name, strlen(t_link.name) ); + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].numSrcAddr = t_link.numSrcAddr; + for (i=1; i<=t_link.numSrcAddr; i++) { + g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[t_link.id].srcAddrList[i] = t_link.srcAddrList[i]; + } + + sngss7_set_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SCTP_PRESENT); + + return FTDM_SUCCESS; +} +/******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 049aa1546d..55b95f6acf 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -35,6 +35,7 @@ * * Moises Silva * David Yat Sin + * James Zhang * */ @@ -49,12 +50,14 @@ static sng_isup_event_interface_t sng_event; static ftdm_io_interface_t g_ftdm_sngss7_interface; ftdm_sngss7_data_t g_ftdm_sngss7_data; +ftdm_sngss7_opr_mode g_ftdm_operating_mode; /******************************************************************************/ /* PROTOTYPES *****************************************************************/ static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj); static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_event); +static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, sngss7_event_data_t *sngss7_event); static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span); static ftdm_status_t ftdm_sangoma_ss7_start (ftdm_span_t * span); @@ -289,24 +292,45 @@ static void handle_hw_alarm(ftdm_event_t *e) int x = 0; ftdm_assert(e != NULL, "Null event!\n"); + + SS7_DEBUG("handle_hw_alarm event [%d/%d]\n",e->channel->physical_span_id,e->channel->physical_chan_id); for (x = (g_ftdm_sngss7_data.cfg.procId * MAX_CIC_MAP_LENGTH) + 1; g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0; x++) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + + /* NC. Its possible for alarms to come in the middle of configuration + especially on large systems */ + if (!ss7_info || !ss7_info->ftdmchan) { + SS7_DEBUG("handle_hw_alarm: span=%i chan=%i ckt=%i x=%i - ss7_info=%p ftdmchan=%p\n", + ftdmchan->physical_span_id,ftdmchan->physical_chan_id, + g_ftdm_sngss7_data.cfg.isupCkt[x].id,x, + ss7_info,ss7_info?ss7_info->ftdmchan:NULL); + continue; + } + ftdmchan = ss7_info->ftdmchan; - if (e->channel->span_id == ftdmchan->physical_span_id && - e->channel->chan_id == ftdmchan->physical_chan_id) { + if (e->channel->physical_span_id == ftdmchan->physical_span_id && + e->channel->physical_chan_id == ftdmchan->physical_chan_id) { + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: span=%i chan=%i ckt=%i x=%i\n", + ftdmchan->physical_span_id,ftdmchan->physical_chan_id,g_ftdm_sngss7_data.cfg.isupCkt[x].id,x); if (e->enum_id == FTDM_OOB_ALARM_TRAP) { + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Set FLAG_GRP_HW_BLOCK_TX %s\n", " "); sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } - } else { - sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + } else if (e->enum_id == FTDM_OOB_ALARM_CLEAR) { + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Clear %s \n", " "); sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX); - if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + sngss7_clear_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + if (sngss7_test_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX_DN)) { + sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_UNBLK_TX); + SS7_DEBUG_CHAN(ftdmchan,"handle_hw_alarm: Setting FLAG_GRP_HW_UNBLK_TX %s\n"," "); + if (ftdmchan->state != FTDM_CHANNEL_STATE_SUSPENDED) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } } } } @@ -314,14 +338,38 @@ static void handle_hw_alarm(ftdm_event_t *e) } } + +static void check_span_oob_events(ftdm_span_t *ftdmspan) +{ + ftdm_event_t *event = NULL; + /* Poll for events, e.g HW DTMF */ + switch (ftdm_span_poll_event(ftdmspan, 0, NULL)) { + /**********************************************************************/ + case FTDM_SUCCESS: + while (ftdm_span_next_event(ftdmspan, &event) == FTDM_SUCCESS) { + if (event->e_type == FTDM_EVENT_OOB) { + handle_hw_alarm(event); + } + } + break; + /**********************************************************************/ + case FTDM_TIMEOUT: + /* No events pending */ + break; + /**********************************************************************/ + default: + SS7_ERROR("%s:Failed to poll span event\n", ftdmspan->name); + /**********************************************************************/ + } +} + /* MONITIOR THREADS ***********************************************************/ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) { ftdm_interrupt_t *ftdm_sangoma_ss7_int[2]; ftdm_span_t *ftdmspan = (ftdm_span_t *) obj; ftdm_channel_t *ftdmchan = NULL; - ftdm_event_t *event = NULL; - sngss7_event_data_t *sngss7_event = NULL; + sngss7_event_data_t *sngss7_event = NULL; sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data; int b_alarm_test = 1; @@ -332,6 +380,8 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /* set IN_THREAD flag so that we know this thread is running */ ftdm_set_flag (ftdmspan, FTDM_SPAN_IN_THREAD); + + /* get an interrupt queue for this span for channel state changes */ if (ftdm_queue_get_interrupt (ftdmspan->pendingchans, &ftdm_sangoma_ss7_int[0]) != FTDM_SUCCESS) { SS7_CRITICAL ("Failed to get a ftdm_interrupt for span = %d for channel state changes!\n", ftdmspan->span_id); @@ -344,6 +394,42 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) goto ftdm_sangoma_ss7_run_exit; } + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + ftdm_log (FTDM_LOG_INFO, "FreeTDM running as M2UA_SG mode, freetdm dont have to do anything \n"); + + while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { + + switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, ftdm_array_len(ftdm_sangoma_ss7_int), 100))) { + + case FTDM_SUCCESS: /* process all pending state changes */ + + SS7_DEVEL_DEBUG ("ftdm_interrupt_wait FTDM_SUCCESS on span = %d\n",ftdmspan->span_id); + + /**********************************************************************/ + case FTDM_TIMEOUT: + SS7_DEVEL_DEBUG ("ftdm_interrupt_wait timed-out on span = %d\n",ftdmspan->span_id); + + break; + /**********************************************************************/ + case FTDM_FAIL: + SS7_ERROR ("ftdm_interrupt_wait returned error!\non span = %d\n", ftdmspan->span_id); + + break; + /**********************************************************************/ + default: + SS7_ERROR("ftdm_interrupt_wait returned with unknown code on span = %d\n",ftdmspan->span_id); + + break; + /**********************************************************************/ + } + check_span_oob_events(ftdmspan); + + /* signal the core that sig events are queued for processing */ + ftdm_span_trigger_signals(ftdmspan); + } + goto ftdm_sangoma_ss7_stop; + } + while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) { int x = 0; if (b_alarm_test) { @@ -360,9 +446,12 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) if (ftdmchan->alarm_flags != 0) { /* we'll send out block */ sngss7_set_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX ); } else { /* we'll send out reset */ - sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX ); - sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX_DN ); - sngss7_set_ckt_blk_flag (ss7_info, FLAG_GRP_HW_UNBLK_TX); + if (sngss7_test_ckt_blk_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX )) { + sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX ); + sngss7_clear_ckt_blk_flag( ss7_info, FLAG_GRP_HW_BLOCK_TX_DN ); + sngss7_set_ckt_blk_flag (ss7_info, FLAG_GRP_HW_UNBLK_TX); + SS7_DEBUG("b_alarm_test FLAG_GRP_HW_UNBLK_TX\n"); + } } } usleep(50); @@ -371,18 +460,27 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) } /* check the channel state queue for an event*/ - switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, 2, 100))) { + switch ((ftdm_interrupt_multiple_wait(ftdm_sangoma_ss7_int, ftdm_array_len(ftdm_sangoma_ss7_int), 100))) { /**********************************************************************/ case FTDM_SUCCESS: /* process all pending state changes */ /* clean out all pending channel state changes */ while ((ftdmchan = ftdm_queue_dequeue (ftdmspan->pendingchans))) { + sngss7_chan_data_t *chan_info = ftdmchan->call_data; /*first lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); /* process state changes for this channel until they are all done */ ftdm_channel_advance_states(ftdmchan); + + if (chan_info->peer_data) { + /* clean out all pending stack events in the peer channel */ + while ((sngss7_event = ftdm_queue_dequeue(chan_info->event_queue))) { + ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event); + ftdm_safe_free(sngss7_event); + } + } /* unlock the channel */ ftdm_mutex_unlock (ftdmchan->mutex); @@ -441,31 +539,15 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /* check each channel on the span to see if it needs to be reconfigured */ check_for_reconfig_flag(ftdmspan); - - /* Poll for events, e.g HW DTMF */ - switch (ftdm_span_poll_event(ftdmspan, 0, NULL)) { - /**********************************************************************/ - case FTDM_SUCCESS: - while (ftdm_span_next_event(ftdmspan, &event) == FTDM_SUCCESS) { - if (event->e_type == FTDM_EVENT_OOB) { - handle_hw_alarm(event); - } - } - break; - /**********************************************************************/ - case FTDM_TIMEOUT: - /* No events pending */ - break; - /**********************************************************************/ - default: - SS7_ERROR("%s:Failed to poll span event\n", ftdmspan->name); - /**********************************************************************/ - } + + check_span_oob_events(ftdmspan); } +ftdm_sangoma_ss7_stop: /* clear the IN_THREAD flag so that we know the thread is done */ ftdm_clear_flag (ftdmspan, FTDM_SPAN_IN_THREAD); + ftdm_log (FTDM_LOG_INFO,"ftmod_sangoma_ss7 monitor thread for span=%u stopping.\n",ftdmspan->span_id); return NULL; @@ -487,6 +569,8 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev { sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + sngss7_event_data_t *event_clone = NULL; + int clone_event = 0; /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(sngss7_event->circuit, &sngss7_info, &ftdmchan)) { @@ -500,6 +584,95 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev /* while there's a state change present on this channel process it */ ftdm_channel_advance_states(ftdmchan); + if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) { + clone_event++; + } + + /* If the call has already started (we only bridge events related to calls) + * and the event is not a release confirmation, then clone the event. + * We do not clone release cfm events because that is the only event (final event) that is not + * bridged to the other leg, the first Spirou customer we had explicitly requested to send + * release confirm as soon as the release is received and therefore not wait for the other leg + * to send release confirm (hence, not need to clone and enqueue in the other leg) */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED) && sngss7_event->event_id != SNGSS7_REL_CFM_EVENT) { + clone_event++; + } + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + + if (sngss7_event->event_id == SNGSS7_SUSP_IND_EVENT) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SUS_RECVD); + sngss7_clear_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + } + + if (sngss7_test_ckt_flag(sngss7_info, FLAG_SUS_RECVD) && + !sngss7_test_ckt_flag(sngss7_info, FLAG_T6_CANCELED)) { + if (sng_cancel_isup_tmr(sngss7_info->suInstId, ISUP_T6i) == RFAILED ) { + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not stop timer T6 \n", sngss7_info->circuit->cic); + } else { + sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d] isup timer T6 has been cancelled. \n", sngss7_info->circuit->cic); + } + } + } + + /* clone the event and save it for later usage, we do not clone RLC messages */ + if (clone_event) { + event_clone = ftdm_calloc(1, sizeof(*sngss7_event)); + if (event_clone) { + memcpy(event_clone, sngss7_event, sizeof(*sngss7_event)); + /* if we have already a peer channel then enqueue the event in their queue */ + if (sngss7_info->peer_data) { + ftdm_span_t *peer_span = sngss7_info->peer_data->ftdmchan->span; + if (sngss7_info->peer_event_transfer_cnt) { + sngss7_event_data_t *peer_event = NULL; + int qi = 0; + /* looks like for the first time we found our peer, transfer any messages we enqueued */ + for (qi = 0; qi < sngss7_info->peer_event_transfer_cnt; qi++) { + peer_event = ftdm_queue_dequeue(sngss7_info->event_queue); + if (peer_event) { + ftdm_queue_enqueue(sngss7_info->peer_data->event_queue, peer_event); + } else { + /* This should never happen! */ + SS7_CRIT_CHAN(ftdmchan,"[CIC:%d]What!? someone stole my messages!\n", sngss7_info->circuit->cic); + } + } + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Transferred %d messages into my peer's queue\n", + sngss7_info->circuit->cic, sngss7_info->peer_event_transfer_cnt); + sngss7_info->peer_event_transfer_cnt = 0; + } + /* we already have a peer attached, wake him up */ + ftdm_queue_enqueue(sngss7_info->peer_data->event_queue, event_clone); + ftdm_queue_enqueue(peer_span->pendingchans, sngss7_info->peer_data->ftdmchan); + } else { + /* we don't have a peer yet, save the event on our own queue for later + * only the first event in this queue is directly consumed by our peer (IAM), subsequent events + * must be transferred by us to their queue as soon as we find our peer */ + ftdm_queue_enqueue(sngss7_info->event_queue, event_clone); + if (sngss7_event->event_id != SNGSS7_CON_IND_EVENT) { + /* This could be an SAM, save it for transfer once we know who our peer is (if we ever find that) */ + sngss7_info->peer_event_transfer_cnt++; + } + } + } + } + + /* we could test for sngss7_info->peer_data too, bit this flag is set earlier, the earlier we know the better */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + /* most messages are simply relayed in sig bridge mode, except for hangup which requires state changing */ + switch (sngss7_event->event_id) { + case SNGSS7_REL_IND_EVENT: + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + break; + case SNGSS7_REL_CFM_EVENT: + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + break; + default: + break; + } + goto done; + } + /* figure out the type of event and send it to the right handler */ switch (sngss7_event->event_id) { /**************************************************************************/ @@ -552,6 +725,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev break; /**************************************************************************/ case (SNGSS7_SSP_STA_CFM_EVENT): + SS7_ERROR("dazed and confused ... hu?!\n"); break; /**************************************************************************/ default: @@ -560,6 +734,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev /**************************************************************************/ } +done: /* while there's a state change present on this channel process it */ ftdm_channel_advance_states(ftdmchan); @@ -568,15 +743,372 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev } +FTDM_ENUM_NAMES(SNG_EVENT_TYPE_NAMES, SNG_EVENT_TYPE_STRINGS) +FTDM_STR2ENUM(ftdm_str2sngss7_event, ftdm_sngss7_event2str, sng_event_type_t, SNG_EVENT_TYPE_NAMES, SNGSS7_INVALID_EVENT) +static void ftdm_sangoma_ss7_process_peer_stack_event (ftdm_channel_t *ftdmchan, sngss7_event_data_t *sngss7_event) +{ + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (ftdmchan->state < FTDM_CHANNEL_STATE_UP && ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); + ftdm_channel_advance_states(ftdmchan); + } + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Receiving message %s from bridged peer (our state = %s)\n", + sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id), ftdm_channel_state2str(ftdmchan->state)); + + switch (sngss7_event->event_id) { + + case (SNGSS7_CON_IND_EVENT): + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]Rx IAM while bridged??\n", sngss7_info->circuit->cic); + break; + + case (SNGSS7_CON_CFM_EVENT): + /* send the ANM request to LibSngSS7 */ + sng_cc_con_response(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siConEvnt, + 5); + + SS7_INFO_CHAN(ftdmchan, "[CIC:%d]Tx peer ANM\n", sngss7_info->circuit->cic); + break; + + case (SNGSS7_CON_STA_EVENT): + switch (sngss7_event->evntType) { + /**************************************************************************/ + case (ADDRCMPLT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ACM\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MODIFY): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MODCMPLT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY-COMPLETE\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MODREJ): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MODIFY-REJECT\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (PROGRESS): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CPG\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (FRWDTRSFR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer FOT\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (INFORMATION): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer INF\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (INFORMATREQ): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer INR\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (SUBSADDR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer SAM\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (EXIT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer EXIT\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (NETRESMGT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer NRM\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (IDENTREQ): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer IDR\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (IDENTRSP): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer IRS\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (MALCLLPRNT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer MALICIOUS CALL\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CHARGE): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (TRFFCHGE): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG-TARIFF\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CHARGEACK): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CRG-ACK\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CALLOFFMSG): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALL-OFFER\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (LOOPPRVNT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer LOP\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (TECT_TIMEOUT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ECT-Timeout\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (RINGSEND): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer RINGING-SEND\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CALLCLEAR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALL-LINE Clear\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (PRERELEASE): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer PRI\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (APPTRANSPORT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer APM\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (OPERATOR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer OPERATOR\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (METPULSE): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer METERING-PULSE\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (CLGPTCLR): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer CALLING_PARTY_CLEAR\n", sngss7_info->circuit->cic); + break; + /**************************************************************************/ + case (SUBDIRNUM): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer SUB-DIR\n", sngss7_info->circuit->cic); + break; +#ifdef SANGOMA_SPIROU + case (CHARGE_ACK): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer TXA\n", sngss7_info->circuit->cic); + break; + case (CHARGE_UNIT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer ITX\n", sngss7_info->circuit->cic); + break; +#endif + /**************************************************************************/ + default: + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer Unknown Msg %d\n", sngss7_info->circuit->cic, sngss7_event->evntType); + break; + /**************************************************************************/ + } + sng_cc_con_status (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siCnStEvnt, + sngss7_event->evntType); + + break; + /**************************************************************************/ + case (SNGSS7_REL_IND_EVENT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer REL cause=%d\n", sngss7_info->circuit->cic, sngss7_event->event.siRelEvnt.causeDgn.causeVal.val); + + //handle_rel_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siRelEvnt); + sng_cc_rel_request (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siRelEvnt); + break; + + /**************************************************************************/ + case (SNGSS7_REL_CFM_EVENT): + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer RLC\n", sngss7_info->circuit->cic); + sng_cc_rel_response (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siRelEvnt); + //handle_rel_cfm(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siRelEvnt); + break; + + /**************************************************************************/ + case (SNGSS7_DAT_IND_EVENT): + //handle_dat_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siInfoEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + sng_cc_dat_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siInfoEvnt); + break; + /**************************************************************************/ + case (SNGSS7_FAC_IND_EVENT): + //handle_fac_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->evntType, + //&sngss7_event->event.siFacEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s -> %d\n", sngss7_info->circuit->cic, + ftdm_sngss7_event2str(sngss7_event->event_id), sngss7_event->evntType); + sng_cc_fac_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + sngss7_event->evntType, + &sngss7_event->event.siFacEvnt); + + break; + /**************************************************************************/ + case (SNGSS7_FAC_CFM_EVENT): + //handle_fac_cfm(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, + //sngss7_event->evntType, &sngss7_event->event.siFacEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s -> %d\n", sngss7_info->circuit->cic, + ftdm_sngss7_event2str(sngss7_event->event_id), sngss7_event->evntType); + sng_cc_fac_response(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + sngss7_event->evntType, + &sngss7_event->event.siFacEvnt); + break; + /**************************************************************************/ + case (SNGSS7_UMSG_IND_EVENT): + //handle_umsg_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + sng_cc_umsg_request (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id); + break; + /**************************************************************************/ + case (SNGSS7_STA_IND_EVENT): + //handle_sta_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->globalFlg, sngss7_event->evntType, &sngss7_event->event.siStaEvnt); + break; + /**************************************************************************/ + case (SNGSS7_SUSP_IND_EVENT): + //handle_susp_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siSuspEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + sng_cc_susp_request (1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siSuspEvnt); + break; + /**************************************************************************/ + case (SNGSS7_RESM_IND_EVENT): + //handle_resm_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siResmEvnt); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx peer %s\n", sngss7_info->circuit->cic, ftdm_sngss7_event2str(sngss7_event->event_id)); + sng_cc_resm_request(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &sngss7_event->event.siResmEvnt); + break; + /**************************************************************************/ + case (SNGSS7_SSP_STA_CFM_EVENT): + SS7_CRITICAL("dazed and confused ... hu?!\n"); + break; + /**************************************************************************/ + default: + SS7_ERROR("Failed to relay unknown event id %d!\n", sngss7_event->event_id); + break; + /**************************************************************************/ + } + + if ((sngss7_event->event_id == SNGSS7_SUSP_IND_EVENT)) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SUS_RECVD); + } + + if (sngss7_test_ckt_flag(sngss7_info, FLAG_SUS_RECVD) && + !sngss7_test_ckt_flag(sngss7_info, FLAG_T6_CANCELED)) { + if (sng_cancel_isup_tmr(sngss7_info->suInstId, ISUP_T6i) == RFAILED ) { + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d]could not stop timer T6 \n", sngss7_info->circuit->cic); + } else { + sngss7_set_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + SS7_ERROR_CHAN(ftdmchan,"[CIC:%d] isup timer T6 has been cancelled. \n", sngss7_info->circuit->cic); + } + } +} + +static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t *ftdmchan); +static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t *ftdmchan) +{ + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + ftdm_channel_complete_state(ftdmchan); + + switch (ftdmchan->state) { + + case FTDM_CHANNEL_STATE_DOWN: + { + ftdm_channel_t *close_chan = ftdmchan; + sngss7_clear_ckt_flag(sngss7_info, FLAG_SUS_RECVD); + sngss7_clear_ckt_flag(sngss7_info, FLAG_T6_CANCELED); + sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_ACM); + sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_CPG); + + sngss7_flush_queue(sngss7_info->event_queue); + sngss7_info->peer_data = NULL; + ftdm_channel_close (&close_chan); + } + break; + + case FTDM_CHANNEL_STATE_UP: + { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_UP); + } + } + break; + + case FTDM_CHANNEL_STATE_TERMINATING: + { + /* Release confirm is sent immediately, since Spirou customer asked us not to wait for the second call leg + * to come back with a release confirm ... */ + /* when receiving REL we move to TERMINATING and notify the user that the bridge is ending */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USER_HANGUP)) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + } else { + /* Notify the user and wait for their ack before sending RLC */ + sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP); + } + } + break; + + case FTDM_CHANNEL_STATE_HANGUP: + { + ft_to_sngss7_rlc(ftdmchan); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } + break; + + default: + break; + } + + return FTDM_SUCCESS; +} + /******************************************************************************/ -ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) +ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan) { sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; sng_isup_inf_t *isup_intf = NULL; int state_flag = 1; int i = 0; - SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s\n", ftdm_channel_state2str (ftdmchan->state)); + SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s: ckt=0x%X, blk=0x%X\n", + ftdm_channel_state2str (ftdmchan->state), + sngss7_info->ckt_flags, + sngss7_info->blk_flags); + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + /* DIALING is the only state we process normally when doing an outgoing call that is natively bridged, + * all other states are run by a different state machine (and the freetdm core does not do any checking) */ + if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) { + return ftdm_sangoma_ss7_native_bridge_state_change(ftdmchan); + } + } /*check what state we are supposed to be in */ switch (ftdmchan->state) { @@ -598,23 +1130,91 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } /* check if the end of pulsing (ST) character has arrived or the right number of digits */ - if (ftdmchan->caller_data.dnis.digits[i-1] == 'F') { + if (ftdmchan->caller_data.dnis.digits[i-1] == 'F' + || sngss7_test_ckt_flag(sngss7_info, FLAG_FULL_NUMBER) ) + { SS7_DEBUG_CHAN(ftdmchan, "Received the end of pulsing character %s\n", ""); - /* remove the ST */ - ftdmchan->caller_data.dnis.digits[i-1] = '\0'; - - /*now go to the RING state */ - state_flag = 0; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_FULL_NUMBER)) { + /* remove the ST */ + ftdmchan->caller_data.dnis.digits[i-1] = '\0'; + sngss7_set_ckt_flag(sngss7_info, FLAG_FULL_NUMBER); + } + if (sngss7_test_ckt_flag(sngss7_info, FLAG_INR_TX)) { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_INR_SENT) ) { + ft_to_sngss7_inr(ftdmchan); + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_SENT); + + SS7_DEBUG_CHAN (ftdmchan, "Scheduling T.39 timer %s \n", " "); + + /* start ISUP t39 */ + if (ftdm_sched_timer (sngss7_info->t39.sched, + "t39", + sngss7_info->t39.beat, + sngss7_info->t39.callback, + &sngss7_info->t39, + &sngss7_info->t39.hb_timer_id)) + { + + SS7_ERROR ("Unable to schedule timer T39, hanging up call!\n"); + + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; + sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + + /* end the call */ + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + } + }else { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } + } else { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } } else if (i >= sngss7_info->circuit->min_digits) { SS7_DEBUG_CHAN(ftdmchan, "Received %d digits (min digits = %d)\n", i, sngss7_info->circuit->min_digits); - /*now go to the RING state */ - state_flag = 0; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); - + if (sngss7_test_ckt_flag(sngss7_info, FLAG_INR_TX)) { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_INR_SENT) ) { + ft_to_sngss7_inr(ftdmchan); + sngss7_set_ckt_flag(sngss7_info, FLAG_INR_SENT); + + SS7_DEBUG_CHAN (ftdmchan, "Scheduling T.39 timer %s\n", " " ); + + /* start ISUP t39 */ + if (ftdm_sched_timer (sngss7_info->t39.sched, + "t39", + sngss7_info->t39.beat, + sngss7_info->t39.callback, + &sngss7_info->t39, + &sngss7_info->t39.hb_timer_id)) + { + + SS7_ERROR ("Unable to schedule timer T39, hanging up call!\n"); + + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; + sngss7_set_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + + /* end the call */ + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + } + + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_IDLE); + }else { + if (sngss7_test_ckt_flag(sngss7_info, FLAG_INF_RX_DN) ) { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } + } + } else { + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } } else { /* if we are coming from idle state then we have already been here once before */ if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) { @@ -670,6 +1270,15 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /**************************************************************************/ case FTDM_CHANNEL_STATE_RING: /*incoming call request */ + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_SENT); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INR_RX_DN); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_TX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_SENT); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INF_RX_DN); + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); break; @@ -680,6 +1289,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) ftdm_sched_cancel_timer (sngss7_info->t35.sched, sngss7_info->t35.hb_timer_id); } + /* cancel t39 timer */ + if (sngss7_info->t39.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id); + } + SS7_DEBUG_CHAN(ftdmchan, "Sending incoming call from %s to %s to FTDM core\n", ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.dnis.digits); @@ -729,6 +1343,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_ACM); ft_to_sngss7_acm(ftdmchan); } + if (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].cpg_on_progress == FTDM_TRUE) { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_SENT_CPG)) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_CPG); + ft_to_sngss7_cpg(ftdmchan); + } + } } break; @@ -748,7 +1368,12 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_ACM); ft_to_sngss7_acm(ftdmchan); } - ft_to_sngss7_cpg(ftdmchan); + if (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].cpg_on_progress_media == FTDM_TRUE) { + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_SENT_CPG)) { + sngss7_set_ckt_flag(sngss7_info, FLAG_SENT_CPG); + ft_to_sngss7_cpg(ftdmchan); + } + } } break; @@ -798,6 +1423,14 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /*this state is set when the line is hanging up */ sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP); + + /* If the RESET flag is set, do not say in TERMINATING state. + Go back to RESTART state and wait for RESET Confirmation */ + if (sngss7_tx_reset_status_pending(sngss7_info)) { + SS7_DEBUG_CHAN(ftdmchan,"Reset pending in Terminating state!%s\n", ""); + state_flag = 0; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } break; /**************************************************************************/ @@ -840,19 +1473,24 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } if (sngss7_test_ckt_flag (sngss7_info, FLAG_REMOTE_REL)) { + + sngss7_clear_ckt_flag (sngss7_info, FLAG_LOCAL_REL); + /* check if this hangup is from a tx RSC */ if (sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX)) { if (!sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_SENT)) { ft_to_sngss7_rsc (ftdmchan); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_SENT); - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + + /* Wait for Reset in HANGUP Complete nothing to do until we + get reset response back */ } else if (sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_TX_RSP)) { state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } else { - /* go to RESTART State until RSCa is received */ - state_flag = 0; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + /* Stay in hangup complete until RSC is received */ + /* Channel is in use if we go to RESTART we will + restart will just come back to HANGUP_COMPLETE */ } } else { /* if the hangup is from a rx RSC, rx GRS, or glare don't sent RLC */ @@ -871,7 +1509,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"Completing remotely requested hangup!%s\n", ""); } else if (sngss7_test_ckt_flag (sngss7_info, FLAG_LOCAL_REL)) { - + /* if this hang up is do to a rx RESET we need to sit here till the RSP arrives */ if (sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX_RSP)) { /* go to the down state as we have already received RSC-RLC */ @@ -887,16 +1525,21 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } else { SS7_DEBUG_CHAN(ftdmchan,"Completing requested hangup for unknown reason!%s\n", ""); + if (sngss7_channel_status_clear(sngss7_info)) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } } break; /**************************************************************************/ case FTDM_CHANNEL_STATE_DOWN: /*the call is finished and removed */ - - if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { - SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); - break; + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) { + SS7_DEBUG_CHAN(ftdmchan,"Down came from SUSPEND - break %s\n", ""); + break; + } } /* check if there is a reset response that needs to be sent */ @@ -953,23 +1596,25 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) !(sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_RX)) && !(sngss7_test_ckt_flag (sngss7_info, FLAG_GRP_RESET_TX)) && !(sngss7_test_ckt_flag (sngss7_info, FLAG_GRP_RESET_RX))) { + + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X\n", + sngss7_info->ckt_flags, + sngss7_info->blk_flags); - /* now check if there is an active block */ - if (!(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX)) && - !(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_HW_BLOCK_RX)) && - !(sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_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_TX))) { - + if (sngss7_channel_status_clear(sngss7_info)) { /* check if the sig status is down, and bring it up if it isn't */ if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) { SS7_DEBUG_CHAN(ftdmchan,"All reset flags cleared %s\n", ""); /* all flags are down so we can bring up the sig status */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - } /* if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) */ - } /* if !blocked */ + } + } else { + state_flag = 0; + SS7_DEBUG_CHAN(ftdmchan,"Down detected blocked flags go to SUSPEND %s\n", " "); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + break; + + } } else { SS7_DEBUG_CHAN(ftdmchan,"Reset flags present (0x%X)\n", sngss7_info->ckt_flags); @@ -977,7 +1622,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); } - } /* if ((ftdmchan->last_state == FTDM_CHANNEL_STATE_RESTART) */ + } /* check if t35 is active */ if (sngss7_info->t35.hb_timer_id) { @@ -994,37 +1639,71 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_flag (sngss7_info, FLAG_REMOTE_REL); sngss7_clear_ckt_flag (sngss7_info, FLAG_LOCAL_REL); sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_ACM); + sngss7_clear_ckt_flag (sngss7_info, FLAG_SENT_CPG); if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) { ftdm_channel_t *close_chan = ftdmchan; /* close the channel */ + SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", ""); + sngss7_flush_queue(sngss7_info->event_queue); ftdm_channel_close (&close_chan); } /* check if there is a glared call that needs to be processed */ if (sngss7_test_ckt_flag(sngss7_info, FLAG_GLARE)) { - - /* clear the glare flag */ sngss7_clear_ckt_flag (sngss7_info, FLAG_GLARE); - /* check if we have an IAM stored...if we don't have one just exit */ if (sngss7_info->glare.circuit != 0) { - /* send the saved call back in to us */ - handle_con_ind (0, - sngss7_info->glare.spInstId, - sngss7_info->glare.circuit, - &sngss7_info->glare.iam); + int bHandle=0; + switch (g_ftdm_sngss7_data.cfg.glareResolution) { + case SNGSS7_GLARE_DOWN: + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Giving control to the other side, handling copied IAM from glare. \n", sngss7_info->circuit->cic); + bHandle = 1; + break; + case SNGSS7_GLARE_PC: + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Trying to handle IAM copied from glare. \n", sngss7_info->circuit->cic); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]My PC = %d, incoming PC = %d. \n", sngss7_info->circuit->cic, + g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc, + g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ); + + if( g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].spc > g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].dpc ) + { + if ((sngss7_info->circuit->cic % 2) == 1 ) { + bHandle = 1; + } + } else { + if( (sngss7_info->circuit->cic % 2) == 0 ) { + bHandle = 1; + } + } + + break; + default: /* if configured as SNGSS7_GLARE_CONTROL, always abandon incoming glared IAM. */ + bHandle = 0; + break; + } + + if (!bHandle) { + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Handling glare IAM. \n", sngss7_info->circuit->cic); + handle_con_ind (0, sngss7_info->glare.spInstId, sngss7_info->glare.circuit, &sngss7_info->glare.iam); + } + /* clear the glare info */ memset(&sngss7_info->glare, 0x0, sizeof(sngss7_glare_data_t)); + state_flag = 0; } } break; /**************************************************************************/ case FTDM_CHANNEL_STATE_RESTART: /* CICs needs a Reset */ - + + SS7_DEBUG_CHAN(ftdmchan,"RESTART: Current flags: ckt=0x%X, blk=0x%X\n", + sngss7_info->ckt_flags, + sngss7_info->blk_flags); + if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK)) { if ((sngss7_test_ckt_flag(sngss7_info, FLAG_RESET_RX)) || (sngss7_test_ckt_flag(sngss7_info, FLAG_GRP_RESET_RX))) { @@ -1131,6 +1810,7 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) state_flag = 0; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } else { + SS7_DEBUG_CHAN(ftdmchan, "Waiting on Reset Rsp/Grp Reset to move to DOWN (0x%X)\n", sngss7_info->ckt_flags); } } @@ -1139,10 +1819,27 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /**************************************************************************/ case FTDM_CHANNEL_STATE_SUSPENDED: /* circuit has been blocked */ - SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X\n", - sngss7_info->ckt_flags, - sngss7_info->blk_flags); - + SS7_DEBUG_CHAN(ftdmchan,"SUSPEND: Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", + sngss7_info->ckt_flags, sngss7_info->blk_flags, + sngss7_info->circuit->flags ); + + if (!(sngss7_info->circuit->flags & SNGSS7_CONFIGURED)) { + /* Configure the circuit if RESUME and PAUSED are not set. + And also in a case when RESUME is set */ + if (!sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED) || + sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME)) { + if (ftmod_ss7_isup_ckt_config(sngss7_info->circuit->id)) { + SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", sngss7_info->circuit->id); + sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); + sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_RESUME); + } else { + SS7_INFO("ISUP CKT %d configuration DONE!\n", sngss7_info->circuit->id); + sngss7_info->circuit->flags |= SNGSS7_CONFIGURED; + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + } + } + } + /**********************************************************************/ if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_RESUME)) { @@ -1154,14 +1851,45 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the PAUSE flag */ sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); - /* if there are any resets present */ - if ((sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_TX)) || - (sngss7_test_ckt_flag (sngss7_info, FLAG_RESET_RX)) || - (sngss7_test_ckt_flag (sngss7_info, FLAG_GRP_RESET_TX)) || - (sngss7_test_ckt_flag (sngss7_info, FLAG_GRP_RESET_RX))) { + /* We tried to hangup the call while in PAUSED state. + We must send a RESET to clear this circuit */ + if (sngss7_test_ckt_flag (sngss7_info, FLAG_LOCAL_REL)) { + SS7_DEBUG_CHAN(ftdmchan, "Channel local release on RESUME, restart Reset procedure%s\n", ""); + /* By setting RESET_TX flag the check below sngss7_tx_reset_status_pending() will + be true, and will restart the RESET TX procedure */ + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + sngss7_set_ckt_flag (sngss7_info, FLAG_RESET_TX); + } + /* We have transmitted Reset/GRS but have not gotten a + * Response. In mean time we got a RESUME. We cannot be sure + * that our reset has been trasmitted, thus restart reset procedure. */ + if (sngss7_tx_reset_status_pending(sngss7_info)) { + SS7_DEBUG_CHAN(ftdmchan, "Channel transmitted RSC/GRS before RESUME, restart Reset procedure%s\n", ""); + clear_rx_grs_flags(sngss7_info); + clear_rx_grs_data(sngss7_info); + clear_tx_grs_flags(sngss7_info); + clear_tx_grs_data(sngss7_info); + clear_rx_rsc_flags(sngss7_info); + clear_tx_rsc_flags(sngss7_info); + + clear_tx_rsc_flags(sngss7_info); + sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); + } + + /* if there are any resets present */ + if (!sngss7_channel_status_clear(sngss7_info)) { /* don't bring up the sig status but also move to reset */ - goto suspend_goto_restart; + if (!sngss7_reset_status_clear(sngss7_info)) { + goto suspend_goto_restart; + } else if (!sngss7_block_status_clear(sngss7_info)) { + /* Do nothing just go through and handle blocks below */ + } else { + /* This should not happen as above function tests + * for reset and blocks */ + SS7_ERROR_CHAN(ftdmchan, "Invalid code path: sngss7_channel_status_clear reset and block are both cleared%s\n", ""); + goto suspend_goto_restart; + } } else { /* bring the sig status back up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); @@ -1176,6 +1904,9 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status down */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); } + + /* Wait for RESUME */ + goto suspend_goto_last; } /* if (sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) { */ /**********************************************************************/ @@ -1193,8 +1924,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_RX)){ @@ -1207,17 +1936,18 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_RX); + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X\n", + sngss7_info->ckt_flags, + sngss7_info->blk_flags); /* not bring the cic up if there is a hardware block */ - if( !sngss7_test_ckt_blk_flag(sngss7_info, (FLAG_GRP_HW_BLOCK_TX | FLAG_GRP_HW_BLOCK_TX_DN) ) ) { + if (sngss7_channel_status_clear(sngss7_info)) { /* bring the sig status up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - /* send a uba */ - ft_to_sngss7_uba (ftdmchan); } + /* send a uba */ + ft_to_sngss7_uba (ftdmchan); - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } @@ -1237,46 +1967,50 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN); - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX)) { + int skip_unblock=0; SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_UNBLK_TX flag %s\n", ""); + if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX) || + sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN)) { + /* Real unblock */ + } else { + SS7_ERROR_CHAN(ftdmchan, "FLAG_GRP_HW_UNBLK_TX set while FLAG_GRP_HW_BLOCK_TX is not %s\n", ""); + skip_unblock=1; + } + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_TX_DN); - /* do not set the channel up if it's blocked by blo/cgb command OR blocked by receiving blo/cgb */ - if (!sngss7_test_ckt_blk_flag(sngss7_info, ( FLAG_CKT_MN_BLOCK_TX - | FLAG_CKT_MN_BLOCK_TX - | FLAG_GRP_MN_BLOCK_TX - | FLAG_GRP_MN_BLOCK_TX_DN - | FLAG_CKT_MN_BLOCK_RX - | FLAG_CKT_MN_BLOCK_RX_DN - | FLAG_GRP_MN_BLOCK_RX - | FLAG_GRP_MN_BLOCK_RX_DN - ) - ) - ) { + if (sngss7_channel_status_clear(sngss7_info)) { sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + + if (sngss7_tx_block_status_clear(sngss7_info) && !skip_unblock) { + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); ft_to_sngss7_ubl(ftdmchan); } - goto suspend_goto_last; } -#if 0 -//jz: there is no such thing of "remote hw block". for receiver, there are only block and unblock /**********************************************************************/ - // jz: hardware block/unblock rx +#if 0 + /* This logic is handled in the handle_cgu_req and handle_cgb_req */ + if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_GRP_HW_BLOCK_RX ) && !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN )) { SS7_DEBUG_CHAN(ftdmchan, "Processing FLAG_GRP_HW_BLOCK_RX flag %s\n", ""); sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); - ft_to_sngss7_bla(ftdmchan); + + /* FIXME: Transmit CRG Ack */ + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN); goto suspend_goto_last; @@ -1288,16 +2022,18 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX_DN); sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_GRP_HW_UNBLK_RX); - sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); - ft_to_sngss7_uba(ftdmchan); + if (sngss7_channel_status_clear(sngs7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + + /* Transmit CRU Ack */ goto suspend_goto_last; } #endif - /**********************************************************************/ if (sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX) && !sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX_DN)) { @@ -1313,10 +2049,8 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX_DN); - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } - + if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_MN_UNBLK_TX)) { SS7_DEBUG_CHAN(ftdmchan, "Processing CKT_MN_UNBLK_TX flag %s\n", ""); @@ -1328,17 +2062,18 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); - /* not bring the cic up if there is a hardware block */ - if (!sngss7_test_ckt_blk_flag(sngss7_info, (FLAG_GRP_HW_BLOCK_TX | FLAG_GRP_HW_BLOCK_TX_DN))) { + if (sngss7_channel_status_clear(sngss7_info)) { /* bring the sig status up */ sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } + if (sngss7_tx_block_status_clear(sngss7_info)) { /* send a ubl */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); ft_to_sngss7_ubl(ftdmchan); } - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } /**********************************************************************/ @@ -1348,13 +2083,20 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan, "Processing CKT_LC_BLOCK_RX flag %s\n", ""); /* send a BLA */ - /*ft_to_sngss7_bla(ftdmchan);*/ + ft_to_sngss7_bla(ftdmchan); /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); + + if (sngss7_tx_block_status_clear(sngss7_info)) { + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX_DN); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); + ft_to_sngss7_ubl(ftdmchan); + } else { + /* bring the sig status down */ + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_DOWN); + } - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_LC_UNBLK_RX)) { @@ -1369,11 +2111,13 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_UNBLK_RX); /* send a uba */ - /*ft_to_sngss7_uba(ftdmchan);*/ + ft_to_sngss7_uba(ftdmchan); + + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_set_sig_status(sngss7_info, FTDM_SIG_STATE_UP); + } - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; } /**********************************************************************/ if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_UCIC_BLOCK) && @@ -1395,8 +2139,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* throw the done flag */ sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK_DN); - /* bring the channel down */ - goto suspend_goto_last; } if (sngss7_test_ckt_blk_flag (sngss7_info, FLAG_CKT_UCIC_UNBLK)) { @@ -1410,6 +2152,15 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_UCIC_UNBLK); /* throw the channel into reset to sync states */ + + clear_rx_grs_flags(sngss7_info); + clear_rx_grs_data(sngss7_info); + clear_tx_grs_flags(sngss7_info); + clear_tx_grs_data(sngss7_info); + clear_rx_rsc_flags(sngss7_info); + clear_tx_rsc_flags(sngss7_info); + + clear_tx_rsc_flags(sngss7_info); sngss7_set_ckt_flag(sngss7_info, FLAG_RESET_TX); /* bring the channel into restart again */ @@ -1419,6 +2170,53 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"No block flag processed!%s\n", ""); suspend_goto_last: + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_UP) { + /* proceed to UP */ + } else if (!sngss7_reset_status_clear(sngss7_info) || + sngss7_test_ckt_flag(sngss7_info, FLAG_INFID_PAUSED)) { + + /* At this point the circuit is in reset, if the call is + in use make sure that at least REMOTE REL flag is set + in order to drop the call on the sip side */ + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) { + if (!sngss7_test_ckt_flag (sngss7_info, FLAG_LOCAL_REL) && + !sngss7_test_ckt_flag (sngss7_info, FLAG_REMOTE_REL)) { + sngss7_set_ckt_flag (sngss7_info, FLAG_REMOTE_REL); + } + } + SS7_DEBUG_CHAN(ftdmchan,"Channel opted to stay in RESTART due to reset!%s\n", ""); + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", + sngss7_info->ckt_flags, sngss7_info->blk_flags, + sngss7_info->circuit->flags ); + + goto suspend_goto_restart; + + } else if (sngss7_channel_status_clear(sngss7_info)) { + + /* In this case all resets and blocks are clear sig state is up, thus go to DOWN */ + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RESTART || + ftdmchan->last_state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdmchan->last_state = FTDM_CHANNEL_STATE_DOWN; + } + + SS7_DEBUG_CHAN(ftdmchan,"Channel signallig is UP: proceed to State %s!\n", + ftdm_channel_state2str(ftdmchan->last_state)); + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", + sngss7_info->ckt_flags, sngss7_info->blk_flags, + sngss7_info->circuit->flags ); + + } else { + + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_DOWN) { + ftdmchan->last_state = FTDM_CHANNEL_STATE_RESTART; + } + SS7_DEBUG_CHAN(ftdmchan,"Channel signaling is in block state: proceed to State=%s]\n", + ftdm_channel_state2str(ftdmchan->last_state)); + SS7_DEBUG_CHAN(ftdmchan,"Current flags: ckt=0x%X, blk=0x%X, circuit->flag=0x%X\n", + sngss7_info->ckt_flags, sngss7_info->blk_flags, + sngss7_info->circuit->flags); + } + state_flag = 0; ftdm_set_state(ftdmchan, ftdmchan->last_state); break; @@ -1469,8 +2267,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_ss7_outgoing_call) /* check if the channel sig state is UP */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { - SS7_ERROR_CHAN(ftdmchan, "Requested channel sig state is down, cancelling call!%s\n", " "); - goto outgoing_fail; + SS7_ERROR_CHAN(ftdmchan, "Requested channel sig state is down, skipping channell!%s\n", " "); + /* Sig state will be down due to a block. + Right action is to hunt for another call */ + goto outgoing_break; } /* check if there is a remote block */ @@ -1495,6 +2295,14 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_ss7_outgoing_call) goto outgoing_break; } + + /* This is a gracefull stack resource check. + Removing this function will cause unpredictable + ungracefule errors. */ + if (sng_cc_resource_check()) { + goto outgoing_fail; + } + /* check the state of the channel */ switch (ftdmchan->state){ /**************************************************************************/ @@ -1566,7 +2374,10 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) sngss7_chan_data_t *sngss7_info = NULL; sngss7_span_data_t *sngss7_span = NULL; sng_isup_inf_t *sngss7_intf = NULL; - int x; + int x; + int first_channel; + + first_channel=0; SS7_INFO ("Starting span %s:%u.\n", span->name, span->span_id); @@ -1614,10 +2425,12 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) #if 0 /* throw the grp reset flag */ sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_TX); - if (x == 1) { - sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_BASE); - sngss7_span->tx_grs.circuit = sngss7_info->circuit->id; - sngss7_span->tx_grs.range = span->chan_count -1; + if (first_channel == 0) { + sngss7_chan_data_t *cinfo = ftdmchan->call_data; + sngss7_set_ckt_flag(sngss7_info, FLAG_GRP_RESET_BASE); + cinfo->tx_grs.circuit = sngss7_info->circuit->id; + cinfo->tx_grs.range = span->chan_count -1; + first_channel=1; } #else /* throw the channel into reset */ @@ -1651,6 +2464,7 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) static ftdm_status_t ftdm_sangoma_ss7_stop(ftdm_span_t * span) { /*this function is called by the FT-Core to stop this span */ + int timeout=0; ftdm_log (FTDM_LOG_INFO, "Stopping span %s:%u.\n", span->name,span->span_id); @@ -1659,10 +2473,17 @@ static ftdm_status_t ftdm_sangoma_ss7_stop(ftdm_span_t * span) /* wait for the thread to stop */ while (ftdm_test_flag (span, FTDM_SPAN_IN_THREAD)) { - ftdm_log (FTDM_LOG_DEBUG,"Waiting for monitor thread to end for %s:%u.\n", + ftdm_set_flag (span, FTDM_SPAN_STOP_THREAD); + ftdm_log (FTDM_LOG_DEBUG,"Waiting for monitor thread to end for %s:%u. [flags=0x%08X]\n", span->name, - span->span_id); - ftdm_sleep (1); + span->span_id, + span->flags); + /* Wait 50ms */ + ftdm_sleep (50); + timeout++; + + /* timeout after 5 sec, better to crash than hang */ + ftdm_assert_return(timeout < 100, FTDM_FALSE, "SS7 Span stop timeout!\n"); } /* KONRAD FIX ME - deconfigure any circuits, links, attached to this span */ @@ -1722,15 +2543,23 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) /* set the flag to indicate that this span uses sig event queues */ ftdm_set_flag (span, FTDM_SPAN_USE_SIGNALS_QUEUE); + + /* parse the configuration and apply to the global config structure */ if (ftmod_ss7_parse_xml(ftdm_parameters, span)) { ftdm_log (FTDM_LOG_CRIT, "Failed to parse configuration!\n"); + ftdm_sleep (100); return FTDM_FAIL; } - /* configure libsngss7 */ - if (ft_to_sngss7_cfg_all()) { + if(SNG_SS7_OPR_MODE_M2UA_SG == g_ftdm_operating_mode){ + ftdm_log (FTDM_LOG_INFO, "FreeTDM running as M2UA_SG mode, Setting Span type to FTDM_SIGTYPE_M2UA\n"); + span->signal_type = FTDM_SIGTYPE_M2UA; + } + + if (ft_to_sngss7_cfg_all()) { /* configure libsngss7 */ ftdm_log (FTDM_LOG_CRIT, "Failed to configure LibSngSS7!\n"); + ftdm_sleep (100); return FTDM_FAIL; } @@ -1790,6 +2619,10 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) sng_event.sm.sng_isup_alarm = handle_sng_isup_alarm; sng_event.sm.sng_cc_alarm = handle_sng_cc_alarm; sng_event.sm.sng_relay_alarm = handle_sng_relay_alarm; + sng_event.sm.sng_m2ua_alarm = handle_sng_m2ua_alarm; + sng_event.sm.sng_nif_alarm = handle_sng_nif_alarm; + sng_event.sm.sng_tucl_alarm = handle_sng_tucl_alarm; + sng_event.sm.sng_sctp_alarm = handle_sng_sctp_alarm; /* initalize sng_ss7 library */ sng_isup_init_gen(&sng_event); @@ -1798,9 +2631,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) sng_isup_version(&major, &minor, &build); SS7_INFO("Loaded LibSng-SS7 %d.%d.%d\n", major, minor, build); - /* crash on assert fail */ - ftdm_global_set_crash_policy (FTDM_CRASH_ON_ASSERT); - return FTDM_SUCCESS; } @@ -1870,6 +2700,10 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_ss7_unload) sngss7_clear_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_RY_STARTED); } + if(SNG_SS7_OPR_MODE_ISUP != g_ftdm_operating_mode){ + ftmod_ss7_m2ua_free(); + } + if (sngss7_test_flag(&g_ftdm_sngss7_data.cfg, SNGSS7_SM_STARTED)) { sng_isup_free_sm(); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index caef19af12..4035eeed67 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -29,6 +29,12 @@ * 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. + * + * + * Contributors: + * + * James Zhang + * */ /******************************************************************************/ #ifndef __FTMOD_SNG_SS7_H__ @@ -46,17 +52,20 @@ #include "private/ftdm_core.h" #include "sng_ss7/sng_ss7.h" +#include "ftmod_sangoma_ss7_m2ua.h" /******************************************************************************/ /* DEFINES ********************************************************************/ #define MAX_NAME_LEN 25 -#define MAX_PATH 4096 #define MAX_CIC_LENGTH 5 #define MAX_CIC_MAP_LENGTH 1000 +#define MAX_SCTP_LINK 100 #define SNGSS7_EVENT_QUEUE_SIZE 100 +#define SNGSS7_PEER_CHANS_QUEUE_SIZE 100 +#define SNGSS7_CHAN_EVENT_QUEUE_SIZE 100 #define MAX_SIZEOF_SUBADDR_IE 24 /* as per Q931 4.5.9 */ @@ -64,6 +73,14 @@ (switchtype == LSI_SW_ANS92) || \ (switchtype == LSI_SW_ANS95) +#define sngss7_flush_queue(queue) \ + do { \ + void *__queue_data = NULL; \ + while ((__queue_data = ftdm_queue_dequeue(queue))) { \ + ftdm_safe_free(__queue_data); \ + } \ + } while (0) + typedef struct ftdm2trillium { uint8_t ftdm_val; uint8_t trillium_val; @@ -82,8 +99,12 @@ typedef enum { SNGSS7_STA_IND_EVENT, SNGSS7_SUSP_IND_EVENT, SNGSS7_RESM_IND_EVENT, - SNGSS7_SSP_STA_CFM_EVENT + SNGSS7_SSP_STA_CFM_EVENT, + SNGSS7_INVALID_EVENT, } sng_event_type_t; +#define SNG_EVENT_TYPE_STRINGS "CON_IND", "CON_CFM", "CON_STA", "REL_IND", "REL_CFM", "DAT_IND", "FAC_IND", \ + "FAC_CFM", "UMSG_IND", "STA_IND", "SUSP_IND", "RESM_IND", "SSP_STA_CFM", "INVALID" +FTDM_STR2ENUM_P(ftdm_str2sngss7_event, ftdm_sngss7_event2str, sng_event_type_t) typedef enum { SNG_BIT_A = (1 << 0), @@ -117,6 +138,12 @@ typedef enum { SNG_CALLING = 2 } sng_addr_type_t; +typedef enum { + SNG_GEN_CFG_STATUS_INIT = 0, + SNG_GEN_CFG_STATUS_PENDING = 1, + SNG_GEN_CFG_STATUS_DONE = 2 +} nsg_gen_cfg_type_t; + typedef struct sng_mtp2_error_type { int init; char sng_type[MAX_NAME_LEN]; @@ -176,6 +203,21 @@ typedef struct sng_mtp2_link { uint32_t t7; } sng_mtp2_link_t; +/* defining glare handling methods: + SNGSS7_GLARE_PC: + higher PointCode controls even number CIC + lower PointCode controls odd number CIC + SNGSS7_GLARE_DOWN: + always give control to the other side + SNGSS7_GLARE_CONTROL: + always trying to control +*/ +typedef enum { + SNGSS7_GLARE_PC = 0, + SNGSS7_GLARE_DOWN, + SNGSS7_GLARE_CONTROL +} sng_glare_resolution; + typedef struct sng_mtp3_link { char name[MAX_NAME_LEN]; uint32_t flags; @@ -328,6 +370,7 @@ typedef struct sng_isup_ckt { uint32_t clg_nadi; uint32_t cld_nadi; uint8_t rdnis_nadi; + uint32_t loc_nadi; /* Generic Number defaults */ uint8_t gn_nmbqual; /* Number Qualifier */ @@ -339,8 +382,11 @@ typedef struct sng_isup_ckt { /* END - Generic Number defaults */ uint32_t min_digits; - uint8_t itx_auto_reply; + uint32_t transparent_iam_max_size; uint8_t transparent_iam; + uint8_t cpg_on_progress_media; + uint8_t cpg_on_progress; + uint8_t itx_auto_reply; void *obj; uint16_t t3; uint32_t t10; @@ -351,6 +397,7 @@ typedef struct sng_isup_ckt { uint16_t t16; uint16_t t17; uint32_t t35; + uint32_t t39; uint16_t tval; } sng_isup_ckt_t; @@ -404,11 +451,34 @@ typedef struct sng_relay { uint32_t procId; } sng_relay_t; +/********************************************** +sctp structures and data definitions +**********************************************/ + +typedef struct sng_sctp_gen_cfg { +} sng_sctp_gen_cfg_t; + +typedef struct sng_sctp_link { + char name[MAX_NAME_LEN]; + uint32_t flags; + uint32_t id; + uint32_t port; + uint32_t numSrcAddr; + uint32_t srcAddrList[SCT_MAX_NET_ADDRS+1]; +} sng_sctp_link_t; + +typedef struct sng_sctp_cfg { + sng_sctp_gen_cfg_t genCfg; + sng_sctp_link_t linkCfg[MAX_SCTP_LINK+1]; +} sng_sctp_cfg_t; + + + typedef struct sng_ss7_cfg { uint32_t spc; uint32_t procId; - char license[MAX_PATH]; - char signature[MAX_PATH]; + char license[MAX_SNGSS7_PATH]; + char signature[MAX_SNGSS7_PATH]; uint32_t transparent_iam_max_size; uint32_t flags; sng_relay_t relay[MAX_RELAY_CHANNELS+1]; @@ -421,6 +491,10 @@ typedef struct sng_ss7_cfg { sng_isup_ckt_t isupCkt[10000]; /* KONRAD - only need 2000 ( and 0-1000 aren't used) since other servers are registerd else where */ sng_nsap_t nsap[MAX_NSAPS+1]; sng_isap_t isap[MAX_ISAPS+1]; + sng_glare_resolution glareResolution; + uint32_t force_inr; + sng_m2ua_gbl_cfg_t g_m2ua_cfg; + sng_sctp_cfg_t sctpCfg; } sng_ss7_cfg_t; typedef struct ftdm_sngss7_data { @@ -433,6 +507,14 @@ typedef struct ftdm_sngss7_data { fio_signal_cb_t sig_cb; } ftdm_sngss7_data_t; +typedef enum{ + SNG_SS7_OPR_MODE_NONE, + SNG_SS7_OPR_MODE_M2UA_SG, + SNG_SS7_OPR_MODE_ISUP, +}ftdm_sngss7_operating_modes_e; + +typedef ftdm_sngss7_operating_modes_e ftdm_sngss7_opr_mode; + typedef struct sngss7_timer_data { ftdm_timer_id_t hb_timer_id; int beat; @@ -472,10 +554,14 @@ typedef struct sngss7_chan_data { sngss7_glare_data_t glare; sngss7_timer_data_t t35; sngss7_timer_data_t t10; + sngss7_timer_data_t t39; sngss7_group_data_t rx_grs; sngss7_group_data_t rx_gra; sngss7_group_data_t tx_grs; sngss7_group_data_t ucic; + ftdm_queue_t *event_queue; + struct sngss7_chan_data *peer_data; + uint8_t peer_event_transfer_cnt; } sngss7_chan_data_t; #define SNGSS7_RX_GRS_PENDING (1 << 0) @@ -533,6 +619,18 @@ typedef enum { FLAG_INFID_RESUME = (1 << 14), FLAG_INFID_PAUSED = (1 << 15), FLAG_SENT_ACM = (1 << 16), + FLAG_SENT_CPG = (1 << 17), + FLAG_SUS_RECVD = (1 << 18), + FLAG_T6_CANCELED = (1 << 19), + FLAG_INR_TX = (1 << 20), + FLAG_INR_SENT = (1 << 21), + FLAG_INR_RX = (1 << 22), + FLAG_INR_RX_DN = (1 << 23), + FLAG_INF_TX = (1 << 24), + FLAG_INF_SENT = (1 << 25), + FLAG_INF_RX = (1 << 26), + FLAG_INF_RX_DN = (1 << 27), + FLAG_FULL_NUMBER = (1 << 28), FLAG_RELAY_DOWN = (1 << 30), FLAG_CKT_RECONFIG = (1 << 31) } sng_ckt_flag_t; @@ -541,20 +639,28 @@ typedef enum { "RX_RSC", \ "TX_RSC", \ "TX_RSC_REQ_SENT", \ - "TX_RSC_RSP_RECIEVED", \ + "TX_RSC_RSP_RECEIVED", \ "RX_GRS", \ "RX_GRS_DONE", \ "RX_GRS_CMPLT", \ "GRS_BASE", \ "TX_GRS", \ "TX_GRS_REQ_SENT", \ - "TX_GRS_RSP_RECIEVED", \ + "TX_GRS_RSP_RECEIVED", \ "REMOTE_REL", \ "LOCAL_REL", \ "GLARE", \ "INF_RESUME", \ "INF_PAUSED", \ "TX_ACM_SENT" \ + "TX_INR" \ + "INR_SENT" \ + "RX_INR" \ + "RX_INR_DN" \ + "TX_INF" \ + "INF SENT" \ + "RX_INF" \ + "RX_INF_DN" \ "RELAY_DOWN", \ "CKT_RECONFIG" FTDM_STR2ENUM_P(ftmod_ss7_ckt_state2flag, ftmod_ss7_ckt_flag2str, sng_ckt_flag_t) @@ -588,7 +694,7 @@ typedef enum { FLAG_GRP_HW_UNBLK_TX = (1 << 24), FLAG_GRP_HW_UNBLK_TX_DN = (1 << 25), FLAG_GRP_MN_UNBLK_TX = (1 << 26), - FLAG_GRP_MN_UNBLK_TX_DN = (1 << 27) + FLAG_GRP_MN_UNBLK_TX_DN = (1 << 27), } sng_ckt_block_flag_t; #define BLK_FLAGS_STRING \ @@ -652,11 +758,27 @@ typedef enum { SNGSS7_CC_PRESENT = (1 << 12), SNGSS7_CC_STARTED = (1 << 13), + + SNGSS7_TUCL_PRESENT = (1 << 14), + SNGSS7_TUCL_STARTED = (1 << 15), + + SNGSS7_SCTP_PRESENT = (1 << 16), + SNGSS7_SCTP_STARTED = (1 << 17), + + SNGSS7_M2UA_PRESENT = (1 << 18), + SNGSS7_M2UA_STARTED = (1 << 19), + SNGSS7_M2UA_EP_OPENED = (1 << 20), + SNGSS7_M2UA_INIT_ASSOC_DONE = (1 << 21), + + SNGSS7_NIF_PRESENT = (1 << 22), + SNGSS7_NIF_STARTED = (1 << 23), + } sng_task_flag_t; /******************************************************************************/ /* GLOBALS ********************************************************************/ extern ftdm_sngss7_data_t g_ftdm_sngss7_data; +extern ftdm_sngss7_opr_mode g_ftdm_operating_mode; extern sng_ssf_type_t sng_ssf_type_map[]; extern sng_switch_type_t sng_switch_type_map[]; extern sng_link_type_t sng_link_type_map[]; @@ -679,6 +801,10 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta); void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta); void handle_sng_cc_alarm(Pst *pst, CcMngmt *sta); void handle_sng_relay_alarm(Pst *pst, RyMngmt *sta); +void handle_sng_m2ua_alarm(Pst *pst, MwMgmt *sta); +void handle_sng_nif_alarm(Pst *pst, NwMgmt *sta); +void handle_sng_tucl_alarm(Pst *pst, HiMngmt *sta); +void handle_sng_sctp_alarm(Pst *pst, SbMgmt *sta); /* in ftmod_sangoma_ss7_relay.c */ ftdm_status_t handle_relay_connect(RyMngmt *sta); @@ -731,7 +857,9 @@ int ftmod_ss7_enable_grp_mtp3Link(uint32_t procId); int ftmod_ss7_disable_grp_mtp2Link(uint32_t procId); -int ftmod_ss7_block_isup_ckt(uint32_t cktId); +#define ftmod_ss7_block_isup_ckt(x) __ftmod_ss7_block_isup_ckt(x,FTDM_TRUE) +#define ftmod_ss7_block_isup_ckt_nowait(x) __ftmod_ss7_block_isup_ckt(x,FTDM_FALSE) +int __ftmod_ss7_block_isup_ckt(uint32_t cktId, ftdm_bool_t wait); int ftmod_ss7_unblock_isup_ckt(uint32_t cktId); @@ -767,6 +895,9 @@ void ft_to_sngss7_cgb(ftdm_channel_t * ftdmchan); void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan); void ft_to_sngss7_itx (ftdm_channel_t * ftdmchan); void ft_to_sngss7_txa (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_inr(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan, SiCnStEvnt *inr); + /* in ftmod_sangoma_ss7_in.c */ @@ -835,15 +966,27 @@ ftdm_status_t copy_cdPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cd ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum); ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum); ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum); +ftdm_status_t copy_redirgInfo_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo); +ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo); +ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); +ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum); + +ftdm_status_t copy_access_transport_from_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt); +ftdm_status_t copy_access_transport_to_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt); +ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); +ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum); ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); ftdm_status_t copy_genNmb_from_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb); ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat); ftdm_status_t copy_cgPtyCat_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat); ftdm_status_t copy_accTrnspt_to_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt); ftdm_status_t copy_natConInd_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd); +ftdm_status_t copy_fwdCallInd_hex_from_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd); ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd); ftdm_status_t copy_txMedReq_to_sngss7(ftdm_channel_t *ftdmchan, SiTxMedReq *txMedReq); ftdm_status_t copy_usrServInfoA_to_sngss7(ftdm_channel_t *ftdmchan, SiUsrServInfo *usrServInfoA); +ftdm_status_t copy_NatureOfConnection_from_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd ); +ftdm_status_t copy_NatureOfConnection_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd); ftdm_status_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); ftdm_status_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); @@ -889,6 +1032,8 @@ ftdm_status_t sngss7_add_raw_data(sngss7_chan_data_t *sngss7_info, uint8_t* data /* in ftmod_sangoma_ss7_timers.c */ void handle_isup_t35(void *userdata); void handle_isup_t10(void *userdata); +void handle_isup_t39(void *userdata); + /******************************************************************************/ @@ -910,9 +1055,9 @@ if (ftdmchan->state == new_state) { \ #define SS7_INFO_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_INFO, msg , ##args) #define SS7_WARN_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_WARNING, msg , ##args) #define SS7_ERROR_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_ERROR, msg , ##args) -#define SS7_CTRIT_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_CRIT, msg , ##args) +#define SS7_CRIT_CHAN(fchan, msg, args...) ftdm_log_chan(fchan, FTDM_LOG_CRIT, msg , ##args) -#ifdef KONRAD_DEVEL +#ifdef SS7_CODE_DEVEL #define SS7_DEVEL_DEBUG(a,...) ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ ); #else #define SS7_DEVEL_DEBUG(a,...) @@ -1039,6 +1184,40 @@ if (ftdmchan->state == new_state) { \ #define sngss7_clear_options(obj, option) ((obj)->options &= ~(option)) #define sngss7_set_options(obj, option) ((obj)->options |= (option)) +#define sngss7_tx_block_status_clear(obj) (!sngss7_test_ckt_blk_flag(obj, (FLAG_CKT_MN_BLOCK_TX | \ + FLAG_CKT_MN_BLOCK_TX_DN | \ + FLAG_GRP_MN_BLOCK_TX | \ + FLAG_GRP_MN_BLOCK_TX_DN | \ + FLAG_GRP_HW_BLOCK_TX | \ + FLAG_GRP_HW_BLOCK_TX_DN | \ + FLAG_GRP_HW_UNBLK_TX | \ + FLAG_CKT_MN_UNBLK_TX ))) + +#define sngss7_block_status_clear(obj) (obj->blk_flags == 0) + +#define sngss7_reset_status_clear(obj) (!sngss7_test_ckt_flag(obj, (FLAG_RESET_TX | \ + FLAG_RESET_RX | \ + FLAG_GRP_RESET_TX | \ + FLAG_GRP_RESET_RX ))) + +#define sngss7_tx_reset_sent(obj) ((sngss7_test_ckt_flag(obj, (FLAG_RESET_TX)) && \ + sngss7_test_ckt_flag(obj, (FLAG_RESET_SENT))) || \ + (sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_TX)) && \ + sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_SENT)))) + +#define sngss7_tx_reset_status_pending(obj) (sngss7_test_ckt_flag(obj, (FLAG_RESET_TX)) || sngss7_test_ckt_flag(obj, (FLAG_GRP_RESET_TX))) + +#define sngss7_channel_status_clear(obj) ((sngss7_block_status_clear(obj)) && \ + (sngss7_reset_status_clear(obj)) && \ + (!sngss7_test_ckt_flag((obj),FLAG_INFID_PAUSED))) + +#define sngss7_tx_reset_restart(obj) do { clear_tx_grs_flags((obj)); \ + clear_tx_grs_data((obj)); \ + clear_tx_rsc_flags((obj)); \ + sngss7_set_ckt_flag((obj), (FLAG_RESET_TX)); \ + } while (0); + + #ifdef SMG_RELAY_DBG #define SS7_RELAY_DBG(a,...) printf(a"\n", ##__VA_ARGS__) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index b729552092..4f177a3957 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -44,8 +44,11 @@ /* FUNCTIONS ******************************************************************/ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) { + const char *var = NULL; SiConEvnt iam; + ftdm_bool_t native_going_up = FTDM_FALSE; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; + sngss7_event_data_t *event_clone = NULL; SS7_FUNC_TRACE_ENTER (__FUNCTION__); @@ -55,9 +58,113 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) memset (&iam, 0x0, sizeof (iam)); - if (sngss7_info->circuit->transparent_iam && + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + ftdm_span_t *peer_span = NULL; + ftdm_channel_t *peer_chan = NULL; + sngss7_chan_data_t *peer_info = NULL; + + var = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "sigbridge_peer"); + ftdm_get_channel_from_string(var, &peer_span, &peer_chan); + if (!peer_chan) { + SS7_ERROR_CHAN(ftdmchan, "Failed to find sigbridge peer from string '%s'\n", var); + } else { + if (peer_span->signal_type != FTDM_SIGTYPE_SS7) { + SS7_ERROR_CHAN(ftdmchan, "Peer channel '%s' has different signaling type %d'\n", + var, peer_span->signal_type); + } else { + peer_info = peer_chan->call_data; + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Starting native bridge with peer CIC %d\n", + sngss7_info->circuit->cic, peer_info->circuit->cic); + + /* retrieve only first message from the others guys queue (must be IAM) */ + event_clone = ftdm_queue_dequeue(peer_info->event_queue); + + /* make each one of us aware of the native bridge */ + peer_info->peer_data = sngss7_info; + sngss7_info->peer_data = peer_info; + + /* Go to up until release comes, note that state processing is done different and much simpler when there is a peer, + We can't go to UP state right away yet though, so do not set the state to UP here, wait until the end of this function + because moving from one state to another causes the ftdmchan->usrmsg structure to be wiped + and we still need those variables for further IAM processing */ + native_going_up = FTDM_TRUE; + } + } + } + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) { + if (!event_clone) { + SS7_ERROR_CHAN(ftdmchan, "No IAM event clone in peer queue!%s\n", ""); + } else if (event_clone->event_id != SNGSS7_CON_IND_EVENT) { + /* first message in the queue should ALWAYS be an IAM */ + SS7_ERROR_CHAN(ftdmchan, "Invalid initial peer message type '%d'\n", event_clone->event_id); + } else { + ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged, dialing %s)\n", sngss7_info->circuit->cic, caller_data->dnis.digits); + + /* copy original incoming IAM */ + memcpy(&iam, &event_clone->event.siConEvnt, sizeof(iam)); + + /* Change DNIS to whatever was specified, do not change NADI or anything else! */ + copy_tknStr_to_sngss7(caller_data->dnis.digits, &iam.cdPtyNum.addrSig, &iam.cdPtyNum.oddEven); + + /* SPIROU certification hack + If the IAM already contain RDINF, just increment the count and set the RDNIS digits + otherwise, honor RDNIS and RDINF stuff coming from the user */ + if (iam.redirInfo.eh.pres == PRSNT_NODEF) { + const char *val = NULL; + if (iam.redirInfo.redirCnt.pres) { + iam.redirInfo.redirCnt.val++; + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect count incremented = %d\n", sngss7_info->circuit->cic, iam.redirInfo.redirCnt.val); + } + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_digits"); + if (!ftdm_strlen_zero(val)) { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), found user supplied RDNIS digits = %s\n", sngss7_info->circuit->cic, val); + copy_tknStr_to_sngss7((char*)val, &iam.redirgNum.addrSig, &iam.redirgNum.oddEven); + } else { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), not found user supplied RDNIS digits\n", sngss7_info->circuit->cic); + } + } else { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Bridged), redirect info not present, attempting to copy user supplied values\n", sngss7_info->circuit->cic); + /* Redirecting Number */ + copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); + + /* Redirecting Information */ + copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); + } + + if (iam.origCdNum.eh.pres != PRSNT_NODEF) { + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); + } + copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); + } + } else if (sngss7_info->circuit->transparent_iam && sngss7_retrieve_iam(ftdmchan, &iam) == FTDM_SUCCESS) { SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM (Transparent)\n", sngss7_info->circuit->cic); + + /* Called Number information */ + copy_cdPtyNum_to_sngss7(ftdmchan, &iam.cdPtyNum); + + /* Redirecting Number */ + copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); + + /* Redirecting Information */ + copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); + + /* Location Number information */ + copy_locPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum1); + + /* Forward Call Indicators */ + copy_fwdCallInd_to_sngss7(ftdmchan, &iam.fwdCallInd); + + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); + + copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); + + copy_NatureOfConnection_to_sngss7(ftdmchan, &iam.natConInd); } else { /* Nature of Connection Indicators */ copy_natConInd_to_sngss7(ftdmchan, &iam.natConInd); @@ -79,6 +186,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Calling Number information */ copy_cgPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum); + /* Location Number information */ + copy_locPtyNum_to_sngss7(ftdmchan, &iam.cgPtyNum1); + /* Generic Number information */ copy_genNmb_to_sngss7(ftdmchan, &iam.genNmb); @@ -88,15 +198,30 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* Redirecting Number */ copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum); - /* Access Transport */ - copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); + /* Redirecting Information */ + copy_redirgInfo_to_sngss7(ftdmchan, &iam.redirInfo); - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d)\n", + /* Original Called Number */ + copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum); + + /* Access Transport - old implementation, taking from channel variable of ss7_clg_subaddr */ + copy_accTrnspt_to_sngss7(ftdmchan, &iam.accTrnspt); + + /* Access Transport - taking from channel variable of ss7_access_transport_urlenc. + This will overwirte the IE value set be above old implementation. + */ + copy_access_transport_to_sngss7(ftdmchan, &iam.accTrnspt); + + copy_NatureOfConnection_to_sngss7(ftdmchan, &iam.natConInd); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\" (NADI=%d), cld = \"%s\" (NADI=%d), loc = %s (NADI=%d)\n", sngss7_info->circuit->cic, ftdmchan->caller_data.cid_num.digits, iam.cgPtyNum.natAddrInd.val, ftdmchan->caller_data.dnis.digits, - iam.cdPtyNum.natAddrInd.val); + iam.cdPtyNum.natAddrInd.val, + ftdmchan->caller_data.loc.digits, + iam.cgPtyNum1.natAddrInd.val); } sng_cc_con_request (sngss7_info->spId, @@ -106,16 +231,124 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) &iam, 0); + if (native_going_up) { + /* + Note that this function (ft_to_sngss7_iam) is run within the main SS7 processing loop in + response to the DIALING state handler, we can set the state to UP here and that will + implicitly complete the DIALING state, but we *MUST* also advance the state handler + right away for a native bridge, otherwise, the processing state function (ftdm_sangoma_ss7_process_state_change) + will complete the state without having executed the handler for FTDM_CHANNEL_STATE_UP, and we won't notify + the user sending FTDM_SIGEVENT_UP which can cause the application to misbehave (ie, no audio) */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); + ftdm_channel_advance_states(ftdmchan); + } + + ftdm_safe_free(event_clone); + SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } +void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan, SiCnStEvnt *inr) +{ + SiCnStEvnt evnt; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset (&evnt, 0x0, sizeof (evnt)); + + evnt.infoInd.eh.pres = PRSNT_NODEF; + evnt.infoInd.cgPtyAddrRespInd.pres = PRSNT_NODEF; + evnt.infoInd.cgPtyCatRespInd.pres = PRSNT_NODEF; + + evnt.infoInd.chrgInfoRespInd.pres = PRSNT_NODEF; + evnt.infoInd.chrgInfoRespInd.val = 0; + evnt.infoInd.solInfoInd.pres = PRSNT_NODEF; + evnt.infoInd.solInfoInd.val = 0; + evnt.infoInd.holdProvInd.pres = PRSNT_NODEF; + evnt.infoInd.holdProvInd.val = 0; + evnt.infoInd.spare.pres = PRSNT_NODEF; + evnt.infoInd.spare.val = 0; + + if (inr->infoReqInd.eh.pres == PRSNT_NODEF) { + if ((inr->infoReqInd.holdingInd.pres == PRSNT_NODEF) && (inr->infoReqInd.holdingInd.val == HOLD_REQ)) { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting holding information. Holding is not supported in INF.\n", sngss7_info->circuit->cic); + } + if ((inr->infoReqInd.chrgInfoReqInd.pres == PRSNT_NODEF) && (inr->infoReqInd.chrgInfoReqInd.val == CHRGINFO_REQ)) { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting charging information. Charging is not supported in INF.\n", sngss7_info->circuit->cic); + } + if ((inr->infoReqInd.malCaIdReqInd.pres == PRSNT_NODEF) && (inr->infoReqInd.malCaIdReqInd.val == CHRGINFO_REQ)) { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR requesting malicious call id. Malicious call id is not supported in INF.\n", sngss7_info->circuit->cic); + } + + if ((inr->infoReqInd.cgPtyAdReqInd.pres == PRSNT_NODEF) && (inr->infoReqInd.cgPtyAdReqInd.val == CGPRTYADDREQ_REQ)) { + evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_INCL; + copy_cgPtyNum_to_sngss7 (ftdmchan, &evnt.cgPtyNum); + } else { + evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_NOTINCL; + } + + if ((inr->infoReqInd.cgPtyCatReqInd.pres == PRSNT_NODEF) && (inr->infoReqInd.cgPtyCatReqInd.val == CGPRTYCATREQ_REQ)) { + evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_INCL; + copy_cgPtyCat_to_sngss7 (ftdmchan, &evnt.cgPtyCat); + } else { + evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_NOTINCL; + } + } + else { + SS7_DEBUG_CHAN(ftdmchan,"[CIC:%d]Received INR with no information request. Sending back default INF.\n", sngss7_info->circuit->cic); + } + + sng_cc_inf(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &evnt, + INFORMATION); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx INF\n", sngss7_info->circuit->cic); + +} + +void ft_to_sngss7_inr(ftdm_channel_t *ftdmchan) +{ + SiCnStEvnt evnt; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset (&evnt, 0x0, sizeof (evnt)); + + evnt.infoReqInd.eh.pres = PRSNT_NODEF; + evnt.infoReqInd.cgPtyAdReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.cgPtyAdReqInd.val=CGPRTYADDREQ_REQ; + + evnt.infoReqInd.holdingInd.pres = PRSNT_NODEF; + evnt.infoReqInd.holdingInd.val = HOLD_REQ; + + evnt.infoReqInd.cgPtyCatReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.cgPtyCatReqInd.val = CGPRTYCATREQ_REQ; + + evnt.infoReqInd.chrgInfoReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.chrgInfoReqInd.val = CHRGINFO_REQ; + + evnt.infoReqInd.malCaIdReqInd.pres = PRSNT_NODEF; + evnt.infoReqInd.malCaIdReqInd.val = MLBG_INFOREQ; + + sng_cc_inr(1, + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &evnt, + INFORMATREQ); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx INR\n", sngss7_info->circuit->cic); +} + void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) { SS7_FUNC_TRACE_ENTER (__FUNCTION__); sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; SiCnStEvnt acm; + const char *backwardInd = NULL; memset (&acm, 0x0, sizeof (acm)); @@ -133,8 +366,16 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.bckCallInd.intInd.val = INTIND_NOINTW; acm.bckCallInd.end2EndInfoInd.pres = PRSNT_NODEF; acm.bckCallInd.end2EndInfoInd.val = E2EINF_NOINFO; + acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; - acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_NOTUSED; + backwardInd = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "acm_bi_iup"); + if (!ftdm_strlen_zero(backwardInd)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied backward indicator ISDN user part indicator ACM, value \"%s\"\n", backwardInd); + if (atoi(backwardInd) != 0 ) { + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; + } + } acm.bckCallInd.holdInd.pres = PRSNT_NODEF; acm.bckCallInd.holdInd.val = HOLD_NOTREQD; acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF; @@ -241,6 +482,7 @@ void ft_to_sngss7_anm (ftdm_channel_t * ftdmchan) /******************************************************************************/ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) { + const char *loc_ind = NULL; SS7_FUNC_TRACE_ENTER (__FUNCTION__); sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; @@ -250,7 +492,15 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) rel.causeDgn.eh.pres = PRSNT_NODEF; rel.causeDgn.location.pres = PRSNT_NODEF; - rel.causeDgn.location.val = 0x01; + + loc_ind = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rel_loc"); + if (!ftdm_strlen_zero(loc_ind)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied location indicator in REL, value \"%s\"\n", loc_ind); + rel.causeDgn.location.val = atoi(loc_ind); + } else { + rel.causeDgn.location.val = 0x01; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied location indicator in REL, using 0x01\"%s\"\n", ""); + } rel.causeDgn.cdeStand.pres = PRSNT_NODEF; rel.causeDgn.cdeStand.val = 0x00; rel.causeDgn.recommend.pres = NOTPRSNT; @@ -260,10 +510,10 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) /* send the REL request to LibSngSS7 */ sng_cc_rel_request (1, - sngss7_info->suInstId, - sngss7_info->spInstId, - sngss7_info->circuit->id, - &rel); + sngss7_info->suInstId, + sngss7_info->spInstId, + sngss7_info->circuit->id, + &rel); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx REL cause=%d \n", sngss7_info->circuit->cic, @@ -518,8 +768,6 @@ void ft_to_sngss7_grs (ftdm_channel_t *fchan) cinfo->circuit->cic, (cinfo->circuit->cic + cinfo->tx_grs.range)); - memset(&cinfo->tx_grs, 0, sizeof(cinfo->tx_grs)); - sngss7_set_ckt_flag(cinfo, FLAG_GRP_RESET_SENT); SS7_FUNC_TRACE_EXIT (__FUNCTION__); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c index c99a14a7e7..0fb496843f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c @@ -42,8 +42,6 @@ /******************************************************************************/ /* PROTOTYPES *****************************************************************/ -ftdm_status_t handle_relay_connect(RyMngmt *sta); -ftdm_status_t handle_relay_disconnect(RyMngmt *sta); /*static ftdm_status_t enable_all_ckts_for_relay(void);*/ static ftdm_status_t reconfig_all_ckts_for_relay(void); @@ -66,11 +64,9 @@ ftdm_status_t handle_relay_connect(RyMngmt *sta) SS7_INFO("Relay Channel %d connection UP\n", sng_relay->id); if (sng_relay->type == LRY_CT_TCP_CLIENT) { - if (!sngss7_test_flag(sng_relay, SNGSS7_RELAY_INIT)) { - if (reconfig_all_ckts_for_relay()) { - SS7_ERROR("Failed to reconfigure ISUP Ckts!\n"); - /* we're done....this is very bad! */ - } + if (reconfig_all_ckts_for_relay()) { + SS7_ERROR("Failed to reconfigure ISUP Ckts!\n"); + /* we're done....this is very bad! */ } return FTDM_SUCCESS; } else if (sng_relay->type == LRY_CT_TCP_SERVER) { @@ -84,23 +80,24 @@ ftdm_status_t handle_relay_connect(RyMngmt *sta) /******************************************************************************/ ftdm_status_t handle_relay_disconnect_on_error(RyMngmt *sta) { + SS7_DEBUG("SS7 relay disconnect on error\n"); /* check which procId is in error, if it is 1, disable the ckts */ if (sta->t.usta.s.ryErrUsta.errPid == 1 ) { - /* we've lost the server, bring down the mtp2 links */ - disble_all_mtp2_sigs_for_relay(); - /* we've lost the server, bring the sig status down on all ckts */ disable_all_ckts_for_relay(); + + /* we've lost the server, bring down the mtp2 links */ + disble_all_mtp2_sigs_for_relay(); } /* check if the channel is a server, means we just lost a MGW */ if (g_ftdm_sngss7_data.cfg.relay[sta->t.usta.s.ryErrUsta.errPid].type == LRY_CT_TCP_SERVER) { - /* we've lost the client, bring down all mtp3 links for this procId */ - disable_all_sigs_for_relay(sta->t.usta.s.ryErrUsta.errPid); - /* we've lost the client, bring down all the ckts for this procId */ block_all_ckts_for_relay(sta->t.usta.s.ryErrUsta.errPid); + + /* we've lost the client, bring down all mtp3 links for this procId */ + disable_all_sigs_for_relay(sta->t.usta.s.ryErrUsta.errPid); } return FTDM_SUCCESS; @@ -110,6 +107,8 @@ ftdm_status_t handle_relay_disconnect_on_error(RyMngmt *sta) ftdm_status_t handle_relay_disconnect_on_down(RyMngmt *sta) { + SS7_DEBUG("SS7 relay disconnect on down\n"); + /* check if the channel is a server, means we just lost a MGW */ if (g_ftdm_sngss7_data.cfg.relay[sta->t.usta.s.ryUpUsta.id].type == LRY_CT_TCP_SERVER) { block_all_ckts_for_relay(sta->t.usta.s.ryUpUsta.id); @@ -248,7 +247,7 @@ ftdm_status_t block_all_ckts_for_relay(uint32_t procId) if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == SNG_CKT_VOICE) { /* send a block request via stack manager */ - ret = ftmod_ss7_block_isup_ckt(g_ftdm_sngss7_data.cfg.isupCkt[x].id); + ret = ftmod_ss7_block_isup_ckt_nowait(g_ftdm_sngss7_data.cfg.isupCkt[x].id); if (ret) { SS7_INFO("Successfully BLOcked CIC:%d(ckt:%d) due to Relay failure\n", g_ftdm_sngss7_data.cfg.isupCkt[x].cic, @@ -331,6 +330,7 @@ static ftdm_status_t unblock_all_ckts_for_relay(uint32_t procId) } #endif + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 457964a95f..70d1315353 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -87,8 +87,12 @@ FTDM_STR2ENUM(ftmod_ss7_blk_state2flag, ftmod_ss7_blk_flag2str, sng_ckt_block_fl /* FUNCTIONS ******************************************************************/ static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t default_val); static uint8_t get_ftdm_val(ftdm2trillium_t *vals, uint8_t trillium_val, uint8_t default_val); +ftdm_status_t four_char_to_hex(const char* in, uint16_t* out) ; +ftdm_status_t hex_to_four_char(uint16_t in, char* out); +ftdm_status_t hex_to_char(uint16_t in, char* out, int len); +ftdm_status_t char_to_hex(const char* in, uint16_t* out, int len); /* Maps generic FreeTDM CPC codes to SS7 CPC codes */ ftdm2trillium_t cpc_codes[] = { @@ -186,31 +190,40 @@ ftdm_status_t copy_cgPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cgPt ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Calling NADI value \"%s\"\n", clg_nadi); cgPtyNum->natAddrInd.val = atoi(clg_nadi); } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", cgPtyNum->presRest.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number NADI value %d\n", cgPtyNum->natAddrInd.val); 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 */ + char var[FTDM_DIGITS_LIMIT]; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (cdPtyNum->eh.pres == PRSNT_NODEF && + cdPtyNum->natAddrInd.pres == PRSNT_NODEF) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Called Party Number NADI %d\n", cdPtyNum->natAddrInd.val); + sprintf(var, "%d", cdPtyNum->natAddrInd.val); + sngss7_add_var(sngss7_info, "ss7_cld_nadi", var); + } + return FTDM_SUCCESS; } ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPtyNum) { - const char *cld_nadi = NULL; + const char *val = 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); + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_nadi"); + if (!ftdm_strlen_zero(val)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Called NADI value \"%s\"\n", val); + cdPtyNum->natAddrInd.val = atoi(val); } 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); @@ -220,11 +233,78 @@ ftdm_status_t copy_cdPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCdPtyNum *cdPt cdPtyNum->numPlan.val = 0x01; cdPtyNum->innInd.pres = PRSNT_NODEF; - cdPtyNum->innInd.val = 0x01; + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_inn"); + if (!ftdm_strlen_zero(val)) { + cdPtyNum->innInd.val = atoi(val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Called INN value \"%s\"\n", val); + } else { + cdPtyNum->innInd.val = 0x01; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Called INN value, set to default value 0x01\n"); + } return copy_tknStr_to_sngss7(caller_data->dnis.digits, &cdPtyNum->addrSig, &cdPtyNum->oddEven); } +ftdm_status_t copy_locPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum) +{ + return FTDM_SUCCESS; +} + +ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *locPtyNum) +{ + const char *val = NULL; + const char *loc_nadi = NULL; + int pres_val = PRSNT_NODEF; + + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; + + if (!strcasecmp(caller_data->loc.digits, "NULL")) { + pres_val = NOTPRSNT; + return FTDM_SUCCESS; + } + + locPtyNum->eh.pres = pres_val; + locPtyNum->natAddrInd.pres = pres_val; + locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; + + locPtyNum->scrnInd.pres = pres_val; + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_screen_ind"); + if (!ftdm_strlen_zero(val)) { + locPtyNum->scrnInd.val = atoi(val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Screening Ind %d\n", locPtyNum->scrnInd.val); + } else { + locPtyNum->scrnInd.val = caller_data->screen; + } + + locPtyNum->presRest.pres = pres_val; + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_pres_ind"); + if (!ftdm_strlen_zero(val)) { + locPtyNum->presRest.val = atoi(val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Presentation Ind %d\n", locPtyNum->presRest.val); + } else { + locPtyNum->presRest.val = caller_data->pres; + } + + locPtyNum->numPlan.pres = pres_val; + locPtyNum->numPlan.val = 0x01; + + locPtyNum->niInd.pres = pres_val; + locPtyNum->niInd.val = 0x00; + + /* check if the user would like a custom NADI value for the Location Reference */ + loc_nadi = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_loc_nadi"); + if (!ftdm_strlen_zero(loc_nadi)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Location Reference NADI value \"%s\"\n", loc_nadi); + locPtyNum->natAddrInd.val = atoi(loc_nadi); + } else { + locPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].loc_nadi; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "No user supplied NADI value found for LOC, using \"%d\"\n", locPtyNum->natAddrInd.val); + } + + return copy_tknStr_to_sngss7(caller_data->loc.digits, &locPtyNum->addrSig, &locPtyNum->oddEven); +} + ftdm_status_t copy_genNmb_to_sngss7(ftdm_channel_t *ftdmchan, SiGenNum *genNmb) { const char *val = NULL; @@ -369,11 +449,18 @@ ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *red 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); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Redirection Number\"%s\"\n", caller_data->rdnis.digits); if (copy_tknStr_to_sngss7(caller_data->rdnis.digits, &redirgNum->addrSig, &redirgNum->oddEven) != FTDM_SUCCESS) { return FTDM_FAIL; } } else { + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_pres_ind"); + if (!ftdm_strlen_zero(val)) { + redirgNum->presRest.val = atoi(val); + } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirecting Number Address Presentation Restricted Ind:%d\n", redirgNum->presRest.val); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Number\n"); return FTDM_SUCCESS; } @@ -474,6 +561,227 @@ ftdm_status_t copy_redirgNum_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *r return FTDM_SUCCESS; } +ftdm_status_t copy_redirgInfo_from_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo) +{ + char val[20]; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (redirInfo->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Redirecting Information available\n"); + return FTDM_SUCCESS; + } + + + if (redirInfo->redirInd.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", redirInfo->redirInd.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirection Information - redirection indicator:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_rdinfo_indicator", val); + } + + if (redirInfo->origRedirReas.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", redirInfo->origRedirReas.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirection Information - original redirection reason:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_rdinfo_orig", val); + } + + if (redirInfo->redirCnt.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", redirInfo->redirCnt.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirection Information - redirection count:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_rdinfo_count", val); + } + + if (redirInfo->redirReas.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", redirInfo->redirReas.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Redirection Information - redirection reason:%s\n", val); + sngss7_add_var(sngss7_info, "ss7_rdinfo_reason", val); + } + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_redirgInfo_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirInfo *redirInfo) +{ + const char* val = NULL; + int bProceed = 0; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_indicator"); + if (!ftdm_strlen_zero(val)) { + redirInfo->redirInd.val = atoi(val); + redirInfo->redirInd.pres = 1; + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Indicator\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_orig"); + if (!ftdm_strlen_zero(val)) { + redirInfo->origRedirReas.val = atoi(val); + redirInfo->origRedirReas.pres = 1; + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Original Reasons\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_count"); + if (!ftdm_strlen_zero(val)) { + redirInfo->redirCnt.val = atoi(val); + redirInfo->redirCnt.pres= 1; + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Count\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdinfo_reason"); + if (!ftdm_strlen_zero(val)) { + redirInfo->redirReas.val = atoi(val); + redirInfo->redirReas.pres = 1; + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Redirection Information on Redirection Reasons\n"); + } + + if( bProceed == 1 ) { + redirInfo->eh.pres = PRSNT_NODEF; + } else { + redirInfo->eh.pres = NOTPRSNT; + } + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_access_transport_from_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt) +{ + char val[3*((MF_SIZE_TKNSTRE + 7) & 0xff8)]; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (accTrnspt->eh.pres != PRSNT_NODEF || accTrnspt->infoElmts.pres !=PRSNT_NODEF) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Access Transport IE available\n"); + return FTDM_SUCCESS; + } + + ftdm_url_encode((const char*)accTrnspt->infoElmts.val, val, accTrnspt->infoElmts.len); + sngss7_add_var (sngss7_info, "ss7_access_transport_urlenc", val); + + return FTDM_SUCCESS; +} +ftdm_status_t copy_access_transport_to_sngss7(ftdm_channel_t *ftdmchan, SiAccTrnspt *accTrnspt) +{ + const char *val = NULL; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_access_transport_urlenc"); + if (ftdm_strlen_zero(val)) { + accTrnspt->eh.pres = NOTPRSNT; + accTrnspt->infoElmts.pres = NOTPRSNT; + } + else { + char *val_dec = NULL; + int val_len = strlen (val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found Access Transport IE encoded : %s\n", val); + + accTrnspt->eh.pres = PRSNT_NODEF; + accTrnspt->infoElmts.pres = PRSNT_NODEF; + + val_dec = ftdm_strdup(val); + ftdm_url_decode(val_dec, (ftdm_size_t*)&val_len); + memcpy (accTrnspt->infoElmts.val, val_dec, val_len); + accTrnspt->infoElmts.len = val_len; + ftdm_safe_free(val_dec); + } + return FTDM_SUCCESS; +} + +ftdm_status_t copy_ocn_from_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) +{ + char val[20]; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (origCdNum->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No Original Called Number available\n"); + return FTDM_SUCCESS; + } + + if (origCdNum->addrSig.pres == PRSNT_NODEF) { + copy_tknStr_from_sngss7(origCdNum->addrSig, val, origCdNum->oddEven); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Digits: %s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn", val); + } + + if (origCdNum->natAddr.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->natAddr.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - NADI: %s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_nadi", val); + } + + if (origCdNum->numPlan.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->numPlan.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Plan: %s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_plan", val); + } + + if (origCdNum->presRest.pres == PRSNT_NODEF) { + snprintf(val, sizeof(val), "%d", origCdNum->presRest.val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Original Called Number - Presentation: %s\n", val); + sngss7_add_var(sngss7_info, "ss7_ocn_pres", val); + } + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_ocn_to_sngss7(ftdm_channel_t *ftdmchan, SiOrigCdNum *origCdNum) +{ + const char *val = NULL; + int bProceed = 0; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn"); + if (!ftdm_strlen_zero(val)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Digits: %s\n", val); + if (copy_tknStr_to_sngss7((char*)val, &origCdNum->addrSig, &origCdNum->oddEven) != FTDM_SUCCESS) { + return FTDM_FAIL; + } + origCdNum->addrSig.pres = 1; + } else { + return FTDM_SUCCESS; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_nadi"); + if (!ftdm_strlen_zero(val)) { + origCdNum->natAddr.val = atoi(val); + origCdNum->natAddr.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - NADI: %s\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number NADI value\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_plan"); + if (!ftdm_strlen_zero(val)) { + origCdNum->numPlan.val = atoi(val); + origCdNum->numPlan.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Plan: %s\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Plan value\n"); + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_ocn_pres"); + if (!ftdm_strlen_zero(val)) { + origCdNum->presRest.val = atoi(val); + origCdNum->presRest.pres = 1; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Original Called Number - Presentation: %s\n", val); + bProceed = 1; + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No user supplied Original Called Number Presentation value\n"); + } + + if( bProceed == 1 ) { + origCdNum->eh.pres = PRSNT_NODEF; + } else { + origCdNum->eh.pres = NOTPRSNT; + } + + return FTDM_SUCCESS; +} + ftdm_status_t copy_cgPtyCat_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyCat *cgPtyCat) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; @@ -598,27 +906,323 @@ ftdm_status_t copy_natConInd_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *na return FTDM_SUCCESS; } +ftdm_status_t four_char_to_hex(const char* in, uint16_t* out) +{ + int i= 4; + char a, b, c, d; + if (!in || 4>strlen(in)) { + return FTDM_FAIL; + } + while(i) + { + switch((char)*(in+(4-i))) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (i==4) { + d = *(in+(4-i)) - 48; + } else if (i==3) { + c = *(in+(4-i)) - 48; + } else if (i==2) { + b = *(in+(4-i)) - 48; + } else { + a = *(in+(4-i)) - 48; + } + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + if (i==4) { + d = *(in+(4-i)) - 55; + } else if (i==3) { + c = *(in+(4-i)) - 55; + } else if (i==2) { + b = *(in+(4-i)) - 55; + } else { + a = *(in+(4-i)) - 55; + } + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + if (i==4) { + d = *(in+(4-i)) - 87; + } else if (i==3) { + c = *(in+(4-i)) - 87; + } else if (i==2) { + b = *(in+(4-i)) - 87; + } else { + a = *(in+(4-i)) - 87; + } + break; + default: + SS7_ERROR("Invalid character found when decoding hex string, %c!\n", *(in+(4-i)) ); + break; + } + i--; + }; + + *out |= d; + *out = *out<<4; + *out |= c; + *out = *out<<4; + *out |= b; + *out = *out<<4; + *out |= a; + + return FTDM_SUCCESS; +} + +ftdm_status_t char_to_hex(const char* in, uint16_t* out, int len) +{ + int i= len; + char *val = ftdm_malloc(len*sizeof(char)); + + if (!val ||!in || len>strlen(in)) { + return FTDM_FAIL; + } + + while(i) + { + switch((char)*(in+(len-i))) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + *(val+(len-i)) = *(in+(len-i)) - 48; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + *(val+(len-i)) = *(in+(len-i)) - 55; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + *(val+(len-i)) = *(in+(len-i)) - 87; + break; + default: + SS7_ERROR("Invalid character found when decoding hex string, %c!\n", *(in+(len-i)) ); + break; + } + i--; + }; + + for (i=0; i<=len-1; i++) { + *out = *out << 4; + *out |= *(val+i); + } + + return FTDM_SUCCESS; +} + + + +ftdm_status_t hex_to_char(uint16_t in, char* out, int len) +{ + char val=0; + int mask = 0xf; + int i=0; + if (!out) { + return FTDM_SUCCESS; + } + + for (i=len-1; i>=0; i--) { + val = (in & (mask<<(4*i))) >> (4*i); + sprintf (out+(len-1-i), "%x", val); + } + + return FTDM_SUCCESS; +} +ftdm_status_t hex_to_four_char(uint16_t in, char* out) +{ + char val=0; + int mask = 0xf; + int i=0; + if (!out) { + return FTDM_SUCCESS; + } + + for (i=3; i>=0; i--) { + val = (in & (mask<<(4*i))) >> (4*i); + sprintf (out+(3-i), "%x", val); + } + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_NatureOfConnection_to_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd) +{ + const char *val = NULL; + + natConInd->eh.pres = PRSNT_NODEF; + natConInd->satInd.pres = PRSNT_NODEF; + natConInd->contChkInd.pres = PRSNT_NODEF;; + natConInd->echoCntrlDevInd.pres = PRSNT_NODEF; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_nature_connection_hex"); + if (!ftdm_strlen_zero(val)) { + uint16_t val_hex = 0; + if (char_to_hex (val, &val_hex, 2) == FTDM_FAIL) { + SS7_ERROR ("Wrong value set in ss7_iam_nature_connection_hex variable. Please correct the error. Setting to default values.\n" ); + } else { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "hex = 0x%x\n", val_hex); + natConInd->satInd.val = (val_hex & 0x3); + natConInd->contChkInd.val = (val_hex & 0xc)>>2; + natConInd->echoCntrlDevInd.val = (val_hex & 0x10) >> 4; + + return FTDM_SUCCESS; + } + } + + natConInd->satInd.val = 0; + natConInd->contChkInd.val = 0; + natConInd->echoCntrlDevInd.val = 0; + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_NatureOfConnection_from_sngss7(ftdm_channel_t *ftdmchan, SiNatConInd *natConInd ) +{ + char val[3]; + uint16_t val_hex = 0; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset (val, 0, 3*sizeof(char)); + if (natConInd->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No nature of connection indicator IE available\n"); + return FTDM_SUCCESS; + } + + val_hex |= natConInd->satInd.val; + val_hex |= natConInd->contChkInd.val << 2; + val_hex |= natConInd->echoCntrlDevInd.val <<4; + hex_to_char(val_hex, val, 2) ; + + sngss7_add_var(sngss7_info, "ss7_iam_nature_connection_hex", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Nature of connection indicator Hex: 0x%s\n", val); + + return FTDM_SUCCESS; +} + +ftdm_status_t copy_fwdCallInd_hex_from_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd) +{ + char val[5]; + uint16_t val_hex = 0; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + memset (val, 0, 5*sizeof(char)); + if (fwdCallInd->eh.pres != PRSNT_NODEF ) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No forward call indicator IE available\n"); + return FTDM_SUCCESS; + } + + val_hex |= fwdCallInd->natIntCallInd.val << 8; + val_hex |= (fwdCallInd->end2EndMethInd.val & 0x1) << 9; + val_hex |= ((fwdCallInd->end2EndMethInd.val & 0x2)>>1) << 10; + val_hex |= fwdCallInd->intInd.val << 11; + val_hex |= fwdCallInd->end2EndInfoInd.val << 12; + val_hex |= fwdCallInd->isdnUsrPrtInd.val << 13; + val_hex |= (fwdCallInd->isdnUsrPrtPrfInd.val & 0x1) << 14; + val_hex |= ((fwdCallInd->isdnUsrPrtPrfInd.val & 0x2)>>1) << 15; + + val_hex |= fwdCallInd->isdnAccInd.val; + hex_to_four_char(val_hex, val) ; + + sngss7_add_var(sngss7_info, "ss7_iam_fwd_ind_hex", val); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Forwad Call Indicator Hex: 0x%s\n", val); + + return FTDM_SUCCESS; +} + ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd *fwdCallInd) { + const char *val = NULL; + int acc_val = ISDNACC_ISDN; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; fwdCallInd->eh.pres = PRSNT_NODEF; fwdCallInd->natIntCallInd.pres = PRSNT_NODEF; - fwdCallInd->natIntCallInd.val = 0x00; fwdCallInd->end2EndMethInd.pres = PRSNT_NODEF; - fwdCallInd->end2EndMethInd.val = E2EMTH_NOMETH; fwdCallInd->intInd.pres = PRSNT_NODEF; - fwdCallInd->intInd.val = INTIND_NOINTW; fwdCallInd->end2EndInfoInd.pres = PRSNT_NODEF; - fwdCallInd->end2EndInfoInd.val = E2EINF_NOINFO; fwdCallInd->isdnUsrPrtInd.pres = PRSNT_NODEF; - fwdCallInd->isdnUsrPrtInd.val = ISUP_USED; fwdCallInd->isdnUsrPrtPrfInd.pres = PRSNT_NODEF; - fwdCallInd->isdnUsrPrtPrfInd.val = PREF_PREFAW; fwdCallInd->isdnAccInd.pres = PRSNT_NODEF; - fwdCallInd->isdnAccInd.val = ISDNACC_ISDN; fwdCallInd->sccpMethInd.pres = PRSNT_NODEF; fwdCallInd->sccpMethInd.val = SCCPMTH_NOIND; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_fwd_ind_hex"); + if (!ftdm_strlen_zero(val)) { + uint16_t val_hex = 0; + if (four_char_to_hex (val, &val_hex) == FTDM_FAIL) { + SS7_ERROR ("Wrong value set in iam_fwd_ind_HEX variable. Please correct the error. Setting to default values.\n" ); + } else { + fwdCallInd->natIntCallInd.val = (val_hex & 0x100)>>8; + fwdCallInd->end2EndMethInd.val = (val_hex & 0x600)>>9; + fwdCallInd->intInd.val = (val_hex & 0x800)>>11; + fwdCallInd->end2EndInfoInd.val = (val_hex & 0x1000)>>12; + fwdCallInd->isdnUsrPrtInd.val = (val_hex & 0x2000)>>13; + fwdCallInd->isdnUsrPrtPrfInd.val = (val_hex & 0xC000)>>14; + fwdCallInd->isdnUsrPrtPrfInd.val = (fwdCallInd->isdnUsrPrtPrfInd.val==0x03)?0x0:fwdCallInd->isdnUsrPrtPrfInd.val; + fwdCallInd->isdnAccInd.val = val_hex & 0x1; + + if ((g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS88) || + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS92) || + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS95)) { + + /* include only if we're running ANSI */ + fwdCallInd->transCallNInd.pres = PRSNT_NODEF; + fwdCallInd->transCallNInd.val = 0x0; + } + + return FTDM_SUCCESS; + } + } + + fwdCallInd->natIntCallInd.val = 0x00; + fwdCallInd->end2EndMethInd.val = E2EMTH_NOMETH; + fwdCallInd->intInd.val = INTIND_NOINTW; + fwdCallInd->end2EndInfoInd.val = E2EINF_NOINFO; + fwdCallInd->isdnUsrPrtInd.val = ISUP_USED; + fwdCallInd->isdnUsrPrtPrfInd.val = PREF_PREFAW; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_fwd_ind_isdn_access_ind"); + if (ftdm_strlen_zero(val)) { + /* Kept for backward compatibility */ + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "iam_fwd_ind_isdn_access_ind"); + } + + if (!ftdm_strlen_zero(val)) { + acc_val = (int)atoi(val); + } + + fwdCallInd->isdnAccInd.val = acc_val; if ((g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS88) || (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].switchType == LSI_SW_ANS92) || @@ -628,6 +1232,7 @@ ftdm_status_t copy_fwdCallInd_to_sngss7(ftdm_channel_t *ftdmchan, SiFwdCallInd * fwdCallInd->transCallNInd.pres = PRSNT_NODEF; fwdCallInd->transCallNInd.val = 0x0; } + return FTDM_SUCCESS; } @@ -642,32 +1247,194 @@ ftdm_status_t copy_txMedReq_to_sngss7(ftdm_channel_t *ftdmchan, SiTxMedReq *txMe ftdm_status_t copy_usrServInfoA_to_sngss7(ftdm_channel_t *ftdmchan, SiUsrServInfo *usrServInfoA) { - usrServInfoA->eh.pres = PRSNT_NODEF; + int bProceed = 0; + const char *val = NULL; + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_trans_cap"); + if (!ftdm_strlen_zero(val)) { + int itc_type = 0; + if (!strcasecmp(val, "SPEECH")) { + itc_type = ITC_SPEECH; + } else if (!strcasecmp(val, "UNRESTRICTED")) { + itc_type = ITC_UNRDIG; + } else if (!strcasecmp(val, "RESTRICTED")) { + itc_type = ITC_RESDIG; + } else if (!strcasecmp(val, "31KHZ")) { + itc_type = ITC_A31KHZ; + } else if (!strcasecmp(val, "7KHZ")) { + itc_type = ITC_A7KHZ; + } else if (!strcasecmp(val, "15KHZ")) { + itc_type = ITC_A15KHZ; + } else if (!strcasecmp(val, "VIDEO")) { + itc_type = ITC_VIDEO; + } else { + itc_type = ITC_SPEECH; + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI transmission capability parameter is wrong : %s. Setting to default SPEECH. \n", val ); + } + + usrServInfoA->infoTranCap.pres = PRSNT_NODEF; + usrServInfoA->infoTranCap.val = get_trillium_val(bc_cap_codes, ftdmchan->caller_data.bearer_capability, itc_type); + bProceed = 1; + } else { + usrServInfoA->infoTranCap.pres = NOTPRSNT; + } - usrServInfoA->infoTranCap.pres = PRSNT_NODEF; + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_code_standard"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->cdeStand.pres = PRSNT_NODEF; + usrServInfoA->cdeStand.val = (int)atoi(val); /* default is 0x0 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI coding standard = %d\n", usrServInfoA->cdeStand.val ); + bProceed = 1; + } else { + usrServInfoA->cdeStand.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_trans_mode"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->tranMode.pres = PRSNT_NODEF; + usrServInfoA->tranMode.val = (int)atoi(val); /* transfer mode, default is 0x0*/ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI transfer mode = %d\n", usrServInfoA->tranMode.val ); + bProceed = 1; + } else { + usrServInfoA->tranMode.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_trans_rate_0"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->infoTranRate0.pres = PRSNT_NODEF; + usrServInfoA->infoTranRate0.val = (int)atoi(val); /* default is 0x10, 64kbps origination to destination*/ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI trans rate 0 = %d\n", usrServInfoA->infoTranRate0.val ); + bProceed = 1; + } else { + usrServInfoA->infoTranRate0.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_trans_rate_1"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->infoTranRate1.pres = PRSNT_NODEF; + usrServInfoA->infoTranRate1.val = (int)atoi(val); /* 64kbps destination to origination, default is 0x10 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI trans rate 1 = %d\n", usrServInfoA->infoTranRate1.val ); + bProceed = 1; + } else { + usrServInfoA->infoTranRate1.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer1_ident"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->lyr1Ident.pres = PRSNT_NODEF; + usrServInfoA->lyr1Ident.val = (int)atoi(val); /*default value is 0x01 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 1 indentification = %d\n", usrServInfoA->lyr1Ident.val ); + bProceed = 1; + } else { + usrServInfoA->lyr1Ident.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer1_prot"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->usrInfLyr1Prot.pres = PRSNT_NODEF; + usrServInfoA->usrInfLyr1Prot.val = (int)atoi(val); /*default value is 0x02 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 1 protocol = %d\n", usrServInfoA->usrInfLyr1Prot.val ); + bProceed = 1; + } else { + usrServInfoA->usrInfLyr1Prot.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer2_ident"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->lyr2Ident.pres = PRSNT_NODEF; + usrServInfoA->lyr2Ident.val = (int)atoi(val); /*default value is 0x01 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 2 indentification = %d\n", usrServInfoA->lyr2Ident.val ); + bProceed = 1; + } else { + usrServInfoA->lyr2Ident.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer2_prot"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->usrInfLyr2Prot.pres = PRSNT_NODEF; + usrServInfoA->usrInfLyr2Prot.val = (int)atoi(val); /*default value is 0x02 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 2 protocol = %d\n", usrServInfoA->usrInfLyr2Prot.val ); + bProceed = 1; + } else { + usrServInfoA->usrInfLyr2Prot.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer3_ident"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->lyr3Ident.pres = PRSNT_NODEF; + usrServInfoA->lyr3Ident.val = (int)atoi(val); /*default value is 0x01 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 3 indentification = %d\n", usrServInfoA->lyr3Ident.val ); + bProceed = 1; + } else { + usrServInfoA->lyr3Ident.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_layer3_prot"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->usrInfLyr3Prot.pres = PRSNT_NODEF; + usrServInfoA->usrInfLyr3Prot.val = (int)atoi(val); /*default value is 0x02 */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI layer 3 protocol = %d\n", usrServInfoA->usrInfLyr3Prot.val ); + bProceed = 1; + } else { + usrServInfoA->usrInfLyr3Prot.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_chan_struct"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->chanStruct.pres = PRSNT_NODEF; + usrServInfoA->chanStruct.val = (int)atoi(val); /* default value is 0x1, 8kHz integrity */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI channel structure = %d\n", usrServInfoA->chanStruct.val ); + bProceed = 1; + } else { + usrServInfoA->chanStruct.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_config"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->config.pres = PRSNT_NODEF; + usrServInfoA->config.val = (int)atoi(val); /* default value is 0x0, point to point configuration */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI configuration = %d\n", usrServInfoA->config.val ); + bProceed = 1; + } else { + usrServInfoA->config.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_establish"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->establish.pres = PRSNT_NODEF; + usrServInfoA->establish.val = (int)atoi(val); /* default value is 0x0, on demand */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI establishment = %d\n", usrServInfoA->establish.val ); + bProceed = 1; + } else { + usrServInfoA->establish.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_symmetry"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->symmetry.pres = PRSNT_NODEF; + usrServInfoA->symmetry.val = (int)atoi(val); /* default value is 0x0, bi-directional symmetric */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI symmetry = %d\n", usrServInfoA->symmetry.val ); + bProceed = 1; + } else { + usrServInfoA->symmetry.pres = NOTPRSNT; + } + + val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_iam_usi_rate_multiplier"); + if (!ftdm_strlen_zero(val)) { + usrServInfoA->rateMultiplier.pres = PRSNT_NODEF; + usrServInfoA->rateMultiplier.val = (int)atoi(val); /* default value is 0x1, 1x rate multipler */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "USI rate multipier = %d\n", usrServInfoA->rateMultiplier.val ); + bProceed = 1; + } else { + usrServInfoA->rateMultiplier.pres = NOTPRSNT; + } + + if (bProceed) { + usrServInfoA->eh.pres = PRSNT_NODEF; + } else { + usrServInfoA->eh.pres = NOTPRSNT; + } - usrServInfoA->infoTranCap.val = get_trillium_val(bc_cap_codes, ftdmchan->caller_data.bearer_capability, ITC_SPEECH); - - usrServInfoA->cdeStand.pres = PRSNT_NODEF; - usrServInfoA->cdeStand.val = 0x0; /* ITU-T standardized coding */ - usrServInfoA->tranMode.pres = PRSNT_NODEF; - usrServInfoA->tranMode.val = 0x0; /* circuit mode */ - usrServInfoA->infoTranRate0.pres = PRSNT_NODEF; - usrServInfoA->infoTranRate0.val = 0x10; /* 64kbps origination to destination */ - usrServInfoA->infoTranRate1.pres = PRSNT_NODEF; - usrServInfoA->infoTranRate1.val = 0x10; /* 64kbps destination to origination */ - usrServInfoA->chanStruct.pres = PRSNT_NODEF; - usrServInfoA->chanStruct.val = 0x1; /* 8kHz integrity */ - usrServInfoA->config.pres = PRSNT_NODEF; - usrServInfoA->config.val = 0x0; /* point to point configuration */ - usrServInfoA->establish.pres = PRSNT_NODEF; - usrServInfoA->establish.val = 0x0; /* on demand */ - usrServInfoA->symmetry.pres = PRSNT_NODEF; - usrServInfoA->symmetry.val = 0x0; /* bi-directional symmetric */ - usrServInfoA->usrInfLyr1Prot.pres = PRSNT_NODEF; - usrServInfoA->usrInfLyr1Prot.val = 0x2; /* G.711 ulaw */ - usrServInfoA->rateMultiplier.pres = PRSNT_NODEF; - usrServInfoA->rateMultiplier.val = 0x1; /* 1x rate multipler */ return FTDM_SUCCESS; } @@ -866,11 +1633,6 @@ int check_for_state_change(ftdm_channel_t *ftdmchan) /******************************************************************************/ ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan) { - if (g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj == NULL) { - SS7_ERROR("sngss7_info is Null for circuit #%d\n", circuit); - return FTDM_FAIL; - } - if (!g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj) { SS7_ERROR("No ss7 info for circuit #%d\n", circuit); return FTDM_FAIL; @@ -879,10 +1641,21 @@ ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_in *sngss7_info = g_ftdm_sngss7_data.cfg.isupCkt[circuit].obj; if (!(*sngss7_info)->ftdmchan) { - SS7_ERROR("No channel for circuit #%d\n", circuit); + SS7_ERROR("No ftdmchan for circuit #%d\n", circuit); return FTDM_FAIL; } + if (!(*sngss7_info)->ftdmchan->span) { + SS7_CRITICAL("ftdmchan->span = NULL for circuit #%d\n",circuit); + return FTDM_FAIL; + + } + if (!(*sngss7_info)->ftdmchan->span->signal_data) { + SS7_CRITICAL("ftdmchan->span->signal_data = NULL for circuit #%d\n",circuit); + return FTDM_FAIL; + + } + *ftdmchan = (*sngss7_info)->ftdmchan; return FTDM_SUCCESS; } @@ -1366,7 +2139,7 @@ ftdm_status_t process_span_ucic(ftdm_span_t *ftdmspan) /* lock the channel */ ftdm_channel_lock(ftdmchan); - SS7_INFO_CHAN(ftdmchan, "[CIC:%d]Rx UCIC\n", sngss7_info->circuit->cic); + SS7_INFO_CHAN(ftdmchan, "[CIC:%d]Rx Span UCIC\n", sngss7_info->circuit->cic); /* clear up any pending state changes */ while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { @@ -1881,6 +2654,7 @@ ftdm_status_t check_status_of_all_isup_intf(void) if (ftmod_ss7_isup_intf_sta(sngss7_intf->id, &status)) { SS7_ERROR("Failed to get status of ISUP intf %d\n", sngss7_intf->id); + sngss7_set_flag(sngss7_intf, SNGSS7_PAUSED); continue; } @@ -2035,6 +2809,55 @@ void sngss7_set_sig_status(sngss7_chan_data_t *sngss7_info, ftdm_signaling_statu return; } +#if 0 +ftdm_status_t check_for_invalid_states(ftdm_channel_t *ftmchan) +{ + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + + if (!sngss7_info) { + SS7_WARN_CHAN(ftdmchan, "Found ftdmchan with no sig module data!%s\n", " "); + return FTDM_FAIL; + } + + if (sngss7_test_flag(sngss7_intf, SNGSS7_PAUSED)) { + return FTDM_SUCCESS; + } + + switch (ftdmchan->state) { + case UP: + case DOWN: + return FTDM_SUCCESS; + + default: + if ((ftdm_current_time_in_ms() - ftdmchan->last_state_change_time) > 30000) { + SS7_WARN_CHAN(ftdmchan, "Circuite in state=%s too long - resetting!%s\n", + ftdm_channel_state2str(ftdmchan->state)); + + ftdm_channel_lock(ftdmchan); + + if (sngss7_channel_status_clear(sngss7_info)) { + sngss7_tx_reset_restart(sngss7_info); + + if (ftdmchan->state == FTDM_CHANNEL_STATE_RESTART) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } else { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + } + } else { + + } + + + + ftdm_channel_unlock(ftdmchan); + } + } + + return FTDM_SUCCESS; +} +#endif + + /******************************************************************************/ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) { @@ -2047,6 +2870,7 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) uint8_t bits_ef = 0; int x; int ret; + ret=0; for (x = 1; x < (ftdmspan->chan_count + 1); x++) { /**************************************************************************/ @@ -2071,12 +2895,12 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* 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); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Circuit set to PAUSED %s\n"," "); /* 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); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Circuit set to RESUMED %s\n"," "); /* throw the resume flag */ sngss7_clear_ckt_flag(sngss7_info, FLAG_INFID_PAUSED); sngss7_set_ckt_flag(sngss7_info, FLAG_INFID_RESUME); @@ -2084,7 +2908,11 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* 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); + /* NC: Circuit statistic failed: does not exist. Must re-configure circuit + Reset the circuit CONFIGURED flag so that RESUME will reconfigure + this circuit. */ + sngss7_info->circuit->flags &= ~SNGSS7_CONFIGURED; + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR,"Failed to read isup ckt = %d status\n", sngss7_info->circuit->id); continue; } @@ -2092,10 +2920,20 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) 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; + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Circuit state=0x%X ab=0x%X cd=0x%X ef=0x%X\n",state,bits_ab,bits_cd,bits_ef); if (bits_cd == 0x0) { /* check if circuit is UCIC or transient */ if (bits_ab == 0x3) { + SS7_INFO("ISUP CKT %d re-configuration pending!\n", x); + sngss7_info->circuit->flags &= ~SNGSS7_CONFIGURED; + SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + + /* NC: The code below should be deleted. Its here for hitorical + reason. The RESUME code will reconfigure the channel since + the CONFIGURED flag has been reset */ +#if 0 /* bit a and bit b are set, unequipped */ ret = ftmod_ss7_isup_ckt_config(sngss7_info->circuit->id); if (ret) { @@ -2118,8 +2956,22 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* unlock the channel */ ftdm_mutex_unlock(ftdmchan->mutex); +#endif - } /* if (bits_ab == 0x3) */ + } else { /* if (bits_ab == 0x3) */ + /* The stack status is not blocked. However this is possible if + the circuit state was UP. So even though Master sent out the BLO + the status command is not showing it. + + As a kudge. We will try to send out an UBL even though the status + indicates that there is no BLO. */ + if (!sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) { + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + + /* set the channel to suspended state */ + SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + } } else { /* check the maintenance block status in bits A and B */ switch (bits_ab) { @@ -2129,16 +2981,27 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) break; /**************************************************************************/ case (1): - /* locally blocked */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); + /* The stack status is Blocked. Check if the block was sent + by user via console. If the block was not sent by user then, it + was sent out by Master due to relay down. + Therefore send out the unblock to clear it */ + if (!sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) { + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + + /* set the channel to suspended state */ + SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + + /* Only locally blocked, thus remove a remote block */ + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_clear_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); - /* 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); + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); /* set the channel to suspended state */ SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -2146,8 +3009,11 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /**************************************************************************/ case (3): /* both locally and remotely blocked */ - sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX); + if (!sngss7_test_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) { + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_UNBLK_TX); + } sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX); + sngss7_set_ckt_blk_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX_DN); /* set the channel to suspended state */ SS7_STATE_CHANGE(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -2199,7 +3065,7 @@ ftdm_status_t check_for_reconfig_flag(ftdm_span_t *ftdmspan) /* 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; @@ -2470,8 +3336,9 @@ ftdm_status_t sngss7_save_iam(ftdm_channel_t *ftdmchan, SiConEvnt *siConEvnt) ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "IAM variable length:%"FTDM_SIZE_FMT"\n", strlen(url_encoded_iam)); - if (strlen(url_encoded_iam) > g_ftdm_sngss7_data.cfg.transparent_iam_max_size) { - ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "IAM variable length exceeds max size (len:%"FTDM_SIZE_FMT" max:%d) \n", strlen(url_encoded_iam), g_ftdm_sngss7_data.cfg.transparent_iam_max_size); + if (strlen(url_encoded_iam) > sngss7_info->circuit->transparent_iam_max_size) { + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "IAM variable length exceeds max size (len:%d max:%d) \n", + strlen(url_encoded_iam), sngss7_info->circuit->transparent_iam_max_size); ret_val = FTDM_FAIL; goto done; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c index 6138ea34b0..8cac996213 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c @@ -49,7 +49,7 @@ /******************************************************************************/ /* PROTOTYPES *****************************************************************/ -void handle_isup_t35(void *userdata); + /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -76,10 +76,13 @@ void handle_isup_t35(void *userdata) /* end the call */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); - /* kill t10 if active */ + /* kill t10 t39 if active */ if (sngss7_info->t10.hb_timer_id) { ftdm_sched_cancel_timer (sngss7_info->t10.sched, sngss7_info->t10.hb_timer_id); } + if (sngss7_info->t39.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t39.sched, sngss7_info->t39.hb_timer_id); + } /*unlock*/ ftdm_channel_unlock(ftdmchan); @@ -108,7 +111,43 @@ void handle_isup_t10(void *userdata) SS7_FUNC_TRACE_EXIT(__FUNCTION__); } - + +void handle_isup_t39(void *userdata) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_timer_data_t *timer = userdata; + sngss7_chan_data_t *sngss7_info = timer->sngss7_info; + ftdm_channel_t *ftdmchan = sngss7_info->ftdmchan; + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_channel_lock(ftdmchan); + + /* Q.764 2.2.5 Address incomplete (T35 expiry action is hangup with cause 28 according to Table A.1/Q.764) */ + SS7_ERROR("[Call-Control] Timer 39 expired on CIC = %d\n", sngss7_info->circuit->cic); + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_ckt_flag(sngss7_info, FLAG_LOCAL_REL); + + /* hang up on timer expiry */ + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_INVALID_NUMBER_FORMAT; + + /* end the call */ + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + + /* kill t10 t35 if active */ + if (sngss7_info->t10.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t10.sched, sngss7_info->t10.hb_timer_id); + } + if (sngss7_info->t35.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t35.sched, sngss7_info->t35.hb_timer_id); + } + + /*unlock*/ + ftdm_channel_unlock(ftdmchan); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); +} /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 1631aec216..c028bb709d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -29,6 +29,12 @@ * 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. + * + * + * Contributors: + * + * James Zhang + * */ /* INCLUDE ********************************************************************/ @@ -124,9 +130,13 @@ typedef struct sng_ccSpan uint32_t clg_nadi; uint32_t cld_nadi; uint32_t rdnis_nadi; + uint32_t loc_nadi; uint32_t min_digits; - uint8_t itx_auto_reply; + uint32_t transparent_iam_max_size; uint8_t transparent_iam; + uint8_t cpg_on_progress_media; + uint8_t cpg_on_progress; + uint8_t itx_auto_reply; uint32_t t3; uint32_t t10; uint32_t t12; @@ -136,6 +146,7 @@ typedef struct sng_ccSpan uint32_t t16; uint32_t t17; uint32_t t35; + uint32_t t39; uint32_t tval; } sng_ccSpan_t; @@ -187,18 +198,20 @@ static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, i static int ftmod_ss7_fill_in_circuits(sng_span_t *sngSpan); static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot); +static void ftmod_ss7_set_glare_resolution (const char *method); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ + int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span) { + sng_route_t self_route; + sng_span_t sngSpan; int i = 0; const char *var = NULL; const char *val = NULL; ftdm_conf_node_t *ptr = NULL; - sng_route_t self_route; - sng_span_t sngSpan; /* clean out the isup ckt */ memset(&sngSpan, 0x0, sizeof(sngSpan)); @@ -206,11 +219,31 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa /* clean out the self route */ memset(&self_route, 0x0, sizeof(self_route)); + var = ftdm_parameters[i].var; + val = ftdm_parameters[i].val; + + g_ftdm_operating_mode = SNG_SS7_OPR_MODE_ISUP; + + /* confirm that the first parameter is the "operating-mode" */ + if(!strcasecmp(var, "operating-mode")){ + if(!strcasecmp(val, "ISUP")) { + g_ftdm_operating_mode = SNG_SS7_OPR_MODE_ISUP; + } + else if(!strcasecmp(val, "M2UA_SG")) { + g_ftdm_operating_mode = SNG_SS7_OPR_MODE_M2UA_SG; + } else { + SS7_DEBUG("Operating mode not specified, defaulting to ISUP\n"); + } + i++; + } + + + var = ftdm_parameters[i].var; val = ftdm_parameters[i].val; ptr = (ftdm_conf_node_t *)ftdm_parameters[i].ptr; - /* confirm that the first parameter is the "confnode" */ + /* confirm that the 2nd parameter is the "confnode" */ if (!strcasecmp(var, "confnode")) { /* parse the confnode and fill in the global libsng_ss7 config structure */ if (ftmod_ss7_parse_sng_isup(ptr)) { @@ -225,28 +258,20 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa } i++; - while (ftdm_parameters[i].var != NULL) { - /**************************************************************************/ + while (ftdm_parameters[i].var != NULL) { var = ftdm_parameters[i].var; val = ftdm_parameters[i].val; if (!strcasecmp(var, "dialplan")) { - /**********************************************************************/ /* don't care for now */ - /**********************************************************************/ } else if (!strcasecmp(var, "context")) { - /**********************************************************************/ /* don't care for now */ - /**********************************************************************/ - } else if (!strcasecmp(var, "ccSpanId")) { - /**********************************************************************/ + } else if (!strcasecmp(var, "span-id") || !strcasecmp(var, "ccSpanId")) { sngSpan.ccSpanId = atoi(val); SS7_DEBUG("Found an ccSpanId = %d\n",sngSpan.ccSpanId); - /**********************************************************************/ } else { SS7_ERROR("Unknown parameter found =\"%s\"...ignoring it!\n", var); - /**********************************************************************/ } i++; @@ -255,10 +280,12 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa /* fill the pointer to span into isupCkt */ sngSpan.span = span; - /* setup the circuits structure */ - if(ftmod_ss7_fill_in_circuits(&sngSpan)) { - SS7_ERROR("Failed to fill in circuits structure!\n"); - goto ftmod_ss7_parse_xml_error; + if(SNG_SS7_OPR_MODE_ISUP == g_ftdm_operating_mode){ + /* setup the circuits structure */ + if(ftmod_ss7_fill_in_circuits(&sngSpan)) { + SS7_ERROR("Failed to fill in circuits structure!\n"); + goto ftmod_ss7_parse_xml_error; + } } return FTDM_SUCCESS; @@ -280,6 +307,11 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) ftdm_conf_node_t *isup_interfaces = NULL; ftdm_conf_node_t *cc_spans = NULL; ftdm_conf_node_t *tmp_node = NULL; + ftdm_conf_node_t *nif_ifaces = NULL; + ftdm_conf_node_t *m2ua_ifaces = NULL; + ftdm_conf_node_t *m2ua_peer_ifaces = NULL; + ftdm_conf_node_t *m2ua_clust_ifaces = NULL; + ftdm_conf_node_t *sctp_ifaces = NULL; /* confirm that we are looking at sng_isup */ if (strcasecmp(sng_isup->name, "sng_isup")) { @@ -385,12 +417,62 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_FAIL; } /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_nif_interfaces")) { + /**********************************************************************/ + if (nif_ifaces == NULL) { + nif_ifaces = tmp_node; + SS7_DEBUG("Found a \"sng_nif_interfaces\" section!\n"); + } else { + SS7_ERROR("Found a second \"sng_nif_interfaces\" section\n!"); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_m2ua_interfaces")) { + /**********************************************************************/ + if (m2ua_ifaces == NULL) { + m2ua_ifaces = tmp_node; + SS7_DEBUG("Found a \"sng_m2ua_interfaces\" section!\n"); + } else { + SS7_ERROR("Found a second \"sng_m2ua_interfaces\" section\n!"); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_m2ua_peer_interfaces")) { + /**********************************************************************/ + if (m2ua_peer_ifaces == NULL) { + m2ua_peer_ifaces = tmp_node; + SS7_DEBUG("Found a \"sng_m2ua_peer_interfaces\" section!\n"); + } else { + SS7_ERROR("Found a second \"sng_m2ua_peer_interfaces\" section\n!"); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_m2ua_cluster_interfaces")) { + /**********************************************************************/ + if (m2ua_clust_ifaces == NULL) { + m2ua_clust_ifaces = tmp_node; + SS7_DEBUG("Found a \"sng_m2ua_cluster_interfaces\" section!\n"); + } else { + SS7_ERROR("Found a second \"sng_m2ua_peer_interfaces\" section\n!"); + return FTDM_FAIL; + } + /**********************************************************************/ + } else if (!strcasecmp(tmp_node->name, "sng_sctp_interfaces")) { + /**********************************************************************/ + if (sctp_ifaces == NULL) { + sctp_ifaces = tmp_node; + SS7_DEBUG("Found a section!\n"); + } else { + SS7_ERROR("Found a second section!\n"); + return FTDM_FAIL; + } + /**********************************************************************/ } else { /**********************************************************************/ SS7_ERROR("\tFound an unknown section \"%s\"!\n", tmp_node->name); return FTDM_FAIL; /**********************************************************************/ - } + } /* go to the next sibling */ tmp_node = tmp_node->next; @@ -417,34 +499,92 @@ static int ftmod_ss7_parse_sng_isup(ftdm_conf_node_t *sng_isup) return FTDM_FAIL; } - if (ftmod_ss7_parse_mtp3_links(mtp3_links)) { - SS7_ERROR("Failed to parse \"mtp3_links\"!\n"); - return FTDM_FAIL; - } - if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) { - SS7_ERROR("Failed to parse \"mtp_linksets\"!\n"); - return FTDM_FAIL; - } + switch(g_ftdm_operating_mode) + { + case SNG_SS7_OPR_MODE_ISUP: + { + if (mtp3_links && ftmod_ss7_parse_mtp3_links(mtp3_links)) { + SS7_ERROR("Failed to parse \"mtp3_links\"!\n"); + return FTDM_FAIL; + } - if (ftmod_ss7_parse_mtp_routes(mtp_routes)) { - SS7_ERROR("Failed to parse \"mtp_routes\"!\n"); - return FTDM_FAIL; - } + if (ftmod_ss7_parse_mtp_linksets(mtp_linksets)) { + SS7_ERROR("Failed to parse \"mtp_linksets\"!\n"); + return FTDM_FAIL; + } - if (ftmod_ss7_parse_isup_interfaces(isup_interfaces)) { - SS7_ERROR("Failed to parse \"isup_interfaces\"!\n"); - return FTDM_FAIL; - } + if (ftmod_ss7_parse_mtp_routes(mtp_routes)) { + SS7_ERROR("Failed to parse \"mtp_routes\"!\n"); + return FTDM_FAIL; + } + + if (isup_interfaces && ftmod_ss7_parse_isup_interfaces(isup_interfaces)) { + SS7_ERROR("Failed to parse \"isup_interfaces\"!\n"); + return FTDM_FAIL; + } + + if (cc_spans && ftmod_ss7_parse_cc_spans(cc_spans)) { + SS7_ERROR("Failed to parse \"cc_spans\"!\n"); + return FTDM_FAIL; + } + break; + } + case SNG_SS7_OPR_MODE_M2UA_SG: + { + if (ftmod_ss7_parse_sctp_links(sctp_ifaces) != FTDM_SUCCESS) { + SS7_ERROR("Failed to parse !\n"); + return FTDM_FAIL; + } + + if (nif_ifaces && ftmod_ss7_parse_nif_interfaces(nif_ifaces)) { + SS7_ERROR("Failed to parse \"nif_ifaces\"!\n"); + return FTDM_FAIL; + } + + if (m2ua_ifaces && ftmod_ss7_parse_m2ua_interfaces(m2ua_ifaces)) { + SS7_ERROR("Failed to parse \"m2ua_ifaces\"!\n"); + return FTDM_FAIL; + } + if (m2ua_peer_ifaces && ftmod_ss7_parse_m2ua_peer_interfaces(m2ua_peer_ifaces)) { + SS7_ERROR("Failed to parse \"m2ua_peer_ifaces\"!\n"); + return FTDM_FAIL; + } + if (m2ua_clust_ifaces && ftmod_ss7_parse_m2ua_clust_interfaces(m2ua_clust_ifaces)) { + SS7_ERROR("Failed to parse \"m2ua_clust_ifaces\"!\n"); + return FTDM_FAIL; + } + break; + } + default: + SS7_ERROR("Invalid operating mode[%d]\n",g_ftdm_operating_mode); + break; - if (ftmod_ss7_parse_cc_spans(cc_spans)) { - SS7_ERROR("Failed to parse \"cc_spans\"!\n"); - return FTDM_FAIL; } return FTDM_SUCCESS; } +static void ftmod_ss7_set_glare_resolution (const char *method) +{ + sng_glare_resolution iMethod=SNGSS7_GLARE_PC; + if (!method || (strlen (method) <=0) ) { + SS7_ERROR( "Wrong glare resolution parameter, using default. \n" ); + } else { + if (!strcasecmp( method, "PointCode")) { + iMethod = SNGSS7_GLARE_PC; + } else if (!strcasecmp( method, "Down")) { + iMethod = SNGSS7_GLARE_DOWN; + } else if (!strcasecmp( method, "Control")) { + iMethod = SNGSS7_GLARE_CONTROL; + } else { + SS7_ERROR( "Wrong glare resolution parameter, using default. \n" ); + iMethod = SNGSS7_GLARE_PC; + } + } + g_ftdm_sngss7_data.cfg.glareResolution = iMethod; +} + /******************************************************************************/ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) { @@ -452,31 +592,41 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen) int num_parms = sng_gen->n_parameters; int i = 0; + /* Set the transparent_iam_max_size to default value */ + g_ftdm_sngss7_data.cfg.transparent_iam_max_size=800; + g_ftdm_sngss7_data.cfg.force_inr = 0; + /* extract all the information from the parameters */ for (i = 0; i < num_parms; i++) { - /**************************************************************************/ - if (!strcasecmp(parm->var, "procId")) { - /**********************************************************************/ g_ftdm_sngss7_data.cfg.procId = atoi(parm->val); SS7_DEBUG("Found a procId = %d\n", g_ftdm_sngss7_data.cfg.procId); - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "license")) { - /**********************************************************************/ - strcpy(g_ftdm_sngss7_data.cfg.license, parm->val); - strcpy(g_ftdm_sngss7_data.cfg.signature, parm->val); - strcat(g_ftdm_sngss7_data.cfg.signature, ".sig"); + } + else if (!strcasecmp(parm->var, "license")) { + ftdm_set_string(g_ftdm_sngss7_data.cfg.license, parm->val); + snprintf(g_ftdm_sngss7_data.cfg.signature, sizeof(g_ftdm_sngss7_data.cfg.signature), "%s.sig", parm->val); SS7_DEBUG("Found license file = %s\n", g_ftdm_sngss7_data.cfg.license); SS7_DEBUG("Found signature file = %s\n", g_ftdm_sngss7_data.cfg.signature); - /**********************************************************************/ - } else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { + } + else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { g_ftdm_sngss7_data.cfg.transparent_iam_max_size = atoi(parm->val); SS7_DEBUG("Found a transparent_iam max size = %d\n", g_ftdm_sngss7_data.cfg.transparent_iam_max_size); - } else { - /**********************************************************************/ + } + else if (!strcasecmp(parm->var, "glare-reso")) { + ftmod_ss7_set_glare_resolution (parm->val); + SS7_DEBUG("Found glare resolution configuration = %d %s\n", g_ftdm_sngss7_data.cfg.glareResolution, parm->val ); + } + else if (!strcasecmp(parm->var, "force-inr")) { + if (ftdm_true(parm->val)) { + g_ftdm_sngss7_data.cfg.force_inr = 1; + } else { + g_ftdm_sngss7_data.cfg.force_inr = 0; + } + SS7_DEBUG("Found INR force configuration = %s\n", parm->val ); + } + else { SS7_ERROR("Found an invalid parameter \"%s\"!\n", parm->val); return FTDM_FAIL; - /**********************************************************************/ } /* move to the next parmeter */ @@ -1845,12 +1995,14 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) int flag_clg_nadi = 0; int flag_cld_nadi = 0; int flag_rdnis_nadi = 0; + int flag_loc_nadi = 0; int i; int ret; /* initalize the ccSpan structure */ memset(&sng_ccSpan, 0x0, sizeof(sng_ccSpan)); + /* confirm that we are looking at an mtp_link */ if (strcasecmp(cc_span->name, "cc_span")) { SS7_ERROR("We're looking at \"%s\"...but we're supposed to be looking at \"cc_span\"!\n",cc_span->name); @@ -1859,6 +2011,14 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) SS7_DEBUG("Parsing \"cc_span\"...\n"); } + /* Backward compatible. + * If cpg_on_progress_media is not in the config file + * default the cpg on progress_media to TRUE */ + sng_ccSpan.cpg_on_progress_media=FTDM_TRUE; + /* If transparent_iam_max_size is not set in cc spans + * use the global value */ + sng_ccSpan.transparent_iam_max_size=g_ftdm_sngss7_data.cfg.transparent_iam_max_size; + for (i = 0; i < num_parms; i++) { /**************************************************************************/ @@ -1904,6 +2064,15 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) sng_ccSpan.transparent_iam = ftdm_true(parm->val); SS7_DEBUG("Found transparent_iam %d\n", sng_ccSpan.transparent_iam); #endif + } else if (!strcasecmp(parm->var, "transparent_iam_max_size")) { + sng_ccSpan.transparent_iam_max_size = atoi(parm->val); + SS7_DEBUG("Found transparent_iam_max_size %d\n", sng_ccSpan.transparent_iam_max_size); + } else if (!strcasecmp(parm->var, "cpg_on_progress_media")) { + sng_ccSpan.cpg_on_progress_media = ftdm_true(parm->val); + SS7_DEBUG("Found cpg_on_progress_media %d\n", sng_ccSpan.cpg_on_progress_media); + } else if (!strcasecmp(parm->var, "cpg_on_progress")) { + sng_ccSpan.cpg_on_progress = ftdm_true(parm->val); + SS7_DEBUG("Found cpg_on_progress %d\n", sng_ccSpan.cpg_on_progress); } else if (!strcasecmp(parm->var, "cicbase")) { /**********************************************************************/ sng_ccSpan.cicbase = atoi(parm->val); @@ -1946,6 +2115,12 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) SS7_DEBUG("Invalid parm->value for obci_bita option\n"); } /**********************************************************************/ + } else if (!strcasecmp(parm->var, "loc_nadi")) { + /* add location reference number */ + flag_loc_nadi = 1; + sng_ccSpan.loc_nadi = atoi(parm->val); + SS7_DEBUG("Found default LOC_NADI parm->value = %d\n", sng_ccSpan.loc_nadi); + /**********************************************************************/ } else if (!strcasecmp(parm->var, "lpa_on_cot")) { /**********************************************************************/ if (*parm->val == '1') { @@ -2002,6 +2177,11 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) sng_ccSpan.t35 = atoi(parm->val); SS7_DEBUG("Found isup t35 = %d\n",sng_ccSpan.t35); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t39")) { + /**********************************************************************/ + sng_ccSpan.t39 = atoi(parm->val); + SS7_DEBUG("Found isup t39 = %d\n",sng_ccSpan.t39); + /**********************************************************************/ } else if (!strcasecmp(parm->var, "isup.tval")) { /**********************************************************************/ sng_ccSpan.tval = atoi(parm->val); @@ -2035,6 +2215,11 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span) sng_ccSpan.rdnis_nadi = 0x03; } + if (!flag_loc_nadi) { + /* default the nadi value to national */ + sng_ccSpan.loc_nadi = 0x03; + } + /* pull up the SSF and Switchtype from the isup interface */ sng_ccSpan.ssf = g_ftdm_sngss7_data.cfg.isupIntf[sng_ccSpan.isupInf].ssf; sng_ccSpan.switchType = g_ftdm_sngss7_data.cfg.isupIntf[sng_ccSpan.isupInf].switchType; @@ -2723,7 +2908,7 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t1 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t1 = sng_isap->t1; } else { - g_ftdm_sngss7_data.cfg.isap[i].t1 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t1 = 150; } if (sng_isap->t2 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t2 = sng_isap->t2; @@ -2738,17 +2923,17 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->t6 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t6 = sng_isap->t6; } else { - g_ftdm_sngss7_data.cfg.isap[i].t6 = 200; + g_ftdm_sngss7_data.cfg.isap[i].t6 = 600; } if (sng_isap->t7 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t7 = sng_isap->t7; } else { - g_ftdm_sngss7_data.cfg.isap[i].t7 = 250; + g_ftdm_sngss7_data.cfg.isap[i].t7 = 200; } if (sng_isap->t8 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t8 = sng_isap->t8; } else { - g_ftdm_sngss7_data.cfg.isap[i].t8 = 120; + g_ftdm_sngss7_data.cfg.isap[i].t8 = 100; } if (sng_isap->t9 != 0) { g_ftdm_sngss7_data.cfg.isap[i].t9 = sng_isap->t9; @@ -2863,7 +3048,7 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) (g_ftdm_sngss7_data.cfg.isupCkt[x].chan == count)) { /* we are processing a circuit that already exists */ - SS7_DEBUG("Found an existing circuit %d, ccSpanId=%d, chan%d\n", + SS7_DEVEL_DEBUG("Found an existing circuit %d, ccSpanId=%d, chan%d\n", x, ccSpan->id, count); @@ -2872,7 +3057,7 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) flag = 1; /* not supporting reconfig at this time */ - SS7_DEBUG("Not supporting ckt reconfig at this time!\n"); + SS7_DEVEL_DEBUG("Not supporting ckt reconfig at this time!\n"); goto move_along; } else { /* this is not the droid you are looking for */ @@ -2885,6 +3070,9 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) /* prepare the global info sturcture */ ss7_info = ftdm_calloc(1, sizeof(sngss7_chan_data_t)); ss7_info->ftdmchan = NULL; + if (ftdm_queue_create(&ss7_info->event_queue, SNGSS7_CHAN_EVENT_QUEUE_SIZE) != FTDM_SUCCESS) { + SS7_CRITICAL("Failed to create ss7 cic event queue\n"); + } ss7_info->circuit = &g_ftdm_sngss7_data.cfg.isupCkt[x]; g_ftdm_sngss7_data.cfg.isupCkt[x].obj = ss7_info; @@ -2919,12 +3107,16 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) g_ftdm_sngss7_data.cfg.isupCkt[x].ssf = ccSpan->ssf; g_ftdm_sngss7_data.cfg.isupCkt[x].cld_nadi = ccSpan->cld_nadi; g_ftdm_sngss7_data.cfg.isupCkt[x].clg_nadi = ccSpan->clg_nadi; - g_ftdm_sngss7_data.cfg.isupCkt[x].rdnis_nadi = ccSpan->rdnis_nadi; + g_ftdm_sngss7_data.cfg.isupCkt[x].rdnis_nadi = ccSpan->rdnis_nadi; + g_ftdm_sngss7_data.cfg.isupCkt[x].loc_nadi = ccSpan->loc_nadi; g_ftdm_sngss7_data.cfg.isupCkt[x].options = ccSpan->options; - g_ftdm_sngss7_data.cfg.isupCkt[x].switchType = ccSpan->switchType; - g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits = ccSpan->min_digits; - g_ftdm_sngss7_data.cfg.isupCkt[x].itx_auto_reply = ccSpan->itx_auto_reply; - g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam = ccSpan->transparent_iam; + g_ftdm_sngss7_data.cfg.isupCkt[x].switchType = ccSpan->switchType; + g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits = ccSpan->min_digits; + g_ftdm_sngss7_data.cfg.isupCkt[x].itx_auto_reply = ccSpan->itx_auto_reply; + g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam = ccSpan->transparent_iam; + g_ftdm_sngss7_data.cfg.isupCkt[x].transparent_iam_max_size = ccSpan->transparent_iam_max_size; + g_ftdm_sngss7_data.cfg.isupCkt[x].cpg_on_progress_media = ccSpan->cpg_on_progress_media; + g_ftdm_sngss7_data.cfg.isupCkt[x].cpg_on_progress = ccSpan->cpg_on_progress; if (ccSpan->t3 == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = 1200; @@ -2972,6 +3164,12 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan) } else { g_ftdm_sngss7_data.cfg.isupCkt[x].t35 = ccSpan->t35; } + if (ccSpan->t39 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t39 = 120; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t39 = ccSpan->t39; + } + if (ccSpan->tval == 0) { g_ftdm_sngss7_data.cfg.isupCkt[x].tval = 10; } else { @@ -3076,6 +3274,13 @@ static int ftmod_ss7_fill_in_circuits(sng_span_t *sngSpan) ss7_info->t10.callback = handle_isup_t10; ss7_info->t10.sngss7_info = ss7_info; + /* prepare the timer structures */ + ss7_info->t39.sched = ((sngss7_span_data_t *)(ftdmspan->signal_data))->sched; + ss7_info->t39.counter = 1; + ss7_info->t39.beat = (isupCkt->t39) * 100; /* beat is in ms, t39 is in 100ms */ + ss7_info->t39.callback = handle_isup_t39; + ss7_info->t39.sngss7_info = ss7_info; + /**************************************************************************/ } /* for (i == 1; i < ftdmspan->chan_count; i++) */ diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index c26cbec02c..68cf7f6743 100755 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -764,6 +764,28 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Disabled DTMF events\n"); #else return FTDM_NOTIMPL; +#endif + } + break; + case FTDM_COMMAND_ENABLE_DTMF_REMOVAL: + { +#ifdef WP_API_FEATURE_LIBSNG_HWEC + int return_code = 0; + err = sangoma_hwec_set_hwdtmf_removal(ftdmchan->sockfd, ftdmchan->physical_chan_id, &return_code, 1, 0); + if (return_code) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to Disable HW-DTMF removal\n"); + } +#endif + } + break; + case FTDM_COMMAND_DISABLE_DTMF_REMOVAL: + { +#ifdef WP_API_FEATURE_LIBSNG_HWEC + int return_code = 0; + err = sangoma_hwec_set_hwdtmf_removal(ftdmchan->sockfd, ftdmchan->physical_chan_id, &return_code, 0, 0); + if (return_code) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to Disable HW-DTMF removal\n"); + } #endif } break; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 1476ee0158..f430ae263e 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -40,7 +40,6 @@ #ifndef FREETDM_H #define FREETDM_H - #include "ftdm_declare.h" #include "ftdm_call_utils.h" @@ -368,6 +367,7 @@ typedef struct ftdm_caller_data { ftdm_number_t ani; /*!< ANI (Automatic Number Identification) */ ftdm_number_t dnis; /*!< DNIS (Dialed Number Identification Service) */ ftdm_number_t rdnis; /*!< RDNIS (Redirected Dialed Number Identification Service) */ + ftdm_number_t loc; /*!< LOC (Location Reference Code) */ char aniII[FTDM_DIGITS_LIMIT]; /*! ANI II */ uint8_t screen; /*!< Screening */ uint8_t pres; /*!< Presentation*/ @@ -754,6 +754,10 @@ typedef enum { /*!< Enable/disable IO stats in the channel */ FTDM_COMMAND_SWITCH_IOSTATS = 60, + /*!< Enable/disable DTMF removal */ + FTDM_COMMAND_ENABLE_DTMF_REMOVAL = 61, + FTDM_COMMAND_DISABLE_DTMF_REMOVAL = 62, + FTDM_COMMAND_COUNT, } ftdm_command_t; @@ -1395,7 +1399,7 @@ FT_DECLARE(uint32_t) ftdm_group_get_id(const ftdm_group_t *group); * Only use ftdm_channel_close if there is no call (incoming or outgoing) in the channel * * \param span_id The span id the channel belongs to - * \param chan_id Channel id of the channel you want to open + * \param chan_id Logical channel id of the channel you want to open * \param ftdmchan Pointer to store the channel once is open * * \retval FTDM_SUCCESS success (the channel was found and is available) @@ -1403,6 +1407,23 @@ FT_DECLARE(uint32_t) ftdm_group_get_id(const ftdm_group_t *group); */ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan); +/*! + * \brief Open a channel specifying the span id and physical chan id (required before placing a call on the channel) + * + * \warning Try using ftdm_call_place instead if you plan to place a call after opening the channel + * + * \note You must call ftdm_channel_close() or ftdm_channel_call_hangup() to release the channel afterwards + * Only use ftdm_channel_close if there is no call (incoming or outgoing) in the channel + * + * \param span_id The span id the channel belongs to + * \param chan_id Physical channel id of the channel you want to open + * \param ftdmchan Pointer to store the channel once is open + * + * \retval FTDM_SUCCESS success (the channel was found and is available) + * \retval FTDM_FAIL failure (channel was not found or not available) + */ +FT_DECLARE(ftdm_status_t) ftdm_channel_open_ph(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan); + /*! * \brief Hunts and opens a channel specifying the span id only * @@ -1640,6 +1661,17 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span(ftdm_span_t *span, const char *typ */ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const char *type, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *parameters); +/*! + * \brief Register callback to listen for incoming events + * \note This function should only be used when there is no signalling module + * \param span The span to register to + * \param sig_cb The callback that the signaling stack will use to notify about events + * + * \retval FTDM_SUCCESS success + * \retval FTDM_FAIL failure + */ +FT_DECLARE(ftdm_status_t) ftdm_span_register_signal_cb(ftdm_span_t *span, fio_signal_cb_t sig_cb); + /*! * \brief Start the span signaling (must call ftdm_configure_span_signaling first) * @@ -1655,7 +1687,6 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const */ FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span); - /*! * \brief Stop the span signaling (must call ftdm_span_start first) * \note certain signalings (boost signaling) does not support granular span start/stop @@ -1796,15 +1827,25 @@ FT_DECLARE(ftdm_trunk_mode_t) ftdm_span_get_trunk_mode(const ftdm_span_t *span); FT_DECLARE(const char *) ftdm_span_get_trunk_mode_str(const ftdm_span_t *span); /*! - * \brief Return the channel identified by the provided id + * \brief Return the channel identified by the provided logical id * * \param span The span where the channel belongs - * \param chanid The channel id within the span + * \param chanid The logical channel id within the span * * \return The channel pointer if found, NULL otherwise */ FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel(const ftdm_span_t *span, uint32_t chanid); +/*! + * \brief Return the channel identified by the provided physical id + * + * \param span The span where the channel belongs + * \param chanid The physical channel id within the span + * + * \return The channel pointer if found, NULL otherwise + */ +FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel_ph(const ftdm_span_t *span, uint32_t chanid); + /*! \brief Return the channel count number for the given span */ FT_DECLARE(uint32_t) ftdm_span_get_chan_count(const ftdm_span_t *span); diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 6725f25655..e378001183 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -126,6 +126,9 @@ extern "C" { #endif +#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 +#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 + #define GOTO_STATUS(label,st) status = st; goto label ; #define ftdm_copy_string(x,y,z) strncpy(x, y, z - 1) @@ -473,6 +476,7 @@ struct ftdm_channel { int32_t txdrops; int32_t rxdrops; ftdm_usrmsg_t *usrmsg; + ftdm_time_t last_state_change_time; }; struct ftdm_span { @@ -690,6 +694,9 @@ FT_DECLARE(ftdm_status_t) ftdm_sigmsg_remove_var(ftdm_sigmsg_t *sigmsg, const ch */ FT_DECLARE(ftdm_status_t) ftdm_sigmsg_set_raw_data(ftdm_sigmsg_t *sigmsg, void *data, ftdm_size_t datalen); +/*! \brief Retrieve a span and channel data structure from a string in the format 'span_id:chan_id'*/ +FT_DECLARE(ftdm_status_t) ftdm_get_channel_from_string(const char *string_id, ftdm_span_t **out_span, ftdm_channel_t **out_channel); + /*! \brief Assert condition */ diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index d87bcd423f..c92164dd8c 100755 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -162,6 +162,7 @@ typedef enum { FTDM_SIGTYPE_ANALOG, FTDM_SIGTYPE_SANGOMABOOST, FTDM_SIGTYPE_M3UA, + FTDM_SIGTYPE_M2UA, FTDM_SIGTYPE_R2, FTDM_SIGTYPE_SS7, FTDM_SIGTYPE_GSM @@ -198,6 +199,8 @@ typedef enum { FTDM_SPAN_NON_STOPPABLE = (1 << 13), /* If this flag is set, then this span supports TRANSFER state */ FTDM_SPAN_USE_TRANSFER = (1 << 14), + /* This is the last flag, no more flags bigger than this */ + FTDM_SPAN_MAX_FLAG = (1 << 15), } ftdm_span_flag_t; /*! \brief Channel supported features */ @@ -266,6 +269,12 @@ typedef enum { #define FTDM_CHANNEL_BLOCKING (1ULL << 35) /*!< Media is digital */ #define FTDM_CHANNEL_DIGITAL_MEDIA (1ULL << 36) +/*!< Native signaling bridge is enabled */ +#define FTDM_CHANNEL_NATIVE_SIGBRIDGE (1ULL << 37) + +/*!< This no more flags after this flag */ +#define FTDM_CHANNEL_MAX_FLAG (1ULL << 38) +/*!