[svn-commits] rmudgett: trunk r312 - /trunk/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Aug 9 11:27:14 CDT 2012


Author: rmudgett
Date: Thu Aug  9 11:27:10 2012
New Revision: 312

URL: http://svnview.digium.com/svn/libss7?view=rev&rev=312
Log:
Omnibus libss7 update.

Kaloyan Kovachev added additional cause codes, Transmission Medium
Requirement setting and connected line to CPG messages + code cleanup.

Big thanks to Kaloyan Kovachev for pushing to get this completed.

Large patch that improves ISUP timers and Q.764 compatibility.
(closes issue SS7-27)
Reported by: adomjan

Listing other issues that are either included or addressed by this patch.
I am not going to investigate each one to see if they are complete or not
at this time.

(issue SS7-7)
(issue SS7-21)
(issue SS7-28)
(issue SS7-33)
(issue SS7-36)
(issue SS7-38)
(issue SS7-39)
(issue SS7-40)
(issue SS7-42)
(issue SS7-43)
(issue SS7-45)
(issue SS7-46)
(issue SS7-47)
(issue SS7-48)
(issue SS7-49)
(issue SS7-51)
(issue SS7-52)
(issue SS7-53)
(issue SS7-54)

Review: https://reviewboard.asterisk.org/r/1653/

Modified:
    trunk/Makefile
    trunk/isup.c
    trunk/isup.h
    trunk/libss7.h
    trunk/mtp2.c
    trunk/mtp2.h
    trunk/mtp3.c
    trunk/mtp3.h
    trunk/parser_debug.c
    trunk/ss7.c
    trunk/ss7_internal.h
    trunk/ss7linktest.c
    trunk/ss7test.c

Modified: trunk/Makefile
URL: http://svnview.digium.com/svn/libss7/trunk/Makefile?view=diff&rev=312&r1=311&r2=312
==============================================================================
--- trunk/Makefile (original)
+++ trunk/Makefile Thu Aug  9 11:27:10 2012
@@ -30,7 +30,7 @@
 # SONAME version; should be changed on every ABI change
 # please don't change it needlessly; it's perfectly fine to have a SONAME
 # of 1.0 and a version of 1.4.x
-SONAME:=1.0
+SONAME:=2.0
 
 STATIC_LIBRARY=libss7.a
 DYNAMIC_LIBRARY:=libss7.so.$(SONAME)

Modified: trunk/isup.c
URL: http://svnview.digium.com/svn/libss7/trunk/isup.c?view=diff&rev=312&r1=311&r2=312
==============================================================================
--- trunk/isup.c (original)
+++ trunk/isup.c Thu Aug  9 11:27:10 2012
@@ -31,6 +31,8 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
 #include "libss7.h"
 #include "isup.h"
 #include "ss7_internal.h"
@@ -47,8 +49,6 @@
 #define PARM_TYPE_OPTIONAL 0x03
 
 #define CODE_CCITT 0x0
-
-#define LOC_PRIV_NET_LOCAL_USER 0x1
 
 struct parm_func {
 	int parm;
@@ -58,13 +58,22 @@
 	FUNC_SEND(*transmit);
 };
 
+struct isup_timer_param {
+	struct ss7 *ss7;
+	struct isup_call *c;
+	int timer;
+};
+
 static int iam_params[] = {ISUP_PARM_NATURE_OF_CONNECTION_IND, ISUP_PARM_FORWARD_CALL_IND, ISUP_PARM_CALLING_PARTY_CAT,
-	ISUP_PARM_TRANSMISSION_MEDIUM_REQS, ISUP_PARM_CALLED_PARTY_NUM, ISUP_PARM_CALLING_PARTY_NUM, -1};
+	ISUP_PARM_TRANSMISSION_MEDIUM_REQS, ISUP_PARM_CALLED_PARTY_NUM, ISUP_PARM_CALLING_PARTY_NUM, ISUP_PARM_REDIRECTING_NUMBER,
+	ISUP_PARM_REDIRECTION_INFO, ISUP_PARM_REDIRECT_COUNTER, ISUP_PARM_ORIGINAL_CALLED_NUM, ISUP_PARM_OPT_FORWARD_CALL_INDICATOR,
+	ISUP_PARM_CUG_INTERLOCK_CODE, -1};
 
 static int ansi_iam_params[] = {ISUP_PARM_NATURE_OF_CONNECTION_IND, ISUP_PARM_FORWARD_CALL_IND, ISUP_PARM_CALLING_PARTY_CAT,
-	ISUP_PARM_USER_SERVICE_INFO, ISUP_PARM_CALLED_PARTY_NUM, ISUP_PARM_CALLING_PARTY_NUM, ISUP_PARM_CHARGE_NUMBER, 
-	ISUP_PARM_ORIG_LINE_INFO, ISUP_PARM_GENERIC_ADDR, ISUP_PARM_GENERIC_DIGITS, ISUP_PARM_GENERIC_NAME, ISUP_PARM_JIP, 
-	ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION, -1};
+	ISUP_PARM_USER_SERVICE_INFO, ISUP_PARM_CALLED_PARTY_NUM, ISUP_PARM_CALLING_PARTY_NUM, ISUP_PARM_CHARGE_NUMBER,
+	ISUP_PARM_ORIG_LINE_INFO, ISUP_PARM_GENERIC_ADDR, ISUP_PARM_GENERIC_DIGITS, ISUP_PARM_GENERIC_NAME, ISUP_PARM_JIP,
+	ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION, ISUP_PARM_REDIRECTION_INFO, ISUP_PARM_REDIRECTING_NUMBER, ISUP_PARM_REDIRECT_COUNTER,
+	ISUP_PARM_ORIGINAL_CALLED_NUM, ISUP_PARM_OPT_FORWARD_CALL_INDICATOR, ISUP_PARM_CUG_INTERLOCK_CODE, -1};
 
 
 static int acm_params[] = {ISUP_PARM_BACKWARD_CALL_IND, -1};
@@ -73,9 +82,9 @@
 
 static int far_params[] = {ISUP_PARM_FACILITY_IND, ISUP_PARM_CALL_REF, -1};
 
-static int anm_params[] = { -1};
-
-static int con_params[] = { ISUP_PARM_BACKWARD_CALL_IND, -1};
+static int anm_params[] = { ISUP_CONNECTED_NUMBER, -1};
+
+static int con_params[] = { ISUP_PARM_BACKWARD_CALL_IND, ISUP_CONNECTED_NUMBER, -1};
 
 static int rel_params[] = { ISUP_PARM_CAUSE, -1};
 
@@ -83,13 +92,19 @@
 
 static int cot_params[] = { ISUP_PARM_CONTINUITY_IND, -1};
 
-static int cpg_params[] = { ISUP_PARM_EVENT_INFO, -1};
+static int cpg_params[] = { ISUP_PARM_EVENT_INFO, ISUP_CONNECTED_NUMBER, -1};
 
 static int cicgroup_params[] = { ISUP_PARM_CIRCUIT_GROUP_SUPERVISION_IND, ISUP_PARM_RANGE_AND_STATUS, -1};
 
 static int cqr_params[] = { ISUP_PARM_RANGE_AND_STATUS, ISUP_PARM_CIRCUIT_STATE_IND, -1};
 
