- implemented support for decoding Call Transfer event - have clean up the code early
   Makes atm only debugging output of feature.
 - moved some code out of chan_capi.c
This commit is contained in:
MelwareDE 2007-06-07 19:24:32 +00:00
parent cae2b60cd4
commit bb3bbe31d3
7 changed files with 192 additions and 29 deletions

View File

@ -81,16 +81,19 @@ The QSIG support includes:
to see the name and number of his connected peer. to see the name and number of his connected peer.
This should be configurable in the next release. This should be configurable in the next release.
- decoding of incoming Call Transfer feature
Does nothing useful yet, only some debug output. It's now a small step to implement inbound Path Replacement.
Future Targets: Future Targets:
=============== ===============
- check code for buffer overflows - check code for buffer overflows
- Call Transfer inbound - complete Call Transfer inbound
- Path Replacement inbound - Path Replacement inbound
- Allow/Disallow Path Replacement within capi.conf - Allow/Disallow Path Replacement within capi.conf
- Call Rerouting feature [ECMA-174] - Call Rerouting feature [ECMA-174]
- CCBS - CCBS
- AOC - AOC
- Sent out LEG_INFO2 - maybe this would allow an sendtext (display instructions on the connected set) - Sent out LEG_INFO3 - maybe this would allow an sendtext (display instructions on the connected set)
- ... - ...
How to use: How to use:
@ -111,3 +114,4 @@ ToDo List:
========== ==========
- Support for inbound routing - Support for inbound routing
- Enhance ASN1-97 Addressing Data Elements support - will save much code

View File

