QSIG:
- 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:
parent
0208255abd
commit
8c79f0d18a
2
Makefile
2
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
|
||||
|
||||
|
|
35
README.qsig
35
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue