]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: INR/INF implementation
authorJames Zhang <jzhang@sangoma.com>
Wed, 11 Apr 2012 15:20:32 +0000 (11:20 -0400)
committerJames Zhang <jzhang@sangoma.com>
Wed, 11 Apr 2012 15:20:32 +0000 (11:20 -0400)
         - When NSG receives INR from network, send back INF with calling
         party category information IE and calling number information IE.
         - Introduced a new global setting of "force-inr" for testing
         purpose. Stinga generated INR/INF packets are not acceptable by
         trillium stack since it misses call related information in the
         packets. If configure force-inr to true in freetdm.conf.xml, when
         NSG receives an incoming IAM, it'll send out INR packet regardless
         of incoming IAM's IEs, and keep waiting for INF response from the
         calling side.
         - T.39 timer is introduced in order to handle INR timeout. The
         default value of T.39 is 12 seconds and is configurable according
         to spec.
         - Only supports calling number IE and calling party category IE in
         current fix. The customer only needs the calling number IE right now.
         In ISUP spec, there are 6 optional IEs. NSG only supports calling
         party number and calling category information IE since the other
         IEs are not configurable in freetdm.conf.xml or included in IAM
         message.
         - In collect state, INR/INF implementation needs to work with existed
         SAM messages. If NSG sent out INR and wait for SAM, collect state
         check both INF received and enough dialed numbers received. If one
         of these conditions are not met, it'll stay in collect state and wait
         until either conditions met or timeout. After received INF and enough
         dailed number, state moves to dailing and proceed as regular calls.

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_support.c
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c
libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c

index d9816dfa0e4e502e9bde62bed449211d5c8d0d67..ac309ddc3e44398db5942e441fd9fd8bd27286d8 100644 (file)
@@ -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", " ");
                        }
 
@@ -437,10 +458,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);
+
+               sngss7_set_ckt_flag(sngss7_info, FLAG_INR_RX);
+               
                break;
        /**************************************************************************/
        case (SUBSADDR):
index 76266f0d53cdef2d9470d24a61422422a0a1a6ce..d37a6111abf914af5c495860c11c866aae37bb2a 100644 (file)
@@ -1080,23 +1080,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 +1220,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 +1239,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);
index fcf7b8ef28bfe487d18c91c77e8be91144a235cc..66732bf10eb141952062d145451dbf6da75244b7 100644 (file)
@@ -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,6 +519,7 @@ 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;
@@ -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);
+
 
 
 /* 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);
 
 /******************************************************************************/
 
index a228cb1ea1cbc39d0e70a9402b6caebea25732f0..b5431d8fe84fa5f456ac887e08b446d3b4a9d263 100644 (file)
@@ -237,6 +237,85 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
        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__);
index 4bfa5d2065844fb8b8995d63acdc34bcba020919..96359ba595dd0108bd4453a2dd85c66a570ef3b2 100644 (file)
@@ -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);
 }
index 6138ea34b0a5f345a86d7b6a0e2427a771cd08ab..8cac996213bf6da9411cddf9342c76277cd39285 100644 (file)
@@ -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:
index 230476d8e163b91b9917d1bcda73fbf8bd0d7765..ee726911af7e996c841f44b428c1bae7e1cd9fc2 100644 (file)
@@ -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 (!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;
@@ -2062,6 +2072,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 +3059,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 +3169,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++) */