diff --git a/README.txt b/README.txt
index f9ca386a8e0cd86a6b868ddaa62ac756daa83509..90366177e19b37a2967a0ae74a2e4c7af61061ff 100644
--- a/README.txt
+++ b/README.txt
@@ -75,7 +75,7 @@ mkdir build
 cd build
 cmake ..
 make
-sudo ./udm-server
+sudo ./udm-server -i 172.16.1.103
 
 ## Build and launch AMF server
 cd /oai-cn5g-smf/src/test/amf
@@ -83,7 +83,7 @@ mkdir build
 cd build
 cmake ..
 make
-sudo ./amf-server 
+sudo ./amf-server -i 172.16.1.102
 
 ## Build and launch AMF client
 cd /oai-cn5g-smf/src/test/amf_client
@@ -91,6 +91,6 @@ mkdir build
 cd build
 cmake ..
 make
-./amf-client
+./amf-client -i 172.16.1.101
 
 
diff --git a/src/common/smf.h b/src/common/smf.h
index 9d18c9982984f0766120c868bbc75e4c31305070..87fcd98177c7e158758c3f659217fa2c11da2ba4 100644
--- a/src/common/smf.h
+++ b/src/common/smf.h
@@ -82,47 +82,6 @@ typedef struct s_nssai  // section 28.4, TS23.003
 
 typedef uint8_t pdu_session_id;
 
