First code commit
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3534f2f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0

+

+    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE

+    PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION

+    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

+

+1. DEFINITIONS

+

+"Contribution" means:

+

+  a) in the case of the initial Contributor, the initial content

+     Distributed under this Agreement, and

+

+  b) in the case of each subsequent Contributor:

+     i) changes to the Program, and

+     ii) additions to the Program;

+  where such changes and/or additions to the Program originate from

+  and are Distributed by that particular Contributor. A Contribution

+  "originates" from a Contributor if it was added to the Program by

+  such Contributor itself or anyone acting on such Contributor's behalf.

+  Contributions do not include changes or additions to the Program that

+  are not Modified Works.

+

+"Contributor" means any person or entity that Distributes the Program.

+

+"Licensed Patents" mean patent claims licensable by a Contributor which

+are necessarily infringed by the use or sale of its Contribution alone

+or when combined with the Program.

+

+"Program" means the Contributions Distributed in accordance with this

+Agreement.

+

+"Recipient" means anyone who receives the Program under this Agreement

+or any Secondary License (as applicable), including Contributors.

+

+"Derivative Works" shall mean any work, whether in Source Code or other

+form, that is based on (or derived from) the Program and for which the

+editorial revisions, annotations, elaborations, or other modifications

+represent, as a whole, an original work of authorship.

+

+"Modified Works" shall mean any work in Source Code or other form that

+results from an addition to, deletion from, or modification of the

+contents of the Program, including, for purposes of clarity any new file

+in Source Code form that contains any contents of the Program. Modified

+Works shall not include works that contain only declarations,

+interfaces, types, classes, structures, or files of the Program solely

+in each case in order to link to, bind by name, or subclass the Program

+or Modified Works thereof.

+

+"Distribute" means the acts of a) distributing or b) making available

+in any manner that enables the transfer of a copy.

+

+"Source Code" means the form of a Program preferred for making

+modifications, including but not limited to software source code,

+documentation source, and configuration files.

+

+"Secondary License" means either the GNU General Public License,

+Version 2.0, or any later versions of that license, including any

+exceptions or additional permissions as identified by the initial

+Contributor.

+

+2. GRANT OF RIGHTS

+

+  a) Subject to the terms of this Agreement, each Contributor hereby

+  grants Recipient a non-exclusive, worldwide, royalty-free copyright

+  license to reproduce, prepare Derivative Works of, publicly display,

+  publicly perform, Distribute and sublicense the Contribution of such

+  Contributor, if any, and such Derivative Works.

+

+  b) Subject to the terms of this Agreement, each Contributor hereby

+  grants Recipient a non-exclusive, worldwide, royalty-free patent

+  license under Licensed Patents to make, use, sell, offer to sell,

+  import and otherwise transfer the Contribution of such Contributor,

+  if any, in Source Code or other form. This patent license shall

+  apply to the combination of the Contribution and the Program if, at

+  the time the Contribution is added by the Contributor, such addition

+  of the Contribution causes such combination to be covered by the

+  Licensed Patents. The patent license shall not apply to any other

+  combinations which include the Contribution. No hardware per se is

+  licensed hereunder.

+

+  c) Recipient understands that although each Contributor grants the

+  licenses to its Contributions set forth herein, no assurances are

+  provided by any Contributor that the Program does not infringe the

+  patent or other intellectual property rights of any other entity.

+  Each Contributor disclaims any liability to Recipient for claims

+  brought by any other entity based on infringement of intellectual

+  property rights or otherwise. As a condition to exercising the

+  rights and licenses granted hereunder, each Recipient hereby

+  assumes sole responsibility to secure any other intellectual

+  property rights needed, if any. For example, if a third party

+  patent license is required to allow Recipient to Distribute the

+  Program, it is Recipient's responsibility to acquire that license

+  before distributing the Program.

+

+  d) Each Contributor represents that to its knowledge it has

+  sufficient copyright rights in its Contribution, if any, to grant

+  the copyright license set forth in this Agreement.

+

+  e) Notwithstanding the terms of any Secondary License, no

+  Contributor makes additional grants to any Recipient (other than

+  those set forth in this Agreement) as a result of such Recipient's

+  receipt of the Program under the terms of a Secondary License

+  (if permitted under the terms of Section 3).

+

+3. REQUIREMENTS

+

+3.1 If a Contributor Distributes the Program in any form, then:

+

+  a) the Program must also be made available as Source Code, in

+  accordance with section 3.2, and the Contributor must accompany

+  the Program with a statement that the Source Code for the Program

+  is available under this Agreement, and informs Recipients how to

+  obtain it in a reasonable manner on or through a medium customarily

+  used for software exchange; and

+

+  b) the Contributor may Distribute the Program under a license

+  different than this Agreement, provided that such license:

+     i) effectively disclaims on behalf of all other Contributors all

+     warranties and conditions, express and implied, including

+     warranties or conditions of title and non-infringement, and

+     implied warranties or conditions of merchantability and fitness

+     for a particular purpose;

+

+     ii) effectively excludes on behalf of all other Contributors all

+     liability for damages, including direct, indirect, special,

+     incidental and consequential damages, such as lost profits;

+

+     iii) does not attempt to limit or alter the recipients' rights

+     in the Source Code under section 3.2; and

+

+     iv) requires any subsequent distribution of the Program by any

+     party to be under a license that satisfies the requirements

+     of this section 3.

+

+3.2 When the Program is Distributed as Source Code:

+

+  a) it must be made available under this Agreement, or if the

+  Program (i) is combined with other material in a separate file or

+  files made available under a Secondary License, and (ii) the initial

+  Contributor attached to the Source Code the notice described in

+  Exhibit A of this Agreement, then the Program may be made available

+  under the terms of such Secondary Licenses, and

+

+  b) a copy of this Agreement must be included with each copy of

+  the Program.

+

+3.3 Contributors may not remove or alter any copyright, patent,

+trademark, attribution notices, disclaimers of warranty, or limitations

+of liability ("notices") contained within the Program from any copy of

+the Program which they Distribute, provided that Contributors may add

+their own appropriate notices.

+

+4. COMMERCIAL DISTRIBUTION

+

+Commercial distributors of software may accept certain responsibilities

+with respect to end users, business partners and the like. While this

+license is intended to facilitate the commercial use of the Program,

+the Contributor who includes the Program in a commercial product

+offering should do so in a manner which does not create potential

+liability for other Contributors. Therefore, if a Contributor includes

+the Program in a commercial product offering, such Contributor

+("Commercial Contributor") hereby agrees to defend and indemnify every

+other Contributor ("Indemnified Contributor") against any losses,

+damages and costs (collectively "Losses") arising from claims, lawsuits

+and other legal actions brought by a third party against the Indemnified

+Contributor to the extent caused by the acts or omissions of such

+Commercial Contributor in connection with its distribution of the Program

+in a commercial product offering. The obligations in this section do not

+apply to any claims or Losses relating to any actual or alleged

+intellectual property infringement. In order to qualify, an Indemnified

+Contributor must: a) promptly notify the Commercial Contributor in

+writing of such claim, and b) allow the Commercial Contributor to control,

+and cooperate with the Commercial Contributor in, the defense and any

+related settlement negotiations. The Indemnified Contributor may

+participate in any such claim at its own expense.

+

+For example, a Contributor might include the Program in a commercial

+product offering, Product X. That Contributor is then a Commercial

+Contributor. If that Commercial Contributor then makes performance

+claims, or offers warranties related to Product X, those performance

+claims and warranties are such Commercial Contributor's responsibility

+alone. Under this section, the Commercial Contributor would have to

+defend claims against the other Contributors related to those performance

+claims and warranties, and if a court requires any other Contributor to

+pay any damages as a result, the Commercial Contributor must pay

+those damages.

+

+5. NO WARRANTY

+

+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT

+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"

+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR

+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF

+TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR

+PURPOSE. Each Recipient is solely responsible for determining the

+appropriateness of using and distributing the Program and assumes all

+risks associated with its exercise of rights under this Agreement,

+including but not limited to the risks and costs of program errors,

+compliance with applicable laws, damage to or loss of data, programs

+or equipment, and unavailability or interruption of operations.

+

+6. DISCLAIMER OF LIABILITY

+

+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT

+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS

+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST

+PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE

+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE

+POSSIBILITY OF SUCH DAMAGES.

+

+7. GENERAL

+

+If any provision of this Agreement is invalid or unenforceable under

+applicable law, it shall not affect the validity or enforceability of

+the remainder of the terms of this Agreement, and without further

+action by the parties hereto, such provision shall be reformed to the

+minimum extent necessary to make such provision valid and enforceable.

+

+If Recipient institutes patent litigation against any entity

+(including a cross-claim or counterclaim in a lawsuit) alleging that the

+Program itself (excluding combinations of the Program with other software

+or hardware) infringes such Recipient's patent(s), then such Recipient's

+rights granted under Section 2(b) shall terminate as of the date such

+litigation is filed.

+

+All Recipient's rights under this Agreement shall terminate if it

+fails to comply with any of the material terms or conditions of this

+Agreement and does not cure such failure in a reasonable period of

+time after becoming aware of such noncompliance. If all Recipient's

+rights under this Agreement terminate, Recipient agrees to cease use

+and distribution of the Program as soon as reasonably practicable.

+However, Recipient's obligations under this Agreement and any licenses

+granted by Recipient relating to the Program shall continue and survive.

+

+Everyone is permitted to copy and distribute copies of this Agreement,

+but in order to avoid inconsistency the Agreement is copyrighted and

+may only be modified in the following manner. The Agreement Steward

+reserves the right to publish new versions (including revisions) of

+this Agreement from time to time. No one other than the Agreement

+Steward has the right to modify this Agreement. The Eclipse Foundation

+is the initial Agreement Steward. The Eclipse Foundation may assign the

+responsibility to serve as the Agreement Steward to a suitable separate

+entity. Each new version of the Agreement will be given a distinguishing

+version number. The Program (including Contributions) may always be

+Distributed subject to the version of the Agreement under which it was

+received. In addition, after a new version of the Agreement is published,

+Contributor may elect to Distribute the Program (including its

+Contributions) under the new version.

+

+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient

+receives no rights or licenses to the intellectual property of any

+Contributor under this Agreement, whether expressly, by implication,

+estoppel or otherwise. All rights in the Program not expressly granted

+under this Agreement are reserved. Nothing in this Agreement is intended

+to be enforceable by any entity that is not a Contributor or Recipient.

+No third-party beneficiary rights are created under this Agreement.

+

+Exhibit A - Form of Secondary Licenses Notice

+

+"This Source Code may also be made available under the following 

+Secondary Licenses when the conditions for such availability set forth 

+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),

+version(s), and exceptions or additional permissions here}."

+

+  Simply including a copy of this Agreement, including this Exhibit A

+  is not sufficient to license the Source Code under Secondary Licenses.

+

+  If it is not possible or desirable to put the notice in a particular

+  file, then You may include the notice in a location (such as a LICENSE

+  file in a relevant directory) where a recipient would be likely to

+  look for such a notice.

+

