From 4ce48382a3356ebc2cb1bc4da3d7f5b4a63355fe Mon Sep 17 00:00:00 2001
From: Tien-Thinh Nguyen <Tien-Thinh.nguyen@eurecom.fr>
Date: Tue, 21 Apr 2020 15:27:13 +0200
Subject: [PATCH] update SMF client/SMF_n11 to display correctly N1/N2 messages
 in wireshark

---
 src/smf_app/smf_n11.cpp            | 282 ++++++-----
 src/test/amf_client/amf-client.cpp | 748 ++++++++++++++++-------------
 2 files changed, 582 insertions(+), 448 deletions(-)

diff --git a/src/smf_app/smf_n11.cpp b/src/smf_app/smf_n11.cpp
index 90b7d3ea..ab9004a3 100644
--- a/src/smf_app/smf_n11.cpp
+++ b/src/smf_app/smf_n11.cpp
@@ -44,6 +44,10 @@
 #include "smf_config.hpp"
 #include "smf_n1_n2.hpp"
 
+extern "C" {
+#include "dynamic_memory_check.h"
+}
+
 using namespace Pistache::Http;
 using namespace Pistache::Http::Mime;
 
@@ -124,152 +128,63 @@ void smf_n11::send_n1n2_message_transfer_request(
     std::shared_ptr<itti_n11_create_sm_context_response> sm_context_res) {
   //Transfer N1/N2 message via AMF by using N_amf_Communication_N1N2MessageTransfer (see TS29518_Namf_Communication.yaml)
   //TODO: use RestSDK for client, use curl to send data for the moment
+
   Logger::smf_n11().debug("Send Communication_N1N2MessageTransfer to AMF");
 
   smf_n1_n2 smf_n1_n2_inst = { };
+  std::string n1_message = sm_context_res->res.get_n1_sm_message();
+  std::string json_part = sm_context_res->res.n1n2_message_transfer_data.dump();
+  std::string boundary = "----Boundary";
+  std::string body;
 
-  pdu_session_create_sm_context_response context_res_msg = sm_context_res->res;
-  std::string n1_message = context_res_msg.get_n1_sm_message();
-
-  /*
-   ENABLE THIS TO TEST NAS PDU SESSION ESTABLISHMENT ACCEPT
-   Don't forget to disable Http_response in SMF CONTEXT
-
-   std::string json_part = context_res_msg.n1n2_message_transfer_data.dump();
-   std::string boundary = "----Boundary";
-   std::string body;
-
-   create_multipart_related_content(body, json_part, boundary, n1_message, multipart_related_content_part_e::NAS);
-   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);
-   */
-
-  /*
-   //format string as hex
-   unsigned char *msg_hex  = smf_app_inst->format_string_as_hex(n1_message);
-
-   string CRLF = "\r\n";
-   body.append("--" + boundary + CRLF);
-   body.append("Content-Type: application/json" + CRLF);
-   body.append(CRLF);
-   body.append(json_part + CRLF);
-
-   body.append("--" + boundary + CRLF);
-   //NAS
-   body.append("Content-Type: application/vnd.3gpp.5gnas"+  CRLF + "Content-Id: n1SmMsg" + CRLF);
-
-   body.append(CRLF);
-   body.append(std::string((char *)msg_hex, n1_message.length()/2) + CRLF);
-   body.append("--" + boundary + "--" + CRLF);
-
-   CURL *curl;
-   CURLcode res;
-
-
-   curl_global_init(CURL_GLOBAL_ALL);
-
-   curl = curl_easy_init();
-   if(curl) {
-   struct curl_slist *headers = nullptr;
-   //headers = curl_slist_append(headers, "charsets: utf-8");
-   headers = curl_slist_append(headers, "content-type: multipart/related; boundary=----Boundary");
-   curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
-   curl_easy_setopt(curl, CURLOPT_URL, context_res_msg.get_amf_url().c_str() );
-
-   curl_easy_setopt(curl, CURLOPT_HTTPGET,1);
-   curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, AMF_CURL_TIMEOUT_MS);
-   //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:sn11"); //Only for testing in all-in-one scenario
-   curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
-
-   res = curl_easy_perform(curl);
-
-   if(res != CURLE_OK)
-   fprintf(stderr, "curl_easy_perform() failed: %s\n",
-   curl_easy_strerror(res));
-
-   curl_easy_cleanup(curl);
-   }
-   curl_global_cleanup();
+  //add N2 content if available
+  auto n2_sm_found = sm_context_res->res.n1n2_message_transfer_data.count(
+      "n2InfoContainer");
+  if (n2_sm_found > 0) {
+    std::string n2_message = sm_context_res->res.get_n2_sm_information();
+    //prepare the body content for Curl
+    create_multipart_related_content(body, json_part, boundary, n1_message,
+                                     n2_message);
+  } else {
+    //prepare the body content for Curl
+    create_multipart_related_content(body, json_part, boundary, n1_message,
+                                     multipart_related_content_part_e::NAS);
+  }
 
-   */
-
-  //format string as hex
-  unsigned char *n1_msg_hex = smf_app_inst->format_string_as_hex(n1_message);
+  unsigned int str_len = body.length();
+  char *data = (char*) malloc(str_len + 1);
+  memset(data, 0, str_len + 1);
+  memcpy((void*) data, (void*) body.c_str(), str_len);
 
+  curl_global_init(CURL_GLOBAL_ALL);
   CURL *curl = curl_easy_init();
 
-  //N1N2MessageTransfer Notification URI??
-  std::string json_part = context_res_msg.n1n2_message_transfer_data.dump();
-
-  Logger::smf_n11().debug("Sending message to AMF....");
-
   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");
+    headers = curl_slist_append(
+        headers, "content-type: multipart/related; boundary=----Boundary");  //TODO: update Boundary
     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
-    curl_easy_setopt(curl, CURLOPT_URL, context_res_msg.get_amf_url().c_str());
+    curl_easy_setopt(curl, CURLOPT_URL,
+                     sm_context_res->res.get_amf_url().c_str());
     curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
     curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, AMF_CURL_TIMEOUT_MS);
     curl_easy_setopt(curl, CURLOPT_INTERFACE, smf_cfg.sbi.if_name.c_str());
 