-//should move to 24.501
-enum pdu_session_type_e {
-  PDU_SESSION_TYPE_E_UNKNOWN = 0,
-  PDU_SESSION_TYPE_E_IPV4 = 1,
-  PDU_SESSION_TYPE_E_IPV6 = 2,
-  PDU_SESSION_TYPE_E_IPV4V6 = 3,
-  PDU_SESSION_TYPE_E_UNSTRUCTURED = 4,
-  PDU_SESSION_TYPE_E_ETHERNET = 5,
-  PDU_SESSION_TYPE_E_RESERVED = 7,
-};
-
-static const std::vector<std::string> pdu_session_type_e2str = { "Error",
-    "IPV4", "IPV6", "IPV4V6", "UNSTRUCTURED", "ETHERNET", "IPV4V6", "RESERVED" };
-
-typedef struct pdu_session_type_s {
-  uint8_t pdu_session_type;
-  pdu_session_type_s()
-      :
-      pdu_session_type(PDU_SESSION_TYPE_E_IPV4) {
-  }
-  pdu_session_type_s(const uint8_t &p)
-      :
-      pdu_session_type(p) {
-  }
-  pdu_session_type_s(const struct pdu_session_type_s &p)
-      :
-      pdu_session_type(p.pdu_session_type) {
-  }
-  bool operator==(const struct pdu_session_type_s &p) const {
-    return (p.pdu_session_type == pdu_session_type);
-  }
-  //------------------------------------------------------------------------------
-  bool operator==(const pdu_session_type_e &p) const {
-    return (p == pdu_session_type);
-  }
-  //------------------------------------------------------------------------------
-  const std::string& toString() const {
-    return pdu_session_type_e2str.at(pdu_session_type);
-  }
-} pdu_session_type_t;
-
 //SMF + AMF + 3GPP TS 29.571 (Common data)
 enum class http_response_codes_e {
   HTTP_RESPONSE_CODE_OK = 200,
diff --git a/src/gtpv1u/3gpp_29.281.cpp b/src/gtpv1u/3gpp_29.281.cpp
deleted file mode 100644
index 804ace9ff001c5e0dbf16a0498d18bccb4ba0623..0000000000000000000000000000000000000000
--- a/src/gtpv1u/3gpp_29.281.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-/*! \file 3gpp_29.281.cpp
-  \brief
-  \author Lionel Gauthier
-  \company Eurecom
-  \email: lionel.gauthier@eurecom.fr
-*/
-
-
-#include "3gpp_29.281.hpp"
-
-#include <string>
-#include <string.h>
-
-using namespace gtpv1u;
-//------------------------------------------------------------------------------
-gtpv1u_ie * gtpv1u_ie::new_gtpv1u_ie_from_stream(std::istream& is) {
-  gtpv1u_tlv    tlv;
-  tlv.load_from(is);
-  if (tlv.length) {
-    switch (tlv.type) {
-      case GTPU_IE_RECOVERY: {
-        gtpv1u_recovery_ie *ie = new gtpv1u_recovery_ie(tlv);
-        ie->load_from(is);
-        return ie;
-      }
-      break;
-      case GTPU_IE_TUNNEL_ENDPOINT_IDENTIFIER_DATA_I: {
-        gtpv1u_tunnel_endpoint_identifier_data_i_ie *ie = new gtpv1u_tunnel_endpoint_identifier_data_i_ie(tlv);
-        ie->load_from(is);
-        return ie;
-      }
-      break;
-      case GTPU_IE_GTP_U_PEER_ADDRESS: {
-        gtpv1u_gtp_u_peer_address_ie *ie = new gtpv1u_gtp_u_peer_address_ie(tlv);
-        ie->load_from(is);
-        return ie;
-      }
-      break;
-      case GTPU_IE_PRIVATE_EXTENSION: {
-        gtpv1u_private_extension_ie *ie = new gtpv1u_private_extension_ie(tlv);
-        ie->load_from(is);
-        return ie;
-      }
-      break;
-
-      default:
-        Logger::gtpv1_u().error("Unknown GTP IE type %d (length %d)", tlv.get_type(), tlv.get_length());
-        return nullptr;
-    }
-  } else {
-    Logger::gtpv1_u().error("GTP IE type %d length %d", tlv.get_type(), tlv.get_length());
-    return nullptr;
-  }
-}
-
-//------------------------------------------------------------------------------
-gtpv1u_msg::gtpv1u_msg(const gtpv1u_echo_request& gtp_ies) : gtpv1u_msg_header() {
-  ies = {};
-  set_message_type(GTPU_ECHO_REQUEST);
-  if (gtp_ies.private_extension.first) {std::shared_ptr<gtpv1u_private_extension_ie> sie(new gtpv1u_private_extension_ie(gtp_ies.private_extension.second)); add_ie(sie);}
-}
-//------------------------------------------------------------------------------
-gtpv1u_msg::gtpv1u_msg(const gtpv1u_echo_response& gtp_ies) : gtpv1u_msg_header() {
-  ies = {};
-  set_message_type(GTPU_ECHO_RESPONSE);
-  if (gtp_ies.recovery.first) {std::shared_ptr<gtpv1u_recovery_ie> sie(new gtpv1u_recovery_ie(gtp_ies.recovery.second)); add_ie(sie);}
-  if (gtp_ies.private_extension.first) {std::shared_ptr<gtpv1u_private_extension_ie> sie(new gtpv1u_private_extension_ie(gtp_ies.private_extension.second)); add_ie(sie);}
-}
-//------------------------------------------------------------------------------
-gtpv1u_msg::gtpv1u_msg(const gtpv1u_error_indication& gtp_ies) : gtpv1u_msg_header() {
-  ies = {};
-  set_message_type(GTPU_ERROR_INDICATION);
-  if (gtp_ies.tunnel_endpoint_identifier_data_i.first) {std::shared_ptr<gtpv1u_tunnel_endpoint_identifier_data_i_ie> sie(new gtpv1u_tunnel_endpoint_identifier_data_i_ie(gtp_ies.tunnel_endpoint_identifier_data_i.second)); add_ie(sie);}
-  if (gtp_ies.gtp_u_peer_address.first) {std::shared_ptr<gtpv1u_gtp_u_peer_address_ie> sie(new gtpv1u_gtp_u_peer_address_ie(gtp_ies.gtp_u_peer_address.second)); add_ie(sie);}
-  if (gtp_ies.private_extension.first) {std::shared_ptr<gtpv1u_private_extension_ie> sie(new gtpv1u_private_extension_ie(gtp_ies.private_extension.second)); add_ie(sie);}
-}
diff --git a/src/gtpv1u/3gpp_29.281.hpp b/src/gtpv1u/3gpp_29.281.hpp
deleted file mode 100644
index 564b7cbcf8651cc0037f71bb181c6bcc6b7e078e..0000000000000000000000000000000000000000
--- a/src/gtpv1u/3gpp_29.281.hpp
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-/*! \file 3gpp_29.281.hpp
-  \brief
-  \author Lionel Gauthier
-  \company Eurecom
-  \email: lionel.gauthier@eurecom.fr
-*/
-
-#ifndef FILE_3GPP_29_281_HPP_SEEN
-#define FILE_3GPP_29_281_HPP_SEEN
-
-#include <arpa/inet.h>
-#include <cstring>
-#include <exception>
-//#include <fmt/format.h> conflicts with spdlog
-#include <iostream>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <vector>
-#include <sys/socket.h>
-
-#include "3gpp_29.281.h"
-#include "msg_gtpv1u.hpp"
-#include "logger.hpp"
-#include "serializable.hpp"
-
-
-namespace gtpv1u {
-
-//------------------------------------------------------------------------------
-class gtpv1u_tlv : public stream_serializable {
-public:
-  static const uint16_t tlv_ie_length = 4;
-  uint8_t  type;
-  uint16_t length;
-
-  gtpv1u_tlv() :
-    type(0),
-    length(0) {}
-
-  gtpv1u_tlv(uint8_t t, uint16_t l = 0) :
-    type(t),
-    length(l) {}
-
-  //~gtpv1u_tlv() {};
-
-  void set_type(const uint8_t& t) {
-    type = t;
-  }
-
-  uint8_t get_type() {
-    return type;
-  }
-
-  void set_length(const uint16_t& l) {
-    length = l;
-  }
-
-  uint16_t get_length() {
-    return length ;
-  }
-
-  void dump_to(std::ostream& os)  {
-    os.write(reinterpret_cast<const char*>(&type), sizeof(type));
-    if (type & 0x80) {
-      auto be_length = htobe16(length);
-      os.write(reinterpret_cast<const char*>(&be_length), sizeof(be_length));
-    }
-  }
-  void load_from(std::istream& is) {
-    is.read(reinterpret_cast<char*>(&type), sizeof(type));
-    if (type & 0x80) {
-      is.read(reinterpret_cast<char*>(&length), sizeof(length));
-      length = be16toh(length);
-    } else {
-      length = 0;
-    }
-  }
-};
-
-//------------------------------------------------------------------------------
-class gtpv1u_ie : public stream_serializable {
-public:
-  gtpv1u_tlv    tlv;
-
-  gtpv1u_ie() :
-    tlv() {}
-
-  explicit gtpv1u_ie(const gtpv1u_tlv& t) :
-    tlv(t) {}
-
-  explicit gtpv1u_ie(const uint8_t tlv_type) :
-    tlv() {
-    tlv.type = tlv_type;
-  }
-
-  virtual ~gtpv1u_ie() {};
-
-  virtual void to_core_type(gtpv1u_ies_container& s) {throw gtpu_msg_illegal_ie_exception(s.msg_id, tlv.type);}
-
-  virtual void dump_to(std::ostream& os) {
-    tlv.dump_to(os);
-  };
-
-  virtual void load_from(std::istream& is) {throw gtpu_ie_unimplemented_exception(tlv.type); /* should not hapen of course*/};
-
-  static gtpv1u_ie * new_gtpv1u_ie_from_stream(std::istream& is);
-};
-//------------------------------------------------------------------------------
-class gtpv1u_msg_header : public stream_serializable {
-private:
-#define GTPV1U_MSG_HEADER_MIN_SIZE        8
-  //-----------------------
-  // Always present fields:
-  //-----------------------
-  union {
-    struct {
-      // N-PDU Number flag (PN): This flag indicates the presence of a meaningful value of the N-PDU Number field.
-      // When it is set to '0', the N-PDU Number field either is not present, or, if present, shall not be interpreted. When it
-      // is set to '1', the N-PDU Number field is present, and shall be interpreted
-      uint8_t                         pn:1;
-      // Sequence number flag (S): This flag indicates the presence of a meaningful value of the Sequence Number field.
-      // When it is set to '0', the Sequence Number field either is not present or, if present, shall not be interpreted. When
-      // it is set to '1', the Sequence Number field is present, and shall be interpreted.
-      // For the Echo Request, Echo Response, Error Indication and Supported Extension Headers Notification
-      // messages, the S flag shall be set to '1'. Since the use of Sequence Numbers is optional for G-PDUs, the PGW,
-      // SGW, ePDG, eNodeB and TWAN should set the flag to '0'. However, when a G-PDU (T-PDU+header) is being
-      // relayed by the Indirect Data Forwarding for Inter RAT HO procedure, then if the received G-PDU has the S flag
-      // set to '1', then the relaying entity shall set S flag to '1' and forward the G-PDU (T-PDU+header). In an End
-      // marker message the S flag shall be set to '0'.
-      uint8_t                         s:1;
-      // Extension Header flag (E): This flag indicates the presence of a meaningful value of the Next Extension Header
-      // field. When it is set to '0', the Next Extension Header field either is not present or, if present, shall not be
-      // interpreted. When it is set to '1', the Next Extension Header field is present, and shall be interpreted
-      uint8_t                         e:1;
-      uint8_t                         spare:1;
-      // Protocol Type (PT): This bit is used as a protocol discriminator between GTP (when PT is '1') and GTP' (when PT is '0')
-      uint8_t                         pt:1;
-      // Version field: This field is used to determine the version of the GTP-U protocol. The version number shall be set to '1'.
-      uint8_t                         version:3;
-    } bf;
-    uint8_t b;
-  } u1;
-  // Message Type: This field indicates the type of GTP-U message.
-  uint8_t                         message_type;
-  // Length: This field indicates the length in octets of the payload, i.e. the rest of the packet following the mandatory
-  // part of the GTP header (that is the first 8 octets). The Sequence Number, the N-PDU Number or any Extension
-  // headers shall be considered to be part of the payload, i.e. included in the length count.
-  uint16_t                        message_length;
-  // Tunnel Endpoint Identifier (TEID): This field unambiguously identifies a tunnel endpoint in the receiving
-  // GTP-U protocol entity. The receiving end side of a GTP tunnel locally assigns the TEID value the transmitting
-  // side has to use. The TEID value shall be assigned in a non-predictable manner for PGW S5/S8/S2a/S2b
-  // interfaces (see 3GPP TS 33.250 [32]). The TEID shall be used by the receiving entity to find the PDP context,
-  // except for the following cases:
-  // -) The Echo Request/Response and Supported Extension Headers notification messages, where the Tunnel
-  //    Endpoint Identifier shall be set to all zeroes
-  // -) The Error Indication message where the Tunnel Endpoint Identifier shall be set to all zeros.
-  uint32_t                        teid;
-  //------------------
-  // Optional fields:
-  //------------------
-  // Sequence Number: If Sequence Number field is used for G-PDUs (T-PDUs+headers), an increasing sequence
-  // number for T-PDUs is transmitted via GTP-U tunnels, when transmission order must be preserved. For
-  // Supported Extension Headers Notification and Error Indication messages, the Sequence Number shall be ignored
-  // by the receiver, even though the S flag is set to '1'.
-  uint16_t                        sequence_number;
-  // N-PDU Number: This field is used at the Inter SGSN Routeing Area Update procedure and some inter-system
-  // handover procedures (e.g. between 2G and 3G radio access networks). This field is used to co-ordinate the data
-  // transmission for acknowledged mode of communication between the MS and the SGSN. The exact meaning of
-  // this field depends upon the scenario. (For example, for GSM/GPRS to GSM/GPRS, the SNDCP N-PDU number
-  // is present in this field).
-  uint8_t                         npdu_number;
-  // Next Extension Header Type: This field defines the type of Extension Header that follows this field in the
-  // GTP-PDU.
-  uint8_t                         next_extension_header_type;
-
-  bool has_teid_;
-public:
-
-  gtpv1u_msg_header() {
-    u1.b = 0;
-    message_type = 0;
-    message_length = 0; //
-    teid = 0;
-    sequence_number = 0;
-    npdu_number = 0;
-    next_extension_header_type = 0;
-    u1.bf.version = 1;
-    u1.bf.pt = 1;
-  }
-
-  gtpv1u_msg_header(const gtpv1u_msg_header& h) {
-    u1.b = h.u1.b;
-    message_type = h.message_type;
-    message_length = h.message_length;
-    teid = h.teid;
-    sequence_number = h.sequence_number;
-    npdu_number = h.npdu_number;
-    next_extension_header_type = h.next_extension_header_type;
-    has_teid_ = h.has_teid_;
-  }
-
-  gtpv1u_msg_header& operator=(gtpv1u_msg_header other)
-  {
-    std::swap(u1, other.u1);
-    std::swap(message_type, other.message_type);
-    std::swap(message_length, other.message_length);
-    std::swap(teid, other.teid);
-    std::swap(sequence_number, other.sequence_number);
-    std::swap(npdu_number, other.npdu_number);
-    std::swap(next_extension_header_type, other.next_extension_header_type);
-    return *this;
-  }
-
-  void set_teid(const uint32_t& tid) {
-    teid = tid;
-  }
-
-  uint32_t get_teid() const {
-    return teid;
-  }
-
-  bool get_sequence_number(uint16_t& vsequence_number) const {
-    if (u1.bf.s) { // if inter rat then check in more details
-      vsequence_number = sequence_number;
-      return true;
-    }
-    // if (...) {
-    //   vsequence_number = 0;
-    //  return true;
-    // }
-    return false;
-  }
-
-  void set_message_type(const uint8_t& t) {
-    message_type = t;
-  }
-
-  uint8_t get_message_type() const {
-    return message_type;
-  }
-
-  void set_message_length(const uint16_t& l) {
-    message_length = l;
-  }
-
-  uint16_t get_message_length() const {
-    return message_length;
-  }
-
-  // get payload length without extra header length
-  uint16_t get_message_length_wo_xheader() const {
-    uint16_t ml = message_length;
-    if (u1.bf.s) {
-      ml -= sizeof(sequence_number);
-    }
-    return ml;
-  }
-
-  void set_sequence_number(const uint16_t& s) {
-    message_length += sizeof(sequence_number);
-    sequence_number = s;
-    u1.bf.s = 1;
-  }
-
-  uint16_t get_sequence_number() const {
-    return sequence_number;
-  }
-
-
-  virtual void dump_to(std::ostream& os) {
-    u1.bf.spare = 0;
-    os.write(reinterpret_cast<const char*>(&u1.b), sizeof(u1.b));
-    os.write(reinterpret_cast<const char*>(&message_type), sizeof(message_type));
-    auto be_message_length = htobe16(message_length);
-    os.write(reinterpret_cast<const char*>(&be_message_length), sizeof(be_message_length));
-    auto be_teid = htobe32(teid);
-    os.write(reinterpret_cast<const char*>(&be_teid), sizeof(be_teid));
-
-    if (u1.bf.s) {
-      auto be_sequence_number = htobe16(sequence_number);
-      os.write(reinterpret_cast<const char*>(&be_sequence_number), sizeof(be_sequence_number));
-    }
-    if (u1.b & 0x05) {
-      os.write(reinterpret_cast<const char*>(&npdu_number), sizeof(npdu_number));
-      os.write(reinterpret_cast<const char*>(&next_extension_header_type), sizeof(next_extension_header_type));
-    }
-  }
-  virtual void load_from(std::istream& is) {
-    // ! Control Plane GTP header length shall be a multiple of 4 octets.
-    is.read(reinterpret_cast<char*>(&u1.b), sizeof(u1.b));
-    is.read(reinterpret_cast<char*>(&message_type), sizeof(message_type));
-    is.read(reinterpret_cast<char*>(&message_length), sizeof(message_length));
-    message_length = be16toh(message_length);
-    is.read(reinterpret_cast<char*>(&teid), sizeof(teid));
-    teid = be32toh(teid);
-//     if (message_length >= sizeof(teid)){
-//       switch (message_type) {
-//         case GTPU_ECHO_REQUEST:
-//         case GTPU_ECHO_RESPONSE:
-//         case GTPU_ERROR_INDICATION:
-//         case GTPU_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION:
-//           break;
-//         default:;
-//       }
-//     }
-    if (u1.bf.s) {
-      is.read(reinterpret_cast<char*>(&sequence_number), sizeof(sequence_number));
-      sequence_number = be16toh(sequence_number);
-    }
-
-    if (u1.b & 0x05) {
-      is.read(reinterpret_cast<char*>(&npdu_number), sizeof(npdu_number));
-      is.read(reinterpret_cast<char*>(&next_extension_header_type), sizeof(next_extension_header_type));
-    }
-  }
-};
-//------------------------------------------------------------------------------
-class gtpv1u_msg : public gtpv1u_msg_header
-{
-public:
-  struct sockaddr_storage r_endpoint;
-  socklen_t               r_endpoint_addr_len;
-
-  std::vector<std::shared_ptr<gtpv1u_ie>>         ies;
-
-  gtpv1u_msg() : gtpv1u_msg_header(), r_endpoint(), r_endpoint_addr_len(0), ies() {}
-
-  gtpv1u_msg(const gtpv1u_msg& m) : gtpv1u_msg_header(m),
-    r_endpoint(m.r_endpoint),
-    r_endpoint_addr_len(m.r_endpoint_addr_len),
-    ies(m.ies) {}
-
-  gtpv1u_msg& operator=(gtpv1u_msg other)
-  {
-    std::swap(r_endpoint, other.r_endpoint);
-    std::swap(r_endpoint_addr_len, other.r_endpoint_addr_len);
-    std::swap(ies, other.ies);
-    return *this;
-  }
-
-  explicit gtpv1u_msg(const gtpv1u_msg_header& hdr) : gtpv1u_msg_header(hdr), r_endpoint(), r_endpoint_addr_len(0), ies() {}
-  explicit gtpv1u_msg(const gtpv1u_echo_request& gtp_ies);
-  explicit gtpv1u_msg(const gtpv1u_echo_response& gtp_ies);
-  explicit gtpv1u_msg(const gtpv1u_error_indication& gtp_ies);
-  explicit gtpv1u_msg(const gtpv1u_supported_extension_headers_notification& gtp_ies);
-  explicit gtpv1u_msg(const gtpv1u_end_marker& gtp_ies);
-
-  ~gtpv1u_msg() {
-    ies.clear();
-  }
-
-  void add_ie(std::shared_ptr<gtpv1u_ie> ie) {
-    ies.push_back(ie);
-    //std::cout << std::dec<< " add_ie   = " << get_message_length() << " -> "<< get_message_length() + gtpv1u_tlv::tlv_ie_length + ie.get()->tlv.get_length() << std::endl;
-    set_message_length(get_message_length() + gtpv1u_tlv::tlv_ie_length + ie.get()->tlv.get_length());
-  }
-
-  void to_core_type(gtpv1u_echo_request& s) {
-    for (auto i : ies) {
-      i.get()->to_core_type(s);
-    }
-  }
-  void to_core_type(gtpv1u_echo_response& s) {
-    for (auto i : ies) {
-      i.get()->to_core_type(s);
-    }
-  }
-  void to_core_type(gtpv1u_error_indication& s) {
-    for (auto i : ies) {
-      i.get()->to_core_type(s);
-    }
-  }
-  void to_core_type(gtpv1u_supported_extension_headers_notification& s) {
-    for (auto i : ies) {
-      i.get()->to_core_type(s);
-    }
-  }
-  void to_core_type(gtpv1u_end_marker& s) {
-    for (auto i : ies) {
-      i.get()->to_core_type(s);
-    }
-  }
-
-  void dump_to(std::ostream& os)  {
-    gtpv1u_msg_header::dump_to(os);
-    for (auto i : ies) {
-      i.get()->dump_to(os);
-    }
-  }
-  void load_from(std::istream& is) {
-    gtpv1u_msg_header::load_from(is);
-
-    uint16_t check_msg_length = get_message_length_wo_xheader(); // total length of message - fixed part of the gtpu header (GTPV1U_MSG_HEADER_MIN_SIZE)
-    gtpv1u_ie * ie = nullptr;
-    uint16_t ies_length = 0;
-    //std::cout << std::dec<< " check_msg_length  = " << check_msg_length << std::endl;
-    do {
-      ie = gtpv1u_ie::new_gtpv1u_ie_from_stream(is);
-      if (ie) {
-        ies_length += (gtpv1u_tlv::tlv_ie_length + ie->tlv.get_length());
-        ies.push_back(std::shared_ptr<gtpv1u_ie>(ie));
-        //std::cout << std::dec << " ies length  = " << ies_length << " IE length = " << ie->tlv.get_length() << std::endl;
-      }
-    } while((ie) && (ies_length < check_msg_length));
-
-    if (ies_length > check_msg_length) { // should be <= (padding)
-      //std::cout << " check_msg_length  = " << check_msg_length << " ies_length  = " << ies_length << std::endl;
-      throw gtpu_msg_bad_length_exception(get_message_type(), get_message_length());
-    }
-  }
-};
-
-
-inline void ipv6_address_dump_to(std::ostream& os, const struct in6_addr& ipv6_address) {
-  os.write(reinterpret_cast<const char*>(ipv6_address.s6_addr), 16);
-}
-
-inline void ipv6_address_load_from(std::istream& is, struct in6_addr& ipv6_address) {
-  is.read(reinterpret_cast<char*>(ipv6_address.s6_addr), 16);
-}
-
-inline void ipv4_address_dump_to(std::ostream& os, const struct in_addr& ipv4_address) {
-  os.write(reinterpret_cast<const char*>(&ipv4_address.s_addr), sizeof(ipv4_address.s_addr));
-}
-
-inline void ipv4_address_load_from(std::istream& is, struct in_addr& ipv4_address) {
-  is.read(reinterpret_cast<char*>(&ipv4_address.s_addr), sizeof(ipv4_address.s_addr));
-}
-
-//------------------------------------------------------------------------------
-class gtpv1u_recovery_ie : public gtpv1u_ie {
-public:
-  uint8_t restart_counter;
-
-  //--------
-  explicit gtpv1u_recovery_ie(const recovery_t& i) : gtpv1u_ie(GTPU_IE_RECOVERY) {
-    // avoid using b[]
-    restart_counter = i.restart_counter;
-    tlv.set_length(1);
-  };
-  //--------
-  explicit gtpv1u_recovery_ie() : gtpv1u_ie(GTPU_IE_RECOVERY) {
-    restart_counter = 0;
-    tlv.set_length(1);
-  };
-  //--------
-  explicit gtpv1u_recovery_ie(const gtpv1u_tlv& t) : gtpv1u_ie(t) {
-    restart_counter = 0;
-  };
-  //--------
-  void to_core_type(recovery_t& i) {
-    i.restart_counter = restart_counter;
-  };
-
-  //--------
-  void dump_to(std::ostream& os) {
-    tlv.dump_to(os);
-    os.write(reinterpret_cast<const char*>(&restart_counter), sizeof(restart_counter));
-  }
-  //--------
-  void load_from(std::istream& is) {
-    //tlv.load_from(is);
-    is.read(reinterpret_cast<char*>(&restart_counter), sizeof(restart_counter));
-  }
-
-  void to_core_type(gtpv1u_ies_container& s) {
-      recovery_t v = {};
-      to_core_type(v);
-      s.set(v);
-  }
-};
-//------------------------------------------------------------------------------
-class gtpv1u_tunnel_endpoint_identifier_data_i_ie : public gtpv1u_ie {
-public:
-
-  uint32_t  tunnel_endpoint_identifier_data_i;
-
-
-  //--------
-  explicit gtpv1u_tunnel_endpoint_identifier_data_i_ie(const tunnel_endpoint_identifier_data_i_t& i) : gtpv1u_ie(GTPU_IE_TUNNEL_ENDPOINT_IDENTIFIER_DATA_I) {
-    tunnel_endpoint_identifier_data_i = i.tunnel_endpoint_identifier_data_i;
-  }
-  //--------
-  gtpv1u_tunnel_endpoint_identifier_data_i_ie() : gtpv1u_ie(GTPU_IE_TUNNEL_ENDPOINT_IDENTIFIER_DATA_I) {
-    tunnel_endpoint_identifier_data_i = 0;
-  };
-  //--------
-  explicit gtpv1u_tunnel_endpoint_identifier_data_i_ie(const gtpv1u_tlv& t) : gtpv1u_ie(t) {
-    tunnel_endpoint_identifier_data_i = 0;
-  };
-  void to_core_type(tunnel_endpoint_identifier_data_i_t& c) {
-    c.tunnel_endpoint_identifier_data_i = tunnel_endpoint_identifier_data_i;
-  }
-  //--------
-  void dump_to(std::ostream& os) {
-    tlv.dump_to(os);
-    auto be_tunnel_endpoint_identifier_data_i = htobe32(tunnel_endpoint_identifier_data_i);
-    os.write(reinterpret_cast<const char*>(&be_tunnel_endpoint_identifier_data_i), sizeof(be_tunnel_endpoint_identifier_data_i));
-  }
-  //--------
-  void load_from(std::istream& is) {
-    //tlv.load_from(is);
-    is.read(reinterpret_cast<char*>(&tunnel_endpoint_identifier_data_i), sizeof(tunnel_endpoint_identifier_data_i));
-    tunnel_endpoint_identifier_data_i = be32toh(tunnel_endpoint_identifier_data_i);
-  }
-
-  void to_core_type(gtpv1u_ies_container& s) {
-      tunnel_endpoint_identifier_data_i_t v = {};
-      to_core_type(v);
-      s.set(v);
-  }
-};
-
-//------------------------------------------------------------------------------
-class gtpv1u_gtp_u_peer_address_ie : public gtpv1u_ie {
-public:
-  bool is_v4;
-  struct in6_addr ipv6_address;
-  struct in_addr  ipv4_address;
-  //--------
-  explicit gtpv1u_gtp_u_peer_address_ie(const gtp_u_peer_address_t& p) :
-gtpv1u_ie(GTPU_IE_GTP_U_PEER_ADDRESS){
-    is_v4 = p.is_v4;
-    if (is_v4) {
-      ipv4_address = p.ipv4_address;
-      tlv.set_length(4);
-    } else {
-      ipv6_address = p.ipv6_address;
-      tlv.set_length(16);
-    }
-  }
-  //--------
-  gtpv1u_gtp_u_peer_address_ie() : gtpv1u_ie(GTPU_IE_GTP_U_PEER_ADDRESS){
-    is_v4 = true;
-    ipv4_address.s_addr = INADDR_ANY;
-    ipv6_address = in6addr_any;
-    tlv.set_length(4);
-  }
-  //--------
-  explicit gtpv1u_gtp_u_peer_address_ie(const gtpv1u_tlv& t) : gtpv1u_ie(t) {
-    is_v4 = true;
-    ipv4_address.s_addr = INADDR_ANY;
-    ipv6_address = in6addr_any;
-  };
-  //--------
-  void to_core_type(gtp_u_peer_address_t& p) {
-    if (is_v4) {
-      p.ipv4_address = ipv4_address;
-    } else {
-      p.ipv6_address = ipv6_address;
-    }
-  }
-  //--------
-  void dump_to(std::ostream& os) {
-    if (is_v4) {
-      tlv.set_length(4);
-    } else {
-      tlv.set_length(16);
-    }
-    tlv.dump_to(os);
-    if (is_v4) {
-      ipv4_address_dump_to(os, ipv4_address);
-    } else {
-      ipv6_address_dump_to(os, ipv6_address);
-    }
-  }
-  //--------
-  void load_from(std::istream& is) {
-    //tlv.load_from(is);
-    if (tlv.get_length() == 4) {
-      ipv4_address_load_from(is, ipv4_address);
-    } else if (tlv.get_length() == 16) {
-      ipv6_address_load_from(is, ipv6_address);
-    } else {
-      throw gtpu_tlv_bad_length_exception(GTPU_IE_GTP_U_PEER_ADDRESS, tlv.length);
-    }
-  }
-  //--------
-  void to_core_type(gtpv1u_ies_container& s) {
-      gtp_u_peer_address_t v = {};
-      to_core_type(v);
-      s.set(v);
-  }
-};
-//------------------------------------------------------------------------------
-class gtpv1u_private_extension_ie : public gtpv1u_ie {
-public:
-
-  uint16_t     extension_identifier;
-  std::string  extension_value;
-
-  //--------
-  explicit gtpv1u_private_extension_ie(const private_extension_t& i) : gtpv1u_ie(GTPU_IE_PRIVATE_EXTENSION),
-    extension_identifier(i.enterprise_id),
-    extension_value(i.proprietary_value)
-  {
-    tlv.set_length(sizeof(extension_identifier) + extension_value.size());
-  }
-  //--------
-  gtpv1u_private_extension_ie() : gtpv1u_ie(GTPU_IE_PRIVATE_EXTENSION),
-    extension_identifier(0),
-    extension_value()
-  {
-    tlv.set_length(sizeof(extension_identifier));
-  };
-  //--------
-  explicit gtpv1u_private_extension_ie(const gtpv1u_tlv& t) : gtpv1u_ie(t),
-    extension_identifier(0),
-    extension_value() {}
-
-  void to_core_type(private_extension_t& c) {
-    c.enterprise_id = extension_identifier;
-    c.proprietary_value = extension_value;
-  }
-  //--------
-  void dump_to(std::ostream& os) {
-    tlv.set_length(sizeof(extension_identifier) + extension_value.size());
-    tlv.dump_to(os);
-    auto be_extension_identifier = htobe16(extension_identifier);
-    os.write(reinterpret_cast<const char*>(&be_extension_identifier), sizeof(be_extension_identifier));
-    os << extension_value;
-  }
-  //--------
-  void load_from(std::istream& is) {
-    //tlv.load_from(is);
-    is.read(reinterpret_cast<char*>(&extension_identifier), sizeof(extension_identifier));
-    extension_identifier = be16toh(extension_identifier);
-
-    uint16_t length = tlv.get_length();
-    if (length > 2) {
-      char apn[length - 2];
-      is.read(apn, length - 2);
-      extension_value.assign(apn, length - 2);
-    } else {
-      extension_value = {};
-    }
-  }
-
-  void to_core_type(gtpv1u_ies_container& s) {
-      private_extension_t v = {};
-      to_core_type(v);
-      s.set(v);
-  }
-};
-
-
-} // namespace gtpv1u
-
-#endif /* FILE_3GPP_29_281_HPP_SEEN */
diff --git a/src/gtpv1u/CMakeLists.txt b/src/gtpv1u/CMakeLists.txt
deleted file mode 100644
index 5b42bf9c872c6e650e0a79fe0d5e866ba457679d..0000000000000000000000000000000000000000
--- a/src/gtpv1u/CMakeLists.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-################################################################################
-# Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The OpenAirInterface Software Alliance licenses this file to You under
-# the OAI Public License, Version 1.1  (the "License"); you may not use this file
-# except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.openairinterface.org/?page_id=698
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#-------------------------------------------------------------------------------
-# For more information about the OpenAirInterface (OAI) Software Alliance:
-#      contact@openairinterface.org
-################################################################################
-add_library(GTPV1U STATIC
-    3gpp_29.281.cpp
-    gtpv1u.cpp
-    )
-
-include_directories(${SRC_TOP_DIR}/common)
-include_directories(${SRC_TOP_DIR}/common/msg)
-include_directories(${SRC_TOP_DIR}/common/utils)
-include_directories(${SRC_TOP_DIR}/itti)
-include_directories(${SRC_TOP_DIR}/gtpv1u)
-include_directories(${SRC_TOP_DIR}/udp)
-include_directories(${SRC_TOP_DIR}/../build/ext/spdlog/include)
diff --git a/src/gtpv1u/gtpu.h b/src/gtpv1u/gtpu.h
deleted file mode 100644
index c0b44fa147a0641cd25928286a94859ae225d68f..0000000000000000000000000000000000000000
--- a/src/gtpv1u/gtpu.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-/*! \file gtpu.h
-* \brief
-* \author Lionel Gauthier
-* \company Eurecom
-* \email: lionel.gauthier@eurecom.fr
-*/
-
-#ifndef FILE_GTPU_SEEN
-#define FILE_GTPU_SEEN
-
-#include <endian.h>
-#include <stdint.h>
-
-struct gtpuhdr
-  {
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-  unsigned int pn:1;
-  unsigned int s:1;
-  unsigned int e:1;
-  unsigned int spare:1;
-  unsigned int pt:1;
-    unsigned int version:3;
-#elif __BYTE_ORDER == __BIG_ENDIAN
-    unsigned int version:3;
-    unsigned int pt:1;
-    unsigned int spare:1;
-    unsigned int e:1;
-    unsigned int s:1;
-    unsigned int pn:1;
-#else
-# error "Please fix <bits/endian.h>"
-#endif
-    // Message Type: This field indicates the type of GTP-U message.
-    uint8_t                         message_type;
-    // Length: This field indicates the length in octets of the payload, i.e. the rest of the packet following the mandatory
-    // part of the GTP header (that is the first 8 octets). The Sequence Number, the N-PDU Number or any Extension
-    // headers shall be considered to be part of the payload, i.e. included in the length count.
-    uint16_t                        message_length;
-    // Tunnel Endpoint Identifier (TEID): This field unambiguously identifies a tunnel endpoint in the receiving
-    // GTP-U protocol entity. The receiving end side of a GTP tunnel locally assigns the TEID value the transmitting
-    // side has to use. The TEID value shall be assigned in a non-predictable manner for PGW S5/S8/S2a/S2b
-    // interfaces (see 3GPP TS 33.250 [32]). The TEID shall be used by the receiving entity to find the PDP context,
-    // except for the following cases:
-    // -) The Echo Request/Response and Supported Extension Headers notification messages, where the Tunnel
-    //    Endpoint Identifier shall be set to all zeroes
-    // -) The Error Indication message where the Tunnel Endpoint Identifier shall be set to all zeros.
-    uint32_t                        teid;
-
-
-    /*The options start here. */
-  };
-#endif
diff --git a/src/gtpv1u/gtpv1u.cpp b/src/gtpv1u/gtpv1u.cpp
deleted file mode 100644
index 474dd172ac97b163a9c6fe595d0241880d59487f..0000000000000000000000000000000000000000
--- a/src/gtpv1u/gtpv1u.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-/*! \file gtpv1u.cpp
-  \brief
-  \author Lionel Gauthier
-  \company Eurecom
-  \email: lionel.gauthier@eurecom.fr
-*/
-
-#include "common_root_types.h"
-#include "conversions.hpp"
-#include "gtpu.h"
-#include "gtpv1u.hpp"
-
-#include <cstdlib>
-#include <sched.h>
-
-using namespace gtpv1u;
-using namespace std;
-
-extern itti_mw *itti_inst;
-
-
-
-////------------------------------------------------------------------------------
-//void udp_server::handle_receive(const int& error, std::size_t bytes_transferred)
-//{
-//  if (!error) {
-//    Logger::udp().trace( "udp_server::handle_receive on %s:%d from %s:%d",
-//        socket_.local_endpoint().address().to_string().c_str(), socket_.local_endpoint().port(),
-//        remote_endpoint_.address().to_string().c_str(), remote_endpoint_.port());
-//    if (app_) {
-//      app_->handle_receive(recv_buffer_.data(), bytes_transferred, remote_endpoint_);
-//    } else {
-//      Logger::udp().error( "No upper layer configured for handling UDP packet");
-//    }
-//    start_receive(app_);
-//  } else {
-//    Logger::udp().error( "udp_server::handle_receive err=%s/%d: %s", error.category().name(), error.value(), error.message());
-//  }
-//}
-
-//------------------------------------------------------------------------------
-gtpu_l4_stack::gtpu_l4_stack(const struct in_addr& address, const uint16_t port_num, const util::thread_sched_params& sched_params) :
-    udp_s(udp_server(address, port_num))
-{
-  Logger::gtpv1_u().info( "gtpu_l4_stack created listening to %s:%d", conv::toString(address).c_str(), port_num);
-
-  id = 0;
-  srand (time(NULL));
-  seq_num = rand() & 0x7FFFFFFF;
-  restart_counter = 0;
-  udp_s.start_receive(this, sched_params);
-}
-//------------------------------------------------------------------------------
-gtpu_l4_stack::gtpu_l4_stack(const struct in6_addr& address, const uint16_t port_num, const util::thread_sched_params& sched_params) :
-    udp_s(udp_server(address, port_num))
-{
-  Logger::gtpv1_u().info( "gtpu_l4_stack created listening to %s:%d", conv::toString(address).c_str(), port_num);
-
-  id = 0;
-  srand (time(NULL));
-  seq_num = rand() & 0x7FFFFFFF;
-  restart_counter = 0;
-  udp_s.start_receive(this, sched_params);
-}
-//------------------------------------------------------------------------------
-gtpu_l4_stack::gtpu_l4_stack(char * address, const uint16_t port_num, const util::thread_sched_params& sched_params) :
-        udp_s(udp_server(address, port_num))
-{
-  Logger::gtpv1_u().info( "gtpu_l4_stack created listening to %s:%d", address, port_num);
-
-  id = 0;
-  srand (time(NULL));
-  seq_num = rand() & 0x7FFFFFFF;
-  restart_counter = 0;
-  udp_s.start_receive(this, sched_params);
-
-}
-
-//------------------------------------------------------------------------------
-uint32_t gtpu_l4_stack::get_next_seq_num() {
-  seq_num++;
-  if (seq_num & 0x80000000) {
-    seq_num = 0;
-  }
-  return seq_num;
-}
-//------------------------------------------------------------------------------
-void gtpu_l4_stack::handle_receive(char* recv_buffer, const std::size_t bytes_transferred,  const endpoint& r_endpoint)
-{
-  Logger::gtpv1_u().error( "TODO implement in derived class");
-}
-//------------------------------------------------------------------------------
-bool gtpu_l4_stack::check_initial_message_type(const uint8_t initial)
-{
-  switch (initial) {
-    case GTPU_ECHO_REQUEST:
-    case GTPU_END_MARKER:
-      return true;
-      break;
-    default:
-      return false;
-  }
-}
-//------------------------------------------------------------------------------
-bool gtpu_l4_stack::check_triggered_message_type(const uint8_t initial, const uint8_t triggered)
-{
-  Logger::gtpv1_u().info( "check_triggered_message_type GTPV1-U msg type %d/%d", (int)initial, (int)triggered);
-  switch (initial) {
-    case GTPU_ECHO_REQUEST:
-      if (triggered == GTPU_ECHO_RESPONSE) return true;
-      return false;
-      break;
-    case GTPU_ERROR_INDICATION:
-    case GTPU_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION:
-       return true;
-      break;
-    default:
-      return false;
-  }
-}
-//------------------------------------------------------------------------------
-void gtpu_l4_stack::handle_receive_message_cb(const gtpv1u_msg& msg, const struct sockaddr_storage& r_endpoint, const socklen_t& r_endpoint_addr_len, const task_id_t& task_id, bool &error, uint64_t& gtpc_tx_id)
-{
-}
-
-//------------------------------------------------------------------------------
-void gtpu_l4_stack::send_g_pdu(const struct sockaddr_in& peer_addr, const teid_t teid, const char* payload, const ssize_t payload_len)
-{
-  struct gtpuhdr *gtpuhdr = reinterpret_cast<struct gtpuhdr *>(reinterpret_cast<uintptr_t>(payload) - (uintptr_t)sizeof(struct gtpuhdr));
-  gtpuhdr->spare = 0;
-  gtpuhdr->e = 0;
-  gtpuhdr->s = 0;
-  gtpuhdr->pn = 0;
-  gtpuhdr->pt = 1;
-  gtpuhdr->version = 1;
-  gtpuhdr->message_type = GTPU_G_PDU;
-  gtpuhdr->message_length = htobe16(payload_len);
-  gtpuhdr->teid = htobe32(teid);
-  udp_s.async_send_to(reinterpret_cast<const char*>(gtpuhdr), payload_len + sizeof(struct gtpuhdr), peer_addr);
-}
-//------------------------------------------------------------------------------
-void gtpu_l4_stack::send_g_pdu(const struct sockaddr_in6& peer_addr, const teid_t teid, const char* payload, const ssize_t payload_len)
-{
-  struct gtpuhdr *gtpuhdr = reinterpret_cast<struct gtpuhdr *>(reinterpret_cast<uintptr_t>(payload) - (uintptr_t)sizeof(struct gtpuhdr));
-  gtpuhdr->spare = 0;
-  gtpuhdr->e = 0;
-  gtpuhdr->s = 0;
-  gtpuhdr->pn = 0;
-  gtpuhdr->pt = 1;
-  gtpuhdr->version = 1;
-  gtpuhdr->message_type = GTPU_G_PDU;
-  gtpuhdr->message_length = htobe16(payload_len);
-  gtpuhdr->teid = htobe32(teid);
-  udp_s.async_send_to(reinterpret_cast<const char*>(gtpuhdr), payload_len + sizeof(struct gtpuhdr), peer_addr);
-}
-//------------------------------------------------------------------------------
-void gtpu_l4_stack::send_response(const gtpv1u_echo_response& gtp_ies)
-{
-  std::ostringstream oss(std::ostringstream::binary);
-  gtpv1u_msg msg(gtp_ies);
-  uint32_t teid = UNASSIGNED_TEID;
-  if (gtp_ies.get_teid(teid)) {
-    msg.set_teid(teid);
-  }
-  uint16_t sn = 0;
-  if (gtp_ies.get_sequence_number(sn)) {
-    msg.set_sequence_number(sn);
-  }
-  msg.dump_to(oss);
-  std::string bstream = oss.str();
-
-  udp_s.async_send_to(reinterpret_cast<const char*>(bstream.c_str()), bstream.length(), gtp_ies.r_endpoint);
-}
-//------------------------------------------------------------------------------
-void gtpu_l4_stack::send_indication(const gtpv1u_error_indication& gtp_ies)
-{
-  std::ostringstream oss(std::ostringstream::binary);
-  gtpv1u_msg msg(gtp_ies);
-  uint32_t teid = UNASSIGNED_TEID;
-  if (gtp_ies.get_teid(teid)) {
-    msg.set_teid(teid);
-  }
-  uint16_t sn = 0;
-  if (gtp_ies.get_sequence_number(sn)) {
-    msg.set_sequence_number(sn);
-  }
-  msg.dump_to(oss);
-  std::string bstream = oss.str();
-  
-  udp_s.async_send_to(reinterpret_cast<const char*>(bstream.c_str()), bstream.length(), gtp_ies.r_endpoint);
-}
diff --git a/src/gtpv1u/gtpv1u.hpp b/src/gtpv1u/gtpv1u.hpp
deleted file mode 100644
index deda525cf94943efa70360f6df74d4c6c1e48c5b..0000000000000000000000000000000000000000
--- a/src/gtpv1u/gtpv1u.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-/*! \file gtpv1u.hpp
-  \brief
-  \author Lionel Gauthier
-  \company Eurecom
-  \email: lionel.gauthier@eurecom.fr
-*/
-#ifndef FILE_GTPV1U_HPP_SEEN
-#define FILE_GTPV1U_HPP_SEEN
-
-#include "3gpp_29.281.hpp"
-#include "itti.hpp"
-#include "msg_gtpv1u.hpp"
-#include "thread_sched.hpp"
-#include "udp.hpp"
-
-#include <iostream>
-#include <map>
-#include <memory>
-#include <stdint.h>
-#include <string>
-#include <system_error>
-#include <thread>
-#include <utility>
-#include <vector>
-
-namespace gtpv1u {
-
-static const uint16_t default_port = 2152;
-  
-
-class gtpu_l4_stack : public udp_application {
-#define GTPV1U_T3_RESPONSE_MS            1000
-#define GTPV1U_N3_REQUESTS               5
-#define GTPV1U_PROC_TIME_OUT_MS          ((GTPV1U_T3_RESPONSE_MS) * (GTPV1U_N3_REQUESTS + 1))
-
-protected:
-  uint32_t                          id;
-  udp_server                        udp_s;
-
-  // seems no need for std::atomic_uint32_t
-  uint32_t                        seq_num;
-  uint32_t                        restart_counter;
-
-  static bool check_initial_message_type(const uint8_t initial);
-  static bool check_triggered_message_type(const uint8_t initial, const uint8_t triggered);
-
-  uint32_t get_next_seq_num();
-
-public:
-  static const uint8_t version = 1;
-  gtpu_l4_stack(const struct in_addr& address, const uint16_t port_num, const util::thread_sched_params& sched_params);
-  gtpu_l4_stack(const struct in6_addr& address, const uint16_t port_num, const util::thread_sched_params& sched_params);
-  gtpu_l4_stack(char * ip_address, const uint16_t port_num, const util::thread_sched_params& sched_params);
-  virtual void handle_receive(char* recv_buffer, const std::size_t bytes_transferred, const endpoint& r_endpoint);
-  void handle_receive_message_cb(const gtpv1u_msg& msg, const struct sockaddr_storage& r_endpoint, const socklen_t& r_endpoint_addr_len, const task_id_t& task_id, bool &error, uint64_t& gtpc_tx_id);
-
-  void send_g_pdu(const struct sockaddr_in& peer_addr, const teid_t teid, const char* payload, const ssize_t payload_len);
-  void send_g_pdu(const struct sockaddr_in6& peer_addr, const teid_t teid, const char* payload, const ssize_t payload_len);
-
-  void send_response(const gtpv1u_echo_response& gtp_ies);
-  void send_indication(const gtpv1u_error_indication& gtp_ies);
-
-};
-} // namespace gtpv1u
-
-#endif /* FILE_GTPV1U_HPP_SEEN */
diff --git a/src/gtpv1u/msg_gtpv1u.hpp b/src/gtpv1u/msg_gtpv1u.hpp
deleted file mode 100644
index 3c1f182d8b4c758ca940285a094f0a0a9d46cc7a..0000000000000000000000000000000000000000
--- a/src/gtpv1u/msg_gtpv1u.hpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The OpenAirInterface Software Alliance licenses this file to You under
- * the OAI Public License, Version 1.1  (the "License"); you may not use this file
- * except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.openairinterface.org/?page_id=698
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *-------------------------------------------------------------------------------
- * For more information about the OpenAirInterface (OAI) Software Alliance:
- *      contact@openairinterface.org
- */
-
-/*! \file msg_gtpv1u.hpp
-  \brief
-  \author Sebastien ROUX, Lionel Gauthier
-  \company Eurecom
-  \email: lionel.gauthier@eurecom.fr
-*/
-
-
-#ifndef MSG_GTPV1U_HPP_INCLUDED_
-#define MSG_GTPV1U_HPP_INCLUDED_
-
-#include "3gpp_29.274.h"
-#include "3gpp_29.281.h"
-#include "endpoint.hpp"
-#include "common_defs.h"
-
-#include <utility>
-#include <vector>
-#include <sys/socket.h>
-
-namespace gtpv1u {
-
-class gtpv1u_ies_container {
-public:
-  static const uint8_t      msg_id = 0;
-  endpoint                  r_endpoint;
-  std::pair<bool, uint32_t> teid;
-  std::pair<bool, uint16_t> sequence_number;
-  std::pair<bool, uint8_t>  npdu_number;
-
-  gtpv1u_ies_container() : r_endpoint(), teid(), sequence_number(), npdu_number() {}
-  gtpv1u_ies_container(const gtpv1u_ies_container& i) :
-    r_endpoint(i.r_endpoint),
-    teid(i.teid),
-    sequence_number(i.sequence_number),
-    npdu_number(i.npdu_number) {}
-
-  gtpv1u_ies_container& operator=(gtpv1u_ies_container other)
-  {
-    std::swap(r_endpoint, other.r_endpoint);
-    std::swap(teid, other.teid);
-    std::swap(sequence_number, other.sequence_number);
-    std::swap(npdu_number, other.npdu_number);
-    return *this;
-  }
-
-  virtual bool get(recovery_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_RECOVERY);}
-  virtual bool get(tunnel_endpoint_identifier_data_i_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_TUNNEL_ENDPOINT_IDENTIFIER_DATA_I);}
-  virtual bool get(gtp_u_peer_address_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_GTP_U_PEER_ADDRESS);}
-  virtual bool get(extension_header_type_list_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_EXTENSION_HEADER_TYPE_LIST);}
-  virtual bool get(private_extension_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_PRIVATE_EXTENSION);}
-
-  virtual void set(const recovery_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_RECOVERY);}
-  virtual void set(const tunnel_endpoint_identifier_data_i_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_TUNNEL_ENDPOINT_IDENTIFIER_DATA_I);}
-  virtual void set(const gtp_u_peer_address_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_GTP_U_PEER_ADDRESS);}
-  virtual void set(const extension_header_type_list_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_EXTENSION_HEADER_TYPE_LIST);}
-  virtual void set(const private_extension_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_PRIVATE_EXTENSION);}
-
-  virtual void set_teid(const uint32_t pteid) {teid.second = pteid; teid.first = true;}
-  virtual void set_sequence_number(const uint16_t psequence_number) {sequence_number.second = psequence_number; sequence_number.first = true;}
-  virtual void set_npdu_number(const uint8_t pnpdu_number) {npdu_number.second = pnpdu_number; npdu_number.first = true;}
-
-  virtual bool get_teid(uint32_t& v) const {if (teid.first) {v = teid.second;return true;}return false;}
-  virtual bool get_sequence_number(uint16_t& v) const {if (sequence_number.first) {v = sequence_number.second;return true;}return false;}
-  virtual bool get_npdu_number(uint8_t& v) const {if (npdu_number.first) {v = npdu_number.second;return true;}return false;}
-};
-
-//------------------------------------------------------------------------------
-class gtpv1u_echo_request : public gtpv1u_ies_container {
-public:
-  static const uint8_t msg_id = GTPU_ECHO_REQUEST;
-
-  std::pair<bool, private_extension_t>     private_extension;
-
-  gtpv1u_echo_request() : gtpv1u_ies_container(), private_extension() {}
-  gtpv1u_echo_request(const gtpv1u_echo_request& i) : gtpv1u_ies_container(i), private_extension(i.private_extension) {}
-  gtpv1u_echo_request& operator=(gtpv1u_echo_request other)
-  {
-    this->gtpv1u_ies_container::operator=(other);
-    std::swap(private_extension, other.private_extension);
-    return *this;
-  }
-  static const char* get_msg_name() {return "GTPU_ECHO_REQUEST";};
-
-  bool get(private_extension_t& v)  const {if (private_extension.first) {v = private_extension.second;return true;}return false;}
-
-  void set(const private_extension_t& v) {private_extension.first = true; private_extension.second = v;}
-};
-
-//------------------------------------------------------------------------------
-class gtpv1u_echo_response : public gtpv1u_ies_container {
-public:
-  static const uint8_t msg_id = GTPU_ECHO_RESPONSE;
-
-  std::pair<bool, recovery_t>              recovery;
-  std::pair<bool, private_extension_t>     private_extension;
-
-  gtpv1u_echo_response(): gtpv1u_ies_container(), recovery(), private_extension() {}
-
-  gtpv1u_echo_response(const gtpv1u_echo_response& i): gtpv1u_ies_container(i), recovery(i.recovery), private_extension(i.private_extension) {}
-  static const char* get_msg_name() {return "GTPU_ECHO_RESPONSE";};
-
-  gtpv1u_echo_response& operator=(gtpv1u_echo_response other)
-  {
-    this->gtpv1u_ies_container::operator=(other);
-    std::swap(recovery, other.recovery);
-    std::swap(private_extension, other.private_extension);
-    return *this;
-  }
-
-  bool get(recovery_t& v)  const {if (recovery.first) {v = recovery.second;return true;}return false;}
-  bool get(private_extension_t& v)  const {if (private_extension.first) {v = private_extension.second;return true;}return false;}
-
-  void set(const recovery_t& v) {recovery.first = true; recovery.second = v;}
-  void set(const private_extension_t& v) {private_extension.first = true; private_extension.second = v;}
-};
-
-//------------------------------------------------------------------------------
-class gtpv1u_error_indication : public gtpv1u_ies_container {
-public:
-  static const uint8_t msg_id = GTPU_ERROR_INDICATION;
-
-
-  std::pair<bool, tunnel_endpoint_identifier_data_i_t>   tunnel_endpoint_identifier_data_i;
-  std::pair<bool, gtp_u_peer_address_t>                  gtp_u_peer_address;
-  std::pair<bool, private_extension_t>                   private_extension;
-
-  gtpv1u_error_indication(): gtpv1u_ies_container(), tunnel_endpoint_identifier_data_i(), gtp_u_peer_address(), private_extension() {}
-
-  gtpv1u_error_indication(const gtpv1u_error_indication& i) : gtpv1u_ies_container(i),
-    tunnel_endpoint_identifier_data_i(i.tunnel_endpoint_identifier_data_i),
-    gtp_u_peer_address(i.gtp_u_peer_address),
-    private_extension(i.private_extension) {}
-
-  gtpv1u_error_indication& operator=(gtpv1u_error_indication other)
-  {
-    this->gtpv1u_ies_container::operator=(other);
-    std::swap(tunnel_endpoint_identifier_data_i, other.tunnel_endpoint_identifier_data_i);
-    std::swap(gtp_u_peer_address, other.gtp_u_peer_address);
-    std::swap(private_extension, other.private_extension);
-    return *this;
-  }
-
-  static const char* get_msg_name() {return "GTPU_ERROR_INDICATION";};
-
-  bool get(tunnel_endpoint_identifier_data_i_t& v)  const {if (tunnel_endpoint_identifier_data_i.first) {v = tunnel_endpoint_identifier_data_i.second;return true;}return false;}
-  bool get(gtp_u_peer_address_t& v)  const {if (gtp_u_peer_address.first) {v = gtp_u_peer_address.second;return true;}return false;}
-  bool get(private_extension_t& v)  const {if (private_extension.first) {v = private_extension.second;return true;}return false;}
-
-  void set(const tunnel_endpoint_identifier_data_i_t& v) {tunnel_endpoint_identifier_data_i.first = true; tunnel_endpoint_identifier_data_i.second = v;}
-  void set(const gtp_u_peer_address_t& v) {gtp_u_peer_address.first = true; gtp_u_peer_address.second = v;}
-  void set(const private_extension_t& v) {private_extension.first = true; private_extension.second = v;}
-};
-//------------------------------------------------------------------------------
-class gtpv1u_supported_extension_headers_notification : public gtpv1u_ies_container {
-public:
-  static const uint8_t msg_id = GTPU_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION;
-
-  std::pair<bool, extension_header_type_list_t>     extension_header_type_list;
-
-  gtpv1u_supported_extension_headers_notification() : gtpv1u_ies_container(),
-    extension_header_type_list() {}
-
-  gtpv1u_supported_extension_headers_notification(const gtpv1u_supported_extension_headers_notification& i) :
-    gtpv1u_ies_container(i),
-    extension_header_type_list(i.extension_header_type_list) {}
-
-  gtpv1u_supported_extension_headers_notification& operator=(gtpv1u_supported_extension_headers_notification other)
-  {
-    this->gtpv1u_ies_container::operator=(other);
-    std::swap(extension_header_type_list, other.extension_header_type_list);
-    return *this;
-  }
-
-  static const char* get_msg_name() {return "GTPU_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION";};
-
-  bool get(extension_header_type_list_t& v)  const {if (extension_header_type_list.first) {v = extension_header_type_list.second;return true;}return false;}
-
-  void set(const extension_header_type_list_t& v) {extension_header_type_list.first = true; extension_header_type_list.second = v;}
-};
-
-//------------------------------------------------------------------------------
-class gtpv1u_end_marker : public gtpv1u_ies_container {
-public:
-  static const uint8_t msg_id = GTPU_END_MARKER;
-
-  std::pair<bool, private_extension_t>     private_extension;
-
-  gtpv1u_end_marker() : gtpv1u_ies_container(),
-    private_extension() {}
-
-  gtpv1u_end_marker(const gtpv1u_end_marker& i) : gtpv1u_ies_container(i),
-    private_extension(i.private_extension) {}
-
-  gtpv1u_end_marker& operator=(gtpv1u_end_marker other)
-  {
-    this->gtpv1u_ies_container::operator=(other);
-    std::swap(private_extension, other.private_extension);
-    return *this;
-  }
-
-  static const char* get_msg_name() {return "GTPU_END_MARKER";};
-
-  bool get(private_extension_t& v)  const {if (private_extension.first) {v = private_extension.second;return true;}return false;}
-
-  void set(const private_extension_t& v) {private_extension.first = true; private_extension.second = v;}
-};
-
-} // namespace gtpv1u
-
-#endif /* MSG_GTPV1U_HPP_INCLUDED_ */
diff --git a/src/nas/3gpp_24.501.h b/src/nas/3gpp_24.501.h
index a38ead97b29e06aeb613156949f78a0d7f8515f1..72de268788283bdaa8e1d9931869f08059835a0b 100644
--- a/src/nas/3gpp_24.501.h
+++ b/src/nas/3gpp_24.501.h
@@ -22,7 +22,7 @@
 /*
  *  This file contains NAS header bits format
  *  Refer TS24.007 TS24.501
- *  Auther: Puzyu Dukl
+ *  Author: Puzyu Dukl (BUPT), Tien-Thinh NGUYEN (EURECOM)
  *  Time:
  *  Email:
  */
