diff --git a/src/smf_app/smf_n11.cpp b/src/smf_app/smf_n11.cpp index 90b7d3eadd70668b61b51c3c685d04b33efebf00..ab9004a3b7e4468bee8984371835e4b5b662b984 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 7e1126d829cde3a17810a939669e1b3855f14953..cb15918d3fc0c9e5b9b8d3e1aea78a275ca59485 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; } } }