-static int sus_res_params[] = { ISUP_PARM_SUSPEND_RESUME_IND, -1};
+static int sus_res_params[] = { ISUP_PARM_SUSPEND_RESUME_IND, ISUP_PARM_CALL_REF, -1};
+
+static int inr_params[] = { ISUP_PARM_INR_IND, -1};
+
+static int inf_params[] = { ISUP_PARM_INF_IND, ISUP_PARM_CALLING_PARTY_NUM, ISUP_PARM_CALLING_PARTY_CAT, -1};
+
+static int sam_params[] = { ISUP_PARM_SUBSEQUENT_NUMBER, -1};
 
 static int empty_params[] = { -1};
 
@@ -98,42 +113,50 @@
 	int mand_fixed_params;
 	int mand_var_params;
 	int opt_params;
+	int ansi_priority;
 	int *param_list;
 } messages[] = {
-	{ISUP_IAM, 4, 1, 1, iam_params},
-	{ISUP_ACM, 1, 0, 1, acm_params},
-	{ISUP_ANM, 0, 0, 1, anm_params},
-	{ISUP_CON, 1, 0, 1, con_params},
-	{ISUP_REL, 0, 1, 1, rel_params},
-	{ISUP_RLC, 0, 0, 1, empty_params},
-	{ISUP_GRS, 0, 1, 0, greset_params},
-	{ISUP_GRA, 0, 1, 0, greset_params},
-	{ISUP_CGB, 1, 1, 0, cicgroup_params},
-	{ISUP_CGU, 1, 1, 0, cicgroup_params},
-	{ISUP_CGBA, 1, 1, 0, cicgroup_params},
-	{ISUP_CGUA, 1, 1, 0, cicgroup_params},
-	{ISUP_COT, 1, 0, 0, cot_params},
-	{ISUP_CCR, 0, 0, 0, empty_params},
-	{ISUP_BLO, 0, 0, 0, empty_params},
-	{ISUP_LPA, 0, 0, 0, empty_params},
-	{ISUP_UBL, 0, 0, 0, empty_params},
-	{ISUP_BLA, 0, 0, 0, empty_params},
-	{ISUP_UBA, 0, 0, 0, empty_params},
-	{ISUP_RSC, 0, 0, 0, empty_params},
-	{ISUP_CVR, 0, 0, 0, empty_params},
-	{ISUP_CVT, 0, 0, 0, empty_params},
-	{ISUP_CPG, 1, 0, 1, cpg_params},
-	{ISUP_UCIC, 0, 0, 0, empty_params},
-	{ISUP_CQM, 0, 1, 0, greset_params},
-	{ISUP_CQR, 0, 2, 0, cqr_params},
-	{ISUP_FAA, 1, 0, 1, faa_params},
-	{ISUP_FAR, 1, 0, 1, far_params},
-	{ISUP_CFN, 0, 1, 0, rel_params},
-	{ISUP_SUS, 1, 0, 1, sus_res_params},
-	{ISUP_RES, 1, 0, 1, sus_res_params}
+	{ISUP_IAM, 4, 1, 1, 0, iam_params},
+	{ISUP_ACM, 1, 0, 1, 1, acm_params},
+	{ISUP_ANM, 0, 0, 1, 2, anm_params},
+	{ISUP_CON, 1, 0, 1, -1, con_params},
+	{ISUP_REL, 0, 1, 1, 1, rel_params},
+	{ISUP_RLC, 0, 0, 1, 2, empty_params},
+	{ISUP_GRS, 0, 1, 0, 0, greset_params},
+	{ISUP_GRA, 0, 1, 0, 0, greset_params},
+	{ISUP_CGB, 1, 1, 0, 0, cicgroup_params},
+	{ISUP_CGU, 1, 1, 0, 0, cicgroup_params},
+	{ISUP_CGBA, 1, 1, 0, 0, cicgroup_params},
+	{ISUP_CGUA, 1, 1, 0, 0, cicgroup_params},
+	{ISUP_COT, 1, 0, 0, 1, cot_params},
+	{ISUP_CCR, 0, 0, 0, 1, empty_params},
+	{ISUP_BLO, 0, 0, 0, 0, empty_params},
+	{ISUP_LPA, 0, 0, 0, 1, empty_params},
+	{ISUP_UBL, 0, 0, 0, 0, empty_params},
+	{ISUP_BLA, 0, 0, 0, 0, empty_params},
+	{ISUP_UBA, 0, 0, 0, 0, empty_params},
+	{ISUP_RSC, 0, 0, 0, 0, empty_params},
+	{ISUP_CVR, 0, 0, 0, 0, empty_params},
+	{ISUP_CVT, 0, 0, 0, 0, empty_params},
+	{ISUP_CPG, 1, 0, 1, 1, cpg_params},
+	{ISUP_UCIC, 0, 0, 0, 1, empty_params},
+	{ISUP_CQM, 0, 1, 0, 0, greset_params},
+	{ISUP_CQR, 0, 2, 0, 0, cqr_params},
+	{ISUP_FAA, 1, 0, 1, -1, faa_params},
+	{ISUP_FAR, 1, 0, 1, -1, far_params},
+	{ISUP_CFN, 0, 1, 1, 0, rel_params},
+	{ISUP_SUS, 1, 0, 1, 1, sus_res_params},
+	{ISUP_RES, 1, 0, 1, 1, sus_res_params},
+	{ISUP_INR, 1, 0, 0, 1, inr_params},
+	{ISUP_INF, 1, 0, 2, 1, inf_params},
+	{ISUP_SAM, 0, 1, 1, -1, sam_params}
 };
 
 static int isup_send_message(struct ss7 *ss7, struct isup_call *c, int messagetype, int parms[]);
+
+static int isup_start_timer(struct ss7 *ss7, struct isup_call *c, int timer);
+static void isup_stop_all_timers(struct ss7 *ss7, struct isup_call *c);
+static void isup_stop_timer(struct ss7 *ss7, struct isup_call *c, int timer);
 
 static char * message2str(unsigned char message)
 {
@@ -144,6 +167,8 @@
 			return "ACM";
 		case ISUP_ANM:
 			return "ANM";
+		case ISUP_CON:
+			return "CON";
 		case ISUP_REL:
 			return "REL";
 		case ISUP_RLC:
@@ -196,65 +221,151 @@
 			return "SUS";
 		case ISUP_RES:
 			return "RES";
+		case ISUP_INR:
+			return "INR";
+		case ISUP_INF:
+			return "INF";
+		case ISUP_SAM:
+			return "SAM";
 		default:
 			return "Unknown";
 	}
 }
 
