- many bugfixes on name presentation handling
 - added support for different qsig variants
 - added support for rerouting informations on incoming calls
 - code cleanup
This commit is contained in:
MelwareDE 2007-03-10 14:23:20 +00:00
parent 0208255abd
commit 8c79f0d18a
10 changed files with 683 additions and 228 deletions

View File

@ -91,7 +91,7 @@ INSTALL=install
SHAREDOS=chan_capi.so
OBJECTS=chan_capi.o c20msg.o chan_capi_rtp.o chan_capi_qsig_core.o chan_capi_qsig_ecma.o
OBJECTS=chan_capi.o c20msg.o chan_capi_rtp.o chan_capi_qsig_core.o chan_capi_qsig_ecma.o chan_capi_qsig_asn197ade.o chan_capi_qsig_asn197no.o
CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations

View File

@ -37,10 +37,20 @@ To use Q.SIG with asterisk, you'll need a card like Eicon DIVA Server
The QSIG support includes:
==========================
- Name presentation on Call SETUP incoming like outgoing
- ISDN LEG INFO2 field - a message which delivers informations about call diversions on incoming call to asterisk
Data is stored in Asterisk variables:
QSIG_LI2_DIVREASON Reason of divertion: 0 - unknown, 1 - unconditional, 2 - user busy, 3 - user no reply
QSIG_LI2_ODIVREASON Reason of original divertion (like above)
QSIG_LI2_DIVCOUNT divertion counter - how many divertions
QSIG_LI2_DIVNUM diverting number
QSIG_LI2_ODIVNUM original diverting number
QSIG_LI2_DIVNAME diverting name
QSIG_LI2_ODIVNAME original diverting name
at the moment only incoming handling is supported
Future Targets:
===============
- better name handling - there are still some case which are wrongly handled
- check code for buffer overflows
- Path Replacement
- CCBS
@ -52,12 +62,23 @@ How to use:
simply enable Q.SIG with following line in your capi.conf interface:
qsig=on
================================================================================
********** deprecated **********************************************************
#### qsig=on
Take care that you enable this only for interfaces, where the other end
understands the Q.SIG protocoll. If not, then these switches may reject the
entire call, because of wrong facility contents.
#### Take care that you enable this only for interfaces, where the other end
#### understands the Q.SIG protocoll. If not, then these switches may reject the
#### entire call, because of wrong facility contents.
Later this will change to qsig=off or qsig=1..x where we can support some
pbx manufacturer specific operations.
#### Later this will change to qsig=off or qsig=1..x where we can support some
#### pbx manufacturer specific operations.
================================================================================
Here we go with new configuration
Set qsig to one of the following values, which corresponds to your configuration.
0 QSIG turned off
1 Alcatel (4400 & Enterprise - Maybe OXO/4200) ECMA variant
2 Siemens HiPath 4000 ECMAV2

View File

