Merging in additional Q.SIG features in #13454. Includes Q.SIG physical/logical channel mapping support, extended coding of Q.SIG name operations (calling name), and call rerouting support via added dialplan application.

git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@636 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
Matthew Fredrickson 2008-10-17 16:13:42 +00:00
parent aeb5a6d284
commit e1bfec4b1e
7 changed files with 329 additions and 20 deletions

View File

@ -615,6 +615,10 @@ void pri_set_error(void (*__pri_error)(struct pri *pri, char *));
#define PRI_SET_OVERLAPDIAL
void pri_set_overlapdial(struct pri *pri,int state);
/* QSIG logical channel mapping option, do not skip channel 16 */
#define PRI_SET_CHAN_MAPPING_LOGICAL
void pri_set_chan_mapping_logical(struct pri *pri, int state);
#define PRI_DUMP_INFO_STR
char *pri_dump_info_str(struct pri *pri);
@ -622,9 +626,12 @@ char *pri_dump_info_str(struct pri *pri);
int pri_fd(struct pri *pri);
#define PRI_PROGRESS
/* Send call proceeding */
/* Send progress */
int pri_progress(struct pri *pri, q931_call *c, int channel, int info);
/* Send progress with cause IE */
int pri_progress_with_cause(struct pri *pri, q931_call *c, int channel, int info, int cause);
#define PRI_PROCEEDING_FULL
/* Send call proceeding */
int pri_proceeding(struct pri *pri, q931_call *c, int channel, int info);
@ -647,6 +654,8 @@ void pri_enslave(struct pri *master, struct pri *slave);
/* Send notification */
int pri_notify(struct pri *pri, q931_call *c, int channel, int info);
int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason);
/* Get/Set PRI Timers */
#define PRI_GETSET_TIMERS
int pri_set_timer(struct pri *pri, int timer, int value);

25
pri.c
View File

