From c1f9897ff56dec00d0296d009ae30cc593fba88e Mon Sep 17 00:00:00 2001
From: Michael Jerris <mike@jerris.com>
Date: Mon, 25 Jun 2007 16:00:24 +0000
Subject: [PATCH] cleanup of service message handling, add separate dialects
 for dms and national.

git-svn-id: http://svn.openzap.org/svn/openzap/trunk@290 a93c3328-9c30-0410-af19-c9cd2b2d52af
---
 libs/freetdm/msvc/openzap.vcproj         |  16 ++
 libs/freetdm/src/isdn/DMSStateNT.c       | 126 +++++++++
 libs/freetdm/src/isdn/DMSStateTE.c       | 291 +++++++++++++++++++
 libs/freetdm/src/isdn/DMSmes.c           | 338 +++++++++++++++++++++++
 libs/freetdm/src/isdn/Q931.c             |   7 +
 libs/freetdm/src/isdn/Q931api.c          |  15 +
 libs/freetdm/src/isdn/Q931ie.c           |  77 ++++++
 libs/freetdm/src/isdn/Q931mes.c          | 131 +++++++++
 libs/freetdm/src/isdn/include/DMS.h      |  95 +++++++
 libs/freetdm/src/isdn/include/Q931.h     |  21 +-
 libs/freetdm/src/isdn/include/Q931ie.h   |  15 +-
 libs/freetdm/src/isdn/include/national.h |   3 +-
 libs/freetdm/src/isdn/nationalStateTE.c  |  42 +--
 libs/freetdm/src/isdn/nationalmes.c      |  37 ---
 libs/freetdm/src/zap_isdn.c              | 194 ++++++++-----
 15 files changed, 1252 insertions(+), 156 deletions(-)
 create mode 100644 libs/freetdm/src/isdn/DMSStateNT.c
 create mode 100644 libs/freetdm/src/isdn/DMSStateTE.c
 create mode 100644 libs/freetdm/src/isdn/DMSmes.c
 create mode 100644 libs/freetdm/src/isdn/include/DMS.h

diff --git a/libs/freetdm/msvc/openzap.vcproj b/libs/freetdm/msvc/openzap.vcproj
index 67565dbb90..c8d612a40f 100644
--- a/libs/freetdm/msvc/openzap.vcproj
+++ b/libs/freetdm/msvc/openzap.vcproj
@@ -162,6 +162,10 @@
 				<Filter
 					Name="Header Files"
 					>
+					<File
+						RelativePath="..\src\isdn\include\DMS.h"
+						>
+					</File>
 					<File
 						RelativePath="..\src\isdn\include\mfifo.h"
 						>
@@ -190,6 +194,18 @@
 				<Filter
 					Name="Source Files"
 					>
+					<File
+						RelativePath="..\src\isdn\DMSmes.c"
+						>
+					</File>
+					<File
+						RelativePath="..\src\isdn\DMSStateNT.c"
+						>
+					</File>
+					<File
+						RelativePath="..\src\isdn\DMSStateTE.c"
+						>
+					</File>
 					<File
 						RelativePath="..\src\isdn\EuroISDNStateNT.c"
 						>