+static char * isup_timer2str(int timer)
+{
+	switch (timer) {
+		case ISUP_TIMER_T1:
+			return "t1";
+		case ISUP_TIMER_T2:
+			return "t2";
+		case ISUP_TIMER_T5:
+			return "t5";
+		case ISUP_TIMER_T6:
+			return "t6";
+		case ISUP_TIMER_T7:
+			return "t7";
+		case ISUP_TIMER_T8:
+			return "t8";
+		case ISUP_TIMER_T10:
+			return "t10";
+		case ISUP_TIMER_T12:
+			return "t12";
+		case ISUP_TIMER_T13:
+			return "t13";
+		case ISUP_TIMER_T14:
+			return "t14";
+		case ISUP_TIMER_T15:
+			return "t15";
+		case ISUP_TIMER_T16:
+			return "t16";
+		case ISUP_TIMER_T17:
+			return "t17";
+		case ISUP_TIMER_T18:
+			return "t18";
+		case ISUP_TIMER_T19:
+			return "t19";
+		case ISUP_TIMER_T20:
+			return "t20";
+		case ISUP_TIMER_T21:
+			return "t21";
+		case ISUP_TIMER_T22:
+			return "t22";
+		case ISUP_TIMER_T23:
+			return "t23";
+		case ISUP_TIMER_T27:
+			return "t27";
+		case ISUP_TIMER_T33:
+			return "t33";
+		case ISUP_TIMER_T35:
+			return "t35";
+		default:
+			return "unknown";
+	}
+}
+
 static char char2digit(char localchar)
 {
 	switch (localchar) {
 		case '0':
-			return 0;
+			return 0x0;
 		case '1':
-			return 1;
+			return 0x1;
 		case '2':
-			return 2;
+			return 0x2;
 		case '3':
-			return 3;
+			return 0x3;
 		case '4':
-			return 4;
+			return 0x4;
 		case '5':
-			return 5;
+			return 0x5;
 		case '6':
-			return 6;
+			return 0x6;
 		case '7':
-			return 7;
+			return 0x7;
 		case '8':
-			return 8;
+			return 0x8;
 		case '9':
-			return 9;
+			return 0x9;
+		case 'a':
+		case 'A':
+			return 0xa;
+		case 'b':
+		case 'B':
+			return 0xb;
+		case 'c':
+		case 'C':
+			return 0xc;
+		case 'd':
+		case 'D':
+			return 0xd;
+		case 'e':
+		case 'E':
+		case '*':
+			return 0xe;
+		case 'f':
+		case 'F':
 		case '#':
 			return 0xf;
 		default:
-			return 0;
+			return 0x0;
 	}
 }
 
 static char digit2char(unsigned char digit)
 {
 	switch (digit & 0xf) {
-		case 0:
+		case 0x0:
 			return '0';
-		case 1:
+		case 0x1:
 			return '1';
-		case 2:
+		case 0x2:
 			return '2';
-		case 3:
+		case 0x3:
 			return '3';
-		case 4:
+		case 0x4:
 			return '4';
-		case 5:
+		case 0x5:
 			return '5';
-		case 6:
+		case 0x6:
 			return '6';
-		case 7:
+		case 0x7:
 			return '7';
-		case 8:
+		case 0x8:
 			return '8';
-		case 9:
+		case 0x9:
 			return '9';
-		case 15:
+		case 0xa:
+			return 'A';
+		case 0xb:
+			return 'B';
+		case 0xc:
+			return 'C';
+		case 0xd:
+			return 'D';
+		case 0xe:
+			return '*';
+		case 0xf:
 			return '#';
 		default:
 			return 0;
@@ -316,10 +427,11 @@
 	}
 
 	while (i < numlen) {
-		if (!(i % 2))
+		if (!(i % 2)) {
 			dest[i/2] |= char2digit(src[i]) & 0xf;
-		else
+		} else {
 			dest[i/2] |= (char2digit(src[i]) << 4) & 0xf0;
+		}
 		i++;
 	}
 }
@@ -328,20 +440,42 @@
 {
 	parm[0] = 0x00;
 
-	if (c->cot_check_required)
+	if (c->cot_check_required) {
 		parm[0] |= 0x04;
-
-	return 1; /* Length plus size of type header */
+	}
+
+	if (c->cot_performed_on_previous_cic) {
+		parm[0] |= 0x08;
+	}
+
+	if (c->local_echocontrol_ind) {
+		parm[0] |= 0x10;
+	}
+
+	return 1;	/* Length plus size of type header */
 }
 
 static FUNC_RECV(nature_of_connection_ind_receive)
 {
 	unsigned char cci = (parm[0] >> 2) & 0x3;
 
-	if (cci != 0x3)
-		c->cot_check_required = cci;
-	else
+	if (cci & 0x1) {
+		c->cot_check_required = 1;
+	} else {
 		c->cot_check_required = 0;
+	}
+
+	if (cci & 0x2) {
+		c->cot_performed_on_previous_cic = 1;
+	} else {
+		c->cot_performed_on_previous_cic = 0;
+	}
+
+	if (parm[0] & 0x10) {
+		c->echocontrol_ind = 1;
+	} else {
+		c->echocontrol_ind = 0;
+	}
 
 	return 1;
 }
@@ -380,7 +514,20 @@
 static FUNC_SEND(forward_call_ind_transmit)
 {
 	parm[0] = 0x60;
-	parm[1] = 0x01;
+	parm[1] = 0x0;
+
+	if (ss7->flags & SS7_ISDN_ACCESS_INDICATOR) {
+		parm [1] |= 0x01;
+	}
+
+	if (c->interworking_indicator) {
+		parm[0] |= (1 << 3);
+	}
+
+	if (c->forward_indicator_pmbits) {
+		parm[1] |= (c->forward_indicator_pmbits & 0xf0);
+	}
+
 	return 2;
 }
 
@@ -447,6 +594,8 @@
 	ss7_message(ss7, "\t\t\tISDN User Part Pref Ind: %s (%d)\n", hg_str, (parm[0] >> 6) & 3);
 	ss7_message(ss7, "\t\t\tISDN Access Ind: originating access %s (%d)\n", (parm[1] & 1) ? "ISDN" : "non-ISDN", parm[1] & 1);
 	ss7_message(ss7, "\t\t\tSCCP Method Ind: %s (%d)\n", kj_str, (parm[1] >> 1) & 3);
+	ss7_message(ss7, "\t\t\tP-M bits(%d) P: %d O: %d N: %d M: %d\n",  (parm[1] & 0xf0),
+		((parm[1] >> 7) & 0x1), ((parm[1] >> 6) & 0x1), ((parm[1] >> 5) & 0x1), ((parm[1] >> 4) & 0x1));
 	return 2;
 }
 
@@ -458,7 +607,7 @@
 
 static FUNC_SEND(calling_party_cat_transmit)
 {
-	parm[0] = 0x0a; /* Default to Ordinary calling subscriber */
+	parm[0] = c->calling_party_cat;
 	return 1;
 }
 
@@ -529,10 +678,11 @@
 
 static FUNC_SEND(transmission_medium_reqs_transmit)
 {
-	if (ss7->switchtype != SS7_ITU)
+	if (ss7->switchtype != SS7_ITU) {
 		return 0;
-	/* Speech */
-	parm[0] = 0;
+	}
+
+	parm[0] = c->transcap;
 	return 1;
 }
 
@@ -551,28 +701,14 @@
 			type = "Speech";
 			break;
 		case 1:
+		case 6:
 			type = "Spare";
 			break;
 		case 2:
 			type = "64 kbit/s unrestricted";
 			break;
-		case 4:
+		case 3:
 			type = "3.1 khz audio";
-			break;
-		case 6:
-			type = "64 kbit/s preferred";
-			break;
-		case 7:
-			type = "2 x 64 kbit/s unrestricted";
-			break;
-		case 8:
-			type = "384 kbit/s unrestricted";
-			break;
-		case 9:
-			type = "1536 kbit/s unrestricted";
-			break;
-		case 10:
-			type = "1920 kbit/s unrestricted";
 			break;
 		default:
 			type = "N x 64kbit/s unrestricted or possibly spare";