+  You may add additional accurate notices of copyright ownership.
\ No newline at end of file
diff --git a/SCTP_CNL113840.tpd b/SCTP_CNL113840.tpd
new file mode 100644
index 0000000..0df43e7
--- /dev/null
+++ b/SCTP_CNL113840.tpd
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<TITAN_Project_File_Information version="1.0">
+  <ProjectName>SCTP_CNL113840</ProjectName>
+  <ReferencedProjects>
+    <ReferencedProject name="SCTP_CNL113830" projectLocationURI="../../ProtocolModules/SCTP_CNL113830/SCTP_CNL113830.tpd"/>
+  </ReferencedProjects>
+  <Files>
+    <FileResource projectRelativePath="SCTP_Engine_Core.ttcn" relativeURI="src/SCTP_Engine_Core.ttcn"/>
+    <FileResource projectRelativePath="SCTP_Engine_Definition.ttcn" relativeURI="src/SCTP_Engine_Definition.ttcn"/>
+    <FileResource projectRelativePath="SCTP_Engine_External_Functions.cc" relativeURI="src/SCTP_Engine_External_Functions.cc"/>
+    <FileResource projectRelativePath="SCTP_Engine_Functions.ttcn" relativeURI="src/SCTP_Engine_Functions.ttcn"/>
+    <FileResource projectRelativePath="SCTP_Engine_PortTypes.ttcn" relativeURI="src/SCTP_Engine_PortTypes.ttcn"/>
+    <FileResource projectRelativePath="SCTP_Engine_Templates.ttcn" relativeURI="src/SCTP_Engine_Templates.ttcn"/>
+  </Files>
+  <ActiveConfiguration>Default</ActiveConfiguration>
+  <Configurations>
+    <Configuration name="Default">
+      <ProjectProperties>
+        <MakefileSettings>
+          <generateInternalMakefile>true</generateInternalMakefile>
+          <GNUMake>true</GNUMake>
+          <incrementalDependencyRefresh>true</incrementalDependencyRefresh>
+          <targetExecutable>bin/SCTP_CNL113840</targetExecutable>
+        </MakefileSettings>
+        <LocalBuildSettings>
+          <workingDirectory>bin</workingDirectory>
+        </LocalBuildSettings>
+      </ProjectProperties>
+    </Configuration>
+  </Configurations>
+</TITAN_Project_File_Information>
\ No newline at end of file
diff --git a/doc/SCTP_CNL113840_1551.doc b/doc/SCTP_CNL113840_1551.doc
new file mode 100644
index 0000000..3c0acc8
--- /dev/null
+++ b/doc/SCTP_CNL113840_1551.doc
Binary files differ
diff --git a/doc/SCTP_CNL113840_PRI.doc b/doc/SCTP_CNL113840_PRI.doc
new file mode 100644
index 0000000..eab15cf
--- /dev/null
+++ b/doc/SCTP_CNL113840_PRI.doc
Binary files differ
diff --git a/src/SCTP_Engine_Core.ttcn b/src/SCTP_Engine_Core.ttcn
new file mode 100644
index 0000000..2483edc
--- /dev/null
+++ b/src/SCTP_Engine_Core.ttcn
@@ -0,0 +1,205 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v2.0
+// which accompanies this distribution, and is available at
+// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+///////////////////////////////////////////////////////////////////////////////
+//
+//  File:               SCTP_Engine_Core.ttcn
+//  Description:        Core functions of the SCTP Engine
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 840
+//
+module SCTP_Engine_Core{
+
+import from SCTP_Engine_Definition all;
+import from SCTP_Engine_PortTypes all
+import from SCTP_Engine_Functions all
+import from SCTP_Types all
+
+//***************************************************************************//
+// 
+//   The main function, it should be started 
+// 
+//***************************************************************************//
+function SCTP_Core_main() runs on SCTP_Engine_CT {
+  // Start the run timer
+  t_run_time.start(2147482.0) // ~24 days. Can be set higher, but in that case
+                              // the TITAN will flood the log with stupid warning
+
+  // Activate the handler altsteps
+  alt{
+    [] SCTP_core_lower_handler()
+    [] SCTP_Core_timer_handler()
+    [] SCTP_Core_upper_handler()
+  }
+
+  
+}
+
+
+
+//***************************************************************************//
+// 
+//   Upper port event handler functions
+// 
+//***************************************************************************//
+
+altstep SCTP_Core_upper_handler() runs on SCTP_Engine_CT {
+  var SCTP_Listen_data  vl_listen_data;
+  var SCTP_Connect_data  vl_connect_data;
+  var SCTP_Engine_CT    vl_sender;
+  var SCTP_MSG_data  vl_send_msg_data ;
+  var SCTP_Shutdown_data  vl_shutdown_data ;
+  var SCTP_Reconfiguration_req vl_reconfig;
+  var integer vl_assoc_id;
+
+  [] p_sctp_req_api.getcall(S_SCTP_Listen:{?}) -> param (vl_listen_data) sender vl_sender{
+       SCTP_api_handle_listen(vl_listen_data,vl_sender)
+       repeat;
+     }
+  [] p_sctp_req_api.getcall(S_SCTP_Connect:{?}) -> param (vl_connect_data) sender vl_sender{
+       SCTP_api_handle_connect(vl_connect_data,vl_sender)
+       repeat;
+     }
+  [] p_sctp_req_api.getcall(S_SCTP_Send_req:{?}) -> param (vl_send_msg_data) sender vl_sender{
+       SCTP_api_handle_send_msg(vl_send_msg_data,vl_sender)
+       repeat;
+     }
+
+  [] p_sctp_req_api.getcall(S_SCTP_Shutdown:{?}) -> param (vl_shutdown_data) sender vl_sender{
+       SCTP_api_handle_shutdown(vl_shutdown_data,vl_sender)
+       repeat;
+     }
+
+  [] p_sctp_req_api.getcall(S_SCTP_Shutdown_conf:{?}) -> param (vl_assoc_id) sender vl_sender{
+       SCTP_api_handle_shutdown_conf(vl_assoc_id,vl_sender)
+       repeat;
+     }
+
+  [] p_sctp_req_api.getcall(S_SCTP_reconfig:{?}) -> param (vl_reconfig) sender vl_sender{
+       SCTP_api_handle_reconfig(vl_reconfig,vl_sender)
+       repeat;
+     }
+
+}
+
+//***************************************************************************//
+// 
+//   Time event handler functions
+// 
+//***************************************************************************//
+altstep SCTP_Core_timer_handler() runs on SCTP_Engine_CT {
+  [] t_next_event.timeout {
+       // Store the event data
+       var integer vl_assoc_id:=v_event_db.events[v_event_db.the_sceduled_event].assoc_id
+       var integer vl_timer_id:=v_event_db.events[v_event_db.the_sceduled_event].timer_id
+       // remove the event from the queue
+       SCTP_event_remove(v_event_db.the_sceduled_event)
+       
+       // Call the timer handler
+       select(vl_timer_id){
+         case (c_timer_T1) {
+           SCTP_timeout_T1_init(vl_assoc_id)
+         }
+         case (c_timer_T1_cookie) {
+           SCTP_timeout_T1_cookie(vl_assoc_id)
+         }
+         case (c_timer_T3_rtx) {
+           SCTP_timeout_T3_rtx(vl_assoc_id)
+         }
+         case (c_timer_T2_shutdown) {
+           SCTP_timeout_T2_shutdown(vl_assoc_id)
+         }
+         case (c_timer_heartbeat) {
+           SCTP_timeout_heartbeat(vl_assoc_id)
+         }
+         case (c_timer_reconfig) {
+           SCTP_timeout_reconfig(vl_assoc_id)
+         }
+         case (c_timer_close) {
+           SCTP_timeout_close(vl_assoc_id)
+         }
+      }
+       repeat;
+     }
+}
+
+
+//***************************************************************************//
+// 
+//   Lower port event handler functions
+// 
+//***************************************************************************//
+
+altstep SCTP_core_lower_handler() runs on SCTP_Engine_CT {
+  var SCTP_Engine_packet vl_recv_packet;
+  var SCTP_Packet        vl_sctp_pdu; 
+  var integer            vl_decode_res;
+
+  [] p_packet_port.receive(SCTP_Engine_packet:?) -> value  vl_recv_packet {
+       // Process the incoming sctp packet
+       vl_decode_res:=f_SCTP_dec(vl_recv_packet.sctp_packet,vl_sctp_pdu);
+       //log("received: ",vl_decode_res)
+       if(vl_decode_res==0){ // Decode OK
+         // Find the association
+         var integer vl_assoc_id:=SCTP_find_id_map(vl_recv_packet.transport_id,
+                    // incoming packet, the destination port is the local port                
+                                    vl_sctp_pdu.common_header.destination_port,
+                                    vl_sctp_pdu.common_header.source_port)
+         
+         //log("assoc id ",vl_assoc_id)
+         if(vl_assoc_id != -1 ){  // we found the assoctiation
+           SCTP_message_incoming_handler(vl_assoc_id,vl_sctp_pdu);
+           repeat;
+         } else {
+           // if it is an INIT or COOKIE ECHO chunk, try to find the listening 
+           // association
+           if((lengthof(vl_sctp_pdu.chunks)>0) and 
+              (ischosen(vl_sctp_pdu.chunks[0].init) 
+               or ischosen(vl_sctp_pdu.chunks[0].cookie_echo) )
+              ){
+              // Lets find the listening association
+              vl_assoc_id:=SCTP_find_id_map(vl_recv_packet.transport_id,
+                    // incoming packet, the destination port is the local port                
+                                    vl_sctp_pdu.common_header.destination_port,
+                                    // the remote port is 0 for listening assoc
+                                    0)
+              if(vl_assoc_id == -1){
+                // The listening assoc_id is not found
+                // Look for assoc listening on all transport
+                vl_assoc_id:=SCTP_find_id_map(-1, // All transport
+                    // incoming packet, the destination port is the local port                
+                                    vl_sctp_pdu.common_header.destination_port,
+                                    // the remote port is 0 for listening assoc
+                                    0)
+                
+              }
+              
+              
+              if(vl_assoc_id != -1 ){  // we found the assoctiation
+                SCTP_message_incoming_init_cookie_handler(vl_assoc_id,
+                               vl_recv_packet.transport_id, vl_sctp_pdu);
+                repeat; 
+              }
+           }
+         }
+         // Not processed message, Out of the blue packet
+         // Send abort
+         SCTP_message_process_oob_packet(vl_recv_packet.transport_id, vl_sctp_pdu);
+       } else {
+         // What the hell we received?
+         log("Undecodable packet: ", vl_recv_packet);
+         // just drop it
+       }
+       repeat;
+     }
+
+  [] p_packet_port.receive(SCTP_Addr_change_notification:?) {
+         repeat;
+       }
+
+}
+
+}
diff --git a/src/SCTP_Engine_Definition.ttcn b/src/SCTP_Engine_Definition.ttcn
new file mode 100644
index 0000000..40c4479
--- /dev/null
+++ b/src/SCTP_Engine_Definition.ttcn
@@ -0,0 +1,414 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v2.0
+// which accompanies this distribution, and is available at
+// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+///////////////////////////////////////////////////////////////////////////////
+//
+//  File:               SCTP_Engine_Definition.ttcn
+//  Description:        Component definition of the SCTP Engine
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 840
+//
+module SCTP_Engine_Definition {
+
+import from SCTP_Engine_PortTypes all;
+import from SCTP_Types all;
+
+modulepar SCTP_Proto_params tsp_proto_params:={ rto_initial := 3.0,
+                                                rto_min := 1.0,
+                                                rto_max := 60.0,
+                                                max_burst := 4,
+                                                rto_alpha := 0.125,
+                                                rto_beta := 0.25,
+                                                valid_cookie_life :=60,
+                                                assoc_max_retrans := 10,
+                                                path_max_retrans := 5,
+                                                max_init_retrans := 8,
+                                                hb_interval := 30.0,
+                                                hb_max_burst :=1,
+                                                
+                                                // MTU discovery parameters
+                                                pmntu_min := 900, // This value is used to calculate the data chunk size
+                                                                 // The maximum data chunk size is 
+                                                                 // pmntu_min - SCTP_common_header_size
+                                                                 // This ensures that the data chunk can be delivered every cases
+                                                                 // Normal ethernet frame size - (vpn,DTLS,UDP,IPv4 or IPv6) - something more
+                                                pmtu_max := 8960, // For Jumbo frames
+                                                
+                                                pmtu_initial := 1200 // WebRTC draft
+
+                                              }
+
+modulepar SCTP_Reconfig_config tsp_reconf_params:={
+  is_supported := true,
+  stream_reset_allowed:= true,
+  assoc_reset_allowed:= true,
+  stream_add_allowed:= true
+}
+
+modulepar boolean tsp_forward_tsn_supported := true
+
+type component SCTP_Engine_CT {
+// Test ports
+  port SCTP_Engine_API_request_PT      p_sctp_req_api  // the upper side, SCTP test port
+  port SCTP_Engine_API_indication_PT   p_sctp_ind_api  // the upper side, SCTP test port
+  port SCTP_Engine_packet_PT   p_packet_port  // The lower side test port
+
+// main database
+  var SCTP_Assoc_DB_t          v_assoc_db := c_empty_SCTP_Assoc_DB // The association data base
+
+  var octetstring v_secret_key := '11223344556677889900'O // the key used to generate MAC of the state cookie
+
+
+// time & event queue handling
+  timer t_run_time            // timer used to mesure the time, started once
+                              // with a very-very long timeout
+  timer t_next_event          // expires on the next scheduled event
+  
+  var SCTP_event_db_t          v_event_db:= c_empty_event_db // Event queue database  
+  var SCTP_Assoc_data c_empty_SCTP_Assoc_data:={
+                                state := SCTP_ASSOC_CLOSED,
+                                transport_id:=-1,
+                                local_port:=-1,
+                                remote_port:=-1,
+                                own_tag:=-1,
+                                remote_tag:=-1,
+                                cookie_validity:=-1,
+                                remote_tsn:=-1,
+                                own_tsn:=-1,
+                                remote_os:=-1,
+                                remote_mis:=-1,
+                                remote_a_rwnd:=-1,
+                                cookie_lifespan:=-1,
+                                state_cookie := ''O,
+                                rem_comp := null,
+                                i_data_supported := false,
+                                proto_params := tsp_proto_params,
+                                retransmit_counter:=0,
+                                retransmit_timer_event := -1,
+                                rto:=tsp_proto_params.rto_initial,
+                                srtt:=0.0,
+                                rttvar:=0.0,
+                                pmtu:=tsp_proto_params.pmtu_initial,
+                                tx_msg_queues := {},
+                                tx_stream_idx_map_id := -1,
+                                tx_chunk_queue := c_empty_chunk_queue_db,
+                                cwnd:=0,
+                                flight_size:=0,
+                                partially_acked_bytes:=0,
+                                ssthresh := 0,
+                                scheduled_queue := 0,
+                                remote_last_sack_tsn := -1,
+                                rx_chunk_queue := c_empty_chunk_queue_db,
+                                idx_of_last_acked := -1,
+                                rx_msg_queues := {},
+                                rx_stream_idx_map_id := -1,
+                                hb_event_id := -1,
+                                hb_retrial_counter := 0,
+                                data_chunk_max_size := tsp_proto_params.pmntu_min-12, // 12: SCTP common header size. See up
+                                reconf_params:=tsp_reconf_params,
+                                reconf_own_seq_num:=-1,
+                                reconf_remote_seq_num:=-1,
+                                reconfig_ongoing := false,
+                                forward_tsn_supported:=tsp_forward_tsn_supported,
+                                reconfig_event_id := -1,
+                                ongoing_incoming_reconf_req_seq := -1,
+                                ongoing_outgoing_reconf_req_seq := -1,
+                                last_reconf_resp := omit,
+                                last_reconf_req := omit,
+                                deffered_reset := omit,
+                                reconfig_retransmit_counter:=0,
+                                close_timer := -1
+                              }
+}
+
+// Type for association data base
+type record SCTP_Assoc_DB_t{
+  // the data base realized by the list of the association entries.
+  // Each entries are not removed from the list, but reused if needed.
+  // In order to track the free elements, the free entries forms a linked list
+  // holding the index of the next free entry.
+  // The index of first  & last free entries are stored also.
+  
+  
+  integer       used_entries, // How many entries are used.
+  integer       first_free, // points to the first free 
+  integer       last_free,  // points to the last free
+  
+  SCTP_Assoc_entry_list   associations  // The list of the entries
+}
+// constant used to initialize the v_assoc_db
+const SCTP_Assoc_DB_t c_empty_SCTP_Assoc_DB:={
+  used_entries := 0,
+  first_free   :=-1,
+  last_free    :=-1,
+  associations :={}
+}
+
+type record of SCTP_Assoc_entry SCTP_Assoc_entry_list
+
+type record SCTP_Assoc_entry {
+  integer             next_free,  // points to the next free entry if not used
+  SCTP_Assoc_data     assoc_data optional // holds the data of the association
+                                          // if the entry is not used, the data
+                                          // is ommited in order to free the
+                                          // memory
+}
+
+const SCTP_Assoc_entry c_empty_SCTP_Assoc_entry:={
+  next_free := -1,
+  assoc_data := omit
+}
+
+
+// The value of the enumeration is ordered, so a range can be specified
+type enumerated SCTP_Assoc_state { SCTP_ASSOC_LISTEN(0),
+   SCTP_ASSOC_COOKIE_WAIT(1),SCTP_ASSOC_COOKIE_ECHOED(2),
+   SCTP_ASSOC_ESTABLISHED(3), 
+   SCTP_ASSOC_SHUTDOWN_PENDING(4), SCTP_ASSOC_SHUTDOWN_RECEIVED(5),
+   SCTP_ASSOC_SHUTDOWN_SENT(6),
+   SCTP_ASSOC_SHUTDOWN_ACK_SENT(7), SCTP_ASSOC_CLOSED(8),
+   SCTP_ASSOC_CLOSE_TIME_WAIT(9) }
+
+// holds the data belongs to the association
+type record SCTP_Assoc_data {
+  SCTP_Assoc_state state,
+
+  integer    transport_id,  // The transport id
+  integer    local_port,    // Local sctp port number
+  integer    remote_port,   // Remote sctp port number
+  integer    own_tag,       // Own verification tag, The incoming message should come with this
+  integer    remote_tag,    // Remotes verification tag, set in the outgoing message
+  integer    cookie_validity, // 0 - Cookie ok, 1- Cokkie expired. See the return value of SCTP_check_state_cookie
+  integer    remote_tsn,    // remote initial tsn, last sent SACK tsn + 1
+  integer    own_tsn,       // own next tsn/ initial tsn
+  integer    remote_os,     // remote outgoing sream number
+  integer    remote_mis,    // remote's max incoming stream number
+  integer    remote_a_rwnd, // remote advertised receive window
+  integer    cookie_lifespan, // The lifespan of our state cookie
+  
+  octetstring state_cookie,  // the stored received state cookie, used for retransmission
+  
+  SCTP_Engine_CT  rem_comp,  // The component id of sctp user component
+  
+  boolean    i_data_supported, // Support I-DATA chunk
+  
+  SCTP_Proto_params  proto_params,  // SCTP protocol parameters of the association
+  integer    retransmit_counter,    // the messages was retransmitted that many time without answer
+  integer    retransmit_timer_event, // The event id of the retransmitt timer
+  float      rto,           // RTO
+  float      srtt,          // SRTT
+  float      rttvar,        // RTTVAR see: RFC 4960 6.3.  Management of Retransmission Timer
+  
+  integer    pmtu,          // The Path MTU 
+  
+  // Message queues
+  SCTP_msg_queue_list_t  tx_msg_queues,  // The queues of the TX messages, every stream has an own queue
+                                         // the Nth queue is the ordered msg queue, that idx is stored in the map below
+                                         // the N+1 th is for the unordered
+  integer    tx_stream_idx_map_id,  // The ID of the stream -> queue idx map, tells which stream belongs to which queue
+  
+  SCTP_Chunk_queue_db_t tx_chunk_queue,  // the TX DATA chunk queue
+  
+  // Congestion control data see the rfc 4690
+  integer    cwnd,                // congestion window
+  integer    flight_size,         // sent but not acked bytes
+  integer    partially_acked_bytes,  // partially acknowledged bytes
+  
+  integer    ssthresh,    // Slow start treshold
+  
+  integer    scheduled_queue,  // the message from that queue will be sent
+  
+  integer    remote_last_sack_tsn,  // The latest TSN acked by the remote
+
+  SCTP_Chunk_queue_db_t rx_chunk_queue,  // the RX DATA chunk queue, used for reassembly
+  // How the queue is used: When a data chunk is received, it will be inserted into the queue
+  // If there are missing data chunk, a dummy placeholder is inserted into the queue
+  // The chunk field of the queue element is omited in that case
+  
+  integer    idx_of_last_acked,   // the index of the last acked chunk in the queue
+
+  SCTP_msg_queue_list_t  rx_msg_queues,  // The queues of the RX messages, every stream has an own queue
+                                         // the Nth queue is the ordered msg queue, that idx is stored in the map below
+                                         // the N+1 th is for the unordered
+
+  integer    rx_stream_idx_map_id,  // The ID of the stream -> rx queue idx map, tells which stream belongs to which queue
+  
+  
+  integer    hb_event_id,              // The event id of the scheduled heartbeat event
+  integer    hb_retrial_counter,        // The heatbeat retrial counter
+  integer    data_chunk_max_size,      // the maximum size of the data chunk
+  
+  SCTP_Reconfig_config reconf_params,    // reconfiguration extension RFC6525
+  integer reconf_own_seq_num,            // our next seq number/ initial one
+  integer reconf_remote_seq_num ,        // our next expected
+  boolean reconfig_ongoing,
+  
+  boolean    forward_tsn_supported, // indicates the support of RFC3758
+  
+  integer reconfig_event_id,
+  integer ongoing_incoming_reconf_req_seq,  // store the initiated "incomig type request": Incoming SSN Reset, Add Incoming Streams
+  integer ongoing_outgoing_reconf_req_seq,  // store the initiated "outgoing type request": Outgoing SSN Reset, Add Outgoing Streams, SSN/TSN Reset Request
+  SCTP_Re_Config_chunk last_reconf_resp optional, // stores the last reconf response chunk for retransmission
+  SCTP_Re_Config_chunk last_reconf_req optional, // stores the last reconf request chunk for retransmission
+  SCTP_Out_SSN_Reset_req_parameter deffered_reset optional, // stores the reconf request for "deferred reset processing"
+  integer reconfig_retransmit_counter,
+  integer close_timer
+}
+
+
+// Parameters for reconfiguration extension RFC6525
+/*type record SCTP_Reconf_data {
+  boolean is_supported,
+  boolean stream_reset_allowed,
+  boolean assoc_reset_allowed,
+  boolean stream_add_allowed
+}*/
+
+// The type holds the SCTP Protocol Parameters
+// See RFC4960 chapter 15
+type record SCTP_Proto_params{
+  float     rto_initial,
+  float     rto_min,
+  float     rto_max,
+  integer   max_burst,
+  float     rto_alpha,
+  float     rto_beta,
+  integer   valid_cookie_life,
+  integer   assoc_max_retrans,
+  integer   path_max_retrans,
+  integer   max_init_retrans,
+  float     hb_interval,
+  integer   hb_max_burst,
+  integer   pmntu_min,
+  integer   pmtu_max,
+
+ integer    pmtu_initial
+}
+
+
+// Event handling database
+// All of the scheduled events are stored in the event DB
+// One event DB entry stores the <assoc_id, timer_id>
+// the t_next_event timer is sceduled for the earliest event
+// in the case of timeout, adding or deleting event, the timer is recalculated
+// The events are stored in the same way as the assoc DB
+// The order of the events are stored & maintained in an external ordered std::map
+type record SCTP_event_db_t{
+  integer       used_entries, // How many entries are used.
+  integer       first_free, // points to the first free 
+  integer       last_free,  // points to the last free
+  
+  integer       the_sceduled_event, // That event is used to start the t_next_event timer
+  
+  SCTP_event_entry_list   events  // The list of the events
+}
+
+const SCTP_event_db_t c_empty_event_db:={
+  used_entries := 0,
+  first_free   :=-1,
+  last_free    :=-1,
+  the_sceduled_event := -1,
+  events :={}
+}
+
+type record of SCTP_event_entry SCTP_event_entry_list
+
+type record SCTP_event_entry {
+  integer             next_free,  // points to the next free entry if not used
+  integer             assoc_id,   // the event is scheduled by this assoc
+  integer             timer_id,   // the id of the assoc timer
+  float               timeout_time // The absulute time of the timeout
+                                   // calculated as 'time_since_start' + 'timeout_val'
+}
+
+const SCTP_event_entry c_empty_event_entry:={
+  next_free:=-1,
+  assoc_id:=-1,
+  timer_id:=-1,
+  timeout_time:=-1.0
+}
+
+// Data types for queues
+
+// Chunk queue
+// Simple linked list, with free queue
+type record SCTP_Chunk_queue_db_t{
+  integer           used_entries, // How many entries are used.
+  integer           first_free, // points to the first free 
+  integer           last_free,  // points to the last free
+  integer           first_element, // points to the head of the chunk queue
+  integer           last_element, // points to the tail of the chunk queue
+  
+  SCTP_Chunk_queue_element_list_t   chunk_queue
+}
+
+const SCTP_Chunk_queue_db_t c_empty_chunk_queue_db:={
+  used_entries := 0,
+  first_free   :=-1,
+  last_free    :=-1,
+  first_element :=-1,
+  last_element := -1,
+  chunk_queue :={}
+}
+
+type record of SCTP_Chunk_queue_element_t SCTP_Chunk_queue_element_list_t
+
+type record SCTP_Chunk_queue_element_t {
+  integer   next_element,
+  boolean   mark_flag,  // used to mark the chunk in the queue:
+                        // tx chunk queue: mark for retransmit
+                        // rx chunk queue: added to the rx stream queue
+  float     lifetime,   // Used on sender side, partial reliability feature
+  integer   counter,    // Used on sender side, partial reliability feature
+  boolean   unmark_flag, // tx queues: mark for abandon
+  integer   tsn,
+  SCTP_Chunk chunk  optional
+}
+
+const SCTP_Chunk_queue_element_t c_empty_Chunk_queue_element:={
+  next_element := -1,
+  mark_flag := false,
+  lifetime := -1.0,
+  counter := -1,
+  unmark_flag := false,
+  tsn := -1,
+  chunk := omit
+}
+
+// TX message queue types
+// Every outgoing stream has its own queue
+
+// represents one msg queue
+type record SCTP_msg_queue_t {
+  integer next_ssn,  // the next SSN for the stream
+  integer num_of_queued_octets, // The number of the octets of the first message already put into the TX queue
+  boolean flag,
+  SCTP_Chunk_queue_db_t messages  // Each message is represented by a DATA chunk
+}
+
+const SCTP_msg_queue_t c_empty_msg_queue:={
+  next_ssn := 0,
+  num_of_queued_octets := 0,
+  flag:=false,
+  messages := c_empty_chunk_queue_db
+}
+
+type record of SCTP_msg_queue_t SCTP_msg_queue_list_t
+
+type record of integer integer_list
+
+// Timer constants
+const integer c_timer_T1 := 0;
+const integer c_timer_T1_cookie := 1;
+const integer c_timer_T3_rtx := 2;
+const integer c_timer_T2_shutdown := 3;
+const integer c_timer_heartbeat := 4;
+const integer c_timer_reconfig := 5;
+const integer c_timer_close := 6;
+
+const integer c_min_chunk_size := 24  // The minimum data chunk size we use
+
+}
diff --git a/src/SCTP_Engine_External_Functions.cc b/src/SCTP_Engine_External_Functions.cc
new file mode 100644
index 0000000..5bd0b82
--- /dev/null
+++ b/src/SCTP_Engine_External_Functions.cc
@@ -0,0 +1,315 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v2.0
+// which accompanies this distribution, and is available at
+// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+///////////////////////////////////////////////////////////////////////////////
+//
+//  File:               SCTP_Engine_ExternalFunctions.cc
+//  Description:        function definition of the SCTP Engine
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 840
+//
+#include "SCTP_Engine_Functions.hh"
+#include <map>
+#include <vector>
+#include <queue> 
+#include <stdint.h>
+#include <openssl/md5.h>
+#include <openssl/hmac.h>
+#include <time.h>
+
+typedef std::map<uint64_t,int> id_map_t;
+typedef id_map_t::iterator id_map_it_t;
+
+typedef std::map<uint64_t,uint64_t> ii_map_t;
+typedef ii_map_t::iterator ii_map_it_t;
+
+// Map to store assoc-id <-> (transport_id,local_port,remote_port) mapping
+// The (transport_id,local_port,remote_port) concatenated into a 
+// 64 unsigned int value to form the key
+static id_map_t id_map;
+
+
+
+// Event scheduler types and map
+// std::multimap type is used, because it stores the elements in a 
+// specific order
+// We need to order the event by the scheduled time -> use the time as key
+typedef std::multimap<double,int> event_map_t;
+typedef event_map_t::iterator event_map_it_t;
+static event_map_t event_map;
+
+
+// We need int2int maps for every association
+// - outgoing stream-id -> queue index
+// - incoming stream-id -> queue index
+//
+// These maps are allocated at the assoc creation and freed at the assoc deletion
+//
+
+static std::vector<ii_map_t*> ii_map_vector;
+static std::queue<int> ii_empty_queue;  // stores the index of free/reusable elements
+
+namespace SCTP__Engine__Functions {
+
+//***************************************************************************//
+// 
+//   int2int map handler functions
+// 
+//***************************************************************************//
+INTEGER SCTP__int2int__new(){
+  int idx=-1;
+  if(ii_empty_queue.empty()){
+    // No free item, add one
+    idx=ii_map_vector.size();
+    ii_map_vector.push_back(NULL);
+    
+  } else {
+    // get the index of the free item
+    idx=ii_empty_queue.front();
+    ii_empty_queue.pop();
+  }
+  ii_map_vector[idx]=new ii_map_t;
+  
+  return idx;
+
+}
+
+void SCTP__int2int__delete(INTEGER const&pl_map_id){
+  int idx=(int)pl_map_id;
+  if( idx>=0 && idx<(int)ii_map_vector.size() && ii_map_vector[idx] != NULL){
+    // valid index
+    // delete the map
+    delete ii_map_vector[idx];
+    ii_map_vector[idx]=NULL;
+    // put the map index into the empty queue
+    ii_empty_queue.push(idx);
+  }
+}
+
+INTEGER SCTP__int2int__add(INTEGER const& pl_map_id, INTEGER const& pl_key, INTEGER const& pl_value){
+  int idx=(int)pl_map_id;
+  if( idx>=0 && idx<(int)ii_map_vector.size() && ii_map_vector[idx] != NULL){
+    // valid index
+    
+    (*(ii_map_vector[idx]))[(uint64_t)pl_key.get_long_long_val()]=(uint64_t)pl_value.get_long_long_val();
+    return 0;
+  }
+  return -1;
+}
+
+INTEGER SCTP__int2int__get(INTEGER const& pl_map_id, INTEGER const& pl_key, INTEGER& pl_value){
+  int idx=(int)pl_map_id;
+  if( idx>=0 && idx<(int)ii_map_vector.size() && ii_map_vector[idx] != NULL){
+    // valid index
+    ii_map_it_t it=(ii_map_vector[idx])->find((uint64_t)pl_key.get_long_long_val());
+    if(it!=(ii_map_vector[idx])->end()){
+      // valid key
+      pl_value.set_long_long_val(it->second);
+      return 0;
+    }
+  }
+
+  return -1;
+}
+//***************************************************************************//
+// 
+//   assoc-id <-> (transport_id,local_port,remote_port) map handler functions
+// 
+//***************************************************************************//
+
+// Constructs the 64 bit key value
+uint64_t get_id(const int64_t tr_id, const uint64_t loc_port, const uint64_t rem_port){
+  uint64_t vl_tr_id=0;
+  // the tr_id can be -1 => all transport => translate to all 1's
+  if(tr_id>=0){
+    vl_tr_id = tr_id;
+  } else {
+    vl_tr_id = ~vl_tr_id;
+  }
+  return (vl_tr_id << 32 ) | ((loc_port & 0xff) << 16 ) | (rem_port & 0xff);
+}
+
+INTEGER SCTP__add__id__map(INTEGER const& vl_assoc_id, 
+                   INTEGER const& vl_transport_id, 
+                   INTEGER const& vl_local_port, 
+                   INTEGER const& vl_remote_port){
+  
+  uint64_t key=get_id(vl_transport_id.get_long_long_val(),(int)vl_local_port,(int)vl_remote_port);
+  
+  if(id_map.find(key) == id_map.end()){
+    // if the key is not found, we can insert it 
+    id_map[key]=(int)vl_assoc_id;
+    
+    return 0;
+  }
+  // the key is found, return error
+  return -1;
+}
+INTEGER SCTP__del__id__map(INTEGER const& vl_transport_id, 
+                           INTEGER const& vl_local_port, 
+                           INTEGER const& vl_remote_port){
+  uint64_t key=get_id(vl_transport_id.get_long_long_val(),(int)vl_local_port,(int)vl_remote_port);
+  id_map_it_t it=id_map.find(key);
+  if(it != id_map.end()){
+    // found the key, delete it.
+    id_map.erase(it);
+    return 0; // Success
+  }
+  // the key is not found, return error
+  return -1;
+
+}
+INTEGER SCTP__find__id__map(INTEGER const& vl_transport_id, 
+                            INTEGER const& vl_local_port, 
+                            INTEGER const& vl_remote_port){
+  uint64_t key=get_id(vl_transport_id.get_long_long_val(),(int)vl_local_port,(int)vl_remote_port);
+  id_map_it_t it=id_map.find(key);
+  if(it != id_map.end()){
+    // found the key, return the assoc_id.
+
+    return it->second; // Success
+  }
+  // the key is not found, return error
+  return -1;
+
+}
+
+//***************************************************************************//
+// 
+//   State cookie handler functions
+// 
+//***************************************************************************//
+
+OCTETSTRING SCTP__gen__state__cookie(INTEGER const& pl_lifespan, 
+                                     INTEGER const& pl_own_init_tag, 
+                                     INTEGER const& pl_remote_init_tag, 
+                                     INTEGER const& pl_tie_tag, 
+                                     INTEGER const& pl_remote_tsn, 
+                                     INTEGER const& pl_remote_os, 
+                                     INTEGER const& pl_remote_mis, 
+                                     INTEGER const& pl_remote_a_rwnd, 
+                                     BOOLEAN const& pl_idata_flag,
+                                     BOOLEAN const& pl_reconf_flag,
+                                     BOOLEAN const& pl_forward_tsn_flag,
+                                     OCTETSTRING const& pl_key){
+
+  time_t tstamp_t=time(NULL);
+  int tstamp_i = (tstamp_t &0x7fffffff ); // to calculate the lifespan of teh cookie
+                                          // the lowest 31 bit is enough
+
+  int lifespan = (int)pl_lifespan & 0xffff;
+  
+  int zero = 0;
+  int ones = ~0;
+
+  OCTETSTRING ret_val= int2oct(tstamp_i,4) + int2oct(lifespan,2) + 
+                       int2oct(pl_own_init_tag,4)+ int2oct(pl_remote_init_tag,4)
+                       + int2oct(pl_tie_tag,4)
+                       + int2oct(pl_remote_tsn,4)+ int2oct(pl_remote_os,2)
+                       + int2oct(pl_remote_mis,2)+ int2oct(pl_remote_a_rwnd,4)+
+                       bit2oct( (pl_idata_flag?BITSTRING(1,(const unsigned char*)&ones):BITSTRING(1,(const unsigned char*)&zero)) 
+                                 + (pl_reconf_flag?BITSTRING(1,(const unsigned char*)&ones):BITSTRING(1,(const unsigned char*)&zero))
+                                 + (pl_forward_tsn_flag?BITSTRING(1,(const unsigned char*)&ones):BITSTRING(1,(const unsigned char*)&zero))
+                                 + BITSTRING(5,(const unsigned char*)&zero) )
+                       ;
+
+  unsigned int out_length;
+  unsigned char output[EVP_MAX_MD_SIZE];
+  HMAC(EVP_md5(), (const unsigned char*)pl_key, (size_t) pl_key.lengthof(),
+                  (const unsigned char*)ret_val, (size_t) ret_val.lengthof(),
+                   output, &out_length);
+  
+  return ret_val + OCTETSTRING(16,output);
+
+}
+
+INTEGER SCTP__check__state__cookie(OCTETSTRING const& pl_cookie, 
+                                   OCTETSTRING const& pl_key){
+
+  if(pl_cookie.lengthof()!= 47){
+    // We use 46 octet length state cookie
+    return -1;
+  }
+
+  // check the MAC
+  unsigned int out_length;
+  unsigned char output[EVP_MAX_MD_SIZE];
+  HMAC(EVP_md5(), (const unsigned char*)pl_key, (size_t) pl_key.lengthof(),
+                  (const unsigned char*)pl_cookie, 31,
+                   output, &out_length);
+  
+  if(substr(pl_cookie,31,16)!=OCTETSTRING(16,output)){
+    // MAC error
+    return -1;
+  }
+  
+  // check lifespan
+  time_t tstamp_t=time(NULL);
+  unsigned int tstamp_i = (tstamp_t &0x7fffffff ); // to calculate the lifespan of teh cookie
+                                          // the lowest 31 bit is enough
+  unsigned int lifespan = (int)oct2int(substr(pl_cookie,4,2));
+  unsigned int orig_ts= (int)oct2int(substr(pl_cookie,0,4));
+  
+  if( orig_ts<(tstamp_i-lifespan) ){
+    // expired
+    return 1;
+  }
+  // cookie ok
+  return 0;
+}
+
+//***************************************************************************//
+// 
+//   Event map handler functions
+// 
+//***************************************************************************//
+void SCTP__event__add__map(INTEGER const& pl_event_id, 
+                           FLOAT const& pl_event_time){
+  // Just insert it
+  event_map.insert(std::pair<double,int>((double)pl_event_time,(int)pl_event_id));
+}
+
+void SCTP__event__del__map(INTEGER const& pl_event_id, 
+                           FLOAT const& pl_event_time){
+  // find the the time,id pair.
+  // Note that several event can be scheduled at the same time
+  // so it is not enough to delete the key.
+  
+  event_map_it_t it=event_map.find((double)pl_event_time);
+  while( (it != event_map.end()) && (it->second != (int)pl_event_id ) ){
+    it++;
+  }
+  
+  // now the it point to either the event ot delete or to the end
+  if(it != event_map.end()){
+    // delete the event
+    event_map.erase(it);
+  }
+  
+}
+
+INTEGER SCTP__event__get__map() {
+  // return the event id of the first event.
+  // the map is ordered by the event time
+  event_map_it_t it=event_map.begin();
+  if(it != event_map.end()){
+    return it->second;  // return the event id
+  }
+  return -1;  // map is empty
+  
+}
+
+OCTETSTRING SCTP__misc__float2oct(FLOAT const& pl_in){
+  double fl=(double)pl_in;
+  return OCTETSTRING(sizeof(double),(const unsigned char*)&fl);
+
+}
+FLOAT SCTP__misc__oct2float( OCTETSTRING const& pl_in){
+  return FLOAT(*((float*)(const unsigned char*)pl_in));
+}
+
+}
+
diff --git a/src/SCTP_Engine_Functions.ttcn b/src/SCTP_Engine_Functions.ttcn
new file mode 100644
index 0000000..27e39ce
--- /dev/null
+++ b/src/SCTP_Engine_Functions.ttcn
@@ -0,0 +1,4702 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v2.0
+// which accompanies this distribution, and is available at
+// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+///////////////////////////////////////////////////////////////////////////////
+//
+//  File:               SCTP_Engine_Functions.ttcn
+//  Description:        Functions of the SCTP Engine
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 840
+//
+module SCTP_Engine_Functions{
+
+import from SCTP_Engine_Definition all;
+import from SCTP_Engine_PortTypes all;
+import from SCTP_Types all
+import from SCTP_Engine_Templates all
+
+// Allocates an entry in the assoc DB, returns the index of the entry
+
+function SCTP_allocate_assoc_entry() runs on SCTP_Engine_CT return integer {
+  var integer vl_selected_entry:=-1;
+
+  if(v_assoc_db.used_entries<sizeof(v_assoc_db.associations)){
+    // There are free entries in the list
+    // remove it from the free list
+    vl_selected_entry:=v_assoc_db.first_free
+    v_assoc_db.first_free:=v_assoc_db.associations[vl_selected_entry].next_free
+    if(v_assoc_db.first_free == -1) {
+      // the last free entry was selected
+      v_assoc_db.last_free :=-1
+    }
+    v_assoc_db.associations[vl_selected_entry].next_free:=-1
+  } else {
+    // No free entry, add one to the list
+    vl_selected_entry:=sizeof(v_assoc_db.associations)
+    v_assoc_db.associations[vl_selected_entry] := c_empty_SCTP_Assoc_entry
+    v_assoc_db.used_entries:=v_assoc_db.used_entries+1
+  }
+  
+  // initialize the data
+  v_assoc_db.associations[vl_selected_entry].assoc_data:=c_empty_SCTP_Assoc_data
+  
+  // allocate int2int maps
+  
+  v_assoc_db.associations[vl_selected_entry].assoc_data.tx_stream_idx_map_id := SCTP_int2int_new()
+  v_assoc_db.associations[vl_selected_entry].assoc_data.rx_stream_idx_map_id := SCTP_int2int_new()
+  return vl_selected_entry
+  
+}
+
+// Put the association into closed state
+function SCTP_assoc_set_closed(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  // Stop all timers
+  SCTP_timer_stop_all(pl_assoc_id)
+
+  // Remove the association from the map
+  if( SCTP_del_id_map(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id ,
+                  v_assoc_db.associations[pl_assoc_id].assoc_data.local_port ,
+                  v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port ) == -1) {
+    // Something went wrong
+    log("INTERNAL ERROR: SCTP_timeout_T1_init SCTP_del_id_map: the association is not found in the id map ",pl_assoc_id , " " , v_assoc_db.associations[pl_assoc_id])
+  }
+  // Set the state of the association
+  v_assoc_db.associations[pl_assoc_id].assoc_data.state:=SCTP_ASSOC_CLOSED
+}
+
+// Constructs the assoc entry from Cookie echo message
+// 
+// Return value:
+//    - -1 error
+//    - assoc_id
+function SCTP_assoc_construct_from_cookie_echo(in SCTP_Packet pl_sctp_packet,
+                                               in integer pl_transport_id := -1,
+                                               in integer pl_parent_id := -1
+                                               ) runs on SCTP_Engine_CT return integer{
+// first check the cookie validity
+  var integer pl_check_res :=-1
+  if( ( lengthof(pl_sctp_packet.chunks) >0 ) and ischosen(pl_sctp_packet.chunks[0].cookie_echo)){
+    // Seems to be a cookie echo message
+    // Check the cookie
+    pl_check_res:=SCTP_check_state_cookie(pl_sctp_packet.chunks[0].cookie_echo.cookie,v_secret_key);
+    if(pl_check_res == -1 ){
+       // invalid MAC
+       return -1;
+    }
+    // The cookie is either valid, or expired.
+    // Construct the assoc db entry. The caller will check for expired state
+  } else {
+    // Not a valid cookie echo
+    return -1;
+  }
+
+  // Allocate the new assoc data entry
+  var integer vl_new_assoc:=SCTP_allocate_assoc_entry();
+
+  // Copy the data from the parent if exists
+  if( pl_parent_id != -1) {
+    v_assoc_db.associations[vl_new_assoc]:=v_assoc_db.associations[pl_parent_id]
+  }
+  
+   v_assoc_db.associations[vl_new_assoc].assoc_data:={
+     transport_id:=pl_transport_id,
+     local_port:=pl_sctp_packet.common_header.destination_port,
+     remote_port:=pl_sctp_packet.common_header.source_port,
+     cookie_validity:=pl_check_res
+   }
+
+  // extract data from state cookie
+  SCTP_cookie_extract(vl_new_assoc,pl_sctp_packet.chunks[0].cookie_echo.cookie);
+
+  return vl_new_assoc;
+}
+
+// Deallocates an entry in the assoc DB.
+function SCTP_free_assoc_entry(in integer pl_idx) runs on SCTP_Engine_CT {
+  if( (pl_idx<0) or (pl_idx>sizeof(v_assoc_db.associations)) 
+      or (not ispresent(v_assoc_db.associations[pl_idx].assoc_data)) ){
+    return // invalid index or item is already free, nothing to do
+  }
+  
+  // delete the int2int maps
+  SCTP_int2int_delete(v_assoc_db.associations[pl_idx].assoc_data.tx_stream_idx_map_id)
+  SCTP_int2int_delete(v_assoc_db.associations[pl_idx].assoc_data.rx_stream_idx_map_id)
+  
+  // Stop all timers
+  SCTP_timer_stop_all(pl_idx)
+
+  // release all the data
+  v_assoc_db.associations[pl_idx].assoc_data:=omit
+  
+  // This entry will be the last free entry
+  v_assoc_db.associations[pl_idx].next_free := -1
+  
+  // put the entry to the end of the chain
+  if(v_assoc_db.last_free!=-1){
+    // There was valid last free entry
+    v_assoc_db.associations[v_assoc_db.last_free].next_free:=pl_idx
+  }
+  
+  // Move the last_free pointer
+  v_assoc_db.last_free:=pl_idx
+
+  v_assoc_db.used_entries:=v_assoc_db.used_entries-1
+
+  return // We're done
+}
+
+function SCTP_timer_stop_all(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event!=-1){
+    SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event)
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+  }
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id!=-1){
+    SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id)
+    v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id:=-1
+  }
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.close_timer!=-1){
+    SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.close_timer)
+    v_assoc_db.associations[pl_assoc_id].assoc_data.close_timer:=-1
+  }
+}
+
+// Function to handle assoc-id <-> (transport_id,local_port,remote_port) mapping
+// Register entries into the map
+// return value: 0 - OK, -1 - Error
+external function SCTP_add_id_map(in integer pl_assoc_id,
+                                  in integer pl_transport_id,
+                                  in integer pl_local_port,
+                                  in integer pl_remote_port) return integer
+
+// Delete entries from the map
+// return value: 0 - OK, -1 - Error
+external function SCTP_del_id_map(in integer pl_transport_id,
+                                  in integer pl_local_port,
+                                  in integer pl_remote_port) return integer
+
+// Search in the map
+// return value: assoc_id - OK, -1 - Error
+external function SCTP_find_id_map(in integer pl_transport_id,
+                                  in integer pl_local_port,
+                                  in integer pl_remote_port) return integer
+
+
+// State cookie handling functions
+// The information should be stored in state cookie
+// timestamp & lifespan
+// Own & remote verification tag
+// Own & remote tie tag
+// remote initial TSN, our own is equal to verification tag
+// output & max input stream of remote
+// remote advertised receive window
+// Those are needed to restore the association data 
+// Our state cookie structure:
+
+// The order and size of the fields:
+// unix_timestamp        4 octets
+// pl_lifespan           2
+// pl_own_init_tag       4
+// pl_remote_init_tag    4
+// pl_tie_tag            4
+// pl_remote_tsn         4
+// pl_remote_os          2
+// pl_remote_mis         2
+// pl_remote_a_rwnd      4
+// flags                 1
+// MAC                  17
+//                 Summ:47
+// generate the state cookie. The actual time is queried.
+external function SCTP_gen_state_cookie(in integer pl_lifespan, 
+                                        in integer pl_own_init_tag,
+                                        in integer pl_remote_init_tag,
+                                        in integer pl_tie_tag,
+                                        in integer pl_remote_tsn,
+                                        in integer pl_remote_os,
+                                        in integer pl_remote_mis,
+                                        in integer pl_remote_a_rwnd,
+                                        in boolean pl_idata_flag,
+                                        in boolean pl_reconf_flag,
+                                        in boolean pl_forward_tsn_flag,
+                                        in octetstring pl_key
+                                        ) return octetstring
+
+// Check the received state cookie validity
+// return values:
+//    0: OK
+//   -1: MAC failed/ invalid contents
+//    1: expired
+external function SCTP_check_state_cookie(in octetstring pl_cookie,
+                                          in octetstring pl_key) return integer
+
+
+// extract the data from the cookie into the assoc db entry
+function SCTP_cookie_extract(in integer pl_assoc_id,
+                             in octetstring pl_cookie) runs on SCTP_Engine_CT {
+                             
+ v_assoc_db.associations[pl_assoc_id].assoc_data:={
+   own_tag:=oct2int(substr(pl_cookie,6,4)),
+   remote_tag:=oct2int(substr(pl_cookie,10,4)),
+   remote_tsn:=oct2int(substr(pl_cookie,18,4)),
+   own_tsn:=oct2int(substr(pl_cookie,6,4)),
+   remote_os:=oct2int(substr(pl_cookie,22,2)),
+   remote_mis := oct2int(substr(pl_cookie,24,2)),
+   remote_a_rwnd := oct2int(substr(pl_cookie,26,4)),
+   i_data_supported := substr(oct2bit(substr(pl_cookie,30,1)),0,1) == '1'B,
+   reconf_own_seq_num := oct2int(substr(pl_cookie,6,4)),
+   reconf_remote_seq_num := oct2int(substr(pl_cookie,18,4))
+ }
+ v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.is_supported:= substr(oct2bit(substr(pl_cookie,30,1)),1,1) == '1'B
+ v_assoc_db.associations[pl_assoc_id].assoc_data.forward_tsn_supported:= substr(oct2bit(substr(pl_cookie,30,1)),2,1) == '1'B
+ 
+}
+/*****************************************************************************/
+//
+//  Event scheduler functions
+// 
+/*****************************************************************************/
+
+// Add event to the event-time map
+// return value: 0 - OK, -1 - Error
+external function SCTP_event_add_map(in integer pl_event_id,
+                                     in float   pl_event_time)
+
+
+// Remove event from the map
+// return value: 0 - OK, -1 - Error
+external function SCTP_event_del_map(in integer pl_event_id,
+                                     in float   pl_event_time)
+
+// Get the first event idx
+// return value: event_idx - OK, -1 - Error
+external function SCTP_event_get_map() return integer
+
+// Schedule the event
+// returns the idx of the 
+function SCTP_event_schedule(in integer pl_assoc_id,
+                             in integer pl_timer_id,
+                             in float   pl_timeout  // relative timeout value
+                             ) runs on SCTP_Engine_CT return integer {
+
+  var float curr_time:=t_run_time.read
+  var integer vl_selected_entry:=-1;
+//  log(v_event_db)
+  if(v_event_db.used_entries<sizeof(v_event_db.events)){
+    // There are free entries in the list
+    // remove it from the free list
+    vl_selected_entry:=v_event_db.first_free
+    v_event_db.first_free:=v_event_db.events[vl_selected_entry].next_free
+    if(v_event_db.first_free == -1) {
+      // the last free entry was selected
+      v_event_db.last_free :=-1
+    }
+    v_event_db.events[vl_selected_entry].next_free:=-1
+  } else {
+    // No free entry, add one to the list
+    vl_selected_entry:=sizeof(v_event_db.events)
+  }
+  v_event_db.used_entries:=v_event_db.used_entries+1;
+  
+  // initialize the data
+  v_event_db.events[vl_selected_entry] := {
+    next_free:=-1,
+    assoc_id:=pl_assoc_id,
+    timer_id:=pl_timer_id,
+    timeout_time:=curr_time+pl_timeout // absulute timeout val
+  }
+  
+  // insert the event into the map
+  SCTP_event_add_map(vl_selected_entry,v_event_db.events[vl_selected_entry].timeout_time)
+
+  // rescedule the timeout timer
+  SCTP_event_recalculate_timer()
+  
+  return vl_selected_entry
+}
+
+// Remove the event from the list
+function SCTP_event_remove(in integer pl_idx) runs on SCTP_Engine_CT {
+  if( (pl_idx<0) or (pl_idx>sizeof(v_event_db.events)) 
+      or (v_event_db.events[pl_idx].assoc_id==-1) ){
+    return // invalid index or item is already free, nothing to do
+  }
+  
+  // remove the event from the map & reschedule the timer
+  SCTP_event_del_map(pl_idx,v_event_db.events[pl_idx].timeout_time)
+  SCTP_event_recalculate_timer()
+
+  // Free the enry and move to the end of the free chain
+  v_event_db.events[pl_idx]:=c_empty_event_entry
+  
+  // put the entry to the end of the chain
+  if(v_event_db.last_free!=-1){
+    // There was valid last free entry
+    v_event_db.events[v_event_db.last_free].next_free:=pl_idx
+  }
+  
+  // Set the first free pointer if needed
+  if(v_event_db.first_free==-1){
+    // There was valid last free entry
+    v_event_db.first_free:=pl_idx
+  }
+  // Move the last_free pointer
+  v_event_db.last_free:=pl_idx
+  
+  v_event_db.used_entries:=v_event_db.used_entries-1;
+  
+}
+
+// Set the t_next_event to the next event. Reset the timer if needed
+function SCTP_event_recalculate_timer() runs on SCTP_Engine_CT {
+  var integer first_event:=SCTP_event_get_map();
+  
+  if(first_event==-1){ 
+    // No event in the queue
+    v_event_db.the_sceduled_event:=-1; // No scheduled event
+    if(t_next_event.running) {
+      t_next_event.stop    // deactivate the timer
+    }
+    return  // we're ready
+  }
+  
+  if(first_event==v_event_db.the_sceduled_event){
+    // the first event is the already scheduled, nothing to do
+    return
+  }
+  
+  // Reschedule the timer
+  if(t_next_event.running) {
+    t_next_event.stop // stop it first
+  }
+  
+  var float curr_time:=t_run_time.read
+  
+  // Calculate the timeout value
+  var float schedule_time:=v_event_db.events[first_event].timeout_time-curr_time
+  if(schedule_time<0.0){
+    // do not chedule in the past
+    schedule_time:=0.0
+  }
+  
+  // remeber the event idx
+  v_event_db.the_sceduled_event:=first_event
+  
+  // Start the timer
+  t_next_event.start(schedule_time)
+  
+  return
+  
+}
+
+/*****************************************************************************/
+//
+//  Message handler functions
+// 
+/*****************************************************************************/
+
+// Process the incoming sctp packet
+// The INIT & COOKIE ECHO processed by other function
+function SCTP_message_incoming_handler(in integer pl_assoc_id,
+                                       in SCTP_Packet pl_sctp_packet,
+                                       in boolean pl_cookie_preprocessed := false  // if true, the Cookie Echo was preprocessed, only Cookie Ack is needed
+                                       ) runs on SCTP_Engine_CT  {
+  // Check the verification tag
+  if(pl_sctp_packet.common_header.verification_tag!=v_assoc_db.associations[pl_assoc_id].assoc_data.own_tag){
+    // Not for me 
+    // Drop it
+    log("Verification tag mismatch. Packet dropped. ",pl_sctp_packet)
+    return;
+  }
+
+  // trigger the processing of the data queue
+  // If new chunk has been put into the incoming chunk queue, set it true to trigger the processing of the queue
+  var boolean vl_process_data:=false
+
+  // The answer packet
+  var SCTP_Packet       vl_response := c_empty_sctp_packet
+
+  for(var integer vl_k:=0;vl_k<lengthof(pl_sctp_packet.chunks);vl_k:=vl_k+1){
+    // Process the chunks by calling the handler functions
+    // Each handler returns the processing result
+    // -1: Stop the further processing
+    //  0: Continue with the next chunk
+    //  1: Continue with the next chunk, postprocess the data queues
+    var integer vl_handler_ret:=-1
+    if(ischosen(pl_sctp_packet.chunks[vl_k].init_ack)){
+      vl_handler_ret:=SCTP_message_incoming_init_ack_handler(pl_sctp_packet.chunks[vl_k].init_ack,pl_assoc_id,vl_k)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].cookie_ack)){
+      vl_handler_ret:=SCTP_message_incoming_cookie_ack_handler(pl_sctp_packet.chunks[vl_k].cookie_ack,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].cookie_echo)){  //Process cookie echo
+      vl_handler_ret:=SCTP_message_incoming_cookie_echo_handler(pl_sctp_packet.chunks[vl_k].cookie_echo,pl_assoc_id,vl_response,pl_cookie_preprocessed)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].data) or ischosen(pl_sctp_packet.chunks[vl_k].idata)){ // process DATA
+      vl_handler_ret:=SCTP_message_incoming_data_handler(pl_sctp_packet.chunks[vl_k],pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].sack)){ // process SACK
+      vl_handler_ret:=SCTP_message_incoming_sack_handler(pl_sctp_packet.chunks[vl_k].sack,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].abort)){ // process ABORT
+      vl_handler_ret:=SCTP_message_incoming_abort_handler(pl_sctp_packet.chunks[vl_k].abort,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].shutdown)){ // process SHUTDOWN
+      vl_handler_ret:=SCTP_message_incoming_shutdown_handler(pl_sctp_packet.chunks[vl_k].shutdown,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].shutdown_ack)){ // process SHUTDOWN ACK
+      vl_handler_ret:=SCTP_message_incoming_shutdown_ack_handler(pl_sctp_packet.chunks[vl_k].shutdown_ack,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].shutdown_complete)){ // process SHUTDOWN COMPLETE
+      vl_handler_ret:=SCTP_message_incoming_shutdown_complete_handler(pl_sctp_packet.chunks[vl_k].shutdown_complete,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].heartbeat)){ // process HEARTBEAT
+      vl_handler_ret:=SCTP_message_incoming_heartbeat_handler(pl_sctp_packet.chunks[vl_k].heartbeat,pl_assoc_id,vl_response)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].heartbeat_ack)){ // process HEARTBEAT
+      vl_handler_ret:=SCTP_message_incoming_heartbeat_ack_handler(pl_sctp_packet.chunks[vl_k].heartbeat_ack,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].forward_tsn)){ // process FORWARD TSN
+      vl_handler_ret:=SCTP_message_incoming_forward_tsn_handler(pl_sctp_packet.chunks[vl_k].forward_tsn,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].iforward_tsn)){ // process FORWARD TSN
+      vl_handler_ret:=SCTP_message_incoming_iforward_tsn_handler(pl_sctp_packet.chunks[vl_k].iforward_tsn,pl_assoc_id)
+    } else if(ischosen(pl_sctp_packet.chunks[vl_k].re_config)){ // process FORWARD TSN
+      vl_handler_ret:=SCTP_message_incoming_re_config_handler(pl_sctp_packet.chunks[vl_k].re_config,vl_response,pl_assoc_id)
+    }
+    
+        
+    if(vl_handler_ret == -1 ){
+      return  // -1: Stop the further processing
+    } else if(vl_handler_ret == 1 ){
+      vl_process_data:=true //  1: Continue with the next chunk, postprocess the data queues
+    }
+  } // for
+  
+  if(vl_process_data){
+    // construct SACK
+    SCTP_data_gen_sack(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue, // The queue
+                                     v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn,   // The first expected tsn of the queue, if empty
+                                     vl_response.chunks[lengthof(vl_response.chunks)],
+                                     pl_assoc_id) // The chunk
+
+    // if "deferred reset processing" is ongoing and received the missing data chunks
+    if(ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.deffered_reset)
+       and (SCTP_compare_tsn(SCTP_next_tsn(v_assoc_db.associations[pl_assoc_id].assoc_data.deffered_reset.last_assigned_tsn),v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn)<=0) ){
+      // then execute the reset
+      var integer vl_idx:=lengthof(vl_response.chunks)
+      vl_response.chunks[vl_idx]:={
+        re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={}
+          
+        }
+      }
+      SCTP_reconf_process_ssn_reset(v_assoc_db.associations[pl_assoc_id].assoc_data.deffered_reset,vl_response.chunks[vl_idx].re_config,pl_assoc_id)
+      v_assoc_db.associations[pl_assoc_id].assoc_data.deffered_reset:=omit
+    }
+
+    // process the chunk queue and reconstruct the messages
+    SCTP_data_chunk2msg(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue,v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues,pl_assoc_id)
+    
+    // deliver the data to the user
+    SCTP_data_deliver(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues,pl_assoc_id)
+    
+    // Release the ack-ed and processed message from the rx chunk queue
+    SCTP_data_clean_tx_chunk_queue(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue,pl_assoc_id)
+
+
+    if(v_assoc_db.associations[pl_assoc_id].assoc_data.state == SCTP_ASSOC_SHUTDOWN_SENT){
+      // We should send shutdown also
+      var integer vl_sack_idx:=lengthof(vl_response.chunks)-1  // the index of the sack chunk
+      var SCTP_Shutdown_chunk vl_sh:={
+        chunk_type:=7,
+        flags:='00000000'B,
+        chunk_length:=0,
+        cum_tsn_ack:=vl_response.chunks[vl_sack_idx].sack.cum_tsn_ack
+      }
+      if(ispresent(vl_response.chunks[vl_sack_idx].sack.gap_blocks) or ispresent(vl_response.chunks[vl_sack_idx].sack.dup_tsns)){
+        // SACK is needed, add the shutdown after the sack
+        vl_response.chunks[lengthof(vl_response.chunks)].shutdown:=vl_sh
+      } else {
+        // SACK is not needed, replace it
+        vl_response.chunks[vl_sack_idx].shutdown:=vl_sh
+      }
+      
+      // Restart the T2 timer
+      SCTP_timer_T2_restart(pl_assoc_id)
+      
+    }
+  }
+  
+  // Send the answer if need
+  if(lengthof(vl_response.chunks)>0){
+    vl_response.common_header:={
+        source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+        destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+        verification_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+    }
+    
+    SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_response);
+  }
+}
+
+// The return values of the chunk handlers:
+// -1: Stop the further processing
+//  0: Continue with the next chunk
+//  1: Continue with the next chunk, postprocess the data queues
+
+
+// Handles the reconfig chunk
+function SCTP_message_incoming_re_config_handler(in SCTP_Re_Config_chunk pl_re_cfg,  // The chunk to process
+                                                 inout SCTP_Packet pl_response,
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+  // validate the chunk
+    var boolean vl_sendresp:=false
+    var boolean vl_storeas_req:=false
+    
+    var SCTP_Re_Config_chunk vl_resp:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={}
+    }
+      
+  if( v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.is_supported  // re config support 
+      and ispresent(pl_re_cfg.params)
+      and (
+        (lengthof(pl_re_cfg.params)==1)    // one or two param present
+        or (lengthof(pl_re_cfg.params)==2)  )
+      ){
+    
+    // process the requests
+    for(var integer vl_i:=0;vl_i<lengthof(pl_re_cfg.params);vl_i:=vl_i+1){
+      if(ischosen(pl_re_cfg.params[vl_i].out_ssn_reset_req)){
+        if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id!=-1){ // timer of outgoing request is running
+          if(pl_re_cfg.params[vl_i].out_ssn_reset_req.reconf_resp_seq == v_assoc_db.associations[pl_assoc_id].assoc_data.ongoing_incoming_reconf_req_seq){
+            // This is the acknowledgement of the sent incoming ssn reset request
+            // stop the timer
+            SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id)
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id:=-1
+            
+            // No need to notify the user here, because the notification will be sent below
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_ongoing:=false  // no outgoing reconfig request as it is acked
+            v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_req:=omit // acked
+            v_assoc_db.associations[pl_assoc_id].assoc_data.ongoing_incoming_reconf_req_seq:=-1
+          }
+          
+        }
+        
+        // Check the seq no
+        var integer vl_in_seq_no:=pl_re_cfg.params[vl_i].out_ssn_reset_req.reconf_req_seq
+        if( ((SCTP_next_tsn(vl_in_seq_no)==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)  // prev received seq_no
+            or (SCTP_next_tsn(SCTP_next_tsn(vl_in_seq_no))==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)) // prev prev seg no
+                   // this is just a hack to handle the case with two requests
+            and ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp)
+          ){
+          // retransmission
+          // send the latest response again
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:=v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp}
+          return 1
+        }
+        
+        if(vl_in_seq_no!=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num){
+          // not the expected seq no
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={{
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=5,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }}
+          }
+          }
+          return 0
+        }
+        
+        // adjust the remote seq no
+        v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num:=SCTP_next_tsn(vl_in_seq_no)
+        
+        if(ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.deffered_reset)){
+          // reset already running
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={{
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=4,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }}
+          }
+          }
+          return 0
+          
+        }
+        
+        if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.stream_reset_allowed){  // Is SSN reset allowed?
+          if(SCTP_compare_tsn(SCTP_next_tsn(pl_re_cfg.params[vl_i].out_ssn_reset_req.last_assigned_tsn),v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn)>0){
+            // The remote last assigned TSN is greater than the sack-ed
+            // Enter "deferred reset processing"
+            
+            // store the packet for the later processing
+            v_assoc_db.associations[pl_assoc_id].assoc_data.deffered_reset:=pl_re_cfg.params[vl_i].out_ssn_reset_req
+            
+            // prepare response
+            vl_resp.params[lengthof(vl_resp.params)]:={
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=6,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }
+            vl_sendresp:=true
+
+          } else {
+            SCTP_reconf_process_ssn_reset(pl_re_cfg.params[vl_i].out_ssn_reset_req,vl_resp,pl_assoc_id)
+            vl_sendresp:=true
+          }
+        } else {
+          // send back the denied
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={{
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=2,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }}
+          }
+          }
+          return 0
+        
+        }
+        
+      } else if(ischosen(pl_re_cfg.params[vl_i].in_ssn_reset_req)){
+        // check seq no
+        // Check the seq no
+        var integer vl_in_seq_no:=pl_re_cfg.params[vl_i].in_ssn_reset_req.reconf_req_seq
+        if( ((SCTP_next_tsn(vl_in_seq_no)==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)  // prev received seq_no
+            or (SCTP_next_tsn(SCTP_next_tsn(vl_in_seq_no))==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)) // prev prev seg no
+                   // this is just a hack to handle the case with two requests
+            and ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp)
+          ){
+          // retransmission
+          // send the latest response again
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:=v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp}
+          return 1
+        }
+        
+        if(vl_in_seq_no!=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num){
+          // not the expected seq no
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={{
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=5,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }}
+          }
+          }
+          return 0
+        }
+        
+        if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_ongoing){
+          // request is sent but not completed
+          // just ignore it
+          // The remote side will retransmit later
+          
+        } else {
+          // TODO: handle request overlap
+          // generate outgoing ssn reset request
+          v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num:=SCTP_next_tsn(vl_in_seq_no)
+          if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.stream_reset_allowed){  // Is SSN reset allowed?
+            if(ispresent(pl_re_cfg.params[vl_i].in_ssn_reset_req.stream_numbers)){
+              SCTP_reconf_generate_out_ssn_reset_req(pl_re_cfg.params[vl_i].in_ssn_reset_req.stream_numbers,vl_in_seq_no,vl_resp,pl_assoc_id)
+            } else {
+              SCTP_reconf_generate_out_ssn_reset_req({},vl_in_seq_no,vl_resp,pl_assoc_id)
+            }
+
+            vl_sendresp:=true;
+          }else {
+          // send back the denied
+            vl_resp.params[lengthof(vl_resp.params)]:={
+                reconf_resp:={
+                  param_type:=16,
+                  param_length:=0,
+                  reconf_resp_seq:=vl_in_seq_no,
+                  result:=2,
+                  sender_next_tsn:=omit,
+                  receiver_next_tsn:=omit
+                }
+              }
+            vl_sendresp:=true;
+          }
+          
+        }
+      } else if(ischosen(pl_re_cfg.params[vl_i].add_out_stream)){
+        var integer vl_in_seq_no:=pl_re_cfg.params[vl_i].add_out_stream.reconf_req_seq
+        if( ((SCTP_next_tsn(vl_in_seq_no)==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)  // prev received seq_no
+            or (SCTP_next_tsn(SCTP_next_tsn(vl_in_seq_no))==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)) // prev prev seg no
+                   // this is just a hack to handle the case with two requests
+            and ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp)
+          ){
+          // retransmission
+          // send the latest response again
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:=v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp}
+          return 1
+        }
+        
+        if(vl_in_seq_no!=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num){
+          // not the expected seq no
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={{
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=5,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }}
+          }
+          }
+          return 0
+        }
+      
+        v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num:=SCTP_next_tsn(vl_in_seq_no)
+        if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.stream_add_allowed){  // allowed?
+          // send back ok
+            vl_resp.params[lengthof(vl_resp.params)]:={
+                reconf_resp:={
+                  param_type:=16,
+                  param_length:=0,
+                  reconf_resp_seq:=vl_in_seq_no,
+                  result:=1,
+                  sender_next_tsn:=omit,
+                  receiver_next_tsn:=omit
+                }
+              }
+            vl_sendresp:=true;
+            
+            // notify the user
+            var SCTP_Notification_data vl_note_data:={
+                assoc_id:=pl_assoc_id,
+                notification := {
+                  reconfig:={
+                    result:=RECONFIG_OK,
+                    method:={add_stream:={ 
+                        incoming:=false,
+                        new_streams:=pl_re_cfg.params[vl_i].add_out_stream.stream_num
+                      }
+                    }
+                  }
+                },
+                options := omit
+              }
+          p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+            
+        } else {
+          // send back the denied
+            vl_resp.params[lengthof(vl_resp.params)]:={
+                reconf_resp:={
+                  param_type:=16,
+                  param_length:=0,
+                  reconf_resp_seq:=vl_in_seq_no,
+                  result:=2,
+                  sender_next_tsn:=omit,
+                  receiver_next_tsn:=omit
+                }
+              }
+            vl_sendresp:=true;
+        }
+
+      } else if(ischosen(pl_re_cfg.params[vl_i].add_in_stream)){
+        var integer vl_in_seq_no:=pl_re_cfg.params[vl_i].add_in_stream.reconf_req_seq
+        if( ((SCTP_next_tsn(vl_in_seq_no)==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)  // prev received seq_no
+            or (SCTP_next_tsn(SCTP_next_tsn(vl_in_seq_no))==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)) // prev prev seg no
+                   // this is just a hack to handle the case with two requests
+            and ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp)
+          ){
+          // retransmission
+          // send the latest response again
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:=v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp}
+          return 1
+        }
+        
+        if(vl_in_seq_no!=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num){
+          // not the expected seq no
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={{
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=5,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }}
+          }
+          }
+          return 0
+        }
+      
+        v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num:=SCTP_next_tsn(vl_in_seq_no)
+        if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.stream_add_allowed){  // Is allowed?
+          // send back ok
+            vl_resp.params[lengthof(vl_resp.params)]:={
+                reconf_resp:={
+                  param_type:=16,
+                  param_length:=0,
+                  reconf_resp_seq:=vl_in_seq_no,
+                  result:=1,
+                  sender_next_tsn:=omit,
+                  receiver_next_tsn:=omit
+                }
+              }
+            vl_sendresp:=true;
+            
+            // send the add outgoing stream req
+            var SCTP_Packet vl_out_req:=c_empty_sctp_packet
+            vl_out_req.common_header:={
+                source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+                destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+                verification_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+            }
+            vl_out_req.chunks[0]:={ re_config:={
+                chunk_type:=130,
+                flags:='00000000'B,
+                chunk_length:=0,
+                params:={{
+                  add_out_stream:={
+                    param_type:=17,
+                    param_length:=0,
+                    reconf_req_seq:=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_own_seq_num,
+                    stream_num:=pl_re_cfg.params[vl_i].add_in_stream.stream_num,
+                    reserved:=0
+                  }
+                }}
+              }
+  
+            }
+            v_assoc_db.associations[pl_assoc_id].assoc_data.ongoing_outgoing_reconf_req_seq:=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_own_seq_num
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_own_seq_num:=SCTP_next_tsn(v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_own_seq_num)
+            v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_req:=vl_out_req.chunks[0].re_config
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_ongoing:=true
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_retransmit_counter:=0      
+            
+            // schedule the timer
+            SCTP_timer_reconf_start(pl_assoc_id)
+
+            SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_out_req);
+
+        } else {
+          // send back the denied
+            vl_resp.params[lengthof(vl_resp.params)]:={
+                reconf_resp:={
+                  param_type:=16,
+                  param_length:=0,
+                  reconf_resp_seq:=vl_in_seq_no,
+                  result:=2,
+                  sender_next_tsn:=omit,
+                  receiver_next_tsn:=omit
+                }
+              }
+            vl_sendresp:=true;
+        }
+
+      } else if(ischosen(pl_re_cfg.params[vl_i].ssn_tsn_reset_req)){
+        var integer vl_in_seq_no:=pl_re_cfg.params[vl_i].ssn_tsn_reset_req.reconf_req_seq
+        if( ((SCTP_next_tsn(vl_in_seq_no)==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)  // prev received seq_no
+            or (SCTP_next_tsn(SCTP_next_tsn(vl_in_seq_no))==v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num)) // prev prev seg no
+                   // this is just a hack to handle the case with two requests
+            and ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp)
+          ){
+          // retransmission
+          // send the latest response again
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:=v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp}
+          return 1
+        }
+        
+        if(vl_in_seq_no!=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num){
+          // not the expected seq no
+          pl_response.chunks[lengthof(pl_response.chunks)]:={ re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={{
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=5,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }}
+          }
+          }
+          return 0
+        }
+        v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_remote_seq_num:=SCTP_next_tsn(vl_in_seq_no)
+        
+        // process the request
+        if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.assoc_reset_allowed){  // Is reset allowed?
+          // Compute an appropriate value for the Receiver's Next TSN
+          v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn:= (v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn + 2147483648) mod 4294967296
+          
+          // Compute an appropriate value for the local endpoint's next TSN
+          // v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn already contains that value
+          
+          // Reset the stream and chunk queues
+          
+          // clear the incoming message queues
+          for(var integer vl_k:=0;vl_k<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues);vl_k:=vl_k+1){
+            v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_k]:=c_empty_msg_queue
+          }
+          
+          // Clear incoming chunk queue
+          v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue := c_empty_chunk_queue_db
+          
+          // Clear outgoing chunk queue
+          v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue := c_empty_chunk_queue_db
+          
+          // clear the outgoing message queues
+          for(var integer vl_k:=0;vl_k<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues);vl_k:=vl_k+1){
+            v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_k]:=c_empty_msg_queue
+          }
+          
+          // stop the T3 timer.
+          if(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event!=-1){
+            SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event)
+            v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+          }
+
+          vl_resp.params[lengthof(vl_resp.params)]:={
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=vl_in_seq_no,
+                result:=1,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }
+          vl_sendresp:=true;
+
+          // notify the user
+          var SCTP_Notification_data vl_note_data:={
+              assoc_id:=pl_assoc_id,
+              notification := {
+                reconfig:={
+                  result:=RECONFIG_OK,
+                  method:={assoc_reset:={}
+                  }
+                }
+              },
+              options := omit
+            }
+          p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+          
+          
+        } else {
+          // send back the denied
+            vl_resp.params[lengthof(vl_resp.params)]:={
+                reconf_resp:={
+                  param_type:=16,
+                  param_length:=0,
+                  reconf_resp_seq:=vl_in_seq_no,
+                  result:=2,
+                  sender_next_tsn:=omit,
+                  receiver_next_tsn:=omit
+                }
+              }
+            vl_sendresp:=true;
+        }
+        
+        
+      } else if(ischosen(pl_re_cfg.params[vl_i].reconf_resp)){
+        if(pl_re_cfg.params[vl_i].reconf_resp.reconf_resp_seq==v_assoc_db.associations[pl_assoc_id].assoc_data.ongoing_outgoing_reconf_req_seq){
+          // we got a response for our request
+          // stop the timers
+          v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_ongoing:=false
+          SCTP_timer_reconf_stop(pl_assoc_id)
+          
+          // get the request type
+          // check the answere code
+          if(pl_re_cfg.params[vl_i].reconf_resp.result==2){
+            // denied
+            var SCTP_Notification_data vl_note_data:={
+                assoc_id:=pl_assoc_id,
+                notification := {
+                  reconfig:={
+                    result:=RECONFIG_DENY,
+                    method:=omit
+                  }
+                },
+                options := omit
+              }
+            p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+            SCTP_reconf_clear_marks(pl_assoc_id)
+          } else if(pl_re_cfg.params[vl_i].reconf_resp.result==6) {
+            // In progress, restart the timer and clear the retransmission counter
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_ongoing:=true
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_retransmit_counter:=0      
+            SCTP_timer_reconf_start(pl_assoc_id)
+          } else if(pl_re_cfg.params[vl_i].reconf_resp.result>2 and pl_re_cfg.params[vl_i].reconf_resp.result<6) {
+            // fail
+            var SCTP_Notification_data vl_note_data:={
+                assoc_id:=pl_assoc_id,
+                notification := {
+                  reconfig:={
+                    result:=RECONFIG_FAIL,
+                    method:=omit
+                  }
+                },
+                options := omit
+              }
+            p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+            SCTP_reconf_clear_marks(pl_assoc_id)
+          } else {
+            // success
+            // check the type of the request
+            var SCTP_parameters vl_req
+            if(SCTP_reconf_get_out_req( v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_req,vl_req)){
+              if(ischosen(vl_req.add_out_stream)){
+                var SCTP_Notification_data vl_note_data:={
+                    assoc_id:=pl_assoc_id,
+                    notification := {
+                      reconfig:={
+                        result:=RECONFIG_OK,
+                        method:= {add_stream:={
+                            incoming:= true,
+                            new_streams:=vl_req.add_out_stream.stream_num
+                          }
+                        }
+                      }
+                    },
+                    options := omit
+                  }
+                p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+                
+              } else if(ischosen(vl_req.out_ssn_reset_req)){
+                // reset the ssn's
+                // the queues are already marked
+                for(var integer vl_k:=0;vl_k<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues);vl_k:=vl_k+1){
+                  if(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_k].flag){
+                    v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_k]:=c_empty_msg_queue
+                  }
+                }
+                var SCTP_Notification_data vl_note_data:={
+                    assoc_id:=pl_assoc_id,
+                    notification := {
+                      reconfig:={
+                        result:=RECONFIG_OK,
+                        method:= {stream_reset:={
+                            incoming:= true,
+                            streams:=vl_req.out_ssn_reset_req.stream_numbers
+                          }
+                        }
+                      }
+                    },
+                    options := omit
+                  }
+                p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+                
+              } else if(ischosen(vl_req.ssn_tsn_reset_req)){
+                // reset the assoc
+                // clear the incoming message queues
+                for(var integer vl_k:=0;vl_k<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues);vl_k:=vl_k+1){
+                  v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_k]:=c_empty_msg_queue
+                }
+
+                // Clear incoming chunk queue
+                v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue := c_empty_chunk_queue_db
+
+                // Clear outgoing chunk queue
+                v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue := c_empty_chunk_queue_db
+
+                // clear the outgoing message queues
+                for(var integer vl_k:=0;vl_k<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues);vl_k:=vl_k+1){
+                  v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_k]:=c_empty_msg_queue
+                }
+
+                // stop the T3 timer.
+                if(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event!=-1){
+                  SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event)
+                  v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+                }
+                
+                v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn:= pl_re_cfg.params[vl_i].reconf_resp.sender_next_tsn
+          
+                v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn:=pl_re_cfg.params[vl_i].reconf_resp.receiver_next_tsn
+
+                var SCTP_Notification_data vl_note_data:={
+                    assoc_id:=pl_assoc_id,
+                    notification := {
+                      reconfig:={
+                        result:=RECONFIG_OK,
+                        method:= {assoc_reset:={
+                        }
+                      }
+                    }},
+                    options := omit
+                  }
+                p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+                
+              } 
+            }
+          }
+          
+          
+        } else if(pl_re_cfg.params[vl_i].reconf_resp.reconf_resp_seq==v_assoc_db.associations[pl_assoc_id].assoc_data.ongoing_incoming_reconf_req_seq){
+          // we got a response for our request of do something with the incoming streams
+          // Just stop the timer as we should receive matching request
+          v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_ongoing:=false
+          SCTP_timer_reconf_stop(pl_assoc_id)
+          
+          // check the answere code
+          if(pl_re_cfg.params[vl_i].reconf_resp.result==2){
+            // denied
+            var SCTP_Notification_data vl_note_data:={
+                assoc_id:=pl_assoc_id,
+                notification := {
+                  reconfig:={
+                    result:=RECONFIG_DENY,
+                    method:=omit
+                  }
+                },
+                options := omit
+              }
+            p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+            
+          } else if(pl_re_cfg.params[vl_i].reconf_resp.result>2) {
+            // fail
+            var SCTP_Notification_data vl_note_data:={
+                assoc_id:=pl_assoc_id,
+                notification := {
+                  reconfig:={
+                    result:=RECONFIG_FAIL,
+                    method:=omit
+                  }
+                },
+                options := omit
+              }
+            p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+          }
+        } 
+        // else do nothing
+      }
+
+
+
+    } // for
+    
+  
+  } else {
+    // protocol error
+    pl_response.chunks[lengthof(pl_response.chunks)]:={
+      error_:={
+        chunk_type := 9,
+        flags:= '00000000'B,
+        chunk_length:=0,
+        params:={
+          {protocol_violation:={cause_code:=13,cause_length:=0,reason:=''O}}
+        }
+      }
+    }
+  }
+  
+  if(vl_sendresp){
+    pl_response.chunks[lengthof(pl_response.chunks)]:={re_config:=vl_resp}
+    v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp:=vl_resp
+    
+  }
+  
+  return 0
+}
+
+function SCTP_reconf_get_out_req(in SCTP_Re_Config_chunk pl_chunk, out SCTP_parameters pl_req) return boolean {
+
+  if(ispresent(pl_chunk.params)){
+    for(var integer vl_i; vl_i<lengthof(pl_chunk.params);vl_i:=vl_i+1){
+      if(ischosen(pl_chunk.params[vl_i].out_ssn_reset_req)
+         or ischosen(pl_chunk.params[vl_i].add_out_stream)
+         or ischosen(pl_chunk.params[vl_i].ssn_tsn_reset_req)){
+         pl_req:=pl_chunk.params[vl_i]
+         return true
+      }
+    }
+  }
+  return false
+}
+function SCTP_reconf_clear_marks(in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT{
+  
+              for(var integer vl_i:=0;vl_i<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues);vl_i:=vl_i+1){
+                v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_i].flag:=false;
+              }
+}
+function SCTP_reconf_generate_out_ssn_reset_req( in integer_list pl_stream_list,
+                                       in integer pl_in_seq_no,
+                                       inout SCTP_Re_Config_chunk pl_resp,
+                                       in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT{
+
+            var integer vl_idx:=lengthof(pl_resp.params)
+            pl_resp.params[vl_idx]:={out_ssn_reset_req:={
+              param_type:=13,
+              param_length:=0,
+              reconf_req_seq:=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_own_seq_num,
+              reconf_resp_seq:=pl_in_seq_no,
+              last_assigned_tsn:=SCTP_prev_tsn(v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn),
+              stream_numbers:=omit
+            }}
+            
+            if(lengthof(pl_stream_list)>0){
+              pl_resp.params[vl_idx].out_ssn_reset_req.stream_numbers:=pl_stream_list
+              // mark the lists as closed
+              for(var integer vl_i:=0;vl_i<lengthof(pl_stream_list);vl_i:=vl_i+1){
+                var integer vl_stream_idx
+                if(SCTP_int2int_get(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_stream_idx_map_id,
+                                      pl_stream_list[vl_i],
+                                      vl_stream_idx
+                                      )!=-1){
+                  v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_stream_idx].flag:=true;
+                  v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_stream_idx+1].flag:=true;
+                }
+              
+              }
+              
+            } else {
+              // mark all stream as closed
+              for(var integer vl_i:=0;vl_i<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues);vl_i:=vl_i+1){
+                v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_i].flag:=true;
+              }
+              
+            }
+            
+            v_assoc_db.associations[pl_assoc_id].assoc_data.ongoing_outgoing_reconf_req_seq:=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_own_seq_num
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_own_seq_num:=SCTP_next_tsn(v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_own_seq_num)
+            v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_req:=pl_resp
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_ongoing:=true
+            v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_retransmit_counter:=0      
+            
+            // schedule the timer
+            SCTP_timer_reconf_start(pl_assoc_id)
+
+}
+
+function SCTP_reconf_process_ssn_reset(in SCTP_Out_SSN_Reset_req_parameter pl_re_cfg,  // The chunk to process
+                                       inout SCTP_Re_Config_chunk pl_resp,
+                                       in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT{
+        var SCTP_Notification_data vl_note_data:={
+            assoc_id:=pl_assoc_id,
+            notification := {
+              reconfig:={
+                result:=RECONFIG_OK,
+                method:={stream_reset:={ 
+                    incoming:=false,
+                    streams:={}
+                  }
+                }
+              }
+            },
+            options := omit
+          }
+
+  if(ispresent(pl_re_cfg.stream_numbers)){
+    // reset only the specified streams
+    for(var integer vl_i:=0;vl_i<lengthof(pl_re_cfg.stream_numbers);vl_i:=vl_i+1){
+      var integer vl_stream_idx
+      vl_note_data.notification.reconfig.method.stream_reset.streams[lengthof(vl_note_data.notification.reconfig.method.stream_reset.streams)]:=pl_re_cfg.stream_numbers[vl_i]
+      if(SCTP_int2int_get(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_stream_idx_map_id,
+                            pl_re_cfg.stream_numbers[vl_i],
+                            vl_stream_idx
+                            )!=-1){
+        v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_stream_idx]:=c_empty_msg_queue
+        v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_stream_idx+1]:=c_empty_msg_queue
+      }
+    }
+  } else {
+    // reset all streams
+    for(var integer vl_i:=0;vl_i<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues);vl_i:=vl_i+1){
+      v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues[vl_i]:=c_empty_msg_queue
+    }
+  }
+
+  // generate the ack message
+            pl_resp.params[lengthof(pl_resp.params)]:={
+              reconf_resp:={
+                param_type:=16,
+                param_length:=0,
+                reconf_resp_seq:=pl_re_cfg.reconf_req_seq,
+                result:=1,
+                sender_next_tsn:=omit,
+                receiver_next_tsn:=omit
+              }
+            }
+    v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_resp:=pl_resp
+        // Notify the user
+        p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_note_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+    
+}
+
+// process I-forward TSN chunk
+function SCTP_message_incoming_iforward_tsn_handler(in SCTP_IForward_TSN_chunk pl_fwd_tsn,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+
+  if(SCTP_compare_tsn(pl_fwd_tsn.new_tsn,v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn)<0){
+    // The new TSN has been acked already. Just trigger the SACK
+    return 1
+  }
+  
+  // Clean up the data queue
+  // Mark every hole as processed packet until the new tsn
+  // The data processor part will do the magic later
+ 
+  var integer vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.first_element
+  
+  while(vl_idx!=-1){
+    if( SCTP_compare_tsn(pl_fwd_tsn.new_tsn,v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.chunk_queue[vl_idx].tsn)<0){
+      // the tsn of the chunk is greater than the new tsn
+      break; // we are done
+    }
+    
+    if(not ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.chunk_queue[vl_idx].chunk)){
+      // A hole, mark it.
+      v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.chunk_queue[vl_idx].mark_flag:= true
+    }
+    vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.chunk_queue[vl_idx].next_element
+  }
+  
+  // clean up the queues
+  for(var integer vl_i:=0;vl_i<lengthof(pl_fwd_tsn.stream_ssn_list);vl_i:=vl_i+1){
+    SCTP_message_queue_skip_ssn(pl_assoc_id,pl_fwd_tsn.stream_ssn_list[vl_i].stream_id,pl_fwd_tsn.stream_ssn_list[vl_i].mid mod 65536,v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues )
+  }
+  v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn:=SCTP_next_tsn(pl_fwd_tsn.new_tsn)
+  return 1 // trigger the data processing
+}
+
+
+// process forward TSN chunk
+function SCTP_message_incoming_forward_tsn_handler(in SCTP_Forward_TSN_chunk pl_fwd_tsn,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+
+  if(SCTP_compare_tsn(pl_fwd_tsn.new_tsn,v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn)<0){
+    // The new TSN has been acked already. Just trigger the SACK
+    return 1
+  }
+  
+  // Clean up the data queue
+  // Mark every hole as processed packet until the new tsn
+  // The data processor part will do the magic later
+ 
+  var integer vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.first_element
+  
+  while(vl_idx!=-1){
+    if( SCTP_compare_tsn(pl_fwd_tsn.new_tsn,v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.chunk_queue[vl_idx].tsn)<0){
+      // the tsn of the chunk is greater than the new tsn
+      break; // we are done
+    }
+    
+    if(not ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.chunk_queue[vl_idx].chunk)){
+      // A hole, mark it.
+      v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.chunk_queue[vl_idx].mark_flag:= true
+    }
+    vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue.chunk_queue[vl_idx].next_element
+  }
+  
+  // clean up the queues
+  for(var integer vl_i:=0;vl_i<lengthof(pl_fwd_tsn.stream_ssn_list);vl_i:=vl_i+1){
+    SCTP_message_queue_skip_ssn(pl_assoc_id,pl_fwd_tsn.stream_ssn_list[vl_i].stream_id,pl_fwd_tsn.stream_ssn_list[vl_i].ssn,v_assoc_db.associations[pl_assoc_id].assoc_data.rx_msg_queues )
+  }
+  v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn:=SCTP_next_tsn(pl_fwd_tsn.new_tsn)
+  return 1 // trigger the data processing
+}
+
+// Mark the messages as skiped based in the forward tsn chunk data
+function SCTP_message_queue_skip_ssn( in integer pl_assoc_id,  // The association
+                                      in integer pl_stream_id,
+                                      in integer pl_skipped_ssn,
+                                      inout SCTP_msg_queue_list_t pl_msg_queue_list
+                                      ) runs on SCTP_Engine_CT {
+
+  var integer vl_stream_idx:=-1; // index of the stream in the pl_msg_queue_list
+  if(SCTP_int2int_get(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_stream_idx_map_id,
+                            pl_stream_id,
+                            vl_stream_idx
+                            )==-1){
+    // not seen stream
+    // create it
+    vl_stream_idx:=lengthof(pl_msg_queue_list)
+    // ordered queue
+    pl_msg_queue_list[vl_stream_idx]:=c_empty_msg_queue;
+    pl_msg_queue_list[vl_stream_idx].next_ssn:=SCTP_next_ssn(pl_skipped_ssn); // store the next expected ssn
+
+    // undered queue
+    pl_msg_queue_list[vl_stream_idx+1]:=c_empty_msg_queue;
+    pl_msg_queue_list[vl_stream_idx+1].next_ssn:=-1; // Not used queue
+    
+  } else {
+    var integer vl_idx:=pl_msg_queue_list[vl_stream_idx].messages.first_element
+    while(vl_idx!=-1){
+      if(SCTP_compare_ssn(SCTP_data_get_chunk_ssn(pl_msg_queue_list[vl_stream_idx].messages.chunk_queue[vl_idx].chunk),pl_skipped_ssn )<=0){
+        // ssn less than the last skiped, mark it 
+        pl_msg_queue_list[vl_stream_idx].messages.chunk_queue[vl_idx].mark_flag:=true
+      } else {
+        break; //no more ssn to mark
+      }
+    }
+    
+    if(SCTP_compare_ssn(pl_msg_queue_list[vl_stream_idx].next_ssn,pl_skipped_ssn)<=0){
+      // afdjust the next ssn if needed
+      pl_msg_queue_list[vl_stream_idx].next_ssn:=SCTP_next_ssn(pl_skipped_ssn)
+    }
+    
+  }
+  
+}
+
+// Handles the incoming HEARTBEAT_ACK
+function SCTP_message_incoming_heartbeat_ack_handler(in SCTP_Heartbeat_ack_chunk pl_hb_ack,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+
+  // reset the hearbeat counter
+  v_assoc_db.associations[pl_assoc_id].assoc_data.hb_retrial_counter:=0
+  return 0
+}
+// Handles the incoming HEARTBEAT
+function SCTP_message_incoming_heartbeat_handler(in SCTP_Heartbeat_chunk pl_hb,  // The chunk to process
+                                                   in integer pl_assoc_id,  // The association
+                                                   inout SCTP_Packet       pl_response // Add the heartbeat_ack to the response
+                                                  ) runs on SCTP_Engine_CT return integer {
+
+  select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+    case ( (SCTP_ASSOC_COOKIE_ECHOED,SCTP_ASSOC_ESTABLISHED,SCTP_ASSOC_SHUTDOWN_PENDING,SCTP_ASSOC_SHUTDOWN_RECEIVED)){
+      // A receiver of a HEARTBEAT MUST respond to a
+      // HEARTBEAT with a HEARTBEAT-ACK after entering the COOKIE-ECHOED state
+      // (INIT sender) or the ESTABLISHED state (INIT receiver), up until
+      // reaching the SHUTDOWN-SENT state (SHUTDOWN sender) or the SHUTDOWN-
+      // ACK-SENT state (SHUTDOWN receiver).    
+      
+      // Add the heartbeat ack chunk to the response
+      pl_response.chunks[lengthof(pl_response.chunks)]:={heartbeat_ack:={ chunk_type :=5,
+                                                                          flags := '00000000'B,
+                                                                          chunk_length := 0,
+                                                                          params :=pl_hb.params 
+                                                                          }}
+
+    }
+  }
+
+  
+
+  return 0
+}
+
+// Handles the incoming SHUTDOWN COMPLETE
+function SCTP_message_incoming_shutdown_complete_handler(in SCTP_ShutdownComplete_chunk pl_shutdown,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+    select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+      case ( (SCTP_ASSOC_SHUTDOWN_SENT,SCTP_ASSOC_SHUTDOWN_ACK_SENT)){
+        
+        // Notify the user
+        var SCTP_Shutdown_data vl_sh_data:={
+            assoc_id:=pl_assoc_id,
+            graceful_shutdown := true,
+            reason := "Shutdown finished"
+          }
+
+        p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+        
+        SCTP_assoc_set_closed(pl_assoc_id)
+  
+      }
+    }
+  return -1
+
+}
+
+// Handles the incoming SHUTDOWN ACK
+function SCTP_message_incoming_shutdown_ack_handler(in SCTP_Shutdown_ack_chunk pl_shutdown,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+    select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+      case ( (SCTP_ASSOC_SHUTDOWN_SENT,SCTP_ASSOC_SHUTDOWN_ACK_SENT)){
+        
+
+        SCTP_timer_stop_all(pl_assoc_id)
+        // Send Shutdown Complete
+        SCTP_message_send_shutdown_complete(-,-,pl_assoc_id)
+        
+        // delay the shutdown ind in order to give a chance to deliver the shutdown complete message
+        // The user may destroy the underlying transport in the case of shutdown ind
+        v_assoc_db.associations[pl_assoc_id].assoc_data.state:=SCTP_ASSOC_CLOSE_TIME_WAIT
+        
+        v_assoc_db.associations[pl_assoc_id].assoc_data.close_timer:=SCTP_event_schedule(pl_assoc_id,c_timer_close,v_assoc_db.associations[pl_assoc_id].assoc_data.rto)
+        
+        
+      }
+    }
+  return -1
+}
+
+
+// Handles the incoming SHUTDOWN
+function SCTP_message_incoming_shutdown_handler(in SCTP_Shutdown_chunk pl_shutdown,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+    select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+      case ( (SCTP_ASSOC_ESTABLISHED,SCTP_ASSOC_SHUTDOWN_PENDING)){
+        // Set the state
+        v_assoc_db.associations[pl_assoc_id].assoc_data.state:=SCTP_ASSOC_SHUTDOWN_RECEIVED
+        
+        // Process the cum_tsn_ack
+        SCTP_message_cumulative_ack_handler(pl_shutdown.cum_tsn_ack,pl_assoc_id) 
+        // Schedule the sending of the data
+        // The data send scheduler will check the state and if no outstanding data
+        // will send shutdown ack and move to 
+        SCTP_data_send_scheduler(pl_assoc_id)
+        
+        // Notify the user
+        if(v_assoc_db.associations[pl_assoc_id].assoc_data.state==SCTP_ASSOC_ESTABLISHED){
+          var SCTP_Notification_data vl_notification:={
+            assoc_id := pl_assoc_id,
+            notification:= {comm_lost  := {}},
+            options := omit
+          }
+          p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_notification},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+        }
+      
+      }
+      case (SCTP_ASSOC_SHUTDOWN_RECEIVED){
+        // Process the cum_tsn_ack
+        SCTP_message_cumulative_ack_handler(pl_shutdown.cum_tsn_ack,pl_assoc_id) 
+        // Schedule the sending of the data
+        // The data send scheduler will check the state and if no outstanding data
+        // will send shutdown ack and move to 
+        SCTP_data_send_scheduler(pl_assoc_id)
+      
+      }
+      case (SCTP_ASSOC_SHUTDOWN_SENT){
+        // Set the state
+        v_assoc_db.associations[pl_assoc_id].assoc_data.state:=SCTP_ASSOC_SHUTDOWN_RECEIVED
+        // The data send scheduler will check the state and if no outstanding data
+        // will send shutdown ack
+        SCTP_data_send_scheduler(pl_assoc_id)
+      }
+    }
+  return 0
+}
+
+// Handles the incoming ABORT
+function SCTP_message_incoming_abort_handler(in SCTP_abort_chunk pl_abort,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+  
+  // Notify the user
+  var SCTP_Notification_data vl_notification:={
+    assoc_id := pl_assoc_id,
+    notification:= {comm_lost  := {}},
+    options := omit
+  }
+  p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_notification},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+
+  var SCTP_Shutdown_data vl_sh_data:={
+      assoc_id:=pl_assoc_id,
+      graceful_shutdown := false,
+      reason := "Abort received"
+    }
+  
+  // Store the reason if available
+  if(ispresent(pl_abort.params)){
+    vl_sh_data.reason:=log2str(pl_abort.params)
+  }
+
+  p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+
+  SCTP_assoc_set_closed(pl_assoc_id)  
+  // Stop the further processing
+  return -1
+}
+
+// Handles the incoming SACK
+function SCTP_message_incoming_sack_handler(in SCTP_SAck_chunk pl_sack,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+    select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+      case ((SCTP_ASSOC_ESTABLISHED,SCTP_ASSOC_SHUTDOWN_PENDING,SCTP_ASSOC_SHUTDOWN_RECEIVED)){
+          var integer vl_tsn_comp:=SCTP_message_cumulative_ack_handler( pl_sack.cum_tsn_ack,pl_assoc_id)
+          if(vl_tsn_comp==-1){
+            // TSN already acked
+            // do nothing
+            return 0 // next chunk
+          }
+          // update the peers window size
+          v_assoc_db.associations[pl_assoc_id].assoc_data.remote_a_rwnd:= pl_sack.a_rwnd
+          if(vl_tsn_comp==0){
+            // No new TSN are ACK-ed.
+            if(( pl_sack.a_rwnd==0) and // the peers window is closed
+                (v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter == v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.assoc_max_retrans)  // retransmitting the zero probe, last trial
+                ){
+                // Don't let the retransmitt counter overflow
+                v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter := v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter - 1
+            }
+          } else {
+            // stop the T3 timer, the SCTP_data_send_scheduler will restart it if needed
+            if(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event!=-1){
+              SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event)
+              v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+            }
+            // Something ack-ed -> try to send the remaining data
+            SCTP_data_send_scheduler(pl_assoc_id)
+
+          }
+
+          // TODO: handle gaps for fast retransmit
+
+      }
+    }
+  return 0
+
+}
+
+// Processes the cumulative TSN ack
+// return value:
+// -1: The acked TSN is less than the last acked
+//  0: The acked TSN is the same as the last acked
+//  1: New TSN is acked
+function SCTP_message_cumulative_ack_handler(in integer pl_ack, in integer pl_assoc_id)  runs on SCTP_Engine_CT return integer {
+  var integer vl_tsn_comp:=SCTP_compare_tsn( pl_ack,v_assoc_db.associations[pl_assoc_id].assoc_data.remote_last_sack_tsn)
+  if(vl_tsn_comp==-1){
+    // TSN already acked
+    // do nothing
+    return -1 //The acked TSN is less than the last acked
+  }
+  if(vl_tsn_comp==0){
+    // No new TSN are ACK-ed.
+    return 0
+  }
+  // New TSN's acked
+  // The remote side is alive, clear the retransmit counter
+  v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter := 0
+
+  // remove the acked TSN-s from the tx chunk queue.
+  var integer vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.first_element
+  var integer acked_bytes:=0
+  while((vl_idx!=-1) and (SCTP_compare_tsn(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_idx].tsn,pl_ack)<1) ){
+    acked_bytes:=acked_bytes+SCTP_data_get_chunk_size(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_idx].chunk)
+
+    // decrease the flight size
+    v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size:=v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size-SCTP_data_get_chunk_size(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_idx].chunk)
+    // remove the chunk
+    SCTP_Chunk_queue_pop(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue)
+    // next chunk idx
+    vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.first_element 
+  }
+  //adjust the cwnd
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd<v_assoc_db.associations[pl_assoc_id].assoc_data.ssthresh){
+    // slow-start case
+    if((v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size+acked_bytes) >= (v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd-c_min_chunk_size)){
+      // The cwnd is fully utilized
+      v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd:= v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd + SCTP_min(acked_bytes,v_assoc_db.associations[pl_assoc_id].assoc_data.pmtu)
+    }
+  } else {
+    // congestion avoidance case
+    v_assoc_db.associations[pl_assoc_id].assoc_data.partially_acked_bytes := v_assoc_db.associations[pl_assoc_id].assoc_data.partially_acked_bytes + acked_bytes
+    if((v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size+acked_bytes) >= (v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd-c_min_chunk_size)){
+      // The cwnd is fully utilized
+      v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd:= v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd + v_assoc_db.associations[pl_assoc_id].assoc_data.pmtu
+      v_assoc_db.associations[pl_assoc_id].assoc_data.partially_acked_bytes := v_assoc_db.associations[pl_assoc_id].assoc_data.partially_acked_bytes - v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd
+    }
+    
+  }
+
+  // Remember to the last ack-ed 
+  v_assoc_db.associations[pl_assoc_id].assoc_data.remote_last_sack_tsn:= pl_ack
+
+
+  return 1 //  1: New TSN is acked
+
+}
+
+// Handles the incoming DATA
+function SCTP_message_incoming_data_handler(in SCTP_Chunk pl_data,  // The chunk to process
+                                                   in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+//log("data handler state, ", v_assoc_db.associations[pl_assoc_id].assoc_data.state)
+    select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+      case (SCTP_ASSOC_ESTABLISHED,SCTP_ASSOC_SHUTDOWN_PENDING,SCTP_ASSOC_SHUTDOWN_SENT){
+          if(SCTP_compare_tsn(SCTP_data_get_chunk_tsn(pl_data),v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn)>=0){
+            // put the chunk into the rx data chunk queue
+            SCTP_data_insert_into_rx(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_chunk_queue, // The queue
+                                     v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn,   // The first expected tsn of the queue, if empty
+                                     pl_data,
+                                     pl_assoc_id) // The chunk
+            
+          } //else {
+            // The TSN is smaller than the last ack-ed
+            // just drop the chunk
+            // do nothing
+          //}
+//log("return 1")
+          return 1
+      }
+    }
+//log("return 0")
+  return 0
+}
+// Handles the incoming COOKIE-ECHO
+function SCTP_message_incoming_cookie_echo_handler(in SCTP_CookieEcho_chunk pl_cookie_echo,  // The chunk to process
+                                                  in integer pl_assoc_id,  // The association
+                                                  inout SCTP_Packet pl_response, // place the cookie echo into this message, if DATA chunk is also received, the SACK will be added later
+                                                  in boolean pl_cookie_preprocessed
+                                                  ) runs on SCTP_Engine_CT return integer {
+    select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+      case (SCTP_ASSOC_ESTABLISHED){
+        // Process the messages and send answers if needed
+          if(pl_cookie_preprocessed){
+            // Only the cookie ack is should be sent
+            pl_response.chunks[lengthof(pl_response.chunks)]:={
+                cookie_ack:={
+                  chunk_type := 11,
+                  flags := '00000000'B,
+                  chunk_length := 0
+                }
+              }
+          } else {
+            // TODO: Restart
+          }
+      }
+    }
+  return 0
+}
+// Handles the incoming COOKIE-ACK
+function SCTP_message_incoming_cookie_ack_handler(in SCTP_Cookie_ack_chunk pl_cookie_ack,  // The chunk to process
+                                                  in integer pl_assoc_id  // The association
+                                                  ) runs on SCTP_Engine_CT return integer {
+ 
+    select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+      case (SCTP_ASSOC_COOKIE_ECHOED) {
+          v_assoc_db.associations[pl_assoc_id].assoc_data.state:=SCTP_ASSOC_ESTABLISHED
+          // Start hearbeat
+          SCTP_hearbeat_start(pl_assoc_id)
+          
+          
+          // Stop the T1_cookie timer
+          SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event)
+          v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+          
+          // Notify the user
+          var SCTP_Notification_data vl_notification:={
+            assoc_id := pl_assoc_id,
+            notification:= {comm_up  := {}},
+            options := {
+              {i_data_supported:=v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported},
+              {reconfig_params:=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params},
+              {forward_tsn_supported:=v_assoc_db.associations[pl_assoc_id].assoc_data.forward_tsn_supported}
+
+            }
+          }
+          SCTP_congestion_set_init_params(pl_assoc_id)
+          v_assoc_db.associations[pl_assoc_id].assoc_data.remote_last_sack_tsn := (v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn - 1) mod 4294967296
+          p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_notification},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+          // Reset the retransmit counter
+          v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=0
+      }
+    }
+  return 0
+}
+// Handles the incoming INIT-ACK chunk
+function SCTP_message_incoming_init_ack_handler(in SCTP_InitAck_chunk pl_init_ack,  // The chunk to process
+                                                in integer pl_assoc_id,  // The association
+                                                in integer pl_chunk_idx  // The index of the chunk in the incoming message
+                                                 ) runs on SCTP_Engine_CT return integer {
+    select(v_assoc_db.associations[pl_assoc_id].assoc_data.state){
+      case (SCTP_ASSOC_COOKIE_WAIT) {
+      
+        // Only the INIT ACK is acceptable
+        if( pl_chunk_idx == 0) {
+          
+          // Find the cookie for echo
+          var integer vl_cookie_idx:=-1
+          var integer vl_supported_ext_idx:=-1
+          var integer vl_supported_forward_tsn_idx:=-1
+          
+          if(ispresent(pl_init_ack.params)){
+            for(var integer vl_l:=0;vl_l<lengthof(pl_init_ack.params);vl_l:=vl_l+1){
+              if(ischosen(pl_init_ack.params[vl_l].state_cookie)){
+                vl_cookie_idx:=vl_l
+              }
+              if(ischosen(pl_init_ack.params[vl_l].supported_extensions)){
+                vl_supported_ext_idx:=vl_l
+              }
+              if(ischosen(pl_init_ack.params[vl_l].forward_tsn_supported)){
+                vl_supported_forward_tsn_idx:=vl_l
+              }
+
+            }
+          }
+          
+          // Is there a cookie?
+          if(vl_cookie_idx==-1){
+            // No?
+            // Drop the packet
+            log("No cookie in the INIT_ACK. Dropped. ")
+            return -1;
+          }
+          // The INIT_ack seems OK
+          
+          // Stop the timer
+          SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event)
+          v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+         
+          // Update the database
+          v_assoc_db.associations[pl_assoc_id].assoc_data:={
+            state:=SCTP_ASSOC_COOKIE_ECHOED,
+            remote_tag:=pl_init_ack.init_tag,
+            remote_tsn:=pl_init_ack.init_tsn,
+            remote_os:=pl_init_ack.os,
+            remote_mis:=pl_init_ack.mis,
+            remote_a_rwnd:=pl_init_ack.a_rwnd,
+            state_cookie:=pl_init_ack.params[vl_cookie_idx].state_cookie.state_cookie,
+            reconf_remote_seq_num:=pl_init_ack.init_tsn
+          }
+          
+          // Check the extensions support
+          var boolean vl_idata:=false
+          var boolean vl_reconf:=false
+          if(vl_supported_ext_idx!=-1){
+
+            for(var integer vl_i:=0;vl_i<lengthof(pl_init_ack.params[vl_supported_ext_idx].supported_extensions.supported_extensions);vl_i:=vl_i+1){
+              if(pl_init_ack.params[vl_supported_ext_idx].supported_extensions.supported_extensions[vl_i]==64){  // IDATA chunk
+                vl_idata:=true
+              }
+              if(pl_init_ack.params[vl_supported_ext_idx].supported_extensions.supported_extensions[vl_i]==130){  // IDATA chunk
+                vl_reconf:=true
+              }
+            }
+          }
+
+          v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported:=vl_idata and v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported
+          v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.is_supported:= vl_reconf and v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.is_supported
+          v_assoc_db.associations[pl_assoc_id].assoc_data.forward_tsn_supported:= (vl_supported_forward_tsn_idx!=-1) and v_assoc_db.associations[pl_assoc_id].assoc_data.forward_tsn_supported
+            
+          
+          // Send the Cookie Echo
+          SCTP_message_send_cookie_echo(pl_assoc_id)
+          
+          // Reset the retransmit counter and start the timer
+          v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=0
+          v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                           SCTP_event_schedule(pl_assoc_id,c_timer_T1_cookie,v_assoc_db.associations[pl_assoc_id].assoc_data.rto)
+        } else {
+          // Something else received
+          // Drop it
+          log("Unexpected packet, dorpped: ")
+          return -1
+        }
+      }
+    }
+
+  return 0
+}
+
+//Clean ups the acked and processed messages from the rx chunk queue
+function SCTP_data_clean_tx_chunk_queue(inout SCTP_Chunk_queue_db_t pl_queue, in integer pl_assoc_id) runs on SCTP_Engine_CT  {
+  var integer vl_chunk_idx:=pl_queue.first_element
+  while(vl_chunk_idx!=-1){
+    if( pl_queue.chunk_queue[vl_chunk_idx].mark_flag ){
+      // If the first element is marked, it is acked 
+      SCTP_Chunk_queue_pop(pl_queue)
+      
+      if(v_assoc_db.associations[pl_assoc_id].assoc_data.idx_of_last_acked==vl_chunk_idx){
+        v_assoc_db.associations[pl_assoc_id].assoc_data.idx_of_last_acked:=-1
+        break; // We reached the last acked chunk
+      } else {
+        vl_chunk_idx:=pl_queue.first_element
+      }
+    } else {
+      break; // The chunk can not be removed from the incoming queue
+    }
+  }
+
+}
+
+// Delivers the whole messages to the user
+function SCTP_data_deliver(inout SCTP_msg_queue_list_t pl_msg_queue_list, in integer pl_assoc_id) runs on SCTP_Engine_CT  {
+  // Iterate through the rx message queues and deliver the messages
+  for(var integer vl_idx:=0; vl_idx<lengthof(pl_msg_queue_list);vl_idx:=vl_idx+1){
+    // The ordered queue
+    var integer vl_msg_idx:=pl_msg_queue_list[vl_idx].messages.first_element
+    while(vl_msg_idx!=-1){
+      // check the messages in the stream queue
+      if(SCTP_message_get_E_bit(pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].chunk)=='1'B){
+        // Whole message
+        var SCTP_MSG_data vl_msg_data
+        SCTP_data_get_msg_data(pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].chunk,vl_msg_data,pl_assoc_id) // Copy the msg 
+        // Deliver it
+        p_sctp_ind_api.call(S_SCTP_Received_ind:{vl_msg_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+        // Remove from the queue
+        SCTP_Chunk_queue_pop(pl_msg_queue_list[vl_idx].messages)
+        
+        vl_msg_idx:=pl_msg_queue_list[vl_idx].messages.first_element
+      } else {
+        if(not pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].mark_flag){
+          break;  // we reached the first not fully received message
+        } else {
+          // the msg are marked as skiped, skip it
+          SCTP_Chunk_queue_pop(pl_msg_queue_list[vl_idx].messages)
+
+          vl_msg_idx:=pl_msg_queue_list[vl_idx].messages.first_element
+        }
+      }
+    }
+    
+    // The unordered queue
+    vl_idx:=vl_idx+1
+    vl_msg_idx:=pl_msg_queue_list[vl_idx].messages.first_element
+    while(vl_msg_idx!=-1){
+      // check the messages in the stream queue
+      if( (not pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].mark_flag)  // already processed
+        and (SCTP_message_get_E_bit(pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].chunk)=='1'B) // End flag
+       ){
+        // Whole message
+        var SCTP_MSG_data vl_msg_data
+        SCTP_data_get_msg_data(pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].chunk,vl_msg_data,pl_assoc_id) // Copy the msg 
+        // Deliver it
+        p_sctp_ind_api.call(S_SCTP_Received_ind:{vl_msg_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+        
+        // Mark the msg      
+        pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].mark_flag:=true
+      }
+      
+      // detect the skiped element
+      // For unordered message no direct signal of the skiped messages
+      // But if there is a next message and the tsn of the last fragement < acked tsn
+      // the message is skiped. 
+      // Not allowed to interleave two unordered message of the same queue
+      if((pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].next_element!=-1)
+         and (SCTP_compare_tsn(SCTP_data_get_chunk_tsn(pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].chunk),v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn)<=0)){
+        // Mark the msg      
+        pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].mark_flag:=true
+      }
+      
+      if(pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].mark_flag // already processed
+         and (vl_msg_idx==pl_msg_queue_list[vl_idx].messages.first_element) // first of the queue
+         ){
+      
+         // remove it from the queue
+         SCTP_Chunk_queue_pop(pl_msg_queue_list[vl_idx].messages)
+         vl_msg_idx:=pl_msg_queue_list[vl_idx].messages.first_element
+         
+      } else {
+        vl_msg_idx:=pl_msg_queue_list[vl_idx].messages.chunk_queue[vl_msg_idx].next_element
+      }
+      
+    }
+  }
+
+}
+
+
+// Insert the chunk into the rx queue
+// pl_queue - the queue, where to insert the chunk
+// pl_expected_tsn - If the queue is empty the new first chunk should use this tsn
+// pl_chunk - the chunk to insert
+function SCTP_data_insert_into_rx(inout SCTP_Chunk_queue_db_t pl_queue, in integer pl_expected_tsn,in SCTP_Chunk pl_chunk, in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  var integer vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.idx_of_last_acked
+  var integer vl_tsn:=pl_expected_tsn
+  var integer vl_chunk_tsn:=SCTP_data_get_chunk_tsn(pl_chunk)
+  // set the index to pint to the first not acked item
+  if(vl_idx==-1){
+    // the last_acked was removed from the queue
+    // take the first element
+    vl_idx:=pl_queue.first_element
+  } else {
+    // pick the next one
+    vl_tsn:=SCTP_next_tsn(pl_queue.chunk_queue[vl_idx].tsn) // set the tsn counter
+    vl_idx:=pl_queue.chunk_queue[vl_idx].next_element
+  }
+  // find the place of the item
+  
+  while(true){
+    if(vl_idx==-1){
+      // We need to add item
+      SCTP_Chunk_queue_push(pl_queue,c_empty_Chunk_queue_element)
+      vl_idx:=pl_queue.last_element
+      pl_queue.chunk_queue[vl_idx].tsn:=vl_tsn
+    }
+    if(pl_queue.chunk_queue[vl_idx].tsn == vl_chunk_tsn){
+      break; // we found the place
+    }
+    // move to the next item
+    vl_idx:=pl_queue.chunk_queue[vl_idx].next_element
+    // take next tsn
+    vl_tsn:=SCTP_next_tsn(vl_tsn)
+  }
+  
+  // store the chunk
+  pl_queue.chunk_queue[vl_idx].chunk:=pl_chunk
+  
+}
+
+// Construct the messages from the rx chunk queue
+// scans the rx chunk queue for a messages
+
+function SCTP_data_chunk2msg(inout SCTP_Chunk_queue_db_t pl_queue, inout SCTP_msg_queue_list_t pl_msg_queue_list, in integer pl_assoc_id) runs on SCTP_Engine_CT  {
+  var integer vl_chunk_idx:=pl_queue.first_element
+  var boolean vl_gap_found:=false
+  
+  while(vl_chunk_idx!=-1){
+    if(ispresent(v_assoc_db.associations[pl_assoc_id].assoc_data.deffered_reset)){
+      // See rfc6525 5.2.2. E2:
+      if(SCTP_compare_tsn(pl_queue.chunk_queue[vl_chunk_idx].tsn,v_assoc_db.associations[pl_assoc_id].assoc_data.deffered_reset.last_assigned_tsn )>0){
+        break;
+      }
+    }
+  
+  
+    if(not pl_queue.chunk_queue[vl_chunk_idx].mark_flag){ 
+      // The chunk is not marked. Means was not put into the rx stream message queue
+      if(ispresent(pl_queue.chunk_queue[vl_chunk_idx].chunk)){
+        // Find the stream queue of the message
+        var integer vl_stream_idx:=-1; // index of the stream in the pl_msg_queue_list
+        var integer vl_stream_id:=SCTP_data_get_chunk_stream_id(pl_queue.chunk_queue[vl_chunk_idx].chunk) // The stream identifier
+        var integer vl_stream_seq_no
+        if(SCTP_int2int_get(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_stream_idx_map_id,
+                            vl_stream_id,
+                            vl_stream_idx
+                            )==-1){
+          // New incoming stream
+          // Is this the first message in the stream?
+          if( ((not vl_gap_found)  // All of the previous chunk received, this is the first chunk of the first message
+                                 // of the stream. Or the remote side is sending a shit (or I forgot something)
+             or ( (SCTP_message_get_U_bit(pl_queue.chunk_queue[vl_chunk_idx].chunk))=='1'B) )  // or first chunk of an unordered msg
+                  and  (SCTP_message_get_B_bit(pl_queue.chunk_queue[vl_chunk_idx].chunk)=='1'B) 
+             ){
+            vl_stream_idx:=lengthof(pl_msg_queue_list)
+            // ordered queue
+            pl_msg_queue_list[vl_stream_idx]:=c_empty_msg_queue;
+            pl_msg_queue_list[vl_stream_idx].next_ssn:=-1; // Not used queue
+            
+            // undered queue
+            pl_msg_queue_list[vl_stream_idx+1]:=c_empty_msg_queue;
+            pl_msg_queue_list[vl_stream_idx+1].next_ssn:=-1; // Not used queue
+            if(SCTP_int2int_add(v_assoc_db.associations[pl_assoc_id].assoc_data.rx_stream_idx_map_id,
+                            vl_stream_id,
+                            vl_stream_idx) == -1){
+                              log("Intenal error")
+                            }
+          } else {
+            vl_stream_idx:=-1 // We can't be sure that this is the first message of the stream
+          }
+        }
+        
+        if(vl_stream_idx!=-1){
+        // valid stream
+          if(SCTP_message_get_U_bit(pl_queue.chunk_queue[vl_chunk_idx].chunk)=='0'B){
+            //ordered
+            if(pl_msg_queue_list[vl_stream_idx].next_ssn!=-1 or (not vl_gap_found)){
+              // In the case of the ordered message
+              // Try to store the first message if all of the previous chunk has been received.
+              SCTP_data_find_store_chunk(pl_msg_queue_list[vl_stream_idx],pl_queue.chunk_queue[vl_chunk_idx],false)
+            }
+          } else {
+            //unordered
+            SCTP_data_find_store_chunk(pl_msg_queue_list[vl_stream_idx+1],pl_queue.chunk_queue[vl_chunk_idx],true)
+          }
+        }
+        
+        if(SCTP_compare_tsn(SCTP_data_get_chunk_tsn(pl_queue.chunk_queue[vl_chunk_idx].chunk), v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn)<=0){
+          // if the tsn of the packet is already ack-ed mark it for clean up
+          pl_queue.chunk_queue[vl_chunk_idx].mark_flag:=true
+        }
+      } else {
+        // found a gap
+        vl_gap_found:=true
+      }
+    }
+    vl_chunk_idx:=pl_queue.chunk_queue[vl_chunk_idx].next_element
+  }
+}
+
+// Stores the message in the msg queue if applicable
+function SCTP_data_find_store_chunk(inout SCTP_msg_queue_t pl_msg_db, inout SCTP_Chunk_queue_element_t pl_chunk, in boolean pl_unordered){
+  if(((pl_msg_db.next_ssn==-1) or  // not used queue
+     (pl_msg_db.next_ssn==SCTP_data_get_chunk_ssn(pl_chunk.chunk)) // next expected message
+     or  pl_unordered) // Unordered
+     and  
+     (SCTP_message_get_B_bit(pl_chunk.chunk)=='1'B)  // First chunk of the message
+     ){
+     // unused queue, first chunk of the message
+     // or the first chunk of the next expected message
+     // Add the chunk as the first chunk of the next message
+     SCTP_Chunk_queue_push(pl_msg_db.messages,pl_chunk)
+     pl_chunk.mark_flag:=true  // Chunk is in the rx stream message queue
+     pl_msg_db.next_ssn:=SCTP_next_ssn(SCTP_data_get_chunk_ssn(pl_chunk.chunk)) // Store the next ssn of the stream
+     pl_msg_db.messages.chunk_queue[pl_msg_db.messages.last_element].tsn:=SCTP_next_tsn(SCTP_data_get_chunk_reassembly_seq_no(pl_chunk.chunk)) // store the next TSN/FSN
+     return 
+  }
+  
+  // Find the message
+  var integer vl_idx:=pl_msg_db.messages.first_element
+  while(vl_idx!=-1){
+    if(SCTP_data_get_chunk_ssn(pl_msg_db.messages.chunk_queue[vl_idx].chunk) == SCTP_data_get_chunk_ssn(pl_chunk.chunk)){
+      // This is the message we're looking for
+      // Is this the next chunk?
+      if(pl_msg_db.messages.chunk_queue[vl_idx].tsn== SCTP_data_get_chunk_reassembly_seq_no(pl_chunk.chunk)){
+        // yes, this is
+        // append the data part.
+        SCTP_data_chunk_append_data(pl_msg_db.messages.chunk_queue[vl_idx].chunk,pl_chunk.chunk)
+        
+        // updated the stored tsn of the message for support the RFC3758
+        SCTP_data_chunk_copy_tsn(pl_msg_db.messages.chunk_queue[vl_idx].chunk,pl_chunk.chunk)
+        
+        pl_chunk.mark_flag:=true  // Chunk is in the rx stream message queue
+        
+        pl_msg_db.messages.chunk_queue[vl_idx].tsn := SCTP_next_tsn(pl_msg_db.messages.chunk_queue[vl_idx].tsn) // store th enext expected TSN/FSN
+        // Set E bit if needed
+        if(SCTP_message_get_E_bit(pl_chunk.chunk)=='1'B){
+          SCTP_message_set_E_bit('1'B,pl_msg_db.messages.chunk_queue[vl_idx].chunk)
+        }
+        
+        
+      }
+      return 
+    }
+    
+    vl_idx:=pl_msg_db.messages.chunk_queue[vl_idx].next_element
+    
+  }
+  
+
+}
+
+// Generates SACK from the rx queue
+// pl_queue - the queue, where to insert the chunk
+// pl_remote_tsn - The last acked tsn+1
+// pl_chunk - the chunk to return the SACK
+function SCTP_data_gen_sack(in SCTP_Chunk_queue_db_t pl_queue, in integer pl_remote_tsn,out SCTP_Chunk pl_chunk, in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  var integer vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.idx_of_last_acked
+  // set the index to point to the first not acked item
+//log("*************************")
+//log(pl_queue)
+//log(pl_remote_tsn)
+//log(pl_assoc_id)
+//log("*************************")
+  if(vl_idx==-1){
+    // the last_acked was removed from the queue
+    // take the first element
+    vl_idx:=pl_queue.first_element
+    if(vl_idx!=-1 and 
+      ((not ispresent(pl_queue.chunk_queue[vl_idx].chunk)) or  pl_queue.chunk_queue[vl_idx].mark_flag )
+    ){
+      //  The first element represents a non marked hole
+      vl_idx:=-1 // no new chunk to ack
+    }
+  }  
+  // find the last element before a hole/end
+  while( (vl_idx != -1) and // valid element
+         (pl_queue.chunk_queue[vl_idx].next_element!=-1) and // has a next element
+         (ispresent(pl_queue.chunk_queue[pl_queue.chunk_queue[vl_idx].next_element].chunk) or  pl_queue.chunk_queue[pl_queue.chunk_queue[vl_idx].next_element].mark_flag)// wich is not a hole
+       ){
+    vl_idx:=pl_queue.chunk_queue[vl_idx].next_element // advance to it
+  }
+  
+  var integer vl_sack_tsn
+  if(vl_idx != -1){
+    vl_sack_tsn:=pl_queue.chunk_queue[vl_idx].tsn
+  } else {
+    vl_sack_tsn:= SCTP_prev_tsn(pl_remote_tsn)
+  }
+  
+  pl_chunk.sack:={
+    chunk_type:= 3,
+    flags := '00000000'B,
+    chunk_length:=0,
+    cum_tsn_ack:=vl_sack_tsn,
+    a_rwnd:=65535,
+    no_of_gap_blocks:=0,
+    no_of_dup_tsn:=0,
+    gap_blocks:=omit,
+    dup_tsns:=omit
+  }
+  
+  // set the pointers
+  v_assoc_db.associations[pl_assoc_id].assoc_data.idx_of_last_acked:=vl_idx
+  v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn:=SCTP_next_tsn(vl_sack_tsn)
+}
+
+//Process the incoming INIT & COOKIE ECHO
+function SCTP_message_incoming_init_cookie_handler(in integer pl_assoc_id,
+                                       in integer pl_transport_id,
+                                       in SCTP_Packet pl_sctp_packet) runs on SCTP_Engine_CT  {
+
+  if(ischosen(pl_sctp_packet.chunks[0].init)){
+    // INIT chunk received. Generate INIT-ACK
+    var SCTP_Packet       vl_response := c_empty_sctp_packet
+    var SCTP_InitAck_chunk vl_initack_chunk := c_empty_init_ack_chunk
+    var integer vl_init_tag:=SCTP_rnd_32bit_int()
+    
+    //Check the supported extensions
+    var boolean vl_idata:=false
+    var boolean vl_reconf:=false
+    var boolean vl_fwd_tsn:=false
+    if(ispresent(pl_sctp_packet.chunks[0].init.params)){
+      for(var integer vl_i:=0;vl_i<lengthof(pl_sctp_packet.chunks[0].init.params);vl_i:=vl_i+1){
+        if(ischosen(pl_sctp_packet.chunks[0].init.params[vl_i].supported_extensions)){
+            for(var integer vl_k:=0;vl_k<lengthof(pl_sctp_packet.chunks[0].init.params[vl_i].supported_extensions.supported_extensions);vl_k:=vl_k+1){
+              if((pl_sctp_packet.chunks[0].init.params[vl_i].supported_extensions.supported_extensions[vl_k]==64)){
+                vl_idata:=true
+              }
+              if((pl_sctp_packet.chunks[0].init.params[vl_i].supported_extensions.supported_extensions[vl_k]==130)){
+                vl_reconf:=true
+              }
+            }
+          
+        } else if(ischosen(pl_sctp_packet.chunks[0].init.params[vl_i].forward_tsn_supported)){
+          vl_fwd_tsn:=true
+        }
+      }
+    }
+    vl_idata:=vl_idata and v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported // support if requested both by the user and remote side
+    
+    vl_reconf:=vl_reconf and v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.is_supported // support if requested both by the user and remote side
+    
+    vl_fwd_tsn :=vl_fwd_tsn and v_assoc_db.associations[pl_assoc_id].assoc_data.forward_tsn_supported
+    
+    var octetstring pl_cookie:=SCTP_gen_state_cookie(v_assoc_db.associations[pl_assoc_id].assoc_data.cookie_lifespan, 
+                                        vl_init_tag,// pl_own_init_tag,
+                                        pl_sctp_packet.chunks[0].init.init_tag, // pl_remote_init_tag,
+                                        0,// pl_tie_tag, 0 means no tie
+                                        pl_sctp_packet.chunks[0].init.init_tsn, // pl_remote_tsn,
+                                        pl_sctp_packet.chunks[0].init.os, // pl_remote_os,
+                                        pl_sctp_packet.chunks[0].init.mis ,// pl_remote_mis,
+                                        pl_sctp_packet.chunks[0].init.a_rwnd, // pl_remote_a_rwnd,
+                                        vl_idata,
+                                        vl_reconf,
+                                        vl_fwd_tsn ,
+                                        v_secret_key // pl_key
+                                        )
+    vl_initack_chunk:={
+      init_tag := vl_init_tag,
+      a_rwnd   := 65535,
+      os       := 65535,
+      mis      := 65535,
+      init_tsn := vl_init_tag,
+      params :={
+        {state_cookie:={param_type:=7,param_length:=0,state_cookie:=pl_cookie}}
+      }
+    }
+    if(vl_idata or vl_reconf){
+      var integer vl_idx:=0
+      if(ispresent(vl_initack_chunk.params)){
+        vl_idx:=lengthof(vl_initack_chunk.params)
+      }
+      vl_initack_chunk.params[vl_idx].supported_extensions:={
+         param_type := 32776,
+         param_length :=0,
+         supported_extensions:={}
+      }
+      if(vl_idata){
+       vl_initack_chunk.params[vl_idx].supported_extensions.supported_extensions[lengthof(vl_initack_chunk.params[vl_idx].supported_extensions.supported_extensions)]:=64
+      }
+      if(vl_reconf){
+       vl_initack_chunk.params[vl_idx].supported_extensions.supported_extensions[lengthof(vl_initack_chunk.params[vl_idx].supported_extensions.supported_extensions)]:=130
+      }
+    }
+    if(vl_fwd_tsn){
+      var integer vl_idx:=0
+      if(ispresent(vl_initack_chunk.params)){
+        vl_idx:=lengthof(vl_initack_chunk.params)
+      }
+      vl_initack_chunk.params[vl_idx].forward_tsn_supported:={
+         param_type := 49152,
+         param_length :=0
+      }
+    }
+    vl_response:={
+      common_header := {
+        source_port:=pl_sctp_packet.common_header.destination_port,
+        destination_port:=pl_sctp_packet.common_header.source_port,
+        verification_tag:=pl_sctp_packet.chunks[0].init.init_tag
+      },
+      chunks := { {init_ack:=vl_initack_chunk} }
+    }
+    SCTP_send_packet(pl_transport_id,vl_response);
+    
+  } else {
+    // Cookie Echo received, process it.
+    // Allocate new assoc 
+    var integer vl_new_assoc:=SCTP_assoc_construct_from_cookie_echo(pl_sctp_packet,pl_transport_id,pl_assoc_id);
+    
+    if(vl_new_assoc < 0){ // The cookie check failed
+      // drop the packet
+      return;
+    }
+    
+    // Check the cookie lifetime
+    if(v_assoc_db.associations[vl_new_assoc].assoc_data.cookie_validity==1){ // Cookie expired
+      // Send abort with erro chunk
+      
+      // Construct the error chunk
+      var SCTP_error_chunk vl_error_chunk:= {
+        chunk_type := 9,
+        flags      := '00000000'B,
+        chunk_length := 0,
+        params := {
+          {stale_cookie:={cause_code:=3, cause_length:=0,measure:=0}}
+        }
+      }
+      
+      // send the abort
+      SCTP_message_send_abort(pl_transport_id,pl_sctp_packet,vl_new_assoc,-,{{error_:=vl_error_chunk}})
+      
+      // drop the association
+      SCTP_free_assoc_entry(vl_new_assoc)
+      return;  // We're done
+    }
+    // Add the connection to the id map
+    if(SCTP_add_id_map(vl_new_assoc,pl_transport_id,v_assoc_db.associations[vl_new_assoc].assoc_data.local_port,v_assoc_db.associations[vl_new_assoc].assoc_data.remote_port)==-1){
+      // Stop further processing
+      return;
+    }
+    
+    // Send connected
+    var SCTP_Connected_data vl_connected:={
+      assoc_id := vl_new_assoc,
+      local_sctp_port := v_assoc_db.associations[vl_new_assoc].assoc_data.local_port,
+      remote_sctp_port := v_assoc_db.associations[vl_new_assoc].assoc_data.remote_port,
+      listen_assoc_id := pl_assoc_id
+    }
+
+    p_sctp_ind_api.call(S_SCTP_Connected_ind:{vl_connected},nowait) to v_assoc_db.associations[vl_new_assoc].assoc_data.rem_comp
+
+    // Send notification to the owner of the listen port
+    var SCTP_Notification_data vl_notification:={
+      assoc_id := vl_new_assoc,
+      notification:= {comm_up  := {}},
+      options := {
+        {i_data_supported:=v_assoc_db.associations[vl_new_assoc].assoc_data.i_data_supported},
+        {reconfig_params:=v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params},
+        {forward_tsn_supported:=v_assoc_db.associations[pl_assoc_id].assoc_data.forward_tsn_supported}
+      
+      }
+    }
+    
+    
+    
+    p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_notification},nowait) to v_assoc_db.associations[vl_new_assoc].assoc_data.rem_comp
+    v_assoc_db.associations[vl_new_assoc].assoc_data.state:=SCTP_ASSOC_ESTABLISHED;
+    SCTP_hearbeat_start(vl_new_assoc)
+    
+    // Reset the retransmit counter
+    v_assoc_db.associations[vl_new_assoc].assoc_data.retransmit_counter:=0
+    
+    SCTP_congestion_set_init_params(vl_new_assoc)
+    // Set the last acked TSN to the expeted -1
+    v_assoc_db.associations[vl_new_assoc].assoc_data.remote_last_sack_tsn := (v_assoc_db.associations[vl_new_assoc].assoc_data.own_tsn - 1) mod 4294967296
+
+    // Send the packet for further processing
+    SCTP_message_incoming_handler(vl_new_assoc,pl_sctp_packet,true)
+    
+    
+    
+  }
+}
+
+// Process the Out of the blue packets
+// See 8.4 of rfc
+function  SCTP_message_process_oob_packet(in integer pl_transport_id,  // Where to send the abort
+                                 in SCTP_Packet pl_sctp_packet // The incoming packet
+                                 ) runs on SCTP_Engine_CT  {
+// first search map the chunks
+// Interested ones:
+//  - Abort
+  var boolean vl_abort_found:=false
+//  - Init
+  var boolean vl_init_found:=false
+//  - Cookie Echo
+  var boolean vl_cookie_echo_found:=false
+//  - Shutdown Complete
+  var boolean vl_shutdown_complete_found:=false
+//  - Shutdown Ack
+  var boolean vl_shutdown_ack_found:=false
+//  - CookieAck
+  var boolean vl_cookie_ack_found:=false
+
+  var integer vl_i:=0
+  for(vl_i:=0;vl_i<lengthof(pl_sctp_packet.chunks);vl_i:=vl_i+1) {
+    if(ischosen(pl_sctp_packet.chunks[vl_i].abort)){
+      vl_abort_found:=true
+      continue
+    } else if (ischosen(pl_sctp_packet.chunks[vl_i].init)) {
+      vl_init_found:=true
+      continue
+    } else if (ischosen(pl_sctp_packet.chunks[vl_i].cookie_echo)) {
+      vl_cookie_echo_found:=true
+      continue
+    } else if (ischosen(pl_sctp_packet.chunks[vl_i].shutdown_complete)) {
+      vl_shutdown_complete_found:=true
+      continue
+    } else if (ischosen(pl_sctp_packet.chunks[vl_i].shutdown_ack)) {
+      vl_shutdown_ack_found:=true
+      continue
+    } else if (ischosen(pl_sctp_packet.chunks[vl_i].cookie_ack)) {
+      vl_cookie_ack_found:=true
+      continue
+    }
+  }
+
+// The packet should be dropped if
+//  - Abort
+//  - CookieAck
+//  - Shutdown Complete
+   if( vl_abort_found or vl_cookie_ack_found or vl_shutdown_complete_found){
+     return;  // do nothing
+   } else if(vl_init_found){
+// Init -> send abort  - tag handled automatically
+     SCTP_message_send_abort(pl_transport_id,pl_sctp_packet)
+   } else if(vl_cookie_echo_found) {
+// Cookie Echo -> Send abort, but check the cookie first
+     // construct a temp assoc entry, it checks the validity of the cookie also
+     var integer pl_temp_id:=SCTP_assoc_construct_from_cookie_echo(pl_sctp_packet,pl_transport_id);
+     
+     if(pl_temp_id>=0){
+       // send abort
+       SCTP_message_send_abort(pl_transport_id,-,pl_temp_id);
+       // free the assoc entry
+       SCTP_free_assoc_entry(pl_temp_id);
+     }
+     // else just drop the message
+   } else if(vl_shutdown_ack_found) {
+// SHUTDOWN ACK -> send SHUTDOWN COMPLETE
+     SCTP_message_send_shutdown_complete(pl_transport_id,pl_sctp_packet)
+   } else {
+     // any other case: send abort
+     SCTP_message_send_abort(pl_transport_id,pl_sctp_packet)
+   }
+
+}                                 
+
+
+
+// Send the shutdown ack message
+function SCTP_message_send_shutdown_ack(in integer pl_assoc_id) runs on SCTP_Engine_CT  {
+
+  var SCTP_Packet       vl_sctp := c_empty_sctp_packet
+  vl_sctp:={ 
+    common_header:={
+      source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+      verification_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+    },
+    chunks:={{shutdown_ack:={chunk_type:=8,flags:='00000000'B,chunk_length:=0}}}
+  }
+
+  
+  // Send it
+  SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_sctp);
+
+
+}
+
+// Send the shutdown message
+function SCTP_message_send_shutdown(in integer pl_assoc_id) runs on SCTP_Engine_CT  {
+
+  var SCTP_Packet       vl_sctp := c_empty_sctp_packet
+  vl_sctp:={ 
+    common_header:={
+      source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+      verification_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+    },
+    chunks:={{shutdown:={chunk_type:=7,flags:='00000000'B,chunk_length:=0,cum_tsn_ack:=SCTP_prev_tsn(v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tsn)}}}
+  }
+
+  
+  // Send it
+  SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_sctp);
+
+
+}
+
+function SCTP_message_send_heartbeat(in integer pl_assoc_id) runs on SCTP_Engine_CT  {
+  var SCTP_Packet       vl_sctp := c_empty_sctp_packet
+  vl_sctp:={ 
+    common_header:={
+      source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+      verification_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+    },
+    chunks:={{heartbeat:={chunk_type:=4,
+                          flags:='00000000'B,
+                          chunk_length:=0,
+                          params:={{heartbeat_info:={ param_type:=1,
+                                                      param_length := 0,
+                                                      info:=SCTP_misc_float2oct(t_run_time.read)
+                                                     }}}
+                          }}}
+  }
+
+  
+  // Send it
+  SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_sctp);
+  
+}
+
+// Send abort message
+// The abort message can be constructed from
+//   -- assoc data
+//   -- incoming sctp packet
+function SCTP_message_send_abort(in integer pl_transport_id:=-1,  // Where to send the abort
+                                 in SCTP_Packet pl_sctp_packet := c_empty_sctp_packet,  // The incoming packet caused the abort
+                                 in integer pl_assoc_id:=-1,   // The assoc id if applicable
+                                 in SCTP_Error_cause_list pl_cause_list:= {}, // the cause the abort
+                                 in SCTP_Chunk_List  pl_chunk_list :={} // The chunks include before the abort chunk
+                                 ) runs on SCTP_Engine_CT  {
+
+  var SCTP_Packet       vl_response := c_empty_sctp_packet
+  var SCTP_abort_chunk  vl_abort_chunk := c_empty_abort_chunk
+  
+  if(pl_assoc_id != -1){
+    // We have association
+    // Use the data from the database
+    pl_transport_id := v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id 
+    vl_response.common_header:={
+      source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+      verification_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+    }
+    vl_abort_chunk.T_flag:='0'B // The verification_tag is not reflected
+  } else {
+    // Out of the blue packet
+    if( (lengthof(pl_sctp_packet.chunks) > 0) 
+         and ischosen(pl_sctp_packet.chunks[0].init)
+         ){
+      // INIT chunk, get the Initiate Tag for the verification_tag
+      vl_response.common_header:={
+        source_port:=pl_sctp_packet.common_header.destination_port,
+        destination_port:=pl_sctp_packet.common_header.source_port,
+        verification_tag:=pl_sctp_packet.chunks[0].init.init_tag
+      }
+      vl_abort_chunk.T_flag:='0'B // The verification_tag is not reflected
+    } else {
+      // reflect the verification_tag
+      vl_response.common_header:={
+        source_port:=pl_sctp_packet.common_header.destination_port,
+        destination_port:=pl_sctp_packet.common_header.source_port,
+        verification_tag:=pl_sctp_packet.common_header.verification_tag
+      }
+      vl_abort_chunk.T_flag:='1'B // The verification_tag is reflected
+    }
+    
+  }
+  
+  // Construct the message
+  
+  // Add cause list if needed
+  if(lengthof(pl_cause_list) > 0){
+    vl_abort_chunk.params:=pl_cause_list
+  }
+
+  // Add the other chunks before the abort chunk
+  if(lengthof(pl_chunk_list) > 0){
+    vl_response.chunks:=pl_chunk_list
+  }
+  
+  // Add the abort chunk
+  vl_response.chunks[lengthof(vl_response.chunks)].abort:=vl_abort_chunk;
+  
+  // Send it
+  SCTP_send_packet(pl_transport_id,vl_response);
+  
+}
+
+// Send abort message
+// The shutdown complete message can be constructed from
+//   -- assoc data
+//   -- incoming sctp packet
+function SCTP_message_send_shutdown_complete(in integer pl_transport_id:=-1,  // Where to send
+                                 in SCTP_Packet pl_sctp_packet := c_empty_sctp_packet,  // The incoming packet
+                                 in integer pl_assoc_id:=-1   // The assoc id if applicable
+                                 ) runs on SCTP_Engine_CT  {
+
+  var SCTP_Packet       vl_response := c_empty_sctp_packet
+  var SCTP_ShutdownComplete_chunk  vl_sh_comp_chunk := c_empty_shutdown_complete_chunk
+  
+  if(pl_assoc_id != -1){
+    // We have association
+    // Use the data from the database
+    pl_transport_id := v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id 
+    vl_response.common_header:={
+      source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+      verification_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+    }
+    vl_sh_comp_chunk.T_flag:='0'B // The verification_tag is not reflected
+  } else {
+    // Out of the blue packet
+    // reflect the verification_tag
+    vl_response.common_header:={
+        source_port:=pl_sctp_packet.common_header.destination_port,
+        destination_port:=pl_sctp_packet.common_header.source_port,
+        verification_tag:=pl_sctp_packet.common_header.verification_tag
+    }
+    vl_sh_comp_chunk.T_flag:='1'B // The verification_tag is reflected
+  }
+    
+  
+  // Construct the message
+
+  // Add the chunk
+  vl_response.chunks[lengthof(vl_response.chunks)].shutdown_complete:=vl_sh_comp_chunk;
+  
+  // Send it
+  SCTP_send_packet(pl_transport_id,vl_response);
+  
+}
+
+// Send the sctp packet
+function SCTP_send_packet(in integer pl_transport_id,  // Where to send the packet
+                          in SCTP_Packet pl_sctp_packet) runs on SCTP_Engine_CT {
+
+  var SCTP_Engine_packet vl_packet:={
+   transport_id:=pl_transport_id,
+   sctp_packet:=f_SCTP_enc(pl_sctp_packet)
+  }
+  
+  p_packet_port.send(vl_packet)
+}
+
+// Send message with Cookie Echo
+function SCTP_message_send_cookie_echo(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  
+  var SCTP_Packet       vl_sctp := c_empty_sctp_packet
+  vl_sctp:={
+    common_header :={
+      source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+      verification_tag := v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+    },
+    chunks:={{cookie_echo:={chunk_type:=10, flags:= '00000000'B, chunk_length:=0,cookie:=v_assoc_db.associations[pl_assoc_id].assoc_data.state_cookie}}}
+  }
+  
+  // Send the packet
+  SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_sctp)
+}
+/*****************************************************************************/
+//
+//  API functions
+// 
+/*****************************************************************************/
+
+// Handles the reconfig request
+function SCTP_api_handle_reconfig(in SCTP_Reconfiguration_req vl_reconfig, // the listen parameters
+                       in SCTP_Engine_CT vl_sender          // The sender of the request
+                       ) runs on SCTP_Engine_CT {
+
+  var integer vl_assoc_id:=vl_reconfig.assoc_id
+  // Check the associ id validity
+  
+  if( (vl_assoc_id<0) or (vl_assoc_id>lengthof(v_assoc_db.associations))  // check boundary
+      or (not ispresent(v_assoc_db.associations[vl_assoc_id].assoc_data))  // Is used?
+      or (v_assoc_db.associations[vl_assoc_id].assoc_data.rem_comp != vl_sender) // Is my assoc?
+    ){
+    // invalid assoc_id
+    p_sctp_req_api.raise(S_SCTP_reconfig, SCTP_operation_execption:{SCTP_ENG_WRONG_ASSOC_ID,"The assoc_id is invalid or belongs to another component"}) to vl_sender
+    return
+  }
+
+  // check the state of the association
+  if(v_assoc_db.associations[vl_assoc_id].assoc_data.state!=SCTP_ASSOC_ESTABLISHED){
+    // The sendrequest is allowed only in established state
+    p_sctp_req_api.raise(S_SCTP_reconfig, SCTP_operation_execption:{SCTP_ENG_WRONG_ASSOC_STATE,"The association is not in the established state"}) to vl_sender
+    return
+    
+  }
+  
+  // Check if request is ongoing
+  if(v_assoc_db.associations[vl_assoc_id].assoc_data.reconfig_ongoing){
+    p_sctp_req_api.raise(S_SCTP_reconfig, SCTP_operation_execption:{SCTP_ENG_RECONFIG_ONGOING,"There is an ongoing reconfig request. Please try again later"}) to vl_sender
+    return
+    
+  }
+
+  var SCTP_Packet       vl_sctp := c_empty_sctp_packet
+  vl_sctp:={
+    common_header :={
+      source_port:=v_assoc_db.associations[vl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[vl_assoc_id].assoc_data.remote_port,
+      verification_tag := v_assoc_db.associations[vl_assoc_id].assoc_data.remote_tag
+    },
+    chunks:={{
+        re_config:={
+            chunk_type:=130,
+            flags:='00000000'B,
+            chunk_length:=0,
+            params:={}
+          
+        }
+     }}
+  }
+  
+  // create and send the request
+  if(ischosen(vl_reconfig.reconf_method.assoc_reset)){
+    vl_sctp.chunks[0].re_config.params[0]:={
+      ssn_tsn_reset_req:={
+        param_type:=15,
+        param_length:=0,
+        reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num
+      }
+    }
+    
+    v_assoc_db.associations[vl_assoc_id].assoc_data.ongoing_outgoing_reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num
+    
+  } else if(ischosen(vl_reconfig.reconf_method.stream_reset)){
+    if(vl_reconfig.reconf_method.stream_reset.incoming){
+      vl_sctp.chunks[0].re_config.params[0]:={
+        in_ssn_reset_req:={
+          param_type:=14,
+          param_length:=0,
+          reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num,
+          stream_numbers:=vl_reconfig.reconf_method.stream_reset.streams
+        }
+      }
+      v_assoc_db.associations[vl_assoc_id].assoc_data.ongoing_incoming_reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num
+      
+    } else {
+      if(ispresent(vl_reconfig.reconf_method.stream_reset.streams)){
+        SCTP_reconf_generate_out_ssn_reset_req(  vl_reconfig.reconf_method.stream_reset.streams,
+                                                 SCTP_prev_tsn(v_assoc_db.associations[vl_assoc_id].assoc_data.own_tsn),
+                                                 vl_sctp.chunks[0].re_config,
+                                                 vl_assoc_id
+        )
+      } else {
+        SCTP_reconf_generate_out_ssn_reset_req(  {},
+                                                 SCTP_prev_tsn(v_assoc_db.associations[vl_assoc_id].assoc_data.own_tsn),
+                                                 vl_sctp.chunks[0].re_config,
+                                                 vl_assoc_id
+        )
+      }
+      v_assoc_db.associations[vl_assoc_id].assoc_data.ongoing_outgoing_reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num
+    }
+    
+  } else {
+    // add stream req
+    if(vl_reconfig.reconf_method.add_stream.incoming){
+      vl_sctp.chunks[0].re_config.params[0]:={
+        add_in_stream:={
+          param_type:=18,
+          param_length:=0,
+          reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num,
+          stream_num:=vl_reconfig.reconf_method.add_stream.new_streams,
+          reserved:=0
+        }
+      }
+      v_assoc_db.associations[vl_assoc_id].assoc_data.ongoing_incoming_reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num
+    } else {
+      vl_sctp.chunks[0].re_config.params[0]:={
+        add_out_stream:={
+          param_type:=17,
+          param_length:=0,
+          reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num,
+          stream_num:=vl_reconfig.reconf_method.add_stream.new_streams,
+          reserved:=0
+        }
+      }
+      v_assoc_db.associations[vl_assoc_id].assoc_data.ongoing_outgoing_reconf_req_seq:=v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num
+    }
+    
+  }
+
+  v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num:=SCTP_next_tsn(v_assoc_db.associations[vl_assoc_id].assoc_data.reconf_own_seq_num)
+  
+  // Send the packet
+  SCTP_send_packet(v_assoc_db.associations[vl_assoc_id].assoc_data.transport_id,vl_sctp)
+
+}
+
+// Handles the shutdown_conf request
+function SCTP_api_handle_shutdown_conf (in integer vl_assoc_id, // the listen parameters
+                       in SCTP_Engine_CT vl_sender          // The sender of the request
+                       ) runs on SCTP_Engine_CT {
+
+  if( (vl_assoc_id<0) or (vl_assoc_id>lengthof(v_assoc_db.associations))  // check boundary
+      or (not ispresent(v_assoc_db.associations[vl_assoc_id].assoc_data))  // Is used?
+      or (v_assoc_db.associations[vl_assoc_id].assoc_data.rem_comp != vl_sender) // Is my assoc?
+    ){
+    // invalid assoc_id
+    p_sctp_req_api.raise(S_SCTP_Shutdown_conf, SCTP_operation_execption:{SCTP_ENG_WRONG_ASSOC_ID,"The assoc_id is invalid or belongs to another component"}) to vl_sender
+    return
+  }
+
+  // check the state of the association
+  if(v_assoc_db.associations[vl_assoc_id].assoc_data.state!=SCTP_ASSOC_CLOSED){
+    // The sendrequest is allowed only in established state
+    p_sctp_req_api.raise(S_SCTP_Shutdown_conf, SCTP_operation_execption:{SCTP_ENG_WRONG_ASSOC_STATE,"The association is not in closed state"}) to vl_sender
+    return
+    
+  }
+
+  // Free the association
+  SCTP_free_assoc_entry(vl_assoc_id)
+  
+      // Confirm the request
+  p_sctp_req_api.reply(S_SCTP_Shutdown_conf:{?} value {vl_assoc_id}) to vl_sender
+
+}
+// Handles the shutdown request
+function SCTP_api_handle_shutdown (in SCTP_Shutdown_data pl_shutdown_data, // the shutdown parameters
+                       in SCTP_Engine_CT vl_sender          // The sender of the request
+                       ) runs on SCTP_Engine_CT {
+
+  var integer vl_assoc_id:=pl_shutdown_data.assoc_id
+  // Check the associ id validity
+  
+  if( (vl_assoc_id<0) or (vl_assoc_id>lengthof(v_assoc_db.associations))  // check boundary
+      or (not ispresent(v_assoc_db.associations[vl_assoc_id].assoc_data))  // Is used?
+      or (v_assoc_db.associations[vl_assoc_id].assoc_data.rem_comp != vl_sender) // Is my assoc?
+    ){
+    // invalid assoc_id
+    p_sctp_req_api.raise(S_SCTP_Shutdown, SCTP_operation_execption:{SCTP_ENG_WRONG_ASSOC_ID,"The assoc_id is invalid or belongs to another component"}) to vl_sender
+    return
+  }
+
+  // check the state of the association
+  if(v_assoc_db.associations[vl_assoc_id].assoc_data.state==SCTP_ASSOC_CLOSED){
+    // The sendrequest is allowed only in established state
+    p_sctp_req_api.raise(S_SCTP_Shutdown, SCTP_operation_execption:{SCTP_ENG_WRONG_ASSOC_STATE,"The association is already in closed state"}) to vl_sender
+    return
+    
+  }
+
+  if(not pl_shutdown_data.graceful_shutdown){
+    // Abort was requested
+    if(ispresent(pl_shutdown_data.reason)){
+      // send the abort with the reason
+      SCTP_message_send_abort(-,-,vl_assoc_id,{{user_abort:={cause_code:=12, cause_length:=0,reason:=char2oct(pl_shutdown_data.reason)}}})
+    } else {
+      SCTP_message_send_abort(-,-,vl_assoc_id)
+    }
+    // Confirm the request
+    p_sctp_req_api.reply(S_SCTP_Shutdown:{?} value {vl_assoc_id}) to vl_sender
+ 
+    var SCTP_Shutdown_data vl_sh_data:={
+        assoc_id:=vl_assoc_id,
+        graceful_shutdown := false,
+        reason := "Abort request has been sent."
+      }
+    
+    p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[vl_assoc_id].assoc_data.rem_comp
+
+    SCTP_assoc_set_closed(vl_assoc_id)
+    
+  } else {
+    select(v_assoc_db.associations[vl_assoc_id].assoc_data.state){
+      case ( (SCTP_ASSOC_COOKIE_WAIT,SCTP_ASSOC_COOKIE_ECHOED)){
+        // We're in th eset up phase
+        // Abort it
+        SCTP_message_send_abort(-,-,vl_assoc_id)
+        // Confirm the request
+        p_sctp_req_api.reply(S_SCTP_Shutdown:{?} value {vl_assoc_id}) to vl_sender
+
+        var SCTP_Shutdown_data vl_sh_data:={
+            assoc_id:=vl_assoc_id,
+            graceful_shutdown := false,
+            reason := "Association set up has been aborted."
+          }
+
+        p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[vl_assoc_id].assoc_data.rem_comp
+
+        SCTP_assoc_set_closed(vl_assoc_id)
+        
+      }
+      case (SCTP_ASSOC_ESTABLISHED ){
+        // Set the state to shutdown pending
+        v_assoc_db.associations[vl_assoc_id].assoc_data.state:=SCTP_ASSOC_SHUTDOWN_PENDING
+
+        // Confirm the request
+        p_sctp_req_api.reply(S_SCTP_Shutdown:{?} value {vl_assoc_id}) to vl_sender
+        
+        // Call the data scheduler. It will send the SHUTDOWN if possible
+        SCTP_data_send_scheduler(vl_assoc_id)
+      }
+      
+      case else {
+        // We're already in the shutdown phase
+        // Confirm the request
+        p_sctp_req_api.reply(S_SCTP_Shutdown:{?} value {vl_assoc_id}) to vl_sender
+        // Nothing more to do here
+      }
+    }
+  
+  }
+
+}
+
+
+// Handles the send msg request
+function SCTP_api_handle_send_msg (in SCTP_MSG_data pl_send_msg_data, // the send req parameters
+                       in SCTP_Engine_CT vl_sender          // The sender of the request
+                       ) runs on SCTP_Engine_CT {
+
+  var integer vl_assoc_id:=pl_send_msg_data.assoc_id
+  // Check the associ id validity
+  
+  if( (vl_assoc_id<0) or (vl_assoc_id>lengthof(v_assoc_db.associations))  // check boundary
+      or (not ispresent(v_assoc_db.associations[vl_assoc_id].assoc_data))  // Is used?
+      or (v_assoc_db.associations[vl_assoc_id].assoc_data.rem_comp != vl_sender) // Is my assoc?
+    ){
+    // invalid assoc_id
+    p_sctp_req_api.raise(S_SCTP_Send_req, SCTP_operation_execption:{SCTP_ENG_WRONG_ASSOC_ID,"The assoc_id is invalid or belongs to another component"}) to vl_sender
+    return
+  }
+
+  // check the state of the association
+  if(v_assoc_db.associations[vl_assoc_id].assoc_data.state!=SCTP_ASSOC_ESTABLISHED){
+    // The sendrequest is allowed only in established state
+    p_sctp_req_api.raise(S_SCTP_Send_req, SCTP_operation_execption:{SCTP_ENG_WRONG_ASSOC_STATE,"The association is not in the established state"}) to vl_sender
+    return
+    
+  }
+  
+  // put the message into th estream queue
+  
+  var integer vl_stream_id:=pl_send_msg_data.stream_id
+  var integer vl_queue_id
+  
+  // get the queue id
+  if(SCTP_int2int_get(v_assoc_db.associations[vl_assoc_id].assoc_data.tx_stream_idx_map_id,
+                      vl_stream_id,
+                      vl_queue_id
+                      )==-1){
+    // No queue for that stream
+    // create one
+    
+    vl_queue_id:=lengthof(v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues)
+    // ordered queue
+    v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id]:=c_empty_msg_queue
+    // unordered queue
+    v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id+1]:=c_empty_msg_queue
+    
+    // register it in the map
+    if(SCTP_int2int_add(v_assoc_db.associations[vl_assoc_id].assoc_data.tx_stream_idx_map_id,
+                      vl_stream_id,
+                      vl_queue_id) == -1){
+      // WTF???
+      p_sctp_req_api.raise(S_SCTP_Send_req, SCTP_operation_execption:{SCTP_ENG_INTERNAL_ERROR,"INTERNAL Error: wrong map id SCTP_api_handle_send_msg SCTP_int2int_add"}) to vl_sender
+      return
+      
+    }
+  }
+  
+  var boolean vl_ordered:= true
+  var bitstring vl_uflag:= '0'B
+  // Put the msg into that queue
+  var SCTP_Chunk_queue_element_t vl_msg_element:=c_empty_Chunk_queue_element
+  
+  // Is it unordered?
+  if(ispresent(pl_send_msg_data.options)){
+    for(var integer vl_x:=0;vl_x<lengthof(pl_send_msg_data.options); vl_x:=vl_x+1){
+      if(ischosen(pl_send_msg_data.options[vl_x].unordered)){
+        vl_ordered:= false  // not ordered
+        vl_queue_id:=vl_queue_id+1 // adjust the queue id 
+        vl_uflag:= '1'B
+      } else if(ischosen(pl_send_msg_data.options[vl_x].lifetime)){
+        vl_msg_element.lifetime:=t_run_time.read+pl_send_msg_data.options[vl_x].lifetime
+      } else if(ischosen(pl_send_msg_data.options[vl_x].max_retransmit_counter)){
+        vl_msg_element.counter:=pl_send_msg_data.options[vl_x].max_retransmit_counter
+      }
+    }
+  }
+  
+  
+  
+  if(v_assoc_db.associations[vl_assoc_id].assoc_data.i_data_supported){
+    // Use IData
+    vl_msg_element:={
+      chunk:={
+        idata:={
+          chunk_type:= 64,
+          E_flag := '0'B,
+          B_flag := '0'B,
+          U_flag := vl_uflag,
+          I_flag := '0'B,
+          res_flags := '0000'B,
+          chunk_length := 0,
+          tsn := 0,
+          stream_id := vl_stream_id,
+          reserved := 0,
+          mid := v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id].next_ssn,
+          ppid_fsn := pl_send_msg_data.ppid,
+          user_data := pl_send_msg_data.data
+        }
+      }
+    }
+    // next_ssn means: next message id
+    v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id].next_ssn :=SCTP_next_tsn(v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id].next_ssn)
+  } else {
+    // Normal DATA chunk
+    vl_msg_element:={
+      chunk:={
+        data:={
+          chunk_type:= 0,
+          E_flag := '0'B,
+          B_flag := '0'B,
+          U_flag := vl_uflag,
+          I_flag := '0'B,
+          res_flags := '0000'B,
+          chunk_length := 0,
+          tsn := 0,
+          stream_id := vl_stream_id,
+          ssn := v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id].next_ssn,
+          ppid := pl_send_msg_data.ppid,
+          user_data := pl_send_msg_data.data
+        }
+      }
+    }
+    // Adjust the next ssn
+    if(vl_ordered){
+      // The unordered doesn't have ssn
+      v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id].next_ssn :=SCTP_next_ssn(v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id].next_ssn)
+    }
+  }
+  
+  
+  SCTP_Chunk_queue_push(v_assoc_db.associations[vl_assoc_id].assoc_data.tx_msg_queues[vl_queue_id].messages,vl_msg_element)
+  
+
+  // send back the result
+  p_sctp_req_api.reply(S_SCTP_Send_req:{?} value {vl_assoc_id}) to vl_sender
+  
+
+  // Invoke the send scheduler
+  SCTP_data_send_scheduler(vl_assoc_id)
+}
+// Handles the listen request
+function SCTP_api_handle_listen(in SCTP_Listen_data pl_listen_data, // the listen parameters
+                       in SCTP_Engine_CT vl_sender          // The sender of the request
+                       ) runs on SCTP_Engine_CT {
+// Basic check
+  if((pl_listen_data.local_sctp_port<1) or (pl_listen_data.local_sctp_port>65535)){
+    // The listen port is out of the range
+    p_sctp_req_api.raise(S_SCTP_Listen, SCTP_operation_execption:{SCTP_ENG_WRONG_PORT,"Listen port is out of the allowed range 1..65535"}) to vl_sender
+    // Stop further processing
+    return;
+  }
+  
+  // Check transport id
+  if(pl_listen_data.transport_id<-1){
+    // The transport id should be >=0 or -1 (all connection)
+    p_sctp_req_api.raise(S_SCTP_Listen, SCTP_operation_execption:{SCTP_ENG_WRONG_PARAMETERS,"The transport id should be >=0 or -1 (all connection)"}) to vl_sender
+    // Stop further processing
+    return;
+  }
+
+  // Is the port is used?
+  if(SCTP_find_id_map(pl_listen_data.transport_id,pl_listen_data.local_sctp_port,0)!=-1){
+    // The port is already used for listen
+    p_sctp_req_api.raise(S_SCTP_Listen, SCTP_operation_execption:{SCTP_ENG_PORT_ALREADY_USED,"The port is already used."}) to vl_sender
+    // Stop further processing
+    return;
+    
+  }
+  
+  // create a new assoc entry
+  var integer vl_new_assoc:=SCTP_allocate_assoc_entry();
+
+  // Fill the data
+  v_assoc_db.associations[vl_new_assoc].assoc_data:={
+    state := SCTP_ASSOC_LISTEN,
+    transport_id :=pl_listen_data.transport_id ,
+    local_port:=pl_listen_data.local_sctp_port,
+    remote_port:=0,
+    rem_comp:=vl_sender
+  }
+  
+  // Add it to the map
+  if(SCTP_add_id_map(vl_new_assoc,pl_listen_data.transport_id,pl_listen_data.local_sctp_port,0)==-1){
+    // Something went wrong
+    // free the assoc entry
+    SCTP_free_assoc_entry(vl_new_assoc);
+    // Raise the exception
+    p_sctp_req_api.raise(S_SCTP_Listen, SCTP_operation_execption:{SCTP_ENG_INTERNAL_ERROR,"Internal error. SCTP_add_id_map -1"}) to vl_sender
+    // Stop further processing
+    return;
+  }
+  
+  // process the options
+  if(ispresent(pl_listen_data.options)){
+    var integer k
+    for(k:=0;k<lengthof(pl_listen_data.options);k:=k+1){
+      if(ischosen(pl_listen_data.options[k].i_data_supported)){
+        v_assoc_db.associations[vl_new_assoc].assoc_data.i_data_supported:=pl_listen_data.options[k].i_data_supported
+      }
+      if(ischosen(pl_listen_data.options[k].forward_tsn_supported)){
+        v_assoc_db.associations[vl_new_assoc].assoc_data.forward_tsn_supported:=pl_listen_data.options[k].forward_tsn_supported
+      }
+      if(ischosen(pl_listen_data.options[k].reconfig_params)){
+        v_assoc_db.associations[vl_new_assoc].assoc_data.reconf_params:=pl_listen_data.options[k].reconfig_params
+      }
+    }
+  }
+  
+  // return the result
+  p_sctp_req_api.reply(S_SCTP_Listen:{?} value {vl_new_assoc}) to vl_sender
+
+}
+
+// Handles the connect request
+function SCTP_api_handle_connect(in SCTP_Connect_data  pl_connect_data , // the connect parameters
+                       in SCTP_Engine_CT vl_sender          // The sender of the request
+                       ) runs on SCTP_Engine_CT {
+// Check the port numbers
+  if((pl_connect_data.local_sctp_port<1) or (pl_connect_data.local_sctp_port>65535)){
+    // The listen port is out of the range
+    p_sctp_req_api.raise(S_SCTP_Connect, SCTP_operation_execption:{SCTP_ENG_WRONG_PORT,"Listen port is out of the allowed range 1..65535"}) to vl_sender
+    // Stop further processing
+    return;
+  }
+  if((pl_connect_data.remote_sctp_port<1) or (pl_connect_data.remote_sctp_port>65535)){
+    // The listen port is out of the range
+    p_sctp_req_api.raise(S_SCTP_Connect, SCTP_operation_execption:{SCTP_ENG_WRONG_PORT,"Listen port is out of the allowed range 1..65535"}) to vl_sender
+    // Stop further processing
+    return;
+  }
+
+  // Check transport id
+  if(pl_connect_data.transport_id<0){
+    // The transport id should be >=0 
+    p_sctp_req_api.raise(S_SCTP_Connect, SCTP_operation_execption:{SCTP_ENG_WRONG_PARAMETERS,"The transport id should be >=0"}) to vl_sender
+    // Stop further processing
+    return;
+  }
+
+  // Is the port is used?
+  if(SCTP_find_id_map(pl_connect_data.transport_id,pl_connect_data.local_sctp_port,pl_connect_data.remote_sctp_port)!=-1){
+    // The port is already used for listen
+    p_sctp_req_api.raise(S_SCTP_Connect, SCTP_operation_execption:{SCTP_ENG_PORT_ALREADY_USED,"The port is already used."}) to vl_sender
+    // Stop further processing
+    return;
+  }
+
+  // create a new assoc entry
+  var integer vl_new_assoc:=SCTP_allocate_assoc_entry();
+
+  // Fill the data
+  v_assoc_db.associations[vl_new_assoc].assoc_data:={
+    state := SCTP_ASSOC_COOKIE_WAIT,
+    transport_id :=pl_connect_data.transport_id ,
+    local_port:=pl_connect_data.local_sctp_port,
+    remote_port:=pl_connect_data.remote_sctp_port,
+    own_tag:=SCTP_rnd_32bit_int(),
+    rem_comp:=vl_sender
+  }
+  v_assoc_db.associations[vl_new_assoc].assoc_data.own_tsn:=v_assoc_db.associations[vl_new_assoc].assoc_data.own_tag
+  v_assoc_db.associations[vl_new_assoc].assoc_data.reconf_own_seq_num:=v_assoc_db.associations[vl_new_assoc].assoc_data.own_tag
+
+  // process the options
+  if(ispresent(pl_connect_data.options)){
+    var integer k
+    for(k:=0;k<lengthof(pl_connect_data.options);k:=k+1){
+      if(ischosen(pl_connect_data.options[k].i_data_supported)){
+        v_assoc_db.associations[vl_new_assoc].assoc_data.i_data_supported:=pl_connect_data.options[k].i_data_supported
+      }
+      if(ischosen(pl_connect_data.options[k].forward_tsn_supported)){
+        v_assoc_db.associations[vl_new_assoc].assoc_data.forward_tsn_supported:=pl_connect_data.options[k].forward_tsn_supported
+      }
+      if(ischosen(pl_connect_data.options[k].reconfig_params)){
+        v_assoc_db.associations[vl_new_assoc].assoc_data.reconf_params:=pl_connect_data.options[k].reconfig_params
+      }
+    }
+  }
+
+  // Add the assoc to the id map
+  if(SCTP_add_id_map(vl_new_assoc,pl_connect_data.transport_id,pl_connect_data.local_sctp_port,pl_connect_data.remote_sctp_port)==-1){
+    // Something went wrong
+    // free the assoc entry
+    SCTP_free_assoc_entry(vl_new_assoc);
+    // Raise the exception
+    p_sctp_req_api.raise(S_SCTP_Listen, SCTP_operation_execption:{SCTP_ENG_INTERNAL_ERROR,"Internal error. SCTP_add_id_map -1"}) to vl_sender
+    // Stop further processing
+    return;
+  }
+  
+  // Send the INIT
+  SCTP_message_send_init(vl_new_assoc)
+    
+  // Start timer
+  v_assoc_db.associations[vl_new_assoc].assoc_data.retransmit_timer_event:=
+                  SCTP_event_schedule(vl_new_assoc,c_timer_T1,v_assoc_db.associations[vl_new_assoc].assoc_data.rto)
+  
+  // Send reply
+  p_sctp_req_api.reply(S_SCTP_Connect:{?} value {vl_new_assoc}) to vl_sender
+
+}
+
+// Send INIT
+function SCTP_message_send_init(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  var SCTP_Packet       vl_sctp := c_empty_sctp_packet
+  var SCTP_Init_chunk   vl_init_chunk := c_empty_init_chunk
+  vl_init_chunk:={
+    init_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.own_tag,
+    a_rwnd:=65535,
+    os:=65535,
+    mis:=65535,
+    init_tsn:=v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn
+  }
+  
+  // Indicate IDATA support if needed
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported or v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.is_supported){
+    var integer vl_idx:=0
+    if(ispresent(vl_init_chunk.params)){
+      vl_idx:=lengthof(vl_init_chunk.params)
+    }
+    vl_init_chunk.params[vl_idx].supported_extensions:={
+       param_type := 32776,
+       param_length :=0,
+       supported_extensions:={}
+    }
+      if(v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported){
+       vl_init_chunk.params[vl_idx].supported_extensions.supported_extensions[lengthof(vl_init_chunk.params[vl_idx].supported_extensions.supported_extensions)]:=64
+      }
+      if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconf_params.is_supported){
+       vl_init_chunk.params[vl_idx].supported_extensions.supported_extensions[lengthof(vl_init_chunk.params[vl_idx].supported_extensions.supported_extensions)]:=130
+      }
+  }
+  
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.forward_tsn_supported){
+    var integer vl_idx:=0
+    if(ispresent(vl_init_chunk.params)){
+      vl_idx:=lengthof(vl_init_chunk.params)
+    }
+    vl_init_chunk.params[vl_idx].forward_tsn_supported:={
+       param_type := 49152,
+       param_length :=0
+    }
+  }
+  
+  vl_sctp:={
+    common_header :={
+      source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port
+    },
+    chunks:={{init:=vl_init_chunk}}
+  }
+  
+  // Send the packet
+  SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_sctp)
+}
+
+/*****************************************************************************/
+//
+//  Timeout handlers functions
+// 
+/*****************************************************************************/
+// Handles the T1_init timer timeout
+// The event is already removed from the event_db
+function SCTP_timeout_T1_init(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+   v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+
+  if( v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter<v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.max_init_retrans){
+    // We should retransmitt the INIT
+    // increase the counter
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter +1 
+    
+    // Calculate the new T1_timer value
+    // See 6.3 of the RFC4960
+    var float vl_new_timeout:= SCTP_timeout_calculate_timeout_value(v_assoc_db.associations[pl_assoc_id].assoc_data.rto,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.rto_max
+                                                                    )
+    // Send the INIT
+    SCTP_message_send_init(pl_assoc_id)
+
+    // Start timer
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                    SCTP_event_schedule(pl_assoc_id,c_timer_T1,vl_new_timeout)
+    
+    
+  } else {
+    // Give up
+    
+    // Notify the user
+    var SCTP_Shutdown_data vl_sh_data:={
+        assoc_id:=pl_assoc_id,
+        graceful_shutdown := true,
+        reason := "INIT timeout. No answer received from the remote side."
+      }
+    
+    p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+    
+    // Set the state of the association
+    SCTP_assoc_set_closed(pl_assoc_id)
+
+  }
+
+}
+
+
+
+// Handles the T1_cookie timer timeout
+// The event is already removed from the event_db
+function SCTP_timeout_T1_cookie(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+   v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+
+  if( v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter<v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.max_init_retrans){
+    // We should retransmitt the INIT
+    // increase the counter
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter +1 
+    
+    // Calculate the new T1_timer value
+    // See 6.3 of the RFC4960
+    var float vl_new_timeout:= SCTP_timeout_calculate_timeout_value(v_assoc_db.associations[pl_assoc_id].assoc_data.rto,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.rto_max
+                                                                    )
+    // Send the INIT
+    SCTP_message_send_cookie_echo(pl_assoc_id)
+
+    // Start timer
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                    SCTP_event_schedule(pl_assoc_id,c_timer_T1_cookie,vl_new_timeout)
+    
+    
+  } else {
+    // Give up
+    
+    // Notify the user
+    var SCTP_Shutdown_data vl_sh_data:={
+        assoc_id:=pl_assoc_id,
+        graceful_shutdown := true,
+        reason := "Cookie echo timeout. No answer received from the remote side."
+      }
+    
+    p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+    
+    SCTP_assoc_set_closed(pl_assoc_id)
+
+  }
+
+}
+// Handles the T3_rtx timer timeout
+// The event is already removed from the event_db
+function SCTP_timeout_T3_rtx(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+   v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+  if( v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter<v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.assoc_max_retrans){
+    // increase the counter
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter +1 
+    // we shoudl mark the first chunk for retransmission
+    var integer vl_i:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.first_element
+    if(vl_i!=-1){
+      v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].mark_flag:=true
+      // try to be more agressive with resending. Resend teh half of the out queue
+      var integer vl_k:= (v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.used_entries-1)/2
+      while(vl_k>0){
+        vl_i:= v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].next_element
+        v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].mark_flag:=true
+        vl_k:=vl_k-1
+      }
+    } else {
+      // Ops we forget to stop the timer
+      // nothing to do
+      return
+    }
+    // Adjust cwnd and ssthres
+    v_assoc_db.associations[pl_assoc_id].assoc_data.ssthresh:=SCTP_max(v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd/2,v_assoc_db.associations[pl_assoc_id].assoc_data.pmtu*4)
+    v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd:=v_assoc_db.associations[pl_assoc_id].assoc_data.pmtu
+    v_assoc_db.associations[pl_assoc_id].assoc_data.partially_acked_bytes:=0
+    
+    // Schedule the sending of the data packets
+    SCTP_data_send_scheduler(pl_assoc_id)
+  } else {
+    // Give up
+    
+    // Notify the user
+    var SCTP_Notification_data vl_notification:={
+      assoc_id := pl_assoc_id,
+      notification:= {comm_lost  := {}},
+      options := omit
+    }
+    p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_notification},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+
+    var SCTP_Shutdown_data vl_sh_data:={
+        assoc_id:=pl_assoc_id,
+        graceful_shutdown := false,
+        reason := "Retransmit timeout. No answer received from the remote side."
+      }
+    
+    p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+    
+    SCTP_assoc_set_closed(pl_assoc_id)
+  }
+}
+
+// Handles the chutdown timer timeout
+function SCTP_timeout_T2_shutdown(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+   v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+  if( v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter<v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.assoc_max_retrans){
+
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter +1 
+  
+  
+    if(v_assoc_db.associations[pl_assoc_id].assoc_data.state==SCTP_ASSOC_SHUTDOWN_SENT){
+       // Resend shutdown
+      SCTP_message_send_shutdown(pl_assoc_id)
+    } else {
+      // Resend shutdown ack
+      SCTP_message_send_shutdown_ack(pl_assoc_id)
+    }
+
+    // calculate the new timeout
+    var float vl_new_timeout:= SCTP_timeout_calculate_timeout_value(v_assoc_db.associations[pl_assoc_id].assoc_data.rto,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.rto_max
+                                                                    )
+    // Schedule the resend
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                    SCTP_event_schedule(pl_assoc_id,c_timer_T2_shutdown,vl_new_timeout)
+    
+  } else {
+    // Give up
+    
+    // Notify the user
+    var SCTP_Notification_data vl_notification:={
+      assoc_id := pl_assoc_id,
+      notification:= {comm_lost  := {}},
+      options := omit
+    }
+    p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_notification},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+
+    var SCTP_Shutdown_data vl_sh_data:={
+        assoc_id:=pl_assoc_id,
+        graceful_shutdown := false,
+        reason := "Retransmit timeout. No answer received from the remote side."
+      }
+    
+    p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+    
+    SCTP_assoc_set_closed(pl_assoc_id)
+  }
+  
+}
+
+function SCTP_timeout_heartbeat(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id:=-1
+  if( v_assoc_db.associations[pl_assoc_id].assoc_data.hb_retrial_counter<v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.assoc_max_retrans){
+    v_assoc_db.associations[pl_assoc_id].assoc_data.hb_retrial_counter:=v_assoc_db.associations[pl_assoc_id].assoc_data.hb_retrial_counter+1
+    SCTP_hearbeat_schedule(pl_assoc_id)
+    
+    SCTP_message_send_heartbeat(pl_assoc_id)
+    
+  } else {
+    // Give up
+    
+    // Notify the user
+    var SCTP_Notification_data vl_notification:={
+      assoc_id := pl_assoc_id,
+      notification:= {comm_lost  := {}},
+      options := omit
+    }
+    p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_notification},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+
+    var SCTP_Shutdown_data vl_sh_data:={
+        assoc_id:=pl_assoc_id,
+        graceful_shutdown := false,
+        reason := "Heartbeat timeout. No answer received from the remote side."
+      }
+    
+    p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+    
+    SCTP_assoc_set_closed(pl_assoc_id)
+  }
+}
+
+function SCTP_timeout_close(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  v_assoc_db.associations[pl_assoc_id].assoc_data.close_timer:=-1
+        // Notify the user
+        var SCTP_Shutdown_data vl_sh_data:={
+            assoc_id:=pl_assoc_id,
+            graceful_shutdown := true,
+            reason := "Shutdown finished"
+          }
+
+        p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+
+        SCTP_assoc_set_closed(pl_assoc_id)
+
+}
+
+function SCTP_timeout_reconfig(in integer pl_assoc_id) runs on SCTP_Engine_CT {
+  v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id:=-1
+  if( v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_retransmit_counter<v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.assoc_max_retrans){
+    v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_retransmit_counter:=v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_retransmit_counter+1
+     var SCTP_Packet       vl_sctp := c_empty_sctp_packet
+     vl_sctp:={ 
+       common_header:={
+         source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+         destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+         verification_tag:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+       },
+       chunks:={{re_config:=v_assoc_db.associations[pl_assoc_id].assoc_data.last_reconf_req}}
+     }
+
+    // resend the last message
+    SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_sctp);
+    // restart the timer
+    SCTP_timer_reconf_start(pl_assoc_id)
+    
+    
+  } else {
+    // Give up
+    
+    // Notify the user
+    var SCTP_Notification_data vl_notification:={
+      assoc_id := pl_assoc_id,
+      notification:= {comm_lost  := {}},
+      options := omit
+    }
+    p_sctp_ind_api.call(S_SCTP_Notification_ind:{vl_notification},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+
+    var SCTP_Shutdown_data vl_sh_data:={
+        assoc_id:=pl_assoc_id,
+        graceful_shutdown := false,
+        reason := "Reconfig timeout. No answer received from the remote side."
+      }
+    
+    p_sctp_ind_api.call(S_SCTP_Shutdown_ind:{vl_sh_data},nowait) to v_assoc_db.associations[pl_assoc_id].assoc_data.rem_comp
+    
+    SCTP_assoc_set_closed(pl_assoc_id)
+  }
+}
+
+function SCTP_timeout_calculate_timeout_value(in float pl_rto, in integer pl_counter, in float pl_max) return float{
+    // Calculate the new timeout value
+    // See 6.3 of the RFC4960
+    var float vl_new_timeout:=pl_rto
+    for(var integer i:=1; i<=pl_counter; i:=i+1){
+      vl_new_timeout:=vl_new_timeout*2.0;
+      if(vl_new_timeout>=pl_max){
+        vl_new_timeout:=pl_max
+        break
+      }
+    }
+    return vl_new_timeout
+}
+
+/*****************************************************************************/
+//
+//  Misc functions
+// 
+/*****************************************************************************/
+
+// generate random a 32 bit non zero integer 
+function SCTP_rnd_32bit_int() return integer {
+  return float2int(4294967295.0*rnd()) + 1
+}
+
+function SCTP_min(in integer pl_a, in integer pl_b) return integer {
+  if(pl_a<pl_b){
+    return pl_a
+  }
+  return pl_b
+}
+function SCTP_max(in integer pl_a, in integer pl_b) return integer {
+  if(pl_a>pl_b){
+    return pl_a
+  }
+  return pl_b
+}
+
+//return the next TSN, wrap if needed
+function SCTP_next_tsn(in integer pl_tsn) return integer {
+  return (pl_tsn+1) mod 4294967296  // the return value is  between 0 and (2^32)-1 wrapping around
+}
+
+//return the previousTSN, wrap if needed
+function SCTP_prev_tsn(in integer pl_tsn) return integer {
+  return (pl_tsn-1) mod 4294967296  // the return value is  between 0 and (2^32)-1 wrapping around
+}
+
+// Compares 2 TSNs, return -1, 0, 1
+function SCTP_compare_tsn(in integer pl_tsn_a, in integer pl_tsn_b) return integer {
+// See RFC 1982, SERIAL_BITS = 32
+  if(pl_tsn_a == pl_tsn_b){
+    return 0 // Equal
+  }
+  if(( (pl_tsn_a < pl_tsn_b) and ((pl_tsn_b - pl_tsn_a) > 2147483648)) or
+     ( (pl_tsn_a > pl_tsn_b) and ((pl_tsn_a - pl_tsn_b) < 2147483648)) ){
+    return 1 // pl_tsn_a Greater than pl_tsn_b
+  }
+
+  return -1 // pl_tsn_a not equal and not greater than pl_tsn_b
+
+}
+
+//return the next SSN, wrap if needed
+function SCTP_next_ssn(in integer pl_ssn) return integer {
+  return (pl_ssn+1) mod 65536  // the return value is  between 0 and (2^16)-1 wrapping around
+}
+
+// Compares 2 SSNs, return -1, 0, 1
+function SCTP_compare_ssn(in integer pl_ssn_a, in integer pl_ssn_b) return integer {
+// See RFC 1982, SERIAL_BITS = 16
+  if(pl_ssn_a == pl_ssn_b){
+    return 0 // Equal
+  }
+  if(( (pl_ssn_a < pl_ssn_b) and ((pl_ssn_b - pl_ssn_a) < 32768)) or
+     ( (pl_ssn_a > pl_ssn_b) and ((pl_ssn_a - pl_ssn_b) > 32768)) ){
+    return 1 // pl_ssn_a Greater than pl_ssn_b
+  }
+
+  return -1 // pl_ssn_a not equal and not greater than pl_ssn_b
+
+}
+
+// Encode decode float 
+external function SCTP_misc_float2oct(in float pl_in) return octetstring
+external function SCTP_misc_oct2float(in octetstring pl_in) return float
+
+/*****************************************************************************/
+//
+//  int2int map handling functions
+// 
+/*****************************************************************************/
+
+// Allocate a new int2int map
+external function SCTP_int2int_new() return integer
+
+// Free the int2int map
+external function SCTP_int2int_delete(in integer pl_map_id) 
+
+// Add/Update value in a map
+external function SCTP_int2int_add(in integer pl_map_id,  // The id of the map
+                                   in integer pl_key,     // The key
+                                   in integer pl_value    // the value stored for the key
+                                   ) return integer  // 0 - OK, -1 - Error, wrong map id
+
+// Get value from a map
+external function SCTP_int2int_get(in integer pl_map_id,  // The id of the map
+                                   in integer pl_key,     // The key
+                                   out integer pl_value   // the value stored for the key
+                                   ) return integer  // 0 - OK, -1 - Error, wrong map id, wrong key
+
+
+/*****************************************************************************/
+//
+//  Chunk queue handling functions
+// 
+/*****************************************************************************/
+
+// Put an element into the end of the queue
+function SCTP_Chunk_queue_push(inout SCTP_Chunk_queue_db_t pl_chunk_db, in SCTP_Chunk_queue_element_t pl_chunk){
+  var integer vl_idx:=-1
+  if(pl_chunk_db.first_free==-1){
+    // No free element in the list
+    // Alocate a new one
+    vl_idx:=lengthof(pl_chunk_db.chunk_queue)
+  } else {
+    vl_idx:=pl_chunk_db.first_free
+    // remove it from the free queue
+    pl_chunk_db.first_free:=pl_chunk_db.chunk_queue[vl_idx].next_element
+    if(pl_chunk_db.first_free==-1){
+      // That was the last entry on the free list
+      pl_chunk_db.last_free:=-1
+    }
+  }
+
+  // Set the new element
+  pl_chunk_db.chunk_queue[vl_idx]:=pl_chunk;
+
+  // Chain the entry into the tail to the list
+  pl_chunk_db.chunk_queue[vl_idx].next_element:=-1;  // This will be the last entry
+  if(pl_chunk_db.last_element!=-1){
+    pl_chunk_db.chunk_queue[pl_chunk_db.last_element].next_element:=vl_idx
+  }
+  pl_chunk_db.last_element:=vl_idx
+
+  if(pl_chunk_db.first_element==-1){
+    // There was no first element. 
+    pl_chunk_db.first_element:=vl_idx
+  }
+  pl_chunk_db.used_entries:=pl_chunk_db.used_entries+1;
+}
+
+// Pop the first element from the queue
+function SCTP_Chunk_queue_pop(inout SCTP_Chunk_queue_db_t pl_chunk_db){
+  if(pl_chunk_db.used_entries>0){
+    // there is something to pop
+    
+    // remove from the used list
+    var integer vl_idx:=pl_chunk_db.first_element
+    pl_chunk_db.first_element:=pl_chunk_db.chunk_queue[vl_idx].next_element
+    if(pl_chunk_db.first_element==-1){
+      // That was the last entry on the list
+      pl_chunk_db.last_element:=-1
+    }
+    // Clear the element
+    pl_chunk_db.chunk_queue[vl_idx]:=c_empty_Chunk_queue_element;
+    
+    
+    // put it into the end of the free list
+    pl_chunk_db.chunk_queue[vl_idx].next_element:=-1;  // This will be the last entry
+    if(pl_chunk_db.last_free!=-1){
+      pl_chunk_db.chunk_queue[pl_chunk_db.last_free].next_element:=vl_idx
+    }
+    pl_chunk_db.last_free:=vl_idx
+    if(pl_chunk_db.first_free==-1){
+      // There was no first element. 
+      pl_chunk_db.first_free:=vl_idx
+    }
+    pl_chunk_db.used_entries:=pl_chunk_db.used_entries-1;
+    
+    
+  }
+}
+
+
+// Examines the tx chunk queue and marks the packet, which should be abandoned.
+// If there are  packets to abandon generates the forward TSN chunk
+function SCTP_data_abandon_marker(in integer pl_assoc_id, inout SCTP_Chunk_List pl_chunks_before_data) runs on SCTP_Engine_CT {
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.forward_tsn_supported){
+    // the function is not active
+    return
+  }
+
+  var boolean vl_abandoned:= false
+  var integer vl_i:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.first_element
+  
+  var integer_list vl_list:={}
+  while(vl_i!=-1){
+    if(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].mark_flag){
+      // The chunk is marked for retransmission
+      // We should inspect only these chunks
+      if( (v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].counter == 0)  // reached the retransmit counter limit
+          or ( (v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].lifetime>0.0)  // reached the lifetime
+               and (v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].lifetime<t_run_time.read)
+             )
+        ){
+        // abandon the packet
+        v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].mark_flag:=false
+        v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].unmark_flag:= true
+        vl_list[sizeof(vl_list)]:=vl_i
+        vl_abandoned:=true
+      }
+      
+    }
+  }
+  
+  // If new packet were market to abandon
+  // find and mark all of the chunk & messages belongs to the marked chunks
+  if(vl_abandoned){
+    for(var integer vl_k:=0;vl_k<sizeof(vl_list);vl_k:=vl_k+1){
+      var integer vl_stream_id:=SCTP_data_get_chunk_stream_id(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_list[vl_k]].chunk)
+      var integer vl_ssn:=SCTP_data_get_chunk_ssn(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_list[vl_k]].chunk)
+      
+      // mark the message as abandoned in the stream queue
+      SCTP_data_abandon_msg_in_stream(vl_stream_id,vl_ssn,SCTP_message_get_U_bit(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_list[vl_k]].chunk),pl_assoc_id)
+      
+      // find the releated chunks in the chunk queue
+      vl_i:=SCTP_data_find_related(vl_stream_id,vl_ssn,vl_list[vl_k],v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue)
+      while(vl_i!=-1){
+        v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].mark_flag:=false
+        v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].unmark_flag:= true
+        vl_i:=SCTP_data_find_related(vl_stream_id,vl_ssn,vl_i,v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue)
+      }
+      
+    }
+  }
+  
+  // Generate the forward tsn chunk if needed
+  // check the beggining of the list. 
+  var SCTP_Chunk vl_chunk
+
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported){
+    vl_chunk.iforward_tsn:={
+      chunk_type:=194,
+      flags:='00000000'B,
+      chunk_length:=0,
+      new_tsn:=-1,
+      stream_ssn_list:={}
+    }
+  } else {
+    vl_chunk.forward_tsn:={
+      chunk_type:=192,
+      flags:='00000000'B,
+      chunk_length:=0,
+      new_tsn:=-1,
+      stream_ssn_list:={}
+    }
+  }
+  
+  vl_i:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.first_element
+  
+  var boolean vl_iforward:=false
+  // We iterate through the chunks in order
+  while( (vl_i != -1) and (v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].unmark_flag) ){
+    vl_iforward:=false
+    // set the tsn
+    if(v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported){
+      vl_chunk.iforward_tsn.new_tsn:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].tsn
+    } else {
+      vl_chunk.forward_tsn.new_tsn:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].tsn
+    }
+    
+    // add the skiped ssn to the map if needed
+    if(SCTP_message_get_U_bit(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].chunk)=='0'B){
+      // ordered chunk
+      // find the index of the stream in the list
+      var integer vl_a:=0
+      var integer vl_len
+      if(v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported){
+        vl_len:=lengthof(vl_chunk.iforward_tsn.stream_ssn_list)
+      } else {
+        vl_len:=lengthof(vl_chunk.forward_tsn.stream_ssn_list)
+      }
+      
+      for(vl_a:=0;vl_a<vl_len;vl_a:=vl_a+1){
+        var integer vl_s
+        if(v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported){
+          vl_s:=vl_chunk.iforward_tsn.stream_ssn_list[vl_a].stream_id
+        } else {
+          vl_s:=vl_chunk.forward_tsn.stream_ssn_list[vl_a].stream_id
+        }
+        if(vl_s==SCTP_data_get_chunk_stream_id(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].chunk)){
+          break
+        }
+      }
+
+      if(v_assoc_db.associations[pl_assoc_id].assoc_data.i_data_supported){
+        vl_chunk.iforward_tsn.stream_ssn_list[vl_a]:={stream_id:=SCTP_data_get_chunk_stream_id(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].chunk),
+                                                      reserved:=0,
+                                                      mid:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].chunk.idata.mid
+                                                      }
+      } else {
+        vl_chunk.forward_tsn.stream_ssn_list[vl_a]:={stream_id:=SCTP_data_get_chunk_stream_id(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].chunk),
+                                                      ssn:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].chunk.data.ssn
+                                                     }
+      }
+      
+    }
+
+    SCTP_Chunk_queue_pop(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue)
+    
+    // reset the T3 timer
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=0
+    SCTP_timer_T3_restart(pl_assoc_id)
+
+    vl_i:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.first_element
+    
+  }
+  
+  // Add forward tsn to the list if built
+  if(vl_iforward){
+    pl_chunks_before_data[lengthof(pl_chunks_before_data)]:=vl_chunk
+  }
+
+}
+
+
+// Finf the next chunk which belongs to the given stream-id, ssn, starting the search from the given idx
+function SCTP_data_find_related ( in integer pl_stream_id,
+                                  in integer pl_ssn,
+                                  in integer pl_idx,
+                                  in SCTP_Chunk_queue_element_list_t   pl_chunk_queue
+                                          ) runs on SCTP_Engine_CT return integer{
+  if(SCTP_message_get_E_bit(pl_chunk_queue[pl_idx].chunk) == '1'B){
+    return -1 // This is the last chunk of the message, there is no next message
+  }
+  
+  var bitstring vl_u:=SCTP_message_get_U_bit(pl_chunk_queue[pl_idx].chunk)
+  pl_idx:=pl_chunk_queue[pl_idx].next_element
+  while(pl_idx!=-1){
+    if( (pl_ssn==SCTP_data_get_chunk_ssn(pl_chunk_queue[pl_idx].chunk))
+        and (pl_stream_id==SCTP_data_get_chunk_stream_id(pl_chunk_queue[pl_idx].chunk))
+        and (vl_u==SCTP_message_get_U_bit(pl_chunk_queue[pl_idx].chunk))
+        ){
+      return pl_idx // found it
+    }
+  }
+  
+  return -1
+}
+
+// Marks one message as abandoned in a stream queue
+function SCTP_data_abandon_msg_in_stream( in integer pl_stream_id,
+                                          in integer pl_ssn,
+                                          in bitstring pl_u_bit,
+                                          in integer pl_assoc_id
+                                          ) runs on SCTP_Engine_CT {
+  // find the idx of the stream
+  var integer vl_stream_idx:=-1
+  if(SCTP_int2int_get(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_stream_idx_map_id,
+                            pl_stream_id,
+                            vl_stream_idx
+                            )!=-1){
+    
+    if(pl_u_bit=='1'B){
+      vl_stream_idx:=vl_stream_idx+1 // we need to inspect the unordered queue
+    }
+    var integer vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_stream_idx].messages.first_element
+    while(vl_idx!=-1){
+      var integer vl_comp:=SCTP_compare_ssn(pl_ssn, SCTP_data_get_chunk_ssn(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_stream_idx].messages.chunk_queue[vl_idx].chunk))
+      if(vl_comp==0){
+        // we found, the message
+        // mark it
+        v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_stream_idx].messages.chunk_queue[vl_idx].unmark_flag:=true
+        return // nothing to do more
+      } else if(vl_comp<0){
+        // The ssn of the message is greater than the searhed one, nothing to do more
+        return
+      }
+      vl_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_stream_idx].messages.chunk_queue[vl_idx].next_element
+    }
+  }
+
+}
+
+// Assembles and send data packet
+// Tries to send as many as enabled by the congestion controll mechanism
+function SCTP_data_send_scheduler(in integer pl_assoc_id, in SCTP_Chunk_List pl_chunks_before_data:={}) runs on SCTP_Engine_CT {
+  
+  var SCTP_Packet       vl_sctp := c_empty_sctp_packet
+  vl_sctp:={
+    common_header :={
+      source_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.local_port,
+      destination_port:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_port,
+      verification_tag := v_assoc_db.associations[pl_assoc_id].assoc_data.remote_tag
+    },
+    chunks:=pl_chunks_before_data
+  }
+  
+  SCTP_data_abandon_marker(pl_assoc_id,vl_sctp.chunks)
+  
+  var integer vl_before_list_size:=lengthof(vl_sctp.chunks)
+//log("Schedule 1 ", v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd)
+//log("Schedule 2 ", v_assoc_db.associations[pl_assoc_id].assoc_data.ssthresh)
+//log("Schedule 3 ", v_assoc_db.associations[pl_assoc_id].assoc_data.partially_acked_bytes)
+  // If there is data chank marked for retransmission, we try to send them first regardless the cwnd
+  while(SCTP_data_add_packet(vl_sctp,pl_assoc_id)){
+//log("Send")
+    SCTP_send_packet(v_assoc_db.associations[pl_assoc_id].assoc_data.transport_id,vl_sctp);
+    vl_before_list_size := 0
+    vl_sctp.chunks:={}
+  }
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.used_entries!=0){
+    SCTP_timer_T3_start(pl_assoc_id)  // start the timer if data chunk is on the fly
+  }
+//log("Schedule end ", v_assoc_db.associations[pl_assoc_id].assoc_data)
+
+  // If shuting down
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.state == SCTP_ASSOC_SHUTDOWN_RECEIVED){
+    if(SCTP_tx_queue_empty(pl_assoc_id)){ // No more data to send
+      // Send shutdown ack
+      
+      // Stop all timers
+      SCTP_timer_stop_all(pl_assoc_id)
+      
+      // Reset the retransmit counter
+      v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=0
+
+      // Send shutdown ack
+      SCTP_message_send_shutdown_ack(pl_assoc_id)
+
+      // Start timer
+      v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                    SCTP_event_schedule(pl_assoc_id,c_timer_T2_shutdown,v_assoc_db.associations[pl_assoc_id].assoc_data.rto)
+      
+      // Set the state
+      v_assoc_db.associations[pl_assoc_id].assoc_data.state := SCTP_ASSOC_SHUTDOWN_ACK_SENT
+      
+      SCTP_hearbeat_stop(pl_assoc_id)
+    }
+  } else if(v_assoc_db.associations[pl_assoc_id].assoc_data.state == SCTP_ASSOC_SHUTDOWN_PENDING){
+    if(SCTP_tx_queue_empty(pl_assoc_id)){ // No more data to send
+      // Send shutdown
+
+      // Stop all timers
+      SCTP_timer_stop_all(pl_assoc_id)
+      
+      // Reset the retransmit counter
+      v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=0
+
+      // Send shutdown ack
+      SCTP_message_send_shutdown(pl_assoc_id)
+
+      // Start timer
+      v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                    SCTP_event_schedule(pl_assoc_id,c_timer_T2_shutdown,v_assoc_db.associations[pl_assoc_id].assoc_data.rto)
+      
+      // Set the state
+      v_assoc_db.associations[pl_assoc_id].assoc_data.state := SCTP_ASSOC_SHUTDOWN_SENT
+      
+      SCTP_hearbeat_stop(pl_assoc_id)
+    }
+  }
+
+}
+
+
+// Return true if all of the sending queues are empty
+function  SCTP_tx_queue_empty(in integer pl_assoc_id) runs on SCTP_Engine_CT return boolean {
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.used_entries!=0){
+    return false  // There are unacknowledged chunk
+  }
+  // check the stream queues
+  for(var integer vl_idx:=0;vl_idx<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues);vl_idx:=vl_idx+1){
+    if(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_idx].messages.used_entries!=0){
+      return false  // There are data to send
+    }
+  
+  }
+  return true
+}
+
+
+// Adds as many data packets to the message as many possible
+// Limits:
+//  - pmtu
+//  - congestion control
+//  - Packet size
+function  SCTP_data_add_packet(inout SCTP_Packet vl_sctp, in integer pl_assoc_id) runs on SCTP_Engine_CT return boolean {
+
+  var integer vl_packet_size:= 12 // the size of the common header
+  if(lengthof(vl_sctp.chunks)!=0){
+  // Calculate the actual packet size
+    var octetstring vl_tmp:=f_SCTP_enc(vl_sctp);
+    vl_packet_size:=lengthof(vl_tmp);
+  }
+
+  // We are allowed to send that many bytes now
+  var integer max_to_send:=v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd-v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size;
+  // calculate the maximum packet size
+  var integer rem_packet_size:=v_assoc_db.associations[pl_assoc_id].assoc_data.pmtu-vl_packet_size;
+
+  // look for packet to retransmit
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.used_entries>0){
+    // the tx chunk queue is not empty
+    var integer vl_i:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.first_element
+    while(vl_i!=-1){
+      if(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].mark_flag){
+        // the chunk is marked for retransmit
+        var integer vl_chunk_size:=SCTP_data_get_chunk_size(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].chunk)
+
+        if(rem_packet_size>=vl_chunk_size){
+          // add the chunk
+          vl_sctp.chunks[sizeof(vl_sctp.chunks)]:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].chunk
+          rem_packet_size:=rem_packet_size-vl_chunk_size
+
+          // Adjust the retransmit counter of the packet
+          if(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].counter>0){
+            v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].counter:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].counter-1
+          }
+          
+          // clear mark
+          v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].mark_flag:=false
+        } else {
+          // chunk doesn't fit into the packet
+          return sizeof(vl_sctp.chunks)>0 // there is something to send
+        }
+      }
+      vl_i:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_i].next_element
+    }
+  }
+
+  // Adjust the max_to_send according to the peer receive window
+  if(max_to_send>v_assoc_db.associations[pl_assoc_id].assoc_data.remote_a_rwnd){
+    if((v_assoc_db.associations[pl_assoc_id].assoc_data.remote_a_rwnd==0) and  // The remote side closed the window
+       (v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size == 0) // and not data in fligth
+       ){  // we can try to send 1 data packet. Zero window probe
+      max_to_send:= SCTP_min(max_to_send,v_assoc_db.associations[pl_assoc_id].assoc_data.pmtu) // max one MTU is allowed, if the cwnd allows it.
+    } else {
+      max_to_send:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_a_rwnd  // limit the max data
+    }
+  }
+
+    // new data sending allowed
+    // 6.1 rule B
+    var integer vl_i:=0
+    while((vl_i<lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues)) and (max_to_send>c_min_chunk_size ) and (rem_packet_size>c_min_chunk_size )){
+      // iterate through the queues for message to send
+      var integer vl_msg_q_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.scheduled_queue
+      
+      var boolean vl_can_try_next := true
+      // The size of the chunk is limited by the 
+      // - rem_packet_size 
+      // - v_assoc_db.associations[pl_assoc_id].assoc_data.data_chunk_max_size
+      var integer vl_max_chunk_size:=SCTP_min(rem_packet_size,v_assoc_db.associations[pl_assoc_id].assoc_data.data_chunk_max_size)
+      
+      if((v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_msg_q_idx].messages.used_entries>0)
+         and (not v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_msg_q_idx].flag)){
+        var integer vl_chunk_size:=SCTP_data_add_one_chunk(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues[vl_msg_q_idx] , // The msg queue of the stream
+                                  v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue, // The tx chunk queue
+                                  vl_sctp,  // The SCTP message, will be sent
+                                  pl_assoc_id, // The association
+                                  vl_max_chunk_size, // The max size of the chunk
+                                  vl_can_try_next // true - last chunk of the message is added, false otherwise
+                                 )
+          rem_packet_size:=rem_packet_size-vl_chunk_size
+          max_to_send:=max_to_send-vl_chunk_size
+      }
+      if(v_assoc_db.associations[pl_assoc_id].assoc_data.remote_a_rwnd==0){  // We added the zero window probe
+        return sizeof(vl_sctp.chunks)>0 // Should not add more chunk
+      }
+      // next queue
+      if(vl_can_try_next){
+        v_assoc_db.associations[pl_assoc_id].assoc_data.scheduled_queue:= (vl_msg_q_idx+1) mod lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues)
+        vl_i:=vl_i+1
+      }
+    }
+    
+    if(vl_i==lengthof(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_msg_queues)){
+      // no more dtat to send
+      v_assoc_db.associations[pl_assoc_id].assoc_data.partially_acked_bytes:=0
+    }
+return sizeof(vl_sctp.chunks)>0 
+}
+
+// adds 1 chunk to the SCTP msg for sending
+// return the size of the added chunk
+//        or 0 if not chunk added
+// indicates if the last chunk of the message were added
+
+function SCTP_data_add_one_chunk( inout SCTP_msg_queue_t  pl_stream_tx_queue, // The msg queue of the stream
+                                  inout SCTP_Chunk_queue_db_t pl_tx_chunk_queue, // The tx chunk queue
+                                  inout SCTP_Packet pl_sctp,  // The SCTP message, will be sent
+                                  in integer pl_assoc_id, // The association
+                                  in integer pl_max_size, // The max size of the chunk
+                                  out boolean pl_last_chunk // true - last chunk of the message is added, false otherwise
+                                 ) runs on SCTP_Engine_CT return integer {
+
+  var integer vl_queue_entry:=pl_stream_tx_queue.messages.first_element
+  var integer vl_chunk_size:=SCTP_data_get_chunk_size(pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+  var integer vl_chunk_header_size:=SCTP_data_get_chunk_header_size(pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+  
+  var integer ret_val:=0
+    pl_last_chunk := false
+  
+  if(pl_max_size<c_min_chunk_size){
+    return ret_val // Can't add more chunk
+  }
+  
+  if( ((pl_stream_tx_queue.num_of_queued_octets==0)
+       and (pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].lifetime>=0.0)
+       and (pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].lifetime<t_run_time.read))  // lifetime expired
+       
+       or
+       
+       (pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].unmark_flag) //marked for abandon
+       
+       
+       ){
+    // drop the message
+    SCTP_Chunk_queue_pop(pl_stream_tx_queue.messages)
+    pl_stream_tx_queue.num_of_queued_octets:=0
+    return ret_val // Can't add more chunk
+    
+  }
+  
+  if( (pl_stream_tx_queue.num_of_queued_octets==0) and
+      ( vl_chunk_size <= pl_max_size)
+      ){
+    // The whole message is fit into the chunk
+    // set counters
+    v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size:=v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size+vl_chunk_size
+
+    // set the tsn
+    var integer vl_act_tsn:=v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn
+    v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn:=SCTP_next_tsn(vl_act_tsn)
+    pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].tsn:=vl_act_tsn
+    SCTP_data_set_chunk_tsn(pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk,vl_act_tsn)
+
+    // Whole message in one chunk, set B & E bits
+    SCTP_message_set_B_bit('1'B, pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+    SCTP_message_set_E_bit('1'B, pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+
+    // copy the packet to the tx_queue
+    SCTP_Chunk_queue_push(pl_tx_chunk_queue,
+         pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry]                 
+      )
+
+    // add the chunk to the message
+    pl_sctp.chunks[sizeof(pl_sctp.chunks)]:=pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk
+
+
+    // remove it from the stream queue
+    SCTP_Chunk_queue_pop(pl_stream_tx_queue.messages)
+
+    pl_last_chunk := true  // Last chunk
+    ret_val := vl_chunk_size  // report the chunk size
+  } else {
+    // The message doesn't fit into one chunk, or fragmented
+    if(pl_stream_tx_queue.num_of_queued_octets==0){
+      // It should be fragmented
+      // Generate the first fragment
+      // set the tsn
+      var integer vl_act_tsn:=v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn
+      v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn:=SCTP_next_tsn(vl_act_tsn)
+      pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].tsn:=vl_act_tsn
+      SCTP_data_set_chunk_tsn(pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk,vl_act_tsn)
+
+      // set B & E bits
+      SCTP_message_set_B_bit('1'B, pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+      SCTP_message_set_E_bit('0'B, pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+
+      // copy the packet to the tx_queue
+      SCTP_Chunk_queue_push(pl_tx_chunk_queue,
+           pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry]                 
+        )
+
+      // Set the next Fragment Sequence Number if I-DATA
+      SCTP_set_next_fsn(pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+
+      // set the data part of the packet
+      var integer vl_chunk_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.last_element
+
+      // The whole message was copied, remove the unnessary data. Note: octetstring uses copy-on-write
+      SCTP_message_substr_chunk_data(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_chunk_idx].chunk,0,pl_max_size-vl_chunk_header_size);
+
+      // add the chunk to the message
+      pl_sctp.chunks[sizeof(pl_sctp.chunks)]:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_chunk_idx].chunk
+
+      // set counters
+      v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size:=v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size+pl_max_size
+      pl_stream_tx_queue.num_of_queued_octets:=pl_max_size-vl_chunk_header_size
+
+      pl_last_chunk := false  // not the last chunk
+      ret_val := pl_max_size  // report th echunk size
+
+    } else {
+      // already fragmented, next fragment
+      // It should be fragmented
+      // set the tsn
+      var integer vl_act_tsn:=v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn
+      v_assoc_db.associations[pl_assoc_id].assoc_data.own_tsn:=SCTP_next_tsn(vl_act_tsn)
+      pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].tsn:=vl_act_tsn
+      SCTP_data_set_chunk_tsn(pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk,vl_act_tsn)
+
+      // set B & E bits
+      SCTP_message_set_B_bit('0'B, pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+
+      if((vl_chunk_size-pl_stream_tx_queue.num_of_queued_octets)<=pl_max_size){
+        // Last chunk of the message
+        SCTP_message_set_E_bit('1'B, pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+        ret_val:=vl_chunk_size-pl_stream_tx_queue.num_of_queued_octets
+        pl_last_chunk := true  // not the last chunk
+      } else {
+        // middle chunk
+        SCTP_message_set_E_bit('0'B, pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+        ret_val:=pl_max_size
+        pl_last_chunk := false  // not the last chunk
+      }
+
+      // copy the packet to the tx_queue
+      SCTP_Chunk_queue_push(pl_tx_chunk_queue,
+           pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry]                 
+        )
+
+      // Set the next Fragment Sequence Number if I-DATA
+      SCTP_set_next_fsn(pl_stream_tx_queue.messages.chunk_queue[vl_queue_entry].chunk)
+
+      // The whole message was copied, remove the unnessary data. Note: octetstring uses copy-on-write
+      var integer vl_chunk_idx:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.last_element
+      SCTP_message_substr_chunk_data(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_chunk_idx].chunk,pl_stream_tx_queue.num_of_queued_octets,ret_val-vl_chunk_header_size);
+
+      // add the chunk to the message
+      pl_sctp.chunks[sizeof(pl_sctp.chunks)]:=v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.chunk_queue[vl_chunk_idx].chunk
+      // set counters
+      v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size:=v_assoc_db.associations[pl_assoc_id].assoc_data.flight_size+ret_val
+
+      if(pl_last_chunk){
+
+        // remove it from the stream queue
+        SCTP_Chunk_queue_pop(pl_stream_tx_queue.messages)
+        pl_stream_tx_queue.num_of_queued_octets:=0
+      } else {
+        pl_stream_tx_queue.num_of_queued_octets:=pl_stream_tx_queue.num_of_queued_octets+ret_val-vl_chunk_header_size
+        // middle chunk, we used all of the spaces in the packet
+      }
+    }  
+  }
+  return ret_val
+}
+
+
+// Set the next Fragment Sequence Number if I-DATA
+function SCTP_set_next_fsn(inout SCTP_Chunk pl_chunk){
+  if(ischosen(pl_chunk.idata)){
+    // I-DATA chunk
+    if(pl_chunk.idata.B_flag=='1'B){
+      // Beginning chunk, the next fsn will be 1
+      pl_chunk.idata.ppid_fsn:=1
+    } else {
+      pl_chunk.idata.ppid_fsn:=SCTP_next_tsn(pl_chunk.idata.ppid_fsn)  // +1 mod 2^32 like TSN
+    }
+  }
+}
+
+function SCTP_message_substr_chunk_data(inout SCTP_Chunk pl_chunk, in integer pl_begin, in integer pl_length){
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    pl_chunk.data.user_data:=substr(pl_chunk.data.user_data,pl_begin,pl_length)
+  } else {
+    // I-DATA chunk
+    pl_chunk.idata.user_data:=substr(pl_chunk.idata.user_data,pl_begin,pl_length)
+
+  }
+}
+
+function SCTP_message_set_B_bit(in bitstring pl_B_bit, inout SCTP_Chunk pl_chunk){
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    pl_chunk.data.B_flag:=pl_B_bit
+  } else {
+    // I-DATA chunk
+    pl_chunk.idata.B_flag:=pl_B_bit
+
+  }
+}
+
+function SCTP_message_get_B_bit(in SCTP_Chunk pl_chunk) return bitstring {
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    return pl_chunk.data.B_flag
+  } else {
+    // I-DATA chunk
+    return pl_chunk.idata.B_flag
+
+  }
+  return '0'B
+}
+
+function SCTP_message_set_E_bit(in bitstring pl_E_bit, inout SCTP_Chunk pl_chunk){
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    pl_chunk.data.E_flag:=pl_E_bit
+  } else {
+    // I-DATA chunk
+    pl_chunk.idata.E_flag:=pl_E_bit
+
+  }
+}
+
+function SCTP_message_get_E_bit(in SCTP_Chunk pl_chunk) return bitstring {
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    return pl_chunk.data.E_flag
+  } else {
+    // I-DATA chunk
+    return pl_chunk.idata.E_flag
+
+  }
+  return '0'B
+}
+
+function SCTP_message_get_U_bit(in SCTP_Chunk pl_chunk) return bitstring {
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    return pl_chunk.data.U_flag
+  } else {
+    // I-DATA chunk
+    return pl_chunk.idata.U_flag
+
+  }
+  return '0'B
+}
+function SCTP_data_get_chunk_size(in SCTP_Chunk pl_chunk) return integer {
+  var integer vl_chunk_size:=0;
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    vl_chunk_size:=16+lengthof(pl_chunk.data.user_data)
+  } else {
+    // I-DATA chunk
+    vl_chunk_size:=20+lengthof(pl_chunk.idata.user_data)
+
+  }
+  return vl_chunk_size
+}
+function SCTP_data_get_chunk_header_size(in SCTP_Chunk pl_chunk) return integer {
+  var integer vl_chunk_size:=0;
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    vl_chunk_size:=16
+  } else {
+    // I-DATA chunk
+    vl_chunk_size:=20
+
+  }
+  return vl_chunk_size
+}
+
+function SCTP_data_set_chunk_tsn(inout  SCTP_Chunk pl_chunk, in integer pl_tsn){
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    pl_chunk.data.tsn:=pl_tsn
+  } else {
+    // I-DATA chunk
+    pl_chunk.idata.tsn:=pl_tsn
+  }
+  
+}
+
+function SCTP_data_get_chunk_tsn(inout  SCTP_Chunk pl_chunk) return integer{
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    return pl_chunk.data.tsn
+  } else {
+    // I-DATA chunk
+    return pl_chunk.idata.tsn
+  }
+  return -1
+}
+
+function SCTP_data_get_chunk_ssn(inout  SCTP_Chunk pl_chunk) return integer{
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    return pl_chunk.data.ssn
+  } else {
+    // I-DATA chunk
+    return pl_chunk.idata.mid mod 65536
+  }
+  return -1
+}
+
+function SCTP_data_get_chunk_stream_id(inout  SCTP_Chunk pl_chunk) return integer{
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    return pl_chunk.data.stream_id
+  } else {
+    // I-DATA chunk
+    return pl_chunk.idata.stream_id
+  }
+  return -1
+}
+
+// returns the sequence number used for reassembly
+// It is TSN for normal data packet
+// It is the FSN for I-data packet
+function SCTP_data_get_chunk_reassembly_seq_no(inout  SCTP_Chunk pl_chunk) return integer{
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    return pl_chunk.data.tsn
+  } else {
+    // I-DATA chunk
+    if(pl_chunk.idata.B_flag == '0'B){
+      // Not the first chunk of the message
+      return pl_chunk.idata.ppid_fsn
+    } else {
+      // First chunk of the message, the FSN is 0
+      return 0
+    }
+  }
+  return -1
+}
+
+function SCTP_data_chunk_append_data(inout  SCTP_Chunk pl_chunk_a, in SCTP_Chunk pl_chunk_b){
+  if(ischosen(pl_chunk_a.data)){
+   pl_chunk_a.data.user_data:=pl_chunk_a.data.user_data & pl_chunk_b.data.user_data
+   // Data chunk
+  } else {
+    // I-DATA chunk
+   pl_chunk_a.idata.user_data:=pl_chunk_a.idata.user_data & pl_chunk_b.idata.user_data
+  }
+}
+
+function SCTP_data_chunk_copy_tsn(inout  SCTP_Chunk pl_chunk_a, in SCTP_Chunk pl_chunk_b){
+  if(ischosen(pl_chunk_a.data)){
+   pl_chunk_a.data.tsn:=pl_chunk_b.data.tsn
+   // Data chunk
+  } else {
+    // I-DATA chunk
+   pl_chunk_a.idata.tsn:=pl_chunk_b.idata.tsn
+  }
+}
+
+function SCTP_data_get_msg_data(in SCTP_Chunk pl_chunk,inout SCTP_MSG_data pl_msg_data, in integer pl_assoc_id) {// Copy the msg 
+  if(ischosen(pl_chunk.data)){
+    // Data chunk
+    pl_msg_data:={
+      assoc_id:=pl_assoc_id,
+      ppid:=pl_chunk.data.ppid,
+      stream_id:=pl_chunk.data.stream_id,
+      data:=pl_chunk.data.user_data,
+      options:=omit
+    }
+  } else {
+    // I-DATA chunk
+    pl_msg_data:={
+      assoc_id:=pl_assoc_id,
+      ppid:=pl_chunk.idata.ppid_fsn,
+      stream_id:=pl_chunk.idata.stream_id,
+      data:=pl_chunk.idata.user_data,
+      options:=omit
+    }
+  }
+  
+}
+
+// Start reconf timer if needed
+function SCTP_timer_reconf_start(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id!=-1){
+    // the timer is already running.
+    // Nothing to do
+    return
+  }
+  // Calculate the timeout
+  var float vl_new_timeout:= SCTP_timeout_calculate_timeout_value(v_assoc_db.associations[pl_assoc_id].assoc_data.rto,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_retransmit_counter,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.rto_max
+                                                                    )
+
+  //start the timer
+  v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id:=
+                           SCTP_event_schedule(pl_assoc_id,c_timer_reconfig,vl_new_timeout)
+  
+  
+}
+function SCTP_timer_reconf_stop(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id!=-1){
+    SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id)
+    v_assoc_db.associations[pl_assoc_id].assoc_data.reconfig_event_id:=-1
+  }
+}
+
+
+//Start the T3-rtx timer if needed
+function SCTP_timer_T3_start(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event!=-1){
+    // the timer is already running.
+    // Nothing to do
+    return
+  }
+  // Calculate the timeout
+  var float vl_new_timeout:= SCTP_timeout_calculate_timeout_value(v_assoc_db.associations[pl_assoc_id].assoc_data.rto,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.rto_max
+                                                                    )
+
+  //start the timer
+  v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                           SCTP_event_schedule(pl_assoc_id,c_timer_T3_rtx,vl_new_timeout)
+  
+  
+}
+
+// Reschedule the T3-rtx timer
+function SCTP_timer_T3_restart(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  // Stop th etimer if running
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event!=-1){
+    SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event)
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+  }
+  
+  // Start it if there is not acked data
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.tx_chunk_queue.used_entries>0){
+    // Calculate the timeout
+    var float vl_new_timeout:= SCTP_timeout_calculate_timeout_value(v_assoc_db.associations[pl_assoc_id].assoc_data.rto,
+                                                                      v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter,
+                                                                      v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.rto_max
+                                                                      )
+
+    //start the timer
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                             SCTP_event_schedule(pl_assoc_id,c_timer_T3_rtx,vl_new_timeout)
+
+  }
+}
+
+function SCTP_timer_T2_restart(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  // Stop the timer if running
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event!=-1){
+    SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event)
+    v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=-1
+  }
+  // Clear counter
+  v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_counter:=0
+
+  //start the timer
+  v_assoc_db.associations[pl_assoc_id].assoc_data.retransmit_timer_event:=
+                           SCTP_event_schedule(pl_assoc_id,c_timer_T2_shutdown,v_assoc_db.associations[pl_assoc_id].assoc_data.rto)
+  
+}
+// Initializes the congestion control parameters
+function SCTP_congestion_set_init_params(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  // initial cwn = min(4* pmtu, max(2*PMTU,4380)
+  var integer vl_cwnd:=4380
+  var integer vl_pmtu:=v_assoc_db.associations[pl_assoc_id].assoc_data.pmtu
+  if((2*vl_pmtu)>vl_cwnd) {
+    vl_cwnd:=2*vl_pmtu
+  }
+  if((4*vl_pmtu)<vl_cwnd){
+    vl_cwnd:=4*vl_pmtu
+  }
+  
+  v_assoc_db.associations[pl_assoc_id].assoc_data.cwnd:=vl_cwnd
+  v_assoc_db.associations[pl_assoc_id].assoc_data.ssthresh:=v_assoc_db.associations[pl_assoc_id].assoc_data.remote_a_rwnd
+  
+}
+
+// Start the heartbeat service
+function SCTP_hearbeat_start(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  v_assoc_db.associations[pl_assoc_id].assoc_data.hb_retrial_counter:=0
+  SCTP_hearbeat_schedule(pl_assoc_id)
+}
+
+// Stop the heartbeat service
+function SCTP_hearbeat_stop(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id!=-1){
+    SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id)
+  }
+  v_assoc_db.associations[pl_assoc_id].assoc_data.hb_retrial_counter:=0
+}
+
+// Schedule the next heartbeat
+function SCTP_hearbeat_schedule(in integer pl_assoc_id) runs on SCTP_Engine_CT{
+  if(v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id!=-1){
+    SCTP_event_remove(v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id)
+  }
+  var float vl_new_timeout:= SCTP_timeout_calculate_timeout_value(v_assoc_db.associations[pl_assoc_id].assoc_data.rto,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.hb_retrial_counter,
+                                                                    v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.rto_max
+                                                                    ) + v_assoc_db.associations[pl_assoc_id].assoc_data.proto_params.hb_interval
+  v_assoc_db.associations[pl_assoc_id].assoc_data.hb_event_id:=SCTP_event_schedule(pl_assoc_id,c_timer_heartbeat,vl_new_timeout)
+}
+
+
+}
diff --git a/src/SCTP_Engine_PortTypes.ttcn b/src/SCTP_Engine_PortTypes.ttcn
new file mode 100644
index 0000000..e589b64
--- /dev/null
+++ b/src/SCTP_Engine_PortTypes.ttcn
@@ -0,0 +1,299 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v2.0
+// which accompanies this distribution, and is available at
+// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+///////////////////////////////////////////////////////////////////////////////
+//
+//  File:               SCTP_Engine_PortTypes.ttcn
+//  Description:        Test port definition of the SCTP Engine
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 840
+//
+module SCTP_Engine_PortTypes {
+
+
+// Upper side test port. Provides the SCTP API
+
+// Signature definition of the procedure calls
+// Client -> SCTP Engine component
+
+// If the requested operation was executed successfully all of the
+// procedure returns SCTP_Engine_result
+// If something went wrong an execption will be raised.
+
+// The assoc-id of the listen port is returned.
+// A separate assoc_id will be created for the accepted connections
+signature S_SCTP_Listen(in SCTP_Listen_data pl_arg) 
+          return SCTP_Engine_result
+          exception (SCTP_operation_execption)
+
+signature S_SCTP_Connect(in SCTP_Connect_data pl_arg) 
+          return SCTP_Engine_result
+          exception (SCTP_operation_execption)
+
+
+// The shutdown procedure and the release of the assoc_id shoud be done as:
+//
+//  User initiated shutdown is a 3 step procedure:
+//     call    S_SCTP_Shutdown
+//     receive S_SCTP_Shutdown_ind
+//     call    S_SCTP_Shutdown_conf
+//
+//  Remote side initiated shutdown
+//     receive S_SCTP_Shutdown_ind
+//     call    S_SCTP_Shutdown_conf
+//
+// The assoc_id is released only after the call of the S_SCTP_Shutdown_conf
+
+signature S_SCTP_Shutdown(in SCTP_Shutdown_data pl_arg) 
+          return SCTP_Engine_result
+          exception (SCTP_operation_execption)
+
+
+signature S_SCTP_Shutdown_conf(in integer assoc_id) 
+          return SCTP_Engine_result
+          exception (SCTP_operation_execption)
+
+
+// Request the sending of user data
+
+signature S_SCTP_Send_req(in SCTP_MSG_data pl_arg)
+          return SCTP_Engine_result
+          exception (SCTP_operation_execption)
+
+
+// Set options
+signature S_SCTP_options(in SCTP_Options_data pl_arg)
+          return SCTP_Engine_result
+          exception (SCTP_operation_execption)
+
+// Reconfiguration request
+signature S_SCTP_reconfig(in SCTP_Reconfiguration_req pl_arg)
+          return SCTP_Engine_result
+          exception (SCTP_operation_execption)
+
+
+// SCTP engine -> Client
+
+// Shutdown indication
+signature S_SCTP_Shutdown_ind(in SCTP_Shutdown_data pl_arg) 
+
+// Connected indication. 
+// called by the SCTP engine, when accepting a new client connection
+signature S_SCTP_Connected_ind(in SCTP_Connected_data pl_arg) 
+
+// Receive data indication
+signature S_SCTP_Received_ind(in SCTP_MSG_data pl_arg) 
+
+// Notification indication
+signature S_SCTP_Notification_ind(in SCTP_Notification_data pl_arg) 
+
+// API type definitions
+type record SCTP_Notification_data {
+  integer assoc_id,
+  SCTP_Notification_union  notification,
+  SCTP_Engine_Option_list options optional     
+}
+
+type record SCTP_Notification_Comm_up{
+}
+
+type record SCTP_Notification_Comm_lost{
+}
+
+type union SCTP_Notification_union{
+  SCTP_Notification_Comm_up     comm_up,
+  SCTP_Notification_Comm_lost   comm_lost,
+  SCTP_Reconfiguration          reconfig
+}
+
+type enumerated SCTP_Reconfig_result { RECONFIG_OK, RECONFIG_FAIL, RECONFIG_DENY }
+
+type record SCTP_Reconfiguration { // RFC 6525
+  SCTP_Reconfig_result         result,
+  SCTP_Reconfiguration_method  method optional
+}
+
+type record SCTP_Reconfiguration_req {
+  integer assoc_id,
+  SCTP_Reconfiguration_method  reconf_method
+}
+
+
+type union SCTP_Reconfiguration_method{ // RFC 6525
+  SCTP_Reconfig_Stream_Reset   stream_reset,
+  SCTP_Reconfig_Assoc_Reset    assoc_reset,
+  SCTP_Reconfig_Stream_Add     add_stream
+}
+
+type record SCTP_Reconfig_Stream_Reset{
+  boolean  incoming,
+  record of integer streams optional
+}
+
+type record SCTP_Reconfig_Assoc_Reset{
+}
+
+type record SCTP_Reconfig_Stream_Add{
+  boolean  incoming,
+  integer  new_streams
+}
+
+
+type record SCTP_Connected_data {
+  integer  assoc_id,
+  integer  local_sctp_port,
+  integer  remote_sctp_port,
+  integer  listen_assoc_id  // assoc_id of the listen port
+                            // Use it to direct the new assoc-id to the right place
+}
+
+
+type record SCTP_Options_data {
+  integer    assoc_id,
+  SCTP_Engine_Option_list options     
+}
+
+
+type record SCTP_MSG_data {
+  integer    assoc_id,
+  integer    ppid,
+  integer    stream_id,
+  octetstring data,
+  SCTP_Engine_Option_list options optional     
+}
+
+
+type record SCTP_Engine_result{
+  integer    assoc_id
+}
+
+type enumerated SCTP_Engine_cause {
+    SCTP_ENG_WRONG_ASSOC_ID,       
+    SCTP_ENG_PORT_ALREADY_USED,
+    SCTP_ENG_WRONG_PORT,
+    SCTP_ENG_WRONG_PARAMETERS,
+    SCTP_ENG_INTERNAL_ERROR,
+    SCTP_ENG_WRONG_ASSOC_STATE,
+    SCTP_ENG_RECONFIG_ONGOING
+    
+    // More cause code will be added later
+  }
+
+type record SCTP_operation_execption{
+  SCTP_Engine_cause       cause,
+  charstring              cause_text
+}
+
+type record SCTP_Shutdown_data{
+  integer    assoc_id,
+  boolean    graceful_shutdown, // true - initiate gracefull shutdown, false - send abort
+  charstring reason optional    // if present sent as abort reason
+}
+
+type record SCTP_Listen_data {
+  integer                 local_sctp_port,
+  integer                 transport_id,
+  SCTP_Engine_Option_list options optional     
+}
+
+
+type record SCTP_Connect_data {
+  integer                 local_sctp_port,
+  integer                 remote_sctp_port,
+  integer                 transport_id,
+  SCTP_Engine_Option_list options optional     
+}
+
+
+
+// SCTP option definitions
+type record of SCTP_Engine_Option SCTP_Engine_Option_list;
+
+type union SCTP_Engine_Option {
+  boolean           i_data_supported,    // If true:
+                               //  Supplied for connection setup: negotiate iData support
+ 
+  boolean           unordered,  // Indicates that the MSG is unordered
+  
+  SCTP_Reconfig_config  reconfig_params, 
+  
+  boolean           forward_tsn_supported,  // indicates the support of RFC3758
+  
+  float             lifetime,  // The relative lifetime of the message as RFC3758
+  
+  integer           max_retransmit_counter // See RFC 7496
+  
+  // More will be added later
+}
+
+type record SCTP_Reconfig_config{
+  boolean is_supported,
+  boolean stream_reset_allowed,
+  boolean assoc_reset_allowed,
+  boolean stream_add_allowed
+}
+
+// Why procedure based?
+// Because the each operation is a request to execute some operation:
+// S_SCTP_Listen: means please start to
+// listen for an incoming association request
+// 
+// The result of the operation should be syncronized and paired with the 
+// request. The result should be available immediately without delay
+//
+// The procedure based port are represents a client-server connections
+// That is why we need 2 port
+//  SCTP_Engine_API_request_PT : The SCTP user call the operation of the 
+//                               SCTP engine component
+//  SCTP_Engine_API_indication_PT: The SCTP engine notifies the user via this
+//
+// Using only one test port can mix up the result of ongoing operation and 
+// the incoming indication calls
+
+// The SCTP API test port
+type port SCTP_Engine_API_request_PT procedure {
+  inout S_SCTP_Listen, S_SCTP_Connect, S_SCTP_Shutdown,S_SCTP_Shutdown_conf
+  inout S_SCTP_Send_req, S_SCTP_options, S_SCTP_reconfig
+} with {
+  extension "internal"
+}
+
+type port SCTP_Engine_API_indication_PT procedure {
+  inout S_SCTP_Shutdown_ind, S_SCTP_Connected_ind, S_SCTP_Received_ind
+  inout S_SCTP_Notification_ind
+} with {
+  extension "internal"
+}
+
+
+
+//******************************************************************************
+// Lower side port. Excahnges the encoded SCTP packets
+
+// Used to represent a SCTP packet in encoded form
+type record SCTP_Engine_packet {
+  integer        transport_id,  // The identifier used to identify the transport connection
+                                // The identifier is specified in a Listen/Connect operation
+                                // The associations using the same transport id are distinguished by the SCTP port numbers
+  octetstring    sctp_packet    // The SCTP packet 
+}
+
+type record SCTP_Addr_change_notification{
+  integer        transport_id  // The identifier used to identify the transport connection
+}
+
+// used only between components
+type port SCTP_Engine_packet_PT message {
+  inout SCTP_Engine_packet
+  inout SCTP_Addr_change_notification
+} with {
+  extension "internal"
+}
+
+
+
+
+}
diff --git a/src/SCTP_Engine_Templates.ttcn b/src/SCTP_Engine_Templates.ttcn
new file mode 100644
index 0000000..b746f5f
--- /dev/null
+++ b/src/SCTP_Engine_Templates.ttcn
@@ -0,0 +1,67 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 Ericsson Telecom AB
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v2.0
+// which accompanies this distribution, and is available at
+// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
+///////////////////////////////////////////////////////////////////////////////
+//
+//  File:               SCTP_Engine_Templates.ttcn
+//  Description:        Template definition of the SCTP Engine
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 840
+//
+module SCTP_Engine_Templates{
+  import from SCTP_Types all;
+  
+  const SCTP_Common_header c_empty_sctp_common_header:={
+    source_port := 0,
+    destination_port := 0,
+    verification_tag := 0,
+    checksum := '00000000'O
+  }
+
+  const SCTP_Packet       c_empty_sctp_packet:={
+    common_header := c_empty_sctp_common_header,
+    chunks :={}
+  }
+
+  const SCTP_abort_chunk  c_empty_abort_chunk := {
+    chunk_type := 6,
+    T_flag     := '0'B,
+    flags      := '0000000'B,
+    chunk_length := 0,
+    params     := omit
+  }
+  
+  const SCTP_ShutdownComplete_chunk c_empty_shutdown_complete_chunk := {
+    chunk_type := 14,
+    T_flag     := '0'B,
+    flags      := '0000000'B,
+    chunk_length := 0
+  }
+
+  const SCTP_Init_chunk c_empty_init_chunk :={
+    chunk_type := 1,
+    flags      := '00000000'B,
+    chunk_length := 0,
+    init_tag := 0,
+    a_rwnd := 0,
+    os := 0,
+    mis := 0,
+    init_tsn := 0,
+    params     := omit
+  }
+  
+  const SCTP_InitAck_chunk c_empty_init_ack_chunk :={
+    chunk_type := 2,
+    flags      := '00000000'B,
+    chunk_length := 0,
+    init_tag := 0,
+    a_rwnd := 0,
+    os := 0,
+    mis := 0,
+    init_tsn := 0,
+    params     := omit
+  }
+}