@ -37,12 +37,36 @@
# include "asterisk/pbx.h"
# include "asterisk/causes.h"
# include "asterisk/musiconhold.h"
# include "asterisk/cli.h"
# include "asterisk/transcap.h"
# include "sig_ss7.h"
/* ------------------------------------------------------------------- */
static const char * sig_ss7_call_level2str ( enum sig_ss7_call_level level )
{
switch ( level ) {
case SIG_SS7_CALL_LEVEL_IDLE :
return " Idle " ;
case SIG_SS7_CALL_LEVEL_ALLOCATED :
return " Allocated " ;
case SIG_SS7_CALL_LEVEL_CONTINUITY :
return " Continuity " ;
case SIG_SS7_CALL_LEVEL_SETUP :
return " Setup " ;
case SIG_SS7_CALL_LEVEL_PROCEEDING :
return " Proceeding " ;
case SIG_SS7_CALL_LEVEL_ALERTING :
return " Alerting " ;
case SIG_SS7_CALL_LEVEL_CONNECT :
return " Connect " ;
case SIG_SS7_CALL_LEVEL_GLARE :
return " Glare " ;
}
return " Unknown " ;
}
# define SIG_SS7_DEADLOCK_AVOIDANCE(p) \
do { \
sig_ss7_unlock_private ( p ) ; \
@ -247,7 +271,7 @@ static void sig_ss7_handle_link_exception(struct sig_ss7_linkset *linkset, int w
* \ brief Obtain the sig_ss7 owner channel lock if the owner exists .
* \ since 1.8
*
* \ param ss7 sig_ss7 SS7 control structure .
* \ param ss7 SS7 linkset control structure .
* \ param chanpos Channel position in the span .
*
* \ note Assumes the ss7 - > lock is already obtained .
@ -278,7 +302,7 @@ static void sig_ss7_lock_owner(struct sig_ss7_linkset *ss7, int chanpos)
* \ brief Queue the given frame onto the owner channel .
* \ since 1.8
*
* \ param ss7 sig_ss7 SS7 control structure .
* \ param ss7 SS7 linkset control structure .
* \ param chanpos Channel position in the span .
* \ param frame Frame to queue onto the owner channel .
*
@ -301,7 +325,7 @@ static void sig_ss7_queue_frame(struct sig_ss7_linkset *ss7, int chanpos, struct
* \ brief Queue a control frame of the specified subclass onto the owner channel .
* \ since 1.8
*
* \ param ss7 sig_ss7 SS7 control structure .
* \ param ss7 SS7 linkset control structure .
* \ param chanpos Channel position in the span .
* \ param subclass Control frame subclass to queue onto the owner channel .
*
@ -323,6 +347,17 @@ static void sig_ss7_queue_control(struct sig_ss7_linkset *ss7, int chanpos, int
sig_ss7_queue_frame ( ss7 , chanpos , & f ) ;
}
/*!
* \ internal
* \ brief Find the channel position by CIC / DPC .
*
* \ param linkset SS7 linkset control structure .
* \ param cic Circuit Identification Code
* \ param dpc Destination Point Code
*
* \ retval chanpos on success .
* \ retval - 1 on error .
*/
static int ss7_find_cic ( struct sig_ss7_linkset * linkset , int cic , unsigned int dpc )
{
int i ;
@ -336,6 +371,31 @@ static int ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int d
return winner ;
}
/*!
* \ internal
* \ brief Find the channel position by CIC / DPC and gripe if not found .
*
* \ param linkset SS7 linkset control structure .
* \ param cic Circuit Identification Code
* \ param dpc Destination Point Code
* \ param msg_name Message type name that failed .
*
* \ retval chanpos on success .
* \ retval - 1 on error .
*/
static int ss7_find_cic_gripe ( struct sig_ss7_linkset * linkset , int cic , unsigned int dpc , const char * msg_name )
{
int chanpos ;
chanpos = ss7_find_cic ( linkset , cic , dpc ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " Linkset %d: SS7 %s requested unconfigured CIC/DPC %d/%d. \n " ,
linkset - > span , msg_name , cic , dpc ) ;
return - 1 ;
}
return chanpos ;
}
static void ss7_handle_cqm ( struct sig_ss7_linkset * linkset , int startcic , int endcic , unsigned int dpc )
{
unsigned char status [ 32 ] ;
@ -386,6 +446,7 @@ static inline void ss7_block_cics(struct sig_ss7_linkset *linkset, int startcic,
{
int i ;
/* XXX the use of state here seems questionable about matching up with the linkset channels */
for ( i = 0 ; i < linkset - > numchans ; i + + ) {
if ( linkset - > pvts [ i ] & & ( linkset - > pvts [ i ] - > dpc = = dpc & & ( ( linkset - > pvts [ i ] - > cic > = startcic ) & & ( linkset - > pvts [ i ] - > cic < = endcic ) ) ) ) {
if ( state ) {
@ -617,8 +678,6 @@ void *ss7_linkset(void *data)
struct sig_ss7_chan * p ;
int chanpos ;
struct pollfd pollers [ SIG_SS7_NUM_DCHANS ] ;
int cic ;
unsigned int dpc ;
int nextms = 0 ;
pthread_setcancelstate ( PTHREAD_CANCEL_DISABLE , NULL ) ;
@ -685,6 +744,11 @@ void *ss7_linkset(void *data)
}
while ( ( e = ss7_check_event ( ss7 ) ) ) {
if ( linkset - > debug ) {
ast_verbose ( " Linkset %d: Processing event: %s \n " ,
linkset - > span , ss7_event2str ( e - > e ) ) ;
}
switch ( e - > e ) {
case SS7_EVENT_UP :
if ( linkset - > state ! = LINKSET_STATE_UP ) {
@ -710,9 +774,8 @@ void *ss7_linkset(void *data)
ast_log ( LOG_WARNING , " MTP2 link down (SLC %d) \n " , e - > gen . data ) ;
break ;
case ISUP_EVENT_CPG :
chanpos = ss7_find_cic ( linkset , e - > cpg . cic , e - > cpg . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > cpg . cic , e - > cpg . opc , " CPG " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " CPG on unconfigured CIC %d \n " , e - > cpg . cic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -753,17 +816,15 @@ void *ss7_linkset(void *data)
break ;
case ISUP_EVENT_RSC :
ast_verbose ( " Resetting CIC %d \n " , e - > rsc . cic ) ;
chanpos = ss7_find_cic ( linkset , e - > rsc . cic , e - > rsc . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > rsc . cic , e - > rsc . opc , " RSC " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " RSC on unconfigured CIC %d \n " , e - > rsc . cic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
sig_ss7_lock_private ( p ) ;
sig_ss7_set_inservice ( p , 1 ) ;
sig_ss7_set_remotelyblocked ( p , 0 ) ;
dpc = p - > dpc ;
isup_set_call_dpc ( e - > rsc . call , dpc ) ;
isup_set_call_dpc ( e - > rsc . call , p - > dpc ) ;
sig_ss7_lock_owner ( linkset , chanpos ) ;
p - > ss7call = NULL ;
if ( p - > owner ) {
@ -775,9 +836,8 @@ void *ss7_linkset(void *data)
break ;
case ISUP_EVENT_GRS :
ast_debug ( 1 , " Got Reset for CICs %d to %d: Acknowledging \n " , e - > grs . startcic , e - > grs . endcic ) ;
chanpos = ss7_find_cic ( linkset , e - > grs . startcic , e - > grs . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > grs . startcic , e - > grs . opc , " GRS " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " GRS on unconfigured CIC %d \n " , e - > grs . startcic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -796,29 +856,53 @@ void *ss7_linkset(void *data)
break ;
case ISUP_EVENT_IAM :
ast_debug ( 1 , " Got IAM for CIC %d and called number %s, calling number %s \n " , e - > iam . cic , e - > iam . called_party_num , e - > iam . calling_party_num ) ;
chanpos = ss7_find_cic ( linkset , e - > iam . cic , e - > iam . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > iam . cic , e - > iam . opc , " IAM " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " IAM on unconfigured CIC %d \n " , e - > iam . cic ) ;
isup_rel ( ss7 , e - > iam . call , - 1 ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
sig_ss7_lock_private ( p ) ;
if ( p - > owner ) {
if ( p - > ss7call = = e - > iam . call ) {
sig_ss7_unlock_private ( p ) ;
ast_log ( LOG_WARNING , " Duplicate IAM requested on CIC %d \n " , e - > iam . cic ) ;
break ;
} else {
sig_ss7_unlock_private ( p ) ;
ast_log ( LOG_WARNING , " Ring requested on CIC %d already in use! \n " , e - > iam . cic ) ;
break ;
sig_ss7_lock_owner ( linkset , chanpos ) ;
if ( p - > call_level ! = SIG_SS7_CALL_LEVEL_IDLE ) {
/*
* Detected glare / dual - seizure
*
* Always abort both calls since we can ' t implement the dual
* seizure procedures due to our channel assignment architecture
* and the fact that we cannot tell libss7 to discard its call
* structure to ignore the incoming IAM .
*/
ast_debug ( 1 ,
" Linkset %d: SS7 IAM glare on CIC/DPC %d/%d. Dropping both calls. \n " ,
linkset - > span , e - > iam . cic , e - > iam . opc ) ;
if ( p - > call_level = = SIG_SS7_CALL_LEVEL_ALLOCATED ) {
/*
* We have not sent our IAM yet and we never will at this point .
*/
p - > alreadyhungup = 1 ;
isup_rel ( ss7 , e - > iam . call , - 1 ) ;
}
p - > call_level = SIG_SS7_CALL_LEVEL_GLARE ;
if ( p - > owner ) {
p - > owner - > hangupcause = AST_CAUSE_NORMAL_CLEARING ;
ast_softhangup_nolock ( p - > owner , AST_SOFTHANGUP_DEV ) ;
ast_channel_unlock ( p - > owner ) ;
}
sig_ss7_unlock_private ( p ) ;
break ;
}
dpc = p - > dpc ;
/*
* The channel should not have an owner at this point since we
* are in the process of creating an owner for it .
*/
ast_assert ( ! p - > owner ) ;
/* Mark channel as in use so no outgoing call will steal it. */
p - > call_level = SIG_SS7_CALL_LEVEL_ALLOCATED ;
p - > ss7call = e - > iam . call ;
isup_set_call_dpc ( p - > ss7call , dpc ) ;
isup_set_call_dpc ( p - > ss7call , p - > dpc ) ;
if ( ( p - > use_callerid ) & & ( ! ast_strlen_zero ( e - > iam . calling_party_num ) ) ) {
ss7_apply_plan_to_number ( p - > cid_num , sizeof ( p - > cid_num ) , linkset , e - > iam . calling_party_num , e - > iam . calling_nai ) ;
@ -830,8 +914,10 @@ void *ss7_linkset(void *data)
if ( ! ast_strlen_zero ( e - > iam . called_party_num ) ) {
ss7_apply_plan_to_number ( p - > exten , sizeof ( p - > exten ) , linkset ,
e - > iam . called_party_num , e - > iam . called_nai ) ;
sig_ss7_set_dnid ( p , p - > exten ) ;
} else {
p - > exten [ 0 ] = ' \0 ' ;
}
sig_ss7_set_dnid ( p , p - > exten ) ;
if ( p - > immediate ) {
p - > exten [ 0 ] = ' s ' ;
@ -874,9 +960,11 @@ void *ss7_linkset(void *data)
if ( ast_exists_extension ( NULL , p - > context , p - > exten , 1 , p - > cid_num ) ) {
if ( e - > iam . cot_check_required ) {
p - > call_level = SIG_SS7_CALL_LEVEL_CONTINUITY ;
sig_ss7_loopback ( p , 1 ) ;
} else
} else {
ss7_start_call ( p , linkset ) ;
}
} else {
ast_debug ( 1 , " Call on CIC for unconfigured extension %s \n " , p - > exten ) ;
p - > alreadyhungup = 1 ;
@ -885,9 +973,8 @@ void *ss7_linkset(void *data)
sig_ss7_unlock_private ( p ) ;
break ;
case ISUP_EVENT_COT :
chanpos = ss7_find_cic ( linkset , e - > cot . cic , e - > cot . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > cot . cic , e - > cot . opc , " COT " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " COT on unconfigured CIC %d \n " , e - > cot . cic ) ;
isup_rel ( ss7 , e - > cot . call , - 1 ) ;
break ;
}
@ -902,9 +989,8 @@ void *ss7_linkset(void *data)
break ;
case ISUP_EVENT_CCR :
ast_debug ( 1 , " Got CCR request on CIC %d \n " , e - > ccr . cic ) ;
chanpos = ss7_find_cic ( linkset , e - > ccr . cic , e - > ccr . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > ccr . cic , e - > ccr . opc , " CCR " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " CCR on unconfigured CIC %d \n " , e - > ccr . cic ) ;
break ;
}
@ -918,9 +1004,8 @@ void *ss7_linkset(void *data)
break ;
case ISUP_EVENT_CVT :
ast_debug ( 1 , " Got CVT request on CIC %d \n " , e - > cvt . cic ) ;
chanpos = ss7_find_cic ( linkset , e - > cvt . cic , e - > cvt . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > cvt . cic , e - > cvt . opc , " CVT " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " CVT on unconfigured CIC %d \n " , e - > cvt . cic ) ;
break ;
}
@ -933,9 +1018,10 @@ void *ss7_linkset(void *data)
isup_cvr ( linkset - > ss7 , e - > cvt . cic , p - > dpc ) ;
break ;
case ISUP_EVENT_REL :
chanpos = ss7_find_cic ( linkset , e - > rel . cic , e - > rel . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > rel . cic , e - > rel . opc , " REL " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " REL on unconfigured CIC %d \n " , e - > rel . cic ) ;
/* Continue hanging up the call anyway. */
isup_rlc ( ss7 , e - > rel . call ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -945,8 +1031,6 @@ void *ss7_linkset(void *data)
p - > owner - > hangupcause = e - > rel . cause ;
ast_softhangup_nolock ( p - > owner , AST_SOFTHANGUP_DEV ) ;
ast_channel_unlock ( p - > owner ) ;
} else {
ast_log ( LOG_WARNING , " REL on channel (CIC %d) without owner! \n " , p - > cic ) ;
}
/* End the loopback if we have one */
@ -958,12 +1042,12 @@ void *ss7_linkset(void *data)
sig_ss7_unlock_private ( p ) ;
break ;
case ISUP_EVENT_ACM :
chanpos = ss7_find_cic ( linkset , e - > acm . cic , e - > acm . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > acm . cic , e - > acm . opc , " ACM " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " ACM on unconfigured CIC %d \n " , e - > acm . cic ) ;
isup_rel ( ss7 , e - > acm . call , - 1 ) ;
break ;
} else {
}
{
p = linkset - > pvts [ chanpos ] ;
ast_debug ( 1 , " Queueing frame from SS7_EVENT_ACM on CIC %d \n " , p - > cic ) ;
@ -994,9 +1078,8 @@ void *ss7_linkset(void *data)
}
break ;
case ISUP_EVENT_CGB :
chanpos = ss7_find_cic ( linkset , e - > cgb . startcic , e - > cgb . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > cgb . startcic , e - > cgb . opc , " CGB " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " CGB on unconfigured CIC %d \n " , e - > cgb . startcic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -1004,9 +1087,8 @@ void *ss7_linkset(void *data)
isup_cgba ( linkset - > ss7 , e - > cgb . startcic , e - > cgb . endcic , e - > cgb . opc , e - > cgb . status , e - > cgb . type ) ;
break ;
case ISUP_EVENT_CGU :
chanpos = ss7_find_cic ( linkset , e - > cgu . startcic , e - > cgu . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > cgu . startcic , e - > cgu . opc , " CGU " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " CGU on unconfigured CIC %d \n " , e - > cgu . startcic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -1014,9 +1096,8 @@ void *ss7_linkset(void *data)
isup_cgua ( linkset - > ss7 , e - > cgu . startcic , e - > cgu . endcic , e - > cgu . opc , e - > cgu . status , e - > cgu . type ) ;
break ;
case ISUP_EVENT_UCIC :
chanpos = ss7_find_cic ( linkset , e - > ucic . cic , e - > ucic . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > ucic . cic , e - > ucic . opc , " UCIC " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " UCIC on unconfigured CIC %d \n " , e - > ucic . cic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -1027,9 +1108,8 @@ void *ss7_linkset(void *data)
sig_ss7_unlock_private ( p ) ; /* doesn't require a SS7 acknowledgement */
break ;
case ISUP_EVENT_BLO :
chanpos = ss7_find_cic ( linkset , e - > blo . cic , e - > blo . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > blo . cic , e - > blo . opc , " BLO " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " BLO on unconfigured CIC %d \n " , e - > blo . cic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -1040,9 +1120,8 @@ void *ss7_linkset(void *data)
isup_bla ( linkset - > ss7 , e - > blo . cic , p - > dpc ) ;
break ;
case ISUP_EVENT_BLA :
chanpos = ss7_find_cic ( linkset , e - > bla . cic , e - > bla . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > bla . cic , e - > bla . opc , " BLA " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " BLA on unconfigured CIC %d \n " , e - > bla . cic ) ;
break ;
}
ast_debug ( 1 , " Blocking CIC %d \n " , e - > bla . cic ) ;
@ -1052,9 +1131,8 @@ void *ss7_linkset(void *data)
sig_ss7_unlock_private ( p ) ;
break ;
case ISUP_EVENT_UBL :
chanpos = ss7_find_cic ( linkset , e - > ubl . cic , e - > ubl . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > ubl . cic , e - > ubl . opc , " UBL " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " UBL on unconfigured CIC %d \n " , e - > ubl . cic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -1065,9 +1143,8 @@ void *ss7_linkset(void *data)
isup_uba ( linkset - > ss7 , e - > ubl . cic , p - > dpc ) ;
break ;
case ISUP_EVENT_UBA :
chanpos = ss7_find_cic ( linkset , e - > uba . cic , e - > uba . opc ) ;
chanpos = ss7_find_cic _gripe ( linkset , e - > uba . cic , e - > uba . opc , " UBA " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " UBA on unconfigured CIC %d \n " , e - > uba . cic ) ;
break ;
}
p = linkset - > pvts [ chanpos ] ;
@ -1078,17 +1155,21 @@ void *ss7_linkset(void *data)
break ;
case ISUP_EVENT_CON :
case ISUP_EVENT_ANM :
if ( e - > e = = ISUP_EVENT_CON )
cic = e - > con . cic ;
else
cic = e - > anm . cic ;
chanpos = ss7_find_cic ( linkset , cic , ( e - > e = = ISUP_EVENT_ANM ) ? e - > anm . opc : e - > con . opc ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " ANM/CON on unconfigured CIC %d \n " , cic ) ;
isup_rel ( ss7 , ( e - > e = = ISUP_EVENT_ANM ) ? e - > anm . call : e - > con . call , - 1 ) ;
break ;
if ( e - > e = = ISUP_EVENT_CON ) {
chanpos = ss7_find_cic_gripe ( linkset , e - > con . cic , e - > con . opc , " CON " ) ;
if ( chanpos < 0 ) {
isup_rel ( ss7 , e - > con . call , - 1 ) ;
break ;
}
} else {
chanpos = ss7_find_cic_gripe ( linkset , e - > anm . cic , e - > anm . opc , " ANM " ) ;
if ( chanpos < 0 ) {
isup_rel ( ss7 , e - > anm . call , - 1 ) ;
break ;
}
}
{
p = linkset - > pvts [ chanpos ] ;
sig_ss7_lock_private ( p ) ;
if ( p - > call_level < SIG_SS7_CALL_LEVEL_CONNECT ) {
@ -1106,30 +1187,43 @@ void *ss7_linkset(void *data)
}
break ;
case ISUP_EVENT_RLC :
chanpos = ss7_find_cic ( linkset , e - > rlc . cic , e - > rlc . opc ) ;
/* XXX Call ptr should be passed up from libss7! */
chanpos = ss7_find_cic_gripe ( linkset , e - > rlc . cic , e - > rlc . opc , " RLC " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " RLC on unconfigured CIC %d \n " , e - > rlc . cic ) ;
break ;
} else {
}
{
p = linkset - > pvts [ chanpos ] ;
sig_ss7_lock_private ( p ) ;
if ( p - > alreadyhungup )
if ( p - > alreadyhungup ) {
if ( ! p - > owner ) {
p - > call_level = SIG_SS7_CALL_LEVEL_IDLE ;
}
p - > ss7call = NULL ;
else
ast_log ( LOG_NOTICE , " Received RLC out and we haven't sent REL. Ignoring. \n " ) ;
}
sig_ss7_unlock_private ( p ) ;
}
break ;
case ISUP_EVENT_FAA :
chanpos = ss7_find_cic ( linkset , e - > faa . cic , e - > faa . opc ) ;
/*!
* \ todo The handling of the SS7 FAA message is not good and I
* don ' t know enough to handle it correctly .
*/
chanpos = ss7_find_cic_gripe ( linkset , e - > faa . cic , e - > faa . opc , " FAA " ) ;
if ( chanpos < 0 ) {
ast_log ( LOG_WARNING , " FAA on unconfigured CIC %d \n " , e - > faa . cic ) ;
isup_rel( linkset - > ss7 , e - > faa . call , - 1 ) ;
break ;
} else {
}
{
/* XXX FAR and FAA used for something dealing with transfers? */
p = linkset - > pvts [ chanpos ] ;
ast_debug ( 1 , " FAA received on CIC %d \n " , e - > faa . cic ) ;
sig_ss7_lock_private ( p ) ;
if ( p - > alreadyhungup ) {
if ( ! p - > owner ) {
p - > call_level = SIG_SS7_CALL_LEVEL_IDLE ;
}
/* XXX We seem to be leaking the isup call structure here. */
p - > ss7call = NULL ;
ast_log ( LOG_NOTICE , " Received FAA and we haven't sent FAR. Ignoring. \n " ) ;
}
@ -1246,6 +1340,24 @@ int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type,
return 0 ;
}
/*!
* \ internal
* \ brief Determine if a private channel structure is available .
*
* \ param pvt Channel to determine if available .
*
* \ return TRUE if the channel is available .
*/
static int sig_ss7_is_chan_available ( struct sig_ss7_chan * pvt )
{
if ( ! pvt - > inalarm & & ! pvt - > owner & & ! pvt - > ss7call
& & pvt - > call_level = = SIG_SS7_CALL_LEVEL_IDLE
& & ! pvt - > locallyblocked & & ! pvt - > remotelyblocked ) {
return 1 ;
}
return 0 ;
}
/*!
* \ brief Determine if the specified channel is available for an outgoing call .
* \ since 1.8
@ -1256,17 +1368,22 @@ int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type,
*/
int sig_ss7_available ( struct sig_ss7_chan * p )
{
int available ;
if ( ! p - > ss7 ) {
/* Something is wrong here. A SS7 channel without the ss7 pointer? */
return 0 ;
}
if ( ! p - > inalarm & & ! p - > owner & & ! p - > ss7call
& & ! p - > locallyblocked & & ! p - > remotelyblocked ) {
return 1 ;
/* Only have to deal with the linkset lock. */
ast_mutex_lock ( & p - > ss7 - > lock ) ;
available = sig_ss7_is_chan_available ( p ) ;
if ( available ) {
p - > call_level = SIG_SS7_CALL_LEVEL_ALLOCATED ;
}
ast_mutex_unlock ( & p - > ss7 - > lock ) ;
return 0 ;
return available ;
}
static unsigned char cid_pres2ss7pres ( int cid_pres )
@ -1333,6 +1450,12 @@ int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, char *rdest)
ss7_grab ( p , p - > ss7 ) ;
if ( p - > call_level ! = SIG_SS7_CALL_LEVEL_ALLOCATED ) {
/* Call collision before sending IAM. Abort call. */
ss7_rel ( p - > ss7 ) ;
return - 1 ;
}
p - > ss7call = isup_new_call ( p - > ss7 - > ss7 ) ;
if ( ! p - > ss7call ) {
ss7_rel ( p - > ss7 ) ;
@ -1447,14 +1570,14 @@ int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
p - > owner = NULL ;
sig_ss7_set_dialing ( p , 0 ) ;
p - > call_level = SIG_SS7_CALL_LEVEL_IDLE ;
p - > outgoing = 0 ;
p - > progress = 0 ;
p - > rlt = 0 ;
p - > exten [ 0 ] = ' \0 ' ;
/* Perform low level hangup if no owner left */
ss7_grab ( p , p - > ss7 ) ;
p - > call_level = SIG_SS7_CALL_LEVEL_IDLE ;
if ( p - > ss7call ) {
ss7_grab ( p , p - > ss7 ) ;
if ( ! p - > alreadyhungup ) {
const char * cause = pbx_builtin_getvar_helper ( ast , " SS7_CAUSE " ) ;
int icause = ast - > hangupcause ? ast - > hangupcause : - 1 ;
@ -1466,11 +1589,9 @@ int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
}
isup_rel ( p - > ss7 - > ss7 , p - > ss7call , icause ) ;
p - > alreadyhungup = 1 ;
} else {
ast_log ( LOG_WARNING , " Trying to hangup twice! \n " ) ;
}
ss7_rel ( p - > ss7 ) ;
}
ss7_rel ( p - > ss7 ) ;
return res ;
}
@ -1537,17 +1658,19 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
res = sig_ss7_play_tone ( p , SIG_SS7_TONE_BUSY ) ;
break ;
case AST_CONTROL_RINGING :
ss7_grab ( p , p - > ss7 ) ;
if ( p - > call_level < SIG_SS7_CALL_LEVEL_ALERTING & & ! p - > outgoing ) {
p - > call_level = SIG_SS7_CALL_LEVEL_ALERTING ;
if ( p - > ss7 & & p - > ss7 - > ss7 ) {
ss7_grab ( p , p - > ss7 ) ;
if ( ( isup_far ( p - > ss7 - > ss7 , p - > ss7call ) ) ! = - 1 )
p - > rlt = 1 ;
if ( p - > rlt ! = 1 ) /* No need to send CPG if call will be RELEASE */
isup_cpg ( p - > ss7 - > ss7 , p - > ss7call , CPG_EVENT_ALERTING ) ;
ss7_rel ( p - > ss7 ) ;
if ( ( isup_far ( p - > ss7 - > ss7 , p - > ss7call ) ) ! = - 1 ) {
p - > rlt = 1 ;
}
/* No need to send CPG if call will be RELEASE */
if ( p - > rlt ! = 1 ) {
isup_cpg ( p - > ss7 - > ss7 , p - > ss7call , CPG_EVENT_ALERTING ) ;
}
}
ss7_rel ( p - > ss7 ) ;
res = sig_ss7_play_tone ( p , SIG_SS7_TONE_RINGTONE ) ;
@ -1557,37 +1680,34 @@ int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condi
break ;
case AST_CONTROL_PROCEEDING :
ast_debug ( 1 , " Received AST_CONTROL_PROCEEDING on %s \n " , chan - > name ) ;
ss7_grab ( p , p - > ss7 ) ;
/* This IF sends the FAR for an answered ALEG call */
if ( chan - > _state = = AST_STATE_UP & & ( p - > rlt ! = 1 ) ) {
ss7_grab ( p , p - > ss7 ) ;
if ( ( isup_far ( p - > ss7 - > ss7 , p - > ss7call ) ) ! = - 1 ) {
p - > rlt = 1 ;
}
ss7_rel ( p - > ss7 ) ;
}
if ( p - > call_level < SIG_SS7_CALL_LEVEL_PROCEEDING & & ! p - > outgoing ) {
p - > call_level = SIG_SS7_CALL_LEVEL_PROCEEDING ;
if ( p - > ss7 & & p - > ss7 - > ss7 ) {
ss7_grab ( p , p - > ss7 ) ;
isup_acm ( p - > ss7 - > ss7 , p - > ss7call ) ;
ss7_rel ( p - > ss7 ) ;
}
isup_acm ( p - > ss7 - > ss7 , p - > ss7call ) ;
}
ss7_rel ( p - > ss7 ) ;
/* don't continue in ast_indicate */
res = 0 ;
break ;
case AST_CONTROL_PROGRESS :
ast_debug ( 1 , " Received AST_CONTROL_PROGRESS on %s \n " , chan - > name ) ;
ss7_grab ( p , p - > ss7 ) ;
if ( ! p - > progress & & p - > call_level < SIG_SS7_CALL_LEVEL_ALERTING & & ! p - > outgoing ) {
p - > progress = 1 ; /* No need to send inband-information progress again. */
if ( p - > ss7 & & p - > ss7 - > ss7 ) {
ss7_grab ( p , p - > ss7 ) ;
isup_cpg ( p - > ss7 - > ss7 , p - > ss7call , CPG_EVENT_INBANDINFO ) ;
ss7_rel ( p - > ss7 ) ;
/* enable echo canceler here on SS7 calls */
sig_ss7_set_echocanceller ( p , 1 ) ;
}
isup_cpg ( p - > ss7 - > ss7 , p - > ss7call , CPG_EVENT_INBANDINFO ) ;
ss7_rel ( p - > ss7 ) ;
/* enable echo canceler here on SS7 calls */
sig_ss7_set_echocanceller ( p , 1 ) ;
} else {
ss7_rel ( p - > ss7 ) ;
}
/* don't continue in ast_indicate */
res = 0 ;
@ -1639,6 +1759,11 @@ struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law
ast = sig_ss7_new_ast_channel ( p , AST_STATE_RESERVED , law , transfercapability , p - > exten , requestor ) ;
if ( ! ast ) {
p - > outgoing = 0 ;
/* Release the allocated channel. Only have to deal with the linkset lock. */
ast_mutex_lock ( & p - > ss7 - > lock ) ;
p - > call_level = SIG_SS7_CALL_LEVEL_IDLE ;
ast_mutex_unlock ( & p - > ss7 - > lock ) ;
}
return ast ;
}
@ -1656,6 +1781,51 @@ void sig_ss7_chan_delete(struct sig_ss7_chan *doomed)
ast_free ( doomed ) ;
}
# define SIG_SS7_SC_HEADER "%-4s %4s %-4s %-3s %-3s %-10s %-4s %s\n"
# define SIG_SS7_SC_LINE "%4d %4d %-4s %-3s %-3s %-10s %-4s %s"
void sig_ss7_cli_show_channels_header ( int fd )
{
ast_cli ( fd , SIG_SS7_SC_HEADER , " link " , " " , " Chan " , " Lcl " , " Rem " , " Call " , " SS7 " , " Channel " ) ;
ast_cli ( fd , SIG_SS7_SC_HEADER , " set " , " Chan " , " Idle " , " Blk " , " Blk " , " Level " , " Call " , " Name " ) ;
}
void sig_ss7_cli_show_channels ( int fd , struct sig_ss7_linkset * linkset )
{
char line [ 256 ] ;
int idx ;
struct sig_ss7_chan * pvt ;
ast_mutex_lock ( & linkset - > lock ) ;
for ( idx = 0 ; idx < linkset - > numchans ; + + idx ) {
if ( ! linkset - > pvts [ idx ] ) {
continue ;
}
pvt = linkset - > pvts [ idx ] ;
sig_ss7_lock_private ( pvt ) ;
sig_ss7_lock_owner ( linkset , idx ) ;
snprintf ( line , sizeof ( line ) , SIG_SS7_SC_LINE ,
linkset - > span ,
pvt - > channel ,
sig_ss7_is_chan_available ( pvt ) ? " Yes " : " No " ,
pvt - > locallyblocked ? " Yes " : " No " ,
pvt - > remotelyblocked ? " Yes " : " No " ,
sig_ss7_call_level2str ( pvt - > call_level ) ,
pvt - > ss7call ? " Yes " : " No " ,
pvt - > owner ? pvt - > owner - > name : " " ) ;
if ( pvt - > owner ) {
ast_channel_unlock ( pvt - > owner ) ;
}
sig_ss7_unlock_private ( pvt ) ;
ast_mutex_unlock ( & linkset - > lock ) ;
ast_cli ( fd , " %s \n " , line ) ;
ast_mutex_lock ( & linkset - > lock ) ;
}
ast_mutex_unlock ( & linkset - > lock ) ;
}
/*!
* \ brief Create a new sig_ss7 private channel structure .
* \ since 1.8
@ -1687,7 +1857,7 @@ struct sig_ss7_chan *sig_ss7_chan_new(void *pvt_data, struct sig_ss7_callback *c
* \ brief Initialize the SS7 linkset control .
* \ since 1.8
*
* \ param ss7 sig_ss7 SS7 control structure .
* \ param ss7 SS7 linkset control structure .
*
* \ return Nothing
*/