From 8c79f0d18adf45ab359b7827e0a7ccb0c44a2b0d Mon Sep 17 00:00:00 2001 From: MelwareDE Date: Sat, 10 Mar 2007 14:23:20 +0000 Subject: [PATCH] QSIG: - many bugfixes on name presentation handling - added support for different qsig variants - added support for rerouting informations on incoming calls - code cleanup --- Makefile | 2 +- README.qsig | 35 +++- chan_capi.c | 6 +- chan_capi_qsig.h | 81 +++------ chan_capi_qsig_asn197ade.c | 82 +++++++++ chan_capi_qsig_asn197ade.h | 29 ++++ chan_capi_qsig_asn197no.c | 101 +++++++++++ chan_capi_qsig_asn197no.h | 28 +++ chan_capi_qsig_core.c | 337 ++++++++++++++++++++++++------------- chan_capi_qsig_ecma.c | 210 ++++++++++++++++++----- 10 files changed, 683 insertions(+), 228 deletions(-) create mode 100644 chan_capi_qsig_asn197ade.c create mode 100644 chan_capi_qsig_asn197ade.h create mode 100644 chan_capi_qsig_asn197no.c create mode 100644 chan_capi_qsig_asn197no.h diff --git a/Makefile b/Makefile index 5c9a86f..4f30002 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.qsig b/README.qsig index 8786b97..e1537e7 100644 --- a/README.qsig +++ b/README.qsig @@ -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 diff --git a/chan_capi.c b/chan_capi.c index e260816..f712553 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -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; diff --git a/chan_capi_qsig.h b/chan_capi_qsig.h index 3d2b247..d329d20 100644 --- a/chan_capi_qsig.h +++ b/chan_capi_qsig.h @@ -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 diff --git a/chan_capi_qsig_asn197ade.c b/chan_capi_qsig_asn197ade.c new file mode 100644 index 0000000..c163b3e --- /dev/null +++ b/chan_capi_qsig_asn197ade.c @@ -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 + * Mario Goegel + * + * 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 +#include +#include + +#include +#include +#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; +} diff --git a/chan_capi_qsig_asn197ade.h b/chan_capi_qsig_asn197ade.h new file mode 100644 index 0000000..ba065b9 --- /dev/null +++ b/chan_capi_qsig_asn197ade.h @@ -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 + * Mario Goegel + * + * 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 diff --git a/chan_capi_qsig_asn197no.c b/chan_capi_qsig_asn197no.c new file mode 100644 index 0000000..f4cb9cf --- /dev/null +++ b/chan_capi_qsig_asn197no.c @@ -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 + * Mario Goegel + * + * 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 +#include +#include + +#include +#include +#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; + } + +} diff --git a/chan_capi_qsig_asn197no.h b/chan_capi_qsig_asn197no.h new file mode 100644 index 0000000..708cd0f --- /dev/null +++ b/chan_capi_qsig_asn197no.h @@ -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 + * Mario Goegel + * + * 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 diff --git a/chan_capi_qsig_core.c b/chan_capi_qsig_core.c index a83376b..c3f580e 100644 --- a/chan_capi_qsig_core.c +++ b/chan_capi_qsig_core.c @@ -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)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)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)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; } + diff --git a/chan_capi_qsig_ecma.c b/chan_capi_qsig_ecma.c index 8679b22..18bab57 100644 --- a/chan_capi_qsig_ecma.c +++ b/chan_capi_qsig_ecma.c @@ -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; + +}