@ -483,10 +483,19 @@ int pri_proceeding(struct pri *pri, q931_call *call, int channel, int info)
return q931_call_proceeding(pri, call, channel, info);
}
int pri_progress_with_cause(struct pri *pri, q931_call *call, int channel, int info, int cause)
{
if (!pri || !call)
return -1;
return q931_call_progress_with_cause(pri, call, channel, info, cause);
}
int pri_progress(struct pri *pri, q931_call *call, int channel, int info)
{
if (!pri || !call)
return -1;
return q931_call_progress(pri, call, channel, info);
}
@ -505,6 +514,15 @@ int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits)
return q931_keypad_facility(pri, call, digits);
}
int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason)
{
if (!pri || !call)
return -1;
return qsig_cf_callrerouting(pri, call, dest, original, reason);
}
int pri_notify(struct pri *pri, q931_call *call, int channel, int info)
{
if (!pri || !call)
@ -787,6 +805,12 @@ void pri_set_overlapdial(struct pri *pri,int state)
pri->overlapdial = state;
}
void pri_set_chan_mapping_logical(struct pri *pri, int state)
{
if (pri->switchtype == PRI_SWITCH_QSIG)
pri->chan_mapping_logical = state;
}
void pri_set_inbanddisconnect(struct pri *pri, unsigned int enable)
{
pri->acceptinbanddisconnect = (enable != 0);
@ -830,6 +854,7 @@ char *pri_dump_info_str(struct pri *pri)
len += sprintf(buf + len, "Retrans: %d\n", pri->retrans);
len += sprintf(buf + len, "Busy: %d\n", pri->busy);
len += sprintf(buf + len, "Overlap Dial: %d\n", pri->overlapdial);
len += sprintf(buf + len, "Logical Channel Mapping: %d\n", pri->chan_mapping_logical);
len += sprintf(buf + len, "T200 Timer: %d\n", pri->timers[PRI_TIMER_T200]);
len += sprintf(buf + len, "T203 Timer: %d\n", pri->timers[PRI_TIMER_T203]);
len += sprintf(buf + len, "T305 Timer: %d\n", pri->timers[PRI_TIMER_T305]);

View File

@ -1186,6 +1186,198 @@ int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
}
/* End EECT */
/* QSIG CF CallRerouting */
int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason)
{
/*CallRerouting ::= OPERATION
-- Sent from the Served User PINX to the Rerouting PINX
ARGUMENT SEQUENCE
{ reroutingReason DiversionReason,
originalReroutingReason [0] IMPLICIT DiversionReason OPTIONAL,
calledAddress Address,
diversionCounter INTEGER (1..15),
pSS1InfoElement PSS1InformationElement,
-- The basic call information elements Bearer capability, High layer compatibility, Low
-- layer compatibity, Progress indicator and Party category can be embedded in the
-- pSS1InfoElement in accordance with 6.5.3.1.5
lastReroutingNr [1] PresentedNumberUnscreened,
subscriptionOption [2] IMPLICIT SubscriptionOption,
callingPartySubaddress [3] PartySubaddress OPTIONAL,
callingNumber [4] PresentedNumberScreened,
callingName [5] Name OPTIONAL,
originalCalledNr [6] PresentedNumberUnscreened OPTIONAL,
redirectingName [7] Name OPTIONAL,
originalCalledName [8] Name OPTIONAL,
extension CHOICE {
[9] IMPLICIT Extension ,
[10] IMPLICIT SEQUENCE OF Extension } OPTIONAL }
*/
int i = 0, j;
int res = 0;
unsigned char buffer[255] = "";
int len = 253;
struct rose_component *comp = NULL, *compstk[10];
int compsp = 0;
static unsigned char op_tag[] = {
0x13,
};
buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
/* Interpretation component */
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
ASN1_PUSH(compstk, compsp, comp);
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
ASN1_FIXUP(compstk, compsp, buffer, i);
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
ASN1_PUSH(compstk, compsp, comp);
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
if (res < 0)
return -1;
i += res;
/* call rerouting argument */
ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* reroutingReason DiversionReason */
if (reason) {
if (!strcasecmp(reason, "cfu"))
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1); /* cfu */
else if (!strcasecmp(reason, "cfb"))
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 2); /* cfb */
else if (!strcasecmp(reason, "cfnr"))
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 3); /* cfnr */
} else {
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); /* unknown */
}
/* calledAddress Address */
/* explicit sequence tag for Address */
ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* implicit choice public party number tag */
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* type of public party number = unknown */
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
/* NumberDigits of public party number */
j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, (char*)dest, strlen(dest));
if (j < 0)
return -1;
i += j;
ASN1_FIXUP(compstk, compsp, buffer, i);
ASN1_FIXUP(compstk, compsp, buffer, i);
/* diversionCounter INTEGER (1..15) */
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1);
/* pSS1InfoElement */
ASN1_ADD_SIMPLE(comp, (ASN1_APPLICATION | ASN1_TAG_0 ), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
buffer[i++] = (0x04); /* add BC */
buffer[i++] = (0x03);
buffer[i++] = (0x80);
buffer[i++] = (0x90);
buffer[i++] = (0xa3);
buffer[i++] = (0x95);
buffer[i++] = (0x32);
buffer[i++] = (0x01);
buffer[i++] = (0x81);
ASN1_FIXUP(compstk, compsp, buffer, i);
/* lastReroutingNr [1]*/
/* implicit optional lastReroutingNr tag */
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* implicit choice presented number unscreened tag */
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* implicit choice public party number tag */
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* type of public party number = unknown */
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, original?(char*)original:c->callednum, original?strlen(original):strlen(c->callednum));
if (j < 0)
return -1;
i += j;
ASN1_FIXUP(compstk, compsp, buffer, i);
ASN1_FIXUP(compstk, compsp, buffer, i);
ASN1_FIXUP(compstk, compsp, buffer, i);
/* subscriptionOption [2]*/
/* implicit optional lastReroutingNr tag */
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* noNotification */
/* callingNumber [4]*/
/* implicit optional callingNumber tag */
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* implicit choice presented number screened tag */
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* implicit choice presentationAllowedAddress tag */
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
/* type of public party number = subscriber number */
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 4);
j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, c->callernum, strlen(c->callernum));
if (j < 0)
return -1;
i += j;
ASN1_FIXUP(compstk, compsp, buffer, i);
/* Screeening Indicator network provided */
ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 3);
ASN1_FIXUP(compstk, compsp, buffer, i);
ASN1_FIXUP(compstk, compsp, buffer, i);
/**/
ASN1_FIXUP(compstk, compsp, buffer, i);
ASN1_FIXUP(compstk, compsp, buffer, i);
res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL);
if (res) {
pri_message(pri, "Could not queue ADPU in facility message\n");
return -1;
}
/* Remember that if we queue a facility IE for a facility message we
* have to explicitly send the facility message ourselves */
res = q931_facility(c->pri, c);
if (res) {
pri_message(pri, "Could not schedule facility message for call %d\n", c->cr);
return -1;
}
return 0;
}
/* End QSIG CC-CallRerouting */
static int anfpr_pathreplacement_respond(struct pri *pri, q931_call *call, q931_ie *ie)
{
int res;
@ -1215,7 +1407,7 @@ static int anfpr_pathreplacement_respond(struct pri *pri, q931_call *call, q931_
return 0;
}
/* AFN-PR */
extern int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
{
/* Did all the tests to see if we're on the same PRI and
* are on a compatible switchtype */
@ -1548,6 +1740,47 @@ static int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long cha
}
/* End AOC */
static int rose_calling_name_decode(struct pri *pri, q931_call *call, struct rose_component *choice, int len)
{
int i = 0;
struct rose_component *comp = NULL;
unsigned char *vdata = choice->data;
int characterSet = 1;
switch (choice->type) {
case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE:
memcpy(call->callername, choice->data, choice->len);
call->callername[choice->len] = 0;
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " Received simple calling name '%s'\n", call->callername);
return 0;
case ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED:
do {
GET_COMPONENT(comp, i, vdata, len);
CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if nameData is of type 0x%x\n");
memcpy(call->callername, comp->data, comp->len);
call->callername[comp->len] = 0;
NEXT_COMPONENT(comp, i);
GET_COMPONENT(comp, i, vdata, len);
CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if CharacterSet is of type 0x%x\n");
ASN1_GET_INTEGER(comp, characterSet);
}
while (0);
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " Received extended calling name '%s', characterset %d\n", call->callername, characterSet);
return 0;
case ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE:
case ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED:
case ROSE_NAME_PRESENTATION_RESTRICTED_NULL:
case ROSE_NAME_NOT_AVAIL:
default:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "Do not handle argument of type 0x%X\n", choice->type);
return -1;
}
}
/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */
static int rose_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
@ -2158,6 +2391,12 @@ int rose_return_result_decode(struct pri *pri, q931_call *call, q931_ie *ie, uns
pri_message(pri, "Could not parse invoke of type 0x%x!\n", invokeidvalue);
return -1;
}
} else if (pri->switchtype == PRI_SWITCH_QSIG) {
switch (invokeidvalue) {
case 0x13:
if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed QSIG CF callRerouting!\n");
return 0;
}
} else {
pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
return -1;
@ -2209,19 +2448,7 @@ int rose_invoke_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned c
case SS_CNID_CALLINGNAME:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " Handle Name display operation\n");
switch (comp->type) {
case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE:
memcpy(call->callername, comp->data, comp->len);
call->callername[comp->len] = 0;
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " Received caller name '%s'\n", call->callername);
return 0;
default:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "Do not handle argument of type 0x%X\n", comp->type);
return -1;
}
break;
return rose_calling_name_decode(pri, call, comp, len-i);
case ROSE_CALL_TRANSFER_IDENTIFY:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag);
@ -2267,8 +2494,10 @@ int rose_invoke_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned c
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
return -1;
case ROSE_DIVERTING_LEG_INFORMATION2:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " Handle DivertingLegInformation2\n");
if (pri->debug & PRI_DEBUG_APDU) {
pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
}
return rose_diverting_leg_information2_decode(pri, call, comp, len-i);
case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE:
if (pri->debug & PRI_DEBUG_APDU) {

View File

@ -41,7 +41,10 @@
/* Argument values */
#define ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE 0x80
#define ROSE_NAME_PRESENTATION_RESTRICTED_NULL 0x87
#define ROSE_NAME_NOT_AVAIL 0x84
#define ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED 0xA1
#define ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE 0xA2
#define ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED 0xA3
#define ROSE_NAME_NOT_AVAIL 0x84
/* Component types */
#define COMP_TYPE_INTERPRETATION 0x8B
@ -306,8 +309,10 @@ int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason);
/* starts a QSIG Path Replacement */
extern int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
/* Use this function to queue a facility-IE born APDU onto a call
* call is the call to use, messagetype is any one of the Q931 messages,

View File

@ -114,6 +114,9 @@ struct pri {
/* do we do overlap dialing */
int overlapdial;
/* do not skip channel 16 */
int chan_mapping_logical;
#ifdef LIBPRI_COUNTERS
/* q921/q931 packet counters */
unsigned int q921_txcount;

