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