diff --git a/libs/freetdm/src/isdn/DMSStateNT.c b/libs/freetdm/src/isdn/DMSStateNT.c
new file mode 100644
index 0000000000..6c75029665
--- /dev/null
+++ b/libs/freetdm/src/isdn/DMSStateNT.c
@@ -0,0 +1,126 @@
+/*****************************************************************************
+
+  FileName:		DMSStateNT.c
+
+  Contents:		DMS-100 ISDN State Engine for NT (Network Mode).
+
+				The controlling state engine for Q.931 is the state engine
+				on the NT side. The state engine on the TE side is a slave 
+				of this. The TE side maintain it's own states as described in
+				ITU-T Q931, but will in	raise conditions be overridden by 
+				the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+  Function:		DMSCreateNT
+
+  Description:	Will create the National ISDN NT as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void DMSCreateNT(L3UCHAR i)
+{
+    Q931SetMesProc(Q931mes_ALERTING,            i,Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+    Q931SetMesProc(Q931mes_CALL_PROCEEDING,     i,Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+    Q931SetMesProc(Q931mes_CONNECT,             i,Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+    Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i,Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+    Q931SetMesProc(Q931mes_PROGRESS,            i,Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+    Q931SetMesProc(Q931mes_SETUP,               i,Q931ProcSetupNT,             DMSUmes_Setup,			   DMSPmes_Setup);
+    Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,   i,Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+    Q931SetMesProc(Q931mes_RESUME,              i,Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+    Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,  i,Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+    Q931SetMesProc(Q931mes_RESUME_REJECT,       i,Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+    Q931SetMesProc(Q931mes_SUSPEND,             i,Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+    Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i,Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+    Q931SetMesProc(Q931mes_SUSPEND_REJECT,      i,Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+    Q931SetMesProc(Q931mes_USER_INFORMATION,    i,Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+    Q931SetMesProc(Q931mes_DISCONNECT,          i,Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+    Q931SetMesProc(Q931mes_RELEASE,             i,Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+    Q931SetMesProc(Q931mes_RELEASE_COMPLETE,    i,Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+    Q931SetMesProc(Q931mes_RESTART,             i,Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+    Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i,Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+    Q931SetMesProc(Q931mes_CONGESTION_CONTROL,  i,Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+    Q931SetMesProc(Q931mes_INFORMATION,         i,Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+    Q931SetMesProc(Q931mes_NOTIFY,              i,Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+    Q931SetMesProc(Q931mes_STATUS,              i,Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+    Q931SetMesProc(Q931mes_STATUS_ENQUIRY,      i,Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+    Q931SetMesProc(Q931mes_SEGMENT,             i,Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+    Q931SetMesProc(Q932mes_FACILITY,            i,Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+    Q931SetMesProc(Q932mes_HOLD,                i,Q932ProcHoldNT,		       Q932Umes_Hold,              Q932Pmes_Hold);
+    Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,    i,Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+    Q931SetMesProc(Q932mes_HOLD_REJECT,         i,Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+    Q931SetMesProc(Q932mes_REGISTER,            i,Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+    Q931SetMesProc(Q932mes_RETRIEVE,            i,Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+    Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE,i,Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+    Q931SetMesProc(Q932mes_RETRIEVE_REJECT,     i,Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+    Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i,Q931Pie_Segment,			Q931Uie_Segment);
+    Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i,Q931Pie_BearerCap,			Q931Uie_BearerCap);
+    Q931SetIEProc(Q931ie_CAUSE,                            i,Q931Pie_Cause,				Q931Uie_Cause);
+    Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i,Q931Pie_CallID,			Q931Uie_CallID);
+    Q931SetIEProc(Q931ie_CALL_STATE,                       i,Q931Pie_CallState,			Q931Uie_CallState);
+    Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i,Q931Pie_ChanID,			Q931Uie_ChanID);
+    Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i,Q931Pie_ProgInd,			Q931Uie_ProgInd);
+    Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i,Q931Pie_NetFac,			Q931Uie_NetFac);
+    Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i,Q931Pie_NotifInd,			Q931Uie_NotifInd);
+    Q931SetIEProc(Q931ie_DISPLAY,                          i,Q931Pie_Display,			Q931Uie_Display);
+    Q931SetIEProc(Q931ie_DATETIME,                         i,Q931Pie_DateTime,			Q931Uie_DateTime);
+    Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i,Q931Pie_KeypadFac,			Q931Uie_KeypadFac);
+    Q931SetIEProc(Q931ie_SIGNAL,                           i,Q931Pie_Signal,			Q931Uie_Signal);
+    Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i,Q931Pie_TransNetSel,		Q931Uie_TransNetSel);
+    Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i,Q931Pie_CallingNum,		Q931Uie_CallingNum);
+    Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i,Q931Pie_CallingSub,		Q931Uie_CallingSub);
+    Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i,Q931Pie_CalledNum,			Q931Uie_CalledNum);
+    Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i,Q931Pie_CalledSub,			Q931Uie_CalledSub);
+    Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i,Q931Pie_TransNetSel,		Q931Uie_TransNetSel);
+    Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i,Q931Pie_RestartInd,		Q931Uie_RestartInd);
+    Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i,Q931Pie_LLComp,			Q931Uie_LLComp);
+    Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i,Q931Pie_HLComp,			Q931Uie_HLComp);
+    Q931SetIEProc(Q931ie_USER_USER,                        i,Q931Pie_UserUser,			Q931Uie_UserUser);
+    Q931SetIEProc(Q931ie_GENERIC_DIGITS,		           i,Q931Pie_GenericDigits,		Q931Uie_GenericDigits);
+
+	/* The following define a state machine. The point is that the Message	*/
+	/* procs can when search this to find out if the message/state			*/
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* TODO define state table here */
+}
diff --git a/libs/freetdm/src/isdn/DMSStateTE.c b/libs/freetdm/src/isdn/DMSStateTE.c
new file mode 100644
index 0000000000..e508e1ce53
--- /dev/null
+++ b/libs/freetdm/src/isdn/DMSStateTE.c
@@ -0,0 +1,291 @@
+/*****************************************************************************
+
+  FileName:		nationalStateTE.c
+
+  Contents:		National ISDN State Engine for TE (User Mode).
+
+				The controlling state engine for Q.931 is the state engine
+				on the NT side. The state engine on the TE side is a slave 
+				of this. The TE side maintain it's own states as described in
+				ITU-T Q931, but will in	raise conditions be overridden by 
+				the NT side.
+
+				This reference implementation uses a process per message,
+				meaning that each message must check call states. This
+				is easier for dialect maintenance as each message proc
+				can be replaced individually. A new TE variant only
+				need to copy the Q931CreateTE and replace those procs or
+				need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "DMS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		DMSCreateTE
+
+  Description:	Will create the National TE as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void DMSCreateTE(L3UCHAR i)
+{
+    Q931SetMesProc(Q931mes_ALERTING,            i,Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+    Q931SetMesProc(Q931mes_CALL_PROCEEDING,     i,Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+    Q931SetMesProc(Q931mes_CONNECT,             i,DMSProc0x07TE,	           DMSUmes_0x07,	           DMSPmes_0x07);
+    Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i,DMSProc0x0fTE,		       DMSUmes_0x0f,		       DMSPmes_0x0f);
+    Q931SetMesProc(Q931mes_PROGRESS,            i,Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+    Q931SetMesProc(Q931mes_SETUP,               i,Q931ProcSetupTE,             DMSUmes_Setup,         DMSPmes_Setup);
+    Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,   i,Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+    Q931SetMesProc(Q931mes_RESUME,              i,Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+    Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,  i,Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+    Q931SetMesProc(Q931mes_RESUME_REJECT,       i,Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+    Q931SetMesProc(Q931mes_SUSPEND,             i,Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+    Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE, i,Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+    Q931SetMesProc(Q931mes_SUSPEND_REJECT,      i,Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+    Q931SetMesProc(Q931mes_USER_INFORMATION,    i,Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+    Q931SetMesProc(Q931mes_DISCONNECT,          i,Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+    Q931SetMesProc(Q931mes_RELEASE,             i,Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+    Q931SetMesProc(Q931mes_RELEASE_COMPLETE,    i,Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+    Q931SetMesProc(Q931mes_RESTART,             i,Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+    Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE, i,Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+    Q931SetMesProc(Q931mes_CONGESTION_CONTROL,  i,Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+    Q931SetMesProc(Q931mes_INFORMATION,         i,Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+    Q931SetMesProc(Q931mes_NOTIFY,              i,Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+    Q931SetMesProc(Q931mes_STATUS,              i,Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+    Q931SetMesProc(Q931mes_STATUS_ENQUIRY,      i,Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+    Q931SetMesProc(Q931mes_SEGMENT,             i,Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+    Q931SetMesProc(Q932mes_FACILITY,            i,Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+    Q931SetMesProc(Q932mes_HOLD,                i,Q932ProcHoldTE,		       Q932Umes_Hold,              Q932Pmes_Hold);
+    Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,    i,Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+    Q931SetMesProc(Q932mes_HOLD_REJECT,         i,Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+    Q931SetMesProc(Q932mes_REGISTER,            i,Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+    Q931SetMesProc(Q932mes_RETRIEVE,            i,Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+    Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE,i,Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+    Q931SetMesProc(Q932mes_RETRIEVE_REJECT,     i,Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+    Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i,Q931Pie_Segment,			Q931Uie_Segment);
+    Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i,Q931Pie_BearerCap,			Q931Uie_BearerCap);
+    Q931SetIEProc(Q931ie_CAUSE,                            i,Q931Pie_Cause,				Q931Uie_Cause);
+    Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i,Q931Pie_CallID,			Q931Uie_CallID);
+    Q931SetIEProc(Q931ie_CALL_STATE,                       i,Q931Pie_CallState,			Q931Uie_CallState);
+    Q931SetIEProc(Q931ie_CHANGE_STATUS,                    i,Q931Pie_ChangeStatus,		Q931Uie_ChangeStatus);
+    Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i,Q931Pie_ChanID,			Q931Uie_ChanID);
+    Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i,Q931Pie_ProgInd,			Q931Uie_ProgInd);
+    Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i,Q931Pie_NetFac,			Q931Uie_NetFac);
+    Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i,Q931Pie_NotifInd,			Q931Uie_NotifInd);
+    Q931SetIEProc(Q931ie_DISPLAY,                          i,Q931Pie_Display,			Q931Uie_Display);
+    Q931SetIEProc(Q931ie_DATETIME,                         i,Q931Pie_DateTime,			Q931Uie_DateTime);
+    Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i,Q931Pie_KeypadFac,			Q931Uie_KeypadFac);
+    Q931SetIEProc(Q931ie_SIGNAL,                           i,Q931Pie_Signal,			Q931Uie_Signal);
+    Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i,Q931Pie_TransNetSel,		Q931Uie_TransNetSel);
+    Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i,Q931Pie_CallingNum,		Q931Uie_CallingNum);
+    Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i,Q931Pie_CallingSub,		Q931Uie_CallingSub);
+    Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i,Q931Pie_CalledNum,			Q931Uie_CalledNum);
+    Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i,Q931Pie_CalledSub,			Q931Uie_CalledSub);
+    Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i,Q931Pie_TransNetSel,		Q931Uie_TransNetSel);
+    Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i,Q931Pie_RestartInd,		Q931Uie_RestartInd);
+    Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i,Q931Pie_LLComp,			Q931Uie_LLComp);
+    Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i,Q931Pie_HLComp,			Q931Uie_HLComp);
+    Q931SetIEProc(Q931ie_USER_USER,                        i,Q931Pie_UserUser,			Q931Uie_UserUser);
+    Q931SetIEProc(Q931ie_GENERIC_DIGITS,				   i,Q931Pie_GenericDigits,		Q931Uie_GenericDigits);
+
+	/* The following define a state machine. The point is that the Message	*/
+	/* procs can when search this to find out if the message/state			*/
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i,Q931_U0,	Q931mes_RESUME,			2);
+	Q931AddStateEntry(i,Q931_U0,	Q931mes_SETUP,			4);
+	Q931AddStateEntry(i,Q931_U0,	Q931mes_SETUP,			2);
+	Q931AddStateEntry(i,Q931_U0,	Q931mes_STATUS,			4);
+	Q931AddStateEntry(i,Q931_U0,	Q931mes_RELEASE,		4);
+	Q931AddStateEntry(i,Q931_U0,	Q931mes_RELEASE_COMPLETE,4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i,Q931_U1,	Q931mes_DISCONNECT,		2);
+	Q931AddStateEntry(i,Q931_U1,	Q931mes_SETUP_ACKNOWLEDGE,		4);
+	Q931AddStateEntry(i,Q931_U1,	Q931mes_RELEASE_COMPLETE,4);
+	Q931AddStateEntry(i,Q931_U1,	Q931mes_CALL_PROCEEDING,	4);
+	Q931AddStateEntry(i,Q931_U1,	Q931mes_ALERTING,		4);
+	Q931AddStateEntry(i,Q931_U1,	Q931mes_CONNECT,		4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i,Q931_U2,	Q931mes_INFORMATION,	2);
+	Q931AddStateEntry(i,Q931_U2,	Q931mes_CALL_PROCEEDING,	4);
+	Q931AddStateEntry(i,Q931_U2,	Q931mes_ALERTING,		4);
+	Q931AddStateEntry(i,Q931_U2,	Q931mes_PROGRESS,		4);
+	Q931AddStateEntry(i,Q931_U2,	Q931mes_CONNECT,		4);
+	Q931AddStateEntry(i,Q931_U2,	Q931mes_RELEASE,		2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i,Q931_U3,	Q931mes_PROGRESS,		4);
+	Q931AddStateEntry(i,Q931_U3,	Q931mes_ALERTING,		4);
+	Q931AddStateEntry(i,Q931_U3,	Q931mes_CONNECT,		4);
+	Q931AddStateEntry(i,Q931_U3,	Q931mes_RELEASE,		2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i,Q931_U4,	Q931mes_CONNECT,		4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i,Q931_U6,	Q931mes_INFORMATION,	2);	
+	Q931AddStateEntry(i,Q931_U6,	Q931mes_ALERTING,		2);	
+	Q931AddStateEntry(i,Q931_U6,	Q931mes_CALL_PROCEEDING,2);	
+	Q931AddStateEntry(i,Q931_U6,	Q931mes_CONNECT,		2);	
+	Q931AddStateEntry(i,Q931_U6,	Q931mes_RELEASE_COMPLETE,2);	
+	Q931AddStateEntry(i,Q931_U6,	Q931mes_RELEASE,		4);	
+	Q931AddStateEntry(i,Q931_U6,	Q931mes_DISCONNECT,		4);	
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i,Q931_U7,	Q931mes_CONNECT,		2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i,Q931_U8,	Q931mes_CONNECT_ACKNOWLEDGE,		4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i,Q931_U9,	Q931mes_CONNECT,		2);
+	Q931AddStateEntry(i,Q931_U9,	Q931mes_ALERTING,		2);
+	Q931AddStateEntry(i,Q931_U9,	Q931mes_PROGRESS,		2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i,Q931_U10,	Q931mes_SUSPEND,		2);
+	Q931AddStateEntry(i,Q931_U10, Q931mes_NOTIFY,			4);
+	Q931AddStateEntry(i,Q931_U10, Q931mes_NOTIFY,			2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i,Q931_U11,	Q931mes_RELEASE,		4);
+	Q931AddStateEntry(i,Q931_U11,	Q931mes_DISCONNECT,		4);
+	Q931AddStateEntry(i,Q931_U11,	Q931mes_NOTIFY,			4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i,Q931_U12,	Q931mes_RELEASE,		4);
+	Q931AddStateEntry(i,Q931_U12, Q931mes_RELEASE,		2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i,Q931_U15,	Q931mes_SUSPEND_ACKNOWLEDGE,		4);
+	Q931AddStateEntry(i,Q931_U15,	Q931mes_SUSPEND_REJECT,	4);
+	Q931AddStateEntry(i,Q931_U15,	Q931mes_DISCONNECT,		4);
+	Q931AddStateEntry(i,Q931_U15,	Q931mes_RELEASE,		4);
+
+/* TODO
+	Q931AddStateEntry(i,Q931_U17,
+	Q931AddStateEntry(i,Q931_U19,
+	Q931AddStateEntry(i,Q931_U25,
+*/
+}
+
+/*****************************************************************************
+
+  Function:		DMSProc0x0fTE
+
+*****************************************************************************/
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+    L3INT callIndex;
+    L3INT ret=Q931E_NO_ERROR;
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if(ret != Q931E_NO_ERROR)
+			return ret;
+
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, 303);
+	}
+	if(iFrom == 4)
+	{
+		/* TODO Add proc here*/
+        ret = Q931Tx32(pTrunk,buf,pMes->Size);
+	}
+	else if (iFrom ==2)
+	{
+		/* TODO Add proc here*/
+        ret = Q931Tx34(pTrunk,buf,pMes->Size);
+
+		if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+			Q931AckService(pTrunk, buf);
+		}
+
+	}
+	return ret;
+
+}
+
+/*****************************************************************************
+
+  Function:		DMSProc0x07TE
+
+*****************************************************************************/
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+    L3INT callIndex;
+    L3INT ret=Q931E_NO_ERROR;
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if(ret != Q931E_NO_ERROR)
+			return ret;
+
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, 303);
+	}
+	if(iFrom == 4)
+	{
+		/* TODO Add proc here*/
+        ret = Q931Tx32(pTrunk,buf,pMes->Size);
+	}
+	else if (iFrom ==2)
+	{
+		/* TODO Add proc here*/
+        ret = Q931Tx34(pTrunk,buf,pMes->Size);
+	}
+	return ret;
+
+}
diff --git a/libs/freetdm/src/isdn/DMSmes.c b/libs/freetdm/src/isdn/DMSmes.c
new file mode 100644
index 0000000000..57aeddfb0d
--- /dev/null
+++ b/libs/freetdm/src/isdn/DMSmes.c
@@ -0,0 +1,338 @@
+/*****************************************************************************
+
+  FileName:		DMSmes.c
+
+  Contents:		Pack/Unpack functions. These functions will unpack a DMS-100 ISDN
+				message from the bit packed original format into structs
+				that contains variables sized by the user. It will also pack
+				the struct back into a Q.931 message as required.
+
+				See	national.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+  Function:     DMSUmes_Setup
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir=0;
+	L3INT OOff=0;
+	L3INT rc=Q931E_NO_ERROR;
+	L3UCHAR last_codeset = 0, codeset = 0;
+	L3UCHAR shift_lock = 1;
+
+	while(IOff < Size)
+	{
+		if (!shift_lock) {
+			codeset = last_codeset;
+		}
+
+		if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+			shift_lock = (IBuf[IOff] & 0x08);
+			if (shift_lock) {
+				last_codeset = codeset;
+			}
+			codeset = ((IBuf[IOff] & 0x07));
+			IOff++;
+		}
+
+		if (codeset == 0) {
+			switch(IBuf[IOff])
+			{
+			case Q931ie_SENDING_COMPLETE:
+			case Q931ie_BEARER_CAPABILITY:
+			case Q931ie_CHANNEL_IDENTIFICATION:
+			case Q931ie_PROGRESS_INDICATOR:
+			case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+			case Q931ie_DISPLAY:
+			case Q931ie_DATETIME:
+			case Q931ie_KEYPAD_FACILITY:
+			case Q931ie_SIGNAL:
+			case Q931ie_CALLING_PARTY_NUMBER:
+			case Q931ie_CALLING_PARTY_SUBADDRESS:
+			case Q931ie_CALLED_PARTY_NUMBER:
+			case Q931ie_CALLED_PARTY_SUBADDRESS:
+			case Q931ie_TRANSIT_NETWORK_SELECTION:
+			case Q931ie_LOW_LAYER_COMPATIBILITY:
+			case Q931ie_HIGH_LAYER_COMPATIBILITY:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if(rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			case Q931ie_REPEAT_INDICATOR:
+				if(ir < 2) {
+					rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+					ir++;
+				} else {
+					return Q931E_ILLEGAL_IE;
+				}
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 6) {
+			switch(IBuf[IOff])
+			{
+			case Q931ie_GENERIC_DIGITS:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if(rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+
+		} else {
+			return Q931E_ILLEGAL_IE;
+		}
+	}
+    mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+    return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:     DMSPmes_Setup
+
+  Decription:	Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:	IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]	Size of input buffer (unpacked message).
+				OBuf[OUT]	Ptr to packed 'octet' wise message.
+				OSize[OUT]	Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+    L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+
+	OBuf[Octet++]	= pMes->ProtDisc;		/* Protocol discriminator		*/
+	OBuf[Octet++]	= 2;					/* length is 2 octets			*/
+	OBuf[Octet++]	= (L3UCHAR)(pMes->CRV>>8) | (pMes->CRVFlag << 7);	/* msb						*/
+	OBuf[Octet++]	= (L3UCHAR)(pMes->CRV);	/* lsb							*/
+	OBuf[Octet++]	= pMes->MesType;		/* message header				*/
+	
+	/* Sending Complete				*/
+	if(Q931IsIEPresent(pMes->SendComplete))
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+
+	/* Repeat Indicator */
+	if(Q931IsIEPresent(pMes->RepeatInd))
+		OBuf[Octet++]	= (L3UCHAR)(pMes->RepeatInd & 0x00ff);		
+
+	/* Bearer capability */
+	if(Q931IsIEPresent(pMes->BearerCap))
+	{
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+	else
+	{
+		rc=Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if(Q931IsIEPresent(pMes->ChanID))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Progress indicator */
+	if(Q931IsIEPresent(pMes->ProgInd))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Network spesific facilities */
+	if(Q931IsIEPresent(pMes->NetFac))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Display */
+	if(Q931IsIEPresent(pMes->Display))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Date/Time */
+	if(Q931IsIEPresent(pMes->DateTime))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Keypad Facility */
+	if(Q931IsIEPresent(pMes->KeypadFac))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Signal */
+	if(Q931IsIEPresent(pMes->Signal))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Calling Party Number */
+	if(Q931IsIEPresent(pMes->CallingNum))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Calling Party Subaddress */
+	if(Q931IsIEPresent(pMes->CallingSub))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Called Party number */
+	if(Q931IsIEPresent(pMes->CalledNum))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Called party subaddress */
+	if(Q931IsIEPresent(pMes->CalledSub))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Transit network selection */
+	if(Q931IsIEPresent(pMes->TransNetSel))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* Repeat Indicator */
+	if(Q931IsIEPresent(pMes->LLRepeatInd))
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+
+	/* Low Layer Compatibility */
+	if(Q931IsIEPresent(pMes->LLComp))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	/* High Layer Compatibility */
+	if(Q931IsIEPresent(pMes->HLComp))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	*OSize = Octet;	
+
+    return rc;
+}
+
+
+/*****************************************************************************
+
+  Function:     DMSUmes_0x0f
+
+*****************************************************************************/
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:     DMSPmes_0x0f
+
+*****************************************************************************/
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:     DMSUmes_0x07
+
+*****************************************************************************/
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:     DMSPmes_0x07
+
+*****************************************************************************/
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
diff --git a/libs/freetdm/src/isdn/Q931.c b/libs/freetdm/src/isdn/Q931.c
index 232b2122c3..098c1a44b3 100644
--- a/libs/freetdm/src/isdn/Q931.c
+++ b/libs/freetdm/src/isdn/Q931.c
@@ -38,6 +38,7 @@
 
 #include "Q931.h"
 #include "national.h"
+#include "DMS.h"
 
 /*****************************************************************************
 
@@ -261,6 +262,12 @@ void Q931Initialize()
 	if(Q931CreateDialectCB[Q931_Dialect_National + Q931_NT] == NULL)
 		Q931AddDialect(Q931_Dialect_National + Q931_NT, nationalCreateNT);
 
+	if(Q931CreateDialectCB[Q931_Dialect_DMS + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_DMS + Q931_TE, DMSCreateTE);
+
+	if(Q931CreateDialectCB[Q931_Dialect_DMS + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_DMS + Q931_NT, DMSCreateNT);
+
 	/* The last step we do is to call the callbacks to create the dialects  */
 	for(x=0; x< Q931MAXDLCT; x++)
 	{
diff --git a/libs/freetdm/src/isdn/Q931api.c b/libs/freetdm/src/isdn/Q931api.c
index 541b28d428..0a6d3a6733 100644
--- a/libs/freetdm/src/isdn/Q931api.c
+++ b/libs/freetdm/src/isdn/Q931api.c
@@ -562,5 +562,20 @@ L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
     return RetCode;
 }
 
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_SERVICE_ACKNOWLEDGE;
+	if (ptr->CRV) {
+		ptr->CRVFlag = !(ptr->CRVFlag);
+	}
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
 Q931_ENUM_NAMES(DIALECT_TYPE_NAMES, DIALECT_STRINGS)
 Q931_STR2ENUM(q931_str2Q931Diaelct_type, q931_Q931Diaelct_type2str, Q931Dialect_t, DIALECT_TYPE_NAMES, Q931_Dialect_Count)
diff --git a/libs/freetdm/src/isdn/Q931ie.c b/libs/freetdm/src/isdn/Q931ie.c
index 2f4fa60b07..1973d20c41 100644
--- a/libs/freetdm/src/isdn/Q931ie.c
+++ b/libs/freetdm/src/isdn/Q931ie.c
@@ -3079,3 +3079,80 @@ L3INT Q931Pie_GenericDigits(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OB
 
     return Q931E_NO_ERROR;
 }
+
+/*****************************************************************************
+
+  Function:     Q931Uie_ChangeStatus
+
+  Parameters:   pIE[OUT]        ptr to Information Element id.
+                IBuf[IN]        ptr to a packed ie.
+                OBuf[OUT]       ptr to buffer for Unpacked ie.
+                IOff[IN\OUT]    Input buffer offset
+                OOff[IN\OUT]    Output buffer offset
+
+                Ibuf and OBuf points directly to buffers. The IOff and OOff
+                must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+    Q931ie_ChangeStatus * pie = (Q931ie_ChangeStatus*)OBuf;
+	ie *pIE = &pMsg->ChangeStatus;
+    L3INT Off = 0;
+    L3INT Octet = 0;
+    L3INT IESize;
+
+    *pIE=0;
+
+    pie->IEId        = IBuf[Octet];
+    Octet ++;
+
+    /* Octet 2*/
+    IESize = IBuf[Octet ++]; 
+
+    /* Octet 3 */
+	pie->Preference = (IBuf[Octet+Off] >> 6) & 0x01;
+    pie->Spare = IBuf[Octet+Off] & 0x38;
+    pie->NewStatus = IBuf[Octet+Off] & 0x07;
+
+    Octet++;
+
+    Q931SetIE(*pIE, *OOff);
+
+    *IOff = (*IOff) + Octet + Off;
+    *OOff = (*OOff) + sizeof(Q931ie_ChangeStatus);
+    pie->Size = sizeof(Q931ie_ChangeStatus);
+
+
+    return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:     Q931Pie_ChangeStatus
+
+  Parameters:   IBuf[IN]        Ptr to struct.
+                OBuf[OUT]        Ptr tp packed output buffer.
+                Octet[IN/OUT]    Offset into OBuf.
+
+  Return Value:    Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+    Q931ie_ChangeStatus * pIE = (Q931ie_ChangeStatus*)IBuf;
+    L3INT rc=Q931E_NO_ERROR;
+    L3INT Beg=*Octet;
+    L3INT li;
+
+    OBuf[(*Octet)++] = Q931ie_CHANGE_STATUS;
+    li=(*Octet)++;
+
+    /* Octet 3*/
+    OBuf[(*Octet)++] = 0x80 | pIE->NewStatus | ((pIE->Preference & 0x01) << 6);
+
+    OBuf[li] = (L3UCHAR)((*Octet)-Beg) - 2;
+    return rc;
+}
diff --git a/libs/freetdm/src/isdn/Q931mes.c b/libs/freetdm/src/isdn/Q931mes.c
index d4229fe958..497e6c1a94 100644
--- a/libs/freetdm/src/isdn/Q931mes.c
+++ b/libs/freetdm/src/isdn/Q931mes.c
@@ -1770,3 +1770,134 @@ L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf,
     return RetCode;
 }
 
