Explorar o código

modules/sipt: initial import of module

Torrey Searle %!s(int64=12) %!d(string=hai) anos
pai
achega
a455837166

+ 18 - 0
modules/sipt/Makefile

@@ -0,0 +1,18 @@
+# $Id: $
+#
+# sipt module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=sipt.so
+LIBS=
+
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+
+include ../../Makefile.modules
+

+ 86 - 0
modules/sipt/README

@@ -0,0 +1,86 @@
+sipt Module
+
+Torrey Searle
+
+   Voxbone SA
+   <[email protected]>
+
+   Copyright © 2013 Voxbone SA
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+        3. Functions
+
+              3.1. sipt_destination(destination, hops, nai)
+              3.2. sipt_get_hop_count()
+
+   List of Examples
+
+   1.1. sipt_destination(destination, hops, nai) usage
+   1.2. sipt_get_hop_counter() usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+   3. Functions
+
+        3.1. sipt_destination(destination, hops, nai)
+        3.2. sipt_get_hop_count()
+
+1. Overview
+
+   Module for updating ISUP encapuslated in SIP (SIP-T/SIP-I)
+
+   The sipt module can be used to update various ss7 headers contained
+   inside a message.
+
+2. Dependencies
+
+   The module depends on the following modules (in the other words the
+   listed modules must be loaded before this module):
+     * none
+
+3. Functions
+
+   3.1. sipt_destination(destination, hops, nai)
+   3.2. sipt_get_hop_count()
+
+3.1. sipt_destination(destination, hops, nai)
+
+   updates the IAM in the body if it exists, setting the called party
+   number to “destination” with the nature address specified in “nai” and
+   decrementing the hop counter value if present. If the hop counter
+   header is missing it will be added with the value of “hops”.
+
+   Example 1.1. sipt_destination(destination, hops, nai) usage
+...
+# update the destination number to our current request uri,
+# setting nature of address to international
+$rU = "19495551234";
+sipt_destination($rU, 31, 4);
+...
+
+3.2. sipt_get_hop_count()
+
+   Returns the value of the Hop Coutner for the IAM message if it exists.
+   Returns -1 if there isn't a hop counter.
+
+   Example 1.2. sipt_get_hop_counter() usage
+...
+# get the hop couter and update the Max-Forwards header if it exists
+$avp(s:hop) = sipt_get_hop_counter();
+if($avp(s:hop) > 0)
+{
+        remove_hf("Max-Forwards");
+        append_hf("Max-Forwards: $avp(s:hop)\r\n");
+}
+
+...

+ 4 - 0
modules/sipt/doc/Makefile

@@ -0,0 +1,4 @@
+docs = sipt.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 31 - 0
modules/sipt/doc/sipt.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+	<title>sipt Module</title>
+	<authorgroup>
+		<author>
+		<firstname>Torrey</firstname>
+		<surname>Searle</surname>
+		<affiliation><orgname>Voxbone SA</orgname></affiliation>
+		<email>[email protected]</email>
+		</author>
+	</authorgroup>
+	<copyright>
+		<year>2013</year>
+		<holder>Voxbone SA</holder>
+	</copyright>
+	</bookinfo>
+	<toc></toc>
+
+	<xi:include href="sipt_admin.xml"/>
+
+</book>

+ 83 - 0
modules/sipt/doc/sipt_admin.xml

