소스 검색

ss7ops: Introduce the beginning of a ss7ops module

This can be used with sipcapture and begings with M2UA and ISUP
support. More SIGTRAN (M3UA, SUA) support is planned and maybe
TCAP/MAP in the future.

The ISUP message format depends on the specific message so I have
exported a Smalltalk ITU ISUP model to C to avoid manual errors.
Holger Hans Peter Freyther 9 년 전
부모
커밋
0ec6eef89d

+ 19 - 0
modules/ss7ops/Makefile

@@ -0,0 +1,19 @@
+#
+# ss7ops module makefile
+#
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=ss7ops.so
+LIBS=
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
+include ../../Makefile.modules

+ 73 - 0
modules/ss7ops/README

@@ -0,0 +1,73 @@
+SS7 Ops Module
+
+Holger Freyther
+
+   <[email protected]>
+
+Edited by
+
+Holger Freyther
+
+   <[email protected]>
+
+   Copyright © 2016 Strong Leaf Consultant Ltd.
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. External Libraries or Applications
+        3. Functions
+
+              3.1. isup (integer)
+
+        4. Parameters
+
+              4.1. isup_to_json (integer)
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. External Libraries or Applications
+   3. Functions
+
+        3.1. isup (integer)
+
+   4. Parameters
+
+        4.1. isup_to_json (integer)
+
+1. Overview
+
+   The ss7ops module can currently handle M2UA/MTP-L3/ISUP and convert it
+   to JSON. In the future this might gain support for more SIGTRAN
+   adoptions and ITU TCAP/GSM MAP.
+
+2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None.
+
+3. Functions
+
+   3.1. isup (integer)
+
+3.1. isup (integer)
+
+   If set to 1, return the JSON representation as string for the last
+   message that was parsed.
+
+4. Parameters
+
+   4.1. isup_to_json (integer)
+
+4.1. isup_to_json (integer)
+
+   Pass the HEP type as parameter (e.g. 8 for M2UA) and the contained ISUP
+   payload will be converted to a JSON string. It can be consumed using
+   the $isup(1) parameter.

+ 4 - 0
modules/ss7ops/doc/Makefile

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

+ 37 - 0
modules/ss7ops/doc/ss7ops.xml

@@ -0,0 +1,37 @@
+<?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>SS7 Ops Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Holger</firstname>
+		<surname>Freyther</surname>
+		<email>[email protected]</email>
+	    </author>
+	    <editor>
+		<firstname>Holger</firstname>
+		<surname>Freyther</surname>
+		<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2016</year>
+	    <holder>Strong Leaf Consultant Ltd.</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+
+    <xi:include href="ss7ops_admin.xml"/>
+
+
+</book>

+ 59 - 0
modules/ss7ops/doc/ss7ops_admin.xml

@@ -0,0 +1,59 @@
+<?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;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+
+	<title>&adminguide;</title>
+
+	<section>
+	<title>Overview</title>
+	<para>
+		The ss7ops module can currently handle M2UA/MTP-L3/ISUP and
+		convert it to JSON. In the future this might gain support for
+		more SIGTRAN adoptions and ITU TCAP/GSM MAP.
+	</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>None</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+	<title>Functions</title>
+	<section>
+		<title><varname>isup</varname> (integer)</title>
+		<para>
+		If set to 1, return the JSON representation as string for the last
+		message that was parsed.
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Parameters</title>
+	<section>
+		<title><varname>isup_to_json</varname> (integer)</title>
+		<para>
+		Pass the HEP type as parameter (e.g. 8 for M2UA) and the contained
+		ISUP payload will be converted to a JSON string. It can be consumed
+		using the $isup(1) parameter.
+		</para>
+	</section>
+	</section>
+</chapter>

+ 467 - 0
modules/ss7ops/isup_generated.c

