2007-02-11 16:01:32 +00:00
/*
2007-04-15 19:39:49 +00:00
* An implementation of Common ISDN API 2.0 for Asterisk
2007-02-11 16:01:32 +00:00
*
2008-02-05 11:16:25 +00:00
* Copyright ( C ) 2005 - 2008 Cytronics & Melware
2007-02-11 16:01:32 +00:00
* Copyright ( C ) 2007 Mario Goegel
*
* Armin Schindler < armin @ melware . de >
* Mario Goegel < m . goegel @ gmx . de >
*
* This program is free software and may be modified and
* distributed under the terms of the GNU Public License .
*/
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include "chan_capi20.h"
# include "chan_capi.h"
2007-04-15 20:29:12 +00:00
# include "chan_capi_utils.h"
2007-02-11 16:01:32 +00:00
# include "chan_capi_qsig.h"
2007-06-12 20:02:36 +00:00
# include "chan_capi_qsig_ecma.h"
2007-03-10 14:23:20 +00:00
# include "chan_capi_qsig_asn197ade.h"
# include "chan_capi_qsig_asn197no.h"
2007-02-11 16:01:32 +00:00
2007-12-06 19:07:28 +00:00
AST_MUTEX_DEFINE_STATIC ( qsig_verbose_lock ) ;
/*
* helper for < pbx > _verbose with different verbose settings
*/
void cc_qsig_verbose ( int c_d , char * text , . . . )
{
char line [ 4096 ] ;
va_list ap ;
va_start ( ap , text ) ;
vsnprintf ( line , sizeof ( line ) , text , ap ) ;
va_end ( ap ) ;
#if 0
{
FILE * fp ;
if ( ( fp = fopen ( " /tmp/cclog " , " a " ) ) ! = NULL ) {
fprintf ( fp , " %s " , line ) ;
fclose ( fp ) ;
}
}
# endif
if ( option_verbose > 4 ) {
if ( ( ! c_d ) | | ( ( c_d ) & & ( capiqsigdebug ) ) ) {
cc_mutex_lock ( & qsig_verbose_lock ) ;
cc_pbx_verbose ( line ) ;
cc_mutex_unlock ( & qsig_verbose_lock ) ;
}
}
}
/*!
* \ brief Encodes an ASN .1 string with type of string
*
* \ param asn1_type type of string like ASN1_OCTETSTRING
* \ param data pointer to target buffer
* \ param len size of target buffer
* \ param max_len of the string data
* \ param src source pointer for string
* \ param src_len string length
* \ return data length
*/
int cc_qsig_asn1_add_string2 ( 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 ;
}
2007-05-18 19:09:22 +00:00
/*!
* \ brief Encodes an ASN .1 string
2007-05-17 16:10:04 +00:00
*
2007-05-18 19:09:22 +00:00
* \ param buf destination pointer for string
* \ param idx index points to string position in buffer
* \ param data string
* \ param datalen string length
* \ return always zero
2007-03-10 14:23:20 +00:00
*/
2007-02-11 16:01:32 +00:00
unsigned int cc_qsig_asn1_add_string ( unsigned char * buf , int * idx , char * data , int datalen )
{
int myidx = * idx ;
if ( ( 1 + datalen + ( * idx ) ) > sizeof ( * buf ) ) {
2007-03-10 14:23:20 +00:00
/* String exceeds buffer size */
2007-02-11 16:01:32 +00:00
return - 1 ;
}
buf [ myidx + + ] = datalen ;
memcpy ( & buf [ myidx ] , data , datalen ) ;
myidx + = 1 + datalen ;
* idx = myidx ;
return 0 ;
}
2007-03-10 14:23:20 +00:00
/*
* Returns an string from ASN .1 encoded string
*/
2007-02-11 16:01:32 +00:00
unsigned int cc_qsig_asn1_get_string ( unsigned char * buf , int buflen , unsigned char * data )
{
int strsize ;
int myidx = 0 ;
strsize = data [ myidx + + ] ;
if ( strsize > buflen )
strsize = buflen - 1 ;
memcpy ( buf , & data [ myidx ] , strsize ) ;
2007-06-01 17:59:08 +00:00
buf [ strsize ] = 0 ;
/* don't increase strsize after closing zero - string ends at strsize ! */
2007-02-11 16:01:32 +00:00
return strsize ;
}
2007-03-10 14:23:20 +00:00
/*
* Encode ASN .1 Integer
*/
2007-02-11 16:01:32 +00:00
unsigned int cc_qsig_asn1_add_integer ( unsigned char * buf , int * idx , int value )
{
int myidx = * idx ;
int intlen = 1 ;
if ( ( unsigned int ) value > ( unsigned int ) 0xFFFF )
2007-03-10 14:23:20 +00:00
return - 1 ; /* no support at the moment */
2007-02-11 16:01:32 +00:00
if ( value > 255 )
2007-03-10 14:23:20 +00:00
intlen + + ; /* we need 2 bytes */
2007-02-11 16:01:32 +00:00
buf [ myidx + + ] = ASN1_INTEGER ;
buf [ myidx + + ] = intlen ;
if ( intlen > 1 ) {
buf [ myidx + + ] = ( unsigned char ) ( value > > 8 ) ;
buf [ myidx + + ] = ( unsigned char ) ( value - 0xff00 ) ;
} else {
buf [ myidx + + ] = ( unsigned char ) value ;
}
* idx = myidx ;
return 0 ;
}
2007-03-10 14:23:20 +00:00
/*
* Returns an Integer from ASN .1 Encoded Integer
*/
2007-02-11 16:01:32 +00:00
unsigned int cc_qsig_asn1_get_integer ( unsigned char * data , int * idx )
2007-03-10 14:23:20 +00:00
{ /* TODO: not conform with negative integers */
2007-02-11 16:01:32 +00:00
int myidx = * idx ;
int intlen ;
int temp ;
intlen = data [ myidx + + ] ;
2007-03-10 14:23:20 +00:00
if ( ( intlen < 1 ) | | ( intlen > 2 ) ) { /* i don't know if there's a bigger Integer as 16bit -> read specs */
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " ASN1Decode: Size of ASN.1 Integer not supported: %i \n " , intlen ) ;
2007-02-11 16:01:32 +00:00
* idx = myidx + intlen ;
return 0 ;
}
temp = ( char ) data [ myidx + + ] ;
if ( intlen = = 2 ) {
temp = ( temp < < 8 ) + data [ myidx + + ] ;
}
* idx = myidx ;
return temp ;
}
2007-03-10 14:23:20 +00:00
/*
* Returns an Human Readable OID from ASN .1 Encoded OID
*/
2007-04-15 17:41:36 +00:00
unsigned char * cc_qsig_asn1_oid2str ( unsigned char * data , int size )
2007-02-11 16:01:32 +00:00
{
2007-05-27 18:14:24 +00:00
unsigned char buf [ 1024 ] ;
char numbuf [ 10 ] ;
unsigned char * s ;
int len , i ;
unsigned long n ;
2007-04-15 17:41:36 +00:00
2007-05-27 18:14:24 +00:00
s = buf ;
if ( size < 3 ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " OID2STR: Object identifier too small (%i). \n " , size ) ;
2007-05-27 18:14:24 +00:00
return NULL ;
}
# define N(n) \
snprintf ( numbuf , sizeof numbuf , " %lu " , ( unsigned long ) n ) ; \
len = strlen ( numbuf ) ; \
memcpy ( s , numbuf , len ) ; \
s + = len ;
N ( data [ 0 ] / 40 )
* s + + = ' . ' ;
N ( data [ 0 ] % 40 )
n = 0 ;
for ( i = 1 ; i < size ; i + + ) {
n = n < < 7 | ( data [ i ] & 0x7f ) ;
if ( ( data [ i ] & 0x80 ) = = 0 ) {
* s + + = ' . ' ;
N ( n )
n = 0 ;
}
}
2007-06-01 17:59:08 +00:00
* s + + = 0 ;
2007-05-27 18:14:24 +00:00
s = buf ;
return ( unsigned char * ) strdup ( ( char * ) s ) ;
2007-04-15 17:41:36 +00:00
2007-02-11 16:01:32 +00:00
}
2007-03-10 14:23:20 +00:00
/*
* Check if OID is ECMA - ISDN ( 1.3 .12 .9 . * )
*/
2007-02-11 16:01:32 +00:00
signed int cc_qsig_asn1_check_ecma_isdn_oid ( unsigned char * data , int len )
{
2007-03-10 14:23:20 +00:00
/* 1.3 .12 .9 */
2007-02-11 16:01:32 +00:00
if ( ( data [ 0 ] = = 0x2B ) & & ( data [ 1 ] = = 0x0C ) & & ( data [ 2 ] = = 0x09 ) )
return 0 ;
return - 1 ;
}
2007-03-10 14:23:20 +00:00
/*
* This function simply updates the length informations of the facility struct
*/
2007-02-11 16:01:32 +00:00
void cc_qsig_update_facility_length ( unsigned char * buf , unsigned int idx )
{
buf [ 0 ] = idx ;
buf [ 2 ] = idx - 2 ;
}
2007-03-10 14:23:20 +00:00
/*
* Create Invoke Struct
*/
2007-04-24 18:43:38 +00:00
int cc_qsig_build_facility_struct ( unsigned char * buf , unsigned int * idx , int protocolvar , int apdu_interpr , struct cc_qsig_nfe * nfe )
2007-02-11 16:01:32 +00:00
{
2007-04-15 17:41:36 +00:00
int myidx = * idx ; /* we start with Index 1 - Byte 0 is Length of Facilitydataarray */
if ( ! myidx )
myidx + + ;
2007-02-11 16:01:32 +00:00
buf [ myidx + + ] = 0x1c ;
2007-03-10 14:23:20 +00:00
buf [ myidx + + ] = 0 ; /* Byte 2 length of Facilitydataarray */
2007-04-24 18:43:38 +00:00
buf [ myidx + + ] = 0x80 | protocolvar ; /* QSIG Facility */
2007-03-10 14:23:20 +00:00
/* TODO: Outsource following struct to an separate function */
buf [ myidx + + ] = COMP_TYPE_NFE ; /* Network Facility Extension */
buf [ myidx + + ] = 6 ; /* NFE Size hardcoded - not good */
buf [ myidx + + ] = 0x80 ; /* Source Entity */
2007-02-11 16:01:32 +00:00
buf [ myidx + + ] = 0x01 ;
2007-03-10 14:23:20 +00:00
buf [ myidx + + ] = 0x00 ; /* End PINX hardcoded */
buf [ myidx + + ] = 0x82 ; /* Dest. Entity */
2007-02-11 16:01:32 +00:00
buf [ myidx + + ] = 0x01 ;
2007-03-10 14:23:20 +00:00
buf [ myidx + + ] = 0x00 ; /* End PINX hardcoded */
buf [ myidx + + ] = COMP_TYPE_APDU_INTERP ; /* How to interpret this APDU */
buf [ myidx + + ] = 0x01 ; /* Length */
2007-02-11 16:01:32 +00:00
buf [ myidx + + ] = apdu_interpr ;
2007-03-10 14:23:20 +00:00
/* Here will follow now the Invoke */
2007-02-11 16:01:32 +00:00
* idx = myidx ;
cc_qsig_update_facility_length ( buf , myidx ) ;
return 0 ;
}
2007-03-10 14:23:20 +00:00
/*
* Add invoke to buf
*/
2007-04-19 18:18:42 +00:00
int cc_qsig_add_invoke ( unsigned char * buf , unsigned int * idx , struct cc_qsig_invokedata * invoke , struct capi_pvt * i )
2007-02-11 16:01:32 +00:00
{
2007-04-19 18:18:42 +00:00
unsigned char oid1 [ ] = { 0x2b , 0x0c , 0x09 , 0x00 } ;
2007-02-11 16:01:32 +00:00
int myidx = * idx ;
int invlenidx ;
int result ;
buf [ myidx + + ] = COMP_TYPE_INVOKE ;
2007-03-10 14:23:20 +00:00
invlenidx = myidx ; /* save the Invoke length index for later */
2007-02-11 16:01:32 +00:00
buf [ myidx + + ] = 0 ;
result = cc_qsig_asn1_add_integer ( buf , & myidx , invoke - > id ) ;
if ( result ) {
cc_log ( LOG_ERROR , " QSIG: Cannot add invoke, identifier is not encoded! \n " ) ;
return - 1 ;
}
2007-04-19 18:18:42 +00:00
if ( invoke - > descr_type = = - 1 ) {
switch ( i - > qsigfeat ) {
case QSIG_TYPE_ALCATEL_ECMA :
invoke - > descr_type = ASN1_OBJECTIDENTIFIER ;
/* Set ECMA/ETSI OID */
oid1 [ 3 ] = ( unsigned char ) invoke - > type ;
invoke - > oid_len = sizeof ( oid1 ) ;
memcpy ( invoke - > oid_bin , oid1 , sizeof ( oid1 ) ) ;
break ;
case QSIG_TYPE_HICOM_ECMAV2 :
invoke - > descr_type = ASN1_INTEGER ;
/* Leave type as it is */
break ;
default :
/* INVOKE is not encoded */
break ;
}
}
2007-02-11 16:01:32 +00:00
switch ( invoke - > descr_type ) {
case ASN1_INTEGER :
result = cc_qsig_asn1_add_integer ( buf , & myidx , invoke - > type ) ;
if ( result ) {
2007-05-27 18:14:24 +00:00
cc_log ( LOG_ERROR , " QSIG: Cannot add invoke, type is not encoded! \n " ) ;
2007-02-11 16:01:32 +00:00
return - 1 ;
}
break ;
case ASN1_OBJECTIDENTIFIER :
if ( ( invoke - > oid_len < 1 ) | | ( invoke - > oid_len > 20 ) ) {
cc_log ( LOG_ERROR , " QSIG: Cannot add invoke, OID is too big! \n " ) ;
return - 1 ;
}
buf [ myidx + + ] = ASN1_OBJECTIDENTIFIER ;
buf [ myidx + + ] = invoke - > oid_len ;
memcpy ( & buf [ myidx ] , invoke - > oid_bin , invoke - > oid_len ) ;
myidx + = invoke - > oid_len ;
break ;
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unknown Invoke Type, not encoded (%i) \n " , invoke - > descr_type ) ;
2007-02-11 16:01:32 +00:00
return - 1 ;
break ;
}
2007-03-10 14:23:20 +00:00
if ( invoke - > datalen > 0 ) { /* may be no error, if there's no data */
2007-02-11 16:01:32 +00:00
memcpy ( & buf [ myidx ] , invoke - > data , invoke - > datalen ) ;
myidx + = invoke - > datalen ;
}
2007-03-28 19:24:55 +00:00
buf [ invlenidx ] = myidx - invlenidx - 1 ;
2007-02-11 16:01:32 +00:00
cc_qsig_update_facility_length ( buf , myidx - 1 ) ;
* idx = myidx ;
return 0 ;
}
2007-03-10 14:23:20 +00:00
/*
* Valid QSIG - Facility ?
* Returns 0 if not
*/
unsigned int cc_qsig_check_facility ( unsigned char * data , int * idx , int * apduval , int protocol )
2007-02-11 16:01:32 +00:00
{
int myidx = * idx ;
2007-05-31 20:28:03 +00:00
char * APDU_STR [ ] = { " IGNORE " , " REJECT CALL " , " CLEAR CALL " } ;
2007-02-11 16:01:32 +00:00
2007-03-10 14:23:20 +00:00
/* First byte after Facility Length */
2007-05-18 19:09:22 +00:00
if ( data [ myidx ] ! = ( unsigned char ) ( 0x80 | protocol ) ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: received protocol 0x%#x not configured! \n " , ( data [ myidx ] ^ = 0x80 ) ) ;
2007-05-18 19:09:22 +00:00
return 0 ;
2007-02-11 16:01:32 +00:00
}
2007-05-18 19:09:22 +00:00
myidx + + ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Supplementary Services \n " ) ;
2007-05-18 19:09:22 +00:00
if ( data [ myidx ] = = ( unsigned char ) COMP_TYPE_NFE ) {
myidx + + ;
/* TODO: Check Entities? */
myidx + = data [ myidx ] + 1 ;
* idx = myidx ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Facility has NFE struct \n " ) ;
2007-05-18 19:09:22 +00:00
}
if ( ( data [ myidx ] = = ( unsigned char ) COMP_TYPE_APDU_INTERP ) ) {
myidx + + ;
myidx + = data [ myidx ] ;
* apduval = data [ myidx + + ] ;
/* TODO: implement real reject or clear call ? */
* idx = myidx ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Facility has APDU - What to do if INVOKE is unknown: %s \n " , APDU_STR [ * apduval ] ) ;
2007-05-18 19:09:22 +00:00
}
return 1 ;
2007-02-11 16:01:32 +00:00
}
2007-03-10 14:23:20 +00:00
/*
* Is this an INVOKE component ?
* when not return - 1 , set idx to next byte ( length of component ? )
* * * * check idx in this case , that we are not out of range - maybe we got an unknown component then
* when it is an invoke , return invoke length and set idx to first byte of component
*
*/
2007-02-11 16:01:32 +00:00
signed int cc_qsig_check_invoke ( unsigned char * data , int * idx )
{
int myidx = * idx ;
2007-04-15 17:41:36 +00:00
if ( data [ myidx + + ] = = ( unsigned char ) COMP_TYPE_INVOKE ) {
/* is an INVOKE */
* idx = myidx ; /* Set index to length byte of component */
2007-03-10 14:23:20 +00:00
return data [ myidx + 1 ] ; /* return component length */
2007-02-11 16:01:32 +00:00
}
2007-04-15 17:41:36 +00:00
* idx + = data [ myidx ] ; /* we can end here, if it is an Invoke Result or Error */
2007-03-10 14:23:20 +00:00
return - 1 ; /* what to do now? got no Invoke */
2007-02-11 16:01:32 +00:00
}
2007-03-10 14:23:20 +00:00
/*
* Get Invoke ID
* returns current index
* idx points to next byte in array
*/
2007-02-11 16:01:32 +00:00
signed int cc_qsig_get_invokeid ( unsigned char * data , int * idx , struct cc_qsig_invokedata * invoke )
{
int myidx ;
int invidtype = 0 ;
int invlen = 0 ;
int invoffset ;
int temp = 0 ;
myidx = * idx ;
invoffset = myidx ;
invlen = data [ myidx + + ] ;
if ( invlen > 0 ) {
2007-03-10 14:23:20 +00:00
invoke - > len = invlen ; /* set Length of Invoke struct */
invoke - > offset = invoffset ; /* offset in Facility Array, where the Invoke Data starts */
invidtype = data [ myidx + + ] ; /* Get INVOKE Id Type */
2007-02-11 16:01:32 +00:00
if ( invidtype ! = ASN1_INTEGER ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unknown Invoke Identifier Type 0x%#x \n " , invidtype ) ;
2007-02-11 16:01:32 +00:00
return - 1 ;
}
2007-03-10 14:23:20 +00:00
temp = cc_qsig_asn1_get_integer ( data , & myidx ) ;
2007-02-11 16:01:32 +00:00
invoke - > id = temp ;
2007-03-10 14:23:20 +00:00
* idx = myidx ;
2007-02-11 16:01:32 +00:00
}
return 0 ;
}
2007-03-10 14:23:20 +00:00
/*
* fill the Invoke struct with all the invoke data
*/
2007-02-11 16:01:32 +00:00
signed int cc_qsig_fill_invokestruct ( unsigned char * data , int * idx , struct cc_qsig_invokedata * invoke , int apduval )
{
int myidx = * idx ;
int invoptyp ;
int temp ;
int temp2 ;
int datalen ;
2007-03-10 14:23:20 +00:00
invoptyp = data [ myidx + + ] ; /* Invoke Operation Type 0x02=INTEGER, 0x06=OID */
2007-02-11 16:01:32 +00:00
switch ( invoptyp ) {
case ASN1_INTEGER :
invoke - > apdu_interpr = apduval ;
2007-03-10 14:23:20 +00:00
temp = cc_qsig_asn1_get_integer ( data , & myidx ) ;
2007-02-11 16:01:32 +00:00
invoke - > descr_type = ASN1_INTEGER ;
invoke - > type = temp ;
2007-03-10 14:23:20 +00:00
temp2 = ( invoke - > len ) + ( invoke - > offset ) + 1 ; /* Array End = Invoke Length + Invoke Offset +1 */
2007-02-11 16:01:32 +00:00
datalen = temp2 - myidx ;
if ( datalen > 255 ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unsupported INVOKE Operation Size (max 255 Bytes): %i \n " , datalen ) ;
2007-02-11 16:01:32 +00:00
datalen = 255 ;
}
invoke - > datalen = datalen ;
2007-03-10 14:23:20 +00:00
memcpy ( invoke - > data , & data [ myidx ] , datalen ) ; /* copy data of Invoke Operation */
2007-05-18 19:09:22 +00:00
myidx + = datalen ; /* points to next INVOKE component, if there's any */
2007-02-11 16:01:32 +00:00
* idx = myidx ;
break ;
case ASN1_OBJECTIDENTIFIER :
invoke - > apdu_interpr = apduval ;
invoke - > descr_type = ASN1_OBJECTIDENTIFIER ;
2007-03-10 14:23:20 +00:00
temp = data [ myidx + + ] ; /* Length of OID */
2007-02-11 16:01:32 +00:00
if ( temp > 20 ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unsupported INVOKE Operation OID Size (max 20 Bytes): %i \n " , temp ) ;
2007-02-11 16:01:32 +00:00
temp = 20 ;
}
2007-03-10 14:23:20 +00:00
/* TODO: Maybe we decode the OID here and be verbose - have to write cc_qsig_asn1get_oid */
2007-02-11 16:01:32 +00:00
invoke - > oid_len = temp ;
2007-03-10 14:23:20 +00:00
memcpy ( invoke - > oid_bin , & data [ myidx ] , temp ) ; /* Copy OID to separate array */
myidx = myidx + temp ; /* Set index to next information */
2007-02-11 16:01:32 +00:00
2007-05-27 18:14:24 +00:00
if ( temp = = 4 ) { /* even if we have an OID, set the numeric invoke type */
invoke - > type = ( int ) invoke - > oid_bin [ 3 ] ;
} else {
invoke - > type = - 1 ;
}
2007-03-10 14:23:20 +00:00
temp2 = ( invoke - > len ) + ( invoke - > offset ) + 1 ; /* Array End = Invoke Length + Invoke Offset +1 */
2007-02-11 16:01:32 +00:00
datalen = temp2 - myidx ;
if ( datalen > 255 ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unsupported INVOKE Operation Size (max 255 Bytes): %i \n " , datalen ) ;
2007-02-11 16:01:32 +00:00
datalen = 255 ;
}
invoke - > datalen = datalen ;
2007-03-10 14:23:20 +00:00
memcpy ( invoke - > data , & data [ myidx ] , datalen ) ; /* copy data of Invoke Operation */
2007-05-18 19:09:22 +00:00
myidx + = datalen ; /* points to next INVOKE component, if there's any */
2007-02-11 16:01:32 +00:00
* idx = myidx ;
break ;
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unknown INVOKE Operation Type: %i \n " , invoptyp ) ;
2007-02-11 16:01:32 +00:00
2007-03-10 14:23:20 +00:00
temp2 = ( invoke - > len ) + ( invoke - > offset ) + 1 ; /* Array End = Invoke Length + Invoke Offset +1 */
2007-02-11 16:01:32 +00:00
datalen = temp2 - myidx ;
if ( datalen > 255 ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unsupported INVOKE Operation Size (max 255 Bytes): %i \n " , datalen ) ;
2007-02-11 16:01:32 +00:00
datalen = 255 ;
}
2007-05-18 19:09:22 +00:00
* idx = myidx + datalen ; /* Set index to next INVOKE, if there's any */
2007-02-11 16:01:32 +00:00
return - 1 ;
break ;
}
2007-03-10 14:23:20 +00:00
return 0 ; /* No problems */
2007-02-11 16:01:32 +00:00
}
2007-05-27 18:14:24 +00:00
static int ident_qsig_invoke ( int invoketype )
{
switch ( invoketype ) {
case 0 :
case 1 :
case 2 :
case 3 :
return CCQSIG__ECMA__NAMEPRES ;
case 4 :
return CCQSIG__ECMA__PRPROPOSE ;
2007-06-07 19:24:32 +00:00
case 12 :
return CCQSIG__ECMA__CTCOMPLETE ;
2007-05-27 18:14:24 +00:00
case 21 :
return CCQSIG__ECMA__LEGINFO2 ;
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_4 " QSIG: Unhandled QSIG INVOKE (%i) \n " , invoketype ) ;
2007-05-27 18:14:24 +00:00
return - 1 ;
}
}
2007-03-10 14:23:20 +00:00
/*
* Identify an INVOKE and return our own Ident Integer ( CCQSIG__ * )
*/
signed int cc_qsig_identifyinvoke ( struct cc_qsig_invokedata * invoke , int protocol )
2007-02-11 16:01:32 +00:00
{
int invokedescrtype = 0 ;
int datalen ;
2007-12-06 19:07:28 +00:00
/* cc_qsig_verbose( 1, VERBOSE_PREFIX_4 "CONNECT_IND (Ident Invoke %i)\n", invoke->descr_type); */
2007-02-11 16:01:32 +00:00
2007-03-10 14:23:20 +00:00
switch ( protocol ) {
case QSIG_TYPE_ALCATEL_ECMA :
switch ( invoke - > descr_type ) {
case ASN1_INTEGER :
invokedescrtype = 1 ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: INVOKE OP (%i) \n " , invoke - > type ) ;
2007-05-27 18:14:24 +00:00
return ident_qsig_invoke ( invoke - > type ) ;
2007-03-10 14:23:20 +00:00
break ;
case ASN1_OBJECTIDENTIFIER :
invokedescrtype = 2 ;
datalen = invoke - > oid_len ;
2007-05-27 18:14:24 +00:00
unsigned char * oidstr = NULL ;
oidstr = cc_qsig_asn1_oid2str ( invoke - > oid_bin , invoke - > oid_len ) ;
if ( oidstr ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: INVOKE OP (%s) \n " , oidstr ) ;
2007-05-27 18:14:24 +00:00
free ( oidstr ) ;
2007-06-01 17:59:08 +00:00
} else {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: INVOKE OP (unknown - OID not displayable) \n " ) ;
2007-05-27 18:14:24 +00:00
}
2007-03-10 14:23:20 +00:00
if ( ( datalen ) = = 4 ) {
if ( ! cc_qsig_asn1_check_ecma_isdn_oid ( invoke - > oid_bin , datalen ) ) {
2007-05-27 18:14:24 +00:00
return ident_qsig_invoke ( ( int ) invoke - > oid_bin [ 3 ] ) ;
2007-03-10 14:23:20 +00:00
}
}
2007-05-27 18:14:24 +00:00
return - 1 ;
2007-03-10 14:23:20 +00:00
break ;
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unidentified INVOKE OP \n " ) ;
2007-03-10 14:23:20 +00:00
break ;
}
2007-02-11 16:01:32 +00:00
break ;
2007-03-10 14:23:20 +00:00
case QSIG_TYPE_HICOM_ECMAV2 :
switch ( invoke - > descr_type ) {
case ASN1_INTEGER :
invokedescrtype = 1 ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: INVOKE OP (%i) \n " , invoke - > type ) ;
2007-05-27 18:14:24 +00:00
return ident_qsig_invoke ( invoke - > type ) ;
2007-03-10 14:23:20 +00:00
break ;
case ASN1_OBJECTIDENTIFIER :
invokedescrtype = 2 ;
2007-04-15 17:41:36 +00:00
datalen = invoke - > oid_len ;
2007-05-27 18:14:24 +00:00
unsigned char * oidstr = NULL ;
oidstr = cc_qsig_asn1_oid2str ( invoke - > oid_bin , invoke - > oid_len ) ;
if ( oidstr ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: INVOKE OP (%s) \n " , oidstr ) ;
2007-05-27 18:14:24 +00:00
free ( oidstr ) ;
2007-06-01 17:59:08 +00:00
} else {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: INVOKE OP (unknown - OID not displayable) \n " ) ;
2007-05-27 18:14:24 +00:00
}
2007-04-15 17:41:36 +00:00
if ( ( datalen ) = = 4 ) {
if ( ! cc_qsig_asn1_check_ecma_isdn_oid ( invoke - > oid_bin , datalen ) ) {
2007-05-27 18:14:24 +00:00
return ident_qsig_invoke ( ( int ) invoke - > oid_bin [ 3 ] ) ;
2007-04-15 17:41:36 +00:00
}
}
2007-03-10 14:23:20 +00:00
break ;
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Unidentified INVOKE OP \n " ) ;
2007-03-10 14:23:20 +00:00
break ;
2007-02-11 16:01:32 +00:00
}
break ;
default :
break ;
}
2007-05-18 19:09:22 +00:00
return - 1 ;
2007-02-11 16:01:32 +00:00
}
2007-06-12 20:02:36 +00:00
/*
* find the interface ( pvt ) the PLCI belongs to
*/
static struct capi_pvt * capi_find_interface_bynumber ( char * num )
{
struct capi_pvt * i ;
if ( ! num )
return NULL ;
for ( i = capi_iflist ; i ; i = i - > next ) {
if ( strcmp ( i - > cid , num ) = = 0 | |
strcmp ( i - > dnid , num ) = = 0 )
return i ;
}
#if 0
cc_mutex_lock ( & nullif_lock ) ;
for ( i = nulliflist ; i ; i = i - > next ) {
if ( strcmp ( i - > cid , num ) = = 0 | |
strcmp ( i - > dnid , num ) = = 0 )
break ;
}
cc_mutex_unlock ( & nullif_lock ) ;
# endif
return i ;
}
2007-06-07 19:24:32 +00:00
static void pbx_capi_qsig_handle_ctc ( struct cc_qsig_invokedata * invoke , struct capi_pvt * i )
{
2007-06-12 20:02:36 +00:00
struct cc_qsig_ctcomplete ctc ;
struct capi_pvt * ii ;
2007-07-05 19:48:19 +00:00
# define CLEAR_CTC { if (ctc.redirectionNumber.partyNumber) free_null(ctc.redirectionNumber.partyNumber);\
if ( ctc . basicCallInfoElements ) free_null ( ctc . basicCallInfoElements ) ; \
if ( ctc . redirectionName ) free_null ( ctc . redirectionName ) ; \
if ( ctc . argumentExtension ) free_null ( ctc . argumentExtension ) ; }
2007-06-12 20:02:36 +00:00
int res = cc_qsig_decode_ecma_calltransfer ( invoke , i , & ctc ) ;
2007-06-07 19:24:32 +00:00
2007-06-12 20:02:36 +00:00
if ( ! res )
return ;
2007-07-05 19:48:19 +00:00
if ( ctc . redirectionNumber . partyNumber & & ( ctc . endDesignation = = 0 ) ) {
2007-06-12 20:02:36 +00:00
ii = capi_find_interface_bynumber ( ctc . redirectionNumber . partyNumber ) ;
if ( ii ) {
2007-07-05 19:48:19 +00:00
char * prpn = i - > qsig_data . if_pr_propose_pn ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Call Transfer partner channel for %s found at channel %s, bridging possible. \n " , ctc . redirectionNumber . partyNumber , ii - > vname ) ;
2007-06-12 20:02:36 +00:00
2007-07-05 19:48:19 +00:00
if ( ! ( strlen ( prpn ) ) ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Path Replacement not configured, bridging not available! \n " ) ;
2007-07-05 19:48:19 +00:00
} else {
unsigned char fac [ CAPI_MAX_FACILITYDATAARRAY_SIZE ] ;
2007-06-12 20:02:36 +00:00
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: Trying to bridge with Path Replacement number %s... \n " , prpn ) ;
2007-07-05 19:48:19 +00:00
switch ( ii - > state ) {
case CAPI_STATE_ALERTING :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: peer is in state ALERTING, PATH REPLACE follows after CONNECT... \n " ) ;
2007-07-05 19:48:19 +00:00
ii - > qsig_data . pr_propose_cid = strdup ( " 123 " ) ; /* HACK: need an dynamic ID */
ii - > qsig_data . pr_propose_pn = strdup ( i - > qsig_data . if_pr_propose_pn ) ;
ii - > qsig_data . pr_propose_doinboundbridge = 1 ;
i - > qsig_data . pr_propose_doinboundbridge = 1 ;
i - > qsig_data . partner_plci = ii - > PLCI ;
break ;
case CAPI_STATE_CONNECTED :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: peer is CONNECTED... \n " ) ;
2007-07-05 19:48:19 +00:00
i - > qsig_data . pr_propose_cid = strdup ( " 123 " ) ; /* HACK: need an dynamic ID */
i - > qsig_data . pr_propose_pn = strdup ( i - > qsig_data . if_pr_propose_pn ) ;
ii - > qsig_data . pr_propose_doinboundbridge = 1 ;
ii - > qsig_data . partner_plci = i - > PLCI ;
cc_qsig_do_facility ( fac , i - > owner , NULL , 4 , 0 ) ;
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" ()(()()()s) " , fac ) ;
i - > qsig_data . pr_propose_cid = NULL ;
i - > qsig_data . pr_propose_pn = NULL ;
break ;
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " QSIG: peer's state is %i, which is not handled yet... \n " , ii - > state ) ;
2007-07-05 19:48:19 +00:00
break ;
}
}
CLEAR_CTC
2007-06-12 20:02:36 +00:00
}
2007-06-07 19:24:32 +00:00
}
2007-07-05 19:48:19 +00:00
CLEAR_CTC
2007-06-12 20:02:36 +00:00
2007-06-07 19:24:32 +00:00
return ;
}
2007-03-10 14:23:20 +00:00
/*
2007-06-07 19:24:32 +00:00
* Handle inbound INVOKEs
2007-03-10 14:23:20 +00:00
*/
2007-02-11 16:01:32 +00:00
unsigned int cc_qsig_handle_invokeoperation ( int invokeident , struct cc_qsig_invokedata * invoke , struct capi_pvt * i )
{
switch ( invokeident ) {
case CCQSIG__ECMA__NAMEPRES :
cc_qsig_op_ecma_isdn_namepres ( invoke , i ) ;
break ;
2007-04-15 17:41:36 +00:00
case CCQSIG__ECMA__PRPROPOSE :
cc_qsig_op_ecma_isdn_prpropose ( invoke , i ) ;
break ;
2007-06-07 19:24:32 +00:00
case CCQSIG__ECMA__CTCOMPLETE :
pbx_capi_qsig_handle_ctc ( invoke , i ) ;
break ;
2007-03-10 14:23:20 +00:00
case CCQSIG__ECMA__LEGINFO2 :
cc_qsig_op_ecma_isdn_leginfo2 ( invoke , i ) ;
break ;
2007-02-11 16:01:32 +00:00
default :
break ;
}
return 0 ;
}
2007-05-18 19:09:22 +00:00
/**
* Handles incoming facilities
*
* @ internal
* @ param data facility buffer
* @ param i points to capip_pvt struct
* @ param idx index in facility buffer
* @ param faclen facility length
* @ param protocoltype Q932_PROTOCOL_ROSE | Q932_PROTOCOL_EXTENSIONS
* @ return zero
*/
static int qsig_handle_q932facility ( unsigned char * data , struct capi_pvt * i , int * idx , int faclen , int protocoltype )
{
int facidx = * idx ;
int action_unkn_apdu ; /* What to do with unknown Invoke-APDUs (0=Ignore, 1=clear call, 2=reject APDU) */
struct cc_qsig_invokedata invoke ;
int invoke_len ;
int invoketmp1 ;
unsigned int invoke_op = 0 ; /* Invoke Operation ID */
if ( cc_qsig_check_facility ( data , & facidx , & action_unkn_apdu , protocoltype ) ) {
while ( ( facidx ) < faclen ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Checking INVOKE at index %i (of %i) \n " , facidx , faclen ) ;
2007-05-18 19:09:22 +00:00
invoke_len = cc_qsig_check_invoke ( data , & facidx ) ;
if ( invoke_len > 0 ) {
if ( cc_qsig_get_invokeid ( data , & facidx , & invoke ) = = 0 ) {
invoketmp1 = cc_qsig_fill_invokestruct ( data , & facidx , & invoke , action_unkn_apdu ) ;
invoke_op = cc_qsig_identifyinvoke ( & invoke , i - > qsigfeat ) ;
if ( invoke_op < 0 ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Invoke not identified! \n " ) ;
2007-05-18 19:09:22 +00:00
}
cc_qsig_handle_invokeoperation ( invoke_op , & invoke , i ) ;
}
} else {
/* Not an Invoke */
}
}
} else { /* kill endlessloop */
facidx + = faclen ;
}
* idx = facidx ;
return 0 ;
}
2007-02-11 16:01:32 +00:00
/*
* Handles incoming Indications from CAPI
*/
unsigned int cc_qsig_handle_capiind ( unsigned char * data , struct capi_pvt * i )
{
2007-04-20 18:29:29 +00:00
int faclen0 = 0 ;
2007-03-10 14:23:20 +00:00
int faclen = 0 ;
2007-02-11 16:01:32 +00:00
int facidx = 2 ;
2007-06-07 19:24:32 +00:00
if ( ! i - > qsigfeat )
return 0 ;
2007-04-20 18:29:29 +00:00
if ( ! data ) {
return 0 ;
}
faclen0 = data [ facidx - 2 ] ; /* Length of facility array - there may be more facilities encoded in this struct */
faclen = data [ facidx + + ] ;
2007-05-18 19:09:22 +00:00
faclen + = facidx ;
2007-04-20 18:29:29 +00:00
while ( facidx < faclen0 ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Checking Facility at index %i \n " , facidx ) ;
2007-04-20 18:29:29 +00:00
switch ( i - > qsigfeat ) {
case QSIG_TYPE_ALCATEL_ECMA :
2007-05-18 19:09:22 +00:00
qsig_handle_q932facility ( data , i , & facidx , faclen , Q932_PROTOCOL_ROSE ) ;
2007-04-20 18:29:29 +00:00
break ;
case QSIG_TYPE_HICOM_ECMAV2 :
2007-05-18 19:09:22 +00:00
qsig_handle_q932facility ( data , i , & facidx , faclen , Q932_PROTOCOL_EXTENSIONS ) ;
2007-04-20 18:29:29 +00:00
break ;
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Unknown QSIG protocol configured (%i) \n " , i - > qsigfeat ) ;
2007-04-20 18:29:29 +00:00
break ;
}
if ( facidx < faclen0 ) { /* there may follow a new facility */
if ( data [ facidx ] = = 0x1c ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Found another facility at index %i \n " , facidx ) ;
2007-04-20 18:29:29 +00:00
facidx + + ;
faclen = data [ facidx + + ] ;
faclen + = facidx ;
} else {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " More data found in facility at index %i, but this is not an facility (%#x) \n " , facidx , data [ facidx ] ) ;
2007-04-20 18:29:29 +00:00
facidx + + ; /* don't start an endlessloop */
2007-02-11 16:01:32 +00:00
}
}
}
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Facility done at index %i from %i \n " , facidx , faclen ) ;
2007-05-18 19:09:22 +00:00
return 1 ;
2007-04-15 17:41:36 +00:00
}
/*
* Handles incoming Facility Indications from CAPI
*/
unsigned int cc_qsig_handle_capi_facilityind ( unsigned char * data , struct capi_pvt * i )
{
int faclen = 0 ;
int facidx = 0 ;
2007-05-18 19:09:22 +00:00
2007-04-15 17:41:36 +00:00
if ( ! data ) {
return 0 ;
}
faclen = data [ facidx + + ] ;
2007-12-06 19:07:28 +00:00
/* cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "CONNECT_IND (Got Facility IE, Length=%#x)\n", faclen); */
2007-04-15 17:41:36 +00:00
while ( facidx < faclen ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Checking Facility at index %i \n " , facidx ) ;
2007-04-15 17:41:36 +00:00
switch ( i - > qsigfeat ) {
case QSIG_TYPE_ALCATEL_ECMA :
2007-05-18 19:09:22 +00:00
qsig_handle_q932facility ( data , i , & facidx , faclen , Q932_PROTOCOL_ROSE ) ;
2007-04-15 17:41:36 +00:00
break ;
case QSIG_TYPE_HICOM_ECMAV2 :
2007-05-18 19:09:22 +00:00
qsig_handle_q932facility ( data , i , & facidx , faclen , Q932_PROTOCOL_EXTENSIONS ) ;
2007-04-15 17:41:36 +00:00
break ;
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Unknown QSIG protocol configured (%i) \n " , i - > qsigfeat ) ;
2007-04-24 08:39:12 +00:00
/* kill endlessloop */
facidx + = faclen ;
2007-04-15 17:41:36 +00:00
break ;
}
}
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_3 " Facility done at index %i from %i \n " , facidx , faclen ) ;
2007-05-18 19:09:22 +00:00
return 1 ;
2007-04-15 17:41:36 +00:00
}
static int identify_qsig_setup_callfeature ( char * param )
{
char * p = param ;
switch ( * p ) {
case ' t ' :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , " Call Transfer " ) ;
2007-04-15 17:41:36 +00:00
p + + ;
if ( * p = = ' r ' ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , " on ALERT " ) ;
2007-04-15 17:41:36 +00:00
return 2 ;
} else {
return 1 ;
}
default :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , " unknown (%c) \n " , * p ) ;
2007-04-15 17:41:36 +00:00
break ;
}
2007-02-11 16:01:32 +00:00
return 0 ;
}
/*
* Handles outgoing Facilies on Call SETUP
*/
2007-03-25 17:03:19 +00:00
unsigned int cc_qsig_add_call_setup_data ( unsigned char * data , struct capi_pvt * i , struct ast_channel * c )
2007-02-11 16:01:32 +00:00
{
/* TODO: Check buffers */
struct cc_qsig_invokedata invoke ;
struct cc_qsig_nfe nfe ;
2007-03-25 17:03:19 +00:00
unsigned int dataidx = 0 ;
2007-04-24 18:43:38 +00:00
int protocolvar = 0 ;
2007-03-25 17:03:19 +00:00
const unsigned char xprogress [ ] = { 0x1e , 0x02 , 0xa0 , 0x90 } ;
char * p = NULL ;
2007-04-15 17:41:36 +00:00
char * pp = NULL ;
2007-03-25 17:03:19 +00:00
int add_externalinfo = 0 ;
2007-06-04 18:37:12 +00:00
data [ 0 ] = 0 ; /* Initialize array length */
2007-05-12 18:23:04 +00:00
if ( ( p = ( char * ) pbx_builtin_getvar_helper ( c , " QSIG_SETUP " ) ) ) {
2007-03-25 17:03:19 +00:00
/* some special dial parameters */
/* parse the parameters */
while ( ( p ) & & ( * p ) ) {
switch ( * p ) {
case ' X ' : /* add PROGRESS INDICATOR for external calls*/
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_4 " Sending QSIG external PROGRESS IE. \n " ) ;
2007-03-25 17:03:19 +00:00
add_externalinfo = 1 ;
2007-04-15 17:41:36 +00:00
pp = strsep ( & p , " / " ) ;
pp = NULL ;
break ;
case ' C ' :
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_4 " QSIG Call Feature requested: " ) ;
2007-04-15 17:41:36 +00:00
p + + ;
switch ( identify_qsig_setup_callfeature ( p ) ) {
case 1 : /* Call transfer */
p + + ;
pp = strsep ( & p , " / " ) ;
if ( ! pp ) {
cc_log ( LOG_WARNING , " QSIG Call Feature needs plci as parameter! \n " ) ;
} else {
i - > qsig_data . calltransfer = 1 ;
i - > qsig_data . partner_plci = atoi ( pp ) ;
2007-04-24 18:43:38 +00:00
/* set the other channel as partner to me */
2007-04-29 22:28:30 +00:00
struct capi_pvt * ii = capi_find_interface_by_plci ( i - > qsig_data . partner_plci ) ;
2007-04-24 18:43:38 +00:00
if ( ii )
ii - > qsig_data . partner_plci = i - > PLCI ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , " for plci %#x \n " , i - > qsig_data . partner_plci ) ;
2007-04-15 17:41:36 +00:00
}
break ;
case 2 : /* Call transfer on ring */
p + = 2 ;
pp = strsep ( & p , " / " ) ;
if ( ! pp ) {
cc_log ( LOG_WARNING , " QSIG Call Feature needs plci as parameter! \n " ) ;
} else {
i - > qsig_data . calltransfer_onring = 1 ;
i - > qsig_data . partner_plci = atoi ( pp ) ;
2007-04-24 18:43:38 +00:00
/* set the other channel as partner to me */
2007-04-29 22:28:30 +00:00
struct capi_pvt * ii = capi_find_interface_by_plci ( i - > qsig_data . partner_plci ) ;
2007-04-24 18:43:38 +00:00
if ( ii )
ii - > qsig_data . partner_plci = i - > PLCI ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , " for plci %#x \n " , i - > qsig_data . partner_plci ) ;
2007-04-15 17:41:36 +00:00
}
break ;
default :
pp = strsep ( & p , " / " ) ;
break ;
}
pp = NULL ;
2007-03-25 17:03:19 +00:00
break ;
default :
cc_log ( LOG_WARNING , " Unknown parameter '%c' in QSIG_SETUP, ignoring. \n " , * p ) ;
2007-04-15 17:41:36 +00:00
p + + ;
2007-03-25 17:03:19 +00:00
}
}
}
2007-02-11 16:01:32 +00:00
2007-04-24 18:43:38 +00:00
switch ( i - > qsigfeat ) {
case QSIG_TYPE_ALCATEL_ECMA :
protocolvar = Q932_PROTOCOL_ROSE ;
break ;
case QSIG_TYPE_HICOM_ECMAV2 :
protocolvar = Q932_PROTOCOL_EXTENSIONS ;
break ;
default :
cc_log ( LOG_WARNING , " Unknown QSIG variant configured. \n " ) ;
return 0 ;
break ;
}
cc_qsig_build_facility_struct ( data , & dataidx , protocolvar , APDUINTERPRETATION_IGNORE , & nfe ) ;
2007-07-10 17:44:09 +00:00
cc_qsig_encode_ecma_name_invoke ( data , & dataidx , & invoke , i , 0 , i - > owner - > cid . cid_name ) ;
2007-04-19 18:18:42 +00:00
cc_qsig_add_invoke ( data , & dataidx , & invoke , i ) ;
2007-03-25 17:03:19 +00:00
if ( add_externalinfo ) {
/* add PROGRESS INDICATOR for external calls*/
2007-06-04 18:37:12 +00:00
int progress_size = sizeof ( xprogress ) ;
memcpy ( & data [ dataidx ] , xprogress , progress_size ) ;
data [ 0 ] + = progress_size ;
dataidx + = progress_size ;
2007-03-25 17:03:19 +00:00
}
2007-06-04 18:37:12 +00:00
2007-02-11 16:01:32 +00:00
return 0 ;
}
2007-03-10 14:23:20 +00:00
2007-07-10 17:44:09 +00:00
/*
* Handles outgoing Facilies on Call Answer
*/
unsigned int cc_qsig_add_call_answer_data ( unsigned char * data , struct capi_pvt * i , struct ast_channel * c )
{
struct cc_qsig_invokedata invoke ;
struct cc_qsig_nfe nfe ;
unsigned int dataidx = 0 ;
int protocolvar = 0 ;
const char * connectedname ;
2007-08-09 07:53:12 +00:00
data [ 0 ] = 0 ;
2007-07-10 17:44:09 +00:00
if ( ! i - > qsigfeat )
return 0 ;
2007-08-09 07:53:12 +00:00
if ( ! ( connectedname = pbx_builtin_getvar_helper ( c , " CONNECTEDNAME " ) ) )
return 0 ;
2007-07-10 17:44:09 +00:00
if ( ! strlen ( connectedname ) )
return 0 ;
switch ( i - > qsigfeat ) {
case QSIG_TYPE_ALCATEL_ECMA :
protocolvar = Q932_PROTOCOL_ROSE ;
break ;
case QSIG_TYPE_HICOM_ECMAV2 :
protocolvar = Q932_PROTOCOL_EXTENSIONS ;
break ;
default :
cc_log ( LOG_WARNING , " Unknown QSIG variant configured. \n " ) ;
return 0 ;
break ;
}
cc_qsig_build_facility_struct ( data , & dataidx , protocolvar , APDUINTERPRETATION_IGNORE , & nfe ) ;
cc_qsig_encode_ecma_name_invoke ( data , & dataidx , & invoke , i , 2 , ( char * ) connectedname ) ;
cc_qsig_add_invoke ( data , & dataidx , & invoke , i ) ;
return 1 ;
}
/*
2007-08-09 07:53:12 +00:00
* Handles outgoing Facilies on Call Alert
2007-07-10 17:44:09 +00:00
*/
unsigned int cc_qsig_add_call_alert_data ( unsigned char * data , struct capi_pvt * i , struct ast_channel * c )
{
struct cc_qsig_invokedata invoke ;
struct cc_qsig_nfe nfe ;
unsigned int dataidx = 0 ;
int protocolvar = 0 ;
const char * connectedname ;
2007-08-09 07:53:12 +00:00
data [ 0 ] = 0 ;
2007-07-10 17:44:09 +00:00
if ( ! i - > qsigfeat )
return 0 ;
2007-08-09 07:53:12 +00:00
if ( ! ( connectedname = pbx_builtin_getvar_helper ( c , " CALLEDNAME " ) ) )
return 0 ;
2007-07-10 17:44:09 +00:00
if ( ! strlen ( connectedname ) )
return 0 ;
switch ( i - > qsigfeat ) {
case QSIG_TYPE_ALCATEL_ECMA :
protocolvar = Q932_PROTOCOL_ROSE ;
break ;
case QSIG_TYPE_HICOM_ECMAV2 :
protocolvar = Q932_PROTOCOL_EXTENSIONS ;
break ;
default :
cc_log ( LOG_WARNING , " Unknown QSIG variant configured. \n " ) ;
return 0 ;
break ;
}
cc_qsig_build_facility_struct ( data , & dataidx , protocolvar , APDUINTERPRETATION_IGNORE , & nfe ) ;
cc_qsig_encode_ecma_name_invoke ( data , & dataidx , & invoke , i , 1 , ( char * ) connectedname ) ;
cc_qsig_add_invoke ( data , & dataidx , & invoke , i ) ;
return 1 ;
}
2007-03-28 19:24:55 +00:00
2007-03-25 17:03:19 +00:00
/*
2007-03-28 19:24:55 +00:00
* Handles outgoing Facilies on capicommand
2007-03-25 17:03:19 +00:00
*/
2007-04-15 17:41:36 +00:00
unsigned int cc_qsig_do_facility ( unsigned char * fac , struct ast_channel * c , char * param , unsigned int factype , int info1 )
2007-03-25 17:03:19 +00:00
{
struct cc_qsig_invokedata invoke ;
struct cc_qsig_nfe nfe ;
2007-03-28 19:24:55 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
/* struct capi_pvt *ii = NULL; */
unsigned int facidx = 0 ;
2007-04-24 18:43:38 +00:00
int protocolvar = 0 ;
2007-03-25 17:03:19 +00:00
2007-04-24 18:43:38 +00:00
switch ( i - > qsigfeat ) {
case QSIG_TYPE_ALCATEL_ECMA :
protocolvar = Q932_PROTOCOL_ROSE ;
break ;
case QSIG_TYPE_HICOM_ECMAV2 :
protocolvar = Q932_PROTOCOL_EXTENSIONS ;
break ;
default :
cc_log ( LOG_WARNING , " Unknown QSIG variant configured. \n " ) ;
return 0 ;
break ;
}
2007-06-04 18:37:12 +00:00
cc_qsig_build_facility_struct ( fac , & facidx , protocolvar , APDUINTERPRETATION_IGNORE , & nfe ) ;
2007-03-28 19:24:55 +00:00
switch ( factype ) {
2007-04-24 18:43:38 +00:00
case 4 : /* ECMA-xxx pathReplacementPropose */
cc_qsig_encode_ecma_prpropose ( fac , & facidx , & invoke , i , param ) ;
cc_qsig_add_invoke ( fac , & facidx , & invoke , i ) ;
break ;
2007-04-15 17:41:36 +00:00
case 12 : /* ECMA-178 callTransfer */
cc_qsig_encode_ecma_calltransfer ( fac , & facidx , & invoke , i , param , info1 ) ;
2007-04-19 18:18:42 +00:00
cc_qsig_add_invoke ( fac , & facidx , & invoke , i ) ;
2007-04-15 17:41:36 +00:00
break ;
2007-03-28 19:24:55 +00:00
case 99 : /* ECMA-300 simpleCallTransfer */
cc_qsig_encode_ecma_sscalltransfer ( fac , & facidx , & invoke , i , param ) ;
2007-04-19 18:18:42 +00:00
cc_qsig_add_invoke ( fac , & facidx , & invoke , i ) ;
2007-03-25 17:03:19 +00:00
break ;
default :
break ;
}
2007-03-28 19:24:55 +00:00
2007-03-25 17:03:19 +00:00
return 0 ;
}
2007-04-18 11:48:07 +00:00
/*
2007-04-24 18:43:38 +00:00
* capicommand getplci - needed for Call Transfer
2007-04-18 11:48:07 +00:00
*/
int pbx_capi_qsig_getplci ( struct ast_channel * c , char * param )
{
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
char buffer [ 10 ] ;
snprintf ( buffer , sizeof ( buffer ) - 1 , " %d " , i - > PLCI ) ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_4 " QSIG_GETPLCI: %s \n " , buffer ) ;
2007-04-18 11:48:07 +00:00
pbx_builtin_setvar_helper ( c , " QSIG_PLCI " , buffer ) ;
return 0 ;
}
/*
* Initiate a QSIG Single Step Call Transfer
*/
int pbx_capi_qsig_ssct ( struct ast_channel * c , char * param )
{
unsigned char fac [ CAPI_MAX_FACILITYDATAARRAY_SIZE ] ;
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
if ( ! param ) { /* no data implies no Calling Number and Destination Number */
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " qsig_ssct requires source number and destination number \n " ) ;
2007-04-18 11:48:07 +00:00
return - 1 ;
}
cc_qsig_do_facility ( fac , c , param , 99 , 0 ) ;
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" ()(()()()s) " ,
fac
) ;
2007-04-18 11:48:07 +00:00
return 0 ;
}
/*
* Initiate a QSIG Call Transfer
*/
int pbx_capi_qsig_ct ( struct ast_channel * c , char * param )
{
unsigned char fac [ CAPI_MAX_FACILITYDATAARRAY_SIZE ] ;
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
struct capi_pvt * ii = NULL ;
unsigned int callmark ;
char * marker ;
if ( ! param ) { /* no data implies no Calling Number and Destination Number */
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " qsig_ct requires call marker, source number, destination number and await_connect info \n " ) ;
2007-04-18 11:48:07 +00:00
return - 1 ;
}
marker = strsep ( & param , " | " ) ;
callmark = atoi ( marker ) ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_4 " * QSIG_CT: using call marker %i(%s) \n " , callmark , marker ) ;
2007-04-18 11:48:07 +00:00
2007-04-29 22:28:30 +00:00
for ( ii = capi_iflist ; ii ; ii = ii - > next ) {
2007-04-18 11:48:07 +00:00
if ( ii - > qsig_data . callmark = = callmark )
break ;
}
if ( ! ii ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " qsig_ct call marker not found! \n " ) ;
2007-04-18 11:48:07 +00:00
return - 1 ;
}
cc_qsig_do_facility ( fac , c , param , 12 , 1 ) ;
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2007-06-07 19:24:32 +00:00
" ()(()()()s()) " ,
2007-04-28 20:59:44 +00:00
fac
) ;
2007-04-18 11:48:07 +00:00
2007-07-05 19:48:19 +00:00
cc_qsig_do_facility ( fac , c , param , 12 , 0 ) ;
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , ii - > PLCI , get_capi_MessageNumber ( ) ,
" ()(()()()s()) " ,
fac
) ;
2007-04-18 11:48:07 +00:00
return 0 ;
}
/*
2007-06-07 19:24:32 +00:00
* mark an call
2007-04-18 11:48:07 +00:00
*/
int pbx_capi_qsig_callmark ( struct ast_channel * c , char * param )
{
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
if ( ! param ) { /* no data implies no Calling Number and Destination Number */
cc_log ( LOG_WARNING , " capi qsig_callmark requires an call identifier \n " ) ;
return - 1 ;
}
i - > qsig_data . callmark = atoi ( param ) ;
return 0 ;
}
2007-06-04 18:37:12 +00:00
static void send_feature_calltransfer ( struct capi_pvt * i )
{
unsigned char * fac = alloca ( CAPI_MAX_FACILITYDATAARRAY_SIZE ) ;
struct capi_pvt * ii = capi_find_interface_by_plci ( i - > qsig_data . partner_plci ) ;
/* needed for Path Replacement */
ii - > qsig_data . partner_plci = i - > PLCI ;
if ( ii ) {
cc_qsig_do_facility ( fac , i - > owner , NULL , 12 , 1 ) ;
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) , " ()(()()()s()) " , fac ) ;
2007-07-05 19:48:19 +00:00
cc_qsig_do_facility ( fac , ii - > owner , NULL , 12 , 0 ) ;
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , ii - > PLCI , get_capi_MessageNumber ( ) , " ()(()()()s()) " , fac ) ;
2007-06-04 18:37:12 +00:00
} else {
cc_log ( LOG_WARNING , " Call Transfer failed - second channel not found (PLCI %#x)! \n " , i - > qsig_data . partner_plci ) ;
}
}
2007-05-28 19:30:20 +00:00
/*
* init QSIG data on new channel - will be called by mkif
*/
void cc_qsig_interface_init ( struct cc_capi_conf * conf , struct capi_pvt * tmp )
{
2007-06-07 19:24:32 +00:00
tmp - > qsigfeat = conf - > qsigfeat ;
if ( ! conf - > qsigfeat )
return ;
2007-05-28 19:30:20 +00:00
tmp - > qsig_data . calltransfer_active = 0 ;
tmp - > qsig_data . calltransfer = 0 ;
tmp - > qsig_data . calltransfer_onring = 0 ;
tmp - > qsig_data . callmark = 0 ;
tmp - > qsig_data . dnameid = NULL ;
/* Path Replacement */
2007-06-04 18:37:12 +00:00
tmp - > qsig_data . pr_propose_active = 0 ;
2007-05-28 19:30:20 +00:00
tmp - > qsig_data . pr_propose_sendback = 0 ; /* send back an prior received PR PROPOSE on Connect */
2007-06-04 18:37:12 +00:00
tmp - > qsig_data . pr_propose_sentback = 0 ;
2007-07-05 19:48:19 +00:00
tmp - > qsig_data . pr_propose_doinboundbridge = 0 ;
2007-05-28 19:30:20 +00:00
tmp - > qsig_data . pr_propose_cid = NULL ; /* Call identity */
tmp - > qsig_data . pr_propose_pn = NULL ; /* Party Number */
2007-07-05 19:48:19 +00:00
cc_copy_string ( tmp - > qsig_data . if_pr_propose_pn , conf - > qsigconf . if_pr_propose_pn , sizeof ( tmp - > qsig_data . if_pr_propose_pn ) ) ;
2007-05-28 19:30:20 +00:00
/* Partner Channel - needed for many features */
tmp - > qsig_data . partner_ch = NULL ;
tmp - > qsig_data . partner_plci = 0 ;
2007-06-04 18:37:12 +00:00
tmp - > qsig_data . waitevent = 0 ;
ast_cond_init ( & tmp - > qsig_data . event_trigger , NULL ) ;
2007-05-28 19:30:20 +00:00
}
2007-07-05 19:48:19 +00:00
/*
* build the qsig - interface according to configs
*/
void cc_pbx_qsig_conf_interface_value ( struct cc_capi_conf * conf , struct ast_variable * v )
{
# define CONF_STRING(var, token) \
if ( ! strcasecmp ( v - > name , token ) ) { \
cc_copy_string ( var , v - > value , sizeof ( var ) ) ; \
}
# define CONF_INTEGER(var, token) \
if ( ! strcasecmp ( v - > name , token ) ) { \
var = atoi ( v - > value ) ; \
}
# define CONF_TRUE(var, token, val) \
if ( ! strcasecmp ( v - > name , token ) ) { \
if ( ast_true ( v - > value ) ) \
var = val ; \
}
CONF_INTEGER ( conf - > qsigfeat , " qsig " )
CONF_STRING ( conf - > qsigconf . if_pr_propose_pn , " qsig_prnum " )
# undef CONF_STRING
# undef CONF_INTEGER
# undef CONF_TRUE
}
2007-05-30 17:56:56 +00:00
/*
* cleanup QSIG stuff on every ( end of ) call per interface
*/
static void qsig_cleanup_channel ( struct capi_pvt * i )
{
i - > qsig_data . callmark = 0 ;
i - > qsig_data . partner_ch = NULL ;
i - > qsig_data . calltransfer_active = 0 ;
i - > qsig_data . calltransfer_onring = 0 ;
2007-06-04 18:37:12 +00:00
i - > qsig_data . pr_propose_active = 0 ;
i - > qsig_data . pr_propose_sentback = 0 ;
2007-07-05 19:48:19 +00:00
i - > qsig_data . pr_propose_doinboundbridge = 0 ;
2007-05-30 17:56:56 +00:00
if ( i - > qsig_data . pr_propose_cid ) {
free ( i - > qsig_data . pr_propose_cid ) ;
i - > qsig_data . pr_propose_cid = NULL ;
}
if ( i - > qsig_data . pr_propose_pn ) {
free ( i - > qsig_data . pr_propose_pn ) ;
i - > qsig_data . pr_propose_pn = NULL ;
}
if ( i - > qsig_data . dnameid ) {
free ( i - > qsig_data . dnameid ) ;
i - > qsig_data . dnameid = NULL ;
}
2007-06-04 18:37:12 +00:00
2007-05-30 17:56:56 +00:00
}
2007-04-19 06:55:44 +00:00
/*
* cleanup QSIG stuff on interface
*/
void interface_cleanup_qsig ( struct capi_pvt * i )
{
if ( i - > qsigfeat ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_4 " QSIG: cleanup channel \n " ) ;
2007-05-30 17:56:56 +00:00
qsig_cleanup_channel ( i ) ;
2007-04-19 06:55:44 +00:00
}
}
2007-04-18 11:48:07 +00:00
2007-06-04 18:37:12 +00:00
/*
* cleanup QSIG stuff on module unload
*/
void pbx_capi_qsig_unload_module ( struct capi_pvt * i )
{
2007-06-07 19:24:32 +00:00
if ( ! i - > qsigfeat )
return ;
2007-06-04 18:37:12 +00:00
ast_cond_destroy ( & i - > qsig_data . event_trigger ) ;
}
/*
* wait for B3 up
*/
int pbx_capi_qsig_wait_for_prpropose ( struct capi_pvt * i )
{
struct timespec abstime ;
int ret = 1 ;
cc_mutex_lock ( & i - > lock ) ;
if ( ! ( i - > qsig_data . pr_propose_sentback ) ) {
i - > qsig_data . waitevent = CAPI_QSIG_WAITEVENT_PRPROPOSE ;
abstime . tv_sec = time ( NULL ) + CCQSIG_TIMER_WAIT_PRPROPOSE ; /* PR PROPOSE TIMER */
abstime . tv_nsec = 0 ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , " %s: wait for PATH REPLACEMENT. \n " ,
2007-06-04 18:37:12 +00:00
i - > vname ) ;
if ( ast_cond_timedwait ( & i - > qsig_data . event_trigger , & i - > lock , & abstime ) ! = 0 ) {
cc_log ( LOG_WARNING , " %s: timed out waiting for PATH REPLACEMENT. \n " ,
i - > vname ) ;
ret = 0 ;
} else {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , " %s: cond signal received for PATH REPLACEMENT. \n " ,
2007-06-04 18:37:12 +00:00
i - > vname ) ;
}
}
cc_mutex_unlock ( & i - > lock ) ;
return ret ;
}
/*
* check special conditions , wake waiting threads and send outstanding commands
* for the given interface
*/
static void pbx_capi_qsig_post_handling ( struct capi_pvt * i )
{
if ( ( i - > qsig_data . waitevent = = CAPI_QSIG_WAITEVENT_PRPROPOSE ) & &
( i - > qsig_data . pr_propose_sentback = = 1 ) ) {
i - > qsig_data . waitevent = 0 ;
ast_cond_signal ( & i - > qsig_data . event_trigger ) ;
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , " %s: found and signal for PATH REPLACEMENT state. \n " ,
2007-06-04 18:37:12 +00:00
i - > vname ) ;
return ;
}
}
/*
* handle a bridge attempt - maybe we ' re allowed to make a path replacement
*/
int pbx_capi_qsig_bridge ( struct capi_pvt * i0 , struct capi_pvt * i1 )
{
if ( i1 - > qsig_data . pr_propose_sentback ) {
return 2 ; /* Path Replacement already sent out - call will be cleared in short */
}
i1 - > qsig_data . partner_plci = i0 - > PLCI ;
send_feature_calltransfer ( i1 ) ;
if ( pbx_capi_qsig_wait_for_prpropose ( i1 ) )
return 1 ; /* Path Replacement successful */
/* No Path Replacement - allow line interconnect */
return 0 ;
}
2007-07-10 17:44:09 +00:00
int pbx_capi_qsig_sendtext ( struct ast_channel * c , const char * text )
{
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
#if 0
/* suppress compiler warnings */
unsigned char * data = alloca ( CAPI_MAX_FACILITYDATAARRAY_SIZE ) ;
unsigned int dataidx = 0 ;
struct cc_qsig_invokedata invoke ;
struct cc_qsig_nfe nfe ;
# endif
int protocolvar = 0 ;
if ( ! i - > qsigfeat )
return 0 ;
if ( ! strlen ( text ) )
return 0 ;
switch ( i - > qsigfeat ) {
case QSIG_TYPE_ALCATEL_ECMA :
protocolvar = Q932_PROTOCOL_ROSE ;
break ;
case QSIG_TYPE_HICOM_ECMAV2 :
protocolvar = Q932_PROTOCOL_EXTENSIONS ;
break ;
default :
cc_log ( LOG_WARNING , " Unknown QSIG variant configured. \n " ) ;
return 0 ;
break ;
}
/* TODO: implement something - QSIG_LEG_INFO3 doesn't work here */
return 0 ;
}
2007-06-04 18:37:12 +00:00
2007-04-19 18:18:42 +00:00
/*
* CAPI INFO_IND ( QSIG part )
*/
void pbx_capi_qsig_handle_info_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
{
if ( ! i - > qsigfeat ) /* Run only, if QSIG enabled */
return ;
switch ( INFO_IND_INFONUMBER ( CMSG ) ) {
case 0x0008 : /* Cause */
break ;
case 0x0014 : /* Call State */
break ;
case 0x0018 : /* Channel Identification */
break ;
case 0x001c : /* Facility Q.932 */
{
unsigned int qsiginvoke ;
qsiginvoke = cc_qsig_handle_capi_facilityind ( ( unsigned char * ) INFO_IND_INFOELEMENT ( CMSG ) , i ) ;
2007-05-16 18:23:55 +00:00
/* got an Path Replacement */
2007-07-05 19:48:19 +00:00
if ( ( i - > qsig_data . pr_propose_cid & & i - > qsig_data . pr_propose_pn ) & ! i - > qsig_data . pr_propose_sendback & ! i - > qsig_data . pr_propose_doinboundbridge ) {
2007-04-29 22:28:30 +00:00
struct capi_pvt * ii = capi_find_interface_by_plci ( i - > qsig_data . partner_plci ) ;
2007-05-16 18:23:55 +00:00
2007-04-24 18:43:38 +00:00
if ( ii ) {
2007-05-16 18:23:55 +00:00
if ( ii - > state = = CAPI_STATE_CONNECTED ) { /* second line is connected, we can proceed */
unsigned char fac [ CAPI_MAX_FACILITYDATAARRAY_SIZE ] ;
2007-04-24 18:43:38 +00:00
2007-05-16 18:23:55 +00:00
cc_qsig_do_facility ( fac , i - > owner , NULL , 4 , 0 ) ;
2007-04-24 18:43:38 +00:00
2007-05-16 18:23:55 +00:00
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , ii - > PLCI , get_capi_MessageNumber ( ) ,
" ()(()()()s) " ,
fac
) ;
2007-06-04 18:37:12 +00:00
i - > qsig_data . pr_propose_active = 1 ;
ii - > qsig_data . pr_propose_sentback = 1 ;
2007-05-16 18:23:55 +00:00
} else { /* Path Replacement has to be sent back after Connect on second line */
ii - > qsig_data . pr_propose_sendback = 1 ;
ii - > qsig_data . pr_propose_cid = strdup ( i - > qsig_data . pr_propose_cid ) ;
ii - > qsig_data . pr_propose_pn = strdup ( i - > qsig_data . pr_propose_pn ) ;
2007-06-04 18:37:12 +00:00
ii - > qsig_data . pr_propose_active = 1 ;
2007-05-16 18:23:55 +00:00
}
} else
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_4 " * QSIG_PATHREPLACEMENT_PROPOSE: no partner channel found (%#x) \n " , i - > qsig_data . partner_plci ) ;
2007-05-16 18:23:55 +00:00
2007-04-24 18:43:38 +00:00
free ( i - > qsig_data . pr_propose_cid ) ;
2007-05-16 18:23:55 +00:00
i - > qsig_data . pr_propose_cid = NULL ;
2007-04-24 18:43:38 +00:00
free ( i - > qsig_data . pr_propose_pn ) ;
2007-05-16 18:23:55 +00:00
i - > qsig_data . pr_propose_pn = NULL ;
2007-04-24 18:43:38 +00:00
}
2007-07-05 19:48:19 +00:00
if ( ( i - > qsig_data . pr_propose_cid & & i - > qsig_data . pr_propose_pn ) & & i - > qsig_data . pr_propose_doinboundbridge ) {
struct ast_channel * chanx ;
struct capi_pvt * ii = capi_find_interface_by_plci ( i - > qsig_data . partner_plci ) ;
if ( ii ) {
2007-12-06 19:07:28 +00:00
cc_qsig_verbose ( 1 , VERBOSE_PREFIX_4 " * QSIG_PATHREPLACEMENT_PROPOSE: trying to complete bridge... \n " ) ;
2007-07-05 19:48:19 +00:00
chanx = ast_bridged_channel ( i - > owner ) ;
ast_channel_masquerade ( ii - > owner , chanx ) ;
}
free ( i - > qsig_data . pr_propose_cid ) ;
i - > qsig_data . pr_propose_cid = NULL ;
free ( i - > qsig_data . pr_propose_pn ) ;
i - > qsig_data . pr_propose_pn = NULL ;
}
2007-04-24 18:43:38 +00:00
2007-04-19 18:18:42 +00:00
}
break ;
case 0x001e : /* Progress Indicator */
break ;
case 0x0027 : /* Notification Indicator */
break ;
case 0x0028 : /* DSP */
break ;
case 0x0029 : /* Date/Time */
break ;
case 0x0070 : /* Called Party Number */
break ;
case 0x0074 : /* Redirecting Number */
break ;
case 0x0076 : /* Redirection Number */
break ;
case 0x00a1 : /* Sending Complete */
break ;
case 0x4000 : /* CHARGE in UNITS */
break ;
case 0x4001 : /* CHARGE in CURRENCY */
break ;
case 0x8001 : /* ALERTING */
/* TODO: some checks, if there's any work here */
if ( i - > qsig_data . calltransfer_onring ) {
i - > qsig_data . calltransfer_onring = 0 ;
2007-06-04 18:37:12 +00:00
send_feature_calltransfer ( i ) ;
2007-04-19 18:18:42 +00:00
}
break ;
case 0x8002 : /* CALL PROCEEDING */
break ;
case 0x8003 : /* PROGRESS */
break ;
case 0x8005 : /* SETUP */
break ;
case 0x8007 : /* CONNECT */
2007-05-16 18:23:55 +00:00
if ( i - > qsig_data . calltransfer ) {
i - > qsig_data . calltransfer = 0 ;
2007-06-04 18:37:12 +00:00
send_feature_calltransfer ( i ) ;
2007-05-16 18:23:55 +00:00
}
{
/* handle prior received Path Replacement */
if ( ( i - > qsig_data . pr_propose_cid & & i - > qsig_data . pr_propose_pn ) & & i - > qsig_data . pr_propose_sendback ) {
unsigned char fac [ CAPI_MAX_FACILITYDATAARRAY_SIZE ] ;
2007-04-24 18:43:38 +00:00
2007-05-16 18:23:55 +00:00
cc_qsig_do_facility ( fac , i - > owner , NULL , 4 , 0 ) ;
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2007-04-28 20:59:44 +00:00
" ()(()()()s) " ,
fac
2007-05-16 18:23:55 +00:00
) ;
i - > qsig_data . pr_propose_sendback = 0 ;
2007-07-05 19:48:19 +00:00
free ( i - > qsig_data . pr_propose_cid ) ;
2007-05-16 18:23:55 +00:00
i - > qsig_data . pr_propose_cid = NULL ;
2007-07-05 19:48:19 +00:00
free ( i - > qsig_data . pr_propose_pn ) ;
2007-05-16 18:23:55 +00:00
i - > qsig_data . pr_propose_pn = NULL ;
2007-06-04 18:37:12 +00:00
i - > qsig_data . pr_propose_sentback = 1 ;
2007-04-24 18:43:38 +00:00
}
2007-05-16 18:23:55 +00:00
}
2007-04-19 18:18:42 +00:00
break ;
case 0x800d : /* SETUP ACK */
break ;
case 0x800f : /* CONNECT ACK */
2007-05-27 18:14:24 +00:00
{
unsigned int qsiginvoke ;
qsiginvoke = cc_qsig_handle_capi_facilityind ( ( unsigned char * ) INFO_IND_INFOELEMENT ( CMSG ) , i ) ;
}
2007-07-05 19:48:19 +00:00
{
/* handle outbound Path Replacement */
if ( ( i - > qsig_data . pr_propose_cid & & i - > qsig_data . pr_propose_pn ) & & i - > qsig_data . pr_propose_doinboundbridge ) {
unsigned char fac [ CAPI_MAX_FACILITYDATAARRAY_SIZE ] ;
cc_qsig_do_facility ( fac , i - > owner , NULL , 4 , 0 ) ;
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" ()(()()()s) " , fac ) ;
i - > qsig_data . pr_propose_sendback = 0 ;
free ( i - > qsig_data . pr_propose_cid ) ;
i - > qsig_data . pr_propose_cid = NULL ;
free ( i - > qsig_data . pr_propose_pn ) ;
i - > qsig_data . pr_propose_pn = NULL ;
i - > qsig_data . pr_propose_sentback = 1 ;
i - > qsig_data . pr_propose_doinboundbridge = 0 ;
}
}
2007-04-19 18:18:42 +00:00
break ;
case 0x8045 : /* DISCONNECT */
2007-05-30 17:56:56 +00:00
qsig_cleanup_channel ( i ) ;
2007-04-19 18:18:42 +00:00
break ;
case 0x804d : /* RELEASE */
break ;
case 0x805a : /* RELEASE COMPLETE */
2007-05-30 17:56:56 +00:00
qsig_cleanup_channel ( i ) ;
2007-04-19 18:18:42 +00:00
break ;
case 0x8062 : /* FACILITY */
break ;
case 0x806e : /* NOTIFY */
break ;
case 0x807b : /* INFORMATION */
break ;
case 0x807d : /* STATUS */
break ;
default :
break ;
}
2007-06-04 18:37:12 +00:00
pbx_capi_qsig_post_handling ( i ) ;
2007-04-19 18:18:42 +00:00
return ;
}