@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- sipt Module User's Guide -->
+
+<chapter>
+    
+    <title>&adminguide;</title>
+
+    <section>
+	<title>Overview</title>
+	<para>Module for updating ISUP encapuslated in SIP (SIP-T/SIP-I)</para>
+	<para>
+	The sipt module can be used to update various ss7 headers contained inside
+	a message.
+	</para>
+	</section>
+	<section>
+	<title>Dependencies</title>
+	<para>
+	    The module depends on the following modules (in the other words the
+		listed modules must be loaded before this module):
+	    <itemizedlist>
+		<listitem>
+		    <para><emphasis>none</emphasis></para>
+		</listitem>
+	    </itemizedlist>
+	</para>
+    </section>
+
+    <section>
+	<title>Functions</title>
+	<section>
+		<title><function moreinfo="none">sipt_destination(destination, hops, nai)</function></title>
+		<para>
+			updates the IAM in the body if it exists, setting the called party number to <quote>destination</quote>
+			with the nature address specified in <quote>nai</quote> and decrementing the hop counter value if present.
+			If the hop counter header is missing it will be added with the value of <quote>hops</quote>.
+		</para>
+		<example>
+			<title><function moreinfo="none">sipt_destination(destination, hops, nai)</function> usage</title>
+			<programlisting format="linespecific">
+...
+# update the destination number to our current request uri, 
+# setting nature of address to international
+$rU = "19495551234";
+sipt_destination($rU, 31, 4);
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><function moreinfo="none">sipt_get_hop_count()</function></title>
+		<para>
+			Returns the value of the Hop Coutner for the IAM message if it exists.
+			Returns -1 if there isn't a hop counter.
+		</para>
+		<example>
+			<title><function moreinfo="none">sipt_get_hop_counter()</function> usage</title>
+			<programlisting format="linespecific">
+...
+# get the hop couter and update the Max-Forwards header if it exists
+$avp(s:hop) = sipt_get_hop_counter();
+if($avp(s:hop) > 0)
+{
+	remove_hf("Max-Forwards");
+	append_hf("Max-Forwards: $avp(s:hop)\r\n");
+}
+
+...
+</programlisting>
+		</example>
+	</section>
+</section>
+</chapter>
+

+ 419 - 0
modules/sipt/sipt.c

