2005-06-22 06:47:39 +08:00
/*
* libpri : An implementation of Primary Rate ISDN
*
* Written by Matthew Fredrickson < creslin @ digium . com >
*
* Copyright ( C ) 2004 - 2005 , Digium
* All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*/
2004-10-28 04:44:39 +08:00
2004-12-16 04:15:28 +08:00
# include "compat.h"
2004-10-28 04:44:39 +08:00
# include "libpri.h"
# include "pri_internal.h"
# include "pri_q921.h"
# include "pri_q931.h"
# include "pri_facility.h"
2005-04-05 11:55:58 +08:00
# include <stdio.h>
2004-10-28 04:44:39 +08:00
# include <stdlib.h>
# include <string.h>
2006-01-06 04:50:51 +08:00
# include <limits.h>
static char * asn1id2text ( int id )
{
static char data [ 32 ] ;
static char * strings [ ] = {
" none " ,
" Boolean " ,
" Integer " ,
" Bit String " ,
" Octet String " ,
" NULL " ,
" Object Identifier " ,
" Object Descriptor " ,
" External Reference " ,
" Real Number " ,
" Enumerated " ,
" Embedded PDV " ,
" UTF-8 String " ,
" Relative Object ID " ,
" Reserved (0e) " ,
" Reserved (0f) " ,
" Sequence " ,
" Set " ,
" Numeric String " ,
" Printable String " ,
" Tele-Text String " ,
" IA-5 String " ,
" UTC Time " ,
" Generalized Time " ,
} ;
if ( id > 0 & & id < = 0x18 ) {
return strings [ id ] ;
} else {
sprintf ( data , " Unknown (%02x) " , id ) ;
return data ;
}
}
static int asn1_dumprecursive ( struct pri * pri , void * comp_ptr , int len , int level )
{
unsigned char * vdata = ( unsigned char * ) comp_ptr ;
struct rose_component * comp ;
int i = 0 ;
int j , k , l ;
int clen = 0 ;
while ( len > 0 ) {
GET_COMPONENT ( comp , i , vdata , len ) ;
pri_message ( pri , " %*s%02X %04X " , 2 * level , " " , comp - > type , comp - > len ) ;
if ( ( comp - > type = = 0 ) & & ( comp - > len = = 0 ) )
return clen + 2 ;
if ( ( comp - > type & ASN1_PC_MASK ) = = ASN1_PRIMITIVE ) {
for ( j = 0 ; j < comp - > len ; + + j )
pri_message ( pri , " %02X " , comp - > data [ j ] ) ;
}
if ( ( comp - > type & ASN1_CLAN_MASK ) = = ASN1_UNIVERSAL ) {
switch ( comp - > type & ASN1_TYPE_MASK ) {
case 0 :
pri_message ( pri , " (none) " ) ;
break ;
case ASN1_BOOLEAN :
pri_message ( pri , " (BOOLEAN: %d) " , comp - > data [ 0 ] ) ;
break ;
case ASN1_INTEGER :
for ( k = l = 0 ; k < comp - > len ; + + k )
l = ( l < < 8 ) | comp - > data [ k ] ;
pri_message ( pri , " (INTEGER: %d) " , l ) ;
break ;
case ASN1_BITSTRING :
pri_message ( pri , " (BITSTRING: " ) ;
for ( k = 0 ; k < comp - > len ; + + k )
pri_message ( pri , " %02x " , comp - > data [ k ] ) ;
pri_message ( pri , " ) " ) ;
break ;
case ASN1_OCTETSTRING :
pri_message ( pri , " (OCTETSTRING: " ) ;
for ( k = 0 ; k < comp - > len ; + + k )
pri_message ( pri , " %02x " , comp - > data [ k ] ) ;
pri_message ( pri , " ) " ) ;
break ;
case ASN1_NULL :
pri_message ( pri , " (NULL) " ) ;
break ;
case ASN1_OBJECTIDENTIFIER :
pri_message ( pri , " (OBJECTIDENTIFIER: " ) ;
for ( k = 0 ; k < comp - > len ; + + k )
pri_message ( pri , " %02x " , comp - > data [ k ] ) ;
pri_message ( pri , " ) " ) ;
break ;
case ASN1_ENUMERATED :
for ( k = l = 0 ; k < comp - > len ; + + k )
l = ( l < < 8 ) | comp - > data [ k ] ;
pri_message ( pri , " (ENUMERATED: %d) " , l ) ;
break ;
case ASN1_SEQUENCE :
pri_message ( pri , " (SEQUENCE) " ) ;
break ;
default :
pri_message ( pri , " (component %02x - %s) " , comp - > type , asn1id2text ( comp - > type & ASN1_TYPE_MASK ) ) ;
break ;
}
}
else if ( ( comp - > type & ASN1_CLAN_MASK ) = = ASN1_CONTEXT_SPECIFIC ) {
pri_message ( pri , " (CONTEXT SPECIFIC [%d]) " , comp - > type & ASN1_TYPE_MASK ) ;
}
else {
pri_message ( pri , " (component %02x) " , comp - > type ) ;
}
pri_message ( pri , " \n " ) ;
if ( ( comp - > type & ASN1_PC_MASK ) = = ASN1_CONSTRUCTOR )
j = asn1_dumprecursive ( pri , comp - > data , ( comp - > len ? comp - > len : INT_MAX ) , level + 1 ) ;
else
j = comp - > len ;
j + = 2 ;
len - = j ;
vdata + = j ;
clen + = j ;
}
return clen ;
}
int asn1_dump ( struct pri * pri , void * comp , int len )
{
return asn1_dumprecursive ( pri , comp , len , 0 ) ;
}
2004-10-28 04:44:39 +08:00
2005-03-02 23:56:11 +08:00
static unsigned char get_invokeid ( struct pri * pri )
{
return + + pri - > last_invoke ;
}
2005-02-04 06:14:44 +08:00
struct addressingdataelements_presentednumberunscreened {
2005-03-02 23:56:11 +08:00
char partyaddress [ 21 ] ;
char partysubaddress [ 21 ] ;
2005-02-04 06:14:44 +08:00
int npi ;
int ton ;
int pres ;
} ;
2006-01-06 04:50:51 +08:00
# define PRI_CHECKOVERFLOW(size) \
if ( msgptr - message + ( size ) > = sizeof ( message ) ) { \
* msgptr = ' \0 ' ; \
pri_message ( pri , " %s " , message ) ; \
msgptr = message ; \
}
2005-05-23 23:06:33 +08:00
static void dump_apdu ( struct pri * pri , unsigned char * c , int len )
2005-04-05 11:55:58 +08:00
{
# define MAX_APDU_LENGTH 255
2006-01-06 04:50:51 +08:00
static char hexs [ 16 ] = " 0123456789ABCDEF " ;
2005-04-05 11:55:58 +08:00
int i ;
char message [ ( 2 + MAX_APDU_LENGTH * 3 + 6 + MAX_APDU_LENGTH + 3 ) ] = " " ; /* please adjust here, if you make changes below! */
2006-01-06 04:50:51 +08:00
char * msgptr ;
2005-04-05 11:55:58 +08:00
2006-01-06 04:50:51 +08:00
msgptr = message ;
* msgptr + + = ' ' ;
* msgptr + + = ' [ ' ;
2005-04-05 11:55:58 +08:00
for ( i = 0 ; i < len ; i + + ) {
2006-01-06 04:50:51 +08:00
PRI_CHECKOVERFLOW ( 3 ) ;
* msgptr + + = ' ' ;
* msgptr + + = hexs [ ( c [ i ] > > 4 ) & 0x0f ] ;
* msgptr + + = hexs [ ( c [ i ] ) & 0x0f ] ;
}
PRI_CHECKOVERFLOW ( 6 ) ;
strcpy ( msgptr , " ] - [ " ) ;
msgptr + = strlen ( msgptr ) ;
for ( i = 0 ; i < len ; i + + ) {
PRI_CHECKOVERFLOW ( 1 ) ;
* msgptr + + = ( ( c [ i ] < ' ' ) | | ( c [ i ] > ' ~ ' ) ) ? ' . ' : c [ i ] ;
2005-04-05 11:55:58 +08:00
}
2006-01-06 04:50:51 +08:00
PRI_CHECKOVERFLOW ( 2 ) ;
* msgptr + + = ' ] ' ;
* msgptr + + = ' \n ' ;
* msgptr = ' \0 ' ;
pri_message ( pri , " %s " , message ) ;
2005-04-05 11:55:58 +08:00
}
2006-01-06 04:50:51 +08:00
# undef PRI_CHECKOVERFLOW
2005-04-05 11:55:58 +08:00
2005-02-04 06:14:44 +08:00
int redirectingreason_from_q931 ( struct pri * pri , int redirectingreason )
{
switch ( pri - > switchtype ) {
2005-04-05 11:55:58 +08:00
case PRI_SWITCH_QSIG :
switch ( redirectingreason ) {
case PRI_REDIR_UNKNOWN :
return QSIG_DIVERT_REASON_UNKNOWN ;
case PRI_REDIR_FORWARD_ON_BUSY :
return QSIG_DIVERT_REASON_CFB ;
case PRI_REDIR_FORWARD_ON_NO_REPLY :
return QSIG_DIVERT_REASON_CFNR ;
case PRI_REDIR_UNCONDITIONAL :
return QSIG_DIVERT_REASON_CFU ;
case PRI_REDIR_DEFLECTION :
case PRI_REDIR_DTE_OUT_OF_ORDER :
case PRI_REDIR_FORWARDED_BY_DTE :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Don't know how to convert Q.931 redirection reason %d to Q.SIG \n " , redirectingreason ) ;
2005-04-05 11:55:58 +08:00
/* Fall through */
default :
return QSIG_DIVERT_REASON_UNKNOWN ;
}
2005-02-04 06:14:44 +08:00
default :
2005-04-05 11:55:58 +08:00
switch ( redirectingreason ) {
case PRI_REDIR_UNKNOWN :
return Q952_DIVERT_REASON_UNKNOWN ;
case PRI_REDIR_FORWARD_ON_BUSY :
return Q952_DIVERT_REASON_CFB ;
case PRI_REDIR_FORWARD_ON_NO_REPLY :
return Q952_DIVERT_REASON_CFNR ;
case PRI_REDIR_DEFLECTION :
return Q952_DIVERT_REASON_CD ;
case PRI_REDIR_UNCONDITIONAL :
return Q952_DIVERT_REASON_CFU ;
case PRI_REDIR_DTE_OUT_OF_ORDER :
case PRI_REDIR_FORWARDED_BY_DTE :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Don't know how to convert Q.931 redirection reason %d to Q.952 \n " , redirectingreason ) ;
2005-04-05 11:55:58 +08:00
/* Fall through */
default :
return Q952_DIVERT_REASON_UNKNOWN ;
}
2005-02-04 06:14:44 +08:00
}
}
static int redirectingreason_for_q931 ( struct pri * pri , int redirectingreason )
{
switch ( pri - > switchtype ) {
2005-04-05 11:55:58 +08:00
case PRI_SWITCH_QSIG :
switch ( redirectingreason ) {
case QSIG_DIVERT_REASON_UNKNOWN :
return PRI_REDIR_UNKNOWN ;
case QSIG_DIVERT_REASON_CFU :
return PRI_REDIR_UNCONDITIONAL ;
case QSIG_DIVERT_REASON_CFB :
return PRI_REDIR_FORWARD_ON_BUSY ;
case QSIG_DIVERT_REASON_CFNR :
return PRI_REDIR_FORWARD_ON_NO_REPLY ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Unknown Q.SIG diversion reason %d \n " , redirectingreason ) ;
2005-04-05 11:55:58 +08:00
return PRI_REDIR_UNKNOWN ;
}
2005-02-04 06:14:44 +08:00
default :
2005-04-05 11:55:58 +08:00
switch ( redirectingreason ) {
case Q952_DIVERT_REASON_UNKNOWN :
return PRI_REDIR_UNKNOWN ;
case Q952_DIVERT_REASON_CFU :
return PRI_REDIR_UNCONDITIONAL ;
case Q952_DIVERT_REASON_CFB :
return PRI_REDIR_FORWARD_ON_BUSY ;
case Q952_DIVERT_REASON_CFNR :
return PRI_REDIR_FORWARD_ON_NO_REPLY ;
case Q952_DIVERT_REASON_CD :
return PRI_REDIR_DEFLECTION ;
case Q952_DIVERT_REASON_IMMEDIATE :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog \n " ) ;
2005-04-05 11:55:58 +08:00
return PRI_REDIR_UNKNOWN ; /* ??? */
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Unknown Q.952 diversion reason %d \n " , redirectingreason ) ;
2005-04-05 11:55:58 +08:00
return PRI_REDIR_UNKNOWN ;
}
2005-02-04 06:14:44 +08:00
}
}
int typeofnumber_from_q931 ( struct pri * pri , int ton )
{
switch ( ton ) {
2005-04-05 11:55:58 +08:00
case PRI_TON_INTERNATIONAL :
return Q932_TON_INTERNATIONAL ;
case PRI_TON_NATIONAL :
return Q932_TON_NATIONAL ;
case PRI_TON_NET_SPECIFIC :
return Q932_TON_NET_SPECIFIC ;
case PRI_TON_SUBSCRIBER :
return Q932_TON_SUBSCRIBER ;
case PRI_TON_ABBREVIATED :
return Q932_TON_ABBREVIATED ;
case PRI_TON_RESERVED :
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Unsupported Q.931 TypeOfNumber value (%d) \n " , ton ) ;
2005-04-05 11:55:58 +08:00
/* fall through */
case PRI_TON_UNKNOWN :
return Q932_TON_UNKNOWN ;
2005-02-04 06:14:44 +08:00
}
}
static int typeofnumber_for_q931 ( struct pri * pri , int ton )
{
switch ( ton ) {
2005-04-05 11:55:58 +08:00
case Q932_TON_UNKNOWN :
return PRI_TON_UNKNOWN ;
case Q932_TON_INTERNATIONAL :
return PRI_TON_INTERNATIONAL ;
case Q932_TON_NATIONAL :
return PRI_TON_NATIONAL ;
case Q932_TON_NET_SPECIFIC :
return PRI_TON_NET_SPECIFIC ;
case Q932_TON_SUBSCRIBER :
return PRI_TON_SUBSCRIBER ;
case Q932_TON_ABBREVIATED :
return PRI_TON_ABBREVIATED ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Invalid Q.932 TypeOfNumber %d \n " , ton ) ;
2005-04-05 11:55:58 +08:00
return PRI_TON_UNKNOWN ;
2005-02-04 06:14:44 +08:00
}
}
2005-04-07 03:42:41 +08:00
int asn1_name_decode ( void * data , int len , char * namebuf , int buflen )
{
struct rose_component * comp = ( struct rose_component * ) data ;
int datalen = 0 , res = 0 ;
if ( comp - > len = = ASN1_LEN_INDEF ) {
2005-06-22 04:37:22 +08:00
datalen = strlen ( ( char * ) comp - > data ) ;
2005-04-07 03:42:41 +08:00
res = datalen + 2 ;
} else
datalen = res = comp - > len ;
if ( datalen > buflen ) {
/* Truncate */
datalen = buflen ;
}
2005-06-04 02:29:25 +08:00
memcpy ( namebuf , comp - > data , datalen ) ;
return res + 2 ;
2005-04-07 03:42:41 +08:00
}
2005-02-04 06:14:44 +08:00
int asn1_string_encode ( unsigned char asn1_type , void * data , int len , int max_len , void * src , int src_len )
{
struct rose_component * comp = NULL ;
if ( len < 2 + src_len )
return - 1 ;
if ( max_len & & ( src_len > max_len ) )
src_len = max_len ;
comp = ( struct rose_component * ) data ;
comp - > type = asn1_type ;
comp - > len = src_len ;
memcpy ( comp - > data , src , src_len ) ;
return 2 + src_len ;
}
2005-07-13 04:15:20 +08:00
int asn1_copy_string ( char * buf , int buflen , struct rose_component * comp )
{
int res ;
int datalen ;
if ( ( comp - > len > buflen ) & & ( comp - > len ! = ASN1_LEN_INDEF ) )
return - 1 ;
if ( comp - > len = = ASN1_LEN_INDEF ) {
2005-07-13 22:09:16 +08:00
datalen = strlen ( ( char * ) comp - > data ) ;
2005-07-13 04:15:20 +08:00
res = datalen + 2 ;
} else
res = datalen = comp - > len ;
memcpy ( buf , comp - > data , datalen ) ;
buf [ datalen ] = 0 ;
return res ;
}
2005-02-04 06:14:44 +08:00
static int rose_number_digits_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len , struct addressingdataelements_presentednumberunscreened * value )
2004-10-28 04:44:39 +08:00
{
int i = 0 ;
struct rose_component * comp = NULL ;
2005-02-04 06:14:44 +08:00
unsigned char * vdata = data ;
2005-04-07 03:42:41 +08:00
int datalen = 0 ;
int res = 0 ;
2005-02-04 06:14:44 +08:00
do {
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , ASN1_NUMERICSTRING , " Don't know what to do with PublicPartyNumber ROSE component type 0x%x \n " ) ;
2005-04-07 03:42:41 +08:00
if ( comp - > len > 20 & & comp - > len ! = ASN1_LEN_INDEF ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Oversized NumberDigits component (%d) \n " , comp - > len ) ;
2005-02-04 06:14:44 +08:00
return - 1 ;
}
2005-04-07 03:42:41 +08:00
if ( comp - > len = = ASN1_LEN_INDEF ) {
2005-06-22 04:37:22 +08:00
datalen = strlen ( ( char * ) comp - > data ) ;
2005-04-07 03:42:41 +08:00
res = datalen + 2 ;
} else
res = datalen = comp - > len ;
memcpy ( value - > partyaddress , comp - > data , datalen ) ;
value - > partyaddress [ datalen ] = ' \0 ' ;
return res + 2 ;
2005-02-04 06:14:44 +08:00
}
while ( 0 ) ;
return - 1 ;
}
2004-10-28 04:44:39 +08:00
2005-02-04 06:14:44 +08:00
static int rose_public_party_number_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len , struct addressingdataelements_presentednumberunscreened * value )
{
int i = 0 ;
struct rose_component * comp = NULL ;
unsigned char * vdata = data ;
int ton ;
2005-04-07 03:42:41 +08:00
int res = 0 ;
2004-10-28 04:44:39 +08:00
2005-02-04 06:14:44 +08:00
if ( len < 2 )
2004-10-28 04:44:39 +08:00
return - 1 ;
2005-02-04 06:14:44 +08:00
do {
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , ASN1_ENUMERATED , " Don't know what to do with PublicPartyNumber ROSE component type 0x%x \n " ) ;
ASN1_GET_INTEGER ( comp , ton ) ;
NEXT_COMPONENT ( comp , i ) ;
ton = typeofnumber_for_q931 ( pri , ton ) ;
2005-04-07 03:42:41 +08:00
res = rose_number_digits_decode ( pri , call , & vdata [ i ] , len - i , value ) ;
if ( res < 0 )
2005-02-04 06:14:44 +08:00
return - 1 ;
value - > ton = ton ;
2005-06-03 04:58:32 +08:00
return res + 3 ;
2005-02-04 06:14:44 +08:00
} while ( 0 ) ;
return - 1 ;
}
static int rose_address_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len , struct addressingdataelements_presentednumberunscreened * value )
{
int i = 0 ;
struct rose_component * comp = NULL ;
unsigned char * vdata = data ;
2005-04-07 03:42:41 +08:00
int res = 0 ;
2005-02-04 06:14:44 +08:00
do {
GET_COMPONENT ( comp , i , vdata , len ) ;
switch ( comp - > type ) {
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0 ) : /* [0] unknownPartyNumber */
2005-04-07 03:42:41 +08:00
res = rose_number_digits_decode ( pri , call , comp - > data , comp - > len , value ) ;
if ( res < 0 )
2005-02-04 06:14:44 +08:00
return - 1 ;
value - > npi = PRI_NPI_UNKNOWN ;
value - > ton = PRI_TON_UNKNOWN ;
break ;
2005-07-13 04:15:20 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0 ) : /* [0] unknownPartyNumber */
res = asn1_copy_string ( value - > partyaddress , sizeof ( value - > partyaddress ) , comp ) ;
if ( res < 0 )
return - 1 ;
value - > npi = PRI_NPI_UNKNOWN ;
value - > ton = PRI_TON_UNKNOWN ;
break ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1 ) : /* [1] publicPartyNumber */
2005-04-07 03:42:41 +08:00
res = rose_public_party_number_decode ( pri , call , comp - > data , comp - > len , value ) ;
if ( res < 0 )
2005-02-04 06:14:44 +08:00
return - 1 ;
value - > npi = PRI_NPI_E163_E164 ;
break ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2 ) : /* [2] nsapEncodedNumber */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! NsapEncodedNumber isn't handled \n " ) ;
2005-02-04 06:14:44 +08:00
return - 1 ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3 ) : /* [3] dataPartyNumber */
2005-02-04 06:14:44 +08:00
if ( rose_number_digits_decode ( pri , call , comp - > data , comp - > len , value ) )
return - 1 ;
value - > npi = PRI_NPI_X121 /* ??? */ ;
value - > ton = PRI_TON_UNKNOWN /* ??? */ ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! dataPartyNumber isn't handled \n " ) ;
2005-02-04 06:14:44 +08:00
return - 1 ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4 ) : /* [4] telexPartyNumber */
2005-04-07 03:42:41 +08:00
res = rose_number_digits_decode ( pri , call , comp - > data , comp - > len , value ) ;
if ( res < 0 )
2005-02-04 06:14:44 +08:00
return - 1 ;
value - > npi = PRI_NPI_F69 /* ??? */ ;
value - > ton = PRI_TON_UNKNOWN /* ??? */ ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! telexPartyNumber isn't handled \n " ) ;
2005-02-04 06:14:44 +08:00
return - 1 ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5 ) : /* [5] priavePartyNumber */
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! privatePartyNumber isn't handled \n " ) ;
2005-02-04 06:14:44 +08:00
value - > npi = PRI_NPI_PRIVATE ;
return - 1 ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8 ) : /* [8] nationalStandardPartyNumber */
2005-04-07 03:42:41 +08:00
res = rose_number_digits_decode ( pri , call , comp - > data , comp - > len , value ) ;
if ( res < 0 )
2005-02-04 06:14:44 +08:00
return - 1 ;
value - > npi = PRI_NPI_NATIONAL ;
value - > ton = PRI_TON_NATIONAL ;
break ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Unknown Party number component received 0x%X \n " , comp - > type ) ;
2005-02-04 06:14:44 +08:00
return - 1 ;
}
2005-06-03 04:58:32 +08:00
ASN1_FIXUP_LEN ( comp , res ) ;
2005-02-04 06:14:44 +08:00
NEXT_COMPONENT ( comp , i ) ;
if ( i < len )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! not all information is handled from Address component \n " ) ;
2005-06-03 06:40:35 +08:00
return res + 2 ;
2004-10-28 04:44:39 +08:00
}
2005-02-04 06:14:44 +08:00
while ( 0 ) ;
return - 1 ;
}
static int rose_presented_number_unscreened_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len , struct addressingdataelements_presentednumberunscreened * value )
{
int i = 0 ;
2005-06-03 04:58:32 +08:00
int size = 0 ;
2005-02-04 06:14:44 +08:00
struct rose_component * comp = NULL ;
unsigned char * vdata = data ;
/* Fill in default values */
value - > ton = PRI_TON_UNKNOWN ;
value - > npi = PRI_NPI_E163_E164 ;
value - > pres = - 1 ; /* Data is not available */
2004-10-28 04:44:39 +08:00
2005-02-04 06:14:44 +08:00
do {
GET_COMPONENT ( comp , i , vdata , len ) ;
2004-10-28 04:44:39 +08:00
2005-02-04 06:14:44 +08:00
switch ( comp - > type ) {
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0 ) : /* [0] presentationAllowedNumber */
2005-02-04 06:14:44 +08:00
value - > pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED ;
2005-06-03 04:58:32 +08:00
size = rose_address_decode ( pri , call , comp - > data , comp - > len , value ) ;
ASN1_FIXUP_LEN ( comp , size ) ;
return size + 2 ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1 ) : /* [1] IMPLICIT presentationRestricted */
2005-02-04 06:14:44 +08:00
if ( comp - > len ! = 0 ) { /* must be NULL */
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! Invalid PresentationRestricted component received (len != 0) \n " ) ;
2005-02-04 06:14:44 +08:00
return - 1 ;
}
value - > pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED ;
2005-04-07 03:42:41 +08:00
return 2 ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2 ) : /* [2] IMPLICIT numberNotAvailableDueToInterworking */
2005-02-04 06:14:44 +08:00
if ( comp - > len ! = 0 ) { /* must be NULL */
2005-05-23 23:06:33 +08:00
pri_error ( pri , " !! Invalid NumberNotAvailableDueToInterworking component received (len != 0) \n " ) ;
2005-02-04 06:14:44 +08:00
return - 1 ;
}
value - > pres = PRES_NUMBER_NOT_AVAILABLE ;
2005-04-07 03:42:41 +08:00
return 2 ;
2005-04-05 11:55:58 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3 ) : /* [3] presentationRestrictedNumber */
2005-02-04 06:14:44 +08:00
value - > pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED ;
2005-06-03 04:58:32 +08:00
size = rose_address_decode ( pri , call , comp - > data , comp - > len , value ) + 2 ;
ASN1_FIXUP_LEN ( comp , size ) ;
return size + 2 ;
2005-02-04 06:14:44 +08:00
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Invalid PresentedNumberUnscreened component 0x%X \n " , comp - > type ) ;
2005-02-04 06:14:44 +08:00
}
2004-10-28 04:44:39 +08:00
return - 1 ;
}
2005-02-04 06:14:44 +08:00
while ( 0 ) ;
2004-10-28 04:44:39 +08:00
2005-02-04 06:14:44 +08:00
return - 1 ;
}
2005-06-04 02:29:25 +08:00
static int rose_diverting_leg_information2_decode ( struct pri * pri , q931_call * call , struct rose_component * sequence , int len )
2005-02-04 06:14:44 +08:00
{
int i = 0 ;
int diversion_counter ;
int diversion_reason ;
2005-04-07 03:42:41 +08:00
char origcalledname [ 50 ] = " " , redirectingname [ 50 ] = " " ;
2005-03-02 23:56:11 +08:00
struct addressingdataelements_presentednumberunscreened divertingnr ;
struct addressingdataelements_presentednumberunscreened originalcallednr ;
2005-02-04 06:14:44 +08:00
struct rose_component * comp = NULL ;
2005-06-04 02:29:25 +08:00
unsigned char * vdata = sequence - > data ;
2005-04-07 03:42:41 +08:00
int res = 0 ;
2005-02-04 06:14:44 +08:00
2005-06-04 02:29:25 +08:00
/* Data checks */
if ( sequence - > type ! = ( ASN1_CONSTRUCTOR | ASN1_SEQUENCE ) ) { /* Constructed Sequence */
pri_message ( pri , " Invalid DivertingLegInformation2Type argument \n " ) ;
return - 1 ;
}
if ( sequence - > len = = ASN1_LEN_INDEF ) {
len - = 4 ; /* For the 2 extra characters at the end
* and two characters of header */
} else
len - = 2 ;
2005-02-04 06:14:44 +08:00
do {
/* diversionCounter stuff */
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , ASN1_INTEGER , " Don't know what to do it diversionCounter is of type 0x%x \n " ) ;
ASN1_GET_INTEGER ( comp , diversion_counter ) ;
NEXT_COMPONENT ( comp , i ) ;
/* diversionReason stuff */
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , ASN1_ENUMERATED , " Invalid diversionReason type 0x%X of ROSE divertingLegInformation2 component received \n " ) ;
ASN1_GET_INTEGER ( comp , diversion_reason ) ;
NEXT_COMPONENT ( comp , i ) ;
diversion_reason = redirectingreason_for_q931 ( pri , diversion_reason ) ;
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Redirection reason: %d, total diversions: %d \n " , diversion_reason , diversion_counter ) ;
2005-06-04 02:29:25 +08:00
pri_message ( NULL , " Length of message is %d \n " , len ) ;
2005-02-04 06:14:44 +08:00
for ( ; i < len ; NEXT_COMPONENT ( comp , i ) ) {
GET_COMPONENT ( comp , i , vdata , len ) ;
2005-06-04 02:29:25 +08:00
switch ( comp - > type ) {
case ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0 ) :
2005-04-07 03:42:41 +08:00
call - > origredirectingreason = redirectingreason_for_q931 ( pri , comp - > data [ 0 ] ) ;
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Received reason for original redirection %d \n " , call - > origredirectingreason ) ;
2005-04-07 03:42:41 +08:00
break ;
2005-06-04 02:29:25 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1 ) :
2005-04-07 03:42:41 +08:00
res = rose_presented_number_unscreened_decode ( pri , call , comp - > data , comp - > len , & divertingnr ) ;
/* TODO: Fix indefinite length form hacks */
2005-06-03 04:58:32 +08:00
ASN1_FIXUP_LEN ( comp , res ) ;
2005-04-07 03:42:41 +08:00
comp - > len = res ;
if ( res < 0 )
2005-02-04 06:14:44 +08:00
return - 1 ;
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Received divertingNr '%s' \n " , divertingnr . partyaddress ) ;
pri_message ( pri , " ton = %d, pres = %d, npi = %d \n " , divertingnr . ton , divertingnr . pres , divertingnr . npi ) ;
2005-02-04 06:14:44 +08:00
}
break ;
2005-06-04 02:29:25 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2 ) :
2005-04-07 03:42:41 +08:00
res = rose_presented_number_unscreened_decode ( pri , call , comp - > data , comp - > len , & originalcallednr ) ;
if ( res < 0 )
2005-02-04 06:14:44 +08:00
return - 1 ;
2005-06-03 04:58:32 +08:00
ASN1_FIXUP_LEN ( comp , res ) ;
2005-04-07 03:42:41 +08:00
comp - > len = res ;
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Received originalcallednr '%s' \n " , originalcallednr . partyaddress ) ;
pri_message ( pri , " ton = %d, pres = %d, npi = %d \n " , originalcallednr . ton , originalcallednr . pres , originalcallednr . npi ) ;
2005-02-04 06:14:44 +08:00
}
break ;
2005-06-04 02:29:25 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3 ) :
2005-06-03 04:58:32 +08:00
res = asn1_name_decode ( comp - > data , comp - > len , redirectingname , sizeof ( redirectingname ) ) ;
if ( res < 0 )
return - 1 ;
ASN1_FIXUP_LEN ( comp , res ) ;
comp - > len = res ;
2005-04-07 03:42:41 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Received RedirectingName '%s' \n " , redirectingname ) ;
2005-04-07 03:42:41 +08:00
break ;
2005-06-04 02:29:25 +08:00
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4 ) :
2005-06-03 04:58:32 +08:00
res = asn1_name_decode ( comp - > data , comp - > len , origcalledname , sizeof ( origcalledname ) ) ;
if ( res < 0 )
return - 1 ;
ASN1_FIXUP_LEN ( comp , res ) ;
comp - > len = res ;
2005-04-07 03:42:41 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Received Originally Called Name '%s' \n " , origcalledname ) ;
2005-04-07 03:42:41 +08:00
break ;
2005-02-04 06:14:44 +08:00
default :
2005-06-04 02:29:25 +08:00
if ( comp - > type = = 0 & & comp - > len = = 0 ) {
break ; /* Found termination characters */
}
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Invalid DivertingLegInformation2 component received 0x%X \n " , comp - > type ) ;
2005-02-04 06:14:44 +08:00
return - 1 ;
}
}
2005-03-02 23:56:11 +08:00
if ( divertingnr . pres > = 0 ) {
call - > redirectingplan = divertingnr . npi ;
call - > redirectingpres = divertingnr . pres ;
2005-02-04 06:14:44 +08:00
call - > redirectingreason = diversion_reason ;
2005-06-22 06:47:39 +08:00
libpri_copy_string ( call - > redirectingnum , divertingnr . partyaddress , sizeof ( call - > redirectingnum ) ) ;
2005-02-04 06:14:44 +08:00
}
2005-04-07 03:42:41 +08:00
if ( originalcallednr . pres > = 0 ) {
call - > origcalledplan = originalcallednr . npi ;
call - > origcalledpres = originalcallednr . pres ;
2005-06-22 06:47:39 +08:00
libpri_copy_string ( call - > origcallednum , originalcallednr . partyaddress , sizeof ( call - > origcallednum ) ) ;
2005-02-04 06:14:44 +08:00
}
2005-06-22 06:47:39 +08:00
libpri_copy_string ( call - > redirectingname , redirectingname , sizeof ( call - > redirectingname ) ) ;
libpri_copy_string ( call - > origcalledname , origcalledname , sizeof ( call - > origcalledname ) ) ;
2005-02-04 06:14:44 +08:00
return 0 ;
}
while ( 0 ) ;
return - 1 ;
}
2005-06-03 04:58:32 +08:00
2005-03-02 23:56:11 +08:00
static int rose_diverting_leg_information2_encode ( struct pri * pri , q931_call * call )
{
int i = 0 , j , compsp = 0 ;
struct rose_component * comp , * compstk [ 10 ] ;
unsigned char buffer [ 256 ] ;
int len = 253 ;
2006-01-06 04:50:51 +08:00
#if 0 /* This is not required by specifications */
2005-03-02 23:56:11 +08:00
if ( ! strlen ( call - > callername ) ) {
return - 1 ;
}
2006-01-06 04:50:51 +08:00
# endif
2005-03-02 23:56:11 +08:00
2005-04-05 11:55:58 +08:00
buffer [ i ] = ( ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS ) ;
2005-03-02 23:56:11 +08:00
i + + ;
/* Interpretation component */
ASN1_ADD_BYTECOMP ( comp , COMP_TYPE_INTERPRETATION , buffer , i , 0x00 /* Discard unrecognized invokes */ ) ;
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Invoke component contents */
/* Invoke ID */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , get_invokeid ( pri ) ) ;
/* Operation Tag */
/* ROSE operationId component */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , ROSE_DIVERTING_LEG_INFORMATION2 ) ;
/* ROSE ARGUMENT component */
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONSTRUCTOR | ASN1_SEQUENCE ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
/* ROSE DivertingLegInformation2.diversionCounter component */
/* Always is 1 because other isn't available in the current design */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , 1 ) ;
/* ROSE DivertingLegInformation2.diversionReason component */
ASN1_ADD_BYTECOMP ( comp , ASN1_ENUMERATED , buffer , i , redirectingreason_from_q931 ( pri , call - > redirectingreason ) ) ;
/* ROSE DivertingLegInformation2.divertingNr component */
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Redirecting information always not screened */
switch ( call - > redirectingpres ) {
case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED :
case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN :
if ( call - > redirectingnum & & strlen ( call - > redirectingnum ) ) {
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
/* NPI of redirected number is not supported in the current design */
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_BYTECOMP ( comp , ASN1_ENUMERATED , buffer , i , typeofnumber_from_q931 ( pri , call - > redirectingplan > > 4 ) ) ;
j = asn1_string_encode ( ASN1_NUMERICSTRING , & buffer [ i ] , len - i , 20 , call - > redirectingnum , strlen ( call - > redirectingnum ) ) ;
if ( j < 0 )
return - 1 ;
i + = j ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
break ;
}
/* fall through */
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN :
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED :
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
break ;
/* Don't know how to handle this */
case PRES_ALLOWED_NETWORK_NUMBER :
case PRES_PROHIB_NETWORK_NUMBER :
case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN :
case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN :
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
break ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Undefined presentation value for redirecting number: %d \n " , call - > redirectingpres ) ;
2005-03-02 23:56:11 +08:00
case PRES_NUMBER_NOT_AVAILABLE :
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
break ;
}
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
/* ROSE DivertingLegInformation2.originalCalledNr component */
/* This information isn't supported by current design - duplicate divertingNr */
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Redirecting information always not screened */
switch ( call - > redirectingpres ) {
case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED :
case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN :
if ( call - > redirectingnum & & strlen ( call - > redirectingnum ) ) {
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_BYTECOMP ( comp , ASN1_ENUMERATED , buffer , i , typeofnumber_from_q931 ( pri , call - > redirectingplan > > 4 ) ) ;
j = asn1_string_encode ( ASN1_NUMERICSTRING , & buffer [ i ] , len - i , 20 , call - > redirectingnum , strlen ( call - > redirectingnum ) ) ;
if ( j < 0 )
return - 1 ;
i + = j ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
break ;
}
/* fall through */
case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN :
case PRES_PROHIB_USER_NUMBER_NOT_SCREENED :
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
break ;
/* Don't know how to handle this */
case PRES_ALLOWED_NETWORK_NUMBER :
case PRES_PROHIB_NETWORK_NUMBER :
case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN :
case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN :
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
break ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Undefined presentation value for redirecting number: %d \n " , call - > redirectingpres ) ;
2005-03-02 23:56:11 +08:00
case PRES_NUMBER_NOT_AVAILABLE :
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2 ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
break ;
}
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
/* Fix length of stacked components */
while ( compsp > 0 ) {
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
}
if ( pri_call_apdu_queue ( call , Q931_SETUP , buffer , i , NULL , NULL ) )
return - 1 ;
return 0 ;
}
2006-01-20 02:22:06 +08:00
/* Send the rltThirdParty: Invoke */
2006-01-20 02:31:48 +08:00
int rlt_initiate_transfer ( struct pri * pri , q931_call * c1 , q931_call * c2 )
2006-01-20 02:22:06 +08:00
{
int i = 0 ;
unsigned char buffer [ 256 ] ;
struct rose_component * comp = NULL , * compstk [ 10 ] ;
const unsigned char rlt_3rd_pty = RLT_THIRD_PARTY ;
q931_call * callwithid = NULL , * apdubearer = NULL ;
int compsp = 0 ;
if ( c2 - > transferable ) {
apdubearer = c1 ;
callwithid = c2 ;
} else if ( c1 - > transferable ) {
apdubearer = c2 ;
callwithid = c1 ;
} else
return - 1 ;
2006-01-20 07:27:27 +08:00
buffer [ i + + ] = ( Q932_PROTOCOL_ROSE ) ;
2006-01-20 02:22:06 +08:00
buffer [ i + + ] = ( 0x80 | RLT_SERVICE_ID ) ; /* Service Identifier octet */
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Invoke ID is set to the operation ID */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , rlt_3rd_pty ) ;
/* Operation Tag */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , rlt_3rd_pty ) ;
/* Additional RLT invoke info - Octet 12 */
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONSTRUCTOR | ASN1_SEQUENCE ) , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_WORDCOMP ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0 ) , buffer , i , callwithid - > rlt_call_id & 0xFFFFFF ) ; /* Length is 3 octets */
/* Reason for redirect - unused, set to 129 */
ASN1_ADD_BYTECOMP ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1 ) , buffer , i , 0 ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
if ( pri_call_apdu_queue ( apdubearer , Q931_FACILITY , buffer , i , NULL , NULL ) )
return - 1 ;
if ( q931_facility ( apdubearer - > pri , apdubearer ) ) {
pri_message ( pri , " Could not schedule facility message for call %d \n " , apdubearer - > cr ) ;
return - 1 ;
}
return 0 ;
}
static int add_dms100_transfer_ability_apdu ( struct pri * pri , q931_call * c )
{
int i = 0 ;
unsigned char buffer [ 256 ] ;
struct rose_component * comp = NULL , * compstk [ 10 ] ;
const unsigned char rlt_op_ind = RLT_OPERATION_IND ;
int compsp = 0 ;
2006-01-20 05:15:31 +08:00
buffer [ i + + ] = ( Q932_PROTOCOL_ROSE ) ; /* Note to self: DON'T set the EXT bit */
2006-01-20 02:22:06 +08:00
buffer [ i + + ] = ( 0x80 | RLT_SERVICE_ID ) ; /* Service Identifier octet */
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Invoke ID is set to the operation ID */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , rlt_op_ind ) ;
/* Operation Tag - basically the same as the invoke ID tag */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , rlt_op_ind ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
if ( pri_call_apdu_queue ( c , Q931_SETUP , buffer , i , NULL , NULL ) )
return - 1 ;
else
return 0 ;
}
2005-03-02 23:56:11 +08:00
/* Sending callername information functions */
2005-04-22 03:58:14 +08:00
static int add_callername_facility_ies ( struct pri * pri , q931_call * c , int cpe )
2005-03-02 23:56:11 +08:00
{
int res = 0 ;
int i = 0 ;
unsigned char buffer [ 256 ] ;
unsigned char namelen = 0 ;
struct rose_component * comp = NULL , * compstk [ 10 ] ;
int compsp = 0 ;
2005-04-22 05:58:21 +08:00
int mymessage = 0 ;
2005-03-02 23:56:11 +08:00
static unsigned char op_tag [ ] = {
0x2a , /* informationFollowing 42 */
0x86 ,
0x48 ,
0xce ,
0x15 ,
0x00 ,
0x04
} ;
if ( ! strlen ( c - > callername ) ) {
return - 1 ;
}
2005-04-05 11:55:58 +08:00
buffer [ i + + ] = ( ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS ) ;
2005-03-02 23:56:11 +08:00
/* Interpretation component */
2007-06-06 21:22:15 +08:00
if ( pri - > switchtype = = PRI_SWITCH_QSIG ) {
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_NFE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_BYTECOMP ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0 ) , buffer , i , 0 ) ;
ASN1_ADD_BYTECOMP ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2 ) , buffer , i , 0 ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
}
2005-03-02 23:56:11 +08:00
ASN1_ADD_BYTECOMP ( comp , COMP_TYPE_INTERPRETATION , buffer , i , 0 ) ;
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Invoke ID */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , get_invokeid ( pri ) ) ;
/* Operation Tag */
res = asn1_string_encode ( ASN1_OBJECTIDENTIFIER , & buffer [ i ] , sizeof ( buffer ) - i , sizeof ( op_tag ) , op_tag , sizeof ( op_tag ) ) ;
if ( res < 0 )
return - 1 ;
i + = res ;
ASN1_ADD_BYTECOMP ( comp , ASN1_ENUMERATED , buffer , i , 0 ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
2005-04-22 03:58:14 +08:00
if ( ! cpe ) {
if ( pri_call_apdu_queue ( c , Q931_SETUP , buffer , i , NULL , NULL ) )
return - 1 ;
}
2005-03-02 23:56:11 +08:00
2006-01-06 04:50:51 +08:00
/* Now the APDU that contains the information that needs sent.
2005-03-02 23:56:11 +08:00
* We can reuse the buffer since the queue function doesn ' t
* need it . */
i = 0 ;
namelen = strlen ( c - > callername ) ;
if ( namelen > 50 ) {
namelen = 50 ; /* truncate the name */
}
2005-04-05 11:55:58 +08:00
buffer [ i + + ] = ( ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS ) ;
2005-03-02 23:56:11 +08:00
/* Interpretation component */
2007-06-06 21:22:15 +08:00
if ( pri - > switchtype = = PRI_SWITCH_QSIG ) {
2007-06-07 05:58:22 +08:00
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_NFE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
2007-06-06 21:22:15 +08:00
ASN1_ADD_BYTECOMP ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0 ) , buffer , i , 0 ) ;
ASN1_ADD_BYTECOMP ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2 ) , buffer , i , 0 ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
}
2005-03-02 23:56:11 +08:00
ASN1_ADD_BYTECOMP ( comp , COMP_TYPE_INTERPRETATION , buffer , i , 0 ) ;
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* Invoke ID */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , get_invokeid ( pri ) ) ;
/* Operation ID: Calling name */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , SS_CNID_CALLINGNAME ) ;
2005-04-05 11:55:58 +08:00
res = asn1_string_encode ( ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0 ) , & buffer [ i ] , sizeof ( buffer ) - i , 50 , c - > callername , namelen ) ;
2005-03-02 23:56:11 +08:00
if ( res < 0 )
2005-04-22 03:58:14 +08:00
return - 1 ;
2005-03-02 23:56:11 +08:00
i + = res ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
2005-04-22 05:58:21 +08:00
if ( cpe )
mymessage = Q931_SETUP ;
else
mymessage = Q931_FACILITY ;
if ( pri_call_apdu_queue ( c , mymessage , buffer , i , NULL , NULL ) )
2005-03-02 23:56:11 +08:00
return - 1 ;
return 0 ;
}
/* End Callername */
/* MWI related encode and decode functions */
static void mwi_activate_encode_cb ( void * data )
{
return ;
}
2006-01-20 02:36:32 +08:00
int mwi_message_send ( struct pri * pri , q931_call * call , struct pri_sr * req , int activate )
2005-03-02 23:56:11 +08:00
{
int i = 0 ;
unsigned char buffer [ 255 ] = " " ;
int destlen = strlen ( req - > called ) ;
struct rose_component * comp = NULL , * compstk [ 10 ] ;
int compsp = 0 ;
int res ;
if ( destlen < = 0 ) {
return - 1 ;
} else if ( destlen > 20 )
destlen = 20 ; /* Destination number cannot be greater then 20 digits */
2005-04-05 11:55:58 +08:00
buffer [ i + + ] = ( ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS ) ;
2005-03-02 23:56:11 +08:00
/* Interpretation component */
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_NFE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
2005-04-05 11:55:58 +08:00
ASN1_ADD_BYTECOMP ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0 ) , buffer , i , 0 ) ;
ASN1_ADD_BYTECOMP ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2 ) , buffer , i , 0 ) ;
2005-03-02 23:56:11 +08:00
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_ADD_BYTECOMP ( comp , COMP_TYPE_INTERPRETATION , buffer , i , 0 ) ;
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , get_invokeid ( pri ) ) ;
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , ( activate ) ? SS_MWI_ACTIVATE : SS_MWI_DEACTIVATE ) ;
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONSTRUCTOR | ASN1_SEQUENCE ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
/* PartyNumber */
2005-04-05 11:55:58 +08:00
res = asn1_string_encode ( ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0 ) , & buffer [ i ] , sizeof ( buffer ) - i , destlen , req - > called , destlen ) ;
2005-03-02 23:56:11 +08:00
if ( res < 0 )
return - 1 ;
i + = res ;
/* Enumeration: basicService */
ASN1_ADD_BYTECOMP ( comp , ASN1_ENUMERATED , buffer , i , 1 /* contents: Voice */ ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
return pri_call_apdu_queue ( call , Q931_SETUP , buffer , i , mwi_activate_encode_cb , NULL ) ;
}
/* End MWI */
/* EECT functions */
2006-01-20 02:31:48 +08:00
int eect_initiate_transfer ( struct pri * pri , q931_call * c1 , q931_call * c2 )
2005-03-02 23:56:11 +08:00
{
int i = 0 ;
int res = 0 ;
unsigned char buffer [ 255 ] = " " ;
2007-09-06 23:11:29 +08:00
short call_reference = c2 - > cr ^ 0x8000 ; /* Let's do the trickery to make sure the flag is correct */
2005-03-02 23:56:11 +08:00
struct rose_component * comp = NULL , * compstk [ 10 ] ;
int compsp = 0 ;
static unsigned char op_tag [ ] = {
0x2A ,
0x86 ,
0x48 ,
0xCE ,
0x15 ,
0x00 ,
0x08 ,
} ;
2007-09-06 23:11:29 +08:00
buffer [ i + + ] = ( ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE ) ;
2005-03-02 23:56:11 +08:00
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , get_invokeid ( pri ) ) ;
res = asn1_string_encode ( ASN1_OBJECTIDENTIFIER , & buffer [ i ] , sizeof ( buffer ) - i , sizeof ( op_tag ) , op_tag , sizeof ( op_tag ) ) ;
if ( res < 0 )
return - 1 ;
i + = res ;
2005-04-05 11:55:58 +08:00
ASN1_ADD_SIMPLE ( comp , ( ASN1_SEQUENCE | ASN1_CONSTRUCTOR ) , buffer , i ) ;
2005-03-02 23:56:11 +08:00
ASN1_PUSH ( compstk , compsp , comp ) ;
2005-04-05 11:55:58 +08:00
ASN1_ADD_WORDCOMP ( comp , ASN1_INTEGER , buffer , i , call_reference ) ;
2005-03-02 23:56:11 +08:00
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
res = pri_call_apdu_queue ( c1 , Q931_FACILITY , buffer , i , NULL , NULL ) ;
if ( res ) {
2006-01-06 04:50:51 +08:00
pri_message ( pri , " Could not queue APDU in facility message \n " ) ;
2005-03-02 23:56:11 +08:00
return - 1 ;
}
/* Remember that if we queue a facility IE for a facility message we
* have to explicitly send the facility message ourselves */
res = q931_facility ( c1 - > pri , c1 ) ;
if ( res ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Could not schedule facility message for call %d \n " , c1 - > cr ) ;
2005-03-02 23:56:11 +08:00
return - 1 ;
}
return 0 ;
}
/* End EECT */
2005-04-05 11:55:58 +08:00
/* AOC */
static int aoc_aoce_charging_request_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len )
{
int chargingcase = - 1 ;
unsigned char * vdata = data ;
struct rose_component * comp = NULL ;
int pos1 = 0 ;
if ( pri - > debug & PRI_DEBUG_AOC )
2005-05-23 23:06:33 +08:00
dump_apdu ( pri , data , len ) ;
2005-04-05 11:55:58 +08:00
do {
GET_COMPONENT ( comp , pos1 , vdata , len ) ;
CHECK_COMPONENT ( comp , ASN1_ENUMERATED , " !! Invalid AOC Charging Request argument. Expected Enumerated (0x0A) but Received 0x%02X \n " ) ;
ASN1_GET_INTEGER ( comp , chargingcase ) ;
if ( chargingcase > = 0 & & chargingcase < = 2 ) {
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Channel %d/%d, Call %d - received AOC charging request - charging case: %i \n " ,
2005-04-05 11:55:58 +08:00
call - > ds1no , call - > channelno , call - > cr , chargingcase ) ;
} else {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! unkown AOC ChargingCase: 0x%02X " , chargingcase ) ;
2005-04-05 11:55:58 +08:00
chargingcase = - 1 ;
}
NEXT_COMPONENT ( comp , pos1 ) ;
} while ( pos1 < len ) ;
if ( pos1 < len ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Only reached position %i in %i bytes long AOC-E structure: " , pos1 , len ) ;
dump_apdu ( pri , data , len ) ;
2005-04-05 11:55:58 +08:00
return - 1 ; /* Aborted before */
}
return 0 ;
}
static int aoc_aoce_charging_unit_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len )
{
long chargingunits = 0 , chargetype = - 1 , temp , chargeIdentifier = - 1 ;
unsigned char * vdata = data ;
struct rose_component * comp1 = NULL , * comp2 = NULL , * comp3 = NULL ;
int pos1 = 0 , pos2 , pos3 , sublen2 , sublen3 ;
struct addressingdataelements_presentednumberunscreened chargednr ;
if ( pri - > debug & PRI_DEBUG_AOC )
2005-05-23 23:06:33 +08:00
dump_apdu ( pri , data , len ) ;
2005-04-05 11:55:58 +08:00
do {
GET_COMPONENT ( comp1 , pos1 , vdata , len ) ; /* AOCEChargingUnitInfo */
CHECK_COMPONENT ( comp1 , ASN1_SEQUENCE , " !! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but Received 0x%02X \n " ) ;
SUB_COMPONENT ( comp1 , pos1 ) ;
GET_COMPONENT ( comp1 , pos1 , vdata , len ) ;
switch ( comp1 - > type ) {
case ( ASN1_SEQUENCE | ASN1_CONSTRUCTOR ) : /* specificChargingUnits */
sublen2 = comp1 - > len ;
pos2 = pos1 ;
comp2 = comp1 ;
SUB_COMPONENT ( comp2 , pos2 ) ;
do {
GET_COMPONENT ( comp2 , pos2 , vdata , len ) ;
switch ( comp2 - > type ) {
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1 ) : /* RecordedUnitsList (0xA1) */
SUB_COMPONENT ( comp2 , pos2 ) ;
GET_COMPONENT ( comp2 , pos2 , vdata , len ) ;
CHECK_COMPONENT ( comp2 , ASN1_SEQUENCE , " !! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but received 0x02%X \n " ) ; /* RecordedUnits */
sublen3 = pos2 + comp2 - > len ;
pos3 = pos2 ;
comp3 = comp2 ;
SUB_COMPONENT ( comp3 , pos3 ) ;
do {
GET_COMPONENT ( comp3 , pos3 , vdata , len ) ;
switch ( comp3 - > type ) {
case ASN1_INTEGER : /* numberOfUnits */
ASN1_GET_INTEGER ( comp3 , temp ) ;
chargingunits + = temp ;
case ASN1_NULL : /* notAvailable */
break ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Don't know how to handle 0x%02X in AOC-E RecordedUnits \n " , comp3 - > type ) ;
2005-04-05 11:55:58 +08:00
}
NEXT_COMPONENT ( comp3 , pos3 ) ;
} while ( pos3 < sublen3 ) ;
if ( pri - > debug & PRI_DEBUG_AOC )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Channel %d/%d, Call %d - received AOC-E charging: %i unit%s \n " ,
2005-04-05 11:55:58 +08:00
call - > ds1no , call - > channelno , call - > cr , chargingunits , ( chargingunits = = 1 ) ? " " : " s " ) ;
break ;
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2 ) : /* AOCEBillingID (0xA2) */
SUB_COMPONENT ( comp2 , pos2 ) ;
GET_COMPONENT ( comp2 , pos2 , vdata , len ) ;
ASN1_GET_INTEGER ( comp2 , chargetype ) ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! not handled: Channel %d/%d, Call %d - received AOC-E billing ID: %i \n " ,
2005-04-05 11:55:58 +08:00
call - > ds1no , call - > channelno , call - > cr , chargetype ) ;
break ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Don't know how to handle 0x%02X in AOC-E RecordedUnitsList \n " , comp2 - > type ) ;
2005-04-05 11:55:58 +08:00
}
NEXT_COMPONENT ( comp2 , pos2 ) ;
} while ( pos2 < sublen2 ) ;
break ;
case ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1 ) : /* freeOfCharge (0x81) */
if ( pri - > debug & PRI_DEBUG_AOC )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Channel %d/%d, Call %d - received AOC-E free of charge \n " , call - > ds1no , call - > channelno , call - > cr ) ;
2005-04-05 11:55:58 +08:00
chargingunits = 0 ;
break ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Invalid AOC-E specificChargingUnits. Expected Sequence (0x30) or Object Identifier (0x81/0x01) but received 0x%02X \n " , comp1 - > type ) ;
2005-04-05 11:55:58 +08:00
}
NEXT_COMPONENT ( comp1 , pos1 ) ;
GET_COMPONENT ( comp1 , pos1 , vdata , len ) ; /* get optional chargingAssociation. will 'break' when reached end of structure */
switch ( comp1 - > type ) {
/* TODO: charged number is untested - please report! */
case ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0 ) : /* chargedNumber (0xA0) */
if ( rose_presented_number_unscreened_decode ( pri , call , comp1 - > data , comp1 - > len , & chargednr ) ! = 0 )
return - 1 ;
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! not handled: Received ChargedNr '%s' \n " , chargednr . partyaddress ) ;
pri_message ( pri , " ton = %d, pres = %d, npi = %d \n " , chargednr . ton , chargednr . pres , chargednr . npi ) ;
2005-04-05 11:55:58 +08:00
break ;
case ASN1_INTEGER :
ASN1_GET_INTEGER ( comp1 , chargeIdentifier ) ;
break ;
default :
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Invalid AOC-E chargingAssociation. Expected Object Identifier (0xA0) or Integer (0x02) but received 0x%02X \n " , comp1 - > type ) ;
2005-04-05 11:55:58 +08:00
}
NEXT_COMPONENT ( comp1 , pos1 ) ;
} while ( pos1 < len ) ;
if ( pos1 < len ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Only reached position %i in %i bytes long AOC-E structure: " , pos1 , len ) ;
dump_apdu ( pri , data , len ) ;
2005-04-05 11:55:58 +08:00
return - 1 ; /* oops - aborted before */
}
call - > aoc_units = chargingunits ;
return 0 ;
}
static int aoc_aoce_charging_unit_encode ( struct pri * pri , q931_call * c , long chargedunits )
{
/* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */
int i = 0 , res = 0 , compsp = 0 ;
unsigned char buffer [ 255 ] = " " ;
struct rose_component * comp = NULL , * compstk [ 10 ] ;
/* ROSE protocol (0x91)*/
buffer [ i + + ] = ( ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE ) ;
/* ROSE Component (0xA1,len)*/
ASN1_ADD_SIMPLE ( comp , COMP_TYPE_INVOKE , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* ROSE invokeId component (0x02,len,id)*/
ASN1_ADD_WORDCOMP ( comp , INVOKE_IDENTIFIER , buffer , i , + + pri - > last_invoke ) ;
/* ROSE operationId component (0x02,0x01,0x24)*/
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , ROSE_AOC_AOCE_CHARGING_UNIT ) ;
/* AOCEChargingUnitInfo (0x30,len) */
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONSTRUCTOR | ASN1_SEQUENCE ) , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
if ( chargedunits > 0 ) {
/* SpecificChargingUnits (0x30,len) */
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONSTRUCTOR | ASN1_SEQUENCE ) , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* RecordedUnitsList (0xA1,len) */
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1 ) , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* RecordedUnits (0x30,len) */
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONSTRUCTOR | ASN1_SEQUENCE ) , buffer , i ) ;
ASN1_PUSH ( compstk , compsp , comp ) ;
/* NumberOfUnits (0x02,len,charge) */
ASN1_ADD_BYTECOMP ( comp , ASN1_INTEGER , buffer , i , chargedunits ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
} else {
/* freeOfCharge (0x81,0) */
ASN1_ADD_SIMPLE ( comp , ( ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1 ) , buffer , i ) ;
}
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
ASN1_FIXUP ( compstk , compsp , buffer , i ) ;
if ( pri - > debug & PRI_DEBUG_AOC )
2005-05-23 23:06:33 +08:00
dump_apdu ( pri , buffer , i ) ;
2005-04-05 11:55:58 +08:00
/* code below is untested */
res = pri_call_apdu_queue ( c , Q931_FACILITY , buffer , i , NULL , NULL ) ;
if ( res ) {
2006-01-06 04:50:51 +08:00
pri_message ( pri , " Could not queue APDU in facility message \n " ) ;
2005-04-05 11:55:58 +08:00
return - 1 ;
}
/* Remember that if we queue a facility IE for a facility message we
* have to explicitly send the facility message ourselves */
res = q931_facility ( c - > pri , c ) ;
if ( res ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Could not schedule facility message for call %d \n " , c - > cr ) ;
2005-04-05 11:55:58 +08:00
return - 1 ;
}
return 0 ;
}
/* End AOC */
2005-03-02 23:56:11 +08:00
2006-01-20 02:36:32 +08:00
int rose_reject_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len )
2006-01-20 02:22:06 +08:00
{
int i = 0 ;
int problemtag = - 1 ;
int problem = - 1 ;
int invokeidvalue = - 1 ;
unsigned char * vdata = data ;
struct rose_component * comp = NULL ;
char * problemtagstr , * problemstr ;
do {
/* Invoke ID stuff */
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , INVOKE_IDENTIFIER , " Don't know what to do if first ROSE component is of type 0x%x \n " ) ;
ASN1_GET_INTEGER ( comp , invokeidvalue ) ;
NEXT_COMPONENT ( comp , i ) ;
GET_COMPONENT ( comp , i , vdata , len ) ;
problemtag = comp - > type ;
problem = comp - > data [ 0 ] ;
if ( pri - > switchtype = = PRI_SWITCH_DMS100 ) {
switch ( problemtag ) {
case 0x80 :
problemtagstr = " General problem " ;
break ;
case 0x81 :
problemtagstr = " Invoke problem " ;
break ;
case 0x82 :
problemtagstr = " Return result problem " ;
break ;
case 0x83 :
problemtagstr = " Return error problem " ;
break ;
default :
problemtagstr = " Unknown " ;
}
switch ( problem ) {
case 0x00 :
problemstr = " Unrecognized component " ;
break ;
case 0x01 :
problemstr = " Mistyped component " ;
break ;
case 0x02 :
problemstr = " Badly structured component " ;
break ;
default :
problemstr = " Unknown " ;
}
pri_error ( pri , " ROSE REJECT: \n " ) ;
pri_error ( pri , " \t INVOKE ID: 0x%X \n " , invokeidvalue ) ;
pri_error ( pri , " \t PROBLEM TYPE: %s (0x%x) \n " , problemtagstr , problemtag ) ;
pri_error ( pri , " \t PROBLEM: %s (0x%x) \n " , problemstr , problem ) ;
return 0 ;
} else {
pri_message ( pri , " Unable to handle return result on switchtype %d! \n " , pri - > switchtype ) ;
return - 1 ;
}
} while ( 0 ) ;
return - 1 ;
}
2006-01-20 02:36:32 +08:00
int rose_return_error_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len )
2006-01-20 02:22:06 +08:00
{
int i = 0 ;
int errorvalue = - 1 ;
int invokeidvalue = - 1 ;
unsigned char * vdata = data ;
struct rose_component * comp = NULL ;
char * invokeidstr , * errorstr ;
do {
/* Invoke ID stuff */
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , INVOKE_IDENTIFIER , " Don't know what to do if first ROSE component is of type 0x%x \n " ) ;
ASN1_GET_INTEGER ( comp , invokeidvalue ) ;
NEXT_COMPONENT ( comp , i ) ;
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , ASN1_INTEGER , " Don't know what to do if second component in return error is 0x%x \n " ) ;
ASN1_GET_INTEGER ( comp , errorvalue ) ;
if ( pri - > switchtype = = PRI_SWITCH_DMS100 ) {
switch ( invokeidvalue ) {
case RLT_OPERATION_IND :
invokeidstr = " RLT_OPERATION_IND " ;
break ;
case RLT_THIRD_PARTY :
invokeidstr = " RLT_THIRD_PARTY " ;
break ;
default :
invokeidstr = " Unknown " ;
}
switch ( errorvalue ) {
case 0x10 :
errorstr = " RLT Bridge Fail " ;
break ;
case 0x11 :
errorstr = " RLT Call ID Not Found " ;
break ;
case 0x12 :
errorstr = " RLT Not Allowed " ;
break ;
case 0x13 :
errorstr = " RLT Switch Equip Congs " ;
break ;
default :
errorstr = " Unknown " ;
}
pri_error ( pri , " ROSE RETURN ERROR: \n " ) ;
pri_error ( pri , " \t OPERATION: %s \n " , invokeidstr ) ;
pri_error ( pri , " \t ERROR: %s \n " , errorstr ) ;
return 0 ;
} else {
pri_message ( pri , " Unable to handle return result on switchtype %d! \n " , pri - > switchtype ) ;
return - 1 ;
}
} while ( 0 ) ;
return - 1 ;
}
2006-01-20 02:36:32 +08:00
int rose_return_result_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len )
2006-01-20 02:22:06 +08:00
{
int i = 0 ;
int operationidvalue = - 1 ;
int invokeidvalue = - 1 ;
unsigned char * vdata = data ;
struct rose_component * comp = NULL ;
do {
/* Invoke ID stuff */
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , INVOKE_IDENTIFIER , " Don't know what to do if first ROSE component is of type 0x%x \n " ) ;
ASN1_GET_INTEGER ( comp , invokeidvalue ) ;
NEXT_COMPONENT ( comp , i ) ;
if ( pri - > switchtype = = PRI_SWITCH_DMS100 ) {
switch ( invokeidvalue ) {
case RLT_THIRD_PARTY :
if ( pri - > debug & PRI_DEBUG_APDU ) pri_message ( pri , " Successfully completed RLT transfer! \n " ) ;
return 0 ;
case RLT_OPERATION_IND :
if ( pri - > debug & PRI_DEBUG_APDU ) pri_message ( pri , " Received RLT_OPERATION_IND \n " ) ;
/* Have to take out the rlt_call_id */
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , ASN1_SEQUENCE , " Protocol error detected in parsing RLT_OPERATION_IND return result! \n " ) ;
/* Traverse the contents of this sequence */
/* First is the Operation Value */
SUB_COMPONENT ( comp , i ) ;
GET_COMPONENT ( comp , i , vdata , len ) ;
CHECK_COMPONENT ( comp , ASN1_INTEGER , " RLT_OPERATION_IND should be of type ASN1_INTEGER! \n " ) ;
ASN1_GET_INTEGER ( comp , operationidvalue ) ;
if ( operationidvalue ! = RLT_OPERATION_IND ) {
pri_message ( pri , " Invalid Operation ID value (0x%x) in return result! \n " , operationidvalue ) ;
return - 1 ;
}
/* Next is the Call ID */
NEXT_COMPONENT ( comp , i ) ;
GET_COMPONENT ( comp , i , vdata , len ) ;
2006-01-20 06:18:01 +08:00
CHECK_COMPONENT ( comp , ASN1_TAG_0 , " Error check failed on Call ID! \n " ) ;
2006-01-20 02:22:06 +08:00
ASN1_GET_INTEGER ( comp , call - > rlt_call_id ) ;
/* We have enough data to transfer the call */
call - > transferable = 1 ;
return 0 ;
default :
pri_message ( pri , " Could not parse invoke of type 0x%x! \n " , invokeidvalue ) ;
return - 1 ;
}
} else {
pri_message ( pri , " Unable to handle return result on switchtype %d! \n " , pri - > switchtype ) ;
return - 1 ;
}
} while ( 0 ) ;
return - 1 ;
}
2006-01-20 02:36:32 +08:00
int rose_invoke_decode ( struct pri * pri , q931_call * call , unsigned char * data , int len )
2005-02-04 06:14:44 +08:00
{
int i = 0 ;
int operation_tag ;
unsigned char * vdata = data ;
struct rose_component * comp = NULL , * invokeid = NULL , * operationid = NULL ;
2005-04-05 11:55:58 +08:00
2005-02-04 06:14:44 +08:00
do {
/* Invoke ID stuff */
GET_COMPONENT ( comp , i , vdata , len ) ;
2006-02-14 07:07:56 +08:00
#if 0
2005-04-05 11:55:58 +08:00
CHECK_COMPONENT ( comp , INVOKE_IDENTIFIER , " Don't know what to do if first ROSE component is of type 0x%x \n " ) ;
2006-02-14 07:07:56 +08:00
# endif
2005-02-04 06:14:44 +08:00
invokeid = comp ;
NEXT_COMPONENT ( comp , i ) ;
2004-10-28 04:44:39 +08:00
2005-02-04 06:14:44 +08:00
/* Operation Tag */
GET_COMPONENT ( comp , i , vdata , len ) ;
2006-02-14 07:07:56 +08:00
#if 0
2005-02-04 06:14:44 +08:00
CHECK_COMPONENT ( comp , ASN1_INTEGER , " Don't know what to do if second ROSE component is of type 0x%x \n " ) ;
2006-02-14 07:07:56 +08:00
# endif
2005-02-04 06:14:44 +08:00
operationid = comp ;
ASN1_GET_INTEGER ( comp , operation_tag ) ;
NEXT_COMPONENT ( comp , i ) ;
2004-10-28 04:44:39 +08:00
2005-02-04 06:14:44 +08:00
/* No argument - return with error */
if ( i > = len )
return - 1 ;
/* Arguement Tag */
GET_COMPONENT ( comp , i , vdata , len ) ;
if ( ! comp - > type )
return - 1 ;
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " [ Handling operation %d ] \n " , operation_tag ) ;
2005-02-04 06:14:44 +08:00
switch ( operation_tag ) {
case SS_CNID_CALLINGNAME :
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Handle Name display operation \n " ) ;
2005-03-11 04:37:16 +08:00
switch ( comp - > type ) {
case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE :
memcpy ( call - > callername , comp - > data , comp - > len ) ;
call - > callername [ comp - > len ] = 0 ;
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Received caller name '%s' \n " , call - > callername ) ;
2005-03-11 04:37:16 +08:00
return 0 ;
default :
2005-04-05 11:55:58 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Do not handle argument of type 0x%X \n " , comp - > type ) ;
2005-03-11 04:37:16 +08:00
return - 1 ;
2005-02-04 06:14:44 +08:00
}
break ;
case ROSE_DIVERTING_LEG_INFORMATION2 :
2005-03-03 00:03:22 +08:00
if ( pri - > debug & PRI_DEBUG_APDU )
2005-05-23 23:06:33 +08:00
pri_message ( pri , " Handle DivertingLegInformation2 \n " ) ;
2005-06-04 02:29:25 +08:00
return rose_diverting_leg_information2_decode ( pri , call , comp , len - i ) ;
2005-04-05 11:55:58 +08:00
case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE :
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " ROSE %i: AOC No Charging Info Available - not handled! " , operation_tag ) ;
dump_apdu ( pri , comp - > data , comp - > len ) ;
2005-04-05 11:55:58 +08:00
}
return - 1 ;
case ROSE_AOC_CHARGING_REQUEST :
return aoc_aoce_charging_request_decode ( pri , call , ( u_int8_t * ) comp , comp - > len + 2 ) ;
case ROSE_AOC_AOCS_CURRENCY :
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " ROSE %i: AOC-S Currency - not handled! " , operation_tag ) ;
dump_apdu ( pri , ( u_int8_t * ) comp , comp - > len + 2 ) ;
2005-04-05 11:55:58 +08:00
}
return - 1 ;
case ROSE_AOC_AOCS_SPECIAL_ARR :
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " ROSE %i: AOC-S Special Array - not handled! " , operation_tag ) ;
dump_apdu ( pri , ( u_int8_t * ) comp , comp - > len + 2 ) ;
2005-04-05 11:55:58 +08:00
}
return - 1 ;
case ROSE_AOC_AOCD_CURRENCY :
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " ROSE %i: AOC-D Currency - not handled! " , operation_tag ) ;
dump_apdu ( pri , ( u_int8_t * ) comp , comp - > len + 2 ) ;
2005-04-05 11:55:58 +08:00
}
return - 1 ;
case ROSE_AOC_AOCD_CHARGING_UNIT :
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " ROSE %i: AOC-D Charging Unit - not handled! " , operation_tag ) ;
dump_apdu ( pri , ( u_int8_t * ) comp , comp - > len + 2 ) ;
2005-04-05 11:55:58 +08:00
}
return - 1 ;
case ROSE_AOC_AOCE_CURRENCY :
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " ROSE %i: AOC-E Currency - not handled! " , operation_tag ) ;
dump_apdu ( pri , ( u_int8_t * ) comp , comp - > len + 2 ) ;
2005-04-05 11:55:58 +08:00
}
return - 1 ;
case ROSE_AOC_AOCE_CHARGING_UNIT :
return aoc_aoce_charging_unit_decode ( pri , call , ( u_int8_t * ) comp , comp - > len + 2 ) ;
if ( 0 ) { /* the following function is currently not used - just to make the compiler happy */
aoc_aoce_charging_unit_encode ( pri , call , call - > aoc_units ) ; /* use this function to forward the aoc-e on a bridged channel */
return 0 ;
}
case ROSE_AOC_IDENTIFICATION_OF_CHARGE :
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " ROSE %i: AOC Identification Of Charge - not handled! " , operation_tag ) ;
dump_apdu ( pri , ( u_int8_t * ) comp , comp - > len + 2 ) ;
2005-04-05 11:55:58 +08:00
}
return - 1 ;
2005-02-04 06:14:44 +08:00
default :
2005-04-05 11:55:58 +08:00
if ( pri - > debug & PRI_DEBUG_APDU ) {
2005-05-23 23:06:33 +08:00
pri_message ( pri , " !! Unable to handle ROSE operation %d " , operation_tag ) ;
dump_apdu ( pri , ( u_int8_t * ) comp , comp - > len + 2 ) ;
2005-04-05 11:55:58 +08:00
}
2005-02-04 06:14:44 +08:00
return - 1 ;
2004-10-28 04:44:39 +08:00
}
2005-02-04 06:14:44 +08:00
} while ( 0 ) ;
return - 1 ;
2004-10-28 04:44:39 +08:00
}
2006-01-20 02:36:32 +08:00
int pri_call_apdu_queue ( q931_call * call , int messagetype , void * apdu , int apdu_len , void ( * function ) ( void * data ) , void * data )
2005-03-02 23:56:11 +08:00
{
struct apdu_event * cur = NULL ;
struct apdu_event * new_event = NULL ;
if ( ! call | | ! messagetype | | ! apdu | | ( apdu_len < 1 ) | | ( apdu_len > 255 ) )
return - 1 ;
new_event = malloc ( sizeof ( struct apdu_event ) ) ;
if ( new_event ) {
2005-03-11 04:37:16 +08:00
memset ( new_event , 0 , sizeof ( struct apdu_event ) ) ;
2005-03-02 23:56:11 +08:00
new_event - > message = messagetype ;
new_event - > callback = function ;
new_event - > data = data ;
memcpy ( new_event - > apdu , apdu , apdu_len ) ;
new_event - > apdu_len = apdu_len ;
} else {
2005-05-23 23:06:33 +08:00
pri_error ( call - > pri , " !! Malloc failed! \n " ) ;
2005-03-02 23:56:11 +08:00
return - 1 ;
}
if ( call - > apdus ) {
cur = call - > apdus ;
while ( cur - > next ) {
cur = cur - > next ;
}
cur - > next = new_event ;
} else
call - > apdus = new_event ;
return 0 ;
}
2006-01-20 02:36:32 +08:00
int pri_call_apdu_queue_cleanup ( q931_call * call )
2005-03-02 23:56:11 +08:00
{
struct apdu_event * cur_event = NULL , * free_event = NULL ;
if ( call & & call - > apdus ) {
cur_event = call - > apdus ;
while ( cur_event ) {
/* TODO: callbacks, some way of giving return res on status of apdu */
free_event = cur_event ;
cur_event = cur_event - > next ;
2005-03-11 04:37:16 +08:00
free ( free_event ) ;
2005-03-02 23:56:11 +08:00
}
call - > apdus = NULL ;
}
return 0 ;
}
2006-01-20 02:36:32 +08:00
int pri_call_add_standard_apdus ( struct pri * pri , q931_call * call )
2005-03-02 23:56:11 +08:00
{
2005-05-12 22:48:00 +08:00
if ( ! pri - > sendfacility )
return 0 ;
2005-03-02 23:56:11 +08:00
if ( pri - > switchtype = = PRI_SWITCH_QSIG ) { /* For Q.SIG it does network and cpe operations */
2005-10-05 01:35:48 +08:00
if ( call - > redirectingnum [ 0 ] )
2005-09-17 01:02:44 +08:00
rose_diverting_leg_information2_encode ( pri , call ) ;
2005-05-12 22:48:00 +08:00
add_callername_facility_ies ( pri , call , 1 ) ;
2005-10-05 01:35:48 +08:00
return 0 ;
2005-03-02 23:56:11 +08:00
}
2006-01-06 04:50:51 +08:00
#if 0
2005-03-02 23:56:11 +08:00
if ( pri - > localtype = = PRI_NETWORK ) {
switch ( pri - > switchtype ) {
case PRI_SWITCH_NI2 :
2005-04-22 03:58:14 +08:00
add_callername_facility_ies ( pri , call , 0 ) ;
break ;
default :
break ;
}
2005-10-05 01:35:48 +08:00
return 0 ;
2005-04-22 03:58:14 +08:00
} else if ( pri - > localtype = = PRI_CPE ) {
switch ( pri - > switchtype ) {
case PRI_SWITCH_NI2 :
add_callername_facility_ies ( pri , call , 1 ) ;
2005-03-02 23:56:11 +08:00
break ;
default :
break ;
}
2005-10-05 01:35:48 +08:00
return 0 ;
2005-03-02 23:56:11 +08:00
}
2006-01-06 04:50:51 +08:00
# else
if ( pri - > switchtype = = PRI_SWITCH_NI2 )
add_callername_facility_ies ( pri , call , ( pri - > localtype = = PRI_CPE ) ) ;
# endif
2005-04-22 03:58:14 +08:00
2006-01-20 02:22:06 +08:00
if ( ( pri - > switchtype = = PRI_SWITCH_DMS100 ) & & ( pri - > localtype = = PRI_CPE ) ) {
add_dms100_transfer_ability_apdu ( pri , call ) ;
}
2005-03-02 23:56:11 +08:00
return 0 ;
}