[svn-commits] mattf: branch 1.4 r636 - /branches/1.4/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Oct 17 11:13:43 CDT 2008


Author: mattf
Date: Fri Oct 17 11:13:42 2008
New Revision: 636

URL: http://svn.digium.com/view/libpri?view=rev&rev=636
Log:
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.

Modified:
    branches/1.4/libpri.h
    branches/1.4/pri.c
    branches/1.4/pri_facility.c
    branches/1.4/pri_facility.h
    branches/1.4/pri_internal.h
    branches/1.4/pri_q931.h
    branches/1.4/q931.c

Modified: branches/1.4/libpri.h
URL: http://svn.digium.com/view/libpri/branches/1.4/libpri.h?view=diff&rev=636&r1=635&r2=636
==============================================================================
--- branches/1.4/libpri.h (original)
+++ branches/1.4/libpri.h Fri Oct 17 11:13:42 2008
@@ -615,6 +615,10 @@
 #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,8 +626,11 @@
 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 */
@@ -646,6 +653,8 @@
 
 /* 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

Modified: branches/1.4/pri.c
URL: http://svn.digium.com/view/libpri/branches/1.4/pri.c?view=diff&rev=636&r1=635&r2=636
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Fri Oct 17 11:13:42 2008
@@ -483,10 +483,19 @@
 	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);
 }
 
@@ -503,6 +512,15 @@
 		return -1;
 
 	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)
@@ -787,6 +805,12 @@
 	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 @@
 	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]);

Modified: branches/1.4/pri_facility.c
URL: http://svn.digium.com/view/libpri/branches/1.4/pri_facility.c?view=diff&rev=636&r1=635&r2=636
==============================================================================
--- branches/1.4/pri_facility.c (original)
+++ branches/1.4/pri_facility.c Fri Oct 17 11:13:42 2008
@@ -1186,6 +1186,198 @@
 }
 /* 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 @@
 	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 @@
 }
 /* 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 @@
 				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 @@
 		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 @@
 			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) {

Modified: branches/1.4/pri_facility.h
URL: http://svn.digium.com/view/libpri/branches/1.4/pri_facility.h?view=diff&rev=636&r1=635&r2=636
==============================================================================
--- branches/1.4/pri_facility.h (original)
+++ branches/1.4/pri_facility.h Fri Oct 17 11:13:42 2008
@@ -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 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,

Modified: branches/1.4/pri_internal.h
URL: http://svn.digium.com/view/libpri/branches/1.4/pri_internal.h?view=diff&rev=636&r1=635&r2=636
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Fri Oct 17 11:13:42 2008
@@ -113,6 +113,9 @@
 
 	/* do we do overlap dialing */
 	int overlapdial;
+
+	/* do not skip channel 16 */
+	int chan_mapping_logical;
 
 #ifdef LIBPRI_COUNTERS
 	/* q921/q931 packet counters */

Modified: branches/1.4/pri_q931.h
URL: http://svn.digium.com/view/libpri/branches/1.4/pri_q931.h?view=diff&rev=636&r1=635&r2=636
==============================================================================
--- branches/1.4/pri_q931.h (original)
+++ branches/1.4/pri_q931.h Fri Oct 17 11:13:42 2008
@@ -256,6 +256,8 @@
 
 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);

Modified: branches/1.4/q931.c
URL: http://svn.digium.com/view/libpri/branches/1.4/q931.c?view=diff&rev=636&r1=635&r2=636
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Fri Oct 17 11:13:42 2008
@@ -345,6 +345,8 @@
 			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 @@
 		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 @@
 #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 @@
 		channel &= 0xff;
 		c->channelno = channel;		
 	}
+
 	if (info) {
 		c->progloc = LOC_PRIV_NET_LOCAL_USER;
 		c->progcode = CODE_CCITT;
@@ -2751,8 +2759,36 @@
 		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




More information about the svn-commits mailing list