@@ -246,64 +246,6 @@ enum class cause_value_5gsm_e {
   CAUSE_100_CONDITIONAL_IE_ERROR = 100,
   CAUSE_101_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
   CAUSE_111_PROTOCOL_ERROR_UNSPECIFIED = 111
-/*
- Cause #8 – Operator Determined Barring
- Cause #26 – Insufficient resources
- Cause #27 – Missing or unknown DNN
- Cause #28 – Unknown PDU session type
- Cause #29 – User authentication or authorization failed
- Cause #31 – Request rejected, unspecified
- Cause #32 – Service option not supported
- Cause #33 – Requested service option not subscribed
- Cause #35 – PTI already in use
- Cause #36 – Regular deactivation
- Cause #38 – Network failure
- Cause #39 – Reactivation requested
- Cause #41 – Semantic error in the TFT operation
- Cause #42 – Syntactical error in the TFT operation
- Cause #43 –Invalid PDU session identity
- Cause #44 – Semantic errors in packet filter(s)
- Cause #45 – Syntactical error in packet filter(s)
- Cause #46 –Out of LADN service area
- Cause #47 –PTI mismatch
- Cause #50 – PDU session type IPv4 only allowed
- Cause #51 – PDU session type IPv6 only allowed
- Cause #54 –PDU session does not exist
- Cause #67 – Insufficient resources for specific slice and DNN
- Cause #68 – Not supported SSC mode
- Cause #69 –Insufficient resources for specific slice
- Cause #70 – Missing or unknown DNN in a slice
- Cause #81 – Invalid PTI value
- Cause #82 – Maximum data rate per UE for user-plane integrity protection is too low
- Cause #83 – Semantic error in the QoS operation
- Cause #84 – Syntactical error in the QoS operation
- Cause #85 – Invalid mapped EPS bearer identity
- //Protocol errors
- Cause #95 – Semantically incorrect message
- Cause #96 – Invalid mandatory information
- Cause #97 – Message type non-existent or not implemented
- Cause #98 – Message type not compatible with protocol state
- Cause #99 – Information element non-existent or not implemented
- Cause #100 – Conditional IE error
- Cause #101 – Message not compatible with protocol state
- Cause #111 – Protocol error, unspecified
- */
-
-};
-
-enum cause_value_protocol_errors_e {
-  CAUSE_95_SEMANTICALLY_INCORRECT_MESSAGE = 95
-/*
- Cause #95 – Semantically incorrect message
- Cause #96 – Invalid mandatory information
- Cause #97 – Message type non-existent or not implemented
- Cause #98 – Message type not compatible with protocol state
- Cause #99 – Information element non-existent or not implemented
- Cause #100 – Conditional IE error
- Cause #101 – Message not compatible with protocol state
- Cause #111 – Protocol error, unspecified
- */
-
 };
 
 //The 5GSM sublayer states for PDU session handling in the network
@@ -348,6 +290,49 @@ enum notification_control_e {
 static const std::vector<std::string> notification_control_e2str = { "ERROR",
     "REQUESTED", "NOT_REQUESTED" };
 
+//PDU Session Type value
+enum pdu_session_type_e {
+  PDU_SESSION_TYPE_E_UNKNOWN = 0,
+  PDU_SESSION_TYPE_E_IPV4 = 1,
+  PDU_SESSION_TYPE_E_IPV6 = 2,
+  PDU_SESSION_TYPE_E_IPV4V6 = 3,
+  PDU_SESSION_TYPE_E_UNSTRUCTURED = 4,
+  PDU_SESSION_TYPE_E_ETHERNET = 5,
+  PDU_SESSION_TYPE_E_RESERVED = 7,
+};
+
+static const std::vector<std::string> pdu_session_type_e2str = { "Error",
+    "IPV4", "IPV6", "IPV4V6", "UNSTRUCTURED", "ETHERNET", "IPV4V6", "RESERVED" };
+
+typedef struct pdu_session_type_s {
+  uint8_t pdu_session_type;
+  pdu_session_type_s()
+      :
+      pdu_session_type(PDU_SESSION_TYPE_E_IPV4) {
+  }
+  pdu_session_type_s(const uint8_t &p)
+      :
+      pdu_session_type(p) {
+  }
+  pdu_session_type_s(const struct pdu_session_type_s &p)
+      :
+      pdu_session_type(p.pdu_session_type) {
+  }
+  bool operator==(const struct pdu_session_type_s &p) const {
+    return (p.pdu_session_type == pdu_session_type);
+  }
+  //------------------------------------------------------------------------------
+  bool operator==(const pdu_session_type_e &p) const {
+    return (p == pdu_session_type);
+  }
+  //------------------------------------------------------------------------------
+  const std::string& toString() const {
+    return pdu_session_type_e2str.at(pdu_session_type);
+  }
+} pdu_session_type_t;
+
+
+
 #endif
 
 #endif
diff --git a/src/nas/ies/SNSSAI.c b/src/nas/ies/SNSSAI.c
index bd1e536b405e6863ffb4b681729eb179d3237b58..23162c13feb8526769ae026f6465d7c6dbb43a80 100644
--- a/src/nas/ies/SNSSAI.c
+++ b/src/nas/ies/SNSSAI.c
@@ -6,104 +6,105 @@
 #include "TLVDecoder.h"
 #include "SNSSAI.h"
 
-int encode_snssai ( SNSSAI snssai, uint8_t iei, uint8_t * buffer, uint32_t len  ) 
-{
-    uint32_t encoded = 0;
-	uint8_t ielen = 0;
-	uint8_t bitStream = 0;
-	uint32_t bit32Stream = 0;
-	
-    CHECK_PDU_POINTER_AND_LENGTH_ENCODER (buffer,((iei > 0) ? SNSSAI_MINIMUM_LENGTH_TLV : SNSSAI_MINIMUM_LENGTH_TLV-1) , len);
-    
-	if( iei >0  )
-	{
-		*buffer=iei;
-		encoded++;
-	}
-	
-	ielen = snssai.len;
-
-    *(buffer + encoded) = ielen;
+int encode_snssai(SNSSAI snssai, uint8_t iei, uint8_t *buffer, uint32_t len) {
+  uint32_t encoded = 0;
+  uint8_t ielen = 0;
+  uint8_t bitStream = 0;
+  uint32_t bit32Stream = 0;
+
+  CHECK_PDU_POINTER_AND_LENGTH_ENCODER(
+      buffer,
+      ((iei > 0) ? SNSSAI_MINIMUM_LENGTH_TLV : SNSSAI_MINIMUM_LENGTH_TLV-1),
+      len);
+
+  if (iei > 0) {
+    *buffer = iei;
     encoded++;
+  }
 
-	bitStream = snssai.sst;
-	ENCODE_U8(buffer+encoded,bitStream,encoded);
-
-	if((ielen == SST_AND_SD_LENGHT) || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_LENGHT) || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGHT))
-	{
-		bit32Stream = snssai.sd;
-		ENCODE_U8(buffer+encoded,(uint8_t)bit32Stream,encoded);
-		ENCODE_U8(buffer+encoded,(uint8_t)(bit32Stream>>8),encoded);
-		ENCODE_U8(buffer+encoded,(uint8_t)(bit32Stream>>16),encoded);
-	}
-
-	if((ielen == SST_AND_MAPPEDHPLMNSST_LENGHT) || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_LENGHT) || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGHT))
-	{
-		bitStream = snssai.mappedhplmnsst;
-		ENCODE_U8(buffer+encoded,bitStream,encoded);
-	}
-	if(ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGHT)
-	{
-		bit32Stream = snssai.mappedhplmnsd;
-		ENCODE_U8(buffer+encoded,(uint8_t)bit32Stream,encoded);
-		ENCODE_U8(buffer+encoded,(uint8_t)(bit32Stream>>8),encoded);
-		ENCODE_U8(buffer+encoded,(uint8_t)(bit32Stream>>16),encoded);
-	}
-   
-    return encoded;
-}
+  ielen = snssai.len;
+
+  *(buffer + encoded) = ielen;
+  encoded++;
 
-int decode_snssai ( SNSSAI * snssai, uint8_t iei, uint8_t * buffer, uint32_t len  ) 
-{
-	int decoded=0;
-	uint8_t ielen=0;
-	uint8_t bitStream = 0;
-	uint32_t bit32Stream = 0;
+  bitStream = snssai.sst;
+  ENCODE_U8(buffer + encoded, bitStream, encoded);
+
+  if ((ielen == SST_AND_SD_LENGTH)
+      || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_LENGTH)
+      || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGTH)) {
+    bit32Stream = snssai.sd;
+    ENCODE_U8(buffer + encoded, (uint8_t )bit32Stream, encoded);
+    ENCODE_U8(buffer + encoded, (uint8_t )(bit32Stream >> 8), encoded);
+    ENCODE_U8(buffer + encoded, (uint8_t )(bit32Stream >> 16), encoded);
+  }
+
+  if ((ielen == SST_AND_MAPPEDHPLMNSST_LENGTH)
+      || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_LENGTH)
+      || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGTH)) {
+    bitStream = snssai.mappedhplmnsst;
+    ENCODE_U8(buffer + encoded, bitStream, encoded);
+  }
+  if (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGTH) {
+    bit32Stream = snssai.mappedhplmnsd;
+    ENCODE_U8(buffer + encoded, (uint8_t )bit32Stream, encoded);
+    ENCODE_U8(buffer + encoded, (uint8_t )(bit32Stream >> 8), encoded);
+    ENCODE_U8(buffer + encoded, (uint8_t )(bit32Stream >> 16), encoded);
+  }
+
+  return encoded;
+}
 