+/*****************************************************************************
+
+  Function:     Q931Umes_Service
+
+*****************************************************************************/
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff=0;
+	L3INT rc=Q931E_NO_ERROR;
+
+	while(IOff < Size)
+	{
+		switch(IBuf[IOff])
+		{
+		case Q931ie_CHANNEL_IDENTIFICATION:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if(rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		case Q931ie_CHANGE_STATUS:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if(rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+    mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+    return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:     Q931Pmes_Service
+
+*****************************************************************************/
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+    L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+
+	OBuf[Octet++]	= pMes->ProtDisc;		/* Protocol discriminator		*/
+	OBuf[Octet++]	= 2;					/* length is 2 octets			*/
+	OBuf[Octet++]	= (L3UCHAR)(pMes->CRV>>8) | (pMes->CRVFlag << 7);	/* msb							*/
+	OBuf[Octet++]	= (L3UCHAR)(pMes->CRV);	/* lsb							*/
+	OBuf[Octet++]	= pMes->MesType;		/* message header				*/
+	
+	/* Display */
+	if(Q931IsIEPresent(pMes->ChanID))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	if(Q931IsIEPresent(pMes->ChangeStatus))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	*OSize = Octet;	
+
+    return rc;
+}
+
+/*****************************************************************************
+
+  Function:     Q931Umes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff=0;
+	L3INT rc=Q931E_NO_ERROR;
+
+	while(IOff < Size)
+	{
+		switch(IBuf[IOff])
+		{
+		case Q931ie_CHANNEL_IDENTIFICATION:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if(rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		case Q931ie_CHANGE_STATUS:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if(rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+    mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+    return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:     Q931Pmes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+    L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+
+	OBuf[Octet++]	= pMes->ProtDisc;		/* Protocol discriminator		*/
+	OBuf[Octet++]	= 2;					/* length is 2 octets			*/
+	OBuf[Octet++]	= (L3UCHAR)(pMes->CRV>>8) | (pMes->CRVFlag << 7);	/* msb							*/
+	OBuf[Octet++]	= (L3UCHAR)(pMes->CRV);	/* lsb							*/
+	OBuf[Octet++]	= pMes->MesType;		/* message header				*/
+	
+	/* Display */
+	if(Q931IsIEPresent(pMes->ChanID))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	if(Q931IsIEPresent(pMes->ChangeStatus))
+		if((rc=Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+
+	*OSize = Octet;	
+
+    return rc;
+}
diff --git a/libs/freetdm/src/isdn/include/DMS.h b/libs/freetdm/src/isdn/include/DMS.h
new file mode 100644
index 0000000000..35d10d7b5b
--- /dev/null
+++ b/libs/freetdm/src/isdn/include/DMS.h
@@ -0,0 +1,95 @@
+/******************************************************************************
+
+  FileName:         national.h
+
+  Contents:         Header and definition for the National ISDN dialect. The 
+										header contents the following parts:
+
+					- Definition of codes
+                    - Definition of information elements (nationalie_).
+                    - Definition of messages (nationalmes_).
+					- Function prototypes.
+
+  Description:		The National ISDN dialect here covers ????
+
+  Related Files:	national.h				National ISDN Definitions
+					nationalie.c			National ISDN IE encoders/coders
+					nationalStateTE.c		National ISDN TE State Engine
+					nationalStateNT.c		National ISDN NT State Engine
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _DMS_NL
+#define _DMS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  Only National specific message and ie types 
+  here the rest are inherited from national.h
+  
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+
+void DMSCreateTE(L3UCHAR i);
+void DMSCreateNT(L3UCHAR i);
+
+#endif /* _DMS_NL */
diff --git a/libs/freetdm/src/isdn/include/Q931.h b/libs/freetdm/src/isdn/include/Q931.h
index ce74a4e0fc..ee92e48b26 100644
--- a/libs/freetdm/src/isdn/include/Q931.h
+++ b/libs/freetdm/src/isdn/include/Q931.h
@@ -283,7 +283,7 @@ typedef L3USHORT ie;                /* Special data type to hold a dynamic  */
 /* WARNING! Initialize Q931CreateDialectCB[] will NULL when increasing the  */
 /* Q931MAXDLCT value to avoid Q931Initialize from crashing if one entry is  */
 /* not used.																*/
-#define Q931MAXDLCT 4           /* Max dialects included in this        */
+#define Q931MAXDLCT 6           /* Max dialects included in this        */
                                 /* compile. User and Network count as   */
                                 /* one dialect each.                    */
 
@@ -377,6 +377,9 @@ typedef L3USHORT ie;                /* Special data type to hold a dynamic  */
 #define Q931mes_STATUS_ENQUIRY       0x75 /* 0111 0101                   */
 #define Q931mes_SEGMENT              0x60 /* 0110 0000                   */
 
+#define Q931mes_SERVICE              0x0f /* 0000 1111                   */
+#define Q931mes_SERVICE_ACKNOWLEDGE  0x07 /* 0000 0111                   */
+
 
 /*****************************************************************************
 
@@ -422,6 +425,7 @@ typedef struct
     ie              CallState;      /* Call State                           */
     ie              CallID;			/* Call Identity                        */
     ie              ChanID;         /* Channel Identification               */
+    ie              ChangeStatus;   /* Change Staus                         */
     ie              ProgInd;        /* Progress Indicator                   */
     ie              NetFac;         /* Network Spesific Facilities          */
     ie              NotifInd;       /* Notification Indicator               */
@@ -488,10 +492,11 @@ typedef enum						/* Dialect enum                         */
 {
 	Q931_Dialect_Q931 = 0,
 	Q931_Dialect_National = 2,
+	Q931_Dialect_DMS = 4,
 
 	Q931_Dialect_Count
 } Q931Dialect_t;
-#define DIALECT_STRINGS "q931", "", "national"
+#define DIALECT_STRINGS "q931", "", "national", "", "dms"
 Q931_STR2ENUM_P(q931_str2Q931Diaelct_type, q931_Q931Diaelct_type2str, Q931Dialect_t)
 
 typedef enum						/* Trunk Line Type.                     */
@@ -557,7 +562,10 @@ struct Q931_TrunkInfo
 	L3BOOL  autoRestartAck;			/* Indicate if the stack should send    */
 									/* RESTART ACK or not. 0=No, 1=Yes.		*/
 
-    /* channel array holding info per channel. Usually defined to 32		*/
+	L3BOOL  autoServiceAck;			/* Indicate if the stack should send    */
+									/* SERVICE ACK or not. 0=No, 1=Yes.		*/
+
+	/* channel array holding info per channel. Usually defined to 32		*/
 	/* channels to fit an E1 since T1/J1 and BRI will fit inside a E1.		*/
     struct _charray
     {
@@ -786,6 +794,9 @@ L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISi
 L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
 L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
 L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
 
 L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
 L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
@@ -812,6 +823,9 @@ L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *
 L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
 L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
 L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+
 
 /*****************************************************************************
 
@@ -943,6 +957,7 @@ L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
 L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
 L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
 L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
 
 L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
 						Q931Dialect_t Dialect,
diff --git a/libs/freetdm/src/isdn/include/Q931ie.h b/libs/freetdm/src/isdn/include/Q931ie.h
index dbca5b3990..5b0e7314a5 100644
--- a/libs/freetdm/src/isdn/include/Q931ie.h
+++ b/libs/freetdm/src/isdn/include/Q931ie.h
@@ -1068,6 +1068,18 @@ typedef struct
                                     /*  111 All interfaces                  */
 }Q931ie_RestartInd;
 
+typedef struct
+{
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+	L3UCHAR Preference;             /* Preference 0 = reserved, 1 = channel */
+	L3UCHAR Spare;                  /* Spare                                */
+    L3UCHAR NewStatus;              /* NewStatus                            */
+                                    /*  000 In service                      */
+                                    /*  001 Maintenance                     */
+                                    /*  010 Out of service                  */
+}Q931ie_ChangeStatus;
+
 /*****************************************************************************
 
   Struct:       Q931ie_GenericDigits
@@ -1090,7 +1102,7 @@ typedef struct
   Q.931 Information Element Pack/Unpack functions. Implemented in Q931ie.c
 
 *****************************************************************************/
-
+q931pie_func_t Q931Pie_ChangeStatus;
 q931pie_func_t Q931Pie_BearerCap;
 q931pie_func_t Q931Pie_ChanID;
 q931pie_func_t Q931Pie_ProgInd;
@@ -1121,6 +1133,7 @@ q931pie_func_t Q931Pie_GenericDigits;
 
 L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk,L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
 
+q931uie_func_t Q931Uie_ChangeStatus;
 q931uie_func_t Q931Uie_BearerCap;
 q931uie_func_t Q931Uie_ChanID;
 q931uie_func_t Q931Uie_ProgInd;
diff --git a/libs/freetdm/src/isdn/include/national.h b/libs/freetdm/src/isdn/include/national.h
index 983a6de1dc..c47daf4ed9 100644
--- a/libs/freetdm/src/isdn/include/national.h
+++ b/libs/freetdm/src/isdn/include/national.h
@@ -72,7 +72,8 @@
 *****************************************************************************/
 L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
 L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
-L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+
+#include "DMS.h"
 
 
 /*****************************************************************************
diff --git a/libs/freetdm/src/isdn/nationalStateTE.c b/libs/freetdm/src/isdn/nationalStateTE.c
index 289e9c9de9..efd1d81ea2 100644
--- a/libs/freetdm/src/isdn/nationalStateTE.c
+++ b/libs/freetdm/src/isdn/nationalStateTE.c
@@ -53,7 +53,6 @@
 
 #include "national.h"
 extern L3INT Q931L4HeaderSpace;
-L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
 
 /*****************************************************************************
   Function:		nationalCreateTE
@@ -68,8 +67,8 @@ void nationalCreateTE(L3UCHAR i)
 {
     Q931SetMesProc(Q931mes_ALERTING,            i,Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
     Q931SetMesProc(Q931mes_CALL_PROCEEDING,     i,Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
-    Q931SetMesProc(Q931mes_CONNECT,             i,Q931ProcConnectTE,           Q931Umes_Connect,           Q931Pmes_Connect);
-    Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i,DMSProc0x0fTE,		       DMSUmes_0x0f,		       Q931Pmes_ConnectAck);
+    Q931SetMesProc(Q931mes_CONNECT,             i,DMSProc0x07TE,	           DMSUmes_0x07,	           DMSPmes_0x07);
+    Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE, i,DMSProc0x0fTE,		       DMSUmes_0x0f,		       DMSPmes_0x0f);
     Q931SetMesProc(Q931mes_PROGRESS,            i,Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
     Q931SetMesProc(Q931mes_SETUP,               i,Q931ProcSetupTE,             nationalUmes_Setup,         nationalPmes_Setup);
     Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,   i,Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
@@ -107,6 +106,7 @@ void nationalCreateTE(L3UCHAR i)
     Q931SetIEProc(Q931ie_CAUSE,                            i,Q931Pie_Cause,				Q931Uie_Cause);
     Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i,Q931Pie_CallID,			Q931Uie_CallID);
     Q931SetIEProc(Q931ie_CALL_STATE,                       i,Q931Pie_CallState,			Q931Uie_CallState);
+    Q931SetIEProc(Q931ie_CHANGE_STATUS,                    i,Q931Pie_ChangeStatus,		Q931Uie_ChangeStatus);
     Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i,Q931Pie_ChanID,			Q931Uie_ChanID);
     Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i,Q931Pie_ProgInd,			Q931Uie_ProgInd);
     Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i,Q931Pie_NetFac,			Q931Uie_NetFac);
@@ -211,39 +211,3 @@ void nationalCreateTE(L3UCHAR i)
 */
 }
 
-/*****************************************************************************
-
-  Function:		Q931ProcConnectAckTE
-
-*****************************************************************************/
-L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
-{
-    L3INT callIndex;
-    L3INT ret=Q931E_NO_ERROR;
-	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
-
-	if (pMes->ProtDisc == 8) {
-		/* Find the call using CRV */
-		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
-		if(ret != Q931E_NO_ERROR)
-			return ret;
-
-
-		/* TODO chack against state table for illegal or unexpected message here*/
-
-		/* TODO - Set correct timer here */
-		Q931StartTimer(pTrunk, callIndex, 303);
-	}
-	if(iFrom == 4)
-	{
-		/* TODO Add proc here*/
-        ret = Q931Tx32(pTrunk,buf,pMes->Size);
-	}
-	else if (iFrom ==2)
-	{
-		/* TODO Add proc here*/
-        ret = Q931Tx34(pTrunk,buf,pMes->Size);
-	}
-	return ret;
-
-}
diff --git a/libs/freetdm/src/isdn/nationalmes.c b/libs/freetdm/src/isdn/nationalmes.c
index 75e313d90d..81361bd70d 100644
--- a/libs/freetdm/src/isdn/nationalmes.c
+++ b/libs/freetdm/src/isdn/nationalmes.c
@@ -261,40 +261,3 @@ L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT
 }
 
 
-/*****************************************************************************
-
-  Function:     DMSUmes_0x0f
-
-*****************************************************************************/
-L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
-//L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
-{
-	L3INT OOff=0;
-	L3INT rc=Q931E_NO_ERROR;
-
-	if (mes->ProtDisc == 8) {
-		return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
-	}
-
-	while(IOff < Size)
-	{
-		switch(IBuf[IOff])
-		{
-		case Q931ie_CHANNEL_IDENTIFICATION:
-			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
-			if(rc != Q931E_NO_ERROR) 
-				return rc;
-			break;
-		case Q931ie_CHANGE_STATUS:
-			rc = Q931Uie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
-			if(rc != Q931E_NO_ERROR) 
-				return rc;
-			break;
-		default:
-			return Q931E_ILLEGAL_IE;
-			break;
-		}
-	}
-    mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
-    return Q931E_NO_ERROR;
-}
diff --git a/libs/freetdm/src/zap_isdn.c b/libs/freetdm/src/zap_isdn.c
index db5ffdfadb..e898a7927b 100644
--- a/libs/freetdm/src/zap_isdn.c
+++ b/libs/freetdm/src/zap_isdn.c
@@ -46,7 +46,7 @@
 
 static L2ULONG zap_time_now()
 {
-	return zap_current_time_in_ms();
+	return (L2ULONG)zap_current_time_in_ms();
 }
 
 static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
@@ -79,86 +79,129 @@ static L3INT zap_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen)
 	}
 
 	zap_log(ZAP_LOG_DEBUG, "Yay I got an event! Type:[%02x] Size:[%d]\n", gen->MesType, gen->Size);