@@ -0,0 +1,467 @@
+/* Generated from ISUP-C-ParserGenerator. Do not modify */
+#include "isup_generated.h"
+
+static const struct isup_ie_fixed acm_fixed[] = {
+	{
+		.name = "ISUPBackwardCallIndicators",
+		.type = ISUPBackwardCallIndicators,
+		.len = 2,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed cgb_fixed[] = {
+	{
+		.name = "ISUPCircuitGroupSupervisionMessageType",
+		.type = ISUPCircuitGroupSupervisionMessageType,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed cgba_fixed[] = {
+	{
+		.name = "ISUPCircuitGroupSupervisionMessageType",
+		.type = ISUPCircuitGroupSupervisionMessageType,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed cgu_fixed[] = {
+	{
+		.name = "ISUPCircuitGroupSupervisionMessageType",
+		.type = ISUPCircuitGroupSupervisionMessageType,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed cgua_fixed[] = {
+	{
+		.name = "ISUPCircuitGroupSupervisionMessageType",
+		.type = ISUPCircuitGroupSupervisionMessageType,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed con_fixed[] = {
+	{
+		.name = "ISUPBackwardCallIndicators",
+		.type = ISUPBackwardCallIndicators,
+		.len = 2,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed cot_fixed[] = {
+	{
+		.name = "ISUPContinuityIndicators",
+		.type = ISUPContinuityIndicators,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed cpg_fixed[] = {
+	{
+		.name = "ISUPEventInformation",
+		.type = ISUPEventInformation,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed faa_fixed[] = {
+	{
+		.name = "ISUPFacilityIndicator",
+		.type = ISUPFacilityIndicator,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed far_fixed[] = {
+	{
+		.name = "ISUPFacilityIndicator",
+		.type = ISUPFacilityIndicator,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed frj_fixed[] = {
+	{
+		.name = "ISUPFacilityIndicator",
+		.type = ISUPFacilityIndicator,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed iam_fixed[] = {
+	{
+		.name = "ISUPNatureOfConnectionIndicators",
+		.type = ISUPNatureOfConnectionIndicators,
+		.len = 1,
+	},
+	{
+		.name = "ISUPForwardCallIndicators",
+		.type = ISUPForwardCallIndicators,
+		.len = 2,
+	},
+	{
+		.name = "ISUPCallingPartysCategory",
+		.type = ISUPCallingPartysCategory,
+		.len = 1,
+	},
+	{
+		.name = "ISUPTransmissionMediumRequirement",
+		.type = ISUPTransmissionMediumRequirement,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed inf_fixed[] = {
+	{
+		.name = "ISUPInformationIndicators",
+		.type = ISUPInformationIndicators,
+		.len = 2,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed inr_fixed[] = {
+	{
+		.name = "ISUPInformationRequestIndicators",
+		.type = ISUPInformationRequestIndicators,
+		.len = 2,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed res_fixed[] = {
+	{
+		.name = "ISUPSuspendResumeIndicators",
+		.type = ISUPSuspendResumeIndicators,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_fixed sus_fixed[] = {
+	{
+		.name = "ISUPSuspendResumeIndicators",
+		.type = ISUPSuspendResumeIndicators,
+		.len = 1,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable cfn_variable[] = {
+	{
+		.name = "ISUPCauseIndicators",
+		.type = ISUPCauseIndicators,
+		.min_len = 2,
+		.max_len = UINT8_MAX,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable cgb_variable[] = {
+	{
+		.name = "ISUPRangeAndStatus",
+		.type = ISUPRangeAndStatus,
+		.min_len = 2,
+		.max_len = 33,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable cgba_variable[] = {
+	{
+		.name = "ISUPRangeAndStatus",
+		.type = ISUPRangeAndStatus,
+		.min_len = 2,
+		.max_len = 33,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable cgu_variable[] = {
+	{
+		.name = "ISUPRangeAndStatus",
+		.type = ISUPRangeAndStatus,
+		.min_len = 2,
+		.max_len = 33,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable cgua_variable[] = {
+	{
+		.name = "ISUPRangeAndStatus",
+		.type = ISUPRangeAndStatus,
+		.min_len = 2,
+		.max_len = 33,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable cqr_variable[] = {
+	{
+		.name = "ISUPRange",
+		.type = ISUPRange,
+		.min_len = 1,
+		.max_len = UINT8_MAX,
+	},
+	{
+		.name = "ISUPCircuitStateIndicator",
+		.type = ISUPCircuitStateIndicator,
+		.min_len = 1,
+		.max_len = 32,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable frj_variable[] = {
+	{
+		.name = "ISUPCauseIndicators",
+		.type = ISUPCauseIndicators,
+		.min_len = 2,
+		.max_len = UINT8_MAX,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable grs_variable[] = {
+	{
+		.name = "ISUPRange",
+		.type = ISUPRange,
+		.min_len = 1,
+		.max_len = UINT8_MAX,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable gra_variable[] = {
+	{
+		.name = "ISUPRange",
+		.type = ISUPRange,
+		.min_len = 1,
+		.max_len = UINT8_MAX,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable iam_variable[] = {
+	{
+		.name = "ISUPCalledPartyNumber",
+		.type = ISUPCalledPartyNumber,
+		.min_len = 3,
+		.max_len = UINT8_MAX,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable rel_variable[] = {
+	{
+		.name = "ISUPCauseIndicators",
+		.type = ISUPCauseIndicators,
+		.min_len = 2,
+		.max_len = UINT8_MAX,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable sam_variable[] = {
+	{
+		.name = "ISUPSubsequentNumber",
+		.type = ISUPSubsequentNumber,
+		.min_len = 2,
+		.max_len = UINT8_MAX,
+	},
+	{ 0, },
+};
+static const struct isup_ie_variable usr_variable[] = {
+	{
+		.name = "ISUPUserToUserInformation",
+		.type = ISUPUserToUserInformation,
+		.min_len = 1,
+		.max_len = 129,
+	},
+	{ 0, },
+};
+const struct isup_msg isup_msgs[256] = {
+	[1] = {
+		.name = "IAM",
+		.fixed_ies = iam_fixed,
+		.variable_ies = iam_variable,
+		.has_optional = 1,
+	},
+	[2] = {
+		.name = "SAM",
+		.variable_ies = sam_variable,
+		.has_optional = 1,
+	},
+	[3] = {
+		.name = "INR",
+		.fixed_ies = inr_fixed,
+		.has_optional = 1,
+	},
+	[4] = {
+		.name = "INF",
+		.fixed_ies = inf_fixed,
+		.has_optional = 1,
+	},
+	[5] = {
+		.name = "COT",
+		.fixed_ies = cot_fixed,
+	},
+	[6] = {
+		.name = "ACM",
+		.fixed_ies = acm_fixed,
+		.has_optional = 1,
+	},
+	[7] = {
+		.name = "CON",
+		.fixed_ies = con_fixed,
+		.has_optional = 1,
+	},
+	[8] = {
+		.name = "FOT",
+		.has_optional = 1,
+	},
+	[9] = {
+		.name = "AMN",
+		.has_optional = 1,
+	},
+	[12] = {
+		.name = "REL",
+		.variable_ies = rel_variable,
+		.has_optional = 1,
+	},
+	[13] = {
+		.name = "SUS",
+		.fixed_ies = sus_fixed,
+		.has_optional = 1,
+	},
+	[14] = {
+		.name = "RES",
+		.fixed_ies = res_fixed,
+		.has_optional = 1,
+	},
+	[16] = {
+		.name = "RLC",
+		.has_optional = 1,
+	},
+	[17] = {
+		.name = "CCR",
+	},
+	[18] = {
+		.name = "RSC",
+	},
+	[19] = {
+		.name = "BLO",
+	},
+	[20] = {
+		.name = "UBL",
+	},
+	[21] = {
+		.name = "BLA",
+	},
+	[22] = {
+		.name = "UBA",
+	},
+	[23] = {
+		.name = "GRS",
+		.variable_ies = grs_variable,
+	},
+	[24] = {
+		.name = "CGB",
+		.fixed_ies = cgb_fixed,
+		.variable_ies = cgb_variable,
+	},
+	[25] = {
+		.name = "CGU",
+		.fixed_ies = cgu_fixed,
+		.variable_ies = cgu_variable,
+	},
+	[26] = {
+		.name = "CGBA",
+		.fixed_ies = cgba_fixed,
+		.variable_ies = cgba_variable,
+	},
+	[27] = {
+		.name = "CGUA",
+		.fixed_ies = cgua_fixed,
+		.variable_ies = cgua_variable,
+	},
+	[31] = {
+		.name = "FAR",
+		.fixed_ies = far_fixed,
+		.has_optional = 1,
+	},
+	[32] = {
+		.name = "FAA",
+		.fixed_ies = faa_fixed,
+		.has_optional = 1,
+	},
+	[33] = {
+		.name = "FRJ",
+		.fixed_ies = frj_fixed,
+		.variable_ies = frj_variable,
+		.has_optional = 1,
+	},
+	[36] = {
+		.name = "LPA",
+	},
+	[41] = {
+		.name = "GRA",
+		.variable_ies = gra_variable,
+	},
+	[43] = {
+		.name = "CQR",
+		.variable_ies = cqr_variable,
+	},
+	[44] = {
+		.name = "CPG",
+		.fixed_ies = cpg_fixed,
+		.has_optional = 1,
+	},
+	[45] = {
+		.name = "USR",
+		.variable_ies = usr_variable,
+		.has_optional = 1,
+	},
+	[46] = {
+		.name = "UCIC",
+	},
+	[47] = {
+		.name = "CFN",
+		.variable_ies = cfn_variable,
+		.has_optional = 1,
+	},
+	[48] = {
+		.name = "OLM",
+	},
+	[50] = {
+		.name = "NRM",
+		.has_optional = 1,
+	},
+	[51] = {
+		.name = "FAC",
+		.has_optional = 1,
+	},
+	[52] = {
+		.name = "UPT",
+		.has_optional = 1,
+	},
+	[52] = {
+		.name = "UPA",
+		.has_optional = 1,
+	},
+	[54] = {
+		.name = "IDR",
+		.has_optional = 1,
+	},
+	[55] = {
+		.name = "IDS",
+		.has_optional = 1,
+	},
+	[56] = {
+		.name = "SEG",
+		.has_optional = 1,
+	},
+	[64] = {
+		.name = "LPR",
+		.has_optional = 1,
+	},
+	[65] = {
+		.name = "APT",
+		.has_optional = 1,
+	},
+	[66] = {
+		.name = "PRI",
+		.has_optional = 1,
+	},
+	[67] = {
+		.name = "SAN",
+		.has_optional = 1,
+	},
+};

+ 130 - 0
modules/ss7ops/isup_generated.h

@@ -0,0 +1,130 @@
+/* Generated from ISUP-C-ParserGenerator. Do not modify */
+#pragma once
+
+#include <stdint.h>
+#define ISUPEndOfOptionalParameters 0 /* End of optional parameters spec: 3.20*/
+#define ISUPCallReference 1 /* Call reference spec: 3.8*/
+#define ISUPTransmissionMediumRequirement 2 /* Transmission medium requirement spec: 3.54*/
+#define ISUPAccessTransport 3 /* Access transport spec: 3.3*/
+#define ISUPCalledPartyNumber 4 /* Called party number spec: 3.9*/
+#define ISUPSubsequentNumber 5 /* Subsequent number spec: 3.51*/
+#define ISUPNatureOfConnectionIndicators 6 /* Nature of connection indicators spec: 3.35*/
+#define ISUPForwardCallIndicators 7 /* Forward call indicators spec: 3.23*/
+#define ISUPOptionalForwardCallIndicators 8 /* Optional forward call indicators spec: 3.38*/
+#define ISUPCallingPartysCategory 9 /* Calling party's category spec: 3.11*/
+#define ISUPCallingPartyNumber 10 /* Calling party number spec: 3.10*/
+#define ISUPRedirectingNumber 11 /* Redirecting number spec: 3.44*/
+#define ISUPRedirectionNumber 12 /* Redirection number spec: 3.46*/
+#define ISUPConnectionRequest 13 /* Connection request spec: 3.17*/
+#define ISUPInformationRequestIndicators 14 /* Information request indicators spec: 3.29*/
+#define ISUPInformationIndicators 15 /* Information indicators spec: 3.28*/
+#define ISUPContinuityIndicators 16 /* Continuity indicators spec: 3.18*/
+#define ISUPBackwardCallIndicators 17 /* Backward call indicators spec: 3.5*/
+#define ISUPCauseIndicators 18 /* Cause indicators spec: 3.12*/
+#define ISUPRedirectionInformation 19 /* Redirection information spec: 3.45*/
+#define ISUPCircuitGroupSupervisionMessageType 21 /* Circuit group supervision message type spec: 3.13*/
+#define ISUPRange 22 /* Range spec: 3.43b*/
+#define ISUPRangeAndStatus 22 /* Range and status spec: 3.43*/
+#define ISUPFacilityIndicator 24 /* Facility indicator spec: 3.22*/
+#define ISUPClosedUserGroupInterlockCode 26 /* Closed user group interlock code spec: 3.15*/
+#define ISUPUserServiceInformation 29 /* User service information spec: 3.57*/
+#define ISUPSignallingPointCode 30 /* Signalling point code spec: 3.50*/
+#define ISUPUserToUserInformation 32 /* User-to-user information spec: 3.61*/
+#define ISUPConnectedNumber 33 /* Connected number spec: 3.16*/
+#define ISUPSuspendResumeIndicators 34 /* Suspend/resume indicators spec: 3.52*/
+#define ISUPTransitNetworkSelection 35 /* Transit network selection spec: 3.53*/
+#define ISUPEventInformation 36 /* Event information spec: 3.21*/
+#define ISUPCircuitAssignmentMap 37 /* Circuit assignment map spec: 3.69*/
+#define ISUPCircuitStateIndicator 38 /* Circuit state indicator spec: 3.14*/
+#define ISUPAutomaticCongestionLevel 39 /* Automatic congestion level spec: 3.4*/
+#define ISUPOriginalCalledNumber 40 /* Original called number spec: 3.39*/
+#define ISUPOptionalBackwardCallIndicators 41 /* Optional backward call indicators spec: 3.37*/
+#define ISUPUserToUserIndicators 42 /* User-to-user indicators spec: 3.60*/
+#define ISUPOriginationISCPointCode 43 /* Origination ISC point code spec: 3.40*/
+#define ISUPGenericNotificationIndicator 44 /* Generic notification indicator spec: 3.25*/
+#define ISUPCallHistoryInformation 45 /* Call history information spec: 3.7*/
+#define ISUPAccessDeliveryInformation 46 /* Access delivery information spec: 3.2*/
+#define ISUPNetworkSpecificFacility 47 /* Network specific facility spec: 3.36*/
+#define ISUPUserServiceInformationPrime 48 /* User service information prime spec: 3.58*/
+#define ISUPPropagationDelayCounter 49 /* Propagation delay counter spec: 3.42*/
+#define ISUPRemoteOperations 50 /* Remote operations spec: 3.48*/
+#define ISUPServiceActivation 51 /* Service activation spec: 3.49*/
+#define ISUPUserTeleserviceInformation 52 /* User teleservice information spec: 3.59*/
+#define ISUPTransmissionMediumUsed 53 /* Transmission medium used spec: 3.56*/
+#define ISUPCallDiversionInformation 54 /* Call diversion information spec: 3.6*/
+#define ISUPEchoControlInformation 55 /* Echo control information spec: 3.19*/
+#define ISUPMessageCompatibilityInformation 56 /* Message compatibility information spec: 3.33*/
+#define ISUPParameterCompatibilityInformation 57 /* Parameter compatibility information spec: 3.41*/
+#define ISUPMLPPPrecedence 58 /* MLPP precedence spec: 3.34*/
+#define ISUPMCIDRequestIndicators 59 /* MCID request indicators spec: 3.31*/
+#define ISUPMCIDResponseIndicators 60 /* MCID response indicators spec: 3.32*/
+#define ISUPHopCounter 61 /* Hop counter spec: 3.80*/
+#define ISUPTransmissionMediumRequirementPrime 62 /* Transmission medium requirement prime spec: 3.55*/
+#define ISUPLocationNumber 63 /* Location number spec: 3.30*/
+#define ISUPRedirectionNumberRestriction 64 /* Redirection number restriction spec: 3.47*/
+#define ISUPCallTransferReference 67 /* Call transfer reference spec: 3.65*/
+#define ISUPLoopPreventionIndicators 68 /* Loop prevention indicators spec: 3.67*/
+#define ISUPCallTransferNumber 69 /* Call transfer number spec: 3.64*/
+#define ISUPCCSS 75 /* CCSS spec: 3.63*/
+#define ISUPForwardGVNS 76 /* Forward GVNS spec: 3.66*/
+#define ISUPBackwardGVNS 77 /* Backward GVNS spec: 3.62*/
+#define ISUPRedirectCapability 78 /* Redirect capability spec: 3.96*/
+#define ISUPNetworkManagementControls 91 /* Network management controls spec: 3.68*/
+#define ISUPCorrelationId 101 /* Correlation id spec: 3.70*/
+#define ISUPSCFId 102 /* SCF id spec: 3.71*/
+#define ISUPCallDiversionTreatmentIndicators 110 /* Call diversion treatment indicators spec: 3.72*/
+#define ISUPCalledINNumber 111 /* Called IN number spec: 3.73*/
+#define ISUPCallOfferingTreatmentIndicators 112 /* Call offering treatment indicators spec: 3.74*/
+#define ISUPChargedPartyIdentification 113 /* Charged party identification spec: 3.75*/
+#define ISUPConferenceTreatmentIndicators 114 /* Conference treatment indicators spec: 3.76*/
+#define ISUPDisplayInformation 115 /* Display information spec: 3.77*/
+#define ISUPUIDActionIndicators 116 /* UID action indicators spec: 3.78*/
+#define ISUPUIDCapabilityIndicators 117 /* UID capability indicators spec: 3.79*/
+#define ISUPRedirectCounter 119 /* Redirect counter spec: 3.97*/
+#define ISUPApplicationTransportParameter 120 /* Application transport parameter spec: 3.82*/
+#define ISUPCollectCallRequest 121 /* Collect call request spec: 3.81*/
+#define ISUPCCNRPossibleIndicator 122 /* CCNR possible indicator spec: 3.83*/
+#define ISUPPivotCapability 123 /* Pivot capability spec: 3.84*/
+#define ISUPPivotRoutingIndicators 124 /* Pivot routing indicators spec: 3.85*/
+#define ISUPCalledDirectoryNumber 125 /* Called directory number spec: 3.86*/
+#define ISUPOriginalCalledINNumber 127 /* Original called IN number spec: 3.87*/
+#define ISUPCallingGeodeticLocation 129 /* Calling geodetic location spec: 3.88*/
+#define ISUPGenericReference 130 /* Generic reference spec: 3.27*/
+#define ISUPHTRInformation 130 /* HTR information spec: 3.89*/
+#define ISUPNetworkRoutingNumber 132 /* Network routing number spec: 3.90*/
+#define ISUPQoRCapability 133 /* QoR capability spec: 3.91*/
+#define ISUPPivotStatus 134 /* Pivot status spec: 3.92*/
+#define ISUPPivotCounter 135 /* Pivot counter spec: 3.93*/
+#define ISUPPivotRoutingForwardInformation 136 /* Pivot routing forward information spec: 3.94*/
+#define ISUPPivotRoutingBackwardInformation 137 /* Pivot routing backward information spec: 3.95*/
+#define ISUPRedirectStatus 138 /* Redirect status spec: 3.98*/
+#define ISUPRedirectForwardInformation 139 /* Redirect forward information spec: 3.99*/
+#define ISUPRedirectBackwardInformation 140 /* Redirect backward information spec: 3.100*/
+#define ISUPNumberPortabilityForwardInformation 141 /* Number portability forward information spec: 3.101*/
+#define ISUPGenericNumber 192 /* Generic number spec: 3.26*/
+#define ISUPGenericDigits 193 /* Generic digits spec: 3.24*/
+struct isup_ie_fixed {
+	const char *name;
+	uint8_t type;
+	uint8_t len;
+};
+struct isup_ie_variable {
+	const char *name;
+	uint8_t type;
+	uint8_t min_len;
+	uint8_t max_len;
+};
+struct isup_ie_optional {
+	const char *name;
+	uint8_t type;
+	uint8_t min_len;
+	uint8_t max_len;
+};
+struct isup_msg {
+	const char      *name;
+
+	const struct isup_ie_fixed *fixed_ies;
+	const struct isup_ie_variable *variable_ies;
+	int has_optional;
+};
+extern const struct isup_msg isup_msgs[256];

+ 485 - 0
modules/ss7ops/isup_parsed.c

@@ -0,0 +1,485 @@
+/*
+ * ss7 module - ISUP parsed
+ *
+ * Copyright (C) 2016 Holger Hans Peter Freyther ([email protected])
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "isup_parsed.h"
+#include "isup_generated.h"
+
+#include "../../dprint.h"
+#include "../../endianness.h"
+
+#include <arpa/inet.h>
+
+#include <string.h>
+
+typedef void (*visit)(uint8_t type, const uint8_t *data, uint8_t len, struct isup_state *ptrs);
+
+struct key_val {
+	uint8_t		key;
+	const char	*value;
+};
+
+static const struct key_val itu_cause_class[] = {
+	{ 0x00, "normal event" },
+	{ 0x01, "normal event" },
+	{ 0x02, "resource unavailable" },
+	{ 0x03, "service or option not available" },
+	{ 0x04, "service or option not implemented" },
+	{ 0x05, "invalid message" },
+	{ 0x06, "protocol error" },
+	{ 0x07, "interworking"} ,
+	{ 0, },
+};
+
+static const struct key_val cause_value[] = {
+	{ 1,	"Unallocated (unassigned) number" },
+	{ 2,	"No route to specified transit network" },
+	{ 3,	"No route to destination" },
+	{ 4,	"Send special information tone" },
+	{ 5,	"Misdialled trunk prefix" },
+	{ 6,	"Channel unacceptable" },
+	{ 7,	"Call awarded and being delivered in an established channel" },
+	{ 8,	"Preemption" },
+	{ 9,	"Preemption - circuit reserved for reuse" },
+	{ 14,	"QoR: ported number" }, /* Add.1 */
+	{ 16,	"Normal call clearing" },
+	{ 17,	"User busy" },
+	{ 18,	"No user responding" },
+	{ 19,	"No answer from user (user alerted)" },
+	{ 20,	"Subscriber absent" },
+	{ 21,	"Call rejected" },
+	{ 22,	"Number changed" },
+	{ 23,	"Redirection to new destination" },
+	{ 24,	"Call rejected due to failure at the destination" }, /* Amd.1 */
+	{ 25,	"Exchange routing error" },
+	{ 26,	"Non-selected user clearing" },
+	{ 27,	"Destination out of order" },
+	{ 28,	"Invalid number format (address incomplete)" },
+	{ 29,	"Facility rejected" },
+	{ 30,	"Response to STATUS ENQUIRY" },
+	{ 31,	"Normal, unspecified" },
+	{ 34,	"No circuit/channel available" },
+	{ 38,	"Network out of order" },
+	{ 39,	"Permanent frame mode connection out of service" },
+	{ 40,	"Permanent frame mode connection operational" },
+	{ 41,	"Temporary failure" },
+	{ 42,	"Switching equipment congestion" },
+	{ 43,	"Access information discarded" },
+	{ 44,	"Requested circuit/channel not available" },
+	{ 46,	"Precedence call blocked" },
+	{ 47,	"Resource unavailable, unspecified" },
+	{ 49,	"Quality of service not available" },
+	{ 50,	"Requested facility not subscribed" },
+	{ 53,	"Outgoing calls barred within CUG" },
+	{ 55,	"Incoming calls barred within CUG" },
+	{ 57,	"Bearer capability not authorized" },
+	{ 58,	"Bearer capability not presently available" },
+	{ 62,	"Inconsistency in designated outgoing access information and subscriber class" },
+	{ 63,	"Service or option not available, unspecified" },
+	{ 65,	"Bearer capability not implemented" },
+	{ 66,	"Channel type not implemented" },
+	{ 69,	"Requested facility not implemented" },
+	{ 70,	"Only restricted digital information bearer capability is available" },
+	{ 79,	"Service or option not implemented, unspecified" },
+	{ 81,	"Invalid call reference value" },
+	{ 82,	"Identified channel does not exist" },
+	{ 83,	"A suspended call exists, but this call identity does not" },
+	{ 84,	"Call identity in use" },
+	{ 85,	"No call suspended" },
+	{ 86,	"Call having the requested call identity has been cleared" },
+	{ 87,	"User not member of CUG" },
+	{ 88,	"Incompatible destination" },
+	{ 90,	"Non-existent CUG" },
+	{ 91,	"Invalid transit network selection" },
+	{ 95,	"Invalid message, unspecified" },
+	{ 96,	"Mandatory information element is missing" },
+	{ 97,	"Message type non-existent or not implemented" },
+	{ 98,	"Message not compatible with call state or message type non-existent or not implemented" },
+	{ 99,	"Information element /parameter non-existent or not implemented" },
+	{ 100,	"Invalid information element contents" },
+	{ 101,	"Message not compatible with call state" },
+	{ 102,	"Recovery on timer expiry" },
+	{ 103,	"Parameter non-existent or not implemented, passed on" },
+	{ 110,	"Message with unrecognized parameter, discarded" },
+	{ 111,	"Protocol error, unspecified" },
+	{ 127,	"Interworking, unspecified" },
+	{ 0, },
+};
+
+static const struct key_val cause_std[] = {
+	{ 0x00, "ITU-T" },
+	{ 0x01, "ISO/IEC" },
+	{ 0x02, "National" },
+	{ 0x03, "Specific" },
+	{ 0, },
+};
+
+static const struct key_val cause_location[] = {
+	{ 0x0, "user (U)" },
+	{ 0x01, "private network serving the local user (LPN)" },
+	{ 0x02, "public network serving the local user (LN)" },
+	{ 0x03, "transit network (TN)" },
+	{ 0x04, "public network serving the remote user (RLN)" },
+	{ 0x05, "private network serving the remote user (RPN)" },
+	{ 0x07, "international network (INTL)" },
+	{ 0x0A, "network beyond interworking point (BI)" },
+	{ 0, },
+};
+
+static const struct key_val event_info[] = {
+	{ 0x01, "ALERTING" },
+	{ 0x02, "PROGRESS" },
+	{ 0x03, "in-band" },
+	{ 0x04, "call forwarded on busy" },
+	{ 0x05, "call forwarded on no reply" },
+	{ 0x06, "call forwarded unconditional" },
+	{ 0, },
+};
+
+static const char *lookup(const struct key_val *table, const uint8_t val, const char *deflt)
+{
+	while (1) {
+		if (!table->value)
+			return deflt;
+		if (table->key == val)
+			return table->value;
+		table += 1;
+	}
+}
+
+static inline char from_bcd(const uint8_t item) {
+	if (item >= 0x0A)
+		return 'A' + (item - 0x0A);
+	return '0' + item;
+}
+
+static inline void decode_bcd(char *dest, const uint8_t *data, size_t len, int odd)
+{
+	int i;
+
+	for (i = 0; i < len; ++i) {
+		uint8_t lo = data[i] & 0x0F;
+		uint8_t hi = (data[i] & 0xF0) >> 4;
+
+		if (lo != 0x0F)
+			*dest++ = from_bcd(lo);
+
+		/* ignore the last digit */
+		if (i + 1 == len && odd)
+			break;
+		if (hi != 0x0F)
+			*dest++ = from_bcd(hi);
+	}
+	*dest = '\0';
+}
+
+static void append_e164(srjson_doc_t *doc, const char *name, const uint8_t *data, uint8_t len)
+{
+	char num[17] = { 0, };
+	srjson_t *obj;
+	int odd;
+
+	/* at least TON/NPI in there */
+	if (len < 2) {
+		LM_ERR("Too short %s %u\n", name, len);
+		return;
+	}
+
+	/* E.164 is limited to 15 digits so 8 octets */
+	if (len - 2 > 8) {
+		LM_ERR("Too big %s %u\n", name, len);
+		return;
+	}
+
+	obj = srjson_CreateObject(doc);
+	if (!obj) {
+		LM_ERR("Can not allocate json object for %s\n", name);
+		return;
+	}
+
+	odd = !!(data[0] & 0x80);
+	srjson_AddNumberToObject(doc, obj, "ton", data[0] & 0x7F);
+	srjson_AddNumberToObject(doc, obj, "npi", (data[1] >> 4) & 0x07);
+
+	decode_bcd(num, &data[2], len - 2, odd);
+	srjson_AddStringToObject(doc, obj, "num", num);
+
+	srjson_AddItemToObject(doc, doc->root, name, obj);
+}
+
+static void append_itu_cause(srjson_doc_t *doc, srjson_t *obj, const uint8_t cause)
+{
+	/* ignore the "extension bit" */
+	uint8_t itu_class = (cause & 0x60) >> 5;
+	srjson_AddStringToObject(doc, obj, "itu_class_name", lookup(itu_cause_class, itu_class, "Unknown"));
+	srjson_AddNumberToObject(doc, obj, "itu_class_num", itu_class);
+	srjson_AddStringToObject(doc, obj, "itu_cause_name", lookup(cause_value, cause & 0x7F, "Unknown"));
+	srjson_AddNumberToObject(doc, obj, "itu_cause_num", cause & 0x7F);
+}
+
+static void append_cause(srjson_doc_t *doc, const char *name, const uint8_t *data, uint8_t len)
+{
+	uint8_t std_loc;
+	uint8_t cause_val;
+	const char *std, *loc;
+	int is_itu = 0;
+	srjson_t *obj;
+
+	if (len < 2) {
+		LM_ERR("Not enough data for cause\n");
+		return;
+	}
+
+	obj = srjson_CreateObject(doc);
+	if (!obj) {
+		LM_ERR("Can not allocate json object for %s\n", name);
+		return;
+	}
+
+	std_loc = data[0];
+	cause_val = data[1];
+
+	is_itu = (std_loc & 0x60) == 0;
+	std = lookup(cause_std, (std_loc & 0x60) >> 5, "Unknown");
+	srjson_AddNumberToObject(doc, obj, "standard_num", ((std_loc & 0x60) >> 5));
+	srjson_AddStringToObject(doc, obj, "standard_name", std);
+
+
+	loc = lookup(cause_location, std_loc & 0x0F, "Unknown");
+	srjson_AddNumberToObject(doc, obj, "location_num", (std_loc & 0x0F));
+	srjson_AddStringToObject(doc, obj, "location_name", loc);
+
+	if (is_itu)
+		append_itu_cause(doc, obj, cause_val);
+
+	srjson_AddItemToObject(doc, doc->root, name, obj);
+}
+
+static void append_event_information(srjson_doc_t *doc, const char *name, const uint8_t *data, uint8_t len)
+{
+	const char *event_str;
+	const char *pres_str;
+	srjson_t *obj;
+
+	if (len < 1) {
+		LM_ERR("Not enough data for event information\n");
+		return;
+	}
+
+	obj = srjson_CreateObject(doc);
+	if (!obj) {
+		LM_ERR("Can not allocate json object for %s\n", name);
+		return;
+	}
+
+	event_str = lookup(event_info, data[0] & 0x7F, "spare");
+	if (data[0] & 0x80)
+		pres_str = "presentation restricted";
+	else
+		pres_str = "no indication";
+
+	srjson_AddNumberToObject(doc, obj, "event_num", data[0]);
+	srjson_AddStringToObject(doc, obj, "event_str", event_str);
+	srjson_AddStringToObject(doc, obj, "presentation_str", pres_str);
+
+	srjson_AddItemToObject(doc, doc->root, name, obj);
+}
+
+static void isup_visitor(uint8_t type, const uint8_t *data, uint8_t len, struct isup_state *ptrs)
+{
+	switch (type) {
+	case ISUPCalledPartyNumber:
+		append_e164(ptrs->json, "called_number", data, len);
+		break;
+	case ISUPCallingPartyNumber:
+		append_e164(ptrs->json, "calling_number", data, len);
+		break;
+	case ISUPCauseIndicators:
+		append_cause(ptrs->json, "cause", data, len);
+		break;
+	case ISUPEventInformation:
+		append_event_information(ptrs->json, "event", data, len);
+		break;
+	}
+}
+
+static uint16_t parse_cic(const uint8_t *data)
+{
+	uint16_t cic;
+	memcpy(&cic, &data[0], sizeof(cic));
+#ifdef __IS_LITTLE_ENDIAN
+	return cic;
+#else
+	return bswap16(cic);
+#endif
+}
+
+static int do_parse(const uint8_t *data, size_t len, visit visitor, struct isup_state *ptr)
+{
+	const struct isup_msg *msg_class;
+	const uint8_t *ptrs;
+	size_t ptrs_size;
+	size_t left;
+
+	if (len < 3) {
+		LM_ERR("ISUP message too short %zu\n", len);
+		return -1;
+	}
+
+	/* extract the basics */
+	srjson_AddNumberToObject(ptr->json, ptr->json->root, "cic", parse_cic(data));
+	srjson_AddNumberToObject(ptr->json, ptr->json->root, "msg_type", data[2]);
+
+	msg_class = &isup_msgs[data[2]];
+	if (!msg_class->name) {
+		LM_ERR("ISUP message not known %d\n", data[2]);
+		return -2;
+	}
+	srjson_AddStringToObject(ptr->json, ptr->json->root, "msg_name", msg_class->name);
+	data += 3;
+	left = len - 3;
+
+	/*
+	 * 1.) Fixed size mandatory elements!
+	 * 2.) Area with pointers to variable and optional
+	 * 3.) Variable elements pointed
+	 * 4.) Optional ones..
+	 */
+	if (msg_class->fixed_ies) {
+		const struct isup_ie_fixed *fixed = msg_class->fixed_ies;
+		while (1) {
+			if (!fixed->name)
+				break;
+
+			if (left < fixed->len) {
+				LM_ERR("ISUP fixed too short %zu vs. %un", left, fixed->len);
+				return -3;
+			}
+
+			/* handle the type */
+			visitor(fixed->type, data, fixed->len, ptr);
+
+			/* move forward */
+			data += fixed->len;
+			left -= fixed->len;
+			fixed += 1;
+		}
+	}
+
+	/* now we reached pointers to variable and optional */
+	ptrs = data;
+	ptrs_size = left;
+
+
+	/* consume variables */
+	if (msg_class->variable_ies) {
+		const struct isup_ie_variable *variable = msg_class->variable_ies;
+
+		while (1) {
+			const uint8_t *ie_data;
+			size_t ie_left;
+			uint8_t ie_len;
+
+			if (!variable->name)
+				break;
+
+			if (ptrs_size < 1) {
+				LM_ERR("ISUP no space for ptr %zu\n", ptrs_size);
+				return -1;
+			}
+
+			ie_left = ptrs_size;
+			ie_data = ptrs;
+			if (ie_left < ie_data[0]) {
+				LM_ERR("ISUP no space for len %zu vs. %u\n", ie_left, ie_data[0]);
+				return -1;
+			}
+			ie_left -= ie_data[0];
+			ie_data += ie_data[0];
+
+			ie_len = ie_data[0];
+			if (ie_left < ie_len + 1) {
+				LM_ERR("ISUP no space for data %zu vs. %u\n", ie_left, ie_len + 1);
+				return -1;
+			}
+
+			visitor(variable->type, &ie_data[1], ie_len, ptr);
+
+			/* move forward */
+			ptrs_size -= 1;
+			ptrs += 1;
+			variable += 1;
+		}
+	}
+
+	if (msg_class->has_optional) {
+		size_t opt_left = ptrs_size;
+		const uint8_t *opt_data = ptrs;
+
+		if (opt_left < 1) {
+			LM_ERR("ISUP no space for optional ptr\n");
+			return -1;
+		}
+		if (opt_left < opt_data[0]) {
+			LM_ERR("ISUP optional beyond msg %zu vs. %u\n", opt_left, opt_data[0]);
+			return -1;
+		}
+
+		opt_left -= opt_data[0];
+		opt_data += opt_data[0];
+
+		while (opt_left > 0) {
+			uint8_t ie = opt_data[0];
+			size_t len;
+			opt_data += 1;
+			opt_left -= 1;
+
+			if (ie == ISUPEndOfOptionalParameters)
+				break;
+
+			if (opt_left < 1) {
+				LM_ERR("ISUP no space for len %zu\n", opt_left);
+				return -1;
+			}
+			len = opt_data[0];
+			opt_left -= 1;
+			opt_data += 1;
+
+			if (opt_left < len) {
+				LM_ERR("ISUP no space optional data %zu vs. %zu\n", opt_left, len);
+				return -1;
+			}
+
+			visitor(ie, opt_data, len, ptr);
+
+			opt_data += len;
+			opt_left -= len;
+		}
+	}
+
+	return 0;
+}
+
+int isup_parse(const uint8_t *data, size_t len, struct isup_state *ptr)
+{
+	return do_parse(data, len, isup_visitor, ptr);
+}

+ 37 - 0
modules/ss7ops/isup_parsed.h

@@ -0,0 +1,37 @@
+/*
+ * ss7 module - ISUP parsed
+ *
+ * Copyright (C) 2016 Holger Hans Peter Freyther ([email protected])
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "../../lib/srutils/srjson.h"
+
+/**
+ * State structure
+ */
+struct isup_state {
+	srjson_doc_t*	json;
+};
+
+int isup_parse(const uint8_t *data, size_t len, struct isup_state *ptrs);

+ 348 - 0
modules/ss7ops/ss7.c

@@ -0,0 +1,348 @@
+/*
+ * ss7 module - helper module to convert SIGTRAN/ss7 to json
+ *
+ * Copyright (C) 2016 Holger Hans Peter Freyther ([email protected])
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "isup_parsed.h"
+#include "../../sr_module.h"
+#include "../../endianness.h"
+
+MODULE_VERSION
+
+/* hep defines */
+#define HEP_M2UA		0x08
+
+/* M2UA messages */
+#define M2UA_MSG	6
+#define M2UA_DATA	1
+#define M2UA_IE_DATA	0x0300
+
+/* MTPl3 */
+#define MTP_ISUP	0x05
+
+struct mtp_level_3_hdr {
+#ifdef __IS_LITTLE_ENDIAN
+	uint8_t ser_ind : 4,
+		spare : 2,
+		ni : 2;
+	uint32_t dpc : 14,
+		opc : 14,
+		sls : 4;
+#else /* ignore middle endian */
+	uint8_t ni : 2,
+		spare : 2,
+		ser_ind : 4;
+	uint32_t sls : 4,
+		opc : 14,
+		dpc : 14;
+#endif
+	uint8_t data[0];
+} __attribute__((packed));
+
+/*! \file
+ * ss7 module - helper module to convert M2UA/ISUP to JSON
+ *
+ */
+static const char *isup_last;
+
+static int w_isup_to_json(struct sip_msg* _m, char* param1, char* param2);
+static int pv_get_isup(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+static int pv_parse_isup_name(pv_spec_p sp, str *in);
+
+static cmd_export_t cmds[] = {
+	{"isup_to_json", (cmd_function)w_isup_to_json, 1, 0, 0, ANY_ROUTE},
+	{0, 0, 0, 0, 0, 0}
+};
+
+static pv_export_t mod_pvs[] = {
+        { {"isup", sizeof("isup")-1}, PVT_OTHER, pv_get_isup, 0, pv_parse_isup_name, 0, 0, 0 },
+        { {0, 0}, 0, 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 int mod_init(void)
+{
+	LM_DBG("ss7 module\n");
+	return 0;
+}
+
+static void destroy(void)
+{
+	LM_DBG("Destroying ss7 module\n");
+}
+
+struct module_exports exports = {
+	"ss7",
+	DEFAULT_DLFLAGS, /*!< dlopen flags */
+	cmds,       /*!< Exported functions */
+	params,     /*!< Exported parameters */
+	0,
+	mi_cmds,    /*!< exported MI functions */
+	mod_pvs,          /*!< exported pseudo-variables */
+	0,          /*!< extra processes */
+	mod_init,   /*!< module initialization function */
+	0,          /*!< response function */
+	destroy,    /*!< destroy function */
+	0           /*!< child initialization function */
+};
+
+static const uint8_t *extract_from_m2ua(const uint8_t *data, size_t *len)
+{
+	uint32_t data_len;
+
+	if (*len <= 8) {
+		LM_ERR("M2UA hdr too short %zu\n", *len);
+		return NULL;
+	}
+
+	/* check the header */
+	if (data[0] != 0x01) {
+		LM_ERR("M2UA unknown version number %d\n", data[0]);
+		return NULL;
+	}
+	if (data[1] != 0x00) {
+		LM_ERR("M2UA unknown reserved fields %d\n", data[1]);
+		return NULL;
+	}
+	if (data[2] != M2UA_MSG) {
+		LM_ERR("M2UA unhandled message class %d\n", data[2]);
+		return NULL;
+	}
+	if (data[3] != M2UA_DATA) {
+		LM_ERR("M2UA not data msg but %d\n", data[3]);
+		return NULL;
+	}
+
+	/* check the length */
+	memcpy(&data_len, &data[4], sizeof(data_len));
+	data_len = ntohl(data_len);
+	if (*len < data_len) {
+		LM_ERR("M2UA data can't fit %zu vs. %zu\n", *len, data_len);
+		return NULL;
+	}
+
+	/* skip the header */
+	data += 8;
+	data_len -= 8;
+	while (data_len > 4) {
+		uint16_t ie_tag, ie_len, padding;
+		memcpy(&ie_tag, &data[0], sizeof(ie_tag));
+		memcpy(&ie_len, &data[2], sizeof(ie_len));
+		ie_tag = ntohs(ie_tag);
+		ie_len = ntohs(ie_len);
+
+		if (ie_len > data_len) {
+			LM_ERR("M2UA premature end %u vs. %zu\n", ie_len, data_len);
+			return NULL;
+		}
+
+		if (ie_tag != M2UA_IE_DATA)
+			goto next;
+
+		*len = ie_len - 4;
+		return &data[4];
+
+next:
+		data += ie_len;
+		data_len -= ie_len;
+
+		/* and now padding... */
+                padding = (4 - (ie_len % 4)) & 0x3;
+		if (data_len < padding) {
+			LM_ERR("M2UA no place for padding %u vs. %u\n", padding, data_len);
+			return NULL;
+		}
+		data += padding;
+		data_len -= padding;
+	}
+	/* No data IE was found */
+	LM_ERR("M2UA no data element found\n");
+	return NULL;
+}
+
+static const uint8_t *extract_from_mtp(const uint8_t *data, size_t *len, int *opc, int *dpc, int *type)
+{
+	struct mtp_level_3_hdr *hdr;
+
+	*opc = INT_MAX;
+	*dpc = INT_MAX;
+
+	if (!data)
+		return NULL;
+	if (*len < sizeof(*hdr)) {
+		LM_ERR("MTP not enough space for mtp hdr %zu vs. %zu", *len, sizeof(*hdr));
+		return NULL;
+	}
+
+	hdr = (struct mtp_level_3_hdr *) data;
+	*opc = hdr->opc;
+	*dpc = hdr->dpc;
+	*type = hdr->ser_ind;
+	*len -= sizeof(*hdr);
+	return &hdr->data[0];
+}
+
+
+static const uint8_t *ss7_extract_payload(const uint8_t *data, size_t *len, int proto, int *opc, int *dpc, int *mtp_type)
+{
+	switch (proto) {
+	case HEP_M2UA:
+		return extract_from_mtp(extract_from_m2ua(data, len), len, opc, dpc, mtp_type);
+		break;
+	default:
+		LM_ERR("Unknown HEP type %d/0x%c\n", proto, proto);
+		return NULL;
+	}
+}
+
+static uint8_t *fetch_payload(struct sip_msg *_m, char *pname, int *len)
+{
+	pv_spec_t *pv;
+	pv_value_t pt;
+	int rc;
+	str s;
+
+	s.s = pname;
+	s.len = strlen(pname);
+	pv = pv_cache_get(&s);
+	if (!pv) {
+		LM_ERR("Can't get %s\n", s.s);
+		return NULL;
+	}
+
+	rc = pv->getf(_m, &pv->pvp, &pt);
+	if (rc < 0) {
+		LM_ERR("Can't getf rc=%d\n", rc);
+		return NULL;
+	}
+
+	*len = pt.rs.len;
+	return (uint8_t *) pt.rs.s;
+}
+
+static int w_isup_to_json(struct sip_msg *_m, char *param1, char *param2)
+{
+	struct isup_state isup_state = { 0, };
+	int proto = atoi(param1);
+	const uint8_t *data;
+	int opc, dpc, mtp_type, int_len, rc;
+	size_t len;
+
+	free((char *) isup_last);
+	isup_last = NULL;
+
+	data = fetch_payload(_m, "$var(payload)", &int_len);
+	if (!data)
+		return -1;
+
+	if (int_len < 0) {
+		LM_ERR("Payload length low %d\n", int_len);
+		return -1;
+	}
+	len = int_len;
+
+	data = ss7_extract_payload(data, &len, proto, &opc, &dpc, &mtp_type);
+	if (!data)
+		return -1;
+
+	if (mtp_type != MTP_ISUP) {
+		LM_DBG("Non ISUP payload %d\n", mtp_type);
+		return -1;
+	}
+
+	/* parse isup... */
+	isup_state.json = srjson_NewDoc(NULL);
+	if (!isup_state.json) {
+		LM_ERR("Failed to allocate JSON document\n");
+		return -1;
+	}
+	isup_state.json->root = srjson_CreateObject(isup_state.json);
+	if (!isup_state.json->root) {
+		LM_ERR("Failed to allocate JSON object\n");
+		srjson_DeleteDoc(isup_state.json);
+		return -1;
+	}
+
+	rc = isup_parse(data, len, &isup_state);
+	if (rc != 0) {
+		srjson_DeleteDoc(isup_state.json);
+		return rc;
+	}
+	srjson_AddNumberToObject(isup_state.json, isup_state.json->root, "opc", opc);
+	srjson_AddNumberToObject(isup_state.json, isup_state.json->root, "dpc", dpc);
+	isup_last = srjson_PrintUnformatted(isup_state.json, isup_state.json->root);
+	srjson_DeleteDoc(isup_state.json);
+	return 1;
+}
+
+static int pv_get_isup(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	if (!param)
+		return -1;
+
+	switch (param->pvn.u.isname.name.n) {
+	case 1:
+		if (isup_last) {
+			str tmpstr;
+			tmpstr.s = (char *) isup_last;
+			tmpstr.len = strlen(isup_last);
+			return pv_get_strval(msg, param, res, &tmpstr);
+		}
+		break;
+	}
+
+	return -1;
+}
+
+static int pv_parse_isup_name(pv_spec_p sp, str *in)
+{
+	unsigned int input;
+
+	if(sp==NULL || in==NULL || in->len<=0)
+		return -1;
+
+	if (str2int(in, &input) < 0)
+		goto error;
+
+	switch (input) {
+	case 1:
+		/* all valid input */
+		break;
+	default:
+		goto error;
+	}
+
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
+	sp->pvp.pvn.u.isname.type = 0;
+	sp->pvp.pvn.u.isname.name.n = input;
+
+	return 0;
+error:
+	LM_ERR("unknown isup input %.*s\n", in->len, in->s);
+	return -1;
+}