@@ -603,12 +739,13 @@
 {
 	int odd = 0;
 
-	if (parm[0] & 0x80)
+	if (parm[0] & 0x80) {
 		odd = 1;
+	}
 
 	isup_get_number(c->called_party_num, &parm[2], len - 2, odd);
 
-	c->called_nai = parm[0] & 0x7f; /* Nature of Address Indicator */
+	c->called_nai = parm[0] & 0x7f;	/* Nature of Address Indicator */
 
 	return len;
 }
@@ -619,12 +756,13 @@
 
 	isup_put_number(&parm[2], c->called_party_num, &numlen, &oddeven);
 
-	parm[0] = c->called_nai & 0x7f; /* Nature of Address Indicator */
-
-	if (oddeven)
-		parm[0] |= 0x80; /* Odd number of digits */
-
-	parm[1] = 0x1 << 4; /* Assume E.164 ISDN numbering plan, called number complete  */
+	parm[0] = c->called_nai & 0x7f;	/* Nature of Address Indicator */
+
+	if (oddeven) {
+		parm[0] |= 0x80;	/* Odd number of digits */
+	}
+
+	parm[1] = 0x1 << 4;		/* Assume E.164 ISDN numbering plan, called number complete  */
 
 	return numlen + 2;
 }
@@ -632,13 +770,23 @@
 static FUNC_RECV(backward_call_ind_receive)
 {
 	c->called_party_status_ind = (parm[0] >> 2) & 0x3;
+	c->echocontrol_ind = (parm[1] >> 5) & 0x1;
 	return 2;
 }
 
 static FUNC_SEND(backward_call_ind_transmit)
 {
 	parm[0] = 0x40;
-	parm[1] = 0x14;
+	parm[1] = 0x04;
+
+	if (c->local_echocontrol_ind) {
+		parm[1] |= 0x20;
+	}
+
+	if (ss7->flags | SS7_ISDN_ACCESS_INDICATOR) {
+		parm[1] |= 0x10;
+	}
+
 	return 2;
 }
 
@@ -691,6 +839,51 @@
 	return 1;
 }
 
+static FUNC_DUMP(opt_forward_call_ind_dump)
+{
+	char *desc;
+
+	switch (parm[0] & 0x03) {
+	case ISUP_CUG_NON:
+		desc = "non-CUG call";
+		break;
+	case ISUP_CUG_OUTGOING_ALLOWED:
+		desc = "closed user group call, outgoing access allowed";
+		break;
+	case ISUP_CUG_OUTGOING_NOT_ALLOWED:
+		desc = "closed user group call, outgoing access not allowed";
+		break;
+	default:
+		desc = "spare";
+	}
+
+	ss7_message(ss7, "\t\t\tClosed user group call indicator: %s\n", desc);
+	ss7_message(ss7, "\t\t\tSimple segmentation indicator: %s\n", (parm[0] & (1 << 2)) ?
+			"additional information will be sent in segmentation message" :
+			"no additional message will be sent");
+	ss7_message(ss7, "\t\t\tConnected line identify request indicator %s\n", (parm[0] & (1 << 7)) ?
+			"requested": "not requested");
+
+	return 1;
+}
+
+static FUNC_SEND(opt_forward_call_ind_transmit)
+{
+	if (c->col_req || c->cug_indicator) {
+		parm[0] = (c->cug_indicator & 0x03) | (c->col_req << 7);
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+static FUNC_RECV(opt_forward_call_ind_receive)
+{
+	c->cug_indicator = parm[0] & 0x03;
+	c->col_req = parm[0] >> 7;
+	return 1;
+}
+
 static FUNC_RECV(cause_receive)
 {
 	c->causeloc = parm[0] & 0xf;
@@ -946,14 +1139,16 @@
 	numcics = c->range + 1;
 
 	/* No status for these messages */
-	if ((messagetype == ISUP_CQR) || (messagetype == ISUP_CQM) || (messagetype == ISUP_GRS))
+	if ((messagetype == ISUP_CQR) || (messagetype == ISUP_CQM) || (messagetype == ISUP_GRS)) {
 		return len;
+	}
 
 	for (i = 0; i < numcics; i++) {
-		if (parm[1 + (i/8)] & (1 << (i%8)))
+		if (parm[1 + (i/8)] & (1 << (i%8))) {
 			c->status[i] = 1;
-		else
+		} else {
 			c->status[i] = 0;
+		}
 	}
 
 	return len;
@@ -967,19 +1162,18 @@
 	parm[0] = c->range & 0xff;
 
 	/* No status for these messages */
-	if ((messagetype == ISUP_CQR) || (messagetype == ISUP_CQM) || (messagetype == ISUP_GRS))
+	if ((messagetype == ISUP_CQR) || (messagetype == ISUP_CQM) || (messagetype == ISUP_GRS)) {
 		return 1;
+	}
 
 	statuslen = (numcics / 8) + !!(numcics % 8);
 
-	if (messagetype == ISUP_GRA) {
-		for (i = 0; i < statuslen; i++) {
-			parm[1 + i] = 0;
+	for (i = 0; i < numcics; i++) {
+		if (!(i % 8)) {
+			parm[1 + (i/8)] = '\0';
 		}
-	} else {
-		for (i = 0; i < numcics; i++) {
-			if (c->status[i])
-				parm[1 + (i/8)] |= (1 << (i % 8));
+		if (c->status[i]) {
+			parm[1 + (i/8)] |= (1 << (i % 8));
 		}
 	}
 
@@ -1010,28 +1204,85 @@
 
 	isup_get_number(c->calling_party_num, &parm[2], len - 2, oddeven);
 
-	c->calling_nai = parm[0] & 0x7f;                /* Nature of Address Indicator */
+	c->calling_nai = parm[0] & 0x7f;		/* Nature of Address Indicator */
 	c->presentation_ind = (parm[1] >> 2) & 0x3;
 	c->screening_ind = parm[1] & 0x3;
 
 	return len;
-
 }
 
 static FUNC_SEND(calling_party_num_transmit)
 {
 	int oddeven, datalen;
 
-	if (!c->calling_party_num[0])
+	if (!c->calling_party_num[0] && c->presentation_ind != SS7_PRESENTATION_ADDR_NOT_AVAILABLE) {
 		return 0;
-
-	isup_put_number(&parm[2], c->calling_party_num, &datalen, &oddeven);
-
-	parm[0] = (oddeven << 7) | c->calling_nai;      /* Nature of Address Indicator */
-	parm[1] = (1 << 4) |                            /* Assume E.164 ISDN numbering plan, calling number complete */
+	}
+
+	if (c->calling_party_num[0] && c->presentation_ind != SS7_PRESENTATION_ADDR_NOT_AVAILABLE) {
+		isup_put_number(&parm[2], c->calling_party_num, &datalen, &oddeven);
+	} else {
+		datalen = 0;
+		oddeven = 0;
+		c->calling_nai = 0;
+	}
+
+	parm[0] = (oddeven << 7) | c->calling_nai;	/* Nature of Address Indicator */
+	 /* Assume E.164 ISDN numbering plan, calling number complete */
+	parm[1] = ((c->presentation_ind == SS7_PRESENTATION_ADDR_NOT_AVAILABLE) ? 0 : (1 << 4)) |
 		((c->presentation_ind & 0x3) << 2) |
 		(c->screening_ind & 0x3);
 
+	return datalen + 2;
+}
+
+static FUNC_DUMP(connected_num_dump)
+{
+	int oddeven = (parm[0] >> 7) & 0x1;
+	char numbuf[64] = "";
+
+	ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[0] & 0x7f);
+	ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[1] >> 4) & 0x7);
+	ss7_message(ss7, "\t\t\tPresentation: %x\n", (parm[1] >> 2) & 0x3);
+	ss7_message(ss7, "\t\t\tScreening: %x\n", parm[1] & 0x3);
+
+	isup_get_number(numbuf, &parm[2], len - 2, oddeven);
+
+	ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf);
+
+	return len;
+}
+
+static FUNC_RECV(connected_num_receive)
+{
+	int oddeven = (parm[0] >> 7) & 0x1;
+
+	isup_get_number(c->connected_num, &parm[2], len - 2, oddeven);
+
+	c->connected_nai = parm[0] & 0x7f;		/* Nature of Address Indicator */
+	c->connected_presentation_ind = (parm[1] >> 2) & 0x3;
+	c->connected_screening_ind = parm[1] & 0x3;
+
+	return len;
+}
+
+static FUNC_SEND(connected_num_transmit)
+{
+	int oddeven = 0, datalen = 0;
+
+	if (!c->col_req) {
+		return 0;				/* if they don't ask we won't tell */
+	}
+
+	if (!c->connected_num[0]) {
+		c->connected_presentation_ind = SS7_PRESENTATION_ADDR_NOT_AVAILABLE;
+	} else {
+		isup_put_number(&parm[2], c->connected_num, &datalen, &oddeven);
+	}
+
+	parm[0] = (oddeven << 7) | c->connected_nai;	/* Nature of Address Indicator */
+	 /* Assume E.164 ISDN numbering plan, calling number complete */
+	parm[1] = ((c->connected_presentation_ind & 0x3) << 2) | (c->connected_screening_ind & 0x3);
 	return datalen + 2;
 }
 
@@ -1236,17 +1487,17 @@
 	return 1;
 }
 