-    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");
-
-    //N1 SM Container
-    Logger::smf_n11().debug(
-        "Add N1 SM Container (NAS) into the message: %s (bytes %d)",
-        context_res_msg.get_n1_sm_message().c_str(),
-        context_res_msg.get_n1_sm_message().length() / 2);
-    part = curl_mime_addpart(mime);
-    curl_mime_data(part, reinterpret_cast<const char*>(n1_msg_hex),
-                   context_res_msg.get_n1_sm_message().length() / 2);
-    curl_mime_type(part, "application/vnd.3gpp.5gnas");
-    curl_mime_name(
-        part,
-        context_res_msg.n1n2_message_transfer_data["n1MessageContainer"]["n1MessageContent"]["contentId"]
-            .dump().c_str());
-
-    auto n2_sm_found = context_res_msg.n1n2_message_transfer_data.count(
-        "n2InfoContainer");
-    if (n2_sm_found > 0) {
-      std::string n2_message = context_res_msg.get_n2_sm_information();
-      unsigned char *n2_msg_hex = smf_app_inst->format_string_as_hex(
-          n2_message);
-      Logger::smf_n11().debug(
-          "Add N2 SM Information (NGAP) into the message: %s (bytes %d)",
-          n2_message.c_str(), n2_message.length() / 2);
-      part = curl_mime_addpart(mime);
-      curl_mime_data(part, reinterpret_cast<const char*>(n2_msg_hex), 80);  //TODO: n2_message.length()/2 ISSUE need to be solved
-      curl_mime_type(part, "application/vnd.3gpp.ngap");
-      curl_mime_name(
-          part,
-          context_res_msg.n1n2_message_transfer_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapData"]["contentId"]
-              .dump().c_str());
-    }
-
-    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.
+    // Hook up data handling function
     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback);
     curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
 
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
+
     res = curl_easy_perform(curl);
+
     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
 
     //get cause from the response