@ -90,6 +90,8 @@ OPENPBX_FILE_VERSION("$HeadURL$", "$Revision$")
#include "chan_capi.h"
#include "chan_capi_rtp.h"
#include "chan_capi_qsig.h"
#include "chan_capi_qsig_asn197ade.h"
#include "chan_capi_qsig_asn197no.h"
#endif
#ifdef PBX_IS_OPBX
@ -3929,7 +3931,7 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un
pbx_builtin_setvar_helper(i->owner, "SECONDCALLERID", buffer);
*/
if (i->qsigfeat == QSIG_ENABLED) {
if (i->qsigfeat != QSIG_DISABLED) {
cc_qsig_handle_capiind(CONNECT_IND_FACILITYDATAARRAY(CMSG), i);
}
@ -5822,7 +5824,7 @@ static int conf_interface(struct cc_capi_conf *conf, struct ast_variable *v)
CONF_TRUE(conf->es, "echosquelch", 1)
CONF_TRUE(conf->bridge, "bridge", 1)
CONF_TRUE(conf->ntmode, "ntmode", 1)
CONF_TRUE(conf->qsigfeat, "qsig", 1)
CONF_INTEGER(conf->qsigfeat, "qsig")
if (!strcasecmp(v->name, "callgroup")) {
conf->callgroup = ast_get_group(v->value);
continue;

View File

@ -15,11 +15,10 @@
#define PBX_QSIG_H
#define QSIG_DISABLED 0x00
#define QSIG_ENABLED 0x01
#define QSIG_ENABLED 0x01 /* shouldn't be used anymore */
#define QSIG_TYPE_DEFAULT 0x00 /* use only common features */
#define QSIG_TYPE_ALCATEL 0x01 /* use additional Alcatel features */
#define QSIG_TYPE_HICOM 0x02 /* use additional Hicom features */
#define QSIG_TYPE_ALCATEL_ECMA 0x01 /* use additional Alcatel ECMA */
#define QSIG_TYPE_HICOM_ECMAV2 0x02 /* use additional Hicom ECMA V2 */
#define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */
#define Q932_PROTOCOL_CMIP 0x12 /* Q.941 */
@ -64,6 +63,15 @@
#define ASN1_UTCTIME 0x17
#define ASN1_GENERALIZEDTIME 0x18
/* ASN.1 Type/Tag Class (bits 7 & 6 of Tag octet) */
#define ASN1_TC_UNIVERSAL 0x00
#define ASN1_TC_APPLICATION 0x40
#define ASN1_TC_CONTEXTSPEC 0x80
#define ASN1_TC_PRIVATE 0xC0
/* ASN.1 Type/Tag Form (bit 5 of Tag octet) */
#define ASN1_TF_PRIMITVE 0x00
#define ASN1_TF_CONSTRUCTED 0x20 /* field may be a type of sequence or set */
#define CNIP_CALLINGNAME 0x00 /* Name-Types defined in ECMA-164 */
#define CNIP_CALLEDNAME 0x01
@ -79,6 +87,7 @@
#define CNIP_NAMEUSERPROVIDEDV 0x01 /* Name is User-provided and validated */
#define CCQSIG__ECMA__NAMEPRES 1000 /* Setting an own constant for ECMA Operation/Namepresentation, others will follow */
#define CCQSIG__ECMA__LEGINFO2 1011 /* LEG INFORMATION2 */
/*
* INVOKE Data struct, contains data for further operations
@ -117,73 +126,35 @@ struct cc_qsig_nfe {
/***************** QSIG Core Functions */
/*
* prototypes
*/
/*
*** QSIG Core Functions
*/
/* Create an default QSIG Facility Array */
extern int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int apdu_interpr, struct cc_qsig_nfe *nfe);
extern int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke);
/* Returns an String from ASN.1 Encoded String */
extern unsigned int cc_qsig_asn1_get_string(unsigned char *buf, int buflen, unsigned char *data);
/* Returns an Integer from ASN.1 Encoded Integer */
extern unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx);
/* Returns an Human Readable OID from ASN.1 Encoded OID */
extern unsigned char cc_qsig_asn1_get_oid(unsigned char *data, int *idx);
/* Check if OID is ECMA-ISDN (1.3.12.9.*) */
extern signed int cc_qsig_asn1_check_ecma_isdn_oid(unsigned char *data, int len);
/*
* Valid QSIG-Facility?
* Returns 0 if not
*/
extern unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval);
/*
* 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
*/
extern unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval, int protocol);
extern signed int cc_qsig_check_invoke(unsigned char *data, int *idx);
/*
* Get Invoke ID
* returns current index
* idx points to next byte in array
*/
extern signed int cc_qsig_get_invokeid(unsigned char *data, int *idx, struct cc_qsig_invokedata *invoke);
/* fill the Invoke struct with all the invoke data */
extern signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qsig_invokedata *invoke, int apduval);
/*
* Handles incoming Facilities on CAPI Indications
*/
extern unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i);
/*
* Handles outgoing Facilies on Call SETUP
*/
extern unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i);
/* Identify an INVOKE and return our own Ident Integer (CCQSIG__*) */
extern signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke);
extern signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protocol);
extern unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
/*
*** ECMA QSIG Functions
*/
/* ECMA QSIG Functions */
/* Handle Operation: 1.3.12.9.0-3 ECMA/ISDN/NAMEPRESENTATION */
extern void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
extern int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
extern void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
#endif

View File

@ -0,0 +1,82 @@
/*
* (CAPI*)
*
* An implementation of Common ISDN API 2.0 for
* Asterisk / OpenPBX.org
*
* Copyright (C) 2005-2007 Cytronics & Melware
* 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.
*/
/*
* Decoding of addressing-data-elements from asn1-97
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <asterisk/channel.h>
#include <asterisk/options.h>
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_qsig.h"
#include "chan_capi_qsig_asn197ade.h"
/*
* Returns an "Party Number" from an string, encoded as in addressing-data-elements-asn1-97
* data should be a buffer with max. 20 bytes, according to spec
* return:
* index counter
*/
unsigned int cc_qsig_asn197ade_get_partynumber(unsigned char *buf, int buflen, int *idx, unsigned char *data)
{
int myidx = *idx;
int datalength = data[myidx++];
int numtype = (data[myidx++] & 0x0F); /* defines type of Number: numDigits, publicPartyNum, nsapEncNum, dataNumDigits */
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i\n", numtype); */
switch (numtype){
case 0:
if (data[myidx++] > 0) /* length of this context data */
if (data[myidx++] == ASN1_TC_CONTEXTSPEC)
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data) + 1;
break;
case 1: /* publicPartyNumber (E.164) not supported yet */
return 0;
break;
case 2: /* NsapEncodedNumber (some ATM stuff) not supported yet */
return 0;
break;
case 3:
if (data[myidx++] > 0) /* length of this context data */
if (data[myidx++] == ASN1_TC_CONTEXTSPEC)
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data) + 1;
break;
};
return myidx - *idx;
}
/*
* Returns an string from ASN.1 encoded string
*/
unsigned int cc_qsig_asn197ade_get_numdigits(unsigned char *buf, int buflen, int *idx, unsigned char *data)
{
int strsize;
int myidx = *idx;
strsize = data[myidx++];
if (strsize > buflen)
strsize = buflen;
memcpy(buf, &data[myidx], strsize);
buf[strsize] = 0;
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * string length %i\n", strsize); */
return strsize;
}

View File