-static FUNC_SEND(originating_line_information_transmit) 
-{
-	if (c->oli_ani2 < 0) {  /* Allow dialplan to strip OLI parm if you don't want to resend what was received */
+static FUNC_SEND(originating_line_information_transmit)
+{
+	if (c->oli_ani2 < 0) {	/* Allow dialplan to strip OLI parm if you don't want to resend what was received */
 		return 0;
 	} else if (c->oli_ani2 < 99) {
-		parm[0] = c->oli_ani2;  
+		parm[0] = c->oli_ani2;
 		return 1;
 	} else {
-		parm[0] = 0x00; /* This value is setting OLI equal to POTS line. */
+		parm[0] = 0x00;	/* This value is setting OLI equal to POTS line. */
 		return 1;
-	}   
+	}
 }
 
 static FUNC_DUMP(carrier_identification_dump)
@@ -1261,8 +1512,8 @@
 
 static FUNC_SEND(carrier_identification_transmit)
 {
-	parm[0] = 0x22;  /* 4 digit CIC */
-	parm[1] = 0x00;  /* would send default 0000 */
+	parm[0] = 0x22;	/* 4 digit CIC */
+	parm[1] = 0x00;	/* would send default 0000 */
 	parm[2] = 0x00;
 
 	return 3;
@@ -1305,7 +1556,7 @@
 
 static FUNC_SEND(hop_counter_transmit)
 {
-	parm[0] = 0x01; /* would send hop counter with value of 1 */
+	parm[0] = 0x01;	/* would send hop counter with value of 1 */
 	return 1;
 }
 
@@ -1315,7 +1566,7 @@
 
 	isup_get_number(c->charge_number, &parm[2], len - 2, oddeven);
 
-	c->charge_nai = parm[0] & 0x7f;                /* Nature of Address Indicator */
+	c->charge_nai = parm[0] & 0x7f;			/* Nature of Address Indicator */
 	c->charge_num_plan = (parm[1] >> 4) & 0x7;
 
 	return len;
@@ -1336,38 +1587,40 @@
 	return len;
 }
 
-static FUNC_SEND(charge_number_transmit)  //ANSI network
+static FUNC_SEND(charge_number_transmit)	// ANSI network
 {
 	int oddeven, datalen;
 
 	if (!c->charge_number[0])
 		return 0;
 
-	isup_put_number(&parm[2], c->charge_number, &datalen, &oddeven);  /* use the value from callerid in sip.conf to fill charge number */
-
-	parm[0] = (oddeven << 7) | c->charge_nai;        /* Nature of Address Indicator = odd/even and ANI of the Calling party, subscriber number */
-	parm[1] = (1 << 4) | 0x0;       //c->charge_num_plan    /* Assume E.164 ISDN numbering plan, calling number complete and make sure reserved bits are zero */
+	isup_put_number(&parm[2], c->charge_number, &datalen, &oddeven);	/* use the value from callerid in sip.conf to fill charge number */
+
+	parm[0] = (oddeven << 7) | c->charge_nai;		/* Nature of Address Indicator = odd/even and ANI of the Calling party, subscriber number */
+	parm[1] = (1 << 4) | 0x0;	//c->charge_num_plan	/* Assume E.164 ISDN numbering plan, calling number complete and make sure reserved bits are zero */
 
 	return datalen + 2;
-
 }
 
 static FUNC_SEND(continuity_ind_transmit)
 {
-	if (c->cot_check_passed)
+	if (c->cot_check_passed) {
 		parm[0] = 0x01;
-	else
+	} else {
 		parm[0] = 0x00;
+	}
 
 	return 1;
 }
 
 static FUNC_RECV(continuity_ind_receive)
 {
-	if (0x1 & parm[0])
+	if (0x1 & parm[0]) {
 		c->cot_check_passed = 1;
-	else
+	} else {
 		c->cot_check_passed = 0;
+	}
+
 	return 1;
 }
 
@@ -1552,11 +1805,22 @@
 
 static FUNC_RECV(redirection_info_receive)
 {
+	c->redirect_info = 1;
+	c->redirect_info_ind = parm[0] & 0x7;
+	c->redirect_info_orig_reas = (parm[0] >> 4) & 0xf;
+	c->redirect_info_counter = parm[1] & 0x7;
+	c->redirect_info_reas = (parm[1] >> 4) & 0xf;
 	return 2;
 }
 
 static FUNC_SEND(redirection_info_transmit)
 {
+	if (!c->redirect_info) {
+		return 0;
+	}
+
+	parm[0] = (c->redirect_info_ind & 0x7) | ((c->redirect_info_orig_reas << 4) & 0xf0);
+	parm[1] = (c->redirect_info_counter & 0x7) | ((c->redirect_info_reas << 4) & 0xf0);
 	return 2;
 }
 
@@ -1591,8 +1855,9 @@
 	int namelen = strlen(c->generic_name);
 
 	/* Check to see if generic name is set before we try to add it */
-	if (!c->generic_name[0])
+	if (!c->generic_name[0]) {
 		return 0;
+	}
 
 	parm[0] = (c->generic_name_typeofname << 5) | ((c->generic_name_avail & 0x1) << 4) | (c->generic_name_presentation & 0x3);
 	memcpy(&parm[1], c->generic_name, namelen);
@@ -1604,74 +1869,72 @@
 {
 	int oddeven = (parm[1] >> 7) & 0x1;
 	char numbuf[64] = "";
-	
+
 	ss7_message(ss7, "\t\t\tType of address: %x\n", parm[0]);
 	ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[1] & 0x7f);
 	ss7_message(ss7, "\t\t\tOddEven: %x\n", (parm[1] >> 7) & 0x1);
 	ss7_message(ss7, "\t\t\tReserved: %x\n", parm[2] & 0x3);
 	ss7_message(ss7, "\t\t\tPresentation: %x\n", (parm[2] >> 2) & 0x3);
 	ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[2] >> 4) & 0x7);
