Browse Source

sipt: added functions to work with forwarding info

- new variables as part of $sipt(...)
sergey-vb 7 years ago
parent
commit
21b9694d4e
4 changed files with 371 additions and 3 deletions
  1. 72 0
      src/modules/sipt/doc/sipt_admin.xml
  2. 157 1
      src/modules/sipt/sipt.c
  3. 4 2
      src/modules/sipt/ss7.h
  4. 138 0
      src/modules/sipt/ss7_parser.c

+ 72 - 0
src/modules/sipt/doc/sipt_admin.xml

@@ -90,6 +90,22 @@ sipt_set_bci_1("2", "1", "1", "0");
 # update the calling party to the value in the from header
 sipt_set_calling($fU, 4, 0, 3);
 ...
+</programlisting>
+		</example>
+	</section>
+	<section id="sipt.f.sipt_forwarding">
+		<title><function moreinfo="none">sipt_forwarding(origin, nai)</function></title>
+		<para>
+			updates the IAM in the body if it exists, setting (or adding) the forwarding number to <quote>origin</quote>
+			with the nature address specified in <quote>nai</quote>.
+		</para>
+		<example>
+			<title><function moreinfo="none">sipt_set_calling(origin, nai)</function> usage</title>
+			<programlisting format="linespecific">
+...
+# update the forwarding number to the value in the from header
+sipt_forwarfing($avp(s:forwarding_number), 3);
+...
 </programlisting>
 		</example>
 	</section>
@@ -313,7 +329,63 @@ if($sipt(called_party_number.nai) == 3)
 			</tgroup>
 		</table>
 	</section>
+	<section id="sipt.v.sipt_redirection_info">
+		<title><varname>$sipt(redirection_info) / $sipt_redirection_info</varname></title>
+		<para>
+			Returns redirection info header from ISUP
+			Returns "Redirecting reason" or -1 if no redirection info found.
+		</para>
+		<table>
+			<title>Redirecting reason Values</title>
+			<tgroup cols="2">
+				<tbody>
+					<row><entry>0</entry><entry>Unknown</entry></row>
+					<row><entry>1</entry><entry>User busy</entry></row>
+					<row><entry>2</entry><entry>PROGRESS</entry></row>
+					<row><entry>3</entry><entry>no reply</entry></row>
+					<row><entry>4</entry><entry>deflection during alerting</entry></row>
+					<row><entry>5</entry><entry>deflection immediate response</entry></row>
+					<row><entry>6</entry><entry>mobile subscriber not reachable</entry></row>
+				</tbody>
+			</tgroup>
+		</table>
+	</section>
+        	<section id="sipt.v.sipt_redirection_number">
+		<title><varname>$sipt(redirection_number) / $sipt_redirection_number</varname></title>
+		<para>
+			Returns number to which redirection will trigered
+			Returns -1 if there is a parsing error.
+		</para>
+		<example>
+			<title><function moreinfo="none">sipt_redirection_number</function> usage</title>
+			<programlisting format="linespecific">
+...
+# get the redirection number
+$avp(s:redir_num) = $sipt(redirection_number);
 
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="sipt.v.sipt_redirection_number_nai">
+		<title><varname>$sipt(redirection_number.nai) / $sipt_redirection_number_nai</varname></title>
+		<para>
+			Returns NAI for redirection number from ISUP
+			Returns NAI for redirection number or -1 if no info found.
+		</para>
+		<table>
+			<title>Redirecting number NAI Values</title>
+			<tgroup cols="2">
+				<tbody>
+					<row><entry>0</entry><entry>Spare</entry></row>
+					<row><entry>1</entry><entry>Subscriber Number (national use)</entry></row>
+					<row><entry>2</entry><entry>Unknown (national use)</entry></row>
+					<row><entry>3</entry><entry>National (significant) number (national use)</entry></row>
+					<row><entry>4</entry><entry>International use</entry></row>
+				</tbody>
+			</tgroup>
+		</table>
+	</section>
 </section>
 </chapter>
 

+ 157 - 1
src/modules/sipt/sipt.c

@@ -41,6 +41,7 @@ MODULE_VERSION
 static int sipt_set_bci_1(struct sip_msg *msg, char *_charge_indicator, char *_called_status, char * _called_category, char * _e2e_indicator);
 static int sipt_destination(struct sip_msg *msg, char *_destination, char *_hops, char * _nai);
 static int sipt_destination2(struct sip_msg *msg, char *_destination, char *_hops, char * _nai, char * _terminator);
