mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-13 07:45:26 +00:00
Merge branch 'releases.3.4' into releases.3.5
Conflicts: libs/freetdm/mod_freetdm/mod_freetdm.c libs/freetdm/src/ftdm_state.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c
This commit is contained in:
commit
5226489c39
43
libs/freetdm/docs/ss7-native-bridge.txt
Normal file
43
libs/freetdm/docs/ss7-native-bridge.txt
Normal file
@ -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
|
||||
|
@ -1409,7 +1409,7 @@ 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;
|
||||
|
||||
@ -1474,7 +1474,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||
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) {
|
||||
@ -1726,7 +1726,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||
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"))
|
||||
@ -2043,6 +2042,7 @@ 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-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);
|
||||
|
@ -2203,9 +2203,12 @@ static ftdm_status_t _ftdm_channel_call_hangup_nl(const char *file, const char *
|
||||
{
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
|
||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,6 @@ 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
|
||||
@ -59,6 +58,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c
|
||||
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",
|
||||
|
@ -35,7 +35,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#if 0
|
||||
#define SMG_RELAY_DBG
|
||||
#endif
|
||||
|
||||
@ -1332,7 +1332,7 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span,
|
||||
}
|
||||
|
||||
#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) */
|
||||
@ -1374,36 +1374,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);
|
||||
|
||||
@ -1440,33 +1430,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);
|
||||
|
||||
}
|
||||
@ -1812,6 +1791,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);
|
||||
|
||||
@ -1945,6 +1926,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) {
|
||||
|
@ -131,6 +131,16 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
||||
|
||||
/* 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) {
|
||||
@ -175,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 */
|
||||
@ -186,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", " ");
|
||||
}
|
||||
|
||||
@ -436,10 +457,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):
|
||||
@ -1143,11 +1180,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 */
|
||||
@ -2472,6 +2510,8 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
||||
|
||||
/* 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);
|
||||
@ -2589,8 +2629,7 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
||||
while( x < loop_range ) {
|
||||
if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != SNG_CKT_VOICE) {
|
||||
loop_range++;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (extract_chan_data(x, &sngss7_info, &ftdmchan)) {
|
||||
SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x);
|
||||
}
|
||||
@ -2627,7 +2666,8 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
||||
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*/
|
||||
|
@ -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__);
|
||||
|
@ -340,10 +340,9 @@ static void handle_hw_alarm(ftdm_event_t *e)
|
||||
/* MONITIOR THREADS ***********************************************************/
|
||||
static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
|
||||
{
|
||||
ftdm_interrupt_t *ftdm_sangoma_ss7_int[3];
|
||||
ftdm_interrupt_t *ftdm_sangoma_ss7_int[2];
|
||||
ftdm_span_t *ftdmspan = (ftdm_span_t *) obj;
|
||||
ftdm_channel_t *ftdmchan = NULL;
|
||||
ftdm_channel_t *peerchan = NULL;
|
||||
ftdm_event_t *event = NULL;
|
||||
sngss7_event_data_t *sngss7_event = NULL;
|
||||
sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->signal_data;
|
||||
@ -368,12 +367,6 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
|
||||
goto ftdm_sangoma_ss7_run_exit;
|
||||
}
|
||||
|
||||
/* get an interrupt queue for this span for peer channel events */
|
||||
if (ftdm_queue_get_interrupt (sngss7_span->peer_chans, &ftdm_sangoma_ss7_int[2]) != FTDM_SUCCESS) {
|
||||
SS7_CRITICAL ("Failed to get a ftdm_interrupt for span = %d for peer channel events queue!\n", ftdmspan->span_id);
|
||||
goto ftdm_sangoma_ss7_run_exit;
|
||||
}
|
||||
|
||||
while (ftdm_running () && !(ftdm_test_flag (ftdmspan, FTDM_SPAN_STOP_THREAD))) {
|
||||
int x = 0;
|
||||
if (b_alarm_test) {
|
||||
@ -410,42 +403,26 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* clean out all peer pending channel events */
|
||||
while ((peerchan = ftdm_queue_dequeue (sngss7_span->peer_chans))) {
|
||||
/* note that the channels being dequeued here may not belong to this span
|
||||
they may belong to just about any other span that one of our channels
|
||||
happens to be bridged to */
|
||||
sngss7_chan_data_t *peer_info = peerchan->call_data;
|
||||
sngss7_chan_data_t *chan_info = peer_info->peer_data;
|
||||
ftdmchan = chan_info->ftdmchan;
|
||||
|
||||
/*
|
||||
if there is any state changes at all, those will be done in the opposite channel
|
||||
to peerchan (where the original event was received), therefore we must lock ftdmchan,
|
||||
but do not need to lock peerchan as we only read its event queue, which is already
|
||||
locked when dequeueing */
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
|
||||
/* clean out all pending stack events in the peer channel */
|
||||
while ((sngss7_event = ftdm_queue_dequeue(peer_info->event_queue))) {
|
||||
ftdm_sangoma_ss7_process_peer_stack_event(ftdmchan, sngss7_event);
|
||||
ftdm_safe_free(sngss7_event);
|
||||
}
|
||||
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
}
|
||||
|
||||
/* clean out all pending stack events */
|
||||
while ((sngss7_event = ftdm_queue_dequeue(sngss7_span->event_queue))) {
|
||||
ftdm_sangoma_ss7_process_stack_event(sngss7_event);
|
||||
@ -561,16 +538,16 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
|
||||
if (sngss7_event->event_id == SNGSS7_CON_IND_EVENT) {
|
||||
/* this is the first event in a call, flush the event queue */
|
||||
sngss7_flush_queue(sngss7_info->event_queue);
|
||||
/* clear the peer if any */
|
||||
sngss7_info->peer_data = NULL;
|
||||
clone_event++;
|
||||
}
|
||||
|
||||
/* if the call has already started and the event is not a release confirmation, clone the event */
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED) &&
|
||||
sngss7_event->event_id != SNGSS7_REL_CFM_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++;
|
||||
}
|
||||
|
||||
@ -597,11 +574,38 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
||||
event_clone = ftdm_calloc(1, sizeof(*sngss7_event));
|
||||
if (event_clone) {
|
||||
memcpy(event_clone, sngss7_event, sizeof(*sngss7_event));
|
||||
ftdm_queue_enqueue(sngss7_info->event_queue, event_clone);
|
||||
/* if we have already a peer channel then enqueue the event in their queue */
|
||||
if (sngss7_info->peer_data) {
|
||||
sngss7_span_data_t *sngss7_peer_span = (sngss7_span_data_t *)sngss7_info->peer_data->ftdmchan->span->signal_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_peer_span->peer_chans, sngss7_info->ftdmchan);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -614,25 +618,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
|
||||
break;
|
||||
case SNGSS7_REL_CFM_EVENT:
|
||||
{
|
||||
if (sngss7_info->peer_data) {
|
||||
ftdm_channel_t *peer_chan = sngss7_info->peer_data->ftdmchan;
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
if (peer_chan) {
|
||||
/* we need to unlock our chan or we risk deadlock */
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
|
||||
ftdm_channel_lock(peer_chan);
|
||||
if (peer_chan->state != FTDM_CHANNEL_STATE_DOWN) {
|
||||
ftdm_set_state(peer_chan, FTDM_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
ftdm_channel_unlock(peer_chan);
|
||||
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
}
|
||||
}
|
||||
}
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1011,7 +997,11 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t
|
||||
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;
|
||||
@ -1026,9 +1016,22 @@ static ftdm_status_t ftdm_sangoma_ss7_native_bridge_state_change(ftdm_channel_t
|
||||
|
||||
case FTDM_CHANNEL_STATE_TERMINATING:
|
||||
{
|
||||
ft_to_sngss7_rlc(ftdmchan);
|
||||
/* 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 */
|
||||
sngss7_send_signal(sngss7_info, FTDM_SIGEVENT_STOP);
|
||||
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;
|
||||
|
||||
@ -1053,11 +1056,11 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan)
|
||||
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 */
|
||||
/* 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);
|
||||
}
|
||||
sngss7_info->peer_data = NULL;
|
||||
}
|
||||
|
||||
/*check what state we are supposed to be in */
|
||||
@ -1080,23 +1083,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) {
|
||||
@ -1152,6 +1223,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;
|
||||
@ -1162,6 +1242,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);
|
||||
@ -1512,19 +1597,6 @@ ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan)
|
||||
|
||||
if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OPEN)) {
|
||||
ftdm_channel_t *close_chan = ftdmchan;
|
||||
|
||||
/* detach native bridging if needed (only the outbound leg is responsible for that)
|
||||
Inbound leg was responsible of flushing its queue of events, but peer attach/detach
|
||||
is left as an outbound leg responsibility
|
||||
*/
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
sngss7_chan_data_t *peer_info = sngss7_info->peer_data;
|
||||
sngss7_info->peer_data = NULL;
|
||||
if (peer_info) {
|
||||
peer_info->peer_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* close the channel */
|
||||
SS7_DEBUG_CHAN(ftdmchan,"FTDM Channel Close %s\n", "");
|
||||
sngss7_flush_queue(sngss7_info->event_queue);
|
||||
@ -2404,12 +2476,6 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config)
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
/* create an peer channel queue for this span */
|
||||
if ((ftdm_queue_create(&(ss7_span_info)->peer_chans, SNGSS7_PEER_CHANS_QUEUE_SIZE)) != FTDM_SUCCESS) {
|
||||
SS7_CRITICAL("Unable to create peer chans queue!\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
/*setup the span structure with the info so far */
|
||||
g_ftdm_sngss7_data.sig_cb = sig_cb;
|
||||
span->start = ftdm_sangoma_ss7_start;
|
||||
|
@ -395,6 +395,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;
|
||||
|
||||
@ -466,6 +467,7 @@ typedef struct sng_ss7_cfg {
|
||||
sng_nsap_t nsap[MAX_NSAPS+1];
|
||||
sng_isap_t isap[MAX_ISAPS+1];
|
||||
sng_glare_resolution glareResolution;
|
||||
uint32_t force_inr;
|
||||
} sng_ss7_cfg_t;
|
||||
|
||||
typedef struct ftdm_sngss7_data {
|
||||
@ -517,12 +519,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;
|
||||
struct sngss7_chan_data *peer_data;
|
||||
uint8_t peer_event_transfer_cnt;
|
||||
} sngss7_chan_data_t;
|
||||
|
||||
#define SNGSS7_RX_GRS_PENDING (1 << 0)
|
||||
@ -536,7 +540,6 @@ typedef struct sngss7_span_data {
|
||||
sngss7_group_data_t rx_cgu;
|
||||
sngss7_group_data_t tx_cgu;
|
||||
ftdm_queue_t *event_queue;
|
||||
ftdm_queue_t *peer_chans;
|
||||
} sngss7_span_data_t;
|
||||
|
||||
typedef struct sngss7_event_data
|
||||
@ -584,6 +587,15 @@ typedef enum {
|
||||
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;
|
||||
@ -606,6 +618,14 @@ typedef enum {
|
||||
"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)
|
||||
@ -820,6 +840,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 */
|
||||
@ -949,6 +972,7 @@ 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);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@ -970,7 +994,7 @@ 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 SS7_CODE_DEVEL
|
||||
#define SS7_DEVEL_DEBUG(a,...) ftdm_log(FTDM_LOG_DEBUG,a,##__VA_ARGS__ );
|
||||
|
@ -48,6 +48,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
|
||||
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__);
|
||||
|
||||
@ -75,28 +76,25 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
|
||||
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;
|
||||
|
||||
/* flush our own queue */
|
||||
sngss7_flush_queue(sngss7_info->event_queue);
|
||||
|
||||
/* 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
|
||||
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) && sngss7_info->peer_data) {
|
||||
sngss7_span_data_t *span_data = ftdmchan->span->signal_data;
|
||||
sngss7_event_data_t *event_clone = ftdm_queue_dequeue(sngss7_info->peer_data->event_queue);
|
||||
/* Retrieve IAM from our peer */
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NATIVE_SIGBRIDGE)) {
|
||||
if (!event_clone) {
|
||||
SS7_ERROR_CHAN(ftdmchan, "No event clone in peer queue!%s\n", "");
|
||||
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);
|
||||
@ -141,9 +139,6 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
|
||||
copy_ocn_to_sngss7(ftdmchan, &iam.origCdNum);
|
||||
}
|
||||
}
|
||||
/* since this is the first time we dequeue an event from the peer, make sure our main thread process any other events,
|
||||
this will trigger the interrupt in our span peer_chans queue which will wake up our main thread if it is sleeping */
|
||||
ftdm_queue_enqueue(span_data->peer_chans, sngss7_info->peer_data->ftdmchan);
|
||||
} 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);
|
||||
@ -234,12 +229,107 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
|
||||
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__);
|
||||
|
@ -186,7 +186,7 @@ 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);
|
||||
}
|
||||
@ -257,7 +257,7 @@ ftdm_status_t copy_locPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *loc
|
||||
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");
|
||||
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);
|
||||
|
@ -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:
|
||||
|
@ -146,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;
|
||||
|
||||
@ -487,6 +488,7 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen)
|
||||
|
||||
/* 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++) {
|
||||
@ -508,6 +510,14 @@ static int ftmod_ss7_parse_sng_gen(ftdm_conf_node_t *sng_gen)
|
||||
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;
|
||||
@ -2004,7 +2014,6 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span)
|
||||
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")) {
|
||||
/**********************************************************************/
|
||||
@ -2062,6 +2071,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);
|
||||
@ -3044,6 +3058,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 {
|
||||
@ -3148,6 +3168,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++) */
|
||||
|
Loading…
x
Reference in New Issue
Block a user