-	
+
 	isup_get_number(numbuf, &parm[3], len - 3, oddeven);
-	
+
 	ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf);
-	
+
 	return len;
 }
 
 static FUNC_RECV(generic_address_receive)
 {
 	int oddeven = (parm[1] >> 7) & 0x1;
-	
+
 	c->gen_add_type = parm[0];
 	c->gen_add_nai = parm[1] & 0x7f;
 	c->gen_add_pres_ind = (parm[2] >> 2) & 0x3;
 	c->gen_add_num_plan = (parm[2] >> 4) & 0x7;
-	
+
 	isup_get_number(c->gen_add_number, &parm[3], len - 3, oddeven);
-	
+
 	return len;
 }
 
 static FUNC_SEND(generic_address_transmit)
 {
-	
 	int oddeven, datalen;
-	
-	if (!c->gen_add_number[0])
+
+	if (!c->gen_add_number[0]) {
 		return 0;
-	
+	}
+
 	isup_put_number(&parm[3], c->gen_add_number, &datalen, &oddeven);
-	
+
 	parm[0] = c->gen_add_type;
-	parm[1] = (oddeven << 7) | c->gen_add_nai;      /* Nature of Address Indicator */
-	parm[2] = (c->gen_add_num_plan << 4) |                           
+	parm[1] = (oddeven << 7) | c->gen_add_nai;	/* Nature of Address Indicator */
+	parm[2] = (c->gen_add_num_plan << 4) |
 		((c->gen_add_pres_ind & 0x3) << 2) |
 		( 0x00 & 0x3);
-	
+
 	return datalen + 3;
 }
-
 
 static FUNC_DUMP(generic_digits_dump)
 {
 	int oddeven = (parm[0] >> 5) & 0x7;
 	char numbuf[64] = "";
-	
+
 	ss7_message(ss7, "\t\t\tType of digits: %x\n", parm[0] & 0x1f);
 	ss7_message(ss7, "\t\t\tEncoding Scheme: %x\n", (parm[0] >> 5) & 0x7);
 	isup_get_number(numbuf, &parm[1], len - 1, oddeven);
 	ss7_message(ss7, "\t\t\tAddress digits: %s\n", numbuf);
 
 	return len;
-	
 }
 
 static FUNC_RECV(generic_digits_receive)
 {
 	c->gen_dig_scheme = (parm[0] >> 5) & 0x7;
 	c->gen_dig_type = parm[0] & 0x1f;
-	
+
 	isup_get_number(c->gen_dig_number, &parm[1], len - 1, c->gen_dig_scheme);
 	return len;
 }
@@ -1679,18 +1942,19 @@
 static FUNC_SEND(generic_digits_transmit)
 {
 	int oddeven, datalen;
-	
-	if (!c->gen_dig_number[0])
+
+	if (!c->gen_dig_number[0]) {
 		return 0;
-	
+	}
+
 	switch (c->gen_dig_type) {
 		case 0:
 		case 1:
-		case 2: /* used for sending digit strings */
+		case 2:	/* used for sending digit strings */
 			isup_put_number(&parm[1], c->gen_dig_number, &datalen, &oddeven);
 			parm[0] = (oddeven << 5 ) | c->gen_dig_type;
 			break;
-		case 3:	 /*used for sending BUSINESS COMM. GROUP IDENTIY type */
+		case 3:	/*used for sending BUSINESS COMM. GROUP IDENTIY type */
 			isup_put_generic(&parm[1], c->gen_dig_number, &datalen);
 			parm[0] = (c->gen_dig_scheme << 5 ) | c->gen_dig_type;
 			break;
@@ -1706,15 +1970,16 @@
 {
 	int oddeven = (parm[0] >> 7) & 0x1;
 	char numbuf[64] = "";
-	
+
 	ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[0] & 0x7f);
 	ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[1] >> 4) & 0x7);
 	ss7_message(ss7, "\t\t\tPresentation: %x\n", (parm[1] >> 2) & 0x3);
-	
+	ss7_message(ss7, "\t\t\tScreening: %x\n", parm[1] & 0x3);
+
 	isup_get_number(numbuf, &parm[2], len - 2, oddeven);
-	
+
 	ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf);
-	
+
 	return len;
 }
 
@@ -1733,7 +1998,20 @@
 
 static FUNC_SEND(original_called_num_transmit)
 {
-	return len;
+	int oddeven, datalen;
+
+	if (!c->orig_called_num[0]) {
+		return 0;
+	}
+
+	isup_put_number(&parm[2], c->orig_called_num, &datalen, &oddeven);
+
+	parm[0] = (oddeven << 7) | c->orig_called_nai;	/* Nature of Address Indicator */
+	parm[1] = (1 << 4) |				/* Assume E.164 ISDN numbering plan, calling number complete */
+		((c->orig_called_pres_ind & 0x3) << 2) |
+		(c->orig_called_screening_ind & 0x3);
+
+	return datalen + 2;
 }
 
 static FUNC_DUMP(echo_control_info_dump)
@@ -1840,7 +2118,7 @@
 	unsigned char dcbits, babits, febits;
 	char *ba_str, *dc_str, *fe_str;
 	int i;
-	
+
 	for (i = 0; i < len; i++) {
 		babits = parm[i] & 0x3;
 		dcbits = (parm[i] >> 2) & 0x3;
@@ -1919,8 +2197,9 @@
 {
 	int numcics = c->range + 1, i;
 
-	for (i = 0; i < numcics; i++)
+	for (i = 0; i < numcics; i++) {
 		parm[i] = c->status[i];
+	}
 
 	return numcics;
 }
@@ -1931,7 +2210,7 @@
 	ss7_message(ss7, "\t\t\tNetwork ID plan: %x\n", parm[0] & 0xf);
 	ss7_message(ss7, "\t\t\tNetwork ID: %x %x\n", parm[1], parm[2]);
 	ss7_message(ss7, "\t\t\tCircuit Code: %x\n", (parm[3] >> 4) & 0xf);
-	
+
 	return len;
 }
 
@@ -1941,6 +2220,98 @@
 }
 
 static FUNC_RECV(tns_receive)