@ -0,0 +1,29 @@
/*
* (CAPI*)
*
* An implementation of Common ISDN API 2.0 for
* Asterisk / OpenPBX.org
*
* Copyright (C) 2005-2007 Cytronics & Melware
* 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.
*/
/*
* Decoding of addressing-data-elements from asn1-97
*/
#ifndef PBX_QSIG_ASN197ADE_H
#define PBX_QSIG_ASN197ADE_H
#define ASN197ADE_NUMDIGITS_STRSIZE 20
extern unsigned int cc_qsig_asn197ade_get_partynumber(unsigned char *buf, int buflen, int *idx, unsigned char *data);
extern unsigned int cc_qsig_asn197ade_get_numdigits(unsigned char *buf, int buflen, int *idx, unsigned char *data);
#endif

101
chan_capi_qsig_asn197no.c Normal file
View File

@ -0,0 +1,101 @@
/*
* (CAPI*)
*
* An implementation of Common ISDN API 2.0 for
* Asterisk / OpenPBX.org
*
* Copyright (C) 2005-2007 Cytronics & Melware
* 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.
*/
/*
* Decoding of name-operations from asn1-97
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <asterisk/channel.h>
#include <asterisk/options.h>
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_qsig.h"
#include "chan_capi_qsig_asn197no.h"
/*
* Returns an "Name" from an string, encoded as in name-operations-asn1-97
* data should be a buffer with max. 50 bytes, according to spec
* bufds returns size of name in "buf"
* return:
* index counter
*/
unsigned int cc_qsig_asn197no_get_name(unsigned char *buf, int buflen, unsigned int *bufds, int *idx, unsigned char *data)
{
unsigned int myidx = *idx;
unsigned int nametag;
unsigned int namelength = 0;
unsigned int nametype;
unsigned int namesetlength = 0;
unsigned int namepres;
unsigned int charset = 1;
unsigned int seqlength = 0;
nametag = data[myidx++];
if (nametag == (ASN1_SEQUENCE | ASN1_TC_UNIVERSAL | ASN1_TF_CONSTRUCTED)) { /* 0x30 */
/* This facility is encoded as SEQUENCE */
seqlength = data[++myidx];
myidx++;
cc_verbose(1, 1, VERBOSE_PREFIX_4 " Got name sequence (Length= %i)\n", seqlength);
}
if (nametag < 0x80) { /* Tag shows an simple String */
namelength = cc_qsig_asn1_get_string((unsigned char *)buf, buflen, &data[myidx]);
} else { /* Tag shows an context specific String */
nametype = (nametag & 0x0F); /* Type of Name-Struct */
namepres = nametype; /* Name Presentation or Restriction */
switch (nametype) {
case 0: /* Simple Name */
case 2: /* [LENGTH] [STRING] */
namelength = cc_qsig_asn1_get_string((unsigned char *)buf, buflen, &data[myidx]);
break;
case 1: /* Nameset */
case 3: /* [LENGTH] [BIT-STRING] [LENGTH] [STRING] [INTEGER] [LENGTH] [VALUE] */
namesetlength = data[myidx++];
if (data[myidx++] == ASN1_OCTETSTRING) {
/* should be so */
namelength = cc_qsig_asn1_get_string((unsigned char *)buf, buflen, &data[myidx]);
myidx += data[myidx-1]; /* is this safe? */
} else {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " Namestruct not ECMA conform (String expected)\n");
break;
}
if (data[myidx++] == ASN1_INTEGER) {
charset=cc_qsig_asn1_get_integer(data, &myidx);
} else {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " Namestruct not ECMA conform (Integer expected)\n");
}
break;
case 4: /* Name not available */
break;
case 7: /* Namepres. restricted NULL - don't understand ECMA-164, Page 5 */
break;
}
}
if (namelength > 0) {
myidx += namelength + 1;
*bufds = namelength;
return myidx - *idx;
} else {
return 0;
}
}

28
chan_capi_qsig_asn197no.h Normal file
View File

@ -0,0 +1,28 @@
/*
* (CAPI*)
*
* An implementation of Common ISDN API 2.0 for
* Asterisk / OpenPBX.org
*
* Copyright (C) 2005-2007 Cytronics & Melware
* 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.
*/
/*
* Decoding of name-operations from asn1-97
*/
#ifndef PBX_QSIG_ASN197NO_H
#define PBX_QSIG_ASN197NO_H
#define ASN197NO_NAME_STRSIZE 50
extern unsigned int cc_qsig_asn197no_get_name(unsigned char *buf, int buflen, unsigned int *bufds, int *idx, unsigned char *data);
#endif

View File

