/* 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) {
/* 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 */
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", " ");
}
/**************************************************************************/
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);
+
+ sngss7_set_ckt_flag(sngss7_info, FLAG_INR_RX);
+
break;
/**************************************************************************/
case (SUBSADDR):
}
/* 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) {
/**************************************************************************/
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;
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);
uint16_t t16;
uint16_t t17;
uint32_t t35;
+ uint32_t t39;
uint16_t tval;
} sng_isup_ckt_t;
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 {
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;
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;
"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)
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);
+
/* in ftmod_sangoma_ss7_in.c */
/* in ftmod_sangoma_ss7_timers.c */
void handle_isup_t35(void *userdata);
void handle_isup_t10(void *userdata);
+void handle_isup_t39(void *userdata);
/******************************************************************************/
return;
}
+void ft_to_sngss7_inf(ftdm_channel_t *ftdmchan)
+{
+ SiCnStEvnt evnt;
+ sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
+ /*
+ const char *CallerId = NULL;
+ const char *CallerCat = NULL;
+ const char *sipvar;
+ */
+
+ memset (&evnt, 0x0, sizeof (evnt));
+
+ evnt.infoInd.eh.pres = PRSNT_NODEF;
+
+ evnt.infoInd.cgPtyAddrRespInd.pres = PRSNT_NODEF;
+ evnt.infoInd.cgPtyAddrRespInd.val=CGPRTYADDRESP_INCL;
+ copy_cgPtyNum_to_sngss7 (ftdmchan, &evnt.cgPtyNum);
+
+
+ evnt.infoInd.cgPtyCatRespInd.pres = PRSNT_NODEF;
+ evnt.infoInd.cgPtyCatRespInd.val = CGPRTYCATRESP_INCL;
+ copy_cgPtyCat_to_sngss7 (ftdmchan, &evnt.cgPtyCat);
+
+ 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;
+
+ 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_NOTREQ;
+
+ evnt.infoReqInd.cgPtyCatReqInd.pres = PRSNT_NODEF;
+ evnt.infoReqInd.cgPtyCatReqInd.val = CGPRTYCATREQ_REQ;
+
+ evnt.infoReqInd.chrgInfoReqInd.pres = PRSNT_NODEF;
+ evnt.infoReqInd.chrgInfoReqInd.val = CHRGINFO_NOTREQ;
+
+ evnt.infoReqInd.malCaIdReqInd.pres = PRSNT_NODEF;
+ evnt.infoReqInd.malCaIdReqInd.val = MLBG_INFONOTREQ;
+
+ 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__);
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);
}
/******************************************************************************/
/* PROTOTYPES *****************************************************************/
-void handle_isup_t35(void *userdata);
+
/******************************************************************************/
/* FUNCTIONS ******************************************************************/
/* 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);
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:
uint32_t t16;
uint32_t t17;
uint32_t t35;
+ uint32_t t39;
uint32_t tval;
} sng_ccSpan_t;
/* 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++) {
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 (!strcasecmp(parm->val, "true")) {
+ 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;
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);
} 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 {
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++) */