+{
+	return len;
+}
+
+static FUNC_DUMP(generic_notification_ind_dump)
+{
+	int pos = 0;
+	ss7_message(ss7, "\t\t\tNotification indicator: ");
+
+	while (pos < len && (pos || !(parm[pos - 1] & 0x80))) {
+		switch (parm[pos] & 0x7f) {
+			case 0x00:
+				ss7_message(ss7, "user suspended; ");
+				break;
+			case 0x01:
+				ss7_message(ss7, "user resumed; ");
+				break;
+			case 0x02:
+				ss7_message(ss7, "bearer service change; ");
+				break;
+			case 0x03:
+				ss7_message(ss7, "discriminator for extension to ASN.1; ");
+				break;
+			case 0x04:
+				ss7_message(ss7, "call completion delay; ");
+				break;
+			case 0x42:
+				ss7_message(ss7, "conference established; ");
+				break;
+			case 0x43:
+				ss7_message(ss7, "conference disconnected; ");
+				break;
+			case 0x44:
+				ss7_message(ss7, "other party added; ");
+				break;
+			case 0x45:
+				ss7_message(ss7, "isolated; ");
+				break;
+			case 0x46:
+				ss7_message(ss7, "reattached; ");
+				break;
+			case 0x47:
+				ss7_message(ss7, "other party isolated; ");
+				break;
+			case 0x48:
+				ss7_message(ss7, "other party reattached; ");
+				break;
+			case 0x49:
+				ss7_message(ss7, "other party split; ");
+				break;
+			case 0x4a:
+				ss7_message(ss7, "other party disconnected; ");
+				break;
+			case 0x4b:
+				ss7_message(ss7, "other party floating; ");
+				break;
+			case 0x60:
+				ss7_message(ss7, "call is a waiting call; ");
+				break;
+			case 0x68:
+				ss7_message(ss7, "diversion activated; ");
+				break;
+			case 0x69:
+				ss7_message(ss7, "call transfer, alerting; ");
+				break;
+			case 0x6a:
+				ss7_message(ss7, "call transfer, active; ");
+				break;
+			case 0x79:
+				ss7_message(ss7, "remote hold; ");
+				break;
+			case 0x7a:
+				ss7_message(ss7, "remote retrieval; ");
+				break;
+			case 0x7b:
+				ss7_message(ss7, "remote is diverting; ");
+				break;
+			default:
+				ss7_message(ss7, "reserved; ");
+		}
+		pos++;
+	}
+	ss7_message(ss7, "\n");
+	return len;
+}
+
+static FUNC_SEND(generic_notification_ind_transmit)
+{
+	return 0;
+}
+
+static FUNC_RECV(generic_notification_ind_receive)
 {
 	return len;
 }
@@ -1951,7 +2322,7 @@
 	/* This causes the Nortel switch to return the CALLREFERENCE Parm on the ACM of the outgoing call */
 	/* This parm has more fields that can be set but Nortel DMS-250/500 needs it set as below */
 	if (c->lspi_scheme) {
-		parm[0] = c->lspi_scheme << 5 | c->lspi_type;  /* only setting parms for NORTEL RLT on IMT trktype */
+		parm[0] = c->lspi_scheme << 5 | c->lspi_type;	/* only setting parms for NORTEL RLT on IMT trktype */
 		return 1;
 	}
 	return 0;
@@ -1963,7 +2334,7 @@
 	c->lspi_scheme = parm[0] >> 5 & 0x7;
 	c->lspi_context = parm[1] & 0xf;
 	isup_get_number(c->lspi_ident, &parm[2], len - 2, c->lspi_scheme);
-	
+
 	return len;
 }
 
@@ -1974,26 +2345,28 @@
 	ss7_message(ss7, "\t\t\tContext ID: %x\n", parm[1] & 0xf);
 	ss7_message(ss7, "\t\t\tSpare: %x\n", (parm[1] >> 4) & 0xf);
 	ss7_message(ss7, "\t\t\tLSP Identity: %x\n", parm[2]);
-	
+
 	return len;
 }
 
 static FUNC_DUMP(call_ref_dump)
 {
 	unsigned int ptc, callr;
-	
+
 	callr = parm[0] | (parm[1] << 8) | (parm[2] << 16);
-	if (ss7->switchtype == SS7_ANSI)
+	if (ss7->switchtype == SS7_ANSI) {
 		ptc = parm[3] | (parm[4] << 8) | (parm[5] << 16);
-	else
+	} else {
 		ptc = parm[3] | (parm[4] << 8);
-	
+	}
+
 	ss7_message(ss7, "\t\t\tCall identity: %d\n", callr);
-	if (ss7->switchtype == SS7_ANSI)
+	if (ss7->switchtype == SS7_ANSI) {
 		ss7_message(ss7, "\t\t\tPC: Net-CLstr-Mbr: %d-%d-%d\n",(ptc >> 16) & 0xff, (ptc >> 8) & 0xff, ptc & 0xff);
-	else
+	} else {
 		ss7_message(ss7, "\t\t\tPC: 0x%x\n", ptc);
-	
+	}
+
 	return len;
 }
 
@@ -2045,7 +2418,7 @@
 
 static FUNC_SEND(facility_ind_transmit)
 {
-	parm[0] = 0x10; /* Setting Value to Nortel DMS-250/500 needs for RLT */
+	parm[0] = 0x10;	/* Setting Value to Nortel DMS-250/500 needs for RLT */
 	return 1;
 }
 
@@ -2053,66 +2426,234 @@
 {
 	int oddeven = (parm[0] >> 7) & 0x1;
 	char numbuf[64] = "";
-	
+
 	ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[0] & 0x7f);
 	ss7_message(ss7, "\t\t\tNI: %x\n", (parm[1] >> 7) & 0x1);
 	ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[1] >> 4) & 0x7);
 	ss7_message(ss7, "\t\t\tPresentation: %x\n", (parm[1] >> 2) & 0x3);
 	ss7_message(ss7, "\t\t\tScreening: %x\n", parm[1] & 0x3);
-	
+
 	isup_get_number(numbuf, &parm[2], len - 2, oddeven);
-	
+
 	ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf);