+static int sipt_forwarding(struct sip_msg *msg, char *_fwdnumber, char * _nai);
 static int sipt_set_calling(struct sip_msg *msg, char *_origin, char *_nai, char *_pres, char * _screen);
 static int sipt_get_hop_counter(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
 static int sipt_get_event_info(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
@@ -51,6 +52,10 @@ static int sipt_get_screening(struct sip_msg *msg, pv_param_t *param, pv_value_t
 static int sipt_get_called_party_nai(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
 static int sipt_get_charge_indicator(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
 
+static int sipt_get_redirection_info(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+static int sipt_get_redirection_number_nai(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+static int sipt_get_redirection_number(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+
 /* New API */
 int sipt_parse_pv_name(pv_spec_p sp, str *in);
 static int sipt_get_pv(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
@@ -97,6 +102,13 @@ static sipt_header_map_t sipt_header_mapping[] =
 		{{"CHARGE_INDICATOR", 1}, 
 			{NULL, 0}
 		}},
+        {"REDIRECTION_INFO", ISUP_PARM_REDIRECTION_INFO, 
+                {{NULL, 0}}  },
+        {"REDIRECTION_NUMBER", ISUP_PARM_REDIRECTION_NUMBER, 
+            		{{"NATURE_OF_ADDRESS", 1}, 
+			{"NAI", 1},
+			{NULL, 0}
+		}},
 	{ NULL, 0, {}}
 };
 
@@ -139,6 +151,12 @@ static cmd_export_t cmds[]={
 		fixup_str_str_str, fixup_free_str_str_str,         /* */
 		/* can be applied to original requests */
 		REQUEST_ROUTE|BRANCH_ROUTE}, 
+        {"sipt_forwarding", /* action name as in scripts */
+		(cmd_function)sipt_forwarding,  /* C function name */
+		2,          /* number of parameters */
+		fixup_str_str_str, fixup_free_str_str_str,         /* */
+		/* can be applied to original requests */
+		REQUEST_ROUTE|BRANCH_ROUTE}, 
 	{"sipt_set_calling", /* action name as in scripts */
 		(cmd_function)sipt_set_calling,  /* C function name */
 		4,          /* number of parameters */
@@ -275,6 +293,78 @@ static int sipt_get_calling_party_nai(struct sip_msg *msg, pv_param_t *param, pv
 	return 0;
 }
 
+static int sipt_get_redirection_info(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_INFO("No ISUP Message Found");
+		return -1;
+	}
+
+	if((body.s[0] != ISUP_ACM) && (body.s[0] != ISUP_CPG))
+	{
+		LM_DBG("message not an ACM or CPG\n");
+		return -1;
+	}
+	
+	pv_get_sintval(msg, param, res, isup_get_redirection_info((unsigned char*)body.s, body.len));
+	return 0;
+}
+
+static int sipt_get_redirection_number_nai(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_INFO("No ISUP Message Found");
+		return -1;
+	}
+
+	if((body.s[0] != ISUP_ACM) && (body.s[0] != ISUP_CPG))
+	{
+		LM_DBG("message not an ACM or CPG\n");
+		return -1;
+	}
+	
+	pv_get_sintval(msg, param, res, isup_get_redirection_number_nai((unsigned char*)body.s, body.len));
+	return 0;
+}
+
+static int sipt_get_redirection_number(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	char *sb_s_buf = pkg_malloc(sizeof(char) * (26));
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_INFO("No ISUP Message Found");
+		return -1;
+	}
+
+	if((body.s[0] != ISUP_ACM) && (body.s[0] != ISUP_CPG))
+	{
+		LM_DBG("message not an ACM or CPG\n");
+		return -1;
+	}
+	
+	isup_get_redirection_number((unsigned char*)body.s, body.len, sb_s_buf);
+	
+	if (strlen(sb_s_buf) > 0)
+	{
+		pv_get_strzval(msg, param, res, sb_s_buf);
+	} else {
+		pv_get_sintval(msg, param, res, -1);
+	}
+	return 0;
+}
+
+
 static int sipt_get_presentation(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 {
 	str body;
@@ -508,6 +598,17 @@ static int sipt_get_pv(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 				return sipt_get_charge_indicator(msg, param, res);
 			}
 			break;
+		case ISUP_PARM_REDIRECTION_INFO:
+			return sipt_get_redirection_info(msg, param, res);
+                case ISUP_PARM_REDIRECTION_NUMBER:
+			switch(spv->sub_type)
+			{
+				case 0: /* NUMBER */
+					return sipt_get_redirection_number(msg, param, res);
+				case 1: /* NAI */
+					return sipt_get_redirection_number_nai(msg, param, res);
+			}
+			break;
 	}
 
 	return -1;
@@ -689,7 +790,7 @@ static int sipt_set_calling(struct sip_msg *msg, char *_origin, char *_nai, char
 	mangle.msg = msg;
 	mangle.body_offset = (int)(body.s - msg->buf);
 
-	char * digits = calloc(1,origin->len+1);
+	char * digits = calloc(1,origin->len+2);
 	memcpy(digits, origin->s, origin->len);
 
 	int res = isup_update_calling(&mangle, digits, int_nai, pres, screen, (unsigned char*)body.s, body.len);
@@ -703,6 +804,61 @@ static int sipt_set_calling(struct sip_msg *msg, char *_origin, char *_nai, char
 	return 1;
 }
 
+static int sipt_forwarding(struct sip_msg *msg, char *_fwdnumber, char * _nai)
+{
+	str * nai = (str*)_nai;
+	unsigned int int_nai = 0;
+	str2int(nai, &int_nai);
+	str * fwdnumber = (str*)_fwdnumber;
+	struct sdp_mangler mangle;
+
+	// update forwarded iam
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_INFO("No ISUP Message Found");
+		return -1;
+	}
+	str sdp;
+	sdp.s = get_body_part(msg, TYPE_APPLICATION, SUBTYPE_SDP, &sdp.len);
+	
+	unsigned char newbuf[1024];
+	memset(newbuf, 0, 1024);
+	if (body.s==0) {
+		LM_ERR("failed to get the message body\n");
+		return -1;
+	}
+	body.len = msg->len -(int)(body.s-msg->buf);
+	if (body.len==0) {
+		LM_DBG("message body has zero length\n");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+
+	mangle.msg = msg;
+	mangle.body_offset = (int)(body.s - msg->buf);
+
+	char * digits = calloc(1,fwdnumber->len+2);
+	memcpy(digits, fwdnumber->s, fwdnumber->len);
+
+	int res = isup_update_forwarding(&mangle, digits, int_nai, (unsigned char*)body.s, body.len);
+	free(digits);
+	if(res < 0)
+	{
+		LM_DBG("error updating IAM\n");
+		return -1;
+	}
+
+	return 1;
+}
+
 
 static int mod_init(void)
 {

+ 4 - 2
src/modules/sipt/ss7.h

@@ -177,14 +177,12 @@ struct isup_iam_fixed {
 struct isup_acm_fixed {
 	unsigned char type;
 	unsigned char backwards_call_ind[2];
-	unsigned char fixed_pointer;
 	unsigned char optional_pointer;
 };
 
 struct isup_cpg_fixed {
 	unsigned char type;
 	unsigned char event_info;
-	unsigned char fixed_pointer;
 	unsigned char optional_pointer;
 };
 
@@ -206,6 +204,10 @@ int isup_get_charging_indicator(unsigned char *buf, int len);
 int isup_update_destination(struct sdp_mangler * mangle, char * dest, int hops, int nai, unsigned char *buf, int len);
 int isup_update_bci_1(struct sdp_mangler * mangle, int charge_indicator, int called_status, int called_category, int e2e_indicator, unsigned char *buf, int len);
 int isup_update_calling(struct sdp_mangler * mangle, char * origin, int nai, int presentation, int screening, unsigned char * buf, int len);
+int isup_update_forwarding(struct sdp_mangler * mangle, char * forwardn, int nai, unsigned char *buf, int len);
 
+int isup_get_redirection_info(unsigned char *buf, int len);
+int isup_get_redirection_number_nai(unsigned char *buf, int len);
+int isup_get_redirection_number(unsigned char *buf, int len, char* sb_buf);
 
 #endif

+ 138 - 0
src/modules/sipt/ss7_parser.c

@@ -143,6 +143,19 @@ static int encode_calling_party(char * number, int nai, int presentation, int sc
         return datalen + 2;
 }
 
+static int encode_forwarding_number(char * number, int nai, unsigned char * buf, int len) 
+{
+        int oddeven, datalen;
+
+        isup_put_number(&buf[2], number, &datalen, &oddeven);
+
+        buf[0] = (oddeven << 7) | nai;      /* Nature of Address Indicator */
+         /* Assume E.164 ISDN numbering plan, calling number complete */
+        buf[1] = 0x14;
+
+        return datalen + 2;
+}
+
 // returns start of specified optional header of IAM or CPG, otherwise return -1
 static int get_optional_header(unsigned char header, unsigned char *buf, int len)
 {
@@ -322,6 +335,67 @@ int isup_get_charging_indicator(unsigned char *buf, int len) {
 	return (orig_message->backwards_call_ind[0] & 0x03);
 }
 
+int isup_get_redirection_info(unsigned char *buf, int len)
+{
+       int  offset = get_optional_header(ISUP_PARM_GENERIC_NOTIFICATION_IND, buf, len);
+
+       int call_is_diverting = 0;
+       int diversion_reason = 0;
+
+       if(offset != -1 && len-offset > 1)
+       {
+               call_is_diverting = (buf[offset+2]) & 0x7F;
+
+               if ( call_is_diverting == 123 ) {
+                       int  offset1 = get_optional_header(ISUP_PARM_DIVERSION_INFORMATION, buf, len);
+
+                       if(offset1 != -1 && len-offset1 > 1)
+                       {
+                               diversion_reason = (buf[offset1+2]>>3 & 0x0F);
+                               return diversion_reason;
+                       }
+               }
+               return -1;
+
+       }
+        return -1;
+}
+
+int isup_get_redirection_number_nai(unsigned char *buf, int len)
+{
+       int  offset = get_optional_header(ISUP_PARM_REDIRECTION_NUMBER, buf, len);
+
+       if(offset != -1 && len-offset-2 > 1)
+       {
+               return buf[offset+2] & 0x7F;
+       }
+       return -1;
+}
+
+int isup_get_redirection_number(unsigned char *buf, int len, char* sb_buf)
+{
+       int sbparamlen;
+       int sb_i=0;
+       int sb_j=0;
+       int  offset = get_optional_header(ISUP_PARM_REDIRECTION_NUMBER, buf, len);
+
+       if(offset != -1 && len-offset-2 > 1)
+       {
+               sbparamlen = (buf[offset+1] & 0xFF) - 2;
+
+               while ((sbparamlen > 0) && (buf[offset] != 0)) {
+                   sb_buf[sb_i]=(buf[offset+4+sb_j] & 0x0F) + '\x30';
+                   sb_buf[sb_i+1]=(buf[offset+4+sb_j]>>4 & 0x0F) + '\x30';
+                   sb_i=sb_i+2;
+                   sbparamlen--;
+                   sb_j++;
+               }
+               sb_buf[sb_i] = '\x0';
+               return 1;
+       }
+       return -1;
+}
+
 int isup_update_bci_1(struct sdp_mangler * mangle, int charge_indicator, int called_status, int called_category, int e2e_indicator, unsigned char *buf, int len)
 {
 	struct isup_acm_fixed * orig_message = (struct isup_acm_fixed*)buf;
@@ -520,3 +594,67 @@ int isup_update_calling(struct sdp_mangler * mangle, char * origin, int nai, int
 
 	return offset;
 }
+
+int isup_update_forwarding(struct sdp_mangler * mangle, char * forwardn, int nai, unsigned char *buf, int len)
+{
+	int offset = 0;
+	int res;
+	struct isup_iam_fixed * orig_message = (struct isup_iam_fixed*)buf;
+
+	// not an iam? do nothing
+	if(orig_message->type != ISUP_IAM)
+	{
+		return 1;
+	}
+
+	/* Copy the fixed parms */
+	len -= offsetof(struct isup_iam_fixed, called_party_number);
+	offset += offsetof(struct isup_iam_fixed, called_party_number);
+
+	if (len < 1)
+		return -1;
+
+
+	/* IAM has one Fixed variable param, Called party number, we need to modify this */
+
+
+	// add the new mandatory fixed header
+	res = buf[offset];
+	offset += res+1;
+	len -= res+1;
+	
+	if (len < 1 )
+		return -1;
+
+	/* Optional paramter parsing code */
+	if (orig_message->optional_pointer) {
+	
+		while ((len > 0) && (buf[offset] != 0)) {
+			int res2 = 0;
+			struct isup_parm_opt *optparm = (struct isup_parm_opt *)(buf + offset);
+			unsigned char new_party[255];
+
+			res = optparm->len+2;
+			switch(optparm->type)
+			{
+				case ISUP_PARM_REDIRECTING_NUMBER:
+					res2 = encode_forwarding_number(forwardn, nai, &new_party[1], 255-1);
+					new_party[0] = (char)res2;
+					replace_body_segment(mangle, offset+1,(int)buf[offset+1]+1,new_party, res2+1);
+					break;
+                                case ISUP_PARM_ORIGINAL_CALLED_NUM:
+					res2 = encode_forwarding_number(forwardn, nai, &new_party[1], 255-1);
+					new_party[0] = (char)res2;
+					replace_body_segment(mangle, offset+1,(int)buf[offset+1]+1,new_party, res2+1);
+				default:
+					break;
+			}
+
+			len -= res;
+			offset += res;
+		}
+
+	}
+
+	return offset;
+}