@@ -291,7 +206,7 @@ void smf_n11::send_n1n2_message_transfer_request(
     itti_msg->set_response_code(httpCode);
     itti_msg->set_scid(sm_context_res->scid);
     itti_msg->set_cause(response_data["cause"]);
-    if (context_res_msg.get_cause() == REQUEST_ACCEPTED) {
+    if (sm_context_res->res.get_cause() == REQUEST_ACCEPTED) {
       itti_msg->set_msg_type(PDU_SESSION_ESTABLISHMENT_ACCEPT);
     } else {
       itti_msg->set_msg_type(PDU_SESSION_ESTABLISHMENT_REJECT);
@@ -308,9 +223,130 @@ void smf_n11::send_n1n2_message_transfer_request(
 
     curl_slist_free_all(headers);
     curl_easy_cleanup(curl);
-    curl_mime_free(mime);
   }
+  curl_global_cleanup();
+  free_wrapper((void**) &data);
+
+  /*
+   //Curl MIME
+   //format string as hex
+   unsigned char *n1_msg_hex = smf_app_inst->format_string_as_hex(n1_message);
+
+   CURL *curl = curl_easy_init();
 
+   //N1N2MessageTransfer Notification URI??
+   std::string json_part = context_res_msg.n1n2_message_transfer_data.dump();
+
+   Logger::smf_n11().debug("Sending message to AMF....");
+
+   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, context_res_msg.get_amf_url().c_str());
+   curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
+   curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, AMF_CURL_TIMEOUT_MS);
+   curl_easy_setopt(curl, CURLOPT_INTERFACE, smf_cfg.sbi.if_name.c_str());
+
+   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");
+
+   //N1 SM Container
+   Logger::smf_n11().debug(
+   "Add N1 SM Container (NAS) into the message: %s (bytes %d)",
+   context_res_msg.get_n1_sm_message().c_str(),
+   context_res_msg.get_n1_sm_message().length() / 2);
+   part = curl_mime_addpart(mime);
+   curl_mime_data(part, reinterpret_cast<const char*>(n1_msg_hex),
+   context_res_msg.get_n1_sm_message().length() / 2);
+   curl_mime_type(part, "application/vnd.3gpp.5gnas");
+   curl_mime_name(
+   part,
+   context_res_msg.n1n2_message_transfer_data["n1MessageContainer"]["n1MessageContent"]["contentId"]
+   .dump().c_str());
+
+   auto n2_sm_found = context_res_msg.n1n2_message_transfer_data.count(
+   "n2InfoContainer");
+   if (n2_sm_found > 0) {
+   std::string n2_message = context_res_msg.get_n2_sm_information();
+   unsigned char *n2_msg_hex = smf_app_inst->format_string_as_hex(
+   n2_message);
+   Logger::smf_n11().debug(
+   "Add N2 SM Information (NGAP) into the message: %s (bytes %d)",
+   n2_message.c_str(), n2_message.length() / 2);
+   part = curl_mime_addpart(mime);
+   curl_mime_data(part, reinterpret_cast<const char*>(n2_msg_hex), 80);  //TODO: n2_message.length()/2 ISSUE need to be solved
+   curl_mime_type(part, "application/vnd.3gpp.ngap");
+   curl_mime_name(
+   part,
+   context_res_msg.n1n2_message_transfer_data["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapData"]["contentId"]
+   .dump().c_str());
+   }
+
+   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
+   json response_data = { };
+   try {
+   response_data = json::parse(*httpData.get());
+   } catch (json::exception &e) {
+   Logger::smf_n11().error("Could not get the cause from the response");
+   //Set the default Cause
+   response_data["cause"] = "504 Gateway Timeout";
+   }
+   Logger::smf_n11().debug("Response from AMF, Http Code: %d, cause %s",
+   httpCode, response_data["cause"].dump().c_str());
+
+   //send response to APP to process
+   itti_n11_n1n2_message_transfer_response_status *itti_msg =
+   new itti_n11_n1n2_message_transfer_response_status(TASK_SMF_N11,
+   TASK_SMF_APP);
+   itti_msg->set_response_code(httpCode);
+   itti_msg->set_scid(sm_context_res->scid);
+   itti_msg->set_cause(response_data["cause"]);
+   if (context_res_msg.get_cause() == REQUEST_ACCEPTED) {
+   itti_msg->set_msg_type(PDU_SESSION_ESTABLISHMENT_ACCEPT);
+   } else {
+   itti_msg->set_msg_type(PDU_SESSION_ESTABLISHMENT_REJECT);
+   }
+   std::shared_ptr<itti_n11_n1n2_message_transfer_response_status> i =
+   std::shared_ptr<itti_n11_n1n2_message_transfer_response_status>(
+   itti_msg);
+   int ret = itti_inst->send_msg(i);
+   if (RETURNok != ret) {
+   Logger::smf_n11().error(
+   "Could not send ITTI message %s to task TASK_SMF_APP",
+   i->get_msg_name());
+   }
+
+   curl_slist_free_all(headers);
+   curl_easy_cleanup(curl);
+   curl_mime_free(mime);
+   }
+   */
 }
 
 //------------------------------------------------------------------------------
diff --git a/src/test/amf_client/amf-client.cpp b/src/test/amf_client/amf-client.cpp
index 7e1126d8..cb15918d 100644
--- a/src/test/amf_client/amf-client.cpp
+++ b/src/test/amf_client/amf-client.cpp
@@ -1,18 +1,15 @@
-
 #include <curl/curl.h>
 #include <nlohmann/json.hpp>
 #include <iostream>
 #include <string>
 #include <unistd.h>
+#include <stdexcept>
+
 /*
  * To read content of the response from UDM
  */
-static std::size_t callback(
-    const char* in,
-    std::size_t size,
-    std::size_t num,
-    std::string* out)
-{
+static std::size_t callback(const char *in, std::size_t size, std::size_t num,
+                            std::string *out) {
   const std::size_t totalBytes(size * num);
   out->append(in, totalBytes);
   return totalBytes;
@@ -22,35 +19,177 @@ static std::size_t callback(
     *(uint8_t*)(buffer) = value;    \
     size += sizeof(uint8_t)
 
-void send_pdu_session_establishment_request(std::string smf_ip_address)
-{
-  std::cout << "[AMF N11] PDU Session Establishment Request (SM Context Create)"<<std::endl;
+static const char hex_to_ascii_table[16] = { '0', '1', '2', '3', '4', '5', '6',
+    '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', };
+
+static const signed char ascii_to_hex_table[0x100] = { -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1,
+    10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1 };
+
+int ascii_to_hex(uint8_t *dst, const char *h) {
+  const unsigned char *hex = (const unsigned char*) h;
+  unsigned i = 0;
+
+  for (;;) {
+    int high, low;
+
+    while (*hex && isspace(*hex))
+      hex++;
+
+    if (!*hex)
+      return 1;
+
+    high = ascii_to_hex_table[*hex++];
+
+    if (high < 0)
+      return 0;
+
+    while (*hex && isspace(*hex))
+      hex++;
+
+    if (!*hex)
+      return 0;
+
+    low = ascii_to_hex_table[*hex++];
+
+    if (low < 0)
+      return 0;
+
+    dst[i++] = (high << 4) | low;
+  }
+}
+
+enum class multipart_related_content_part_e {
+  JSON = 0,
+  NAS = 1,
+  NGAP = 2
+};
+
+unsigned char* format_string_as_hex(std::string str) {
+  unsigned int str_len = str.length();
+  char *data = (char*) malloc(str_len + 1);
+  memset(data, 0, str_len + 1);
+  memcpy((void*) data, (void*) str.c_str(), str_len);
+
+  unsigned char *data_hex = (uint8_t*) malloc(str_len / 2 + 1);
+  ascii_to_hex(data_hex, (const char*) data);
+
+  std::cout << "[Format string as Hex] Input string" << str.c_str() << "("
+            << str_len << " bytes)" << std::endl;
+  std::cout << "Data (formatted):" << std::endl;
+
+  for (int i = 0; i < str_len / 2; i++)
+    printf(" %02x ", data_hex[i]);
+  printf("\n");
+
+  //free memory
+  free(data);
+
+  return data_hex;
+
+}
+
+//------------------------------------------------------------------------------
+void create_multipart_related_content(std::string &body, std::string &json_part,
+                                      std::string &boundary,
+                                      std::string &n1_message,
+                                      std::string &n2_message) {
+
+  //format string as hex
+  unsigned char *n1_msg_hex = format_string_as_hex(n1_message);
+  unsigned char *n2_msg_hex = format_string_as_hex(n2_message);
+
+  std::string CRLF = "\r\n";
+  body.append("--" + boundary + CRLF);
+  body.append("Content-Type: application/json" + CRLF);
+  body.append(CRLF);
+  body.append(json_part + CRLF);
+
+  body.append("--" + boundary + CRLF);
+  body.append(
+      "Content-Type: application/vnd.3gpp.5gnas" + CRLF + "Content-Id: n1SmMsg"
+          + CRLF);
+  body.append(CRLF);
+  body.append(std::string((char*) n1_msg_hex, n1_message.length() / 2) + CRLF);
+  //body.append(n1_message + CRLF);
+
+  body.append("--" + boundary + CRLF);
+  body.append(
+      "Content-Type: application/vnd.3gpp.ngap" + CRLF + "Content-Id: n2SmMsg"
+          + CRLF);
+  body.append(CRLF);
+  body.append(std::string((char*) n2_msg_hex, n2_message.length() / 2) + CRLF);
+  body.append("--" + boundary + "--" + CRLF);
+}
+
+//------------------------------------------------------------------------------
+void create_multipart_related_content(
+    std::string &body, std::string &json_part, std::string &boundary,
+    std::string &message, multipart_related_content_part_e content_type) {
+
+  //format string as hex
+  //unsigned char *msg_hex = format_string_as_hex(message);
+
+  std::string CRLF = "\r\n";
+  body.append("--" + boundary + CRLF);
+  body.append("Content-Type: application/json" + CRLF);
+  body.append(CRLF);
+  body.append(json_part + CRLF);
+
+  body.append("--" + boundary + CRLF);
+  if (content_type == multipart_related_content_part_e::NAS) {  //NAS
+    body.append(
+        "Content-Type: application/vnd.3gpp.5gnas" + CRLF
+            + "Content-Id: n1SmMsg" + CRLF);
+  } else if (content_type == multipart_related_content_part_e::NGAP) {  //NGAP
+    body.append(
+        "Content-Type: application/vnd.3gpp.ngap" + CRLF + "Content-Id: n2SmMsg"
+            + CRLF);
+  }
+  body.append(CRLF);
+  //body.append(std::string((char*) msg_hex, message.length() / 2) + CRLF);
+  body.append(message + CRLF);
+  body.append("--" + boundary + "--" + CRLF);
+}
+
+void send_pdu_session_establishment_request(std::string smf_ip_address) {
+  std::cout << "[AMF N11] PDU Session Establishment Request (SM Context Create)"
+            << std::endl;
 
   nlohmann::json pdu_session_establishment_request;
-  //encode
-  // 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
+   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); //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++)
-  {
+  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, 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++) {
     printf("%02x ", buffer[i]);
   }
-  std::cout << "Buffer: "<<std::endl;
+  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"));
@@ -68,499 +207,458 @@ void send_pdu_session_establishment_request(std::string smf_ip_address)
   pdu_session_establishment_request["servingNetwork"]["mcc"] = "234";
   pdu_session_establishment_request["servingNetwork"]["mnc"] = "067";
   pdu_session_establishment_request["anType"] = "3GPP_ACCESS";
-  pdu_session_establishment_request["smContextStatusUri"] = "smContextStatusUri";
-  pdu_session_establishment_request["n1SmMsg"]["contentId"] = "n1SmMsg"; // NAS
+  pdu_session_establishment_request["smContextStatusUri"] =
+      "smContextStatusUri";
+  pdu_session_establishment_request["n1SmMsg"]["contentId"] = "n1SmMsg";  // NAS
 
+  std::string body;
+  std::string boundary = "----Boundary";
+  std::string json_part = pdu_session_establishment_request.dump();
+  std::string n1_msg(reinterpret_cast<const char*>(buffer), size);
 
-  CURL *curl = curl_easy_init();
+  create_multipart_related_content(body, json_part, boundary, n1_msg,
+                                   multipart_related_content_part_e::NAS);
 
-  std::string json_part = pdu_session_establishment_request.dump();
+  unsigned char *data = (unsigned char*) malloc(body.length() + 1);
+  memset(data, 0, body.length() + 1);
+  memcpy((void*) data, (void*) body.c_str(), body.length());
 
-  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;
+  curl_global_init(CURL_GLOBAL_ALL);
+  CURL *curl = curl = curl_easy_init();
 
+  if (curl) {
+    CURLcode res = { };
+    struct curl_slist *headers = nullptr;
     //headers = curl_slist_append(headers, "charsets: utf-8");
-    headers = curl_slist_append(headers, "content-type: multipart/related");
+    headers = curl_slist_append(
+        headers, "content-type: multipart/related; boundary=----Boundary");
     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_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);
+    //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:amf");  //hardcoded
 
     // Response information.
-    long httpCode(0);
+    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());
 
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
+
     res = curl_easy_perform(curl);
+
     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
 
     //get cause from the response
     nlohmann::json response_data;
-    try{
+    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;
-
+    } catch (nlohmann::json::exception &e) {
+      std::cout << "Could not get json data from the response" << std::endl;
     }
-    std::cout << "[AMF N11] PDU session establishment request, response from SMF, Http Code " << httpCode <<std::endl;
+    std::cout
+        << "[AMF N11] PDU session establishment request, response from SMF, Http Code "
+        << httpCode << std::endl;
 
-    curl_slist_free_all(headers);
     curl_easy_cleanup(curl);
-    curl_mime_free(mime);
   }
+  curl_global_cleanup();
+
   free(buffer);
 }
 
-
-void send_pdu_session_update_sm_context_establishment(std::string smf_ip_address)
-{
-  std::cout << "[AMF N11] PDU Session Establishment Request (SM Context Update)"<<std::endl;
+void send_pdu_session_update_sm_context_establishment(
+    std::string smf_ip_address) {
+  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
+  //encode PDU Session Resource Setup Response Transfer IE
   /*
-  00 03 e0 ac 0a 05 01 00 00 00 01 00 3c
+   00 03 e0 ac 0a 05 01 00 00 00 01 00 3c
    */
   size_t buffer_size = 128;
-  char *buffer = (char *)calloc(1,buffer_size);
-  int  size = 0;
-  ENCODE_U8 (buffer, 0x00 , size);
-  ENCODE_U8 (buffer+size, 0x03 , size);
-  ENCODE_U8 (buffer+size, 0xe0 , size);
-  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++)
-  {
+  char *buffer = (char*) calloc(1, buffer_size);
+  int size = 0;
+  ENCODE_U8(buffer, 0x00, size);
+  ENCODE_U8(buffer + size, 0x03, size);
+  ENCODE_U8(buffer + size, 0xe0, size);
+  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 < size; i++) {
     printf("%02x ", buffer[i]);
   }
-  std::cout << "Buffer: "<<std::endl;
+  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_update_request["n2SmInfoType"] = "PDU_RES_SETUP_RSP";
-  pdu_session_update_request["n2SmInfo"]["contentId"] = "n2SmMsg"; //NGAP
+  pdu_session_update_request["n2SmInfo"]["contentId"] = "n2SmMsg";  //NGAP
 
-  CURL *curl = curl_easy_init();
+  //pdu_session_update_request["n2InfoContainer"]["n2InformationClass"] = "SM";
+  //pdu_session_update_request["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapData"]["contentId"] = "n2SmMsg";
+  // pdu_session_update_request["n2InfoContainer"]["smInfo"]["n2InfoContent"]["ngapIeType"] =
+  //   "PDU_RES_SETUP_RSP";  //NGAP message
 
+  std::string body;
+  std::string boundary = "----Boundary";
   std::string json_part = pdu_session_update_request.dump();
+  std::string n2_msg(reinterpret_cast<const char*>(buffer), size);
 
-  std::cout<< "Sending message to SMF....\n";
-  if(curl) {
+  create_multipart_related_content(body, json_part, boundary, n2_msg,
+                                   multipart_related_content_part_e::NGAP);
 
-    CURLcode res;
-    struct curl_slist *headers = nullptr;
-    struct curl_slist *slist = nullptr;
-    curl_mime *mime;
-    curl_mime *alt;
-    curl_mimepart *part;
+  unsigned char *data = (unsigned char*) malloc(body.length() + 1);
+  memset(data, 0, body.length() + 1);
+  memcpy((void*) data, (void*) body.c_str(), body.length());
+
+  curl_global_init(CURL_GLOBAL_ALL);
+  CURL *curl = curl = curl_easy_init();
 
-    headers = curl_slist_append(headers, "charsets: utf-8");
-    headers = curl_slist_append(headers, "content-type: multipart/related");
+  if (curl) {
+    CURLcode res = { };
+    struct curl_slist *headers = nullptr;
+    //headers = curl_slist_append(headers, "charsets: utf-8");
+    headers = curl_slist_append(
+        headers, "content-type: multipart/related; boundary=----Boundary");
     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_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*>(buffer), size);
-
-    curl_mime_type(part, "application/vnd.3gpp.ngap");
-    curl_mime_name (part, "n2SmMsg");
-
-    curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
+    //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:amf");  //hardcoded
 
     // Response information.
-    long httpCode(0);
+    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());
 
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
+
     res = curl_easy_perform(curl);
+
     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
 
     //get cause from the response
     nlohmann::json response_data;
-    try{
+    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;
+    } catch (nlohmann::json::exception &e) {
+      std::cout << "Could not get json data from the response" << std::endl;
       //Set the default Cause
       response_data["cause"] = "504 Gateway Timeout";
+
     }
-    std::cout << "[AMF N11] PDU Session Establishment 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);
   }
+  curl_global_cleanup();
+
   free(buffer);
 }
 
+void send_pdu_session_release_request(std::string smf_ip_address) {
 
-void send_pdu_session_release_request(std::string smf_ip_address)
-{
-  std::cout << "[AMF N11] PDU Session Release Request (SM Context Update)"<<std::endl;
+  std::cout << "[AMF N11] PDU Session Release Request (SM Context Update)"
+            << std::endl;
 
   nlohmann::json pdu_session_release_request;
-  //encode
+  //encode PDU Session Release Request
   /*
-    0000   2e 01 01 d1 00 00 00 00 00 00 00 00 00 00 00 00
+   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++)
-  {
+  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;
+  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();
+  pdu_session_release_request["cause"] = "INSUFFICIENT_UP_RESOURCES";  //need to be updated
+  pdu_session_release_request["n1SmMsg"]["contentId"] = "n1SmMsg";  // NAS
 
+  std::string body;
+  std::string boundary = "----Boundary";
   std::string json_part = pdu_session_release_request.dump();
+  std::string n1_msg(reinterpret_cast<const char*>(buffer), size);
 
-  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;
+  create_multipart_related_content(body, json_part, boundary, n1_msg,
+                                   multipart_related_content_part_e::NAS);
 
+  unsigned char *data = (unsigned char*) malloc(body.length() + 1);
+  memset(data, 0, body.length() + 1);
+  memcpy((void*) data, (void*) body.c_str(), body.length());
+
+  curl_global_init(CURL_GLOBAL_ALL);
+  CURL *curl = curl = curl_easy_init();
+
+  if (curl) {
+    CURLcode res = { };
+    struct curl_slist *headers = nullptr;
     //headers = curl_slist_append(headers, "charsets: utf-8");
-    headers = curl_slist_append(headers, "content-type: multipart/related");
+    headers = curl_slist_append(
+        headers, "content-type: multipart/related; boundary=----Boundary");
     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_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);
+    //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:amf");  //hardcoded
 
     // Response information.
-    long httpCode(0);
+    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());
 
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
+
     res = curl_easy_perform(curl);
+
     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
 
     //get cause from the response
     nlohmann::json response_data;
-    try{
+    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;
-
+    } catch (nlohmann::json::exception &e) {
+      std::cout << "Could not get json data from the response" << std::endl;
     }
-    std::cout << "[AMF N11] PDU Session Release Request, response from SMF, Http Code " << httpCode <<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);
   }
+  curl_global_cleanup();
+
   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;
+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
+  //encode PDU Session Resource Release Response Transfer IE
   size_t buffer_size = 128;
-  char *buffer = (char *)calloc(1,buffer_size);
-  int  size = 0;
-  ENCODE_U8 (buffer, 0x00 , size);
-
+  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++)
-  {
+  std::cout << "Buffer: " << std::endl;
+  for (int i = 0; i < size; i++) {
     printf("%02x ", buffer[i]);
   }
-  std::cout << "Buffer: "<<std::endl;
+  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();
+  pdu_session_release_ack["n2SmInfo"]["contentId"] = "n2SmMsg";  //NGAP
 
+  std::string body;
+  std::string boundary = "----Boundary";
   std::string json_part = pdu_session_release_ack.dump();
+  std::string n2_msg(reinterpret_cast<const char*>(buffer), size);
 
-  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;
+  create_multipart_related_content(body, json_part, boundary, n2_msg,
+                                   multipart_related_content_part_e::NGAP);
+
+  unsigned char *data = (unsigned char*) malloc(body.length() + 1);
+  memset(data, 0, body.length() + 1);
+  memcpy((void*) data, (void*) body.c_str(), body.length());
 
+  curl_global_init(CURL_GLOBAL_ALL);
+  CURL *curl = curl = curl_easy_init();
+
+  if (curl) {
+    CURLcode res = { };
+    struct curl_slist *headers = nullptr;
     //headers = curl_slist_append(headers, "charsets: utf-8");
-    headers = curl_slist_append(headers, "content-type: multipart/related");
+    headers = curl_slist_append(
+        headers, "content-type: multipart/related; boundary=----Boundary");
     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_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);
+    //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:amf");  //hardcoded
 
     // Response information.
-    long httpCode(0);
+    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());
 
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
+
     res = curl_easy_perform(curl);
+
     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
 
     //get cause from the response
     nlohmann::json response_data;
-    try{
+    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;
+    } catch (nlohmann::json::exception &e) {
+      std::cout << "Could not get json data from the response" << std::endl;
 
     }
-    std::cout << "[AMF N11] PDU Session Release Ack, response from SMF, Http Code " << httpCode <<std::endl;
+    std::cout
+        << "[AMF N11] PDU Session Establishment Request, response from SMF, Http Code "
+        << httpCode << std::endl;
 
-    curl_slist_free_all(headers);
     curl_easy_cleanup(curl);
-    curl_mime_free(mime);
   }
+  curl_global_cleanup();
+
   free(buffer);
 }
 
+void send_pdu_session_release_complete(std::string smf_ip_address) {
 
-
-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;
+  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
+  //encode PDU Session Release Complete
   /*
-    0000   2e 01 01 c1 d4 00 00 00 00 00 00 00 00 00 00 00
+   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++)
-  {
+  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;
+  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["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";
+  std::string body;
+  std::string boundary = "----Boundary";
+  std::string json_part = pdu_session_release_complete.dump();
+  std::string n1_msg(reinterpret_cast<const char*>(buffer), size);
 
+  create_multipart_related_content(body, json_part, boundary, n1_msg,
+                                   multipart_related_content_part_e::NAS);
 
-  CURL *curl = curl_easy_init();
+  unsigned char *data = (unsigned char*) malloc(body.length() + 1);
+  memset(data, 0, body.length() + 1);
+  memcpy((void*) data, (void*) body.c_str(), body.length());
 
-  std::string json_part = pdu_session_release_complete.dump();
+  curl_global_init(CURL_GLOBAL_ALL);
+  CURL *curl = curl = curl_easy_init();
 
-  std::cout<< "Sending message to SMF....\n";
-  if(curl) {
-    CURLcode res;
+  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");
+    headers = curl_slist_append(
+        headers, "content-type: multipart/related; boundary=----Boundary");
     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_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);
+    //curl_easy_setopt(curl, CURLOPT_INTERFACE, "eno1:amf");  //hardcoded
 
     // Response information.
-    long httpCode(0);
+    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());
 
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
+
     res = curl_easy_perform(curl);
+
     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
 
     //get cause from the response
     nlohmann::json response_data;
-    try{
+    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;
-
+    } catch (nlohmann::json::exception &e) {
+      std::cout << "Could not get json data from the response" << std::endl;
     }
-    std::cout << "[AMF N11] PDU Session Release Complete, response from SMF, Http Code " << httpCode <<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);
-    curl_mime_free(mime);
   }
+  curl_global_cleanup();
+
   free(buffer);
 }
 
-
-
-int main(int argc, char* argv[])
-{
+int main(int argc, char *argv[]) {
   std::string smf_ip_address;
 
   if ((argc != 1) && (argc != 3)) {
-    std::cout << "Error: Usage is " <<std::endl;
-    std::cout << "  " << argv[0] << " [ -i www.xxx.yy.zz ]" <<std::endl;
+    std::cout << "Error: Usage is " << std::endl;
+    std::cout << "  " << argv[0] << " [ -i www.xxx.yy.zz ]" << std::endl;
     return -1;
   }
 
@@ -569,15 +667,15 @@ int main(int argc, char* argv[])
   } else {
     int opt = 0;
     while ((opt = getopt(argc, argv, "i:")) != -1) {
-      switch(opt) {
-      case 'i':
-        smf_ip_address.append(optarg);
-        break;
-      default:
-        std::cout << "Error: Usage is " <<std::endl;
-        std::cout << "  " << argv[0] << " [ -i www.xxx.yy.zz ]" <<std::endl;
-        return -1;
-        break;
+      switch (opt) {
+        case 'i':
+          smf_ip_address.append(optarg);
+          break;
+        default:
+          std::cout << "Error: Usage is " << std::endl;
+          std::cout << "  " << argv[0] << " [ -i www.xxx.yy.zz ]" << std::endl;
+          return -1;
+          break;
       }
     }
   }
-- 
GitLab