2009-05-11 09:07:58 +00:00
/*****************************************************************************\
* * * *
* * LCR * *
* * * *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * *
* * Copyright : Andreas Eversberg * *
2011-09-02 09:08:56 +00:00
* * MNCC - Interface : Harald Welte * *
2009-05-11 09:07:58 +00:00
* * * *
* * mISDN gsm * *
* * * *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "main.h"
2011-09-02 09:08:56 +00:00
# include "mncc.h"
2009-06-28 15:29:07 +00:00
2009-08-23 12:58:21 +00:00
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
2009-05-11 09:07:58 +00:00
extern " C " {
# include "gsm_audio.h"
}
2011-09-02 09:08:56 +00:00
# include <assert.h>
2009-06-28 15:29:07 +00:00
2011-09-02 09:08:56 +00:00
# define SOCKET_RETRY_TIMER 5
//struct lcr_gsm *gsm = NULL;
2009-05-11 09:07:58 +00:00
2010-05-31 16:45:02 +00:00
int new_callref = 1 ;
2009-05-11 09:07:58 +00:00
2011-02-20 16:34:24 +00:00
/* names of MNCC-SAP */
static const struct _value_string {
int msg_type ;
const char * name ;
} mncc_names [ ] = {
2012-01-15 08:42:35 +00:00
{ 0 , " New call ref " } ,
2012-02-01 16:52:36 +00:00
{ 1 , " Codec negotiation " } ,
2011-02-20 16:34:24 +00:00
{ MNCC_SETUP_REQ , " MNCC_SETUP_REQ " } ,
{ MNCC_SETUP_IND , " MNCC_SETUP_IND " } ,
{ MNCC_SETUP_RSP , " MNCC_SETUP_RSP " } ,
{ MNCC_SETUP_CNF , " MNCC_SETUP_CNF " } ,
{ MNCC_SETUP_COMPL_REQ , " MNCC_SETUP_COMPL_REQ " } ,
{ MNCC_SETUP_COMPL_IND , " MNCC_SETUP_COMPL_IND " } ,
{ MNCC_CALL_CONF_IND , " MNCC_CALL_CONF_IND " } ,
{ MNCC_CALL_PROC_REQ , " MNCC_CALL_PROC_REQ " } ,
{ MNCC_PROGRESS_REQ , " MNCC_PROGRESS_REQ " } ,
{ MNCC_ALERT_REQ , " MNCC_ALERT_REQ " } ,
{ MNCC_ALERT_IND , " MNCC_ALERT_IND " } ,
{ MNCC_NOTIFY_REQ , " MNCC_NOTIFY_REQ " } ,
{ MNCC_NOTIFY_IND , " MNCC_NOTIFY_IND " } ,
{ MNCC_DISC_REQ , " MNCC_DISC_REQ " } ,
{ MNCC_DISC_IND , " MNCC_DISC_IND " } ,
{ MNCC_REL_REQ , " MNCC_REL_REQ " } ,
{ MNCC_REL_IND , " MNCC_REL_IND " } ,
{ MNCC_REL_CNF , " MNCC_REL_CNF " } ,
{ MNCC_FACILITY_REQ , " MNCC_FACILITY_REQ " } ,
{ MNCC_FACILITY_IND , " MNCC_FACILITY_IND " } ,
{ MNCC_START_DTMF_IND , " MNCC_START_DTMF_IND " } ,
{ MNCC_START_DTMF_RSP , " MNCC_START_DTMF_RSP " } ,
{ MNCC_START_DTMF_REJ , " MNCC_START_DTMF_REJ " } ,
{ MNCC_STOP_DTMF_IND , " MNCC_STOP_DTMF_IND " } ,
{ MNCC_STOP_DTMF_RSP , " MNCC_STOP_DTMF_RSP " } ,
{ MNCC_MODIFY_REQ , " MNCC_MODIFY_REQ " } ,
{ MNCC_MODIFY_IND , " MNCC_MODIFY_IND " } ,
{ MNCC_MODIFY_RSP , " MNCC_MODIFY_RSP " } ,
{ MNCC_MODIFY_CNF , " MNCC_MODIFY_CNF " } ,
{ MNCC_MODIFY_REJ , " MNCC_MODIFY_REJ " } ,
{ MNCC_HOLD_IND , " MNCC_HOLD_IND " } ,
{ MNCC_HOLD_CNF , " MNCC_HOLD_CNF " } ,
{ MNCC_HOLD_REJ , " MNCC_HOLD_REJ " } ,
{ MNCC_RETRIEVE_IND , " MNCC_RETRIEVE_IND " } ,
{ MNCC_RETRIEVE_CNF , " MNCC_RETRIEVE_CNF " } ,
{ MNCC_RETRIEVE_REJ , " MNCC_RETRIEVE_REJ " } ,
{ MNCC_USERINFO_REQ , " MNCC_USERINFO_REQ " } ,
{ MNCC_USERINFO_IND , " MNCC_USERINFO_IND " } ,
{ MNCC_REJ_REQ , " MNCC_REJ_REQ " } ,
{ MNCC_REJ_IND , " MNCC_REJ_IND " } ,
{ MNCC_PROGRESS_IND , " MNCC_PROGRESS_IND " } ,
{ MNCC_CALL_PROC_IND , " MNCC_CALL_PROC_IND " } ,
{ MNCC_CALL_CONF_REQ , " MNCC_CALL_CONF_REQ " } ,
{ MNCC_START_DTMF_REQ , " MNCC_START_DTMF_REQ " } ,
{ MNCC_STOP_DTMF_REQ , " MNCC_STOP_DTMF_REQ " } ,
{ MNCC_HOLD_REQ , " MNCC_HOLD_REQ " } ,
{ MNCC_RETRIEVE_REQ , " MNCC_RETRIEVE_REQ " } ,
2013-03-31 10:50:04 +00:00
2012-02-01 16:52:36 +00:00
{ MNCC_LCHAN_MODIFY , " MNCC_LCHAN_MODIFY " } ,
2013-03-31 10:50:04 +00:00
{ MNCC_BRIDGE , " MNCC_BRIDGE " } ,
{ MNCC_FRAME_RECV , " MNCC_FRAME_RECV " } ,
{ MNCC_FRAME_DROP , " MNCC_FRAME_DROP " } ,
{ MNCC_RTP_CREATE , " MNCC_RTP_CREATE " } ,
{ MNCC_RTP_CONNECT , " MNCC_RTP_CONNECT " } ,
{ MNCC_RTP_FREE , " MNCC_RTP_FREE " } ,
2011-02-20 16:34:24 +00:00
{ 0 , NULL }
} ;
const char * mncc_name ( int value )
{
int i = 0 ;
2013-03-31 10:50:04 +00:00
static char ukn [ 32 ] ;
2011-02-20 16:34:24 +00:00
while ( mncc_names [ i ] . name ) {
if ( mncc_names [ i ] . msg_type = = value )
return mncc_names [ i ] . name ;
i + + ;
}
2013-03-31 10:50:04 +00:00
SPRINT ( ukn , " unknown(0x%x) " , value ) ;
return ukn ;
2011-02-20 16:34:24 +00:00
}
2011-09-02 09:08:56 +00:00
static int mncc_send ( struct lcr_gsm * lcr_gsm , int msg_type , void * data ) ;
2009-05-11 09:07:58 +00:00
/*
* create and send mncc message
*/
2010-05-31 16:45:02 +00:00
struct gsm_mncc * create_mncc ( int msg_type , unsigned int callref )
2009-05-11 09:07:58 +00:00
{
struct gsm_mncc * mncc ;
mncc = ( struct gsm_mncc * ) MALLOC ( sizeof ( struct gsm_mncc ) ) ;
mncc - > msg_type = msg_type ;
mncc - > callref = callref ;
return ( mncc ) ;
}
2011-09-02 09:08:56 +00:00
int send_and_free_mncc ( struct lcr_gsm * lcr_gsm , unsigned int msg_type , void * data )
2009-05-11 09:07:58 +00:00
{
2011-02-26 16:49:21 +00:00
int ret = 0 ;
2009-05-11 09:07:58 +00:00
2011-09-02 09:08:56 +00:00
if ( lcr_gsm ) {
ret = mncc_send ( lcr_gsm , msg_type , data ) ;
2011-02-26 16:49:21 +00:00
}
2009-05-11 09:07:58 +00:00
free ( data ) ;
return ret ;
}
2012-02-17 14:38:54 +00:00
void Pgsm : : send_mncc_rtp_connect ( void )
{
struct gsm_mncc_rtp * nrtp ;
nrtp = ( struct gsm_mncc_rtp * ) create_mncc ( MNCC_RTP_CONNECT , p_g_callref ) ;
nrtp - > ip = p_g_rtp_ip_remote ;
nrtp - > port = p_g_rtp_port_remote ;
switch ( p_g_media_type ) {
case MEDIA_TYPE_GSM :
nrtp - > payload_msg_type = GSM_TCHF_FRAME ;
break ;
case MEDIA_TYPE_GSM_EFR :
nrtp - > payload_msg_type = GSM_TCHF_FRAME_EFR ;
break ;
case MEDIA_TYPE_AMR :
2012-03-08 13:44:17 +00:00
nrtp - > payload_msg_type = GSM_TCH_FRAME_AMR ;
2012-02-17 14:38:54 +00:00
break ;
case MEDIA_TYPE_GSM_HR :
2012-03-08 13:44:17 +00:00
nrtp - > payload_msg_type = GSM_TCHH_FRAME ;
2012-02-17 14:38:54 +00:00
break ;
}
nrtp - > payload_type = p_g_payload_type ;
PDEBUG ( DEBUG_GSM , " sending MNCC RTP connect with payload_msg_type=%x, payload_type=%d \n " , nrtp - > payload_msg_type , nrtp - > payload_type ) ;
send_and_free_mncc ( p_g_lcr_gsm , nrtp - > msg_type , nrtp ) ;
}
2010-01-16 10:20:23 +00:00
static int delete_event ( struct lcr_work * work , void * instance , int index ) ;
2009-05-11 09:07:58 +00:00
/*
* constructor
*/
2012-08-19 07:42:43 +00:00
Pgsm : : Pgsm ( int type , char * portname , struct port_settings * settings , struct interface * interface ) : Port ( type , portname , settings , interface )
2012-01-15 08:42:35 +00:00
{
2013-03-31 10:50:04 +00:00
# ifdef WITH_GSMHR
signed short homing [ 160 ] ;
int i ;
# endif
2012-01-15 08:42:35 +00:00
p_g_tones = 0 ;
if ( interface - > is_tones = = IS_YES )
p_g_tones = 1 ;
p_g_earlyb = 0 ;
if ( interface - > is_earlyb = = IS_YES )
p_g_earlyb = 1 ;
p_g_rtp_bridge = 0 ;
if ( interface - > rtp_bridge )
p_g_rtp_bridge = 1 ;
2012-02-01 16:52:36 +00:00
p_g_rtp_payloads = 0 ;
2012-01-20 19:28:55 +00:00
memset ( & p_g_samples , 0 , sizeof ( p_g_samples ) ) ;
2012-01-15 08:42:35 +00:00
p_callerinfo . itype = ( interface - > extension ) ? INFO_ITYPE_ISDN_EXTENSION : INFO_ITYPE_ISDN ;
memset ( & p_g_delete , 0 , sizeof ( p_g_delete ) ) ;
add_work ( & p_g_delete , delete_event , this , 0 ) ;
p_g_lcr_gsm = NULL ;
p_g_callref = 0 ;
p_g_mode = 0 ;
p_g_gsm_b_sock = - 1 ;
p_g_gsm_b_index = - 1 ;
p_g_gsm_b_active = 0 ;
p_g_notify_pending = NULL ;
p_g_setup_pending = NULL ;
p_g_connect_pending = NULL ;
2013-03-09 17:15:33 +00:00
p_g_fr_decoder = NULL ;
p_g_fr_encoder = NULL ;
p_g_hr_decoder = NULL ;
p_g_hr_encoder = NULL ;
p_g_amr_decoder = NULL ;
p_g_amr_encoder = NULL ;
2013-03-26 07:57:58 +00:00
p_g_amr_cmr = 0 ;
p_g_amr_cmr_valid = 0 ;
2013-03-09 17:15:33 +00:00
# ifdef WITH_GSMFR
p_g_fr_decoder = gsm_fr_create ( ) ;
p_g_fr_encoder = gsm_fr_create ( ) ;
if ( ! p_g_fr_encoder | | ! p_g_fr_decoder ) {
PERROR ( " Failed to create GSM FR codec instance \n " ) ;
2012-01-15 08:42:35 +00:00
trigger_work ( & p_g_delete ) ;
2009-05-11 09:07:58 +00:00
}
2013-03-14 08:58:31 +00:00
# endif
2013-03-31 10:50:04 +00:00
# ifdef WITH_GSMHR
p_g_hr_decoder = gsm_hr_create ( ) ;
p_g_hr_encoder = gsm_hr_create ( ) ;
if ( ! p_g_hr_encoder | | ! p_g_hr_decoder ) {
PERROR ( " Failed to create GSM HR codec instance \n " ) ;
trigger_work ( & p_g_delete ) ;
}
/* Homing */
for ( i = 0 ; i < 160 ; i + + )
homing [ i ] = 0x0008 ;
gsm_hr_encode ( p_g_hr_encoder , homing , NULL ) ;
# endif
2013-03-14 08:58:31 +00:00
# ifdef WITH_GSMAMR
p_g_amr_decoder = gsm_amr_create ( ) ;
p_g_amr_encoder = gsm_amr_create ( ) ;
if ( ! p_g_amr_encoder | | ! p_g_amr_decoder ) {
PERROR ( " Failed to create GSM AMR codec instance \n " ) ;
trigger_work ( & p_g_delete ) ;
}
2013-03-09 17:15:33 +00:00
# endif
2012-01-15 08:42:35 +00:00
p_g_rxpos = 0 ;
p_g_tch_connected = 0 ;
2012-02-17 14:38:54 +00:00
p_g_media_type = 0 ;
2009-05-11 09:07:58 +00:00
2010-05-31 16:45:02 +00:00
PDEBUG ( DEBUG_GSM , " Created new GSMPort(%s). \n " , portname ) ;
2009-05-11 09:07:58 +00:00
}
/*
* destructor
*/
Pgsm : : ~ Pgsm ( )
{
PDEBUG ( DEBUG_GSM , " Destroyed GSM process(%s). \n " , p_name ) ;
2012-01-15 08:42:35 +00:00
del_work ( & p_g_delete ) ;
2010-01-16 10:20:23 +00:00
2009-05-11 09:07:58 +00:00
/* remove queued message */
2012-01-15 08:42:35 +00:00
if ( p_g_notify_pending )
message_free ( p_g_notify_pending ) ;
if ( p_g_setup_pending )
message_free ( p_g_setup_pending ) ;
if ( p_g_connect_pending )
message_free ( p_g_connect_pending ) ;
2009-05-11 09:07:58 +00:00
2013-03-09 17:15:33 +00:00
//#ifdef WITH_GSMFR
2009-05-11 09:07:58 +00:00
/* close codec */
2013-03-09 17:15:33 +00:00
if ( p_g_fr_encoder )
gsm_fr_destroy ( p_g_fr_encoder ) ;
if ( p_g_fr_decoder )
gsm_fr_destroy ( p_g_fr_decoder ) ;
//#endif
2013-03-31 10:50:04 +00:00
# ifdef WITH_GSMHR
if ( p_g_hr_encoder )
gsm_hr_destroy ( p_g_hr_encoder ) ;
if ( p_g_hr_decoder )
gsm_hr_destroy ( p_g_hr_decoder ) ;
# endif
2013-03-14 08:58:31 +00:00
# ifdef WITH_GSMAMR
/* close codec */
if ( p_g_amr_encoder )
gsm_amr_destroy ( p_g_amr_encoder ) ;
if ( p_g_amr_decoder )
gsm_amr_destroy ( p_g_amr_decoder ) ;
# endif
2009-05-11 09:07:58 +00:00
}
2010-01-16 10:20:23 +00:00
2012-01-15 08:42:35 +00:00
/* receive encoded frame from gsm */
void Pgsm : : frame_receive ( void * arg )
2009-05-11 09:07:58 +00:00
{
2012-01-15 08:42:35 +00:00
struct gsm_data_frame * frame = ( struct gsm_data_frame * ) arg ;
unsigned char data [ 160 ] ;
2013-03-26 07:57:58 +00:00
int i , cmr ;
2009-05-11 09:07:58 +00:00
2013-03-09 17:15:33 +00:00
if ( ! p_g_fr_decoder )
2012-01-15 08:42:35 +00:00
return ;
2009-05-11 09:07:58 +00:00
2013-03-09 17:15:33 +00:00
switch ( frame - > msg_type ) {
2016-01-30 14:38:02 +00:00
case ANALOG_8000HZ :
if ( p_g_media_type ! = MEDIA_TYPE_ANALOG ) {
PERROR ( " 'Analog' frame, but current media type mismatches. \n " ) ;
return ;
}
for ( i = 0 ; i < 160 ; i + + ) {
data [ i ] = audio_s16_to_law [ ( ( int16_t * ) frame - > data ) [ i ] & 0xffff ] ;
}
break ;
2013-03-09 17:15:33 +00:00
case GSM_TCHF_FRAME :
2013-03-14 08:58:31 +00:00
if ( p_g_media_type ! = MEDIA_TYPE_GSM ) {
PERROR ( " FR frame, but current media type mismatches. \n " ) ;
return ;
}
if ( ! p_g_fr_decoder ) {
PERROR ( " FR frame, but decoder not created. \n " ) ;
return ;
}
2013-03-09 17:15:33 +00:00
if ( ( frame - > data [ 0 ] > > 4 ) ! = 0xd ) {
PDEBUG ( DEBUG_GSM , " received GSM frame with wrong magig 0x%x \n " , frame - > data [ 0 ] > > 4 ) ;
goto bfi ;
2012-01-20 19:28:55 +00:00
}
2013-03-09 17:15:33 +00:00
# ifdef WITH_GSMFR
/* decode */
gsm_fr_decode ( p_g_fr_decoder , frame - > data , p_g_samples ) ;
2012-01-20 19:28:55 +00:00
for ( i = 0 ; i < 160 ; i + + ) {
data [ i ] = audio_s16_to_law [ p_g_samples [ i ] & 0xffff ] ;
}
2013-03-31 10:50:04 +00:00
# endif
break ;
case GSM_TCHH_FRAME :
if ( p_g_media_type ! = MEDIA_TYPE_GSM_HR ) {
PERROR ( " HR frame, but current media type mismatches. \n " ) ;
return ;
}
if ( ! p_g_hr_decoder ) {
PERROR ( " HR frame, but decoder not created. \n " ) ;
return ;
}
if ( ( frame - > data [ 0 ] > > 4 ) ! = 0x0 )
goto bfi ;
# ifdef WITH_GSMHR
/* decode */
if ( gsm_hr_decode ( p_g_hr_decoder , frame - > data , p_g_samples ) )
goto bfi ;
for ( i = 0 ; i < 160 ; i + + ) {
data [ i ] = audio_s16_to_law [ p_g_samples [ i ] & 0xffff ] ;
}
2013-03-14 08:58:31 +00:00
# endif
break ;
case GSM_TCHF_FRAME_EFR :
if ( p_g_media_type ! = MEDIA_TYPE_GSM_EFR ) {
PERROR ( " EFR frame, but current media type mismatches. \n " ) ;
return ;
}
if ( ! p_g_amr_decoder ) {
PERROR ( " EFR frame, but decoder not created. \n " ) ;
return ;
}
if ( ( frame - > data [ 0 ] > > 4 ) ! = 0xc )
goto bfi ;
# ifdef WITH_GSMAMR
/* decode */
gsm_efr_decode ( p_g_amr_decoder , frame - > data , p_g_samples ) ;
for ( i = 0 ; i < 160 ; i + + ) {
data [ i ] = audio_s16_to_law [ p_g_samples [ i ] & 0xffff ] ;
}
2013-03-26 07:57:58 +00:00
# endif
break ;
case GSM_TCH_FRAME_AMR :
if ( p_g_media_type ! = MEDIA_TYPE_AMR ) {
PERROR ( " AMR frame, but current media type mismatches. \n " ) ;
return ;
}
if ( ! p_g_amr_decoder ) {
PERROR ( " AMR frame, but decoder not created. \n " ) ;
return ;
}
cmr = ( frame - > data [ 1 ] > > 4 ) ;
if ( cmr < = 7 ) {
p_g_amr_cmr = cmr ;
p_g_amr_cmr_valid = 1 ;
}
if ( ! ( frame - > data [ 2 ] & 0x04 ) )
goto bfi ;
# ifdef WITH_GSMAMR
/* decode (skip length byte in front) */
gsm_amr_decode ( p_g_amr_decoder , frame - > data + 1 , p_g_samples ) ;
for ( i = 0 ; i < 160 ; i + + ) {
data [ i ] = audio_s16_to_law [ p_g_samples [ i ] & 0xffff ] ;
}
2013-03-09 17:15:33 +00:00
# endif
break ;
case GSM_BAD_FRAME :
default :
bfi :
if ( p_echotest ) {
/* beep on bad frame */
for ( i = 0 ; i < 160 ; i + + ) {
if ( ( i & 3 ) > 2 )
p_g_samples [ i ] = 15000 ;
else
p_g_samples [ i ] = - 15000 ;
data [ i ] = audio_s16_to_law [ p_g_samples [ i ] & 0xffff ] ;
}
} else {
/* repeat on bad frame */
for ( i = 0 ; i < 160 ; i + + ) {
p_g_samples [ i ] = ( p_g_samples [ i ] * 14 ) > > 4 ;
data [ i ] = audio_s16_to_law [ p_g_samples [ i ] & 0xffff ] ;
}
2012-01-20 19:28:55 +00:00
}
2009-05-11 09:07:58 +00:00
}
2012-08-21 08:34:15 +00:00
/* record data */
if ( p_record )
record ( data , 160 , 0 ) ; // from down
if ( p_tap )
tap ( data , 160 , 0 ) ; // from down
2012-01-20 19:28:55 +00:00
/* local echo */
if ( p_echotest )
bridge_rx ( data , 160 ) ;
2012-01-15 08:42:35 +00:00
/* send to remote*/
bridge_tx ( data , 160 ) ;
2009-05-11 09:07:58 +00:00
}
2012-01-15 08:42:35 +00:00
/* send traffic to gsm */
int Pgsm : : bridge_rx ( unsigned char * data , int len )
2012-01-21 16:50:45 +00:00
{
2012-12-23 05:45:43 +00:00
int ret ;
if ( ( ret = Port : : bridge_rx ( data , len ) ) )
return ret ;
2012-01-21 16:50:45 +00:00
if ( p_tone_name [ 0 ] )
return - EINVAL ;
return audio_send ( data , len ) ;
}
int Pgsm : : audio_send ( unsigned char * data , int len )
2009-05-11 09:07:58 +00:00
{
unsigned char frame [ 33 ] ;
2013-03-26 07:57:58 +00:00
int ret ;
2009-05-11 09:07:58 +00:00
2012-08-21 08:34:15 +00:00
/* record data */
if ( p_record )
record ( data , len , 1 ) ; // from up
if ( p_tap )
tap ( data , len , 1 ) ; // from up
2009-05-11 09:07:58 +00:00
/* encoder init failed */
2013-03-09 17:15:33 +00:00
if ( ! p_g_fr_encoder )
2012-01-15 08:42:35 +00:00
return - EINVAL ;
2009-05-11 09:07:58 +00:00
/* (currently) not connected, so don't flood tch! */
2012-01-15 08:42:35 +00:00
if ( ! p_g_tch_connected )
return - EINVAL ;
2009-05-11 09:07:58 +00:00
/* write to rx buffer */
while ( len - - ) {
2012-01-15 08:42:35 +00:00
p_g_rxdata [ p_g_rxpos + + ] = audio_law_to_s32 [ * data + + ] ;
2013-03-14 08:58:31 +00:00
if ( p_g_rxpos ! = 160 )
continue ;
p_g_rxpos = 0 ;
switch ( p_g_media_type ) {
2016-01-30 14:38:02 +00:00
case MEDIA_TYPE_ANALOG :
frame_send ( p_g_rxdata , 320 , ANALOG_8000HZ ) ;
break ;
2013-03-14 08:58:31 +00:00
case MEDIA_TYPE_GSM :
if ( ! p_g_fr_encoder ) {
PERROR ( " FR frame, but encoder not created. \n " ) ;
break ;
}
2013-03-09 17:15:33 +00:00
# ifdef WITH_GSMFR
2009-05-11 09:07:58 +00:00
/* encode data */
2013-03-09 17:15:33 +00:00
gsm_fr_encode ( p_g_fr_encoder , p_g_rxdata , frame ) ;
2013-03-14 08:58:31 +00:00
frame_send ( frame , 33 , GSM_TCHF_FRAME ) ;
2013-03-31 10:50:04 +00:00
# endif
break ;
case MEDIA_TYPE_GSM_HR :
if ( ! p_g_hr_encoder ) {
PERROR ( " HR frame, but encoder not created. \n " ) ;
break ;
}
# ifdef WITH_GSMHR
/* encode data */
gsm_hr_encode ( p_g_hr_encoder , p_g_rxdata , frame ) ;
frame_send ( frame , 15 , GSM_TCHH_FRAME ) ;
2013-03-09 17:15:33 +00:00
# endif
2013-03-14 08:58:31 +00:00
break ;
case MEDIA_TYPE_GSM_EFR :
if ( ! p_g_amr_encoder ) {
PERROR ( " EFR frame, but encoder not created. \n " ) ;
break ;
}
# ifdef WITH_GSMAMR
/* encode data */
gsm_efr_encode ( p_g_amr_encoder , p_g_rxdata , frame ) ;
frame_send ( frame , 31 , GSM_TCHF_FRAME_EFR ) ;
2013-03-26 07:57:58 +00:00
# endif
break ;
case MEDIA_TYPE_AMR :
if ( ! p_g_amr_encoder ) {
PERROR ( " AMR frame, but encoder not created. \n " ) ;
break ;
}
if ( ! p_g_amr_cmr_valid ) {
PDEBUG ( DEBUG_GSM , " no valid CMR yet. \n " ) ;
break ;
}
# ifdef WITH_GSMAMR
/* encode data (prefix a length byte) */
ret = gsm_amr_encode ( p_g_amr_encoder , p_g_rxdata , frame + 1 , p_g_amr_cmr ) ;
frame [ 0 ] = ret ;
frame_send ( frame , ret + 1 , GSM_TCH_FRAME_AMR ) ;
2013-03-14 08:58:31 +00:00
# endif
break ;
2009-05-11 09:07:58 +00:00
}
}
2012-01-15 08:42:35 +00:00
return 0 ;
2009-05-11 09:07:58 +00:00
}
2013-03-14 08:58:31 +00:00
void Pgsm : : frame_send ( void * _frame , int len , int msg_type )
2009-05-11 09:07:58 +00:00
{
2013-03-14 08:58:31 +00:00
unsigned char buffer [ sizeof ( struct gsm_data_frame ) + len ] ;
2009-12-20 17:55:03 +00:00
struct gsm_data_frame * frame = ( struct gsm_data_frame * ) buffer ;
2009-05-11 09:07:58 +00:00
2013-03-14 08:58:31 +00:00
frame - > msg_type = msg_type ;
2012-01-15 08:42:35 +00:00
frame - > callref = p_g_callref ;
2013-03-14 08:58:31 +00:00
memcpy ( frame - > data , _frame , len ) ;
2011-09-02 09:08:56 +00:00
2012-01-15 08:42:35 +00:00
if ( p_g_lcr_gsm ) {
mncc_send ( p_g_lcr_gsm , frame - > msg_type , frame ) ;
2009-05-11 09:07:58 +00:00
}
}
/*
* create trace
2011-02-20 16:34:24 +00:00
*/
2012-01-15 08:42:35 +00:00
void gsm_trace_header ( const char * interface_name , class Pgsm * port , unsigned int msg_type , int direction )
2009-05-11 09:07:58 +00:00
{
char msgtext [ 64 ] ;
2012-01-15 08:42:35 +00:00
struct interface * interface = interface_first ;
2012-01-20 09:05:41 +00:00
interface = getinterfacebyname ( interface_name ) ;
2012-01-15 08:42:35 +00:00
if ( ! interface )
return ;
2009-05-11 09:07:58 +00:00
/* select message and primitive text */
2011-02-20 16:34:24 +00:00
SCPY ( msgtext , mncc_name ( msg_type ) ) ;
2009-05-11 09:07:58 +00:00
/* add direction */
2010-07-21 10:12:23 +00:00
if ( port ) {
switch ( port - > p_type ) {
case PORT_TYPE_GSM_BS_OUT :
case PORT_TYPE_GSM_BS_IN :
2011-08-10 19:51:46 +00:00
SCAT ( msgtext , " LCR<->BSC " ) ;
2010-07-21 10:12:23 +00:00
break ;
case PORT_TYPE_GSM_MS_OUT :
case PORT_TYPE_GSM_MS_IN :
2011-08-10 19:51:46 +00:00
SCAT ( msgtext , " LCR<->MS " ) ;
2010-07-21 10:12:23 +00:00
break ;
}
} else
SCAT ( msgtext , " ---- " ) ;
2009-05-11 09:07:58 +00:00
/* init trace with given values */
2012-02-01 16:52:36 +00:00
start_trace ( - 1 ,
2012-01-15 08:42:35 +00:00
interface ,
2009-05-11 09:07:58 +00:00
port ? numberrize_callerinfo ( port - > p_callerinfo . id , port - > p_callerinfo . ntype , options . national , options . international ) : NULL ,
port ? port - > p_dialinginfo . id : NULL ,
direction ,
CATEGORY_CH ,
port ? port - > p_serial : 0 ,
msgtext ) ;
}
2012-02-01 16:52:36 +00:00
/* modify lchan to given payload type */
2012-02-17 14:38:54 +00:00
void Pgsm : : modify_lchan ( int media_type )
2009-05-11 09:07:58 +00:00
{
struct gsm_mncc * mode ;
2013-03-14 08:58:31 +00:00
/* already modified to that media type */
2012-02-17 14:38:54 +00:00
if ( p_g_media_type = = media_type )
2012-02-01 16:52:36 +00:00
return ;
2009-05-11 09:07:58 +00:00
2012-02-17 14:38:54 +00:00
p_g_media_type = media_type ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_LCHAN_MODIFY , DIRECTION_OUT ) ;
2012-01-15 08:42:35 +00:00
mode = create_mncc ( MNCC_LCHAN_MODIFY , p_g_callref ) ;
2012-02-17 14:38:54 +00:00
switch ( media_type ) {
case MEDIA_TYPE_GSM_EFR :
2012-02-01 16:52:36 +00:00
add_trace ( " speech " , " version " , " EFR given " ) ;
mode - > lchan_mode = 0x21 ; /* GSM V2 */
break ;
2012-02-17 14:38:54 +00:00
case MEDIA_TYPE_AMR :
2012-02-01 16:52:36 +00:00
add_trace ( " speech " , " version " , " AMR given " ) ;
mode - > lchan_mode = 0x41 ; /* GSM V3 */
break ;
default :
2012-03-08 13:44:17 +00:00
add_trace ( " speech " , " version " , " Full/Half Rate given " ) ;
2012-02-17 14:38:54 +00:00
mode - > lchan_mode = 0x01 ; /* GSM V1 */
2012-02-01 16:52:36 +00:00
}
mode - > lchan_type = 0x02 ; /* FIXME: unused */
2009-05-11 09:07:58 +00:00
add_trace ( " mode " , NULL , " 0x%02x " , mode - > lchan_mode ) ;
2009-05-14 18:31:43 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
send_and_free_mncc ( p_g_lcr_gsm , mode - > msg_type , mode ) ;
2009-05-11 09:07:58 +00:00
}
2012-02-01 16:52:36 +00:00
/* CALL PROCEEDING INDICATION (from network) */
2010-10-31 16:12:26 +00:00
void Pgsm : : call_proc_ind ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
struct lcr_msg * message ;
struct gsm_mncc * frame ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , msg_type , DIRECTION_IN ) ;
2010-10-31 16:12:26 +00:00
end_trace ( ) ;
message = message_create ( p_serial , ACTIVE_EPOINT ( p_epointlist ) , PORT_TO_EPOINT , MESSAGE_PROCEEDING ) ;
message_put ( message ) ;
new_state ( PORT_STATE_OUT_PROCEEDING ) ;
2012-01-15 08:42:35 +00:00
if ( p_g_earlyb & & ! p_g_tch_connected ) { /* only if ... */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_FRAME_RECV , DIRECTION_OUT ) ;
2010-10-31 16:12:26 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
frame = create_mncc ( MNCC_FRAME_RECV , p_g_callref ) ;
send_and_free_mncc ( p_g_lcr_gsm , frame - > msg_type , frame ) ;
p_g_tch_connected = 1 ;
2010-10-31 16:12:26 +00:00
}
2013-03-14 08:58:31 +00:00
/* modify to GSM FR (this is GSM user side only, so there is FR supported only) */
modify_lchan ( MEDIA_TYPE_GSM ) ;
2010-10-31 16:12:26 +00:00
}
2009-05-11 09:07:58 +00:00
/* ALERTING INDICATION */
void Pgsm : : alert_ind ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
struct lcr_msg * message ;
2010-10-31 16:12:26 +00:00
struct gsm_mncc * frame ;
2009-05-11 09:07:58 +00:00
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , msg_type , DIRECTION_IN ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
message = message_create ( p_serial , ACTIVE_EPOINT ( p_epointlist ) , PORT_TO_EPOINT , MESSAGE_ALERTING ) ;
message_put ( message ) ;
new_state ( PORT_STATE_OUT_ALERTING ) ;
2012-01-15 08:42:35 +00:00
if ( p_g_earlyb & & ! p_g_tch_connected ) { /* only if ... */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_FRAME_RECV , DIRECTION_OUT ) ;
2010-10-31 16:12:26 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
frame = create_mncc ( MNCC_FRAME_RECV , p_g_callref ) ;
send_and_free_mncc ( p_g_lcr_gsm , frame - > msg_type , frame ) ;
p_g_tch_connected = 1 ;
2010-10-31 16:12:26 +00:00
}
2013-03-14 08:58:31 +00:00
/* modify to GSM FR, if not already */
if ( ! p_g_media_type ) {
modify_lchan ( MEDIA_TYPE_GSM ) ;
}
2009-05-11 09:07:58 +00:00
}
/* CONNECT INDICATION */
void Pgsm : : setup_cnf ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
struct gsm_mncc * resp , * frame ;
struct lcr_msg * message ;
2009-06-18 08:06:31 +00:00
SCPY ( p_connectinfo . id , mncc - > connected . number ) ;
2009-06-06 21:46:21 +00:00
SCPY ( p_connectinfo . imsi , mncc - > imsi ) ;
p_connectinfo . present = INFO_PRESENT_ALLOWED ;
p_connectinfo . screen = INFO_SCREEN_NETWORK ;
2017-06-04 09:22:51 +00:00
switch ( mncc - > connected . type ) {
case 0x1 :
p_connectinfo . ntype = INFO_NTYPE_INTERNATIONAL ;
break ;
case 0x2 :
p_connectinfo . ntype = INFO_NTYPE_NATIONAL ;
break ;
case 0x4 :
p_connectinfo . ntype = INFO_NTYPE_SUBSCRIBER ;
break ;
default :
p_connectinfo . ntype = INFO_NTYPE_UNKNOWN ;
break ;
}
2012-08-19 07:42:43 +00:00
SCPY ( p_connectinfo . interface , p_interface_name ) ;
2009-06-18 08:06:31 +00:00
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , msg_type , DIRECTION_IN ) ;
2009-06-06 21:46:21 +00:00
if ( p_connectinfo . id [ 0 ] )
add_trace ( " connect " , " number " , " %s " , p_connectinfo . id ) ;
2009-06-18 08:06:31 +00:00
else if ( mncc - > imsi [ 0 ] )
2009-06-06 21:46:21 +00:00
SPRINT ( p_connectinfo . id , " imsi-%s " , p_connectinfo . imsi ) ;
2009-06-18 08:06:31 +00:00
if ( mncc - > imsi [ 0 ] )
add_trace ( " connect " , " imsi " , " %s " , p_connectinfo . imsi ) ;
end_trace ( ) ;
/* send resp */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_SETUP_COMPL_REQ , DIRECTION_OUT ) ;
2012-01-15 08:42:35 +00:00
resp = create_mncc ( MNCC_SETUP_COMPL_REQ , p_g_callref ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
send_and_free_mncc ( p_g_lcr_gsm , resp - > msg_type , resp ) ;
2009-05-11 09:07:58 +00:00
new_state ( PORT_STATE_CONNECT ) ;
2012-01-15 08:42:35 +00:00
if ( ! p_g_tch_connected ) { /* only if ... */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_FRAME_RECV , DIRECTION_OUT ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
frame = create_mncc ( MNCC_FRAME_RECV , p_g_callref ) ;
send_and_free_mncc ( p_g_lcr_gsm , frame - > msg_type , frame ) ;
p_g_tch_connected = 1 ;
2009-05-11 09:07:58 +00:00
}
2012-01-15 08:42:35 +00:00
message = message_create ( p_serial , ACTIVE_EPOINT ( p_epointlist ) , PORT_TO_EPOINT , MESSAGE_CONNECT ) ;
memcpy ( & message - > param . connectinfo , & p_connectinfo , sizeof ( struct connect_info ) ) ;
2012-02-01 16:52:36 +00:00
/* if we have a bridge, but not yet modified, the phone accepts out requested payload.
* we force the first in list */
if ( p_g_rtp_bridge ) {
2012-02-17 14:38:54 +00:00
if ( ! p_g_media_type ) {
/* modify to first given type */
modify_lchan ( p_g_rtp_media_types [ 0 ] ) ;
/* also set payload type */
p_g_payload_type = p_g_rtp_payload_types [ 0 ] ;
2012-02-01 16:52:36 +00:00
}
2012-02-17 14:38:54 +00:00
message - > param . connectinfo . rtpinfo . media_types [ 0 ] = p_g_media_type ;
2012-02-01 16:52:36 +00:00
message - > param . connectinfo . rtpinfo . payload_types [ 0 ] = p_g_payload_type ;
message - > param . connectinfo . rtpinfo . payloads = 1 ;
2013-03-14 08:58:31 +00:00
} else {
/* modify to GSM FR, if not already
* for network side , this should have been already happened */
if ( ! p_g_media_type )
modify_lchan ( MEDIA_TYPE_GSM ) ;
2012-02-01 16:52:36 +00:00
}
2012-01-15 08:42:35 +00:00
2013-03-14 08:58:31 +00:00
2012-01-15 08:42:35 +00:00
if ( p_g_rtp_bridge ) {
struct gsm_mncc_rtp * rtp ;
PDEBUG ( DEBUG_GSM , " Request RTP peer info, before forwarding connect msg \n " ) ;
p_g_connect_pending = message ;
rtp = ( struct gsm_mncc_rtp * ) create_mncc ( MNCC_RTP_CREATE , p_g_callref ) ;
send_and_free_mncc ( p_g_lcr_gsm , rtp - > msg_type , rtp ) ;
} else
message_put ( message ) ;
2009-05-11 09:07:58 +00:00
}
/* CONNECT ACK INDICATION */
void Pgsm : : setup_compl_ind ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
struct gsm_mncc * frame ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , msg_type , DIRECTION_IN ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
new_state ( PORT_STATE_CONNECT ) ;
2012-01-15 08:42:35 +00:00
if ( ! p_g_tch_connected ) { /* only if ... */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_FRAME_RECV , DIRECTION_OUT ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
frame = create_mncc ( MNCC_FRAME_RECV , p_g_callref ) ;
send_and_free_mncc ( p_g_lcr_gsm , frame - > msg_type , frame ) ;
p_g_tch_connected = 1 ;
2009-05-11 09:07:58 +00:00
}
2013-03-31 10:50:04 +00:00
/* modify to GSM FR, if not already */
if ( ! p_g_media_type ) {
modify_lchan ( MEDIA_TYPE_GSM ) ;
}
2009-05-11 09:07:58 +00:00
}
/* DISCONNECT INDICATION */
void Pgsm : : disc_ind ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
struct lcr_msg * message ;
int cause = 16 , location = 0 ;
struct gsm_mncc * resp ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , msg_type , DIRECTION_IN ) ;
2009-06-18 08:06:31 +00:00
if ( mncc - > fields & MNCC_F_CAUSE ) {
location = mncc - > cause . location ;
cause = mncc - > cause . value ;
add_trace ( " cause " , " coding " , " %d " , mncc - > cause . coding ) ;
2009-05-11 09:07:58 +00:00
add_trace ( " cause " , " location " , " %d " , location ) ;
add_trace ( " cause " , " value " , " %d " , cause ) ;
}
end_trace ( ) ;
/* send release */
2012-01-15 08:42:35 +00:00
resp = create_mncc ( MNCC_REL_REQ , p_g_callref ) ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_REL_REQ , DIRECTION_OUT ) ;
2009-05-17 14:06:26 +00:00
#if 0
2009-06-18 08:06:31 +00:00
resp - > fields | = MNCC_F_CAUSE ;
resp - > cause . coding = 3 ;
resp - > cause . location = 1 ;
resp - > cause . value = cause ;
add_trace ( " cause " , " coding " , " %d " , resp - > cause . coding ) ;
add_trace ( " cause " , " location " , " %d " , resp - > cause . location ) ;
add_trace ( " cause " , " value " , " %d " , resp - > cause . value ) ;
2009-05-17 14:06:26 +00:00
# endif
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
send_and_free_mncc ( p_g_lcr_gsm , resp - > msg_type , resp ) ;
2009-05-11 09:07:58 +00:00
/* sending release to endpoint */
while ( p_epointlist ) {
message = message_create ( p_serial , p_epointlist - > epoint_id , PORT_TO_EPOINT , MESSAGE_RELEASE ) ;
message - > param . disconnectinfo . cause = cause ;
message - > param . disconnectinfo . location = location ;
message_put ( message ) ;
/* remove epoint */
free_epointlist ( p_epointlist ) ;
}
new_state ( PORT_STATE_RELEASE ) ;
2012-01-15 08:42:35 +00:00
trigger_work ( & p_g_delete ) ;
2009-05-11 09:07:58 +00:00
}
/* CC_RELEASE INDICATION */
void Pgsm : : rel_ind ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
int location = 0 , cause = 16 ;
struct lcr_msg * message ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , msg_type , DIRECTION_IN ) ;
2009-06-18 08:06:31 +00:00
if ( mncc - > fields & MNCC_F_CAUSE ) {
location = mncc - > cause . location ;
cause = mncc - > cause . value ;
add_trace ( " cause " , " coding " , " %d " , mncc - > cause . coding ) ;
add_trace ( " cause " , " location " , " %d " , mncc - > cause . location ) ;
add_trace ( " cause " , " value " , " %d " , mncc - > cause . value ) ;
2009-05-11 09:07:58 +00:00
}
end_trace ( ) ;
/* sending release to endpoint */
while ( p_epointlist ) {
message = message_create ( p_serial , p_epointlist - > epoint_id , PORT_TO_EPOINT , MESSAGE_RELEASE ) ;
message - > param . disconnectinfo . cause = cause ;
message - > param . disconnectinfo . location = location ;
message_put ( message ) ;
/* remove epoint */
free_epointlist ( p_epointlist ) ;
}
new_state ( PORT_STATE_RELEASE ) ;
2012-01-15 08:42:35 +00:00
trigger_work ( & p_g_delete ) ;
2009-05-11 09:07:58 +00:00
}
/* NOTIFY INDICATION */
void Pgsm : : notify_ind ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
2010-01-04 18:19:12 +00:00
struct lcr_msg * message ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , msg_type , DIRECTION_IN ) ;
2010-01-04 18:19:12 +00:00
add_trace ( " notify " , NULL , " %d " , mncc - > notify ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
2010-01-04 18:19:12 +00:00
message = message_create ( p_serial , ACTIVE_EPOINT ( p_epointlist ) , PORT_TO_EPOINT , MESSAGE_NOTIFY ) ;
message - > param . notifyinfo . notify = mncc - > notify ;
message_put ( message ) ;
2009-05-11 09:07:58 +00:00
}
/* MESSAGE_NOTIFY */
void Pgsm : : message_notify ( unsigned int epoint_id , int message_id , union parameter * param )
{
struct gsm_mncc * mncc ;
int notify ;
2009-09-06 13:36:36 +00:00
// printf("if = %d\n", param->notifyinfo.notify);
2009-05-11 09:07:58 +00:00
if ( param - > notifyinfo . notify > INFO_NOTIFY_NONE ) {
notify = param - > notifyinfo . notify & 0x7f ;
if ( p_state ! = PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ & & p_state ! = PORT_STATE_IN_ALERTING ) {
/* queue notification */
2012-01-15 08:42:35 +00:00
if ( p_g_notify_pending )
message_free ( p_g_notify_pending ) ;
p_g_notify_pending = message_create ( ACTIVE_EPOINT ( p_epointlist ) , p_serial , EPOINT_TO_PORT , message_id ) ;
memcpy ( & p_g_notify_pending - > param , param , sizeof ( union parameter ) ) ;
2009-05-11 09:07:58 +00:00
} else {
/* sending notification */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_NOTIFY_REQ , DIRECTION_OUT ) ;
2009-05-11 09:07:58 +00:00
add_trace ( " notify " , NULL , " %d " , notify ) ;
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
mncc = create_mncc ( MNCC_NOTIFY_REQ , p_g_callref ) ;
2009-05-11 09:07:58 +00:00
mncc - > notify = notify ;
2012-01-15 08:42:35 +00:00
send_and_free_mncc ( p_g_lcr_gsm , mncc - > msg_type , mncc ) ;
2009-05-11 09:07:58 +00:00
}
}
}
2012-01-15 08:42:35 +00:00
/* RTP create indication */
void Pgsm : : rtp_create_ind ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
struct gsm_mncc_rtp * rtp = ( struct gsm_mncc_rtp * ) mncc ;
/* send queued setup, as we received remote RTP info */
if ( p_g_setup_pending ) {
struct lcr_msg * message ;
message = p_g_setup_pending ;
PDEBUG ( DEBUG_GSM , " Got RTP peer info (%08x,%d) forwarding setup \n " , rtp - > ip , rtp - > port ) ;
message - > param . setup . rtpinfo . ip = rtp - > ip ;
message - > param . setup . rtpinfo . port = rtp - > port ;
message_put ( message ) ;
p_g_setup_pending = NULL ;
}
if ( p_g_connect_pending ) {
PDEBUG ( DEBUG_GSM , " Got RTP peer info (%08x,%d) connecting RTP... \n " , rtp - > ip , rtp - > port ) ;
2012-02-17 14:38:54 +00:00
send_mncc_rtp_connect ( ) ;
2012-01-15 08:42:35 +00:00
}
}
/* RTP connect indication */
void Pgsm : : rtp_connect_ind ( unsigned int msg_type , unsigned int callref , struct gsm_mncc * mncc )
{
struct lcr_msg * message ;
struct gsm_mncc_rtp * rtp = ( struct gsm_mncc_rtp * ) mncc ;
if ( p_g_connect_pending ) {
message = p_g_connect_pending ;
PDEBUG ( DEBUG_GSM , " Got RTP peer info (%08x,%d) forwarding connect \n " , rtp - > ip , rtp - > port ) ;
message - > param . connectinfo . rtpinfo . ip = rtp - > ip ;
message - > param . connectinfo . rtpinfo . port = rtp - > port ;
message_put ( message ) ;
p_g_connect_pending = NULL ;
}
}
/* MESSAGE_PROGRESS */
void Pgsm : : message_progress ( unsigned int epoint_id , int message_id , union parameter * param )
{
if ( param - > progressinfo . progress = = 8 ) {
PDEBUG ( DEBUG_GSM , " Remote provides tones for us \n " ) ;
p_g_tones = 1 ;
}
if ( param - > progressinfo . rtpinfo . port ) {
2012-02-17 14:38:54 +00:00
PDEBUG ( DEBUG_GSM , " PROGRESS with RTP peer info, sent to BSC (%08x,%d) with media %d, pt %d \n " , param - > progressinfo . rtpinfo . ip , param - > progressinfo . rtpinfo . port , param - > progressinfo . rtpinfo . media_types [ 0 ] , param - > progressinfo . rtpinfo . payload_types [ 0 ] ) ;
2012-01-15 08:42:35 +00:00
2012-02-17 14:38:54 +00:00
/* modify channel to givne type, also sets media type */
modify_lchan ( param - > progressinfo . rtpinfo . media_types [ 0 ] ) ;
2012-02-01 16:52:36 +00:00
2012-02-17 14:38:54 +00:00
/* connect RTP */
p_g_rtp_ip_remote = param - > progressinfo . rtpinfo . ip ;
p_g_rtp_port_remote = param - > progressinfo . rtpinfo . port ;
/* p_g_media_type is already set by modify_lchan() */
p_g_payload_type = param - > progressinfo . rtpinfo . payload_types [ 0 ] ;
send_mncc_rtp_connect ( ) ;
2012-01-15 08:42:35 +00:00
}
}
2009-05-11 09:07:58 +00:00
/* MESSAGE_ALERTING */
void Pgsm : : message_alerting ( unsigned int epoint_id , int message_id , union parameter * param )
{
struct gsm_mncc * mncc ;
/* send alert */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_ALERT_REQ , DIRECTION_OUT ) ;
2012-01-15 08:42:35 +00:00
mncc = create_mncc ( MNCC_ALERT_REQ , p_g_callref ) ;
if ( p_g_tones ) {
2009-06-18 08:06:31 +00:00
mncc - > fields | = MNCC_F_PROGRESS ;
mncc - > progress . coding = 3 ; /* GSM */
mncc - > progress . location = 1 ;
mncc - > progress . descr = 8 ;
add_trace ( " progress " , " coding " , " %d " , mncc - > progress . coding ) ;
add_trace ( " progress " , " location " , " %d " , mncc - > progress . location ) ;
add_trace ( " progress " , " descr " , " %d " , mncc - > progress . descr ) ;
2009-05-11 09:07:58 +00:00
}
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
send_and_free_mncc ( p_g_lcr_gsm , mncc - > msg_type , mncc ) ;
2009-05-11 09:07:58 +00:00
new_state ( PORT_STATE_IN_ALERTING ) ;
2012-01-15 08:42:35 +00:00
if ( p_g_tones & & ! p_g_tch_connected ) { /* only if ... */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_FRAME_RECV , DIRECTION_OUT ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
mncc = create_mncc ( MNCC_FRAME_RECV , p_g_callref ) ;
send_and_free_mncc ( p_g_lcr_gsm , mncc - > msg_type , mncc ) ;
p_g_tch_connected = 1 ;
2009-05-11 09:07:58 +00:00
}
2013-03-31 10:50:04 +00:00
/* modify to GSM FR, if not already */
if ( ! p_g_media_type ) {
modify_lchan ( MEDIA_TYPE_GSM ) ;
}
2009-05-11 09:07:58 +00:00
}
/* MESSAGE_CONNECT */
void Pgsm : : message_connect ( unsigned int epoint_id , int message_id , union parameter * param )
{
struct gsm_mncc * mncc ;
/* copy connected information */
memcpy ( & p_connectinfo , & param - > connectinfo , sizeof ( p_connectinfo ) ) ;
/* screen outgoing caller id */
2012-08-19 07:42:43 +00:00
do_screen ( 1 , p_connectinfo . id , sizeof ( p_connectinfo . id ) , & p_connectinfo . ntype , & p_connectinfo . present , p_interface_name ) ;
2009-05-11 09:07:58 +00:00
/* send connect */
2012-01-15 08:42:35 +00:00
mncc = create_mncc ( MNCC_SETUP_RSP , p_g_callref ) ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_SETUP_RSP , DIRECTION_OUT ) ;
2009-05-11 09:07:58 +00:00
/* caller information */
2009-06-18 08:06:31 +00:00
mncc - > fields | = MNCC_F_CONNECTED ;
mncc - > connected . plan = 1 ;
2009-05-11 09:07:58 +00:00
switch ( p_callerinfo . ntype ) {
case INFO_NTYPE_UNKNOWN :
2009-06-18 08:06:31 +00:00
mncc - > connected . type = 0x0 ;
2009-05-11 09:07:58 +00:00
break ;
case INFO_NTYPE_INTERNATIONAL :
2009-06-18 08:06:31 +00:00
mncc - > connected . type = 0x1 ;
2009-05-11 09:07:58 +00:00
break ;
case INFO_NTYPE_NATIONAL :
2009-06-18 08:06:31 +00:00
mncc - > connected . type = 0x2 ;
2009-05-11 09:07:58 +00:00
break ;
case INFO_NTYPE_SUBSCRIBER :
2009-06-18 08:06:31 +00:00
mncc - > connected . type = 0x4 ;
2009-05-11 09:07:58 +00:00
break ;
default : /* INFO_NTYPE_NOTPRESENT */
2009-06-18 08:06:31 +00:00
mncc - > fields & = ~ MNCC_F_CONNECTED ;
2009-05-11 09:07:58 +00:00
break ;
}
switch ( p_callerinfo . screen ) {
case INFO_SCREEN_USER :
2009-06-18 08:06:31 +00:00
mncc - > connected . screen = 0 ;
2009-05-11 09:07:58 +00:00
break ;
default : /* INFO_SCREEN_NETWORK */
2009-06-18 08:06:31 +00:00
mncc - > connected . screen = 3 ;
2009-05-11 09:07:58 +00:00
break ;
}
switch ( p_callerinfo . present ) {
case INFO_PRESENT_ALLOWED :
2009-06-18 08:06:31 +00:00
mncc - > connected . present = 0 ;
2009-05-11 09:07:58 +00:00
break ;
case INFO_PRESENT_RESTRICTED :
2009-06-18 08:06:31 +00:00
mncc - > connected . present = 1 ;
2009-05-11 09:07:58 +00:00
break ;
default : /* INFO_PRESENT_NOTAVAIL */
2009-06-18 08:06:31 +00:00
mncc - > connected . present = 2 ;
2009-05-11 09:07:58 +00:00
break ;
}
2009-06-18 08:06:31 +00:00
if ( mncc - > fields & MNCC_F_CONNECTED ) {
SCPY ( mncc - > connected . number , p_connectinfo . id ) ;
add_trace ( " connected " , " type " , " %d " , mncc - > connected . type ) ;
add_trace ( " connected " , " plan " , " %d " , mncc - > connected . plan ) ;
add_trace ( " connected " , " present " , " %d " , mncc - > connected . present ) ;
add_trace ( " connected " , " screen " , " %d " , mncc - > connected . screen ) ;
add_trace ( " connected " , " number " , " %s " , mncc - > connected . number ) ;
2009-05-11 09:07:58 +00:00
}
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
send_and_free_mncc ( p_g_lcr_gsm , mncc - > msg_type , mncc ) ;
2009-05-11 09:07:58 +00:00
new_state ( PORT_STATE_CONNECT_WAITING ) ;
2012-01-15 08:42:35 +00:00
if ( param - > connectinfo . rtpinfo . port ) {
PDEBUG ( DEBUG_GSM , " CONNECT with RTP peer info, sent to BSC (%08x,%d) \n " , param - > connectinfo . rtpinfo . ip , param - > connectinfo . rtpinfo . port ) ;
2012-02-17 14:38:54 +00:00
/* modify channel to givne type, also sets media type */
modify_lchan ( param - > connectinfo . rtpinfo . media_types [ 0 ] ) ;
/* connect RTP */
p_g_rtp_ip_remote = param - > connectinfo . rtpinfo . ip ;
p_g_rtp_port_remote = param - > connectinfo . rtpinfo . port ;
/* p_g_media_type is already set by modify_lchan() */
p_g_payload_type = param - > connectinfo . rtpinfo . payload_types [ 0 ] ;
send_mncc_rtp_connect ( ) ;
2012-02-01 16:52:36 +00:00
}
2009-05-11 09:07:58 +00:00
}
/* MESSAGE_DISCONNECT */
void Pgsm : : message_disconnect ( unsigned int epoint_id , int message_id , union parameter * param )
{
struct gsm_mncc * mncc ;
/* send disconnect */
2012-01-15 08:42:35 +00:00
mncc = create_mncc ( MNCC_DISC_REQ , p_g_callref ) ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_DISC_REQ , DIRECTION_OUT ) ;
2012-01-15 08:42:35 +00:00
if ( p_g_tones ) {
2009-06-18 08:06:31 +00:00
mncc - > fields | = MNCC_F_PROGRESS ;
mncc - > progress . coding = 3 ; /* GSM */
mncc - > progress . location = 1 ;
mncc - > progress . descr = 8 ;
add_trace ( " progress " , " coding " , " %d " , mncc - > progress . coding ) ;
add_trace ( " progress " , " location " , " %d " , mncc - > progress . location ) ;
add_trace ( " progress " , " descr " , " %d " , mncc - > progress . descr ) ;
2009-05-11 09:07:58 +00:00
}
2009-06-18 08:06:31 +00:00
mncc - > fields | = MNCC_F_CAUSE ;
mncc - > cause . coding = 3 ;
mncc - > cause . location = param - > disconnectinfo . location ;
mncc - > cause . value = param - > disconnectinfo . cause ;
add_trace ( " cause " , " coding " , " %d " , mncc - > cause . coding ) ;
add_trace ( " cause " , " location " , " %d " , mncc - > cause . location ) ;
add_trace ( " cause " , " value " , " %d " , mncc - > cause . value ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
send_and_free_mncc ( p_g_lcr_gsm , mncc - > msg_type , mncc ) ;
2009-05-11 09:07:58 +00:00
new_state ( PORT_STATE_OUT_DISCONNECT ) ;
2012-01-15 08:42:35 +00:00
if ( p_g_tones & & ! p_g_tch_connected ) { /* only if ... */
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_FRAME_RECV , DIRECTION_OUT ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
mncc = create_mncc ( MNCC_FRAME_RECV , p_g_callref ) ;
send_and_free_mncc ( p_g_lcr_gsm , mncc - > msg_type , mncc ) ;
p_g_tch_connected = 1 ;
2009-05-11 09:07:58 +00:00
}
}
/* MESSAGE_RELEASE */
void Pgsm : : message_release ( unsigned int epoint_id , int message_id , union parameter * param )
{
struct gsm_mncc * mncc ;
/* send release */
2012-01-15 08:42:35 +00:00
mncc = create_mncc ( MNCC_REL_REQ , p_g_callref ) ;
2012-08-19 07:42:43 +00:00
gsm_trace_header ( p_interface_name , this , MNCC_REL_REQ , DIRECTION_OUT ) ;
2009-06-18 08:06:31 +00:00
mncc - > fields | = MNCC_F_CAUSE ;
mncc - > cause . coding = 3 ;
mncc - > cause . location = param - > disconnectinfo . location ;
mncc - > cause . value = param - > disconnectinfo . cause ;
add_trace ( " cause " , " coding " , " %d " , mncc - > cause . coding ) ;
add_trace ( " cause " , " location " , " %d " , mncc - > cause . location ) ;
add_trace ( " cause " , " value " , " %d " , mncc - > cause . value ) ;
2009-05-11 09:07:58 +00:00
end_trace ( ) ;
2012-01-15 08:42:35 +00:00
send_and_free_mncc ( p_g_lcr_gsm , mncc - > msg_type , mncc ) ;
2009-05-11 09:07:58 +00:00
new_state ( PORT_STATE_RELEASE ) ;
2012-01-15 08:42:35 +00:00
trigger_work ( & p_g_delete ) ;
2009-05-11 09:07:58 +00:00
return ;
}
/*
* endpoint sends messages to the port
*/
int Pgsm : : message_epoint ( unsigned int epoint_id , int message_id , union parameter * param )
{
2012-01-15 08:42:35 +00:00
int ret = 0 ;
if ( Port : : message_epoint ( epoint_id , message_id , param ) )
return 1 ;
2009-05-11 09:07:58 +00:00
switch ( message_id ) {
case MESSAGE_NOTIFY : /* display and notifications */
2012-01-15 08:42:35 +00:00
ret = 1 ;
2009-05-11 09:07:58 +00:00
message_notify ( epoint_id , message_id , param ) ;
break ;
// case MESSAGE_FACILITY: /* facility message */
// message_facility(epoint_id, message_id, param);
// break;
case MESSAGE_PROCEEDING : /* message not handles */
2012-01-15 08:42:35 +00:00
ret = 1 ;
break ;
case MESSAGE_PROGRESS :
ret = 1 ;
message_progress ( epoint_id , message_id , param ) ;
2009-05-11 09:07:58 +00:00
break ;
case MESSAGE_ALERTING : /* call of endpoint is ringing */
2012-01-15 08:42:35 +00:00
ret = 1 ;
2009-05-11 09:07:58 +00:00
if ( p_state ! = PORT_STATE_IN_PROCEEDING )
break ;
message_alerting ( epoint_id , message_id , param ) ;
2012-01-15 08:42:35 +00:00
if ( p_g_notify_pending ) {
2009-05-11 09:07:58 +00:00
/* send pending notify message during connect */
2012-01-15 08:42:35 +00:00
message_notify ( ACTIVE_EPOINT ( p_epointlist ) , p_g_notify_pending - > type , & p_g_notify_pending - > param ) ;
message_free ( p_g_notify_pending ) ;
p_g_notify_pending = NULL ;
2009-05-11 09:07:58 +00:00
}
break ;
case MESSAGE_CONNECT : /* call of endpoint is connected */
2012-01-15 08:42:35 +00:00
ret = 1 ;
2009-05-11 09:07:58 +00:00
if ( p_state ! = PORT_STATE_IN_PROCEEDING
& & p_state ! = PORT_STATE_IN_ALERTING )
break ;
message_connect ( epoint_id , message_id , param ) ;
2012-01-15 08:42:35 +00:00
if ( p_g_notify_pending ) {
2009-05-11 09:07:58 +00:00
/* send pending notify message during connect */
2012-01-15 08:42:35 +00:00
message_notify ( ACTIVE_EPOINT ( p_epointlist ) , p_g_notify_pending - > type , & p_g_notify_pending - > param ) ;
message_free ( p_g_notify_pending ) ;
p_g_notify_pending = NULL ;
2009-05-11 09:07:58 +00:00
}
break ;
case MESSAGE_DISCONNECT : /* call has been disconnected */
2012-01-15 08:42:35 +00:00
ret = 1 ;
2009-05-11 09:07:58 +00:00
if ( p_state ! = PORT_STATE_IN_PROCEEDING
& & p_state ! = PORT_STATE_IN_ALERTING
& & p_state ! = PORT_STATE_OUT_SETUP
& & p_state ! = PORT_STATE_OUT_OVERLAP
& & p_state ! = PORT_STATE_OUT_PROCEEDING
& & p_state ! = PORT_STATE_OUT_ALERTING
& & p_state ! = PORT_STATE_CONNECT
& & p_state ! = PORT_STATE_CONNECT_WAITING )
break ;
message_disconnect ( epoint_id , message_id , param ) ;
break ;
case MESSAGE_RELEASE : /* release isdn port */
2012-01-15 08:42:35 +00:00
ret = 1 ;
2009-05-11 09:07:58 +00:00
if ( p_state = = PORT_STATE_RELEASE )
break ;
message_release ( epoint_id , message_id , param ) ;
break ;
}
2012-01-15 08:42:35 +00:00
return ret ;
2009-05-11 09:07:58 +00:00
}
2010-01-16 10:20:23 +00:00
/* deletes only if l3id is release, otherwhise it will be triggered then */
static int delete_event ( struct lcr_work * work , void * instance , int index )
{
class Pgsm * gsmport = ( class Pgsm * ) instance ;
delete gsmport ;
return 0 ;
}
2009-05-11 09:07:58 +00:00
int gsm_exit ( int rc )
{
return ( rc ) ;
}
int gsm_init ( void )
{
2009-08-23 12:58:21 +00:00
/* seed the PRNG */
srand ( time ( NULL ) ) ;
2009-05-11 09:07:58 +00:00
2011-09-02 09:08:56 +00:00
return 0 ;
}
/*
* MNCC interface
*/
static int mncc_q_enqueue ( struct lcr_gsm * lcr_gsm , struct gsm_mncc * mncc , unsigned int len )
{
struct mncc_q_entry * qe ;
qe = ( struct mncc_q_entry * ) MALLOC ( sizeof ( * qe ) + sizeof ( * mncc ) + len ) ;
if ( ! qe )
return - ENOMEM ;
qe - > next = NULL ;
qe - > len = len ;
memcpy ( qe - > data , mncc , len ) ;
/* in case of empty list ... */
if ( ! lcr_gsm - > mncc_q_hd & & ! lcr_gsm - > mncc_q_tail ) {
/* the list head and tail both point to the new qe */
lcr_gsm - > mncc_q_hd = lcr_gsm - > mncc_q_tail = qe ;
} else {
/* append to tail of list */
lcr_gsm - > mncc_q_tail - > next = qe ;
lcr_gsm - > mncc_q_tail = qe ;
}
lcr_gsm - > mncc_lfd . when | = LCR_FD_WRITE ;
2009-05-11 09:07:58 +00:00
return 0 ;
}
2011-09-02 09:08:56 +00:00
static struct mncc_q_entry * mncc_q_dequeue ( struct lcr_gsm * lcr_gsm )
{
struct mncc_q_entry * qe = lcr_gsm - > mncc_q_hd ;
if ( ! qe )
return NULL ;
/* dequeue the successfully sent message */
lcr_gsm - > mncc_q_hd = qe - > next ;
if ( ! qe )
return NULL ;
if ( qe = = lcr_gsm - > mncc_q_tail )
lcr_gsm - > mncc_q_tail = NULL ;
return qe ;
}
/* routine called by LCR code if it wants to send a message to OpenBSC */
static int mncc_send ( struct lcr_gsm * lcr_gsm , int msg_type , void * data )
{
int len = 0 ;
/* FIXME: the caller should provide this */
switch ( msg_type ) {
2016-01-30 14:38:02 +00:00
case ANALOG_8000HZ :
len = sizeof ( struct gsm_data_frame ) + 320 ;
break ;
2011-09-02 09:08:56 +00:00
case GSM_TCHF_FRAME :
len = sizeof ( struct gsm_data_frame ) + 33 ;
break ;
default :
len = sizeof ( struct gsm_mncc ) ;
break ;
}
return mncc_q_enqueue ( lcr_gsm , ( struct gsm_mncc * ) data , len ) ;
}
/* close MNCC socket */
static int mncc_fd_close ( struct lcr_gsm * lcr_gsm , struct lcr_fd * lfd )
2010-01-16 10:20:23 +00:00
{
2011-09-02 09:08:56 +00:00
class Port * port ;
class Pgsm * pgsm = NULL ;
struct lcr_msg * message ;
PERROR ( " Lost MNCC socket, retrying in %u seconds \n " , SOCKET_RETRY_TIMER ) ;
close ( lfd - > fd ) ;
unregister_fd ( lfd ) ;
lfd - > fd = - 1 ;
/* free all the calls that were running through the MNCC interface */
port = port_first ;
while ( port ) {
2016-01-30 14:36:50 +00:00
if ( ( port - > p_type & PORT_CLASS_MASK ) = = PORT_CLASS_GSM ) {
2011-09-02 09:08:56 +00:00
pgsm = ( class Pgsm * ) port ;
2012-01-15 08:42:35 +00:00
if ( pgsm - > p_g_lcr_gsm = = lcr_gsm ) {
2011-09-02 09:08:56 +00:00
message = message_create ( pgsm - > p_serial , ACTIVE_EPOINT ( pgsm - > p_epointlist ) , PORT_TO_EPOINT , MESSAGE_RELEASE ) ;
2016-01-30 14:36:50 +00:00
message - > param . disconnectinfo . cause = 41 ; // temp. fail.
2011-09-02 09:08:56 +00:00
message - > param . disconnectinfo . location = LOCATION_PRIVATE_LOCAL ;
message_put ( message ) ;
pgsm - > new_state ( PORT_STATE_RELEASE ) ;
2012-01-15 08:42:35 +00:00
trigger_work ( & pgsm - > p_g_delete ) ;
2011-09-02 09:08:56 +00:00
}
}
port = port - > next ;
}
/* flush the queue */
while ( mncc_q_dequeue ( lcr_gsm ) )
;
/* start the re-connect timer */
schedule_timer ( & lcr_gsm - > socket_retry , SOCKET_RETRY_TIMER , 0 ) ;
return 0 ;
}
/* write to OpenBSC via MNCC socket */
static int mncc_fd_write ( struct lcr_fd * lfd , void * inst , int idx )
{
struct lcr_gsm * lcr_gsm = ( struct lcr_gsm * ) inst ;
struct mncc_q_entry * qe , * qe2 ;
int rc ;
while ( 1 ) {
qe = lcr_gsm - > mncc_q_hd ;
if ( ! qe ) {
lfd - > when & = ~ LCR_FD_WRITE ;
break ;
}
rc = write ( lfd - > fd , qe - > data , qe - > len ) ;
if ( rc = = 0 )
return mncc_fd_close ( lcr_gsm , lfd ) ;
if ( rc < 0 )
return rc ;
if ( rc < ( int ) qe - > len )
return - 1 ;
/* dequeue the successfully sent message */
qe2 = mncc_q_dequeue ( lcr_gsm ) ;
assert ( qe = = qe2 ) ;
free ( qe ) ;
}
return 0 ;
}
/* read from OpenBSC via MNCC socket */
static int mncc_fd_read ( struct lcr_fd * lfd , void * inst , int idx )
{
struct lcr_gsm * lcr_gsm = ( struct lcr_gsm * ) inst ;
int rc ;
static char buf [ sizeof ( struct gsm_mncc ) + 1024 ] ;
struct gsm_mncc * mncc_prim = ( struct gsm_mncc * ) buf ;
2011-10-21 12:11:04 +00:00
struct gsm_mncc_hello * hello = ( struct gsm_mncc_hello * ) buf ;
2017-06-04 09:22:51 +00:00
class Port * port ;
class Pgsm * pgsm = NULL ;
unsigned int callref ;
2011-09-02 09:08:56 +00:00
memset ( buf , 0 , sizeof ( buf ) ) ;
rc = recv ( lfd - > fd , buf , sizeof ( buf ) , 0 ) ;
if ( rc = = 0 )
return mncc_fd_close ( lcr_gsm , lfd ) ;
if ( rc < 0 )
return rc ;
2011-10-21 12:11:04 +00:00
/* TODO: size check? */
switch ( mncc_prim - > msg_type ) {
case MNCC_SOCKET_HELLO :
if ( hello - > version ! = MNCC_SOCK_VERSION ) {
PERROR ( " MNCC version different. BSC version is %u \n " , hello - > version ) ;
mncc_fd_close ( lcr_gsm , lfd ) ;
return 0 ;
}
2012-01-15 09:49:43 +00:00
if ( hello - > mncc_size ! = sizeof ( struct gsm_mncc ) ) {
PERROR ( " MNCC gsm_mncc size differs: %u %u \n " ,
hello - > mncc_size , sizeof ( struct gsm_mncc ) ) ;
mncc_fd_close ( lcr_gsm , lfd ) ;
return 0 ;
}
if ( hello - > data_frame_size ! = sizeof ( struct gsm_data_frame ) ) {
PERROR ( " MNCC gsm_mncc size differs: %u %u \n " ,
hello - > data_frame_size , sizeof ( struct gsm_data_frame ) ) ;
mncc_fd_close ( lcr_gsm , lfd ) ;
return 0 ;
}
# define CHECK_OFFSET(hello, field, lcr_gsm, lfd) \
if ( hello - > field # # _offset ! = __builtin_offsetof ( struct gsm_mncc , field ) ) { \
PERROR ( " MNCC gsm_mncc offset of %s is %u %u \n " , \
# field, hello->field ##_offset, \
__builtin_offsetof ( struct gsm_mncc , field ) ) ; \
mncc_fd_close ( lcr_gsm , lfd ) ; \
return 0 ; \
}
CHECK_OFFSET ( hello , called , lcr_gsm , lfd ) ;
CHECK_OFFSET ( hello , signal , lcr_gsm , lfd ) ;
CHECK_OFFSET ( hello , emergency , lcr_gsm , lfd ) ;
CHECK_OFFSET ( hello , lchan_type , lcr_gsm , lfd ) ;
# undef CHECK_OFFSET
2011-10-21 12:11:04 +00:00
break ;
}
2017-06-04 09:22:51 +00:00
/* Find port object */
callref = mncc_prim - > callref ;
port = port_first ;
while ( port ) {
if ( ( port - > p_type & PORT_CLASS_MASK ) = = PORT_CLASS_GSM ) {
pgsm = ( class Pgsm * ) port ;
if ( pgsm - > p_g_lcr_gsm = = lcr_gsm & & pgsm - > p_g_callref = = callref )
break ;
}
port = port - > next ;
}
2011-09-02 09:08:56 +00:00
/* Hand the MNCC message into LCR */
switch ( lcr_gsm - > type ) {
# ifdef WITH_GSM_BS
case LCR_GSM_TYPE_NETWORK :
2017-06-04 09:22:51 +00:00
if ( port & & ( port - > p_type & PORT_CLASS_GSM_MASK ) ! = PORT_CLASS_GSM_BS )
FATAL ( " Port is set and bound to network socket, but is not of network type, please fix " ) ;
return message_bsc ( ( class Pgsm_bs * ) port , lcr_gsm , mncc_prim - > msg_type , mncc_prim ) ;
2011-09-02 09:08:56 +00:00
# endif
# ifdef WITH_GSM_MS
case LCR_GSM_TYPE_MS :
2017-06-04 09:22:51 +00:00
if ( port & & ( port - > p_type & PORT_CLASS_GSM_MASK ) ! = PORT_CLASS_GSM_MS )
FATAL ( " Port is set and bound to mobile socket, but is not of mobile type, please fix " ) ;
return message_ms ( ( class Pgsm_ms * ) port , lcr_gsm , mncc_prim - > msg_type , mncc_prim ) ;
2011-09-02 09:08:56 +00:00
# endif
default :
return 0 ;
}
}
/* file descriptor callback if we can read or write form MNCC socket */
static int mncc_fd_cb ( struct lcr_fd * lfd , unsigned int what , void * inst , int idx )
{
int rc = 0 ;
if ( what & LCR_FD_READ )
rc = mncc_fd_read ( lfd , inst , idx ) ;
if ( rc < 0 )
return rc ;
if ( what & LCR_FD_WRITE )
rc = mncc_fd_write ( lfd , inst , idx ) ;
return rc ;
}
int mncc_socket_retry_cb ( struct lcr_timer * timer , void * inst , int index )
{
struct lcr_gsm * lcr_gsm = ( struct lcr_gsm * ) inst ;
int fd , rc ;
lcr_gsm - > mncc_lfd . fd = - 1 ;
fd = socket ( PF_UNIX , SOCK_SEQPACKET , 0 ) ;
if ( fd < 0 ) {
PERROR ( " Cannot create SEQPACKET socket, giving up! \n " ) ;
return fd ;
}
rc = connect ( fd , ( struct sockaddr * ) & lcr_gsm - > sun ,
sizeof ( lcr_gsm - > sun ) ) ;
if ( rc < 0 ) {
PERROR ( " Could not connect to MNCC socket %s, "
" retrying in %u seconds \n " , lcr_gsm - > sun . sun_path ,
SOCKET_RETRY_TIMER ) ;
close ( fd ) ;
schedule_timer ( & lcr_gsm - > socket_retry , SOCKET_RETRY_TIMER , 0 ) ;
} else {
PDEBUG ( DEBUG_GSM , " Connected to MNCC socket %s! \n " , lcr_gsm - > sun . sun_path ) ;
lcr_gsm - > mncc_lfd . fd = fd ;
register_fd ( & lcr_gsm - > mncc_lfd , LCR_FD_READ , & mncc_fd_cb , lcr_gsm , 0 ) ;
}
2010-01-16 10:20:23 +00:00
return 0 ;
}