-	
+
 	return len;
 }
 
 static FUNC_RECV(redirecting_number_receive)
 {
 	int oddeven = (parm[0] >> 7) & 0x1;
-	
+
 	isup_get_number(c->redirecting_num, &parm[2], len - 2, oddeven);
-	
-	c->redirecting_num_nai = parm[0] & 0x7f;                /* Nature of Address Indicator */
+
+	c->redirecting_num_nai = parm[0] & 0x7f;			/* Nature of Address Indicator */
 	c->redirecting_num_presentation_ind = (parm[1] >> 2) & 0x3;
 	c->redirecting_num_screening_ind = parm[1] & 0x3;
-	
+
 	return len;
-	
 }
 
 static FUNC_SEND(redirecting_number_transmit)
 {
-	return 0;	
-}	
+	int oddeven, datalen;
+
+	if (!c->redirecting_num[0]) {
+		return 0;
+	}
+
+	isup_put_number(&parm[2], c->redirecting_num, &datalen, &oddeven);
+	parm[0] = (oddeven << 7) | c->redirecting_num_nai;	/* Nature of Address Indicator */
+	parm[1] = (1 << 4) |					/* Assume E.164 ISDN numbering plan, calling number complete */
+		((c->redirecting_num_presentation_ind & 0x3) << 2) |
+		(c->redirecting_num_screening_ind & 0x3);
+
+	return datalen + 2;
+}
+
+static FUNC_DUMP(redirect_counter_dump)
+{
+	ss7_message(ss7, "\t\t\tRedirect count: %i\n", parm[0] & 0x1f);
+	return 1;
+}
+
+static FUNC_RECV(redirect_counter_receive)
+{
+	c->redirect_counter = parm[0] & 0x1f;
+	return 1;
+}
+
+static FUNC_SEND(redirect_counter_transmit)
+{
+	if (!c->redirect_counter) {
+		return 0;
+	}
+
+	parm[0] = c->redirect_counter & 0x1f;
+	return 1;
+}
+
+static FUNC_DUMP(inr_ind_dump)
+{
+	ss7_message(ss7, "\t\t\tCalling party address %srequested\n", (parm[0] & 0x1) ? "" : "not ");
+	ss7_message(ss7, "\t\t\tHolding %srequested\n", (parm[0] & 0x2) ? "" : "not ");
+	ss7_message(ss7, "\t\t\tCalling party category %srequested\n", (parm[0] & 0x8) ? "" : "not ");
+	ss7_message(ss7, "\t\t\tCharge information %srequested\n", (parm[0] & 0x10) ? "" : "not ");
+	ss7_message(ss7, "\t\t\tMalicous call identification %srequested\n", (parm[0] & 0x80) ? "" : "not ");
+	return 2;
+}
+
+static FUNC_RECV(inr_ind_receive)
+{
+	c->inr_ind[0] = parm[0];
+	c->inr_ind[1] = parm[1];
+	return 2;
+}
+
+static FUNC_SEND(inr_ind_transmit)
+{
+	parm[0] = c->inr_ind[0];
+	parm[1] = c->inr_ind[1];
+	return 2;
+}
+
+static FUNC_DUMP(inf_ind_dump)
+{
+	ss7_message(ss7, "\t\t\tCalling party address: %s\n",
+		(parm[0] & 0x2) ? ((parm[0] & 0x1) ? "included" : "spare" ) : ((parm[0] & 0x1) ? "not available" : "not included") );
+	ss7_message(ss7, "\t\t\tHold: %sprovided\n", (parm[0] & 0x4) ? "" : "not ");
+	ss7_message(ss7, "\t\t\tCalling party's category %sincluded\n", (parm[0] & 0x20) ? "" : "not ");
+	ss7_message(ss7, "\t\t\tCharge information %sincluded\n", (parm[0] & 0x40) ? "" : "not ");
+	ss7_message(ss7, "\t\t\t%s\n", (parm[0] & 0x80) ? "Unsolicated" : "Solicated");
+
+	return 2;
+}
+
+static FUNC_RECV(inf_ind_receive)
+{
+	c->inf_ind[0] = parm[0];
+	c->inf_ind[1] = parm[1];
+	if ((parm[0] & 0x3) == 0x1) {
+		c->presentation_ind = SS7_PRESENTATION_ADDR_NOT_AVAILABLE;
+	}
+	return 2;
+}
+
+static FUNC_SEND(inf_ind_transmit)
+{
+	parm[0] = c->inf_ind[0];
+	parm[1] = c->inf_ind[1];
+	return 2;
+}
 
 static FUNC_DUMP(access_transport_dump)
 {
-	return len;	
-}	
+	return len;
+}
+
 static FUNC_RECV(access_transport_receive)
 {
-	return len;	
-}	
+	return len;
+}
 
 static FUNC_SEND(access_transport_transmit)
 {
-	return len;	
-}	
+	return len;
+}
 
 static FUNC_DUMP(suspend_resume_ind_dump)
 {
 	int indicator = parm[0] & 1;
 
 	ss7_message(ss7, "\t\t\tSUS/RES indicator: %s (%d)", indicator ? "Network initiated" : "ISDN Subscriber initiated", indicator);
-	return 1;	
-}	
+	return 1;
+}
 
 static FUNC_RECV(suspend_resume_ind_receive)
 {
 	c->network_isdn_indicator = parm[0] & 1;
-	return 1;	
-}	
+	return 1;
+}
+
+static FUNC_SEND(suspend_resume_ind_transmit)
+{
+	parm[0] = c->network_isdn_indicator & 1;
+	return 1;
+}
+
+static FUNC_DUMP(subs_num_dump)
+{
+	int oddeven = (parm[0] >> 7) & 0x1;
+	char numbuf[64];
+
+	isup_get_number(numbuf, &parm[1], len - 1, oddeven);
+	ss7_message(ss7, "\t\t\tSubsequent signals: %s\n", numbuf);
+
+	return len;
+}
+
+static FUNC_RECV(subs_num_receive)
+{
+	int oddeven = (parm[0] >> 7) & 0x1;
+
+	isup_get_number(c->called_party_num, &parm[1], len - 1, oddeven);
+
+	return len;
+}
+
+static FUNC_SEND(subs_num_transmit)
+{
+	int oddeven, datalen;
+
+	isup_put_number(&parm[1], c->called_party_num, &datalen, &oddeven);
+	parm[0] = (oddeven << 7);
+
+	return datalen + 1;
+}
+
+static FUNC_DUMP(cug_interlock_code_dump)
+{
+	char ni[5];
+	unsigned short code;
+
+	ni[0] = digit2char(parm[0] >> 4);
+	ni[1] = digit2char(parm[0] & 0x0f);
+	ni[2] = digit2char(parm[1] >> 4);
+	ni[3] = digit2char(parm[1] & 0x0f);
+	ni[4] = '\0';
+
+	code = (parm[2] << 8) | parm [3];
+
+	ss7_message(ss7, "\t\t\tNetwork Identify: %s\n", ni);
+	ss7_message(ss7, "\t\t\tBinary Code: %d\n", code);
+	return 4;
+}
+
+static FUNC_RECV(cug_interlock_code_receive)
+{
+	c->cug_interlock_ni[0] = digit2char(parm[0] >> 4);
+	c->cug_interlock_ni[1] = digit2char(parm[0] & 0x0f);
+	c->cug_interlock_ni[2] = digit2char(parm[1] >> 4);
+	c->cug_interlock_ni[3] = digit2char(parm[1] & 0x0f);
+	c->cug_interlock_ni[4] = '\0';
+
+	c->cug_interlock_code = (parm[2] << 8) | parm [3];
+	return 4;
+}
+
+static FUNC_SEND(cug_interlock_code_transmit)
+{
+	if (!(c->cug_indicator == ISUP_CUG_OUTGOING_ALLOWED || c->cug_indicator == ISUP_CUG_OUTGOING_NOT_ALLOWED)) {
+		return 0;
+	}
+
+	parm[0] = (char2digit(c->cug_interlock_ni[0]) << 4) | char2digit(c->cug_interlock_ni[1]);
+	parm[1] = (char2digit(c->cug_interlock_ni[2]) << 4) | char2digit(c->cug_interlock_ni[3]);
+
+	parm[2] = c->cug_interlock_code >> 8;
+	parm[3] = c->cug_interlock_code & 0xff;
+
+	return 4;
+}
 
 static struct parm_func parms[] = {
 	{ISUP_PARM_NATURE_OF_CONNECTION_IND, "Nature of Connection Indicator", nature_of_connection_ind_dump, nature_of_connection_ind_receive, nature_of_connection_ind_transmit },
@@ -2132,13 +2673,13 @@
 	{ISUP_PARM_CHARGE_NUMBER, "Charge Number", charge_number_dump, charge_number_receive, charge_number_transmit},

[... 7578 lines stripped ...]



More information about the svn-commits mailing list