@ -3448,9 +3448,8 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un
pbx_builtin_setvar_helper(i->owner, "SECONDCALLERID", buffer); pbx_builtin_setvar_helper(i->owner, "SECONDCALLERID", buffer);
*/ */
if (i->qsigfeat != QSIG_DISABLED) { /* Handle QSIG informations, if any */
cc_qsig_handle_capiind(CONNECT_IND_FACILITYDATAARRAY(CMSG), i); cc_qsig_handle_capiind(CONNECT_IND_FACILITYDATAARRAY(CMSG), i);
}
if ((i->isdnmode == CAPI_ISDNMODE_MSN) && (i->immediate)) { if ((i->isdnmode == CAPI_ISDNMODE_MSN) && (i->immediate)) {
/* if we don't want to wait for SETUP/SENDING-COMPLETE in MSN mode */ /* if we don't want to wait for SETUP/SENDING-COMPLETE in MSN mode */
@ -4859,11 +4858,9 @@ int mkif(struct cc_capi_conf *conf)
tmp->doDTMF = conf->softdtmf; tmp->doDTMF = conf->softdtmf;
tmp->capability = conf->capability; tmp->capability = conf->capability;
tmp->qsigfeat = conf->qsigfeat; /* Initialize QSIG code */
if (conf->qsigfeat) { cc_qsig_interface_init(conf, tmp);
cc_qsig_interface_init(conf, tmp);
}
tmp->next = capi_iflist; /* prepend */ tmp->next = capi_iflist; /* prepend */
capi_iflist = tmp; capi_iflist = tmp;
cc_verbose(2, 0, VERBOSE_PREFIX_3 "capi %c %s (%s:%s) contr=%d devs=%d EC=%d,opt=%d,tail=%d\n", cc_verbose(2, 0, VERBOSE_PREFIX_3 "capi %c %s (%s:%s) contr=%d devs=%d EC=%d,opt=%d,tail=%d\n",
@ -5734,8 +5731,7 @@ int unload_module(void)
if (i->smoother) if (i->smoother)
ast_smoother_free(i->smoother); ast_smoother_free(i->smoother);
if (i->qsigfeat) pbx_capi_qsig_unload_module(i);
pbx_capi_qsig_unload_module(i);
cc_mutex_destroy(&i->lock); cc_mutex_destroy(&i->lock);
ast_cond_destroy(&i->event_trigger); ast_cond_destroy(&i->event_trigger);

View File

@ -95,6 +95,7 @@
/* QSIG Operations += 1000 */ /* QSIG Operations += 1000 */
#define CCQSIG__ECMA__NAMEPRES 1000 /* Setting an own constant for ECMA Operation/Namepresentation, others will follow */ #define CCQSIG__ECMA__NAMEPRES 1000 /* Setting an own constant for ECMA Operation/Namepresentation, others will follow */
#define CCQSIG__ECMA__PRPROPOSE 1004 /* Path Replacement Propose */ #define CCQSIG__ECMA__PRPROPOSE 1004 /* Path Replacement Propose */
#define CCQSIG__ECMA__CTCOMPLETE 1012 /* Call Transfer Complete */
#define CCQSIG__ECMA__LEGINFO2 1021 /* LEG INFORMATION2 */ #define CCQSIG__ECMA__LEGINFO2 1021 /* LEG INFORMATION2 */
@ -195,5 +196,6 @@ extern void cc_qsig_encode_ecma_prpropose(unsigned char * buf, unsigned int *idx
extern void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param); extern void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param);
extern void cc_qsig_encode_ecma_calltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param, int info); extern void cc_qsig_encode_ecma_calltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param, int info);
extern char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
#endif #endif

View File

@ -25,6 +25,7 @@
#include <asterisk/options.h> #include <asterisk/options.h>
#include "chan_capi20.h" #include "chan_capi20.h"
#include "chan_capi.h" #include "chan_capi.h"
#include "chan_capi_utils.h"
#include "chan_capi_qsig.h" #include "chan_capi_qsig.h"
#include "chan_capi_qsig_asn197ade.h" #include "chan_capi_qsig_asn197ade.h"
@ -48,12 +49,17 @@ unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx,
numtype = (data[myidx++] & 0x0F); /* defines type of Number: numDigits, publicPartyNum, nsapEncNum, dataNumDigits */ numtype = (data[myidx++] & 0x0F); /* defines type of Number: numDigits, publicPartyNum, nsapEncNum, dataNumDigits */
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i\n", numtype); */ /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i\n", numtype); */
switch (numtype){ switch (numtype){
case 0: case 0:
if (data[myidx++] > 0) /* length of this context data */ if (data[myidx] > 0) { /* length of this context data */
if (data[myidx++] == ASN1_TC_CONTEXTSPEC) if (data[myidx+1] == ASN1_TC_CONTEXTSPEC) {
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data) + 1; myidx += 2;
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data);
} else {
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data);
}
}
break; break;
case 1: /* publicPartyNumber (E.164) not supported yet */ case 1: /* publicPartyNumber (E.164) not supported yet */
return 0; return 0;
@ -62,9 +68,14 @@ unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx,
return 0; return 0;
break; break;
case 3: case 3:
if (data[myidx++] > 0) /* length of this context data */ if (data[myidx++] > 0) { /* length of this context data */
if (data[myidx++] == ASN1_TC_CONTEXTSPEC) if (data[myidx+1] == ASN1_TC_CONTEXTSPEC) {
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data) + 1; myidx += 2;
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data);
} else {
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data);
}
}
break; break;
}; };
return myidx - *idx; return myidx - *idx;
@ -84,7 +95,7 @@ unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, un
memcpy(buf, &data[myidx], strsize); memcpy(buf, &data[myidx], strsize);
buf[strsize] = 0; buf[strsize] = 0;
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * string length %i\n", strsize); */ // cc_verbose(1, 1, VERBOSE_PREFIX_4 " * string length %i\n", strsize);
return strsize; return strsize;
} }

View File

@ -22,6 +22,11 @@
#define ASN197ADE_NUMDIGITS_STRSIZE 20 #define ASN197ADE_NUMDIGITS_STRSIZE 20
struct asn197ade_numberscreened {
unsigned char *partyNumber;
enum screeningInd { userProvidedNotScreened, userProvidedVerifiedAndPassed, userProvidedVerifiedAndFailed, networkProvided };
};
extern unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx, unsigned char *data); extern unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx, unsigned char *data);
extern unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, unsigned char *data); extern unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, unsigned char *data);

View File