@@ -0,0 +1,419 @@
+/*
+ *
+ * Copyright (C) 2013 Voxbone SA
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ */
+
+
+#include "../../sr_module.h"
+#include "../../parser/parse_param.h"
+#include "../../data_lump.h"
+#include "../../mem/mem.h"
+#include "../../mod_fix.h"
+#include "../../parser/parse_content.h"
+#include "../../parser/parse_body.h"
+#include "../../parser/parser_f.h"
+#include "../../trim.h"
+#include "ss7.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+MODULE_VERSION
+
+static int sipt_destination(struct sip_msg *msg, char *_destination, char *_hops, char * _nai);
+static int sipt_get_hop_counter(struct sip_msg *msg, char *x, char *y);
+
+static int mod_init(void);
+static void mod_destroy(void);
+
+
+
+static int fixup_str_str_str(void** param, int param_no)
+{
+	if(param_no == 1 || param_no == 2 || param_no == 3)
+	{
+		return fixup_str_null(param, 1);
+	}
+	return E_CFG;
+}
+
+static int fixup_free_str_str_str(void** param, int param_no)
+{
+	if(param_no == 1 || param_no == 2 || param_no == 3)
+	{
+		return fixup_free_str_null(param, 1);
+	}
+	return E_CFG;
+}
+
+
+static cmd_export_t cmds[]={
+	{"sipt_destination", /* action name as in scripts */
+		(cmd_function)sipt_destination,  /* C function name */
+		3,          /* number of parameters */
+		fixup_str_str_str, fixup_free_str_str_str,         /* */
+		/* can be applied to original requests */
+		REQUEST_ROUTE|BRANCH_ROUTE}, 
+	{"sipt_get_hop_counter", /* action name as in scripts */
+		(cmd_function)sipt_get_hop_counter,  /* C function name */
+		0,          /* number of parameters */
+		0, 0,         /* */
+		/* can be applied to original requests */
+		REQUEST_ROUTE|BRANCH_ROUTE}, 
+	{0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[]={ 
+	{0,0,0} 
+};
+
+static mi_export_t mi_cmds[] = {
+	{ 0, 0, 0, 0, 0}
+};
+
+static pv_export_t mod_items[] = {
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+struct module_exports exports = {
+	"sipt",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,        /* exported functions */
+	params,      /* exported parameters */
+	0,           /* exported statistics */
+	mi_cmds,     /* exported MI functions */
+	mod_items,   /* exported pseudo-variables */
+	0,           /* extra processes */
+	mod_init,    /* module initialization function */
+	0,           /* response function*/
+	mod_destroy, /* destroy function */
+	0            /* per-child init function */
+};
+
+/*! \brief returns the value of boundary parameter from the Contect-Type HF */
+static inline int get_boundary_param(struct sip_msg *msg, str *boundary)
+{
+        str     s;
+        char    *c;
+        param_t *p, *list;
+
+#define is_boundary(c) \
+        (((c)[0] == 'b' || (c)[0] == 'B') && \
+        ((c)[1] == 'o' || (c)[1] == 'O') && \
+        ((c)[2] == 'u' || (c)[2] == 'U') && \
+        ((c)[3] == 'n' || (c)[3] == 'N') && \
+        ((c)[4] == 'd' || (c)[4] == 'D') && \
+        ((c)[5] == 'a' || (c)[5] == 'A') && \
+        ((c)[6] == 'r' || (c)[6] == 'R') && \
+        ((c)[7] == 'y' || (c)[7] == 'Y'))
+
+#define boundary_param_len (sizeof("boundary")-1)
+
+        /* get the pointer to the beginning of the parameter list */
+        s.s = msg->content_type->body.s;
+        s.len = msg->content_type->body.len;
+        c = find_not_quoted(&s, ';');
+        if (!c)
+                return -1;
+        c++;
+        s.len = s.len - (c - s.s);
+        s.s = c;
+        trim_leading(&s);
+
+        if (s.len <= 0)
+                return -1;
+
+        /* parse the parameter list, and search for boundary */
+        if (parse_params(&s, CLASS_ANY, NULL, &list)<0)
+                return -1;
+
+        boundary->s = NULL;
+        for (p = list; p; p = p->next)
+                if ((p->name.len == boundary_param_len) &&
+                        is_boundary(p->name.s)
+                ) {
+                        boundary->s = p->body.s;
+                        boundary->len = p->body.len;
+                        break;
+                }
+        free_params(list);
+        if (!boundary->s || !boundary->len)
+                return -1;
+
+        DBG("boundary is \"%.*s\"\n",
+                boundary->len, boundary->s);
+        return 0;
+}
+
+static char * SDP_HEADER = "Content-Type: application/sdp\r\n\r\n";
+static char * ISUP_HEADER = "Content-Type: application/ISUP; version=ITU-93\r\nContent-Disposition: signal; handling=optional\r\n\r\n";
+
+static int replace_body(struct sip_msg *msg, str * nb)
+{
+	str body;
+        body.s = get_body(msg);
+	struct lump *anchor;
+	char * buf;
+	free_lump_list(msg->body_lumps);
+	msg->body_lumps = NULL;
+
+
+        if (msg->content_length)
+        {
+                body.len = get_content_length( msg );
+                if(body.len > 0)
+                {
+                        if(body.s+body.len>msg->buf+msg->len)
+                        {
+                                LM_ERR("invalid content length: %d\n", body.len);
+                                return -1;
+                        }
+                        if(del_lump(msg, body.s - msg->buf, body.len, 0) == 0)
+                        {
+                                LM_ERR("cannot delete existing body");
+                                return -1;
+                        }
+                }
+        }
+
+        anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
+
+        if (anchor == 0)
+        {
+                LM_ERR("failed to get anchor\n");
+                return -1;
+        }
+
+        if (msg->content_length==0)
+        {
+                /* need to add Content-Length */
+                int len = nb->len;
+		int value_len;
+                char* value_s=int2str(len, &value_len);
+                LM_DBG("content-length: %d (%s)\n", value_len, value_s);
+
+                len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
+                buf=pkg_malloc(sizeof(char)*(len));
+
+                if (buf==0)
+                {
+                        LM_ERR("out of pkg memory\n");
+                        return -1;
+                }
+
+                memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
+                memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
+                memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
+                if (insert_new_lump_after(anchor, buf, len, 0) == 0)
+                {
+                        LM_ERR("failed to insert content-length lump\n");
+                        pkg_free(buf);
+                        return -1;
+                }
+        }
+
+
+        anchor = anchor_lump(msg, body.s - msg->buf, 0, 0);
+
+        if (anchor == 0)
+        {
+                LM_ERR("failed to get body anchor\n");
+                return -1;
+        }
+
+        buf=pkg_malloc(sizeof(char)*(nb->len));
+        if (buf==0)
+        {
+                LM_ERR("out of pkg memory\n");
+                return -1;
+        }
+        memcpy(buf, nb->s, nb->len);
+        if (insert_new_lump_after(anchor, buf, nb->len, 0) == 0)
+        {
+                LM_ERR("failed to insert body lump\n");
+                pkg_free(buf);
+                return -1;
+        }
+        LM_DBG("new body: [%.*s]", nb->len, nb->s);
+
+	return 0;
+}
+
+static int sipt_get_hop_counter(struct sip_msg *msg, char *x, char *y)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_UNKNOWN,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+	
+	return isup_get_hop_counter((unsigned char*)body.s, body.len);
+}
+
+static int sipt_destination(struct sip_msg *msg, char *_destination, char *_hops, char * _nai)
+{
+	str * str_hops = (str*)_hops;
+	unsigned int hops = 0;
+	str2int(str_hops, &hops);
+	str * nai = (str*)_nai;
+	unsigned int int_nai = 0;
+	str2int(nai, &int_nai);
+	str * destination = (str*)_destination;
+
+	// update forwarded iam
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_UNKNOWN,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("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;
+	}
+
+
+
+	unsigned int offset = 0;
+
+	if(sdp.s != NULL)
+	{
+		// we need to be clean, handle 2 cases
+		// one with sdp, one without sdp
+		str boundary = {0,0}; 
+		get_boundary_param(msg, &boundary);
+		memcpy(newbuf+offset, "--", 2);
+		offset+=2;
+
+		memcpy(newbuf+offset,boundary.s, boundary.len);
+		offset += boundary.len;
+
+		memcpy(newbuf+offset, "\r\n", 2);
+		offset+=2;
+
+		memcpy(newbuf+offset,SDP_HEADER, strlen(SDP_HEADER));
+		offset += strlen(SDP_HEADER);
+
+
+		memcpy(newbuf+offset,sdp.s, sdp.len);
+		offset += sdp.len;
+
+		memcpy(newbuf+offset, "\r\n", 2);
+		offset+=2;
+		memcpy(newbuf+offset, "\r\n--", 4);
+		offset+=4;
+
+		memcpy(newbuf+offset,boundary.s, boundary.len);
+		offset += boundary.len;
+
+		memcpy(newbuf+offset, "\r\n", 2);
+		offset+=2;
+
+		memcpy(newbuf+offset,ISUP_HEADER, strlen(ISUP_HEADER));
+		offset += strlen(ISUP_HEADER);
+
+		char * digits = calloc(1,destination->len+2);
+		memcpy(digits, destination->s, destination->len);
+		digits[destination->len] = '#';
+
+		int res = isup_update_destination(digits, hops, int_nai, (unsigned char*)body.s, body.len, newbuf+offset, 512);
+
+		if(res == -1)
+		{
+			LM_DBG("error updating IAM\n");
+			return -1;
+		}
+
+		free(digits);
+		offset += res;
+
+		memcpy(newbuf+offset, "\r\n--", 4);
+		offset+=4;
+
+		memcpy(newbuf+offset,boundary.s, boundary.len);
+		offset += boundary.len;
+
+		memcpy(newbuf+offset, "--\r\n", 4);
+		offset+=4;
+	}
+	else
+	{
+		// isup only body
+		char * digits = calloc(1,destination->len+2);
+		memcpy(digits, destination->s, destination->len);
+		digits[destination->len] = '#';
+
+		int res = isup_update_destination(digits, hops, int_nai, (unsigned char*)body.s, body.len, newbuf, 512);
+		free(digits);
+		offset = res;
+		if(res == -1)
+		{
+			LM_DBG("error updating IAM\n");
+			return -1;
+		}
+	}
+
+
+
+	str nb = {(char*)newbuf, offset};
+	replace_body(msg, &nb);
+
+	return 1;
+}
+
+
+static int mod_init(void)
+{
+	return 0;
+}
+
+
+static void mod_destroy(void)
+{
+}

+ 149 - 0
modules/sipt/ss7.h

@@ -0,0 +1,149 @@
+/*
+ *
+ * Copyright (C) 2013 Voxbone SA
+ * 
+ * Parsing code derrived from libss7 Copyright (C) Digium
+ *
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ */
+
+
+/* ISUP messages */
+#define ISUP_IAM	0x01
+#define ISUP_SAM	0x02
+#define ISUP_INR	0x03
+#define ISUP_INF	0x04
+#define ISUP_COT	0x05
+#define ISUP_ACM	0x06
+#define ISUP_CON	0x07
+#define ISUP_FOT	0x08
+#define ISUP_ANM	0x09
+#define ISUP_REL	0x0c
+#define ISUP_SUS	0x0d
+#define ISUP_RES	0x0e
+#define ISUP_RLC	0x10
+#define ISUP_CCR	0x11
+#define ISUP_RSC	0x12
+#define ISUP_BLO	0x13
+#define ISUP_UBL	0x14
+#define ISUP_BLA	0x15
+#define ISUP_UBA	0x16
+#define ISUP_GRS	0x17
+#define ISUP_CGB	0x18
+#define ISUP_CGU	0x19
+#define ISUP_CGBA	0x1a
+#define ISUP_CGUA	0x1b
+#define ISUP_CMR	0x1c
+#define ISUP_CMC	0x1d
+#define ISUP_CMRJ	0x1e
+#define ISUP_FAR	0x1f
+#define ISUP_FAA	0x20
+#define ISUP_FRJ	0x21
+#define ISUP_FAD	0x22
+#define ISUP_FAI	0x23
+#define ISUP_LPA	0x24
+#define ISUP_CSVR	0x25
+#define ISUP_CSVS	0x26
+#define ISUP_DRS	0x27
+#define ISUP_PAM	0x28
+#define ISUP_GRA	0x29
+#define ISUP_CQM	0x2a
+#define ISUP_CQR	0x2b
+#define ISUP_CPG	0x2c
+#define ISUP_USR	0x2d
+#define ISUP_UCIC	0x2e
+#define ISUP_CFN	0x2f
+#define ISUP_OLM	0x30
+#define ISUP_CRG	0x31
+#define ISUP_FAC	0x33
+#define ISUP_CRA	0xe9
+#define ISUP_CRM	0xea
+#define ISUP_CVR	0xeb
+#define ISUP_CVT	0xec
+#define ISUP_EXM	0xed
+
+/* ISUP Parameters */
+#define ISUP_PARM_NATURE_OF_CONNECTION_IND 0x06
+#define ISUP_PARM_FORWARD_CALL_IND 0x07
+#define ISUP_PARM_CALLING_PARTY_CAT 0x09
+#define ISUP_PARM_USER_SERVICE_INFO 0x1d
+#define ISUP_PARM_TRANSMISSION_MEDIUM_REQS 0x02
+#define ISUP_PARM_CALLED_PARTY_NUM 0x04
+#define ISUP_PARM_ACCESS_TRANS 0x03
+#define ISUP_PARM_BUSINESS_GRP 0xc6
+#define ISUP_PARM_CALL_REF 0x01
+#define ISUP_PARM_CALLING_PARTY_NUM 0x0a
+#define ISUP_PARM_CARRIER_ID 0xc5
+#define ISUP_PARM_SELECTION_INFO 0xee
+#define ISUP_PARM_CHARGE_NUMBER 0xeb
+#define ISUP_PARM_CIRCUIT_ASSIGNMENT_MAP 0x25
+#define ISUP_PARM_OPT_BACKWARD_CALL_IND 0x29
+#define ISUP_PARM_CONNECTION_REQ 0x0d
+#define ISUP_PARM_CONTINUITY_IND 0x10
+#define ISUP_PARM_CUG_INTERLOCK_CODE 0x1a
+#define ISUP_PARM_EGRESS_SERV 0xc3
+#define ISUP_PARM_GENERIC_ADDR 0xc0
+#define ISUP_PARM_GENERIC_DIGITS 0xc1
+#define ISUP_PARM_GENERIC_NAME 0xc7
+#define ISUP_PARM_GENERIC_NOTIFICATION_IND 0x2c
+#define ISUP_PARM_BACKWARD_CALL_IND 0x11
+#define ISUP_PARM_CAUSE 0x12
+#define ISUP_PARM_CIRCUIT_GROUP_SUPERVISION_IND 0x15
+#define ISUP_PARM_RANGE_AND_STATUS 0x16
+#define ISUP_PARM_PROPAGATION_DELAY 0x31
+#define ISUP_PARM_EVENT_INFO 0x24
+#define ISUP_PARM_HOP_COUNTER 0x3d
+#define ISUP_PARM_OPT_FORWARD_CALL_INDICATOR 0x08
+#define ISUP_PARM_LOCATION_NUMBER 0x3f
+#define ISUP_PARM_ORIG_LINE_INFO 0xea
+#define ISUP_PARM_REDIRECTION_NUMBER 0x0c
+#define ISUP_PARM_REDIRECTION_INFO 0x13
+#define ISUP_PARM_ORIGINAL_CALLED_NUM 0x28
+#define ISUP_PARM_JIP 0xc4
+#define ISUP_PARM_ECHO_CONTROL_INFO 0x37
+#define ISUP_PARM_PARAMETER_COMPAT_INFO 0x39
+#define ISUP_PARM_CIRCUIT_STATE_IND 0x26
+#define ISUP_PARM_TRANSIT_NETWORK_SELECTION 0x23
+#define ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION 0xe4
+#define ISUP_PARM_FACILITY_IND 0x18
+#define ISUP_PARM_REDIRECTING_NUMBER 0x0b 
+#define ISUP_PARM_ACCESS_DELIVERY_INFO 0x2e
+#define ISUP_PARM_REDIRECT_COUNTER 0x77
+#define ISUP_PARM_SUSRES_IND 0x22
+#define ISUP_PARM_INF_IND 0x0f
+#define ISUP_PARM_INR_IND 0x0e
+#define ISUP_PARM_SUBSEQUENT_NUMBER 0x05
+#define ISUP_CONNECTED_NUMBER 0x21
+#define ISUP_PARM_DIVERSION_INFORMATION 0x36
+#define ISUP_PARM_UUI 0x20
+
+#define bool unsigned char
+
+
+/* ISUP Parameter Pseudo-type */
+struct isup_parm_opt {
+	unsigned char type;
+	unsigned char len;
+	unsigned char data[0];
+};
+
+int isup_get_hop_counter(unsigned char *buf, int len);
+int isup_update_destination(char * dest, int hops, int nai, unsigned char *buf, int len, unsigned char * obuf, int olen);
+

+ 302 - 0
modules/sipt/ss7_parser.c

@@ -0,0 +1,302 @@
+/*
+ *
+ * Copyright (C) 2013 Voxbone SA
+ * 
+ * Parsing code derrived from libss7 Copyright (C) Digium
+ *
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ */
+
+#include "ss7.h"
+#include <string.h>
+
+static char char2digit(char localchar)
+{
+	switch (localchar) {
+		case '0':
+			return 0;
+		case '1':
+			return 1;
+		case '2':
+			return 2;
+		case '3':
+			return 3;
+		case '4':
+			return 4;
+		case '5':
+			return 5;
+		case '6':
+			return 6;
+		case '7':
+			return 7;
+		case '8':
+			return 8;
+		case '9':
+			return 9;
+		case 'A':
+			return 0xa;
+		case 'B':
+			return 0xb;
+		case 'C':
+			return 0xc;
+		case 'D':
+			return 0xd;
+		case '*':
+			return 0xe;
+		case '#':
+		case 'F':
+			return 0xf;
+		default:
+			return 0;
+	}
+}
+
+static void isup_put_number(unsigned char *dest, char *src, int *len, int *oddeven)
+{
+	int i = 0;
+	int numlen = strlen(src);
+
+	if (numlen % 2) {
+		*oddeven = 1;
+		*len = numlen/2 + 1;
+	} else {
+		*oddeven = 0;
+		*len = numlen/2;
+	}
+
+	while (i < numlen) {
+		if (!(i % 2))
+			dest[i/2] |= char2digit(src[i]) & 0xf;
+		else
+		{
+			dest[i/2] |= (char2digit(src[i]) << 4) & 0xf0;
+		}
+		i++;
+	}
+}
+
+static int encode_called_party(char * number, unsigned char * flags, int nai, unsigned char * buf, int len)
+{
+	int numlen, oddeven;
+	buf[0] = flags[0]&0x7F;
+	buf[1] = flags[1];
+
+	isup_put_number(&buf[2], number, &numlen, &oddeven);
+
+	if(oddeven)
+	{
+		buf[0] |= 0x80;
+	}
+	
+	if(nai)
+	{
+		buf[0] &= 0x80;
+		buf[0] = (unsigned char)(nai&0x7F);
+	}
+
+	return numlen + 2;
+}
+
+// returns start of specified optional header of IAM, otherwise return -1
+static int get_optional_header(unsigned char header, unsigned char *buf, int len)
+{
+	int offset = 0;
+	int res;
+	char optparams;
+
+	// not an iam? do nothing
+	if(buf[0] != ISUP_IAM)
+	{
+		return -1;
+	}
+
+	/* Copy the fixed parms */
+	len -= 6;
+	offset += 6;
+
+	if (len < 1)
+		return -1;
+
+	/* IAM has one Fixed variable param, Called party number */
+
+	// pointer to fixed part (2)
+	offset++;
+	len--;
+
+
+	//pointer to optional part
+	optparams = buf[offset];
+	offset++;
+	len--;
+
+
+	// 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 (optparams) {
+		while ((len > 0) && (buf[offset] != 0)) {
+			struct isup_parm_opt *optparm = (struct isup_parm_opt *)(buf + offset);
+
+			res = optparm->len+2;
+			if(optparm->type == header)
+			{
+				return offset;
+			}
+
+			len -= res;
+			offset += res;
+		}
+	}
+	return -1;
+}
+
+int isup_get_hop_counter(unsigned char *buf, int len)
+{
+	int  offset = get_optional_header(ISUP_PARM_HOP_COUNTER, buf, len);
+
+	if(offset != -1 && len-offset-2 > 0)
+	{
+		return buf[offset+2] & 0x1F;
+	}
+	return -1;
+}
+
+
+
+int isup_update_destination(char * dest, int hops, int nai, unsigned char *buf, int len, unsigned char * obuf, int olen)
+{
+	int offset = 0, offset2 = 0;
+	int res;
+	char optparams;
+	unsigned char *param_pointer = NULL;
+
+
+	// not an iam? do nothing
+	if(buf[0] != ISUP_IAM)
+	{
+		int l = len > olen ? olen : len;
+		memcpy((void*)obuf, (void *)(buf), l);
+		return l;
+	}
+
+	memset(obuf, 0, olen);
+
+	// bounds checking
+	if(hops > 31)
+	{
+		hops = 31;
+	}
+
+
+
+	/* Copy the fixed parms */
+	memcpy((void*)obuf, (void *)(buf), 6);
+	len -= 6;
+	olen -= 6;
+	offset += 6;
+	offset2 += 6;
+
+	if (len < 1)
+		return -1;
+
+	/* IAM has one Fixed variable param, Called party number, we need to modify this */
+
+	// pointer to fixed part (2)
+	obuf[offset2++]=buf[offset++];
+
+
+	//pointer to optional part (to update later)
+	param_pointer = (obuf+offset2);
+	optparams = buf[offset];
+	offset2++;
+	offset++;
+	len--;
+	olen--;
+
+
+	// add the new mandatory fixed header
+	res = encode_called_party(dest, buf+offset+1, nai, obuf+offset2+1, olen-1);
+	obuf[offset2] = (char)res;
+
+	offset2 += res+1;
+	olen -= res+1;
+	
+	res = buf[offset];
+	offset += res+1;
+	len -= res+1;
+
+
+	
+	if (len < 1 )
+		return -1;
+
+
+	
+	// set the pointer to the optional part
+	param_pointer[0] = (char)((obuf+offset2) - param_pointer);
+
+	/* Optional paramter parsing code */
+	if (optparams) {
+
+		bool has_hops = 0;
+		
+		while ((len > 0) && (buf[offset] != 0)) {
+			struct isup_parm_opt *optparm = (struct isup_parm_opt *)(buf + offset);
+
+
+			res = optparm->len+2;
+			switch(optparm->type)
+			{
+				case ISUP_PARM_HOP_COUNTER:
+					obuf[offset2++] = ISUP_PARM_HOP_COUNTER;
+					obuf[offset2++] = 1;
+					obuf[offset2++] = ((optparm->data[0]&0x1F)-1)&0x1F;
+					has_hops = 1;
+					break;
+				default:
+					memcpy((void*)(obuf+offset2), (void *)(buf + offset), res);
+					offset2 += res;
+			}
+
+			len -= res;
+			offset += res;
+		}
+
+		// add missing headers
+		if(!has_hops)
+		{
+			obuf[offset2++] = ISUP_PARM_HOP_COUNTER;
+			obuf[offset2++] = 1;
+			obuf[offset2++] = hops & 0x1F;
+			has_hops = 1;
+		}
+
+		// nicely null terminate it
+		obuf[offset2++] = 0;
+	}
+
+	return offset2;
+}