-	switch(gen->MesType) {
-	case Q931mes_RESTART:
-		{
-			if (zchan) {
-				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
-			} else {
-				uint32_t i;
-				for (i = 0; i < span->chan_count; i++) {
-					zap_set_state_locked((&span->channels[i]), ZAP_CHANNEL_STATE_RESTART);
+
+#if 0
+	typedef struct
+{
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+	L3UCHAR Preference;             /* Preference 0 = reserved, 1 = channel */
+	L3UCHAR Spare;                  /* Spare                                */
+    L3UCHAR NewStatus;              /* NewStatus                            */
+                                    /*  000 In service                      */
+                                    /*  001 Maintenance                     */
+                                    /*  010 Out of service                  */
+}Q931ie_ChangeStatus;
+
+#endif
+	if (gen->ProtDisc == 3) {
+		switch(gen->MesType) {
+		case Q931mes_SERVICE:
+			{
+				Q931ie_ChangeStatus *changestatus = Q931GetIEPtr(gen->ChangeStatus, gen->buf);
+				/* TODO: Handle this properly */
+				if (zchan) {
+					switch (changestatus->NewStatus) {
+					case 0: /* change status to "in service" */
+						//zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+						break;
+					case 1: /* change status to "maintenance" */
+						//zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+						break;
+					case 2: /* change status to "out of service" */
+						//zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+						break;
+					default: /* unknown */
+						break;
+					}
 				}
 			}
+			break;
+		default:
+			break;
 		}
-		break;
-	case Q931mes_RELEASE_COMPLETE:
-		{
-			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
-		}
-		break;
-	case Q931mes_DISCONNECT:
-		{
-			Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
-			zchan->caller_data.hangup_cause = cause->Value;
-			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_TERMINATING);
-		}
-		break;
-	case Q931mes_ALERTING:
-		{
-			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
-		}
-		break;
-	case Q931mes_PROGRESS:
-		{
-			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
-		}
-		break;
-	case Q931mes_CONNECT:
-		{
-			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
-		}
-		break;
-	case Q931mes_SETUP:
-		{
-
-			Q931ie_CallingNum *callingnum = Q931GetIEPtr(gen->CallingNum, gen->buf);
-			Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
-			zap_status_t status;
-			int fail = 1;
-			uint32_t cplen = mlen;
-
-
-			if ((status = zap_channel_open(span->span_id, chan_id, &zchan) == ZAP_SUCCESS)) {
-				if (zchan->state == ZAP_CHANNEL_STATE_DOWN) {
-					memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
-
-					zap_set_string(zchan->caller_data.cid_num, (char *)callingnum->Digit);
-					zap_set_string(zchan->caller_data.cid_name, (char *)callingnum->Digit);
-					zap_set_string(zchan->caller_data.ani, (char *)callingnum->Digit);
-					zap_set_string(zchan->caller_data.dnis, (char *)callednum->Digit);
-
-					zchan->caller_data.CRV = gen->CRV;
-					if (cplen > sizeof(zchan->caller_data.raw_data)) {
-						cplen = sizeof(zchan->caller_data.raw_data);
+	} else {
+		switch(gen->MesType) {
+		case Q931mes_RESTART:
+			{
+				if (zchan) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+				} else {
+					uint32_t i;
+					for (i = 0; i < span->chan_count; i++) {
+						zap_set_state_locked((&span->channels[i]), ZAP_CHANNEL_STATE_RESTART);
 					}
-					gen->CRVFlag = !(gen->CRVFlag);
-					memcpy(zchan->caller_data.raw_data, msg, cplen);
-					zchan->caller_data.raw_data_len = cplen;
-					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
-					fail = 0;
-				} 
-			} 
-
-			if (fail) {
-				zap_log(ZAP_LOG_CRIT, "FIX ME!\n");
-				// add me 
+				}
 			}
-			
+			break;
+		case Q931mes_RELEASE_COMPLETE:
+			{
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+			}
+			break;
+		case Q931mes_DISCONNECT:
+			{
+				Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+				zchan->caller_data.hangup_cause = cause->Value;
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_TERMINATING);
+			}
+			break;
+		case Q931mes_ALERTING:
+			{
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+			}
+			break;
+		case Q931mes_PROGRESS:
+			{
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+			}
+			break;
+		case Q931mes_CONNECT:
+			{
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+			}
+			break;
+		case Q931mes_SETUP:
+			{
+
+				Q931ie_CallingNum *callingnum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+				Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+				zap_status_t status;
+				int fail = 1;
+				uint32_t cplen = mlen;
+
+
+				if ((status = zap_channel_open(span->span_id, chan_id, &zchan) == ZAP_SUCCESS)) {
+					if (zchan->state == ZAP_CHANNEL_STATE_DOWN) {
+						memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+
+						zap_set_string(zchan->caller_data.cid_num, (char *)callingnum->Digit);
+						zap_set_string(zchan->caller_data.cid_name, (char *)callingnum->Digit);
+						zap_set_string(zchan->caller_data.ani, (char *)callingnum->Digit);
+						zap_set_string(zchan->caller_data.dnis, (char *)callednum->Digit);
+
+						zchan->caller_data.CRV = gen->CRV;
+						if (cplen > sizeof(zchan->caller_data.raw_data)) {
+							cplen = sizeof(zchan->caller_data.raw_data);
+						}
+						gen->CRVFlag = !(gen->CRVFlag);
+						memcpy(zchan->caller_data.raw_data, msg, cplen);
+						zchan->caller_data.raw_data_len = cplen;
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+						fail = 0;
+					} 
+				} 
+
+				if (fail) {
+					zap_log(ZAP_LOG_CRIT, "FIX ME!\n");
+					// add me 
+				}
+				
+			}
+			break;
+		default:
+			break;
 		}
-		break;
-	default:
-		break;
 	}
 
 	return 0;
@@ -632,6 +675,7 @@ zap_status_t zap_isdn_configure_span(zap_span_t *span, Q921NetUser_t mode, Q931D
 
 	isdn_data->q931.autoRestartAck = 1;
 	isdn_data->q931.autoConnectAck = 1;
+	isdn_data->q931.autoServiceAck = 1;
 	span->signal_data = isdn_data;
 	span->signal_type = ZAP_SIGTYPE_ISDN;
 	span->outgoing_call = isdn_outgoing_call;