View File

@ -256,6 +256,8 @@ extern int q931_receive(struct pri *pri, q931_h *h, int len);
extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info);
extern int q931_call_progress_with_cause(struct pri *pri, q931_call *call, int channel, int info, int cause);
extern int q931_call_progress(struct pri *pri, q931_call *call, int channel, int info);
extern int q931_notify(struct pri *pri, q931_call *call, int channel, int info);

38
q931.c
View File

@ -345,6 +345,8 @@ static FUNC_RECV(receive_channel_id)
pos++;
/* Only expect a particular channel */
call->channelno = ie->data[pos] & 0x7f;
if (pri->chan_mapping_logical && call->channelno > 15)
call->channelno++;
return 0;
}
} else
@ -400,7 +402,10 @@ static FUNC_SEND(transmit_channel_id)
ie->data[pos++] = 0x83;
if (call->channelno > -1) {
/* Channel number specified */
ie->data[pos++] = 0x80 | call->channelno;
if (pri->chan_mapping_logical && call->channelno > 16)
ie->data[pos++] = 0x80 | (call->channelno - 1);
else
ie->data[pos++] = 0x80 | call->channelno;
return pos + 2;
}
/* We have to send a channel map */
@ -2731,6 +2736,8 @@ int q931_notify(struct pri *pri, q931_call *c, int channel, int info)
#ifdef ALERTING_NO_PROGRESS
static int call_progress_ies[] = { -1 };
#else
static int call_progress_with_cause_ies[] = { Q931_PROGRESS_INDICATOR, Q931_CAUSE, -1 };
static int call_progress_ies[] = { Q931_PROGRESS_INDICATOR, -1 };
#endif
@ -2742,6 +2749,7 @@ int q931_call_progress(struct pri *pri, q931_call *c, int channel, int info)
channel &= 0xff;
c->channelno = channel;
}
if (info) {
c->progloc = LOC_PRIV_NET_LOCAL_USER;
c->progcode = CODE_CCITT;
@ -2751,10 +2759,38 @@ int q931_call_progress(struct pri *pri, q931_call *c, int channel, int info)
pri_error(pri, "XXX Progress message requested but no information is provided\n");
c->progressmask = 0;
}
c->alive = 1;
return send_message(pri, c, Q931_PROGRESS, call_progress_ies);
}
int q931_call_progress_with_cause(struct pri *pri, q931_call *c, int channel, int info, int cause)
{
if (channel) {
c->ds1no = (channel & 0xff00) >> 8;
c->ds1explicit = (channel & 0x10000) >> 16;
channel &= 0xff;
c->channelno = channel;
}
if (info) {
c->progloc = LOC_PRIV_NET_LOCAL_USER;
c->progcode = CODE_CCITT;
c->progressmask = PRI_PROG_INBAND_AVAILABLE;
} else {
/* PI is mandatory IE for PROGRESS message - Q.931 3.1.8 */
pri_error(pri, "XXX Progress message requested but no information is provided\n");
c->progressmask = 0;
}
c->cause = cause;
c->causecode = CODE_CCITT;
c->causeloc = LOC_PRIV_NET_LOCAL_USER;
c->alive = 1;
return send_message(pri, c, Q931_PROGRESS, call_progress_with_cause_ies);
}
#ifdef ALERTING_NO_PROGRESS
static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, -1 };
#else