@ -23,15 +23,18 @@
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_qsig.h"
#include "chan_capi_qsig_asn197ade.h"
#include "chan_capi_qsig_asn197no.h"
// Returns an String from ASN.1 Encoded String
/*
* Encodes an ASN.1 string
*/
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)) {
// String exceeds buffer size
/* String exceeds buffer size */
return -1;
}
@ -43,7 +46,9 @@ unsigned int cc_qsig_asn1_add_string(unsigned char *buf, int *idx, char *data, i
return 0;
}
// Returns an String from ASN.1 Encoded String
/*
* Returns an string from ASN.1 encoded string
*/
unsigned int cc_qsig_asn1_get_string(unsigned char *buf, int buflen, unsigned char *data)
{
int strsize;
@ -53,20 +58,24 @@ unsigned int cc_qsig_asn1_get_string(unsigned char *buf, int buflen, unsigned ch
if (strsize > buflen)
strsize = buflen - 1;
memcpy(buf, &data[myidx], strsize);
// cc_verbose(1, 1, VERBOSE_PREFIX_4 " get_string length %i\n", strsize);
buf[strsize] = 0;
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " get_string length %i\n", strsize); */
return strsize;
}
/*
* Encode ASN.1 Integer
*/
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)
return -1; // no support at the moment
return -1; /* no support at the moment */
if (value > 255)
intlen++; // we need 2 bytes
intlen++; /* we need 2 bytes */
buf[myidx++] = ASN1_INTEGER;
buf[myidx++] = intlen;
@ -81,15 +90,17 @@ unsigned int cc_qsig_asn1_add_integer(unsigned char *buf, int *idx, int value)
return 0;
}
// Returns an Integer from ASN.1 Encoded Integer
/*
* Returns an Integer from ASN.1 Encoded Integer
*/
unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx)
{ // TODO: not conform with negative Integers
{ /* TODO: not conform with negative integers */
int myidx = *idx;
int intlen;
int temp;
intlen = data[myidx++];
if ((intlen < 1) || (intlen > 2)) { // i don't know if there's a bigger Integer as 16bit -> read specs
if ((intlen < 1) || (intlen > 2)) { /* i don't know if there's a bigger Integer as 16bit -> read specs */
cc_verbose(1, 1, VERBOSE_PREFIX_3 "ASN1Decode: Size of ASN.1 Integer not supported: %i\n", intlen);
*idx = myidx + intlen;
return 0;
@ -104,59 +115,69 @@ unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx)
return temp;
}
// Returns an Human Readable OID from ASN.1 Encoded OID
/*
* Returns an Human Readable OID from ASN.1 Encoded OID
*/
unsigned char cc_qsig_asn1_get_oid(unsigned char *data, int *idx)
{
// TODO: Add code
/* TODO: Add code */
return 0;
}
// Check if OID is ECMA-ISDN (1.3.12.9.*)
/*
* Check if OID is ECMA-ISDN (1.3.12.9.*)
*/
signed int cc_qsig_asn1_check_ecma_isdn_oid(unsigned char *data, int len)
{
// 1.3 .12 .9
/* 1.3 .12 .9 */
if ((data[0] == 0x2B) && (data[1] == 0x0C) && (data[2] == 0x09))
return 0;
return -1;
}
// This function simply updates the length informations of the facility struct
/*
* This function simply updates the length informations of the facility struct
*/
void cc_qsig_update_facility_length(unsigned char * buf, unsigned int idx)
{
buf[0] = idx;
buf[2] = idx-2;
}
// Create Invoke Struct
/*
* Create Invoke Struct
*/
int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int apdu_interpr, struct cc_qsig_nfe *nfe)
{
int myidx = 1; // we start with Index 1 - Byte 0 is Length of Facilitydataarray
int myidx = 1; /* we start with Index 1 - Byte 0 is Length of Facilitydataarray */
buf[myidx++] = 0x1c;
buf[myidx++] = 0; // Byte 2 length of Facilitydataarray
buf[myidx++] = COMP_TYPE_DISCR_SS; // QSIG Facility
// 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
buf[myidx++] = 0; /* Byte 2 length of Facilitydataarray */
buf[myidx++] = COMP_TYPE_DISCR_SS; /* QSIG Facility */
/* 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 */
buf[myidx++] = 0x01;
buf[myidx++] = 0x00; // End PINX hardcoded
buf[myidx++] = 0x82; // Dest. Entity
buf[myidx++] = 0x00; /* End PINX hardcoded */
buf[myidx++] = 0x82; /* Dest. Entity */
buf[myidx++] = 0x01;
buf[myidx++] = 0x00; // End PINX hardcoded
buf[myidx++] = COMP_TYPE_APDU_INTERP; // How to interpret this APDU
buf[myidx++] = 0x01; // Length
buf[myidx++] = 0x00; /* End PINX hardcoded */
buf[myidx++] = COMP_TYPE_APDU_INTERP; /* How to interpret this APDU */
buf[myidx++] = 0x01; /* Length */
buf[myidx++] = apdu_interpr;
// Here will follow now the Invoke
/* Here will follow now the Invoke */
*idx = myidx;
cc_qsig_update_facility_length(buf, myidx);
return 0;
}
// Add invoke to buf
/*
* Add invoke to buf
*/
int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke)
{
int myidx = *idx;
@ -164,7 +185,7 @@ int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_in
int result;
buf[myidx++] = COMP_TYPE_INVOKE;
invlenidx = myidx; // save the Invoke length index for later
invlenidx = myidx; /* save the Invoke length index for later */
buf[myidx++] = 0;
result = cc_qsig_asn1_add_integer(buf, &myidx, invoke->id);
@ -197,7 +218,7 @@ int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_in
break;
}
if (invoke->datalen > 0) { // may be no error, if there's no data
if (invoke->datalen > 0) { /* may be no error, if there's no data */
memcpy(&buf[myidx], invoke->data, invoke->datalen);
myidx += invoke->datalen;
}
@ -211,24 +232,26 @@ int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_in
// Valid QSIG-Facility?
// Returns 0 if not
unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval)
/*
* Valid QSIG-Facility?
* Returns 0 if not
*/
unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval, int protocol)
{
int myidx = *idx;
// First byte after Facility Length
if (data[myidx] == (unsigned char)(0x80 | Q932_PROTOCOL_ROSE)) {
/* First byte after Facility Length */
if (data[myidx] == (unsigned char)(0x80 | protocol)) {
myidx++;
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: ROSE Supplementary Services\n");
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Supplementary Services\n");
if (data[myidx++] == (unsigned char)COMP_TYPE_NFE) {
// Todo: Check Entities?
/* Todo: Check Entities? */
myidx = myidx + data[myidx] + 1;
// cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (idc #1 %i)\n",idx);
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (idc #1 %i)\n",idx); */
if ((data[myidx++] == (unsigned char)COMP_TYPE_APDU_INTERP)) {
myidx = myidx + data[myidx];
*apduval = data[myidx];
// ToDo: implement real reject or clear call ?
/* ToDo: implement real reject or clear call ? */
*idx = ++myidx;
return 1;
}
@ -237,27 +260,34 @@ unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval)
return 0;
}
// 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
/*
* 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
*
*/
signed int cc_qsig_check_invoke(unsigned char *data, int *idx)
{
int myidx = *idx;
if (data[myidx] == (unsigned char)COMP_TYPE_INVOKE) {
// is an INVOKE_IDENT
*idx = myidx + 1; // Set index to first byte of component
// cc_verbose(1, 1, VERBOSE_PREFIX_4 "CONNECT_IND (Invoke Length %i)\n", data[myidx+1]);
return data[myidx + 1]; // return component length
/* is an INVOKE_IDENT */
*idx = myidx + 1; /* Set index to length byte of component */
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 "CONNECT_IND (Invoke Length %i)\n", data[myidx+1]); */
return data[myidx + 1]; /* return component length */
}
*idx = ++myidx;
return -1; // what to do now? got no Invoke
return -1; /* what to do now? got no Invoke */
}
// Get Invoke ID
// returns current index
// idx points to next byte in array
/*
* Get Invoke ID
* returns current index
* idx points to next byte in array
*/
signed int cc_qsig_get_invokeid(unsigned char *data, int *idx, struct cc_qsig_invokedata *invoke)
{
int myidx;
@ -270,23 +300,27 @@ signed int cc_qsig_get_invokeid(unsigned char *data, int *idx, struct cc_qsig_in
invoffset = myidx;
invlen = data[myidx++];
if (invlen > 0) {
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
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 */
if (invidtype != ASN1_INTEGER) {
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unknown Invoke Identifier Type 0x%#x\n", invidtype);
return -1;
}
*idx = myidx;
temp = cc_qsig_asn1_get_integer(data, idx);
temp = cc_qsig_asn1_get_integer(data, &myidx);
invoke->id = temp;
// cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (Invoke Identifier %#x)\n", temp);
// *idx=myidx; // Set by cc_qsig_asn1get_integer
*idx = myidx;
/* *idx += invlen + 1; */
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (Invoke Identifier %#x)\n", temp); */
/* *idx=myidx; /* Set by cc_qsig_asn1get_integer */
}
return 0;
}
// fill the Invoke struct with all the invoke data
/*
* fill the Invoke struct with all the invoke data
*/
signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qsig_invokedata *invoke, int apduval)
{
int myidx = *idx;
@ -295,16 +329,16 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
int temp2;
int datalen;
invoptyp = data[myidx++]; // Invoke Operation Type 0x02=INTEGER, 0x06=OID
invoptyp = data[myidx++]; /* Invoke Operation Type 0x02=INTEGER, 0x06=OID */
switch (invoptyp) {
case ASN1_INTEGER:
invoke->apdu_interpr = apduval;
temp = cc_qsig_asn1_get_integer(data, idx);
temp = cc_qsig_asn1_get_integer(data, &myidx);
invoke->descr_type = ASN1_INTEGER;
invoke->type = temp;
myidx++; // component length
//datalen=data[myidx++]; // maybe correct, better we calculate the datalength
temp2 = (invoke->len) + (invoke->offset) + 1; // Array End = Invoke Length + Invoke Offset +1
/*myidx++;*/ /* component length */
/*datalen=data[myidx++]; /* maybe correct, better we calculate the datalength */
temp2 = (invoke->len) + (invoke->offset) + 1; /* Array End = Invoke Length + Invoke Offset +1 */
datalen = temp2 - myidx;
if (datalen > 255) {
@ -313,8 +347,8 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
}
invoke->datalen = datalen;
memcpy(invoke->data, &data[myidx], datalen); // copy data of Invoke Operation
myidx = myidx + datalen; // points to next INVOKE component, if there's any
memcpy(invoke->data, &data[myidx], datalen); /* copy data of Invoke Operation */
myidx = myidx + datalen; /* points to next INVOKE component, if there's any */
*idx = myidx;
break;
@ -322,20 +356,20 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
case ASN1_OBJECTIDENTIFIER:
invoke->apdu_interpr = apduval;
invoke->descr_type = ASN1_OBJECTIDENTIFIER;
temp = data[myidx++]; // Length of OID
temp = data[myidx++]; /* Length of OID */
if (temp > 20) {
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unsupported INVOKE Operation OID Size (max 20 Bytes): %i\n", temp);
temp = 20;
}
// TODO: Maybe we decode the OID here and be verbose - have to write cc_qsig_asn1get_oid
/* TODO: Maybe we decode the OID here and be verbose - have to write cc_qsig_asn1get_oid */
// cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (OID, Length %i)\n", temp);
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (OID, Length %i)\n", temp); */
invoke->oid_len = temp;
memcpy(invoke->oid_bin, &data[myidx], temp); // Copy OID to separate array
myidx = myidx + temp; // Set index to next information
memcpy(invoke->oid_bin, &data[myidx], temp); /* Copy OID to separate array */
myidx = myidx + temp; /* Set index to next information */
temp2 = (invoke->len) + (invoke->offset) + 1; // Array End = Invoke Length + Invoke Offset +1
temp2 = (invoke->len) + (invoke->offset) + 1; /* Array End = Invoke Length + Invoke Offset +1 */
datalen = temp2 - myidx;
if (datalen > 255) {
@ -343,10 +377,10 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
datalen = 255;
}
// cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (OID, Datalength %i)\n",datalen);
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (OID, Datalength %i)\n",datalen); */
invoke->datalen = datalen;
memcpy(invoke->data, &data[myidx], datalen); // copy data of Invoke Operation
myidx = myidx + datalen; // points to next INVOKE component, if there's any
memcpy(invoke->data, &data[myidx], datalen); /* copy data of Invoke Operation */
myidx = myidx + datalen; /* points to next INVOKE component, if there's any */
*idx = myidx;
break;
@ -354,7 +388,7 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
default:
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unknown INVOKE Operation Type: %i\n", invoptyp);
temp2 = (invoke->len) + (invoke->offset) + 1; // Array End = Invoke Length + Invoke Offset +1
temp2 = (invoke->len) + (invoke->offset) + 1; /* Array End = Invoke Length + Invoke Offset +1 */
datalen = temp2 - myidx;
if (datalen > 255) {
@ -362,57 +396,95 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
datalen = 255;
}
*idx = datalen; // Set index to next INVOKE, if there's any
*idx = datalen; /* Set index to next INVOKE, if there's any */
return -1;
break;
}
return 0; // No problems
return 0; /* No problems */
}
// Identify an INVOKE and return our own Ident Integer (CCQSIG__*)
signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke)
/*
* Identify an INVOKE and return our own Ident Integer (CCQSIG__*)
*/
signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protocol)
{
int invokedescrtype = 0;
int datalen;
// cc_verbose(1, 1, VERBOSE_PREFIX_4 "CONNECT_IND (Ident Invoke %i)\n", invoke->descr_type);
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 "CONNECT_IND (Ident Invoke %i)\n", invoke->descr_type); */
switch (invoke->descr_type) {
case ASN1_INTEGER:
invokedescrtype = 1;
switch (protocol) {
case QSIG_TYPE_ALCATEL_ECMA:
switch (invoke->descr_type) {
case ASN1_INTEGER:
invokedescrtype = 1;
break;
case ASN1_OBJECTIDENTIFIER:
invokedescrtype = 2;
datalen = invoke->oid_len;
if ((datalen) == 4) {
if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) {
switch (invoke->oid_bin[3]) {
case 0: /* ECMA QSIG Name Presentation */
return CCQSIG__ECMA__NAMEPRES;
case 21:
return CCQSIG__ECMA__LEGINFO2;
default: /* Unknown Operation */
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ECMA-ISDN QSIG INVOKE (%i)\n", invoke->oid_bin[3]);
return 0;
}
}
}
break;
default:
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unidentified INVOKE OP\n");
break;
}
break;
case ASN1_OBJECTIDENTIFIER:
invokedescrtype = 2;
datalen = invoke->oid_len;
if ((datalen) == 4) {
if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) {
switch (invoke->oid_bin[3]) {
case 0: // ECMA QSIG Name Presentation
case QSIG_TYPE_HICOM_ECMAV2:
switch (invoke->descr_type) {
case ASN1_INTEGER:
invokedescrtype = 1;
switch (invoke->type) {
case 0:
return CCQSIG__ECMA__NAMEPRES;
default: // Unknown Operation
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ECMA-ISDN QSIG INVOKE (%i)\n", invoke->oid_bin[3]);
case 21:
return CCQSIG__ECMA__LEGINFO2;
default:
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled QSIG INVOKE (%i)\n", invoke->type);
return 0;
}
}
break;
case ASN1_OBJECTIDENTIFIER:
invokedescrtype = 2;
break;
default:
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unidentified INVOKE OP\n");
break;
}
break;
default:
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unidentified INVOKE OP\n");
break;
}
return 0;
}
/*
*
*/
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;
case CCQSIG__ECMA__LEGINFO2:
cc_qsig_op_ecma_isdn_leginfo2(invoke, i);
break;
default:
break;
}
@ -424,36 +496,64 @@ unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invo
*/
unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i)
{
int faclen;
int faclen = 0;
int facidx = 2;
int action_unkn_apdu; // What to do with unknown Invoke-APDUs (0=Ignore, 1=clear call, 2=reject APDU)
int action_unkn_apdu; /* What to do with unknown Invoke-APDUs (0=Ignore, 1=clear call, 2=reject APDU) */
int invoke_len; // Length of Invoke APDU
unsigned int invoke_op; // Invoke Operation ID
int invoke_len; /* Length of Invoke APDU */
unsigned int invoke_op; /* Invoke Operation ID */
struct cc_qsig_invokedata invoke;
int invoketmp1;
if (data) {
faclen=data[facidx];
// cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (Got Facility IE, Length=%#x)\n", faclen);
faclen=data[facidx-2];
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (Got Facility IE, Length=%#x)\n", faclen); */
facidx++;
if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu)) {
// cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND ROSE Supplementary Services (APDU Interpretation: %i)\n", action_unkn_apdu);
while ((facidx-1)<faclen) {
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);
cc_qsig_handle_invokeoperation(invoke_op, &invoke, i);
while (facidx < faclen) {
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Checking Facility at index %i\n", facidx);
switch (i->qsigfeat) {
case QSIG_TYPE_ALCATEL_ECMA:
if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu, Q932_PROTOCOL_ROSE)) {
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND ROSE Supplementary Services (APDU Interpretation: %i)\n", action_unkn_apdu); */
while ((facidx-1)<faclen) {
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);
cc_qsig_handle_invokeoperation(invoke_op, &invoke, i);
}
} else {
/* Not an Invoke */
}
}
}
} else {
// Not an Invoke
}
break;
case QSIG_TYPE_HICOM_ECMAV2:
if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu, Q932_PROTOCOL_EXTENSIONS)) {
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND ROSE Supplementary Services (APDU Interpretation: %i)\n", action_unkn_apdu); */
while ((facidx-1)<faclen) {
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);
cc_qsig_handle_invokeoperation(invoke_op, &invoke, i);
}
} else {
/* Not an Invoke */
}
}
}
break;
default:
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Unknown QSIG protocol configured (%i)\n", i->qsigfeat);
break;
}
}
}
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Facility done at index %i from %i\n", facidx, faclen);
return 0;
}
@ -467,8 +567,11 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
struct cc_qsig_nfe nfe;
unsigned int dataidx;
/*mg:remember me switch (i->doqsig) {*/
cc_qsig_build_facility_struct(data, &dataidx, APDUINTERPRETATION_IGNORE, &nfe);
cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i);
cc_qsig_add_invoke(data, &dataidx, &invoke);
/* }*/
return 0;
}