-    if (iei > 0)
-    {
-        CHECK_IEI_DECODER (iei, *buffer);
-        decoded++;
-    }
+int decode_snssai(SNSSAI *snssai, uint8_t iei, uint8_t *buffer, uint32_t len) {
+  int decoded = 0;
+  uint8_t ielen = 0;
+  uint8_t bitStream = 0;
+  uint32_t bit32Stream = 0;
 
-    ielen = *(buffer + decoded);
+  if (iei > 0) {
+    CHECK_IEI_DECODER(iei, *buffer);
     decoded++;
-    CHECK_LENGTH_DECODER (len - decoded, ielen);
-
-	snssai->len = ielen;
-
-	DECODE_U8(buffer+decoded,bitStream,decoded);
-	snssai->sst = bitStream;
-
-	if((ielen == SST_AND_SD_LENGHT) || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_LENGHT) || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGHT))
-	{
-		DECODE_U8(buffer+decoded,bitStream,decoded);
-		bit32Stream = (uint32_t)(bitStream&0Xff);
-		DECODE_U8(buffer+decoded,bitStream,decoded);
-		bit32Stream |= (uint32_t)((bitStream<<8)&0xff00);
-		DECODE_U8(buffer+decoded,bitStream,decoded);
-		bit32Stream |= (uint32_t)((bitStream<<16)&0xff0000);
-		
-		snssai->sd = bit32Stream;
-	}
-
-	if((ielen == SST_AND_MAPPEDHPLMNSST_LENGHT) || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_LENGHT) || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGHT))
-	{
-		DECODE_U8(buffer+decoded,bitStream,decoded);
-		snssai->mappedhplmnsst = bitStream;
-	}
-	if(ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGHT)
-	{
-		DECODE_U8(buffer+decoded,bitStream,decoded);
-		bit32Stream = (uint32_t)(bitStream&0Xff);
-		DECODE_U8(buffer+decoded,bitStream,decoded);
-		bit32Stream |= (uint32_t)((bitStream<<8)&0xff00);
-		DECODE_U8(buffer+decoded,bitStream,decoded);
-		bit32Stream |= (uint32_t)((bitStream<<16)&0xff0000);
-		
-		snssai->mappedhplmnsd = bit32Stream;
-	}
-
-	return decoded;
+  }
+
+  ielen = *(buffer + decoded);
+  decoded++;
+  CHECK_LENGTH_DECODER(len - decoded, ielen);
+
+  snssai->len = ielen;
+
+  DECODE_U8(buffer + decoded, bitStream, decoded);
+  snssai->sst = bitStream;
+
+  if ((ielen == SST_AND_SD_LENGTH)
+      || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_LENGTH)
+      || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGTH)) {
+    DECODE_U8(buffer + decoded, bitStream, decoded);
+    bit32Stream = (uint32_t) (bitStream & 0Xff);
+    DECODE_U8(buffer + decoded, bitStream, decoded);
+    bit32Stream |= (uint32_t) ((bitStream << 8) & 0xff00);
+    DECODE_U8(buffer + decoded, bitStream, decoded);
+    bit32Stream |= (uint32_t) ((bitStream << 16) & 0xff0000);
+
+    snssai->sd = bit32Stream;
+  }
+
+  if ((ielen == SST_AND_MAPPEDHPLMNSST_LENGTH)
+      || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_LENGTH)
+      || (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGTH)) {
+    DECODE_U8(buffer + decoded, bitStream, decoded);
+    snssai->mappedhplmnsst = bitStream;
+  }
+  if (ielen == SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGTH) {
+    DECODE_U8(buffer + decoded, bitStream, decoded);
+    bit32Stream = (uint32_t) (bitStream & 0Xff);
+    DECODE_U8(buffer + decoded, bitStream, decoded);
+    bit32Stream |= (uint32_t) ((bitStream << 8) & 0xff00);
+    DECODE_U8(buffer + decoded, bitStream, decoded);
+    bit32Stream |= (uint32_t) ((bitStream << 16) & 0xff0000);
+
+    snssai->mappedhplmnsd = bit32Stream;
+  }
+
+  return decoded;
 }
 
diff --git a/src/nas/ies/SNSSAI.h b/src/nas/ies/SNSSAI.h
index 7c1188b5283518b36f43b242d087b9c042dc1f47..299c31d9e3d8e183794e7f0c8c195aedf48ca100 100644
--- a/src/nas/ies/SNSSAI.h
+++ b/src/nas/ies/SNSSAI.h
@@ -10,24 +10,23 @@
 #define SNSSAI_MINIMUM_LENGTH_TLV 3
 #define SNSSAI_MAXIMUM_LENGTH_TLV 10
 
-typedef enum{
-	SST_LENGHT = 0b00000001,
-	SST_AND_MAPPEDHPLMNSST_LENGHT = 0b00000010,
-	SST_AND_SD_LENGHT = 0b00000100,
-	SST_AND_SD_AND_MAPPEDHPLMNSST_LENGHT = 0b00000101,
-	SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGHT = 0b00001000
-}length_of_snssai_contents;
-
-
-typedef struct{
-	length_of_snssai_contents len;
- 	uint8_t sst;
-	uint32_t sd:24;
-	uint8_t mappedhplmnsst;
-	uint32_t mappedhplmnsd;
+typedef enum {
+  SST_LENGTH = 0b00000001,
+  SST_AND_MAPPEDHPLMNSST_LENGTH = 0b00000010,
+  SST_AND_SD_LENGTH = 0b00000100,
+  SST_AND_SD_AND_MAPPEDHPLMNSST_LENGTH = 0b00000101,
+  SST_AND_SD_AND_MAPPEDHPLMNSST_AND_MAPPEDHPLMNSD_LENGTH = 0b00001000
+} length_of_snssai_contents;
+
+typedef struct {
+  length_of_snssai_contents len;
+  uint8_t sst;
+  uint32_t sd :24;
+  uint8_t mappedhplmnsst;
+  uint32_t mappedhplmnsd;
 } SNSSAI;
 
-int encode_snssai ( SNSSAI snssai, uint8_t iei, uint8_t * buffer, uint32_t len  ) ;
-int decode_snssai ( SNSSAI * snssai, uint8_t iei, uint8_t * buffer, uint32_t len  ) ;
+int encode_snssai(SNSSAI snssai, uint8_t iei, uint8_t *buffer, uint32_t len);
+int decode_snssai(SNSSAI *snssai, uint8_t iei, uint8_t *buffer, uint32_t len);
 
 #endif
diff --git a/src/oai_smf/CMakeLists.txt b/src/oai_smf/CMakeLists.txt
index 84bacec18f674c5b78538df810326b4ab5f8f414..46dd237eb1c4b7e61d80fdcc4cdea680354eae7f 100644
--- a/src/oai_smf/CMakeLists.txt
+++ b/src/oai_smf/CMakeLists.txt
@@ -271,9 +271,6 @@ ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../../src/gtpv2c ${CMAKE_CURRENT_BI
 ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../../src/pfcp ${CMAKE_CURRENT_BINARY_DIR}/pfcp)
 ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../../src/udp ${CMAKE_CURRENT_BINARY_DIR}/udp)
 ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../../src/api-server ${CMAKE_CURRENT_BINARY_DIR}/api-server)
-if(${SGW_AUTOTEST})
-ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../../src/gtpv1u ${CMAKE_CURRENT_BINARY_DIR}/gtpv1u)
-endif(${SGW_AUTOTEST})
 
 #ENABLE_TESTING()
 #ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../../src/test ${CMAKE_CURRENT_BINARY_DIR}/test)
@@ -381,9 +378,6 @@ IF(STATIC_LINKING)
     SET(ASAN)
 ENDIF(STATIC_LINKING)
 
-if(${SGW_AUTOTEST})
-  SET(GTPV1U_LIB GTPV1U)
-endif(${SGW_AUTOTEST})
 
-target_link_libraries (smf ${ASAN} -Wl,--start-group CN_UTILS SMF UDP ${GTPV1U_LIB} GTPV2C PFCP 3GPP_COMMON_TYPES SMF_API -lnettle ${NETTLE_LIBRARIES} ${CRYPTO_LIBRARIES} NAS gflags glog dl double-conversion folly -Wl,--end-group pthread m rt config++ event boost_system pistache curl)
+target_link_libraries (smf ${ASAN} -Wl,--start-group CN_UTILS SMF UDP GTPV2C PFCP 3GPP_COMMON_TYPES SMF_API -lnettle ${NETTLE_LIBRARIES} ${CRYPTO_LIBRARIES} NAS gflags glog dl double-conversion folly -Wl,--end-group pthread m rt config++ event boost_system pistache curl)
 
diff --git a/src/smf_app/smf_app.cpp b/src/smf_app/smf_app.cpp
index d3156d6460f4aab0956f8ec61f0a60f9b450c6e5..e5c2a61aaddc08f359c2e9a8f00ba5b4c926ebda 100755
--- a/src/smf_app/smf_app.cpp
+++ b/src/smf_app/smf_app.cpp
@@ -516,7 +516,9 @@ void smf_app::handle_pdu_session_create_sm_context_request(
         "NAS, pdu_session_type %d",
         decoded_nas_msg.plain.sm.pdu_session_establishment_request
             ._pdusessiontype.pdu_session_type_value);
-    smreq->req.set_pdu_session_type(decoded_nas_msg.plain.sm.pdu_session_establishment_request._pdusessiontype.pdu_session_type_value);
+    smreq->req.set_pdu_session_type(
+        decoded_nas_msg.plain.sm.pdu_session_establishment_request
+            ._pdusessiontype.pdu_session_type_value);
   }
 
   //Get necessary information
@@ -564,6 +566,8 @@ void smf_app::handle_pdu_session_create_sm_context_request(
         Pistache::Http::Code::Forbidden, n1_sm_message_hex);
   }
 