@ -483,6 +483,8 @@ static int ident_qsig_invoke(int invoketype)
return CCQSIG__ECMA__NAMEPRES; return CCQSIG__ECMA__NAMEPRES;
case 4: case 4:
return CCQSIG__ECMA__PRPROPOSE; return CCQSIG__ECMA__PRPROPOSE;
case 12:
return CCQSIG__ECMA__CTCOMPLETE;
case 21: case 21:
return CCQSIG__ECMA__LEGINFO2; return CCQSIG__ECMA__LEGINFO2;
default: default:
@ -572,9 +574,19 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
} }
static void pbx_capi_qsig_handle_ctc(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{
char *destination = cc_qsig_decode_ecma_calltransfer(invoke, i);
if (destination) {
free(destination);
}
return ;
}
/* /*
* * Handle inbound INVOKEs
*/ */
unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invokedata *invoke, struct capi_pvt *i) unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{ {
@ -585,6 +597,9 @@ unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invo
case CCQSIG__ECMA__PRPROPOSE: case CCQSIG__ECMA__PRPROPOSE:
cc_qsig_op_ecma_isdn_prpropose(invoke, i); cc_qsig_op_ecma_isdn_prpropose(invoke, i);
break; break;
case CCQSIG__ECMA__CTCOMPLETE:
pbx_capi_qsig_handle_ctc(invoke, i);
break;
case CCQSIG__ECMA__LEGINFO2: case CCQSIG__ECMA__LEGINFO2:
cc_qsig_op_ecma_isdn_leginfo2(invoke, i); cc_qsig_op_ecma_isdn_leginfo2(invoke, i);
break; break;
@ -647,6 +662,9 @@ unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i)
int faclen = 0; int faclen = 0;
int facidx = 2; int facidx = 2;
if (!i->qsigfeat)
return 0;
if (!data) { if (!data) {
return 0; return 0;
} }
@ -965,14 +983,14 @@ int pbx_capi_qsig_ct(struct ast_channel *c, char *param)
cc_qsig_do_facility(fac, c, param, 12, 0); cc_qsig_do_facility(fac, c, param, 12, 0);
capi_sendf(NULL, 0, CAPI_INFO_REQ, ii->PLCI, get_capi_MessageNumber(), capi_sendf(NULL, 0, CAPI_INFO_REQ, ii->PLCI, get_capi_MessageNumber(),
"()(()()()s)", "()(()()()s())",
fac fac
); );
cc_qsig_do_facility(fac, c, param, 12, 1); cc_qsig_do_facility(fac, c, param, 12, 1);
capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(), capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(),
"()(()()()s)", "()(()()()s())",
fac fac
); );
@ -980,7 +998,7 @@ int pbx_capi_qsig_ct(struct ast_channel *c, char *param)
} }
/* /*
* Initiate a QSIG Call Transfer * mark an call
*/ */
int pbx_capi_qsig_callmark(struct ast_channel *c, char *param) int pbx_capi_qsig_callmark(struct ast_channel *c, char *param)
{ {
@ -1025,6 +1043,10 @@ static void send_feature_calltransfer(struct capi_pvt *i)
*/ */
void cc_qsig_interface_init(struct cc_capi_conf *conf, struct capi_pvt *tmp) void cc_qsig_interface_init(struct cc_capi_conf *conf, struct capi_pvt *tmp)
{ {
tmp->qsigfeat = conf->qsigfeat;
if (!conf->qsigfeat)
return;
tmp->qsig_data.calltransfer_active = 0; tmp->qsig_data.calltransfer_active = 0;
tmp->qsig_data.calltransfer = 0; tmp->qsig_data.calltransfer = 0;
tmp->qsig_data.calltransfer_onring = 0; tmp->qsig_data.calltransfer_onring = 0;
@ -1088,6 +1110,8 @@ void interface_cleanup_qsig(struct capi_pvt *i)
*/ */
void pbx_capi_qsig_unload_module(struct capi_pvt *i) void pbx_capi_qsig_unload_module(struct capi_pvt *i)
{ {
if (!i->qsigfeat)
return;
ast_cond_destroy(&i->qsig_data.event_trigger); ast_cond_destroy(&i->qsig_data.event_trigger);
} }

View File

@ -144,12 +144,8 @@ int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, stru
invoke->descr_type = -1; /* Let others do the work: qsig_add_invoke */ invoke->descr_type = -1; /* Let others do the work: qsig_add_invoke */
invoke->type = 0; /* Invoke Operation Number, if OID it's the last byte*/ invoke->type = 0; /* Invoke Operation Number, if OID it's the last byte*/
/* HACK: */
if (nametype)
invoke->type = 2;
if (namelen>0) { if (namelen>0) {
data[dataidx++] = 0x80; /* We send only simple Name, Namepresentation allowed */ data[dataidx++] = 0x80 | (nametype % 4); /* We send only simple Name, Namepresentation allowed */
data[dataidx++] = namelen; data[dataidx++] = namelen;
memcpy(&data[dataidx], namebuf, namelen); memcpy(&data[dataidx], namebuf, namelen);
dataidx += namelen; dataidx += namelen;
@ -416,6 +412,131 @@ void cc_qsig_encode_ecma_calltransfer(unsigned char * buf, unsigned int *idx, st
} }
/*
* Decode Operation: 1.3.12.9.12 ECMA/ISDN/CALLTRANSFER
*
* This function decodes the call transfer facility
*
* 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 from facility
* i is pointer to capi channel
* returns
* transfer to destination number
*/
char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{
unsigned int datalength;
unsigned int seqlength = 0;
unsigned char *data = invoke->data;
int myidx = 0;
/* TODO: write more code */
char *ct_status_txt[] = { "ANSWERED", "ALERTING" };
int ct_status = 0;
char ct_target[ASN197ADE_NUMDIGITS_STRSIZE+1] = { 0 };
char ct_name[ASN197NO_NAME_STRSIZE+1] = { "EMPTY" };
int ct_enddesignation = 0;
int ct_numberpresentation = 0;
unsigned int namelength = 0;
int temp = 0;
#define ct_err(x...) { cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - "x); return NULL; }
cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling QSIG CALL TRANSFER (id# %#x)\n", invoke->id);
if (data[myidx++] != (ASN1_SEQUENCE | ASN1_TC_UNIVERSAL | ASN1_TF_CONSTRUCTED)) { /* 0x30 */
/* We do not handle this, because it should start with an sequence tag */
ct_err("not a sequence\n");
}
/* This facility is encoded as SEQUENCE */
seqlength = data[myidx++];
datalength = invoke->datalen;
if (datalength < (seqlength+1)) {
ct_err("buffer error\n");
}
if (data[myidx++] == ASN1_ENUMERATED) {
ct_enddesignation = cc_qsig_asn1_get_integer(data, &myidx);
} else {
ct_err("no endDesignation information.\n");
}
if (data[myidx] == (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED | 0)) { /* Parameter 0: partyNumber - transferee number */
myidx ++;
temp = cc_qsig_asn197ade_get_partynumber(ct_target, ASN197ADE_NUMDIGITS_STRSIZE+1, &myidx, data);
if (temp)
myidx += temp + 1;
/* HACK: this has to be moved to _get_presentednumberscreened */
if (data[myidx++] == ASN1_ENUMERATED) {
ct_numberpresentation = cc_qsig_asn1_get_integer(data, &myidx);
} else {
ct_err("screeningIndicator is missing.\n");
return NULL;
}
} else {
myidx += 2; /* HACK: I've seen an IMPLICIT ade "numberNotAvailableDueToInterworking NULL" */
}
/* TODO: remove this code snippet, when it's 100% working */
/*
if (data[myidx++] == (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED | 0)) { */ /* Parameter 0: partyNumber - transferee number */
/* if (!data[myidx++]) /* length = 0 */
/* ct_err("No destination received.\n");
if (data[myidx++] != ASN1_TC_CONTEXTSPEC)
ct_err("No destination received.\n");
temp = cc_qsig_asn1_get_string((unsigned char*)&ct_target, sizeof(ct_target), &data[myidx]);
if (temp) {
myidx += temp + 1;
} else {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - partyNumber expected (%i)\n", myidx);
return NULL;
}
if (data[myidx++] == ASN1_ENUMERATED) {
ct_numberpresentation = cc_qsig_asn1_get_integer(data, &myidx);
} else {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - wrong encoded #2.\n");
return NULL;
}
}*/
if (myidx < datalength) {
if (data[myidx] == ASN1_TC_APPLICATION) {
/* ignore special Application Parameters - have no info about content */
myidx++;
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG CALL TRANSFER - ignoring application data (%i bytes).\n", (int)data[myidx]);
myidx += data[myidx] + 1;
}
}
if (myidx < datalength) {
if (data[myidx] != ASN1_ENUMERATED) { /* Maybe we get an name (OPTIONAL) */
myidx += cc_qsig_asn197no_get_name(ct_name, ASN197NO_NAME_STRSIZE+1, &namelength, &myidx, data );
}
}
if (myidx < datalength) {
if (data[myidx++] == ASN1_ENUMERATED) { /* Call Status */
ct_status = cc_qsig_asn1_get_integer(data, &myidx);
}
}
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Got QSIG CALL TRANSFER endDesignation: %i partyNumber: %s (ScreeningInd: %i), partyName: \"%s\", Call state: %s\n", ct_enddesignation, ct_target, ct_numberpresentation, ct_name, ct_status_txt[ct_status]);
return strdup(ct_target);
#undef ct_err
}
/* /*
* Encode Operation: 1.3.12.9.99 ECMA/ISDN/SINGLESTEPCALLTRANSFER * Encode Operation: 1.3.12.9.99 ECMA/ISDN/SINGLESTEPCALLTRANSFER