View File

@ -23,81 +23,81 @@
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_qsig.h"
#include "chan_capi_qsig_asn197ade.h"
#include "chan_capi_qsig_asn197no.h"
/* Handle Operation: 1.3.12.9.0-3 ECMA/ISDN/NAMEPRESENTATION */
/*
* Handle Operation: 1.3.12.9.0-3 ECMA/ISDN/NAMEPRESENTATION
*
* This function decodes the namepresentation facility
* The name will be copied in the cid.cid_name field of the asterisk channel struct
*
* parameters
* invoke struct, which contains encoded data from facility
* i is pointer to capi channel
* returns
* nothing
*/
void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{
char callername[50]; /* ECMA defines max length to 50 */
char callername[51]; /* ECMA defines max length to 50 */
unsigned int namelength = 0;
unsigned int namesetlength = 0;
unsigned int charset = 1;
unsigned int namepres;
unsigned int nametype;
unsigned int datalength;
int myidx = 0;
cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling Name Operation (id# %#x)\n", invoke->id);
datalength = invoke->datalen;
namepres = (invoke->data[myidx] & 0xF0); /* Name Presentation or Restriction */
nametype = (invoke->data[myidx++] & 0x0F); /* Type of Name-Struct */
switch (nametype) {
case 0: /* Simple Name */
case 2: /* [LENGTH] [STRING] */
namelength = cc_qsig_asn1_get_string((unsigned char *)callername, sizeof(callername), &invoke->data[myidx]);
callername[namelength] = 0;
break;
case 1: /* Nameset */
case 3: /* [LENGTH] [BIT-STRING] [LENGTH] [STRING] [INTEGER] [LENGTH] [VALUE] */
namesetlength = invoke->data[myidx++];
if (invoke->data[myidx++] == ASN1_OCTETSTRING) {
/* should be so */
namelength = cc_qsig_asn1_get_string((unsigned char *)callername, sizeof(callername), &invoke->data[myidx]);
callername[namelength] = 0;
myidx += invoke->data[myidx-1]; /* is this safe? */
} else {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " Namestruct not ECMA conform (String expected)\n");
break;
}
if (invoke->data[myidx++] == ASN1_INTEGER) {
charset=cc_qsig_asn1_get_integer(invoke->data, &myidx);
} else {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " Namestruct not ECMA conform (Integer expected)\n");
}
break;
case 4: /* Name not available */
break;
case 7: /* Namepres. restricted NULL - don't understand ECMA-164, Page 5 */
break;
}
myidx = cc_qsig_asn197no_get_name(callername, ASN197NO_NAME_STRSIZE, &namelength, &myidx, invoke->data );
if (namelength > 0) {
/* TODO: Maybe we do some charset conversions */
i->owner->cid.cid_name = strdup(callername);
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " callers name length: %i, \"%s\"\n", namelength, callername); */
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * received name (%i byte(s)): \"%s\"\n", namelength, callername);
}
/* if there was an sequence tag, we have more informations here, but we will ignore it at the moment */
}
/*
* Encode Operation: 1.3.12.9.0-3 ECMA/ISDN/NAMEPRESENTATION
*
* This function encodes the namepresentation facility
* The name will be copied from the cid.cid_name field of the asterisk channel struct.
* We create an invoke struct with the complete encoded invoke.
*
* parameters
* buf is pointer to facility array, not used now
* idx current idx in facility array, not used now
* invoke struct, which contains encoded data for facility
* i is pointer to capi channel
* returns
* always 0
*/
int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{
const unsigned char oid[] = {0x2b,0x0c,0x09,0x00}; /* 1.3.12.9.0 */
int oid_len = sizeof(oid);
unsigned char namebuf[50];
unsigned char namebuf[51];
unsigned char data[255];
int dataidx = 0;
int namelen = 0;
/*TODO: write something */
namelen = strlen(i->owner->cid.cid_name);
if (i->owner->cid.cid_name)
namelen = strlen(i->owner->cid.cid_name);
if (namelen < 1) { /* There's no name available, try to take Interface-Name */
if (strlen(i->name) >= 1) {
if (namelen > 50)
namelen = 50;
namelen = strlen(i->name);
memcpy(namebuf, i->name, namelen);
if (i->name) {
if (strlen(i->name) >= 1) {
if (namelen > 50)
namelen = 50;
namelen = strlen(i->name);
memcpy(namebuf, i->name, namelen);
}
}
} else {
if (namelen > 50)
@ -127,3 +127,121 @@ int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, stru
return 0;
}
/*
* Handle Operation: 1.3.12.9.21 ECMA/ISDN/LEG_INFORMATION2
*
* This function decodes the namepresentation facility
* The name will be copied in the cid.cid_name field of the asterisk channel struct
*
* parameters
* invoke struct, which contains encoded data from facility
* i is pointer to capi channel
* returns
* nothing
*/
void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{
unsigned int datalength;
unsigned int seqlength = 0;
int myidx = 0;
unsigned int parameter = 0;
unsigned int divCount = 0;
unsigned int divReason = 0;
unsigned int orgDivReason = 0;
char tempstr[5];
unsigned char divertNum[ASN197ADE_NUMDIGITS_STRSIZE+1];
unsigned char origCalledNum[ASN197ADE_NUMDIGITS_STRSIZE+1];
unsigned char divertName[ASN197NO_NAME_STRSIZE+1];
unsigned char origCalledName[ASN197NO_NAME_STRSIZE+1];
unsigned int temp = 0;
unsigned int temp2 = 0;
divertNum[0] = 0;
origCalledNum[0] = 0;
divertNum[0] = 0;
divertName[0] = 0;
origCalledName[0] = 0;
cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling QSIG LEG INFO2 (id# %#x)\n", invoke->id);
if (invoke->data[myidx++] != (ASN1_SEQUENCE | ASN1_TC_UNIVERSAL | ASN1_TF_CONSTRUCTED)) { /* 0x30 */
/* We do not handle this, because it should start with an sequence tag */
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG LEG INFO2 - not a sequence\n");
return;
}
/* This facility is encoded as SEQUENCE */
seqlength = invoke->data[myidx++];
datalength = invoke->datalen;
if (datalength < (seqlength+1)) {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG LEG INFO2 - buffer error\n");
return;
}
if (invoke->data[myidx++] == ASN1_INTEGER)
divCount = cc_qsig_asn1_get_integer(invoke->data, &myidx);
if (invoke->data[myidx++] == ASN1_ENUMERATED)
divReason = cc_qsig_asn1_get_integer(invoke->data, &myidx);
while (myidx < datalength) {
parameter = (invoke->data[myidx++] & 0x0f);
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Found parameter %i\n", parameter);
switch (parameter) {
case 0:
myidx++; /* Ignore Length of enumeration tag*/
if (invoke->data[myidx++] == ASN1_ENUMERATED)
orgDivReason = cc_qsig_asn1_get_integer(invoke->data, &myidx);
break;
case 1:
temp = cc_qsig_asn197ade_get_partynumber(divertNum, ASN197ADE_NUMDIGITS_STRSIZE, &myidx, invoke->data);
if (temp) {
myidx += temp;
}
break;
case 2:
temp = cc_qsig_asn197ade_get_partynumber(origCalledNum, ASN197ADE_NUMDIGITS_STRSIZE, &myidx, invoke->data);
if (temp) {
myidx += temp;
}
break;
case 3:
/* Redirecting Name */
myidx++;
temp = cc_qsig_asn197no_get_name(divertName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data);
if (temp) {
myidx += temp;
}
break;
case 4:
/* origCalled Name */
myidx++;
temp = cc_qsig_asn197no_get_name(origCalledName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data);
if (temp) {
myidx += temp;
}
break;
}
}
snprintf(tempstr, 5, "%i", divReason);
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVREASON", tempstr);
snprintf(tempstr, 5, "%i", orgDivReason);
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVREASON", tempstr);
snprintf(tempstr, 5, "%i", divCount);
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVCOUNT", tempstr);
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVNUM", divertNum);
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVNUM", origCalledNum);
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVNAME", divertName);
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVNAME", origCalledName);
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_LEG_INFO2: (%i(%i), %ix %s->%s, %s->%s)\n", divReason, orgDivReason, divCount, origCalledNum, divertNum, origCalledName, divertName);
return;
}