+  context_req_msg.set_pti(pti);
+
   //check pdu session id
   if ((pdu_session_id == PDU_SESSION_IDENTITY_UNASSIGNED )
       || (pdu_session_id > PDU_SESSION_IDENTITY_LAST )) {
diff --git a/src/smf_app/smf_app.hpp b/src/smf_app/smf_app.hpp
index 7d74a0df5b3c8dc51708c0858ee21fafa3a0ca70..bbfd4106a87bec9e45123d5e2ccf2530d4162464 100644
--- a/src/smf_app/smf_app.hpp
+++ b/src/smf_app/smf_app.hpp
@@ -56,10 +56,15 @@ namespace smf {
 
 #define TASK_SMF_APP_TRIGGER_T3591     (0)
 #define TASK_SMF_APP_TIMEOUT_T3591     (1)
+#define TASK_SMF_APP_TRIGGER_T3592     (2)
+#define TASK_SMF_APP_TIMEOUT_T3592     (3)
 
 //Table 10.3.2 @3GPP TS 24.501 V16.1.0 (2019-06)
 #define T3591_TIMER_VALUE_SEC 16
 #define T3591_TIMER_MAX_RETRIES 4
+#define T3592_TIMER_VALUE_SEC 16
+#define T3592_TIMER_MAX_RETRIES 4
+
 
 typedef enum {
   PDU_SESSION_ESTABLISHMENT = 1,
diff --git a/src/smf_app/smf_context.cpp b/src/smf_app/smf_context.cpp
index c46815936567979c4a581770f5f659f6db63c23e..c9024fe7de18287aac1f25ea310abeac636fa127 100644
--- a/src/smf_app/smf_context.cpp
+++ b/src/smf_app/smf_context.cpp
@@ -61,6 +61,42 @@ extern smf::smf_app *smf_app_inst;
 extern smf::smf_n11 *smf_n11_inst;
 extern smf::smf_config smf_cfg;
 
+//------------------------------------------------------------------------------
+void smf_qos_flow::release_qos_flow() {
+  released = true;
+}
+
+//------------------------------------------------------------------------------
+std::string smf_qos_flow::toString() const {
+  std::string s = { };
+  s.append("QoS Flow:\n");
+  s.append("\tFQI:\t\t\t\t").append(std::to_string((uint8_t) qfi.qfi)).append(
+      "\n");
+  s.append("\tUL FTEID:\t\t").append(ul_fteid.toString()).append("\n");
+  s.append("\tPDR ID UL:\t\t\t").append(std::to_string(pdr_id_ul.rule_id))
+      .append("\n");
+  s.append("\tPDR ID DL:\t\t\t").append(std::to_string(pdr_id_dl.rule_id))
+      .append("\n");
+  s.append("\tPRECEDENCE:\t\t\t").append(std::to_string(precedence.precedence))
+      .append("\n");
+  if (far_id_ul.first) {
+    s.append("\tFAR ID UL:\t\t\t").append(
+        std::to_string(far_id_ul.second.far_id)).append("\n");
+  }
+  if (far_id_dl.first) {
+    s.append("\tFAR ID DL:\t\t\t").append(
+        std::to_string(far_id_dl.second.far_id)).append("\n");
+  }
+  return s;
+}
+//------------------------------------------------------------------------------
+void smf_qos_flow::deallocate_ressources() {
+  clear();
+  Logger::smf_app().info(
+      "Resources associated with this QoS Flow (%d) have been released",
+      (uint8_t) qfi.qfi);
+}
+
 //------------------------------------------------------------------------------
 void smf_pdu_session::set(const paa_t &paa) {
   switch (paa.pdn_type.pdn_type) {
@@ -68,21 +104,25 @@ void smf_pdu_session::set(const paa_t &paa) {
       ipv4 = true;
       ipv6 = false;
       ipv4_address = paa.ipv4_address;
+      pdn_type.pdn_type = paa.pdn_type.pdn_type;
       break;
     case PDN_TYPE_E_IPV6:
       ipv4 = false;
       ipv6 = true;
       ipv6_address = paa.ipv6_address;
+      pdn_type.pdn_type = paa.pdn_type.pdn_type;
       break;
     case PDN_TYPE_E_IPV4V6:
       ipv4 = true;
       ipv6 = true;
       ipv4_address = paa.ipv4_address;
       ipv6_address = paa.ipv6_address;
+      pdn_type.pdn_type = paa.pdn_type.pdn_type;
       break;
     case PDN_TYPE_E_NON_IP:
       ipv4 = false;
       ipv6 = false;
+      pdn_type.pdn_type = paa.pdn_type.pdn_type;
       break;
     default:
       Logger::smf_app().error("smf_pdu_session::set(paa_t) Unknown PDN type %d",
@@ -90,6 +130,37 @@ void smf_pdu_session::set(const paa_t &paa) {
   }
 }
 
+//------------------------------------------------------------------------------
+void smf_pdu_session::get_paa(paa_t &paa) {
+  switch (pdn_type.pdn_type) {
+    case PDN_TYPE_E_IPV4:
+      ipv4 = true;
+      ipv6 = false;
+      paa.ipv4_address = ipv4_address;
+      break;
+    case PDN_TYPE_E_IPV6:
+      ipv4 = false;
+      ipv6 = true;
+      paa.ipv6_address = ipv6_address;
+      break;
+    case PDN_TYPE_E_IPV4V6:
+      ipv4 = true;
+      ipv6 = true;
+      paa.ipv4_address = ipv4_address;
+      paa.ipv6_address = ipv6_address;
+      break;
+    case PDN_TYPE_E_NON_IP:
+      ipv4 = false;
+      ipv6 = false;
+      break;
+    default:
+      Logger::smf_app().error(
+          "smf_pdu_session::get_paa (paa_t) Unknown PDN type %d",
+          pdn_type.pdn_type);
+  }
+  paa.pdn_type.pdn_type = pdn_type.pdn_type;
+}
+
 //------------------------------------------------------------------------------
 void smf_pdu_session::add_qos_flow(smf_qos_flow &flow) {
   if ((flow.qfi.qfi >= QOS_FLOW_IDENTIFIER_FIRST )
@@ -208,14 +279,19 @@ void smf_pdu_session::deallocate_ressources(const std::string &apn) {
 
   for (std::map<uint8_t, smf_qos_flow>::iterator it = qos_flows.begin();
       it != qos_flows.end(); ++it) {
+    //TODO: release FAR_ID, PDR_ID
+    //release_pdr_id(it->second.pdr_id_dl);
+    //release_pdr_id(it->second.pdr_id_ul);
+    //release_far_id(it->second.far_id_dl.second);
+    //release_far_id(it->second.far_id_ul.second);
     it->second.deallocate_ressources();
   }
-  qos_flows.clear();
   if (ipv4) {
     paa_dynamic::get_instance().release_paa(apn, ipv4_address);
   }
-  //smf_app_inst->free_s5s8_cp_fteid(pgw_fteid_s5_s8_cp);
-  clear();
+  clear(); //including qos_flows.clear()
+  Logger::smf_app().info(
+      "Resources associated with this PDU Session have been released");
 }
 
 //------------------------------------------------------------------------------
@@ -283,6 +359,10 @@ std::string smf_pdu_session::toString() const {
 //------------------------------------------------------------------------------
 void smf_pdu_session::set_pdu_session_status(
     const pdu_session_status_e &status) {
+  //TODO: Should consider congestion handling
+  Logger::smf_app().info(
+      "Set PDU Session Status to %s",
+      pdu_session_status_e2str[static_cast<int>(status)].c_str());
   pdu_session_status = status;
 }
 
@@ -301,6 +381,28 @@ upCnx_state_e smf_pdu_session::get_upCnx_state() const {
   return upCnx_state;
 }
 
+//------------------------------------------------------------------------------
+pdn_type_t smf_pdu_session::get_pdn_type() const {
+  return pdn_type;
+}
+
+//------------------------------------------------------------------------------
+void session_management_subscription::insert_dnn_configuration(
+    std::string dnn, std::shared_ptr<dnn_configuration_t> &dnn_configuration) {
+  dnn_configurations.insert(
+      std::pair<std::string, std::shared_ptr<dnn_configuration_t>>(
+          dnn, dnn_configuration));
+}
+
+//------------------------------------------------------------------------------
+void session_management_subscription::find_dnn_configuration(
+    std::string dnn, std::shared_ptr<dnn_configuration_t> &dnn_configuration) {
+  Logger::smf_app().info("find_dnn_configuration with dnn %s", dnn.c_str());
+  if (dnn_configurations.count(dnn) > 0) {
+    dnn_configuration = dnn_configurations.at(dnn);
+  }
+}
+
 //------------------------------------------------------------------------------
 void smf_context::insert_procedure(std::shared_ptr<smf_procedure> &sproc) {
   std::unique_lock<std::recursive_mutex> lock(m_context);
@@ -1219,7 +1321,7 @@ void smf_context::handle_pdu_session_update_sm_context_request(
           // qos_rules_ie[0].segregation ;
           // qos_rules_ie[0].qosflowidentifer ;
         }
-        free_wrapper((void **) &qos_rules_ie);
+        free_wrapper((void**) &qos_rules_ie);
 
         //verify the PDU session ID
         if (smreq->req.get_pdu_session_id()
@@ -1298,6 +1400,10 @@ void smf_context::handle_pdu_session_update_sm_context_request(
       case PDU_SESSION_MODIFICATION_COMPLETE: {
         //PDU Session Modification procedure (Section 4.3.3.2@3GPP TS 23.502)
         //TODO: should be verified since mentioned PDU_SESSION_MODIFICATION_COMMAND ACK in spec (see Step 11, section 4.3.3.2@3GPP TS 23.502)
+        Logger::smf_app().debug("PDU_SESSION_MODIFICATION_COMPLETE");
+        procedure_type =
+            session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED_STEP3;
+
         //send response
 
         /* see section 6.3.2.3@3GPP TS 24.501 V16.1.0
@@ -1320,6 +1426,63 @@ void smf_context::handle_pdu_session_update_sm_context_request(
         //PDU Session Release UE-Initiated (Step 1)
       case PDU_SESSION_RELEASE_REQUEST: {
         //PDU Session Release procedure (Section 4.3.4@3GPP TS 23.502)
+        Logger::smf_app().debug("PDU_SESSION_RELEASE_REQUEST");
+        Logger::smf_app().info(
+            "PDU Session Release (UE-Initiated), processing N1 SM Information");
+        procedure_type =
+            session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP1;
+        //verify PDU Session ID
+        if (sm_context_req_msg.get_pdu_session_id()
+            != decoded_nas_msg.plain.sm.header.pdu_session_identity) {
+          //TODO: PDU Session ID mismatch
+        }
+        //PTI
+        Logger::smf_app().info(
+            "PTI %d",
+            decoded_nas_msg.plain.sm.header.procedure_transaction_identity);
+        procedure_transaction_id_t pti = { .procedure_transaction_id =
+            decoded_nas_msg.plain.sm.header.procedure_transaction_identity };
+        n1_sm_context_resp->res.set_pti(pti);
+
+        //Message Type
+        //Presence
+        //5GSM Cause
+        //Extended Protocol Configuration Options
+
+        //Release the resources related to this PDU Session
+        //The SMF releases the IP address / Prefix(es) that were allocated to the PDU Session and releases the
+        //corresponding User Plane resources
+
+        //SMF releases the IP address / Prefix(es) that were allocated to the PDU Session
+
+        //find DNN context
+        std::shared_ptr<dnn_context> sd = { };
+
+        if ((!find_dnn_context(sm_context_req_msg.get_snssai(),
+                               sm_context_req_msg.get_dnn(), sd))
+            or (nullptr == sd.get())) {
+          //TODO: error cannot find the associated DNN context
+          return;
+        }
+
+        //find PDU Session
+        std::shared_ptr<smf_pdu_session> ss;
+        if ((!sd.get()->find_pdu_session(
+            sm_context_req_msg.get_pdu_session_id(), ss))
+            or (nullptr == ss.get())) {
+          //TODO: error cannot find the corresponding PDU Session
+        }
+
+        //get the associated QoS flows: to be used for PFCP Session Modification procedure
+        std::vector<smf_qos_flow> qos_flows;
+        ss.get()->get_qos_flows(qos_flows);
+        for (auto i : qos_flows) {
+          sm_context_req_msg.add_qfi(i.qfi.qfi);
+        }
+
+        //need to update UPF accordingly
+        update_upf = true;
+
         //TODO:
       }
         break;
@@ -1327,7 +1490,64 @@ void smf_context::handle_pdu_session_update_sm_context_request(
         //PDU Session Release UE-Initiated (Step 3)
       case PDU_SESSION_RELEASE_COMPLETE: {
         //PDU Session Release procedure
-        //TODO:
+        Logger::smf_app().debug("PDU_SESSION_RELEASE_COMPLETE");
+        Logger::smf_app().info(
+            "PDU Session Release Complete (UE-Initiated), processing N1 SM Information");
+        procedure_type =
+            session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP3;
+        //verify PDU Session ID
+        if (sm_context_req_msg.get_pdu_session_id()
+            != decoded_nas_msg.plain.sm.header.pdu_session_identity) {
+          //TODO: PDU Session ID mismatch
+        }
+        //PTI
+        Logger::smf_app().info(
+            "PTI %d",
+            decoded_nas_msg.plain.sm.header.procedure_transaction_identity);
+        procedure_transaction_id_t pti = { .procedure_transaction_id =
+            decoded_nas_msg.plain.sm.header.procedure_transaction_identity };
+
+        //Message Type
+        if (decoded_nas_msg.plain.sm.header.message_type
+            != PDU_SESSION_RELEASE_COMPLETE) {
+          //TODO: Message Type mismatch
+        }
+        //5GSM Cause
+        //Extended Protocol Configuration Options
+
+        //Update PDU Session status -> INACTIVE
+        sp.get()->set_pdu_session_status(
+            pdu_session_status_e::PDU_SESSION_INACTIVE);
+        //Stop timer T3592
+        itti_inst->timer_remove(sp.get()->timer_T3592);
+
+        //send response to AMF
+        //Verify, do we need this?
+        oai::smf_server::model::SmContextCreatedData smContextCreatedData;
+        smf_n11_inst->send_pdu_session_create_sm_context_response(
+            smreq->http_response, smContextCreatedData,
+            Pistache::Http::Code::Ok);
+
+        //TODO: SMF invokes Nsmf_PDUSession_SMContextStatusNotify to notify AMF that the SM context for this PDU Session is released
+        //TODO: if dynamic PCC applied, SMF invokes an SM Policy Association Termination
+        //TODO: SMF unsubscribes from Session Management Subscription data changes notification from UDM by invoking Numd_SDM_Unsubscribe
+        //find dnn context
+        std::shared_ptr<dnn_context> sd = { };
+        bool find_dnn = find_dnn_context(sm_context_req_msg.get_snssai(),
+                                         sm_context_req_msg.get_dnn(), sd);
+        //At this step, this context should be existed
+        if (nullptr == sd.get()) {
+          Logger::smf_app().debug(
+              "DNN context (dnn_in_use %s) is not existed yet!",
+              sm_context_req_msg.get_dnn().c_str());
+          //TODO:
+        }
+        if (sd.get()->get_number_pdu_sessions() == 0) {
+          Logger::smf_app().debug(
+              "Unsubscribe from Session Management Subscription data changes notification from UDM");
+          //TODO: unsubscribes from Session Management Subscription data changes notification from UDM
+        }
+        //TODO: Invoke Nudm_UECM_Deregistration
       }
         break;
 
@@ -1362,6 +1582,7 @@ void smf_context::handle_pdu_session_update_sm_context_request(
       //UE-Requested PDU Session Establishment procedure (Section 4.3.2.2.1@3GPP TS 23.502)
       //or UE Triggered Service Request Procedure (step 2)
       case n2_sm_info_type_e::PDU_RES_SETUP_RSP: {
+        Logger::smf_app().info("PDU_RES_SETUP_RSP");
         Logger::smf_app().info(
             "PDU Session Establishment Request, processing N2 SM Information");
 
@@ -1453,6 +1674,10 @@ void smf_context::handle_pdu_session_update_sm_context_request(
 
         //PDU Session Modification procedure (UE-initiated, Section 4.3.3.2@3GPP TS 23.502 or SMF-Requested)(Step 2)
       case n2_sm_info_type_e::PDU_RES_MOD_RSP: {
+        Logger::smf_app().info("PDU_RES_MOD_RSP");
+        Logger::smf_app().info(
+            "PDU Session Modification, processing N2 SM Information");
+
         procedure_type =
             session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED_STEP2;
 
@@ -1516,13 +1741,29 @@ void smf_context::handle_pdu_session_update_sm_context_request(
 
         //PDU Session Modification procedure
       case n2_sm_info_type_e::PDU_RES_MOD_FAIL: {
+        Logger::smf_app().info("PDU_RES_MOD_FAIL");
         //TODO:
       }
         break;
 
         //PDU Session Release procedure (UE-initiated, Section 4.3.4.2@3GPP TS 23.502 or SMF-Requested)(Step 2)
       case n2_sm_info_type_e::PDU_RES_REL_RSP: {
-        //TODO:
+        Logger::smf_app().info("PDU_RES_REL_RSP");
+        Logger::smf_app().info(
+            "PDU Session Release (UE-initiated), processing N2 SM Information");
+
+        procedure_type =
+            session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP2;
+        //TODO: SMF does nothing (Step 7, section 4.3.4.2@3GPP TS 23.502)
+        //SMF send response to AMF
+
+        //Verify, do we need this?
+        oai::smf_server::model::SmContextCreatedData smContextCreatedData;
+
+        smf_n11_inst->send_pdu_session_create_sm_context_response(
+            smreq->http_response, smContextCreatedData,
+            Pistache::Http::Code::Ok);
+
       }
         break;
 
@@ -1702,6 +1943,10 @@ void dnn_context::insert_pdu_session(std::shared_ptr<smf_pdu_session> &sp) {
   pdu_sessions.push_back(sp);
 }
 
+size_t dnn_context::get_number_pdu_sessions() {
+  return pdu_sessions.size();
+}
+
 //------------------------------------------------------------------------------
 std::string dnn_context::toString() const {
   std::string s = { };
@@ -1716,55 +1961,3 @@ std::string dnn_context::toString() const {
   return s;
 }
 
-//------------------------------------------------------------------------------
-void session_management_subscription::insert_dnn_configuration(
-    std::string dnn, std::shared_ptr<dnn_configuration_t> &dnn_configuration) {
-  dnn_configurations.insert(
-      std::pair<std::string, std::shared_ptr<dnn_configuration_t>>(
-          dnn, dnn_configuration));
-}
-
-//------------------------------------------------------------------------------
-void session_management_subscription::find_dnn_configuration(
-    std::string dnn, std::shared_ptr<dnn_configuration_t> &dnn_configuration) {
-  Logger::smf_app().info("find_dnn_configuration with dnn %s", dnn.c_str());
-  if (dnn_configurations.count(dnn) > 0) {
-    dnn_configuration = dnn_configurations.at(dnn);
-  }
-}
-
-//------------------------------------------------------------------------------
-void smf_qos_flow::release_qos_flow() {
-  released = true;
-}
-
-//------------------------------------------------------------------------------
-std::string smf_qos_flow::toString() const {
-  std::string s = { };
-  s.append("QoS Flow:\n");
-  s.append("\tFQI:\t\t\t\t").append(std::to_string((uint8_t) qfi.qfi)).append(
-      "\n");
-  s.append("\tUL FTEID:\t\t").append(ul_fteid.toString()).append("\n");
-  s.append("\tPDR ID UL:\t\t\t").append(std::to_string(pdr_id_ul.rule_id))
-      .append("\n");
-  s.append("\tPDR ID DL:\t\t\t").append(std::to_string(pdr_id_dl.rule_id))
-      .append("\n");
-  s.append("\tPRECEDENCE:\t\t\t").append(std::to_string(precedence.precedence))
-      .append("\n");
-  if (far_id_ul.first) {
-    s.append("\tFAR ID UL:\t\t\t").append(
-        std::to_string(far_id_ul.second.far_id)).append("\n");
-  }
-  if (far_id_dl.first) {
-    s.append("\tFAR ID DL:\t\t\t").append(
-        std::to_string(far_id_dl.second.far_id)).append("\n");
-  }
-  return s;
-}
-//------------------------------------------------------------------------------
-void smf_qos_flow::deallocate_ressources() {
-  Logger::smf_app().info("smf_qos_flow::deallocate_ressources(%d)",
-                         (uint8_t) qfi.qfi);
-  clear();
-}
-
diff --git a/src/smf_app/smf_context.hpp b/src/smf_app/smf_context.hpp
index 0eea6ed25a4ae591c176d9c4e815ea79d5b50d7f..43ea7ce3edbfb2c7f2dd528820774e8e49cce953 100644
--- a/src/smf_app/smf_context.hpp
+++ b/src/smf_app/smf_context.hpp
@@ -131,11 +131,13 @@ class smf_pdu_session : public std::enable_shared_from_this<smf_pdu_session> {
     pdu_session_status = pdu_session_status_e::PDU_SESSION_INACTIVE;
     timer_T3590 = ITTI_INVALID_TIMER_ID;
     timer_T3591 = ITTI_INVALID_TIMER_ID;
+    timer_T3592 = ITTI_INVALID_TIMER_ID;
   }
 
   smf_pdu_session(smf_pdu_session &b) = delete;
 
   void set(const paa_t &paa);
+  void get_paa(paa_t &paa);
 
   bool get_qos_flow(const pfcp::pdr_id_t &pdr_id, smf_qos_flow &q);
   bool get_qos_flow(const pfcp::far_id_t &far_id, smf_qos_flow &q);
@@ -184,6 +186,7 @@ class smf_pdu_session : public std::enable_shared_from_this<smf_pdu_session> {
 
   void generate_qos_rule_id(uint8_t &rule_id);
   void release_qos_rule_id(const uint8_t &rule_id);
+  pdn_type_t get_pdn_type() const;
 
   bool ipv4;                  // IP Address(es): IPv4 address and/or IPv6 prefix
   bool ipv6;                  // IP Address(es): IPv4 address and/or IPv6 prefix
@@ -212,6 +215,7 @@ class smf_pdu_session : public std::enable_shared_from_this<smf_pdu_session> {
   pdu_session_status_e pdu_session_status;
   timer_id_t timer_T3590;
   timer_id_t timer_T3591;
+  timer_id_t timer_T3592;
   //N3 tunnel status (ACTIVATED, DEACTIVATED, ACTIVATING)
   upCnx_state_e upCnx_state;
   //5GSM parameters and capabilities
@@ -272,6 +276,8 @@ class dnn_context {
 
   /* Insert a PDU Session into the DNN context */
   void insert_pdu_session(std::shared_ptr<smf_pdu_session> &sp);
+  /* get number of pdu sessions associated with this context (dnn and Nssai) */
+  size_t get_number_pdu_sessions();
 
   std::string toString() const;
 
diff --git a/src/smf_app/smf_msg.cpp b/src/smf_app/smf_msg.cpp
index e6c12255627410cd3d2d6621afd7f094029a5cc2..c26966fb5d39260774b2929e6b44f9afdef2c783 100644
--- a/src/smf_app/smf_msg.cpp
+++ b/src/smf_app/smf_msg.cpp
@@ -146,25 +146,26 @@ void pdu_session_msg::set_pdu_session_type(uint8_t const &pdu_session_type) {
 }
 
 //-----------------------------------------------------------------------------
-extended_protocol_discriminator_t pdu_session_create_sm_context::get_epd() const {
-  return m_epd;
+procedure_transaction_id_t pdu_session_msg::get_pti() const {
+  return m_pti;
 }
 
 //-----------------------------------------------------------------------------
-void pdu_session_create_sm_context::set_epd(
-    extended_protocol_discriminator_t const &epd) {
-  m_epd = epd;
+void pdu_session_msg::set_pti(
+    procedure_transaction_id_t const &pti) {
+  m_pti = pti;
 }
 
+
 //-----------------------------------------------------------------------------
-procedure_transaction_id_t pdu_session_create_sm_context::get_pti() const {
-  return m_pti;
+extended_protocol_discriminator_t pdu_session_create_sm_context::get_epd() const {
+  return m_epd;
 }
 
 //-----------------------------------------------------------------------------
-void pdu_session_create_sm_context::set_pti(
-    procedure_transaction_id_t const &pti) {
-  m_pti = pti;
+void pdu_session_create_sm_context::set_epd(
+    extended_protocol_discriminator_t const &epd) {
+  m_epd = epd;
 }
 
 //-----------------------------------------------------------------------------
@@ -370,6 +371,12 @@ void pdu_session_update_sm_context_request::add_qfi(pfcp::qfi_t const &qfi) {
   qfis.push_back(qfi);
 }
 
+//-----------------------------------------------------------------------------
+void pdu_session_update_sm_context_request::add_qfi(uint8_t const &q) {
+  pfcp::qfi_t qfi(q);
+  qfis.push_back(qfi);
+}
+
 //-----------------------------------------------------------------------------
 void pdu_session_update_sm_context_request::get_qfis(
     std::vector<pfcp::qfi_t> &q) {
@@ -412,17 +419,6 @@ void pdu_session_update_sm_context_request::set_an_type(
   m_an_type = value;
 }
 
-//-----------------------------------------------------------------------------
-procedure_transaction_id_t pdu_session_update_sm_context_response::get_pti() const {
-  return m_pti;
-}
-
-//-----------------------------------------------------------------------------
-void pdu_session_update_sm_context_response::set_pti(
-    procedure_transaction_id_t const &pti) {
-  m_pti = pti;
-}
-
 //-----------------------------------------------------------------------------
 void pdu_session_update_sm_context_response::set_cause(uint8_t cause) {
   m_cause = cause;
diff --git a/src/smf_app/smf_msg.hpp b/src/smf_app/smf_msg.hpp
index 9f2065d541c8fb028dcb84e92bd27ec6728da87d..f5641aca1930c418293d628215369b5e5f57a8f0 100644
--- a/src/smf_app/smf_msg.hpp
+++ b/src/smf_app/smf_msg.hpp
@@ -133,6 +133,9 @@ class pdu_session_msg {
   uint8_t get_pdu_session_type() const;
   void set_pdu_session_type(uint8_t const &pdu_session_type);
 
+  procedure_transaction_id_t get_pti() const;
+  void set_pti(procedure_transaction_id_t const &pti);
+
  private:
   pdu_session_msg_type_t m_msg_type;
   std::string m_api_root;
@@ -142,6 +145,7 @@ class pdu_session_msg {
   std::string m_dnn;
   snssai_t m_snssai;
   uint8_t m_pdu_session_type;
+  procedure_transaction_id_t m_pti;
 };
 
 //---------------------------------------------------------------------------------------
@@ -174,15 +178,11 @@ class pdu_session_create_sm_context : public pdu_session_msg {
   extended_protocol_discriminator_t get_epd() const;
   void set_epd(extended_protocol_discriminator_t const &epd);
 
-  procedure_transaction_id_t get_pti() const;
-  void set_pti(procedure_transaction_id_t const &pti);
-
   uint8_t get_message_type() const;
   void set_message_type(uint8_t const &message_type);
 
  private:
   extended_protocol_discriminator_t m_epd;
-  procedure_transaction_id_t m_pti;
   uint8_t m_message_type;
 };
 
@@ -420,6 +420,7 @@ class pdu_session_update_sm_context_request : public pdu_session_msg {
   bool n1_sm_msg_is_set() const;
   bool n2_sm_info_is_set() const;
   void add_qfi(pfcp::qfi_t const &qfi);
+  void add_qfi(uint8_t const &qfi);
   void get_qfis(std::vector<pfcp::qfi_t> &q);
   void set_dl_fteid(fteid_t const &t);
   void get_dl_fteid(fteid_t &t);
@@ -487,7 +488,6 @@ class pdu_session_update_sm_context_response : public pdu_session_msg {
   pdu_session_update_sm_context_response()
       :
       pdu_session_msg(PDU_SESSION_UPDATE_SM_CONTEXT_RESPONSE) {
-    m_pti = { };
     m_cause = 0;
     m_n1_sm_msg_is_set = false;
     m_n2_sm_info_is_set = false;
@@ -514,11 +514,8 @@ class pdu_session_update_sm_context_response : public pdu_session_msg {
       std::map<uint8_t, qos_flow_context_updated> &all_flows);
   void remove_all_qos_flow_context_updateds();
   nlohmann::json sm_context_updated_data;  //N1N2MessageTransferReqData from oai::amf::model
-  procedure_transaction_id_t get_pti() const;
-  void set_pti(procedure_transaction_id_t const &pti);
 
  private:
-  procedure_transaction_id_t m_pti;
   uint8_t m_cause;
   std::string m_n1_sm_message;  //N1 SM after decoding
   bool m_n1_sm_msg_is_set;
diff --git a/src/smf_app/smf_n11.cpp b/src/smf_app/smf_n11.cpp
index 153f5a03cc19a15516dd55db0d07982252de7777..90b7d3eadd70668b61b51c3c685d04b33efebf00 100644
--- a/src/smf_app/smf_n11.cpp
+++ b/src/smf_app/smf_n11.cpp
@@ -341,7 +341,7 @@ void smf_n11::send_pdu_session_update_sm_context_response(
       break;
 
     case session_management_procedures_type_e::PDU_SESSION_ESTABLISHMENT_UE_REQUESTED: {
-      Logger::smf_n11().debug("PDU_SESSION_ESTABLISHMENT_UE_REQUESTED");
+      Logger::smf_n11().info("PDU_SESSION_ESTABLISHMENT_UE_REQUESTED");
       std::string json_part =
           sm_context_res->res.sm_context_updated_data.dump();
       sm_context_res->http_response.headers()
@@ -353,7 +353,7 @@ void smf_n11::send_pdu_session_update_sm_context_response(
       break;
 
     case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED_STEP1: {
-      Logger::smf_n11().debug("PDU_SESSION_MODIFICATION_UE_INITIATED");
+      Logger::smf_n11().info("PDU_SESSION_MODIFICATION_UE_INITIATED");
 
       std::string boundary = "----Boundary";
       std::string json_part =
@@ -406,6 +406,26 @@ void smf_n11::send_pdu_session_update_sm_context_response(
     }
       break;
 
+    case session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP1: {
+      Logger::smf_n11().debug("PDU_SESSION_RELEASE_UE_REQUESTED_STEP1");
+
+      std::string boundary = "----Boundary";
+      std::string json_part =
+          sm_context_res->res.sm_context_updated_data.dump();
+      std::string n1_message = sm_context_res->res.get_n1_sm_message();
+      std::string n2_message = sm_context_res->res.get_n2_sm_information();
+      std::string body;
+
+      create_multipart_related_content(body, json_part, boundary, n1_message,
+                                       n2_message);
+      sm_context_res->http_response.headers()
+          .add<Pistache::Http::Header::ContentType>(
+          Pistache::Http::Mime::MediaType(
+              "multipart/related; boundary=" + boundary));
+      sm_context_res->http_response.send(Pistache::Http::Code::Ok, body);
+    }
+      break;
+
     default: {
       Logger::smf_n11().debug("Session management procedure: unknown!");
     }
diff --git a/src/smf_app/smf_n1_n2.cpp b/src/smf_app/smf_n1_n2.cpp
index 712d6fce9741f2da50aa2c629379402a12acd16f..6cd7c99a5af264770acf1b11e8b60b8b16f30304 100644
--- a/src/smf_app/smf_n1_n2.cpp
+++ b/src/smf_app/smf_n1_n2.cpp
@@ -56,6 +56,7 @@ extern "C" {
 #include "Ngap_QosFlowAddOrModifyRequestItem.h"
 #include "Ngap_PDUSessionResourceReleaseCommandTransfer.h"
 #include "dynamic_memory_check.h"
+#include "Ngap_PDUSessionResourceReleaseResponseTransfer.h"
 }
 
 #define BUF_LEN 512
@@ -104,15 +105,19 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
   //nas_msg.header.message_authentication_code = 0xffee;
 
   SM_msg *sm_msg = &nas_msg.plain.sm;
+  //Fill the content of SM header
+  //Extended Protocol Discriminator
   sm_msg->header.extended_protocol_discriminator =
       EPD_5GS_SESSION_MANAGEMENT_MESSAGES;
+  //Message Type
   sm_msg->header.pdu_session_identity = msg.get_pdu_session_id();
 
   switch (n1_msg_type) {
 
     //PDU Session Establishment Accept
     case PDU_SESSION_ESTABLISHMENT_ACCEPT: {
-      //PDU Session Establishment Accept is including in the N1N2MessageTransfer Request sent from SMF to AMF (PDU Session Establishment procedure)
+      //PDU Session Establishment Accept is including in the N1N2MessageTransfer Request
+      //sent from SMF to AMF (PDU Session Establishment procedure)
       if (msg.get_msg_type() != PDU_SESSION_CREATE_SM_CONTEXT_RESPONSE) {
         Logger::smf_app().error(
             "Cannot create an PDU Session Establishment Accept for this message (type %d)",
@@ -133,33 +138,30 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
       Logger::smf_app().info(
           "PDU_SESSION_ESTABLISHMENT_ACCEPT, encode starting...");
 
-      //Message Type
-      sm_msg->header.message_type = PDU_SESSION_ESTABLISHMENT_ACCEPT;
-
-      //Fill the content of PDU Session Establishment Request message with hardcoded values (to be completed)
+      //Fill the rest of SM header
       //PTI
       sm_msg->header.procedure_transaction_identity = sm_context_res.get_pti()
           .procedure_transaction_id;
-      Logger::smf_app().debug(
-          "Procedure_transaction_id %d",
-          sm_context_res.get_pti().procedure_transaction_id);
+      //Message Type
+      sm_msg->header.message_type = PDU_SESSION_ESTABLISHMENT_ACCEPT;
 
       Logger::smf_app().debug(
-          "NAS header, encode extended_protocol_discriminator: 0x%x, security_header_type: 0x%x",
+          "NAS header, Extended Protocol Discriminator 0x%x, Security Header Type 0x%x",
           nas_msg.header.extended_protocol_discriminator,
           nas_msg.header.security_header_type);
       Logger::smf_app().debug(
-          "SM header, extended_protocol_discriminator: 0x%x, pdu_session_identity: 0x%x, procedure_transaction_identity: 0x%x, message type: 0x%x",
+          "SM header, Extended Protocol Discriminator 0x%x, PDU Session Identity 0x%x, Procedure Transaction Identity: 0x%x, Message Type: 0x%x",
           sm_msg->header.extended_protocol_discriminator,
           sm_msg->header.pdu_session_identity,
           sm_msg->header.procedure_transaction_identity,
           sm_msg->header.message_type);
 
+      //Fill the content of PDU Session Establishment Request message
       //PDU Session Type
       sm_msg->pdu_session_establishment_accept._pdusessiontype
           .pdu_session_type_value = sm_context_res.get_pdu_session_type();
       Logger::smf_app().debug(
-          "PDUSessionType: %#0x",
+          "PDU Session Type: %#0x",
           sm_msg->pdu_session_establishment_accept._pdusessiontype
               .pdu_session_type_value);
 
@@ -170,8 +172,7 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
           "SSC Mode: %#0x",
           sm_msg->pdu_session_establishment_accept.sscmode.ssc_mode_value);
 
-      //authorized QoS rules of the PDU session: QOSRules
-      //Section 6.2.5@3GPP TS 24.501
+      //authorized QoS rules of the PDU session: QOSRules (Section 6.2.5@3GPP TS 24.501)
       //(Section 6.4.1.3@3GPP TS 24.501 V16.1.0) Make sure that the number of the packet filters used in the authorized QoS rules of the PDU Session does not
       // exceed the maximum number of packet filters supported by the UE for the PDU session
       sm_msg->pdu_session_establishment_accept.qosrules.lengthofqosrulesie = 1;
@@ -227,16 +228,6 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
             "SMF context with SUPI " SUPI_64_FMT " does not exist!", supi64);
         //TODO:
       }
-      Logger::smf_app().debug(
-          "SessionAMBR: %x %x %x %x",
-          sm_msg->pdu_session_establishment_accept.sessionambr
-              .uint_for_session_ambr_for_downlink,
-          sm_msg->pdu_session_establishment_accept.sessionambr
-              .session_ambr_for_downlink,
-          sm_msg->pdu_session_establishment_accept.sessionambr
-              .uint_for_session_ambr_for_uplink,
-          sm_msg->pdu_session_establishment_accept.sessionambr
-              .session_ambr_for_uplink);
 
       //Presence
       sm_msg->pdu_session_establishment_accept.presence = 0xffff;  //TODO: To be updated
@@ -245,7 +236,7 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
       sm_msg->pdu_session_establishment_accept._5gsmcause =
           static_cast<uint8_t>(sm_cause);
       Logger::smf_app().debug(
-          "5GSMCause: %#0x",
+          "5GSM Cause: %#0x",
           sm_msg->pdu_session_establishment_accept._5gsmcause);
 
       //PDUAddress
@@ -259,10 +250,6 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
           .s_addr) & 0x00ff0000) >> 16);
       bitStream_pdu_address_information[3] = (uint8_t) (((paa.ipv4_address
           .s_addr) & 0xff000000) >> 24);
-      bstring pdu_address_information = bfromcstralloc(4, "\0");
-      pdu_address_information->slen = 4;
-      memcpy(pdu_address_information->data, bitStream_pdu_address_information,
-             sizeof(bitStream_pdu_address_information));
 
       sm_msg->pdu_session_establishment_accept.pduaddress
           .pdu_address_information = bfromcstralloc(4, "\0");
@@ -274,9 +261,9 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
               .pdu_address_information->data,
           bitStream_pdu_address_information,
           sizeof(bitStream_pdu_address_information));
-      //sm_msg->pdu_session_establishment_accept.pduaddress.pdu_address_information = pdu_address_information;
+
       sm_msg->pdu_session_establishment_accept.pduaddress.pdu_session_type_value =
-          1;
+          static_cast<uint8_t>(PDU_SESSION_TYPE_E_IPV4);
       Logger::smf_app().debug("PDU Address %s",
                               conv::toString(paa.ipv4_address).c_str());
 
@@ -285,7 +272,7 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
       //sm_msg->pdu_session_establishment_accept.gprstimer.timeValue = 0;
 
       //SNSSAI
-      sm_msg->pdu_session_establishment_accept.snssai.len = SST_AND_SD_LENGHT;
+      sm_msg->pdu_session_establishment_accept.snssai.len = SST_AND_SD_LENGTH;
       sm_msg->pdu_session_establishment_accept.snssai.sst = sm_context_res
           .get_snssai().sST;
 
@@ -293,13 +280,13 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
         sm_msg->pdu_session_establishment_accept.snssai.sd = std::stoi(
             sm_context_res.get_snssai().sD);
       } catch (const std::exception &e) {
-        Logger::smf_app().warn("Undefined error: %s", e.what());
+        Logger::smf_app().warn("Error when converting from string to int for snssai.SD, error: %s", e.what());
         //"no SD value associated with the SST"
         sm_msg->pdu_session_establishment_accept.snssai.sd = 0xFFFFFF;
       }
 
       Logger::smf_app().debug(
-          "SNSSAI SST: %#0x, SD: %#0x",
+          "SNSSAI SST %#0x, SD %#0x",
           sm_msg->pdu_session_establishment_accept.snssai.sst,
           sm_msg->pdu_session_establishment_accept.snssai.sd);
 
@@ -339,7 +326,7 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
       std::string dnn_str(
           (char*) sm_msg->pdu_session_establishment_accept.dnn->data,
           sm_msg->pdu_session_establishment_accept.dnn->slen);
-      Logger::smf_app().debug("DNN: %s", dnn_str.c_str());
+      Logger::smf_app().debug("DNN %s", dnn_str.c_str());
 
       //Encode NAS message
       bytes = nas_message_encode(data, &nas_msg,
@@ -373,34 +360,40 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
       //3-  PDU Session Update SM Context Response (PDU Session Establishment procedure - reject)​
       //PDU_SESSION_CREATE_SM_CONTEXT_RESPONSE or  PDU_SESSION_CREATE_SM_CONTEXT_REQUEST
 
-      //TODO: to be completed
       Logger::smf_app().info(
-          "PDU_SESSION_CREATE_SM_CONTEXT_RESPONSE, NAS: PDU_SESSION_ESTABLISHMENT_REJECT");
+          "PDU_SESSION_ESTABLISHMENT_REJECT, encode starting...");
 
-      sm_msg->header.message_type = PDU_SESSION_ESTABLISHMENT_REJECT;
-
-      //Fill the content of PDU Session Establishment Request message with hardcoded values (to be completed)
+      //Fill the content of PDU Session Establishment Reject message
       //PDU Session ID
       sm_msg->header.pdu_session_identity = msg.get_pdu_session_id();
       //PTI
-      sm_msg->header.procedure_transaction_identity = 10;  //sm_context_res.get_pti().procedure_transaction_id;
+      sm_msg->header.procedure_transaction_identity = msg.get_pti()
+          .procedure_transaction_id;
+      //Message Type
+      sm_msg->header.message_type = PDU_SESSION_ESTABLISHMENT_REJECT;
       Logger::smf_app().debug(
-          "NAS header, extended protocol discriminator: 0x%x, security header type: 0x%x",
+          "NAS header, Extended Protocol Discriminator  0x%x, Security Header Type: 0x%x",
           nas_msg.header.extended_protocol_discriminator,
           nas_msg.header.security_header_type);
 
       Logger::smf_app().debug(
-          "SM header, pdu session identity: 0x%x, procedure transaction identity: 0x%x, message type: 0x%x",
+          "SM header, PDU Session Identity 0x%x, Procedure Transaction Identity 0x%x, Message Type 0x%x",
           sm_msg->header.pdu_session_identity,
           sm_msg->header.procedure_transaction_identity,
           sm_msg->header.message_type);
 
+      //5GSM Cause
       sm_msg->pdu_session_establishment_reject._5gsmcause =
           static_cast<uint8_t>(sm_cause);
-      sm_msg->pdu_session_establishment_reject.presence = 0x02;
-      sm_msg->pdu_session_establishment_reject.gprstimer3.unit =
-      GPRSTIMER3_VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_1_HOUR;
-      sm_msg->pdu_session_establishment_reject.gprstimer3.timeValue = 0;
+      //Presence
+      sm_msg->pdu_session_establishment_reject.presence = 0x00;
+      /*
+       //GPRSTimer3
+       sm_msg->pdu_session_establishment_reject.gprstimer3.unit =
+       GPRSTIMER3_VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_1_HOUR;
+       sm_msg->pdu_session_establishment_reject.gprstimer3.timeValue = 0;
+       */
+      //AllowedSSCMode
       sm_msg->pdu_session_establishment_reject.allowedsscmode.is_ssc1_allowed =
       SSC_MODE1_ALLOWED;
       sm_msg->pdu_session_establishment_reject.allowedsscmode.is_ssc2_allowed =
@@ -409,6 +402,7 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
       SSC_MODE3_NOT_ALLOWED;
 
       /*
+       //EAPMessage
        unsigned char bitStream_eapmessage[2] = {0x01,0x02};
        bstring eapmessage_tmp = bfromcstralloc(2, "\0");
        eapmessage_tmp->slen = 2;
@@ -416,6 +410,7 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
        sm_msg->pdu_session_establishment_reject.eapmessage = bfromcstralloc(2, "\0");
        sm_msg->pdu_session_establishment_reject.eapmessage->slen = 2;
 
+       //ExtendedProtocolConfigurationOptions
        unsigned char bitStream_extendedprotocolconfigurationoptions[4];
        bitStream_extendedprotocolconfigurationoptions[0] = 0x12;
        bitStream_extendedprotocolconfigurationoptions[1] = 0x13;
@@ -425,6 +420,8 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
        extendedprotocolconfigurationoptions_tmp->slen = 4;
        memcpy(extendedprotocolconfigurationoptions_tmp->data,bitStream_extendedprotocolconfigurationoptions,sizeof(bitStream_extendedprotocolconfigurationoptions));
        sm_msg->pdu_session_establishment_reject.extendedprotocolconfigurationoptions = extendedprotocolconfigurationoptions_tmp;
+
+       //5GSM CongestionReattemptIndicator
        sm_msg->pdu_session_establishment_reject._5gsmcongestionreattemptindicator.abo = THE_BACKOFF_TIMER_IS_APPLIED_IN_ALL_PLMNS;
        */
 
@@ -432,7 +429,7 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
           "SM MSG, 5GSM Cause: 0x%x",
           sm_msg->pdu_session_establishment_reject._5gsmcause);
       Logger::smf_app().debug(
-          "SM MSG, Allowed SSC Mode, ssc1 allowed: 0x%x, ssc2 allowed: 0x%x, sc3 allowed: 0x%x",
+          "SM MSG, Allowed SSC Mode, SSC1 allowed 0x%x, SSC2 allowed 0x%x, SSC3 allowed 0x%x",
           sm_msg->pdu_session_establishment_reject.allowedsscmode
               .is_ssc1_allowed,
           sm_msg->pdu_session_establishment_reject.allowedsscmode
@@ -622,6 +619,10 @@ void smf_n1_n2::create_n1_sm_container(pdu_session_msg &msg,
       //_5GSMCongestionReattemptIndicator
       // ExtendedProtocolConfigurationOptions
 
+      //Encode NAS message
+      bytes = nas_message_encode(data, &nas_msg,
+                                 sizeof(data)/*don't know the size*/, nullptr);
+
       Logger::smf_app().debug("Buffer Data: ");
       for (int i = 0; i < bytes; i++)
         printf("%02x ", data[i]);
@@ -1344,6 +1345,49 @@ void smf_n1_n2::create_n2_sm_information(pdu_session_msg &msg,
       free_wrapper((void**) &ngap_resource_release_command_transfer);
       free_wrapper((void**) &buffer);
 
+    }
+      break;
+
+      //PDU Session Resource Release Response Transfer
+      //FOR TESTING PURPOSE ONLY!!
+    case n2_sm_info_type_e::PDU_RES_REL_RSP: {
+      //PDU Session Resource Release Response Transfer IE
+      //This IE is included in:
+      //1 - PDU Session Update SM Context Request (PDU Session Release UE-Initiated, step 2 - UPLINK)
+
+      Ngap_PDUSessionResourceReleaseResponseTransfer_t *ngap_resource_release_response_transfer =
+          nullptr;
+      ngap_resource_release_response_transfer =
+          (Ngap_PDUSessionResourceReleaseResponseTransfer_t*) calloc(
+              1, sizeof(Ngap_PDUSessionResourceReleaseResponseTransfer_t));
+
+      //TODO: To be completed, here's an example
+      //encode
+      size_t buffer_size = 512;
+      char *buffer = (char*) calloc(1, buffer_size);
+
+      asn_enc_rval_t er = aper_encode_to_buffer(
+          &asn_DEF_Ngap_PDUSessionResourceReleaseResponseTransfer, nullptr,
+          ngap_resource_release_response_transfer, (void*) buffer, buffer_size);
+
+      if (er.encoded < 0) {
+        Logger::smf_app().warn(
+            "[Create N2 SM Information] NGAP PDU Session Release Command encode failed, er.encoded: %d",
+            er.encoded);
+        return;
+      }
+
+      Logger::smf_app().debug("N2 SM buffer data: ");
+      for (int i = 0; i < er.encoded; i++)
+        printf("%02x ", (char) buffer[i]);
+      Logger::smf_app().debug(" (%d bytes) \n", er.encoded);
+      std::string ngap_message((char*) buffer, er.encoded);
+      ngap_msg_str = ngap_message;
+
+      //free memory
+      free_wrapper((void**) &ngap_resource_release_response_transfer);
+      free_wrapper((void**) &buffer);
+
     }
       break;
 
diff --git a/src/smf_app/smf_procedure.cpp b/src/smf_app/smf_procedure.cpp
index 2f9048c26d95ec0df7460181bf282045a02f5f3b..4b8ab3d32927cc64bb84796977a8e812e4307a56 100644
--- a/src/smf_app/smf_procedure.cpp
+++ b/src/smf_app/smf_procedure.cpp
@@ -112,7 +112,6 @@ int session_create_sm_context_procedure::run(
   //-------------------
   n11_trigger = sm_context_req;
   n11_triggered_pending = sm_context_resp;
-  //ppc->generate_seid();
   uint64_t seid = smf_app_inst->generate_seid();
   ppc->set_seid(seid);
   itti_n4_session_establishment_request *n4_ser =
@@ -208,7 +207,6 @@ int session_create_sm_context_procedure::run(
   // DOIT simple
   // shall uniquely identify the PDR among all the PDRs configured for that PFCP session.
   ppc->generate_pdr_id(pdr_id);
-  //precedence.precedence = it.bearer_level_qos.pl; //TODO
 
   //get the default QoS profile
   subscribed_default_qos_t default_qos = { };
@@ -240,9 +238,9 @@ int session_create_sm_context_procedure::run(
   create_pdr.set(pdi);
 
   //wys-add-test
-  if (smf_cfg.test_upf_cfg.is_test)
-    create_pdr.set(outer_header_removal);
-  //create_pdr.set(outer_header_removal);
+  //if (smf_cfg.test_upf_cfg.is_test)
+  //  create_pdr.set(outer_header_removal);
+  create_pdr.set(outer_header_removal);
 
   create_pdr.set(far_id);
   //TODO: list of Usage reporting Rule IDs
@@ -426,14 +424,13 @@ void session_create_sm_context_procedure::handle_itti_msg(
   N1_SM_CONTENT_ID;  //NAS part
   //N2SM
   if (n11_triggered_pending->res.get_cause() == REQUEST_ACCEPTED) {
-    //TODO: fill the content of N1N2MessageTransferReqData
     n11_triggered_pending->res.n1n2_message_transfer_data["n2InfoContainer"]["n2InformationClass"] =
     N1N2_MESSAGE_CLASS;
     n11_triggered_pending->res.n1n2_message_transfer_data["n2InfoContainer"]["smInfo"]["PduSessionId"] =
         n11_triggered_pending->res.get_pdu_session_id();
     //N2InfoContent (section 6.1.6.2.27@3GPP TS 29.518)
     n11_triggered_pending->res.n1n2_message_transfer_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapIeType"] =
-        "PDU_RES_SETUP_REQ";  //NGAP message
+        "PDU_RES_SETUP_REQ";  //NGAP message type
     n11_triggered_pending->res.n1n2_message_transfer_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapData"]["contentId"] =
     N2_SM_CONTENT_ID;  //NGAP part
     n11_triggered_pending->res.n1n2_message_transfer_data["n2InfoContainer"]["smInfo"]["sNssai"]["sst"] =
@@ -495,7 +492,6 @@ int session_update_sm_context_procedure::run(
   n4_ser->r_endpoint = endpoint(up_node_id.u1.ipv4_address, pfcp::default_port);
   n4_triggered = std::shared_ptr<itti_n4_session_modification_request>(n4_ser);
 
-  //TODO: To be completed
   //qos Flow to be modified
   pdu_session_update_sm_context_request sm_context_req_msg = sm_context_req->req;
   std::vector<pfcp::qfi_t> list_of_qfis_to_be_modified = { };
@@ -505,191 +501,271 @@ int session_update_sm_context_procedure::run(
     Logger::smf_app().debug("qfi to be modified: %d", i.qfi);
   }
 
-  ::fteid_t dl_fteid = { };
-  sm_context_req_msg.get_dl_fteid(dl_fteid);  //eNB's fteid
+  switch (session_procedure_type) {
+    case session_management_procedures_type_e::PDU_SESSION_ESTABLISHMENT_UE_REQUESTED:
+    case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_SMF_REQUESTED:
+    case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_AN_REQUESTED:
+    case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED_STEP2: {
 
-  for (auto qfi : list_of_qfis_to_be_modified) {
-    smf_qos_flow qos_flow = { };
-    if (!ppc->get_qos_flow(qfi, qos_flow)) {  //no QoS flow found
-      Logger::smf_app().error(
-          "Update SM Context procedure: could not found QoS flow with QFI %d",
-          qfi.qfi);
-      //Set cause to SYSTEM_FAILURE and send response
-      qos_flow_context_updated qcu = { };
-      qcu.set_cause(SYSTEM_FAILURE);
-      qcu.set_qfi(qfi);
-      n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
-      continue;
-    }
-    pfcp::far_id_t far_id = { };
-    pfcp::pdr_id_t pdr_id = { };
-    if ((dl_fteid == qos_flow.dl_fteid) and (not qos_flow.released)) {
-      Logger::smf_app().debug(
-          "Update SM Context procedure: QFI %d dl_fteid unchanged", qfi.qfi);
-      qos_flow_context_updated qcu = { };
-      qcu.set_cause(REQUEST_ACCEPTED);
-      qcu.set_qfi(qfi);
-      n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
-      continue;
-    } else if ((qos_flow.far_id_dl.first)
-        && (qos_flow.far_id_dl.second.far_id)) {
-      Logger::smf_app().debug("Update SM Context procedure: Update FAR DL");
-      // Update FAR
-      far_id.far_id = qos_flow.far_id_dl.second.far_id;
-      pfcp::update_far update_far = { };
-      pfcp::apply_action_t apply_action = { };
-      pfcp::outer_header_creation_t outer_header_creation = { };
-      pfcp::update_forwarding_parameters update_forwarding_parameters = { };
-
-      update_far.set(qos_flow.far_id_dl.second);
-      outer_header_creation.outer_header_creation_description =
-          OUTER_HEADER_CREATION_GTPU_UDP_IPV4;
-      outer_header_creation.teid = dl_fteid.teid_gre_key;
-      outer_header_creation.ipv4_address.s_addr = dl_fteid.ipv4_address.s_addr;
-      update_forwarding_parameters.set(outer_header_creation);
-      update_far.set(update_forwarding_parameters);
-      apply_action.forw = 1;
-      update_far.set(apply_action);
-
-      n4_ser->pfcp_ies.set(update_far);
-
-      send_n4 = true;
-      qos_flow.far_id_dl.first = true;
+      ::fteid_t dl_fteid = { };
+      sm_context_req_msg.get_dl_fteid(dl_fteid);  //eNB's fteid
 
-    } else {
-      Logger::smf_app().debug("Update SM Context procedure: Create FAR DL");
-      //Create FAR
-      pfcp::create_far create_far = { };
-      pfcp::apply_action_t apply_action = { };
-      pfcp::forwarding_parameters forwarding_parameters = { };
-      //pfcp::duplicating_parameters      duplicating_parameters = {};
-      //pfcp::bar_id_t                    bar_id = {};
-
-      // forwarding_parameters IEs
-      pfcp::destination_interface_t destination_interface = { };
-      //pfcp::network_instance_t          network_instance = {};
-      //pfcp::redirect_information_t      redirect_information = {};
-      pfcp::outer_header_creation_t outer_header_creation = { };
-      //pfcp::transport_level_marking_t   transport_level_marking = {};
-      //pfcp::forwarding_policy_t         forwarding_policy = {};
-      //pfcp::header_enrichment_t         header_enrichment = {};
-      //pfcp::traffic_endpoint_id_t       linked_traffic_endpoint_id_t = {};
-      //pfcp::proxying_t                  proxying = {};
-
-      ppc->generate_far_id(far_id);
-      apply_action.forw = 1;
-
-      destination_interface.interface_value = pfcp::INTERFACE_VALUE_ACCESS;  // ACCESS is for downlink, CORE for uplink
-      forwarding_parameters.set(destination_interface);
-      outer_header_creation.outer_header_creation_description =
-          OUTER_HEADER_CREATION_GTPU_UDP_IPV4;
-      outer_header_creation.teid = dl_fteid.teid_gre_key;
-      outer_header_creation.ipv4_address.s_addr = dl_fteid.ipv4_address.s_addr;
-      forwarding_parameters.set(outer_header_creation);
-
-      create_far.set(far_id);
-      create_far.set(apply_action);
-      create_far.set(forwarding_parameters);
-      //-------------------
-      // ADD IEs to message
-      //-------------------
-      n4_ser->pfcp_ies.set(create_far);
-
-      send_n4 = true;
-
-      qos_flow.far_id_dl.first = true;
-      qos_flow.far_id_dl.second = far_id;
-    }
+      for (auto qfi : list_of_qfis_to_be_modified) {
+        smf_qos_flow qos_flow = { };
+        if (!ppc->get_qos_flow(qfi, qos_flow)) {  //no QoS flow found
+          Logger::smf_app().error(
+              "Update SM Context procedure: could not found QoS flow with QFI %d",
+              qfi.qfi);
+          //Set cause to SYSTEM_FAILURE and send response
+          qos_flow_context_updated qcu = { };
+          qcu.set_cause(SYSTEM_FAILURE);
+          qcu.set_qfi(qfi);
+          n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
+          continue;
+        }
+        pfcp::far_id_t far_id = { };
+        pfcp::pdr_id_t pdr_id = { };
+        if ((dl_fteid == qos_flow.dl_fteid) and (not qos_flow.released)) {
+          Logger::smf_app().debug(
+              "Update SM Context procedure: QFI %d dl_fteid unchanged",
+              qfi.qfi);
+          qos_flow_context_updated qcu = { };
+          qcu.set_cause(REQUEST_ACCEPTED);
+          qcu.set_qfi(qfi);
+          n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
+          continue;
+        } else if ((qos_flow.far_id_dl.first)
+            && (qos_flow.far_id_dl.second.far_id)) {
+          Logger::smf_app().debug("Update SM Context procedure: Update FAR DL");
+          // Update FAR
+          far_id.far_id = qos_flow.far_id_dl.second.far_id;
+          pfcp::update_far update_far = { };
+          pfcp::apply_action_t apply_action = { };
+          pfcp::outer_header_creation_t outer_header_creation = { };
+          pfcp::update_forwarding_parameters update_forwarding_parameters = { };
+
+          update_far.set(qos_flow.far_id_dl.second);
+          outer_header_creation.outer_header_creation_description =
+              OUTER_HEADER_CREATION_GTPU_UDP_IPV4;
+          outer_header_creation.teid = dl_fteid.teid_gre_key;
+          outer_header_creation.ipv4_address.s_addr = dl_fteid.ipv4_address
+              .s_addr;
+          update_forwarding_parameters.set(outer_header_creation);
+          update_far.set(update_forwarding_parameters);
+          apply_action.forw = 1;
+          update_far.set(apply_action);
+
+          n4_ser->pfcp_ies.set(update_far);
+
+          send_n4 = true;
+          qos_flow.far_id_dl.first = true;
 
-    if (not qos_flow.pdr_id_dl.rule_id) {
-      Logger::smf_app().debug("Update SM Context procedure, Create PDR DL");
-      //-------------------
-      // IE create_pdr
-      //-------------------
-      pfcp::create_pdr create_pdr = { };
-      pfcp::precedence_t precedence = { };
-      pfcp::pdi pdi = { };
-      //    pfcp::far_id_t                    far_id;
-      //    pfcp::urr_id_t                    urr_id;
-      //    pfcp::qer_id_t                    qer_id;
-      //    pfcp::activate_predefined_rules_t activate_predefined_rules;
-      // pdi IEs
-      pfcp::source_interface_t source_interface = { };
-      //pfcp::fteid_t                    local_fteid = {};
-      //pfcp::network_instance_t         network_instance = {};
-      pfcp::ue_ip_address_t ue_ip_address = { };
-      //pfcp::traffic_endpoint_id_t      traffic_endpoint_id = {};
-      pfcp::sdf_filter_t sdf_filter = { };
-      pfcp::application_id_t application_id = { };
-      //pfcp::ethernet_packet_filter     ethernet_packet_filter = {};
-      pfcp::qfi_t qfi = { };
-      //pfcp::framed_route_t             framed_route = {};
-      //pfcp::framed_routing_t           framed_routing = {};
-      //pfcp::framed_ipv6_route_t        framed_ipv6_route = {};
-      source_interface.interface_value = pfcp::INTERFACE_VALUE_CORE;
-
-      //local_fteid.from_core_fteid(peb.sgw_fteid_s5_s8_up);
-      if (ppc->ipv4) {
-        ue_ip_address.v4 = 1;
-        ue_ip_address.ipv4_address.s_addr = ppc->ipv4_address.s_addr;
-      }
-      if (ppc->ipv6) {
-        ue_ip_address.v6 = 1;
-        ue_ip_address.ipv6_address = ppc->ipv6_address;
+        } else {
+          Logger::smf_app().debug("Update SM Context procedure: Create FAR DL");
+          //Create FAR
+          pfcp::create_far create_far = { };
+          pfcp::apply_action_t apply_action = { };
+          pfcp::forwarding_parameters forwarding_parameters = { };
+          //pfcp::duplicating_parameters      duplicating_parameters = {};
+          //pfcp::bar_id_t                    bar_id = {};
+
+          // forwarding_parameters IEs
+          pfcp::destination_interface_t destination_interface = { };
+          //pfcp::network_instance_t          network_instance = {};
+          //pfcp::redirect_information_t      redirect_information = {};
+          pfcp::outer_header_creation_t outer_header_creation = { };
+          //pfcp::transport_level_marking_t   transport_level_marking = {};
+          //pfcp::forwarding_policy_t         forwarding_policy = {};
+          //pfcp::header_enrichment_t         header_enrichment = {};
+          //pfcp::traffic_endpoint_id_t       linked_traffic_endpoint_id_t = {};
+          //pfcp::proxying_t                  proxying = {};
+
+          ppc->generate_far_id(far_id);
+          apply_action.forw = 1;
+
+          destination_interface.interface_value = pfcp::INTERFACE_VALUE_ACCESS;  // ACCESS is for downlink, CORE for uplink
+          forwarding_parameters.set(destination_interface);
+          outer_header_creation.outer_header_creation_description =
+              OUTER_HEADER_CREATION_GTPU_UDP_IPV4;
+          outer_header_creation.teid = dl_fteid.teid_gre_key;
+          outer_header_creation.ipv4_address.s_addr = dl_fteid.ipv4_address
+              .s_addr;
+          forwarding_parameters.set(outer_header_creation);
+
+          create_far.set(far_id);
+          create_far.set(apply_action);
+          create_far.set(forwarding_parameters);
+
+          // Add IEs to message
+          n4_ser->pfcp_ies.set(create_far);
+
+          send_n4 = true;
+
+          qos_flow.far_id_dl.first = true;
+          qos_flow.far_id_dl.second = far_id;
+        }
+
+        if (not qos_flow.pdr_id_dl.rule_id) {
+          Logger::smf_app().debug("Update SM Context procedure, Create PDR DL");
+          //-------------------
+          // IE create_pdr
+          //-------------------
+          pfcp::create_pdr create_pdr = { };
+          pfcp::precedence_t precedence = { };
+          pfcp::pdi pdi = { };
+          //    pfcp::far_id_t                    far_id;
+          //    pfcp::urr_id_t                    urr_id;
+          //    pfcp::qer_id_t                    qer_id;
+          //    pfcp::activate_predefined_rules_t activate_predefined_rules;
+          // pdi IEs
+          pfcp::source_interface_t source_interface = { };
+          //pfcp::fteid_t                    local_fteid = {};
+          //pfcp::network_instance_t         network_instance = {};
+          pfcp::ue_ip_address_t ue_ip_address = { };
+          //pfcp::traffic_endpoint_id_t      traffic_endpoint_id = {};
+          pfcp::sdf_filter_t sdf_filter = { };
+          pfcp::application_id_t application_id = { };
+          //pfcp::ethernet_packet_filter     ethernet_packet_filter = {};
+          pfcp::qfi_t qfi = { };
+          //pfcp::framed_route_t             framed_route = {};
+          //pfcp::framed_routing_t           framed_routing = {};
+          //pfcp::framed_ipv6_route_t        framed_ipv6_route = {};
+          source_interface.interface_value = pfcp::INTERFACE_VALUE_CORE;
+
+          //local_fteid.from_core_fteid(qos_flow.qos_flow.dl_fteid);
+          if (ppc->ipv4) {
+            ue_ip_address.v4 = 1;
+            ue_ip_address.ipv4_address.s_addr = ppc->ipv4_address.s_addr;
+          }
+          if (ppc->ipv6) {
+            ue_ip_address.v6 = 1;
+            ue_ip_address.ipv6_address = ppc->ipv6_address;
+          }
+
+          // DOIT simple
+          // shall uniquely identify the PDR among all the PDRs configured for that PFCP session.
+          ppc->generate_pdr_id(pdr_id);
+          precedence.precedence = qos_flow.precedence.precedence;  //TODO: should be verified
+
+          pdi.set(source_interface);
+          //pdi.set(local_fteid);
+          pdi.set(ue_ip_address);
+
+          create_pdr.set(pdr_id);
+          create_pdr.set(precedence);
+          create_pdr.set(pdi);
+          create_pdr.set(far_id);
+
+          // Add IEs to message
+          n4_ser->pfcp_ies.set(create_pdr);
+
+          send_n4 = true;
+
+          qos_flow.pdr_id_dl = pdr_id;
+        } else {
+          Logger::smf_app().debug(
+              "Update SM Context procedure: Update FAR, qos_flow.pdr_id_dl.rule_id %d",
+              qos_flow.pdr_id_dl.rule_id);
+          // Update FAR
+          far_id.far_id = qos_flow.far_id_ul.second.far_id;
+          pfcp::update_far update_far = { };
+          pfcp::apply_action_t apply_action = { };
+
+          update_far.set(qos_flow.far_id_ul.second);
+          apply_action.forw = 1;
+          update_far.set(apply_action);
+
+          n4_ser->pfcp_ies.set(update_far);
+
+          send_n4 = true;
+
+          qos_flow.far_id_dl.first = true;
+        }
+        // after a release flows
+        if (not qos_flow.ul_fteid.is_zero()) {
+
+        }
+        // may be modified
+        smf_qos_flow qos_flow2 = qos_flow;
+        ppc->add_qos_flow(qos_flow2);
+
+        qos_flow_context_updated qcu = { };
+        qcu.set_cause(REQUEST_ACCEPTED);
+        qcu.set_qfi(qfi);
+        n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
       }
+    }
+      break;
 
-      // DOIT simple
-      // shall uniquely identify the PDR among all the PDRs configured for that PFCP session.
-      ppc->generate_pdr_id(pdr_id);
-      precedence.precedence = qos_flow.precedence.precedence;  //TODO: should be verified
+    case session_management_procedures_type_e::PDU_SESSION_RELEASE_NETWORK_REQUESTED:
+    case session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP1: {
 
-      pdi.set(source_interface);
-      //pdi.set(local_fteid);
-      pdi.set(ue_ip_address);
+      for (auto qfi : list_of_qfis_to_be_modified) {
+        smf_qos_flow qos_flow = { };
+        if (!ppc->get_qos_flow(qfi, qos_flow)) {  //no QoS flow found
+          Logger::smf_app().error(
+              "Update SM Context procedure: could not found QoS flow with QFI %d",
+              qfi.qfi);
+          //Set cause to SYSTEM_FAILURE and send response
+          qos_flow_context_updated qcu = { };
+          qcu.set_cause(SYSTEM_FAILURE);
+          qcu.set_qfi(qfi);
+          n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
+          continue;
+        }
 
-      create_pdr.set(pdr_id);
-      create_pdr.set(precedence);
-      create_pdr.set(pdi);
-      create_pdr.set(far_id);
-      //-------------------
-      // ADD IEs to message
-      //-------------------
-      n4_ser->pfcp_ies.set(create_pdr);
+        //for DL
+        if (qos_flow.far_id_dl.first) {
+          pfcp::update_far far = { };
+          pfcp::far_id_t far_id = { };
 
-      send_n4 = true;
+          far_id.far_id = qos_flow.far_id_dl.second.far_id;
+          // apply_action.buff = 1;
+          pfcp::apply_action_t apply_action = { };
+          apply_action.nocp = 1;
 
-      qos_flow.pdr_id_dl = pdr_id;
-    } else {
-      Logger::smf_app().debug(
-          "Update SM Context procedure: Update FAR, qos_flow.pdr_id_dl.rule_id %d",
-          qos_flow.pdr_id_dl.rule_id);
-      // Update FAR
-      far_id.far_id = qos_flow.far_id_ul.second.far_id;
-      pfcp::update_far update_far = { };
-      pfcp::apply_action_t apply_action = { };
+          far.set(far_id);
+          far.set(apply_action);
+          // Add IEs to message
+          n4_ser->pfcp_ies.set(far);
 
-      update_far.set(qos_flow.far_id_ul.second);
-      apply_action.forw = 1;
-      update_far.set(apply_action);
+          send_n4 = true;
 
-      n4_ser->pfcp_ies.set(update_far);
+        } else {
+          Logger::smf_app().info(
+              "Update SM Context procedure , could not get FAR ID of QoS Flow ID %d",
+              qos_flow.qfi.qfi);
+        }
 
-      send_n4 = true;
+        //for UL
+        if (qos_flow.far_id_ul.first) {
+          pfcp::update_far far = { };
+          pfcp::far_id_t far_id = { };
+          far_id.far_id = qos_flow.far_id_ul.second.far_id;
+          pfcp::apply_action_t apply_action = { };
+          apply_action.drop = 1;
+
+          far.set(far_id);
+          far.set(apply_action);
+          // Add IEs to message
+          n4_ser->pfcp_ies.set(far);
+          send_n4 = true;
+        }
 
-      qos_flow.far_id_dl.first = true;
+        //update in the PDU Session
+        qos_flow.release_qos_flow();
+        smf_qos_flow qos_flow2 = qos_flow;
+        ppc->add_qos_flow(qos_flow2);
+      }
     }
-    // after a release flows
-    if (not qos_flow.ul_fteid.is_zero()) {
 
+      break;
+    default: {
+      Logger::smf_app().error(
+          "Update SM Context procedure: Unknown session management type %d",
+          session_procedure_type);
     }
-    // may be modified
-    smf_qos_flow qos_flow2 = qos_flow;
-    ppc->add_qos_flow(qos_flow2);
-
-    qos_flow_context_updated qcu = { };
-    qcu.set_cause(REQUEST_ACCEPTED);
-    qcu.set_qfi(qfi);
-    n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
+
   }
 
   if (send_n4) {
@@ -703,18 +779,11 @@ int session_update_sm_context_procedure::run(
       return RETURNerror ;
     }
   } else {
-    // send to AMF, update response
-    //TODO: to be completed
-    Logger::smf_app().info("Sending ITTI message %s to task TASK_SMF_N11",
-                           n11_triggered_pending->get_msg_name());
-    int ret = itti_inst->send_msg(n11_triggered_pending);
-    if (RETURNok != ret) {
-      Logger::smf_app().error(
-          "Could not send ITTI message %s to task TASK_SMF_N11",
-          n11_triggered_pending->get_msg_name());
-    }
-    return RETURNclear ;
+    Logger::smf_app().error(
+        "Update SM Context procedure: There is no QoS flow to be modified");
+    return RETURNerror ;
   }
+
   return RETURNok ;
 
 }
@@ -744,102 +813,49 @@ void session_update_sm_context_procedure::handle_itti_msg(
   //list of accepted QFI(s) and AN Tunnel Info corresponding to the PDU Session
   std::vector<pfcp::qfi_t> list_of_qfis_to_be_modified = { };
   n11_trigger->req.get_qfis(list_of_qfis_to_be_modified);
-  ::fteid_t dl_fteid = { };
-  n11_trigger->req.get_dl_fteid(dl_fteid);
-
-  std::map<uint8_t, qos_flow_context_updated> qos_flow_context_to_be_updateds =
-      { };
-  n11_triggered_pending->res.get_all_qos_flow_context_updateds(
-      qos_flow_context_to_be_updateds);
-  n11_triggered_pending->res.remove_all_qos_flow_context_updateds();
-
-  for (std::map<uint8_t, qos_flow_context_updated>::iterator it =
-      qos_flow_context_to_be_updateds.begin();
-      it != qos_flow_context_to_be_updateds.end(); ++it)
-    Logger::smf_app().debug("qos_flow_context_to_be_modifieds qfi %d",
-                            it->first);
-
-  for (auto it_created_pdr : resp.pfcp_ies.created_pdrs) {
-    pfcp::pdr_id_t pdr_id = { };
-    if (it_created_pdr.get(pdr_id)) {
-      smf_qos_flow flow = { };
-      if (ppc->get_qos_flow(pdr_id, flow)) {
-        Logger::smf_app().debug("QoS Flow,  qfi %d", flow.qfi.qfi);
-        for (auto it : qos_flow_context_to_be_updateds) {
-          flow.dl_fteid = dl_fteid;
-          flow.dl_fteid.interface_type = S1_U_ENODEB_GTP_U;  //eNB's N3 interface
-          // flow.ul_fteid = it.second.ul_fteid;
-          pfcp::fteid_t local_up_fteid = { };
-          if (it_created_pdr.get(local_up_fteid)) {
-            xgpp_conv::pfcp_to_core_fteid(local_up_fteid, flow.ul_fteid);
-            flow.ul_fteid.interface_type = S1_U_SGW_GTP_U;  //UPF's N3 interface, TODO: should be modified
-            Logger::smf_app().warn("got local_up_fteid from created_pdr %s",
-                                   flow.ul_fteid.toString().c_str());
-          } else {
-            //UPF doesn't include its fteid in the response
-            Logger::smf_app().warn(
-                "Could not get local_up_fteid from created_pdr");
-          }
-
-          flow.released = false;
-          smf_qos_flow flow2 = flow;
-          ppc->add_qos_flow(flow2);
-
-          qos_flow_context_updated qcu = { };
-          qcu.set_cause(REQUEST_ACCEPTED);
-          qcu.set_qfi(pfcp::qfi_t(it.first));
-          qcu.set_ul_fteid(flow.ul_fteid);
-          qcu.set_dl_fteid(flow.dl_fteid);
-          qcu.set_qos_profile(flow.qos_profile);
-          n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
-          //TODO: remove this QFI from the list (as well as in n11_trigger->req)
-          break;
 
-        }
-        /*
-         for (auto qfi: list_of_qfis_to_be_modified){
-         pfcp::fteid_t local_up_fteid = {};
-         if (it_created_pdr.get(local_up_fteid)) {
-         xgpp_conv::pfcp_to_core_fteid(local_up_fteid, flow.ul_fteid);
-         flow.ul_fteid.interface_type = S5_S8_PGW_GTP_U; //TODO: should be modified
-
-         Logger::smf_app().error( "got local_up_fteid from created_pdr %s", flow.ul_fteid.toString().c_str());
-         } else {
-         Logger::smf_app().error( "Could not get local_up_fteid from created_pdr");
-         }
-
-         flow.released = false;
-         smf_qos_flow flow2 = flow;
-         ppc->add_qos_flow(flow2);
-
-         qos_flow_context_updated qcu = {};
-         qcu.set_cause(REQUEST_ACCEPTED);
-         qcu.set_qfi(qfi);
-         qcu.set_ul_fteid(flow.ul_fteid);
-         n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
-         //TODO: remove this QFI from the list (as well as in n11_trigger->req)
-         break;
-
-         }
-         */
-      }
-    } else {
-      Logger::smf_app().error("Could not get pdr_id for created_pdr in %s",
-                              resp.pfcp_ies.get_msg_name());
-    }
-  }
+  switch (session_procedure_type) {
+    case session_management_procedures_type_e::PDU_SESSION_ESTABLISHMENT_UE_REQUESTED:
+    case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_SMF_REQUESTED:
+    case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_AN_REQUESTED:
+    case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED_STEP2: {
 
-  if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) {
-    // TODO failed rule id
-    for (auto it_update_far : n4_triggered->pfcp_ies.update_fars) {
-      pfcp::far_id_t far_id = { };
-      if (it_update_far.get(far_id)) {
-        smf_qos_flow flow = { };
-        if (ppc->get_qos_flow(far_id, flow)) {
-          //for (auto qfi: list_of_qfis_to_be_modified){
-          for (auto it : qos_flow_context_to_be_updateds) {
-            if (it.first == flow.qfi.qfi) {
+      ::fteid_t dl_fteid = { };
+      n11_trigger->req.get_dl_fteid(dl_fteid);
+
+      std::map<uint8_t, qos_flow_context_updated> qos_flow_context_to_be_updateds =
+          { };
+      n11_triggered_pending->res.get_all_qos_flow_context_updateds(
+          qos_flow_context_to_be_updateds);
+      n11_triggered_pending->res.remove_all_qos_flow_context_updateds();
+
+      for (auto it : qos_flow_context_to_be_updateds)
+        Logger::smf_app().debug("qos_flow_context_to_be_modifieds qfi %d",
+                                it.first);
+
+      for (auto it_created_pdr : resp.pfcp_ies.created_pdrs) {
+        pfcp::pdr_id_t pdr_id = { };
+        if (it_created_pdr.get(pdr_id)) {
+          smf_qos_flow flow = { };
+          if (ppc->get_qos_flow(pdr_id, flow)) {
+            Logger::smf_app().debug("QoS Flow,  qfi %d", flow.qfi.qfi);
+            for (auto it : qos_flow_context_to_be_updateds) {
               flow.dl_fteid = dl_fteid;
+              flow.dl_fteid.interface_type = S1_U_ENODEB_GTP_U;  //eNB's N3 interface
+              // flow.ul_fteid = it.second.ul_fteid;
+              pfcp::fteid_t local_up_fteid = { };
+              if (it_created_pdr.get(local_up_fteid)) {
+                xgpp_conv::pfcp_to_core_fteid(local_up_fteid, flow.ul_fteid);
+                flow.ul_fteid.interface_type = S1_U_SGW_GTP_U;  //UPF's N3 interface, TODO: should be modified
+                Logger::smf_app().warn("got local_up_fteid from created_pdr %s",
+                                       flow.ul_fteid.toString().c_str());
+              } else {
+                //UPF doesn't include its fteid in the response
+                Logger::smf_app().warn(
+                    "Could not get local_up_fteid from created_pdr");
+              }
+
+              flow.released = false;
               smf_qos_flow flow2 = flow;
               ppc->add_qos_flow(flow2);
 
@@ -850,38 +866,80 @@ void session_update_sm_context_procedure::handle_itti_msg(
               qcu.set_dl_fteid(flow.dl_fteid);
               qcu.set_qos_profile(flow.qos_profile);
               n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
+              //TODO: remove this QFI from the list (as well as in n11_trigger->req)
               break;
+
             }
           }
         } else {
-          Logger::smf_app().error(
-              "Could not get qos flow for far_id for update_far in %s",
-              resp.pfcp_ies.get_msg_name());
+          Logger::smf_app().error("Could not get pdr_id for created_pdr in %s",
+                                  resp.pfcp_ies.get_msg_name());
+        }
+      }
+
+      if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) {
+        // TODO failed rule id
+        for (auto it_update_far : n4_triggered->pfcp_ies.update_fars) {
+          pfcp::far_id_t far_id = { };
+          if (it_update_far.get(far_id)) {
+            smf_qos_flow flow = { };
+            if (ppc->get_qos_flow(far_id, flow)) {
+              //for (auto qfi: list_of_qfis_to_be_modified){
+              for (auto it : qos_flow_context_to_be_updateds) {
+                if (it.first == flow.qfi.qfi) {
+                  flow.dl_fteid = dl_fteid;
+                  smf_qos_flow flow2 = flow;
+                  ppc->add_qos_flow(flow2);
+
+                  qos_flow_context_updated qcu = { };
+                  qcu.set_cause(REQUEST_ACCEPTED);
+                  qcu.set_qfi(pfcp::qfi_t(it.first));
+                  qcu.set_ul_fteid(flow.ul_fteid);
+                  qcu.set_dl_fteid(flow.dl_fteid);
+                  qcu.set_qos_profile(flow.qos_profile);
+                  n11_triggered_pending->res.add_qos_flow_context_updated(qcu);
+                  break;
+                }
+              }
+            } else {
+              Logger::smf_app().error(
+                  "Could not get QoS flow for far_id for update_far in %s",
+                  resp.pfcp_ies.get_msg_name());
+            }
+          } else {
+            Logger::smf_app().error("Could not get far_id for update_far in %s",
+                                    resp.pfcp_ies.get_msg_name());
+          }
         }
       } else {
-        Logger::smf_app().error("Could not get far_id for update_far in %s",
-                                resp.pfcp_ies.get_msg_name());
+        Logger::smf_app().info(
+            "PDU Session Update SM Context, rejected by UPF");
+        //send response to AMF
+        oai::smf_server::model::SmContextUpdateError smContextUpdateError = { };
+        oai::smf_server::model::ProblemDetails problem_details = { };
+        problem_details.setCause(
+            pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_NETWORK_FAILURE]);
+        smContextUpdateError.setError(problem_details);
+        smf_n11_inst->send_pdu_session_update_sm_context_response(
+            n11_triggered_pending->http_response, smContextUpdateError,
+            Pistache::Http::Code::Forbidden);
+        return;
       }
+
+    }
+      break;
+
+    case session_management_procedures_type_e::PDU_SESSION_RELEASE_NETWORK_REQUESTED:
+    case session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP1: {
+
+      if (cause.cause_value == CAUSE_VALUE_REQUEST_ACCEPTED) {
+        Logger::smf_app().info(
+            "PDU Session Update SM Context (PDU Session Release) accepted by UPF");
+        //clear the resources including addresses allocated to this Session and associated QoS flows
+        ppc->deallocate_ressources(n11_trigger.get()->req.get_dnn());  //TODO: for IPv6 (only for Ipv4 for the moment)
+      }
+
     }
-  } else {
-    Logger::smf_app().info("PDU Session Update SM Context, rejected by UPF");
-    //send PDU Session Establishment Reject to AMF
-    oai::smf_server::model::SmContextUpdateError smContextUpdateError = { };
-    oai::smf_server::model::ProblemDetails problem_details = { };
-    oai::smf_server::model::RefToBinaryData refToBinaryData = { };
-    problem_details.setCause(
-        pdu_session_application_error_e2str[PDU_SESSION_APPLICATION_ERROR_NETWORK_FAILURE]);
-    smContextUpdateError.setError(problem_details);
-    refToBinaryData.setContentId(N1_SM_CONTENT_ID);
-    smContextUpdateError.setN1SmMsg(refToBinaryData);
-    smf_n1_n2_inst.create_n1_sm_container(
-        n11_triggered_pending->res, PDU_SESSION_ESTABLISHMENT_REJECT, n1_sm_msg,
-        cause_value_5gsm_e::CAUSE_38_NETWORK_FAILURE);
-    smf_app_inst->convert_string_2_hex(n1_sm_msg, n1_sm_msg_hex);
-    smf_n11_inst->send_pdu_session_update_sm_context_response(
-        n11_triggered_pending->http_response, smContextUpdateError,
-        Pistache::Http::Code::Forbidden, n1_sm_msg_hex);
-    return;
   }
 
   n11_triggered_pending->res.set_cause(cause.cause_value);
@@ -928,7 +986,7 @@ void session_update_sm_context_procedure::handle_itti_msg(
       n11_triggered_pending->res.set_n1_sm_message(n1_sm_msg_hex);
       //N2 SM Information
       smf_n1_n2_inst.create_n2_sm_information(
-          n11_triggered_pending->res, 1, n2_sm_info_type_e::PDU_RES_MOD_REQ,
+          n11_triggered_pending->res, 1, n2_sm_info_type_e::PDU_RES_REL_RSP,
           n2_sm_info);
       smf_app_inst->convert_string_2_hex(n2_sm_info, n2_sm_info_hex);
       n11_triggered_pending->res.set_n2_sm_information(n2_sm_info_hex);
@@ -937,7 +995,7 @@ void session_update_sm_context_procedure::handle_itti_msg(
       n11_triggered_pending->res.sm_context_updated_data =
           sm_context_updated_data;
       n11_triggered_pending->res.sm_context_updated_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapIeType"] =
-          "PDU_RES_MOD_REQ";  //NGAP message
+          "PDU_RES_REL_RSP";  //NGAP message
     }
       break;
 
@@ -949,19 +1007,9 @@ void session_update_sm_context_procedure::handle_itti_msg(
       n11_triggered_pending->res.sm_context_updated_data["cause"] =
           n11_triggered_pending->res.get_cause();
 
-      //Send session status update to SMF APP
-      std::shared_ptr<itti_n11_update_pdu_session_status> itti_status =
-          std::make_shared<itti_n11_update_pdu_session_status>(TASK_SMF_APP,
-                                                               TASK_SMF_APP);
-      itti_status->set_scid(std::stoi(n11_trigger->scid));
-      itti_status->set_pdu_session_status(
-          pdu_session_status_e::PDU_SESSION_ACTIVE);
-      int ret = itti_inst->send_msg(itti_status);
-      if (RETURNok != ret) {
-        Logger::smf_app().error(
-            "Could not send ITTI message %s to task TASK_SMF_APP",
-            itti_status->get_msg_name());
-      }
+      //Update PDU session status to ACTIVE
+      ppc->set_pdu_session_status(pdu_session_status_e::PDU_SESSION_ACTIVE);
+
     }
       break;
 
@@ -1016,6 +1064,11 @@ void session_update_sm_context_procedure::handle_itti_msg(
           sm_context_updated_data;
       n11_triggered_pending->res.sm_context_updated_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapIeType"] =
           "PDU_RES_MOD_REQ";  //NGAP message
+
+      //Update PDU session status to PDU_SESSION_MODIFICATION_PENDING
+      ppc->set_pdu_session_status(
+          pdu_session_status_e::PDU_SESSION_MODIFICATION_PENDING);
+
     }
       break;
 
@@ -1023,7 +1076,7 @@ void session_update_sm_context_procedure::handle_itti_msg(
     case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED_STEP2: {
       //No need to create N1/N2 Container
       Logger::smf_app().info("PDU Session Modification UE-initiated (Step 2)");
-      //TODO:
+      //TODO: To be completed
     }
       break;
 
@@ -1031,7 +1084,7 @@ void session_update_sm_context_procedure::handle_itti_msg(
     case session_management_procedures_type_e::PDU_SESSION_MODIFICATION_UE_INITIATED_STEP3: {
       //No need to create N1/N2 Container
       Logger::smf_app().info("PDU Session Modification UE-initiated (Step 3)");
-      //TODO:
+      //TODO: To be completed
     }
       break;
 
@@ -1044,7 +1097,7 @@ void session_update_sm_context_procedure::handle_itti_msg(
       //N1 SM
       smf_n1_n2_inst.create_n1_sm_container(
           n11_triggered_pending->res, PDU_SESSION_RELEASE_COMMAND, n1_sm_msg,
-          cause_value_5gsm_e::CAUSE_0_UNKNOWN);  //TODO: need cause?
+          cause_value_5gsm_e::CAUSE_26_INSUFFICIENT_RESOURCES);  //TODO: check Cause
       smf_app_inst->convert_string_2_hex(n1_sm_msg, n1_sm_msg_hex);
       n11_triggered_pending->res.set_n1_sm_message(n1_sm_msg_hex);
       //N2 SM Information
@@ -1060,6 +1113,19 @@ void session_update_sm_context_procedure::handle_itti_msg(
       n11_triggered_pending->res.sm_context_updated_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapIeType"] =
           "PDU_RES_REL_CMD";  //NGAP message
 
+      //Update PDU session status to PDU_SESSION_INACTIVE_PENDING
+      ppc->set_pdu_session_status(
+          pdu_session_status_e::PDU_SESSION_INACTIVE_PENDING);
+
+      //TODO: To be completed
+      //TODO: start timer T3592 (see Section 6.3.3@3GPP TS 24.501)
+      //get smf_pdu_session and set the corresponding timer
+      ppc->timer_T3592 = itti_inst->timer_setup(
+          T3591_TIMER_VALUE_SEC, 0, TASK_SMF_APP, TASK_SMF_APP_TRIGGER_T3592,
+          n11_trigger->req.get_pdu_session_id());
+
+      //TODO: How SMF can retransmit the PDU SESSION RELEASE COMMAND message on the expiry of the timer T3592
+
     }
       break;
 
@@ -1067,7 +1133,7 @@ void session_update_sm_context_procedure::handle_itti_msg(
     case session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP2: {
       //No need to create N1/N2 Container
       Logger::smf_app().info("PDU Session Release UE-initiated (Step 2)");
-      //TODO:
+      //TODO: To be completed
     }
       break;
 
@@ -1075,7 +1141,7 @@ void session_update_sm_context_procedure::handle_itti_msg(
     case session_management_procedures_type_e::PDU_SESSION_RELEASE_UE_REQUESTED_STEP3: {
       //No need to create N1/N2 Container
       Logger::smf_app().info("PDU Session Release UE-initiated (Step 3)");
-      //TODO:
+      //TODO: To be completed
     }
       break;
 
diff --git a/src/smf_app/smf_procedure.hpp b/src/smf_app/smf_procedure.hpp
index 0bf612bcb65a4645dab7c869f9532112e0b4f472..8a4c77673a137db02000d7499e62c3cb25f0265f 100644
--- a/src/smf_app/smf_procedure.hpp
+++ b/src/smf_app/smf_procedure.hpp
@@ -171,6 +171,43 @@ class session_update_sm_context_procedure : public smf_procedure {
 
 };
 
+
+//------------------------------------------------------------------------------
+class session_release_pdu_session_procedure : public smf_procedure {
+ public:
+  explicit session_release_pdu_session_procedure(
+      std::shared_ptr<smf_pdu_session> &sppc)
+      :
+      smf_procedure(),
+      ppc(sppc),
+      n4_triggered(),
+      n11_triggered_pending(),
+      n11_trigger(),
+      session_procedure_type() {
+  }
+
+  int run(std::shared_ptr<itti_n11_update_sm_context_request> req,
+          std::shared_ptr<itti_n11_update_sm_context_response> resp,
+          std::shared_ptr<smf::smf_context> sc);
+  /*
+   * Handle N4 modification response from UPF
+   * @param [itti_n4_session_modification_response] resp
+   * @param [std::shared_ptr<smf::smf_context>] sc smf context
+   * @return void
+   */
+  void handle_itti_msg(itti_n4_session_modification_response &resp,
+                       std::shared_ptr<smf::smf_context> sc);
+
+  std::shared_ptr<itti_n4_session_modification_request> n4_triggered;
+  std::shared_ptr<smf_pdu_session> ppc;
+  std::shared_ptr<smf::smf_context> pc;
+
+  std::shared_ptr<itti_n11_update_sm_context_request> n11_trigger;
+  std::shared_ptr<itti_n11_update_sm_context_response> n11_triggered_pending;
+  session_management_procedures_type_e session_procedure_type;
+
+};
+
 }
 #include "../smf_app/smf_context.hpp"
 
diff --git a/src/test/amf_client/amf-client.cpp b/src/test/amf_client/amf-client.cpp
index 0419c1aaa07dabec3f17e81a8ae5d58720399e4f..7e1126d829cde3a17810a939669e1b3855f14953 100644
--- a/src/test/amf_client/amf-client.cpp
+++ b/src/test/amf_client/amf-client.cpp
@@ -24,24 +24,24 @@ static std::size_t callback(
 
 void send_pdu_session_establishment_request(std::string smf_ip_address)
 {
-  std::cout << "[AMF N11] PDU Session Establishment Request"<<std::endl;
+  std::cout << "[AMF N11] PDU Session Establishment Request (SM Context Create)"<<std::endl;
 
   nlohmann::json pdu_session_establishment_request;
   //encode
+  // PDU Session Establishment Request
   /*
     0000   2e 01 01 c1 ff ff 91 00 00 00 00 00 00 00 00 00
    */
   size_t buffer_size = 128;
   char *buffer = (char *)calloc(1,buffer_size);
   int  size = 0;
-  ENCODE_U8 (buffer, 0x2e , size);
-  ENCODE_U8 (buffer+size, 0x01 , size);
-  ENCODE_U8 (buffer+size, 0x01 , size);
-  ENCODE_U8 (buffer+size, 0xc1 , size);
-  ENCODE_U8 (buffer+size, 0xff , size);
-  ENCODE_U8 (buffer+size, 0xff , size);
-  //    ENCODE_U8 (buffer+size, 0x00 , size);
-  ENCODE_U8 (buffer+size, 0x91 , size);
+  ENCODE_U8 (buffer, 0x2e , size); //ExtendedProtocolDiscriminator
+  ENCODE_U8 (buffer+size, 0x01 , size); //PDUSessionIdentity
+  ENCODE_U8 (buffer+size, 0x01 , size); //ProcedureTransactionIdentity
+  ENCODE_U8 (buffer+size, 0xc1 , size); //MessageType - PDU_SESSION_ESTABLISHMENT_REQUEST
+  ENCODE_U8 (buffer+size, 0xff , size); //Integrity Protection Maximum Data Rate
+  ENCODE_U8 (buffer+size, 0xff , size); //Integrity Protection Maximum Data Rate
+  ENCODE_U8 (buffer+size, 0x91 , size); //01 PDU Session Type - Ipv4
 
   std::cout << "Buffer: "<<std::endl;
   for(int i=0;i<size;i++)
@@ -105,7 +105,7 @@ void send_pdu_session_establishment_request(std::string smf_ip_address)
     //curl_mime_data(part, reinterpret_cast<const char*>(n1_msg_hex), CURL_ZERO_TERMINATED);
     curl_mime_data(part, reinterpret_cast<const char*>(buffer), size);
     curl_mime_type(part, "application/vnd.3gpp.5gnas");
-    //curl_mime_name (part, "n1SmMsg");
+    curl_mime_name (part, "n1SmMsg");
 
     curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
 
@@ -140,11 +140,12 @@ void send_pdu_session_establishment_request(std::string smf_ip_address)
 
 void send_pdu_session_update_sm_context_establishment(std::string smf_ip_address)
 {
-  std::cout << "[AMF N11] send_pdu_session_update_sm_context_establishment"<<std::endl;
+  std::cout << "[AMF N11] PDU Session Establishment Request (SM Context Update)"<<std::endl;
 
   nlohmann::json pdu_session_update_request;
 
   //encode
+  //PDU Session Resource Setup Response Transfer IE
   /*
   00 03 e0 ac 0a 05 01 00 00 00 01 00 3c
    */
@@ -154,16 +155,16 @@ void send_pdu_session_update_sm_context_establishment(std::string smf_ip_address
   ENCODE_U8 (buffer, 0x00 , size);
   ENCODE_U8 (buffer+size, 0x03 , size);
   ENCODE_U8 (buffer+size, 0xe0 , size);
-  ENCODE_U8 (buffer+size, 0xac , size);
-  ENCODE_U8 (buffer+size, 0x0a , size);
-  ENCODE_U8 (buffer+size, 0x05 , size);
-  ENCODE_U8 (buffer+size, 0x01 , size);
-  ENCODE_U8 (buffer+size, 0x00 , size);
-  ENCODE_U8 (buffer+size, 0x00 , size);
-  ENCODE_U8 (buffer+size, 0x00 , size);
-  ENCODE_U8 (buffer+size, 0x01 , size);
-  ENCODE_U8 (buffer+size, 0x00 , size);
-  ENCODE_U8 (buffer+size, 0x3c , size);  //QFI: 60
+  ENCODE_U8 (buffer+size, 0xac , size); //uPTransportLayerInformation IP Addr 172.10.5.1: 172.
+  ENCODE_U8 (buffer+size, 0x0a , size); //10
+  ENCODE_U8 (buffer+size, 0x05 , size); //.5
+  ENCODE_U8 (buffer+size, 0x01 , size); //.1
+  ENCODE_U8 (buffer+size, 0x00 , size); //gTP_TEID 00 00 00 01: 00
+  ENCODE_U8 (buffer+size, 0x00 , size); //00
+  ENCODE_U8 (buffer+size, 0x00 , size); //00
+  ENCODE_U8 (buffer+size, 0x01 , size); //01
+  ENCODE_U8 (buffer+size, 0x00 , size); //Associated QoS Flow 00 3c
+  ENCODE_U8 (buffer+size, 0x3c , size); //QFI: 60
 
   std::cout << "Buffer: "<<std::endl;
   for(int i=0;i<2;i++)
@@ -173,7 +174,6 @@ void send_pdu_session_update_sm_context_establishment(std::string smf_ip_address
   std::cout << "Buffer: "<<std::endl;
 
   //Fill Json part
-  //std::string url = std::string("http://172.16.1.101/nsmf-pdusession/v2/sm-contexts/imsi-200000000000001/modify");
   std::string url = std::string("http://");
   url.append(smf_ip_address);
   url.append(std::string("/nsmf-pdusession/v2/sm-contexts/1/modify"));
@@ -241,7 +241,309 @@ void send_pdu_session_update_sm_context_establishment(std::string smf_ip_address
       //Set the default Cause
       response_data["cause"] = "504 Gateway Timeout";
     }
-    std::cout << "[AMF N11] PDU session modification request, response from SMF, Http Code " << httpCode << " cause  "<<  response_data["cause"].dump().c_str()<<std::endl;
+    std::cout << "[AMF N11] PDU Session Establishment Request, response from SMF, Http Code " << httpCode << " cause  "<<  response_data["cause"].dump().c_str()<<std::endl;
+
+    curl_slist_free_all(headers);
+    curl_easy_cleanup(curl);
+    curl_mime_free(mime);
+  }
+  free(buffer);
+}
+
+
+void send_pdu_session_release_request(std::string smf_ip_address)
+{
+  std::cout << "[AMF N11] PDU Session Release Request (SM Context Update)"<<std::endl;
+
+  nlohmann::json pdu_session_release_request;
+  //encode
+  /*
+    0000   2e 01 01 d1 00 00 00 00 00 00 00 00 00 00 00 00
+   */
+  size_t buffer_size = 128;
+  char *buffer = (char *)calloc(1,buffer_size);
+  int  size = 0;
+  ENCODE_U8 (buffer, 0x2e , size); //ExtendedProtocolDiscriminator
+  ENCODE_U8 (buffer+size, 0x01 , size); //PDUSessionIdentity
+  ENCODE_U8 (buffer+size, 0x01 , size); //ProcedureTransactionIdentity
+  ENCODE_U8 (buffer+size, 0xd1 , size); //MessageType
+  ENCODE_U8 (buffer+size, 0x00 , size); //presence
+
+  std::cout << "Buffer: "<<std::endl;
+  for(int i=0;i<size;i++)
+  {
+    printf("%02x ", buffer[i]);
+  }
+  std::cout << "Buffer: "<<std::endl;
+
+  //Fill Json part
+  std::string url = std::string("http://");
+  url.append(smf_ip_address);
+  url.append(std::string("/nsmf-pdusession/v2/sm-contexts/1/modify"));
+
+  //Fill the json part
+  pdu_session_release_request["cause"] = "INSUFFICIENT_UP_RESOURCES"; //need to be updated
+  pdu_session_release_request["n1SmMsg"]["contentId"] = "n1SmMsg"; // NAS
+
+  CURL *curl = curl_easy_init();
+
+  std::string json_part = pdu_session_release_request.dump();
+
+  std::cout<< "Sending message to SMF....\n";
+  if(curl) {
+    CURLcode res;
+    struct curl_slist *headers = nullptr;
+    struct curl_slist *slist = nullptr;
+    curl_mime *mime;
+    curl_mime *alt;
+    curl_mimepart *part;
+
+    //headers = curl_slist_append(headers, "charsets: utf-8");
+    headers = curl_slist_append(headers, "content-type: multipart/related");
+    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+    curl_easy_setopt(curl, CURLOPT_HTTPGET,1);
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 100L);
+    //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:amf"); //hardcoded
+
+    mime = curl_mime_init(curl);
+    alt = curl_mime_init(curl);
+
+    //part with N1N2MessageTransferReqData (JsonData)
+    part = curl_mime_addpart(mime);
+    curl_mime_data(part, json_part.c_str(), CURL_ZERO_TERMINATED);
+    curl_mime_type(part, "application/json");
+
+    part = curl_mime_addpart(mime);
+    //curl_mime_data(part, reinterpret_cast<const char*>(n1_msg_hex), CURL_ZERO_TERMINATED);
+    curl_mime_data(part, reinterpret_cast<const char*>(buffer), size);
+    curl_mime_type(part, "application/vnd.3gpp.5gnas");
+    //curl_mime_name (part, "n1SmMsg");
+
+    curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
+
+    // Response information.
+    long httpCode(0);
+    std::unique_ptr<std::string> httpData(new std::string());
+
+    // Hook up data handling function.
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
+
+    res = curl_easy_perform(curl);
+    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
+
+    //get cause from the response
+    nlohmann::json response_data;
+    try{
+      response_data = nlohmann::json::parse(*httpData.get());
+    } catch (nlohmann::json::exception& e){
+      std::cout << "Could not get the cause from the response" <<std::endl;
+
+    }
+    std::cout << "[AMF N11] PDU Session Release Request, response from SMF, Http Code " << httpCode <<std::endl;
+
+    curl_slist_free_all(headers);
+    curl_easy_cleanup(curl);
+    curl_mime_free(mime);
+  }
+  free(buffer);
+}
+
+void send_pdu_session_release_resource_release_ack(std::string smf_ip_address)
+{
+  std::cout << "[AMF N11] PDU Session Release Ack (Update SM Context): N2 SM - Resource Release Ack"<<std::endl;
+
+  nlohmann::json pdu_session_release_ack;
+  //encode
+  size_t buffer_size = 128;
+  char *buffer = (char *)calloc(1,buffer_size);
+  int  size = 0;
+  ENCODE_U8 (buffer, 0x00 , size);
+
+
+  std::cout << "Buffer: "<<std::endl;
+  for(int i=0;i<size;i++)
+  {
+    printf("%02x ", buffer[i]);
+  }
+  std::cout << "Buffer: "<<std::endl;
+
+  //Fill Json part
+  std::string url = std::string("http://");
+  url.append(smf_ip_address);
+  url.append(std::string("/nsmf-pdusession/v2/sm-contexts/1/modify"));
+
+  //Fill the json part
+
+  //Fill the json part
+  pdu_session_release_ack["n2SmInfoType"] = "PDU_RES_REL_RSP";
+  pdu_session_release_ack["n2SmInfo"]["contentId"] = "n2SmMsg"; //NGAP
+
+  CURL *curl = curl_easy_init();
+
+  std::string json_part = pdu_session_release_ack.dump();
+
+  std::cout<< "Sending message to SMF....\n";
+  if(curl) {
+    CURLcode res;
+    struct curl_slist *headers = nullptr;
+    struct curl_slist *slist = nullptr;
+    curl_mime *mime;
+    curl_mime *alt;
+    curl_mimepart *part;
+
+    //headers = curl_slist_append(headers, "charsets: utf-8");
+    headers = curl_slist_append(headers, "content-type: multipart/related");
+    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+    curl_easy_setopt(curl, CURLOPT_HTTPGET,1);
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 100L);
+    //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:amf"); //hardcoded
+
+    mime = curl_mime_init(curl);
+    alt = curl_mime_init(curl);
+
+    //part with N1N2MessageTransferReqData (JsonData)
+    part = curl_mime_addpart(mime);
+    curl_mime_data(part, json_part.c_str(), CURL_ZERO_TERMINATED);
+    curl_mime_type(part, "application/json");
+
+    part = curl_mime_addpart(mime);
+    //curl_mime_data(part, reinterpret_cast<const char*>(n1_msg_hex), CURL_ZERO_TERMINATED);
+    curl_mime_data(part, reinterpret_cast<const char*>(buffer), size);
+    curl_mime_type(part, "application/vnd.3gpp.ngap");
+    curl_mime_name (part, "n2SmMsg");
+
+    curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
+
+    // Response information.
+    long httpCode(0);
+    std::unique_ptr<std::string> httpData(new std::string());
+
+    // Hook up data handling function.
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
+
+    res = curl_easy_perform(curl);
+    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
+
+    //get cause from the response
+    nlohmann::json response_data;
+    try{
+      response_data = nlohmann::json::parse(*httpData.get());
+    } catch (nlohmann::json::exception& e){
+      std::cout << "Could not get the cause from the response" <<std::endl;
+
+    }
+    std::cout << "[AMF N11] PDU Session Release Ack, response from SMF, Http Code " << httpCode <<std::endl;
+
+    curl_slist_free_all(headers);
+    curl_easy_cleanup(curl);
+    curl_mime_free(mime);
+  }
+  free(buffer);
+}
+
+
+
+void send_pdu_session_release_complete(std::string smf_ip_address)
+{
+  std::cout << "[AMF N11] PDU Session Release Complete (Update SM Context): N1 SM - PDU Session Release Complete"<<std::endl;
+
+  nlohmann::json pdu_session_release_complete;
+  //encode
+  /*
+    0000   2e 01 01 c1 d4 00 00 00 00 00 00 00 00 00 00 00
+   */
+  size_t buffer_size = 128;
+  char *buffer = (char *)calloc(1,buffer_size);
+  int  size = 0;
+  ENCODE_U8 (buffer, 0x2e , size); //ExtendedProtocolDiscriminator
+  ENCODE_U8 (buffer+size, 0x01 , size); //PDUSessionIdentity
+  ENCODE_U8 (buffer+size, 0x01 , size); //ProcedureTransactionIdentity
+  ENCODE_U8 (buffer+size, 0xd4 , size); //MessageType
+  ENCODE_U8 (buffer+size, 0x00 , size); //Cause
+  ENCODE_U8 (buffer+size, 0x00 , size); //Extended protocol configuration options
+
+
+  std::cout << "Buffer: "<<std::endl;
+  for(int i=0;i<size;i++)
+  {
+    printf("%02x ", buffer[i]);
+  }
+  std::cout << "Buffer: "<<std::endl;
+
+  //Fill Json part
+  std::string url = std::string("http://");
+  url.append(smf_ip_address);
+  url.append(std::string("/nsmf-pdusession/v2/sm-contexts/1/modify"));
+
+  //Fill the json part
+  pdu_session_release_complete["cause"] = "INSUFFICIENT_UP_RESOURCES"; //need to be updated
+  pdu_session_release_complete["n1SmMsg"]["contentId"] = "n1SmMsg"; // NAS
+
+  //pdu_session_release_complete["n1MessageContainer"]["n1MessageClass"] = "SM";
+  //pdu_session_release_complete["n1MessageContainer"]["n1MessageContent"]["contentId"] = "n1SmMsg";
+
+
+  CURL *curl = curl_easy_init();
+
+  std::string json_part = pdu_session_release_complete.dump();
+
+  std::cout<< "Sending message to SMF....\n";
+  if(curl) {
+    CURLcode res;
+    struct curl_slist *headers = nullptr;
+    struct curl_slist *slist = nullptr;
+    curl_mime *mime;
+    curl_mime *alt;
+    curl_mimepart *part;
+
+    //headers = curl_slist_append(headers, "charsets: utf-8");
+    headers = curl_slist_append(headers, "content-type: multipart/related");
+    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+    curl_easy_setopt(curl, CURLOPT_HTTPGET,1);
+    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 100L);
+    //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:amf"); //hardcoded
+
+    mime = curl_mime_init(curl);
+    alt = curl_mime_init(curl);
+
+    //part with N1N2MessageTransferReqData (JsonData)
+    part = curl_mime_addpart(mime);
+    curl_mime_data(part, json_part.c_str(), CURL_ZERO_TERMINATED);
+    curl_mime_type(part, "application/json");
+
+    part = curl_mime_addpart(mime);
+    //curl_mime_data(part, reinterpret_cast<const char*>(n1_msg_hex), CURL_ZERO_TERMINATED);
+    curl_mime_data(part, reinterpret_cast<const char*>(buffer), size);
+    curl_mime_type(part, "application/vnd.3gpp.5gnas");
+    curl_mime_name (part, "n1SmMsg");
+
+    curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
+
+    // Response information.
+    long httpCode(0);
+    std::unique_ptr<std::string> httpData(new std::string());
+
+    // Hook up data handling function.
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
+
+    res = curl_easy_perform(curl);
+    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
+
+    //get cause from the response
+    nlohmann::json response_data;
+    try{
+      response_data = nlohmann::json::parse(*httpData.get());
+    } catch (nlohmann::json::exception& e){
+      std::cout << "Could not get the cause from the response" <<std::endl;
+
+    }
+    std::cout << "[AMF N11] PDU Session Release Complete, response from SMF, Http Code " << httpCode <<std::endl;
 
     curl_slist_free_all(headers);
     curl_easy_cleanup(curl);
@@ -250,6 +552,8 @@ void send_pdu_session_update_sm_context_establishment(std::string smf_ip_address
   free(buffer);
 }
 
+
+
 int main(int argc, char* argv[])
 {
   std::string smf_ip_address;
@@ -278,9 +582,17 @@ int main(int argc, char* argv[])
     }
   }
 
+  //PDU Session Establishment procedure
   send_pdu_session_establishment_request(smf_ip_address);
   usleep(100000);
   send_pdu_session_update_sm_context_establishment(smf_ip_address);
+  usleep(200000);
+  //PDU Session Release procedure
+  send_pdu_session_release_request(smf_ip_address);
+  usleep(200000);
+  send_pdu_session_release_resource_release_ack(smf_ip_address);
+  usleep(200000);
+  send_pdu_session_release_complete(smf_ip_address);
   return 0;
 }