QSIG:
- some code cleanups - enhanced debugging output (Object Identifier Decoder) - prepared name handling for call transfer this code would also allow to send an CONNECTED NAME facility
This commit is contained in:
parent
4d614104eb
commit
e013fdd7f5
16
chan_capi.c
16
chan_capi.c
|
@ -4832,6 +4832,22 @@ int mkif(struct cc_capi_conf *conf)
|
||||||
tmp->capability = conf->capability;
|
tmp->capability = conf->capability;
|
||||||
|
|
||||||
tmp->qsigfeat = conf->qsigfeat;
|
tmp->qsigfeat = conf->qsigfeat;
|
||||||
|
if (conf->qsigfeat) {
|
||||||
|
tmp->qsig_data.calltransfer_active = 0;
|
||||||
|
tmp->qsig_data.calltransfer = 0;
|
||||||
|
tmp->qsig_data.calltransfer_onring = 0;
|
||||||
|
tmp->qsig_data.callmark = 0;
|
||||||
|
tmp->qsig_data.dnameid = NULL;
|
||||||
|
|
||||||
|
/* Path Replacement */
|
||||||
|
tmp->qsig_data.pr_propose_sendback = 0; /* send back an prior received PR PROPOSE on Connect */
|
||||||
|
tmp->qsig_data.pr_propose_cid = NULL; /* Call identity */
|
||||||
|
tmp->qsig_data.pr_propose_pn = NULL; /* Party Number */
|
||||||
|
|
||||||
|
/* Partner Channel - needed for many features */
|
||||||
|
tmp->qsig_data.partner_ch = NULL;
|
||||||
|
tmp->qsig_data.partner_plci = 0;
|
||||||
|
}
|
||||||
|
|
||||||
tmp->next = capi_iflist; /* prepend */
|
tmp->next = capi_iflist; /* prepend */
|
||||||
capi_iflist = tmp;
|
capi_iflist = tmp;
|
||||||
|
|
|
@ -262,6 +262,8 @@ struct cc_qsig_data {
|
||||||
int calltransfer_onring;
|
int calltransfer_onring;
|
||||||
unsigned int callmark;
|
unsigned int callmark;
|
||||||
|
|
||||||
|
char *dnameid;
|
||||||
|
|
||||||
/* Path Replacement */
|
/* Path Replacement */
|
||||||
int pr_propose_sendback; /* send back an prior received PR PROPOSE on Connect */
|
int pr_propose_sendback; /* send back an prior received PR PROPOSE on Connect */
|
||||||
char *pr_propose_cid; /* Call identity */
|
char *pr_propose_cid; /* Call identity */
|
||||||
|
|
|
@ -127,10 +127,40 @@ unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx)
|
||||||
*/
|
*/
|
||||||
unsigned char *cc_qsig_asn1_oid2str(unsigned char *data, int size)
|
unsigned char *cc_qsig_asn1_oid2str(unsigned char *data, int size)
|
||||||
{
|
{
|
||||||
/* TODO: Add code */
|
unsigned char buf[1024];
|
||||||
|
char numbuf[10];
|
||||||
|
unsigned char *s;
|
||||||
|
int len, i;
|
||||||
|
unsigned long n;
|
||||||
|
|
||||||
|
s = buf;
|
||||||
|
if (size < 3) {
|
||||||
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "OID2STR: Object identifier too small (%i).\n", size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define N(n) \
|
||||||
|
snprintf(numbuf, sizeof numbuf, "%lu", (unsigned long)n); \
|
||||||
|
len = strlen(numbuf); \
|
||||||
|
memcpy(s, numbuf, len); \
|
||||||
|
s += len;
|
||||||
|
|
||||||
|
N(data[0] / 40)
|
||||||
|
*s++ = '.';
|
||||||
|
N(data[0] % 40)
|
||||||
|
n = 0;
|
||||||
|
for (i = 1; i < size; i++) {
|
||||||
|
n = n << 7 | (data[i] & 0x7f);
|
||||||
|
if ((data[i] & 0x80) == 0) {
|
||||||
|
*s++ = '.';
|
||||||
|
N(n)
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = buf;
|
||||||
|
return (unsigned char *) strdup((char*)s);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -230,7 +260,7 @@ int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_in
|
||||||
case ASN1_INTEGER:
|
case ASN1_INTEGER:
|
||||||
result = cc_qsig_asn1_add_integer(buf, &myidx, invoke->type);
|
result = cc_qsig_asn1_add_integer(buf, &myidx, invoke->type);
|
||||||
if (result) {
|
if (result) {
|
||||||
cc_log(LOG_ERROR, "QSIG: Cannot add invoke, identifier is not encoded!\n");
|
cc_log(LOG_ERROR, "QSIG: Cannot add invoke, type is not encoded!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -395,11 +425,16 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
|
||||||
|
|
||||||
/* 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); */
|
|
||||||
invoke->oid_len = temp;
|
invoke->oid_len = temp;
|
||||||
memcpy(invoke->oid_bin, &data[myidx], temp); /* Copy OID to separate array */
|
memcpy(invoke->oid_bin, &data[myidx], temp); /* Copy OID to separate array */
|
||||||
myidx = myidx + temp; /* Set index to next information */
|
myidx = myidx + temp; /* Set index to next information */
|
||||||
|
|
||||||
|
if (temp == 4) { /* even if we have an OID, set the numeric invoke type */
|
||||||
|
invoke->type = (int) invoke->oid_bin[3];
|
||||||
|
} else {
|
||||||
|
invoke->type = -1;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
datalen = temp2 - myidx;
|
||||||
|
|
||||||
|
@ -408,7 +443,6 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
|
||||||
datalen = 255;
|
datalen = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (OID, Datalength %i)\n",datalen); */
|
|
||||||
invoke->datalen = datalen;
|
invoke->datalen = datalen;
|
||||||
memcpy(invoke->data, &data[myidx], datalen); /* copy data of Invoke Operation */
|
memcpy(invoke->data, &data[myidx], datalen); /* copy data of Invoke Operation */
|
||||||
myidx += datalen; /* points to next INVOKE component, if there's any */
|
myidx += datalen; /* points to next INVOKE component, if there's any */
|
||||||
|
@ -435,6 +469,24 @@ signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qs
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ident_qsig_invoke(int invoketype)
|
||||||
|
{
|
||||||
|
switch (invoketype) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
return CCQSIG__ECMA__NAMEPRES;
|
||||||
|
case 4:
|
||||||
|
return CCQSIG__ECMA__PRPROPOSE;
|
||||||
|
case 21:
|
||||||
|
return CCQSIG__ECMA__LEGINFO2;
|
||||||
|
default:
|
||||||
|
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled QSIG INVOKE (%i)\n", invoketype);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Identify an INVOKE and return our own Ident Integer (CCQSIG__*)
|
* Identify an INVOKE and return our own Ident Integer (CCQSIG__*)
|
||||||
*/
|
*/
|
||||||
|
@ -450,37 +502,26 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
|
||||||
switch (invoke->descr_type) {
|
switch (invoke->descr_type) {
|
||||||
case ASN1_INTEGER:
|
case ASN1_INTEGER:
|
||||||
invokedescrtype = 1;
|
invokedescrtype = 1;
|
||||||
switch (invoke->type) {
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%i)\n", invoke->type);
|
||||||
case 0:
|
return ident_qsig_invoke(invoke->type);
|
||||||
return CCQSIG__ECMA__NAMEPRES;
|
|
||||||
case 4:
|
|
||||||
return CCQSIG__ECMA__PRPROPOSE;
|
|
||||||
case 21:
|
|
||||||
return CCQSIG__ECMA__LEGINFO2;
|
|
||||||
default:
|
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ECMA-ISDN QSIG INVOKE (%i)\n", invoke->type);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ASN1_OBJECTIDENTIFIER:
|
case ASN1_OBJECTIDENTIFIER:
|
||||||
invokedescrtype = 2;
|
invokedescrtype = 2;
|
||||||
datalen = invoke->oid_len;
|
datalen = invoke->oid_len;
|
||||||
if ((datalen) == 4) {
|
|
||||||
if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) {
|
unsigned char *oidstr = NULL;
|
||||||
switch (invoke->oid_bin[3]) {
|
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
|
||||||
case 0: /* ECMA QSIG Name Presentation */
|
if (oidstr) {
|
||||||
return CCQSIG__ECMA__NAMEPRES;
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
|
||||||
case 4:
|
free(oidstr);
|
||||||
return CCQSIG__ECMA__PRPROPOSE;
|
|
||||||
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 -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((datalen) == 4) {
|
||||||
|
if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) {
|
||||||
|
return ident_qsig_invoke( (int)invoke->oid_bin[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unidentified INVOKE OP\n");
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unidentified INVOKE OP\n");
|
||||||
|
@ -491,34 +532,23 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
|
||||||
switch (invoke->descr_type) {
|
switch (invoke->descr_type) {
|
||||||
case ASN1_INTEGER:
|
case ASN1_INTEGER:
|
||||||
invokedescrtype = 1;
|
invokedescrtype = 1;
|
||||||
switch (invoke->type) {
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%i)\n", invoke->type);
|
||||||
case 0:
|
return ident_qsig_invoke(invoke->type);
|
||||||
return CCQSIG__ECMA__NAMEPRES;
|
|
||||||
case 4:
|
|
||||||
return CCQSIG__ECMA__PRPROPOSE;
|
|
||||||
case 21:
|
|
||||||
return CCQSIG__ECMA__LEGINFO2;
|
|
||||||
default:
|
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ISO QSIG INVOKE (%i)\n", invoke->type);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ASN1_OBJECTIDENTIFIER:
|
case ASN1_OBJECTIDENTIFIER:
|
||||||
invokedescrtype = 2;
|
invokedescrtype = 2;
|
||||||
datalen = invoke->oid_len;
|
datalen = invoke->oid_len;
|
||||||
|
|
||||||
|
unsigned char *oidstr = NULL;
|
||||||
|
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
|
||||||
|
if (oidstr) {
|
||||||
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
|
||||||
|
free(oidstr);
|
||||||
|
}
|
||||||
|
|
||||||
if ((datalen) == 4) {
|
if ((datalen) == 4) {
|
||||||
if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) {
|
if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) {
|
||||||
switch (invoke->oid_bin[3]) {
|
return ident_qsig_invoke( (int)invoke->oid_bin[3]);
|
||||||
case 0: /* ECMA QSIG Name Presentation */
|
|
||||||
return CCQSIG__ECMA__NAMEPRES;
|
|
||||||
case 4:
|
|
||||||
return CCQSIG__ECMA__PRPROPOSE;
|
|
||||||
case 21:
|
|
||||||
return CCQSIG__ECMA__LEGINFO2;
|
|
||||||
default: /* Unknown Operation */
|
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ISO QSIG INVOKE (%i)\n", invoke->oid_bin[3]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -968,6 +998,8 @@ void interface_cleanup_qsig(struct capi_pvt *i)
|
||||||
free(i->qsig_data.pr_propose_cid);
|
free(i->qsig_data.pr_propose_cid);
|
||||||
if (i->qsig_data.pr_propose_pn)
|
if (i->qsig_data.pr_propose_pn)
|
||||||
free(i->qsig_data.pr_propose_pn);
|
free(i->qsig_data.pr_propose_pn);
|
||||||
|
if (i->qsig_data.dnameid)
|
||||||
|
free(i->qsig_data.dnameid);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1133,6 +1165,10 @@ void pbx_capi_qsig_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsign
|
||||||
case 0x800d: /* SETUP ACK */
|
case 0x800d: /* SETUP ACK */
|
||||||
break;
|
break;
|
||||||
case 0x800f: /* CONNECT ACK */
|
case 0x800f: /* CONNECT ACK */
|
||||||
|
{
|
||||||
|
unsigned int qsiginvoke;
|
||||||
|
qsiginvoke = cc_qsig_handle_capi_facilityind( (unsigned char*) INFO_IND_INFOELEMENT(CMSG), i);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x8045: /* DISCONNECT */
|
case 0x8045: /* DISCONNECT */
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,6 +46,7 @@ void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct cap
|
||||||
unsigned int namelength = 0;
|
unsigned int namelength = 0;
|
||||||
unsigned int datalength;
|
unsigned int datalength;
|
||||||
int myidx = 0;
|
int myidx = 0;
|
||||||
|
char *nametype = NULL;
|
||||||
|
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling Name Operation (id# %#x)\n", invoke->id);
|
cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling Name Operation (id# %#x)\n", invoke->id);
|
||||||
|
|
||||||
|
@ -53,11 +54,44 @@ void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct cap
|
||||||
|
|
||||||
myidx = cc_qsig_asn197no_get_name(callername, ASN197NO_NAME_STRSIZE, &namelength, &myidx, invoke->data );
|
myidx = cc_qsig_asn197no_get_name(callername, ASN197NO_NAME_STRSIZE, &namelength, &myidx, invoke->data );
|
||||||
|
|
||||||
if (namelength > 0) {
|
if (namelength == 0) {
|
||||||
/* TODO: Maybe we do some charset conversions */
|
return;
|
||||||
i->owner->cid.cid_name = strdup(callername);
|
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * received name (%i byte(s)): \"%s\"\n", namelength, callername);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Maybe we do some charset conversions */
|
||||||
|
|
||||||
|
switch (invoke->type) {
|
||||||
|
case 0: /* Calling Name */
|
||||||
|
nametype = "CALLING NAME";
|
||||||
|
break;
|
||||||
|
case 1: /* Called Name */
|
||||||
|
nametype = "CALLED NAME";
|
||||||
|
break;
|
||||||
|
case 2: /* Connected Name */
|
||||||
|
nametype = "CONNECTED NAME";
|
||||||
|
break;
|
||||||
|
case 3: /* Busy Name */
|
||||||
|
nametype = "BUSY NAME";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (invoke->type) {
|
||||||
|
case 0: /* Calling Name */
|
||||||
|
i->owner->cid.cid_name = strdup(callername); /* Save name to callerid */
|
||||||
|
break;
|
||||||
|
case 1: /* Called Name */
|
||||||
|
case 2: /* Connected Name */
|
||||||
|
case 3: /* Busy Name */
|
||||||
|
if (i->qsig_data.dnameid) /* this facility may come more than once - if so, then update this value */
|
||||||
|
free(i->qsig_data.dnameid);
|
||||||
|
i->qsig_data.dnameid = strdup(callername); /* save name as destination in qsig specific fields */
|
||||||
|
/* there's no similarly field in asterisk */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * %s: (%i byte(s)): \"%s\"\n", nametype, namelength, callername);
|
||||||
|
|
||||||
/* if there was an sequence tag, we have more informations here, but we will ignore it at the moment */
|
/* if there was an sequence tag, we have more informations here, but we will ignore it at the moment */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue