Added PDU Session est request

master
David Rupprecht 3 years ago committed by David Rupprecht
parent 0385980347
commit 3712983308

@ -13,10 +13,26 @@
#ifndef SRSRAN_UE_NAS_INTERFACES_H
#define SRSRAN_UE_NAS_INTERFACES_H
#include "srsran/asn1/nas_5g_ies.h"
#include "srsran/interfaces/rrc_interface_types.h"
namespace srsue {
enum apn_types {
ipv4 = 0b001,
ipv6 = 0b010,
ipv4v6 = 0b011,
unstructured = 0b100,
ethernet = 0b101,
};
class pdu_session_cfg_t
{
public:
std::string apn_name;
apn_types apn_type;
std::string apn_user;
std::string apn_pass;
};
class nas_interface_rrc
{
public:
@ -49,6 +65,13 @@ class nas_5g_interface_procedures
{
public:
virtual int send_registration_request() = 0;
virtual int send_pdu_session_establishment_request(uint32_t transaction_identity,
uint16_t pdu_session_id,
const pdu_session_cfg_t& pdu_session) = 0;
virtual int
add_pdu_session(uint16_t pdu_session_id, uint16_t pdu_session_type, srsran::nas_5g::pdu_address_t pdu_address) = 0;
virtual uint32_t allocate_next_proc_trans_id() = 0;
};
} // namespace srsue

@ -125,7 +125,7 @@ private:
// TS 38.413 - Section 9.2.2.1 - Initial Context Setup Request
bool handle_initial_ctxt_setup_request(const asn1::ngap_nr::init_context_setup_request_s& msg);
// TS 38.413 - Section 9.2.1.1 - PDU Session Resource Setup Request
bool handle_pdu_session_resource_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg);
bool handle_ue_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg);
class user_list
{

@ -39,6 +39,8 @@ public:
bool handle_initial_ctxt_setup_request(const asn1::ngap_nr::init_context_setup_request_s& msg);
// TS 38.413 - Section 9.2.2.5 - UE Context Release Command
bool handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cmd_s& msg);
// TS 38.413 - Section 9.2.1.1 - PDU Session Resource Setup Request
bool handle_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg);
bool was_uectxtrelease_requested() const { return release_requested; }
void ue_ctxt_setup_complete();
@ -60,6 +62,7 @@ private:
// procedures
srsran::proc_t<ngap_ue_initial_context_setup_proc> initial_context_setup_proc;
srsran::proc_t<ngap_ue_ue_context_release_proc> ue_context_release_proc;
srsran::proc_t<ngap_ue_pdu_session_res_setup_proc> ue_pdu_session_res_setup_proc;
};
} // namespace srsenb

@ -79,6 +79,23 @@ private:
ngap_interface_ngap_proc* parent;
};
class ngap_ue_pdu_session_res_setup_proc
{
public:
explicit ngap_ue_pdu_session_res_setup_proc(ngap_interface_ngap_proc* parent_,
rrc_interface_ngap_nr* rrc_,
ngap_ue_ctxt_t* ue_ctxt);
srsran::proc_outcome_t init(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg);
srsran::proc_outcome_t step();
static const char* name() { return "UE PDU Session Resource Setup"; }
private:
ngap_ue_ctxt_t* ue_ctxt;
ngap_interface_ngap_proc* parent;
rrc_interface_ngap_nr* rrc = nullptr;
srslog::basic_logger& logger;
};
} // namespace srsenb
#endif

@ -414,6 +414,8 @@ bool ngap::handle_initiating_message(const asn1::ngap_nr::init_msg_s& msg)
return handle_initial_ctxt_setup_request(msg.value.init_context_setup_request());
case ngap_elem_procs_o::init_msg_c::types_opts::ue_context_release_cmd:
return handle_ue_ctxt_release_cmd(msg.value.ue_context_release_cmd());
case ngap_elem_procs_o::init_msg_c::types_opts::pdu_session_res_setup_request:
return handle_ue_pdu_session_res_setup_request(msg.value.pdu_session_res_setup_request());
default:
logger.error("Unhandled initiating message: %s", msg.value.type().to_string());
}
@ -532,10 +534,16 @@ bool ngap::handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_release_cm
return true;
}
bool ngap::handle_pdu_session_resource_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg)
bool ngap::handle_ue_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg)
{
// TODO
logger.warning("Not implemented yet");
ue* u =
handle_ngapmsg_ue_id(msg.protocol_ies.ran_ue_ngap_id.value.value, msg.protocol_ies.amf_ue_ngap_id.value.value);
if (u == nullptr) {
logger.warning("Can not find UE");
return false;
}
u->handle_pdu_session_res_setup_request(msg);
return true;
}

@ -27,7 +27,8 @@ ngap::ue::ue(ngap* ngap_ptr_, rrc_interface_ngap_nr* rrc_ptr_, srslog::basic_log
logger(logger_),
ngap_ptr(ngap_ptr_),
initial_context_setup_proc(this, rrc_ptr_, &ctxt),
ue_context_release_proc(this, rrc_ptr_, &ctxt)
ue_context_release_proc(this, rrc_ptr_, &ctxt),
ue_pdu_session_res_setup_proc(this, rrc_ptr_, &ctxt)
{
ctxt.ran_ue_ngap_id = ngap_ptr->next_gnb_ue_ngap_id++;
gettimeofday(&ctxt.init_timestamp, nullptr);
@ -202,4 +203,13 @@ bool ngap::ue::handle_ue_ctxt_release_cmd(const asn1::ngap_nr::ue_context_releas
return true;
}
bool ngap::ue::handle_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg)
{
if (not ue_pdu_session_res_setup_proc.launch(msg)) {
logger.error("Failed to start UE PDU Session Resource Setup Procedure");
return false;
}
return true;
}
} // namespace srsenb

@ -89,4 +89,41 @@ proc_outcome_t ngap_ue_ue_context_release_proc::step()
return proc_outcome_t::success;
}
ngap_ue_pdu_session_res_setup_proc::ngap_ue_pdu_session_res_setup_proc(ngap_interface_ngap_proc* parent_,
rrc_interface_ngap_nr* rrc_,
ngap_ue_ctxt_t* ue_ctxt_) :
logger(srslog::fetch_basic_logger("NGAP UE"))
{
parent = parent_;
rrc = rrc_;
ue_ctxt = ue_ctxt_;
}
proc_outcome_t ngap_ue_pdu_session_res_setup_proc::init(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg)
{
if (msg.protocol_ies.pdu_session_res_setup_list_su_req.value.size() != 1) {
logger.error("Not handling multiple su requests");
return proc_outcome_t::error;
}
asn1::ngap_nr::pdu_session_res_setup_item_su_req_s su_req =
msg.protocol_ies.pdu_session_res_setup_list_su_req.value[0];
if (su_req.pdu_session_nas_pdu_present) {
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Fatal Error: Couldn't allocate buffer in ngap_ue_initial_context_setup_proc::init().");
return proc_outcome_t::error;
}
memcpy(pdu->msg, su_req.pdu_session_nas_pdu.data(), su_req.pdu_session_nas_pdu.size());
pdu->N_bytes = su_req.pdu_session_nas_pdu.size();
rrc->write_dl_info(ue_ctxt->rnti, std::move(pdu));
}
return proc_outcome_t::yield;
}
proc_outcome_t ngap_ue_pdu_session_res_setup_proc::step()
{
return proc_outcome_t::success;
}
} // namespace srsenb

@ -263,8 +263,6 @@ private:
srsran::proc_manager_list_t callbacks;
srsran::proc_t<plmn_search_proc> plmn_searcher;
const std::string gw_setup_failure_str = "Failed to setup/configure GW interface";
};
} // namespace srsue

@ -33,6 +33,9 @@
using srsran::byte_buffer_t;
#define MAX_PDU_SESSIONS 15
#define MAX_TRANS_ID 255
namespace srsue {
/**
@ -110,8 +113,10 @@ private:
// Procedures
// Forward declartion
class registration_procedure;
class pdu_session_establishment_procedure;
srsran::proc_t<registration_procedure> registration_proc;
srsran::proc_t<pdu_session_establishment_procedure> pdu_session_establishment_proc;
// Message sender
int send_registration_request();
@ -121,6 +126,9 @@ private:
const uint8_t* auth_fail_param);
int send_security_mode_complete(const srsran::nas_5g::security_mode_command_t& security_mode_command);
int send_registration_complete();
int send_pdu_session_establishment_request(uint32_t transaction_identity,
uint16_t pdu_session_id,
const pdu_session_cfg_t& pdu_session);
void fill_security_caps(srsran::nas_5g::ue_security_capability_t& sec_caps);
int apply_security_config(srsran::unique_byte_buffer_t& pdu, uint8_t sec_hdr_type);
@ -138,6 +146,33 @@ private:
srsran::nas_5g::deregistration_accept_ue_terminated_t& deregistration_accept_ue_terminated);
int handle_deregistration_request_ue_terminated(
srsran::nas_5g::deregistration_request_ue_terminated_t& deregistration_request_ue_terminated);
int handle_dl_nas_transport(srsran::nas_5g::dl_nas_transport_t& dl_nas_transport);
// message handler container
int handle_n1_sm_information(std::vector<uint8_t> payload_container_contents);
// Transaction ID management
std::array<bool, MAX_TRANS_ID> pdu_trans_ids;
uint32_t allocate_next_proc_trans_id();
void release_proc_trans_id(uint32_t proc_id);
int trigger_pdu_session_est();
// PDU Session Management
int add_pdu_session(uint16_t pdu_session_id, uint16_t pdu_session_type, srsran::nas_5g::pdu_address_t pdu_address);
int init_pdu_sessions(std::vector<pdu_session_cfg_t> pdu_session_cfgs);
int configure_pdu_session(uint16_t pdu_session_id);
bool unestablished_pdu_sessions();
int get_unestablished_pdu_session(uint16_t& pdu_session_id, pdu_session_cfg_t& pdu_session_cfg);
struct pdu_session_t {
bool configured;
bool established;
uint16_t pdu_session_id;
pdu_session_cfg_t pdu_session_cfg;
};
std::array<pdu_session_t, MAX_PDU_SESSIONS> pdu_sessions;
};
} // namespace srsue
#endif

@ -36,6 +36,32 @@ public:
private:
nas_5g_interface_procedures* parent_nas;
};
/**
* @brief 5G NAS (5GSM) UE-requested PDU session establishment procedure
*
* Specified in 24 501 V16.7.0
* UE-requested 5GSM procedures
* 6.4.1 UE-requested PDU session establishment procedure
*/
class nas_5g::pdu_session_establishment_procedure
{
public:
explicit pdu_session_establishment_procedure(nas_5g_interface_procedures* parent_nas_, srslog::basic_logger& logger_);
srsran::proc_outcome_t init(const uint16_t pdu_session_id, const pdu_session_cfg_t pdu_session);
srsran::proc_outcome_t react(const srsran::nas_5g::pdu_session_establishment_accept_t& pdu_session_est_accept);
srsran::proc_outcome_t react(const srsran::nas_5g::pdu_session_establishment_reject_t& pdu_session_est_reject);
srsran::proc_outcome_t step();
srsran::proc_outcome_t then();
static const char* name() { return "PDU Session Establishment Procedure"; }
private:
srslog::basic_logger& logger;
nas_5g_interface_procedures* parent_nas;
uint32_t transaction_identity = 0;
uint16_t pdu_session_id = 0;
};
} // namespace srsue
#endif // SRSUE_NAS_5G_PROCEDURES_H_

@ -73,6 +73,8 @@ protected:
uint32_t mac_offset = 0;
uint32_t seq_offset = 0;
uint32_t bearer_id = 0;
const std::string gw_setup_failure_str = "Failed to setup/configure GW interface";
};
} // namespace srsue

@ -13,6 +13,7 @@
#ifndef SRSUE_NAS_CONFIG_H
#define SRSUE_NAS_CONFIG_H
#include "srsran/interfaces/ue_nas_interfaces.h"
#include <string>
namespace srsue {
@ -34,9 +35,12 @@ public:
bool force_imsi_attach;
std::string eia;
std::string eea;
nas_sim_args_t sim;
// 5G args
std::string ia5g;
std::string ea5g;
nas_sim_args_t sim;
std::vector<pdu_session_cfg_t> pdu_session_cfgs;
};
} // namespace srsue

@ -49,7 +49,8 @@ nas_5g::nas_5g(srslog::basic_logger& logger_, srsran::task_sched_handle task_sch
t3521(task_sched_.get_unique_timer()),
reregistration_timer(task_sched_.get_unique_timer()),
registration_proc(this),
state(logger_)
state(logger_),
pdu_session_establishment_proc(this, logger_)
{
// Configure timers
t3502.set(t3502_duration_ms, [this](uint32_t tid) { timer_expired(tid); });
@ -95,6 +96,10 @@ int nas_5g::init(usim_interface_nas* usim_,
ea5g_caps[3] = true;
}
if (init_pdu_sessions(cfg.pdu_session_cfgs) != SRSRAN_SUCCESS) {
logger.warning("Failure while configuring pdu sessions");
}
running = true;
return SRSRAN_SUCCESS;
}
@ -137,6 +142,94 @@ void nas_5g::run_tti()
}
}
int nas_5g::write_pdu(srsran::unique_byte_buffer_t pdu)
{
logger.info(pdu->msg, pdu->N_bytes, "DL PDU (length %d)", pdu->N_bytes);
nas_5gs_msg nas_msg;
if (nas_msg.unpack_outer_hdr(pdu) != SRSRAN_SUCCESS) {
logger.error("Unable to unpack outer NAS header");
return SRSRAN_ERROR;
}
switch (nas_msg.hdr.security_header_type) {
case nas_5gs_hdr::security_header_type_opts::plain_5gs_nas_message:
break;
case nas_5gs_hdr::security_header_type_opts::integrity_protected:
if (integrity_check(pdu.get()) == false) {
logger.error("Not handling NAS message with integrity check error");
return SRSRAN_ERROR;
}
break;
case nas_5gs_hdr::security_header_type_opts::integrity_protected_and_ciphered:
if (integrity_check(pdu.get()) == false) {
logger.error("Not handling NAS message with integrity check error");
return SRSRAN_ERROR;
} else {
cipher_decrypt(pdu.get());
}
break;
case nas_5gs_hdr::security_header_type_opts::integrity_protected_with_new_5G_nas_context:
break;
case nas_5gs_hdr::security_header_type_opts::integrity_protected_and_ciphered_with_new_5G_nas_context:
return SRSRAN_ERROR;
default:
logger.error("Not handling NAS message with unkown security header");
break;
}
if (pcap != nullptr) {
pcap->write_nas(pdu->msg, pdu->N_bytes);
}
logger.info(pdu->msg, pdu->N_bytes, "Decrypted DL PDU (length %d)", pdu->N_bytes);
// Parse the message header
if (nas_msg.unpack(pdu) != SRSRAN_SUCCESS) {
logger.error("Unable to unpack complete NAS pdu");
return SRSRAN_ERROR;
}
switch (nas_msg.hdr.message_type) {
case msg_opts::options::registration_accept:
handle_registration_accept(nas_msg.registration_accept());
break;
case msg_opts::options::registration_reject:
handle_registration_reject(nas_msg.registration_reject());
break;
case msg_opts::options::authentication_request:
handle_authentication_request(nas_msg.authentication_request());
break;
case msg_opts::options::identity_request:
handle_identity_request(nas_msg.identity_request());
break;
case msg_opts::options::security_mode_command:
handle_security_mode_command(nas_msg.security_mode_command(), std::move(pdu));
break;
case msg_opts::options::service_accept:
handle_service_accept(nas_msg.service_accept());
break;
case msg_opts::options::service_reject:
handle_service_reject(nas_msg.service_reject());
break;
case msg_opts::options::deregistration_accept_ue_terminated:
handle_deregistration_accept_ue_terminated(nas_msg.deregistration_accept_ue_terminated());
break;
case msg_opts::options::deregistration_request_ue_terminated:
handle_deregistration_request_ue_terminated(nas_msg.deregistration_request_ue_terminated());
break;
case msg_opts::options::dl_nas_transport:
handle_dl_nas_transport(nas_msg.dl_nas_transport());
break;
default:
logger.error(
"Not handling NAS message type: %s (0x%02x)", nas_msg.hdr.message_type.to_string(), nas_msg.hdr.message_type);
break;
}
return SRSRAN_SUCCESS;
}
/*******************************************************************************
* Senders
******************************************************************************/
@ -199,6 +292,34 @@ int nas_5g::send_registration_request()
return SRSRAN_SUCCESS;
}
int nas_5g::send_registration_complete()
{
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (!pdu) {
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
return SRSRAN_ERROR;
}
logger.info("Generating Registration Complete");
nas_5gs_msg nas_msg;
registration_complete_t& reg_comp = nas_msg.set_registration_complete();
if (nas_msg.pack(pdu) != SRSASN_SUCCESS) {
logger.error("Failed to pack registration complete.");
return SRSRAN_ERROR;
}
if (pcap != nullptr) {
pcap->write_nas(pdu.get()->msg, pdu.get()->N_bytes);
}
logger.info("Sending Registration Complete");
rrc_nr->write_sdu(std::move(pdu));
return SRSRAN_SUCCESS;
}
int nas_5g::send_authentication_response(const uint8_t res[16])
{
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
@ -224,11 +345,6 @@ int nas_5g::send_authentication_response(const uint8_t res[16])
pcap->write_nas(pdu.get()->msg, pdu.get()->N_bytes);
}
// if (apply_security_config(pdu, current_sec_hdr) != SRSASN_SUCCESS) {
// logger.error("Error applying NAS security.");
// return SRSRAN_ERROR;
// }
logger.info("Sending Authentication Response");
rrc_nr->write_sdu(std::move(pdu));
@ -261,16 +377,6 @@ int nas_5g::send_security_mode_reject(const cause_5gmm_t::cause_5gmm_type_::opti
return SRSRAN_SUCCESS;
}
void copy_msg_to_buffer(unique_byte_buffer_t& pdu, const_byte_span msg)
{
pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
srslog::fetch_basic_logger("ALL").error("Couldn't allocate PDU in %s().", __FUNCTION__);
return;
}
memcpy(pdu->msg, msg.data(), msg.size());
pdu->N_bytes = msg.size();
}
int nas_5g::send_security_mode_complete(const srsran::nas_5g::security_mode_command_t& security_mode_command)
{
@ -339,7 +445,7 @@ int nas_5g::send_security_mode_complete(const srsran::nas_5g::security_mode_comm
logger.info("Sending Security Mode Complete");
rrc_nr->write_sdu(std::move(pdu));
ctxt.rx_count++;
ctxt.tx_count++;
return SRSRAN_SUCCESS;
}
@ -371,7 +477,30 @@ int nas_5g::send_authentication_failure(const cause_5gmm_t::cause_5gmm_type_::op
return SRSRAN_SUCCESS;
}
int nas_5g::send_registration_complete()
uint32_t nas_5g::allocate_next_proc_trans_id()
{
uint32_t i = 0;
for (auto pdu_trans_id : pdu_trans_ids) {
i++;
if (pdu_trans_id == false) {
pdu_trans_id = true;
}
}
// TODO if Trans ID exhausted
return i;
}
void nas_5g::release_proc_trans_id(uint32_t proc_id)
{
if (proc_id < MAX_TRANS_ID) {
pdu_trans_ids[proc_id] = false;
}
return;
}
int nas_5g::send_pdu_session_establishment_request(uint32_t transaction_identity,
uint16_t pdu_session_id,
const pdu_session_cfg_t& pdu_session_cfg)
{
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (!pdu) {
@ -379,13 +508,64 @@ int nas_5g::send_registration_complete()
return SRSRAN_ERROR;
}
logger.info("Generating Registration Complete");
logger.info("Generating PDU Session Establishment Request");
nas_5gs_msg nas_msg;
registration_complete_t& reg_comp = nas_msg.set_registration_complete();
nas_msg.hdr.pdu_session_identity = pdu_session_id;
nas_msg.hdr.procedure_transaction_identity = transaction_identity;
if (nas_msg.pack(pdu) != SRSASN_SUCCESS) {
logger.error("Failed to pack registration complete.");
pdu_session_establishment_request_t& pdu_ses_est_req = nas_msg.set_pdu_session_establishment_request();
pdu_ses_est_req.integrity_protection_maximum_data_rate.max_data_rate_upip_downlink =
integrity_protection_maximum_data_rate_t::max_data_rate_UPIP_downlink_type_::options::full_data_rate;
pdu_ses_est_req.integrity_protection_maximum_data_rate.max_data_rate_upip_uplink =
integrity_protection_maximum_data_rate_t::max_data_rate_UPIP_uplink_type_::options::full_data_rate;
pdu_ses_est_req.pdu_session_type_present = true;
pdu_ses_est_req.pdu_session_type.pdu_session_type_value =
static_cast<srsran::nas_5g::pdu_session_type_t::PDU_session_type_value_type_::options>(pdu_session_cfg.apn_type);
pdu_ses_est_req.ssc_mode_present = true;
pdu_ses_est_req.ssc_mode.ssc_mode_value = ssc_mode_t::SSC_mode_value_type_::options::ssc_mode_1;
// TODO set the capability and extended protocol configuration
pdu_ses_est_req.capability_5gsm_present = false;
pdu_ses_est_req.extended_protocol_configuration_options_present = false;
// Build up the Envelope for the PDU session request
nas_5gs_msg env_nas_msg;
env_nas_msg.hdr.security_header_type = nas_5gs_hdr::security_header_type_opts::integrity_protected_and_ciphered;
// TODO move that seq number setting to the security part
env_nas_msg.hdr.sequence_number = ctxt.tx_count;
ul_nas_transport_t& ul_nas_msg = env_nas_msg.set_ul_nas_transport();
ul_nas_msg.payload_container_type.payload_container_type.value =
payload_container_type_t::Payload_container_type_type_::options::n1_sm_information;
// Pack the pdu session est request into the envelope
if (nas_msg.pack(ul_nas_msg.payload_container.payload_container_contents) != SRSASN_SUCCESS) {
logger.error("Failed to pack PDU Session Establishment Request.");
return SRSRAN_ERROR;
}
ul_nas_msg.pdu_session_id_present = true;
ul_nas_msg.pdu_session_id.pdu_session_identity_2_value = pdu_session_id;
ul_nas_msg.request_type_present = true;
ul_nas_msg.request_type.request_type_value = request_type_t::Request_type_value_type_::options::initial_request;
ul_nas_msg.s_nssai_present = true;
ul_nas_msg.s_nssai.type = s_nssai_t::SST_type_::options::sst;
ul_nas_msg.s_nssai.sst = 1;
ul_nas_msg.dnn_present = true;
ul_nas_msg.dnn.dnn_value.resize(pdu_session_cfg.apn_name.size() + 1);
ul_nas_msg.dnn.dnn_value.data()[0] = static_cast<uint8_t>(pdu_session_cfg.apn_name.size());
memcpy(ul_nas_msg.dnn.dnn_value.data() + 1, pdu_session_cfg.apn_name.data(), pdu_session_cfg.apn_name.size());
if (env_nas_msg.pack(pdu) != SRSASN_SUCCESS) {
logger.error("Failed to pack UL NAS transport.");
return SRSRAN_ERROR;
}
@ -393,235 +573,55 @@ int nas_5g::send_registration_complete()
pcap->write_nas(pdu.get()->msg, pdu.get()->N_bytes);
}
logger.info("Sending Registration Complete");
cipher_encrypt(pdu.get());
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[SEQ_5G_OFFSET],
pdu->N_bytes - SEQ_5G_OFFSET,
&pdu->msg[MAC_5G_OFFSET]);
logger.info("Sending PDU Session Establishment Complete in UL NAS transport.");
rrc_nr->write_sdu(std::move(pdu));
return SRSRAN_SUCCESS;
}
int nas_5g::write_pdu(srsran::unique_byte_buffer_t pdu)
// Message handler
int nas_5g::handle_registration_accept(registration_accept_t& registration_accept)
{
logger.info(pdu->msg, pdu->N_bytes, "DL PDU (length %d)", pdu->N_bytes);
nas_5gs_msg nas_msg;
if (nas_msg.unpack_outer_hdr(pdu) != SRSRAN_SUCCESS) {
logger.error("Unable to unpack outer NAS header");
return SRSRAN_ERROR;
}
switch (nas_msg.hdr.security_header_type) {
case nas_5gs_hdr::security_header_type_opts::plain_5gs_nas_message:
break;
case nas_5gs_hdr::security_header_type_opts::integrity_protected:
if (integrity_check(pdu.get()) == false) {
logger.error("Not handling NAS message with integrity check error");
return SRSRAN_ERROR;
}
break;
case nas_5gs_hdr::security_header_type_opts::integrity_protected_and_ciphered:
if (integrity_check(pdu.get()) == false) {
logger.error("Not handling NAS message with integrity check error");
return SRSRAN_ERROR;
} else {
cipher_decrypt(pdu.get());
}
break;
case nas_5gs_hdr::security_header_type_opts::integrity_protected_with_new_5G_nas_context:
break;
case nas_5gs_hdr::security_header_type_opts::integrity_protected_and_ciphered_with_new_5G_nas_context:
if (state.get_state() != mm5g_state_t::state_t::registered_initiated) {
logger.warning("Not compatibale with current state %s", state.get_full_state_text());
return SRSRAN_ERROR;
default:
logger.error("Not handling NAS message with unkown security header");
break;
}
if (pcap != nullptr) {
pcap->write_nas(pdu->msg, pdu->N_bytes);
bool send_reg_complete = false;
logger.info("Handling Registration Accept");
if (registration_accept.guti_5g_present) {
guti_5g = registration_accept.guti_5g.guti_5g();
send_reg_complete = true;
}
logger.info(pdu->msg, pdu->N_bytes, "Decrypted DL PDU (length %d)", pdu->N_bytes);
// TODO: reset counters and everything what is needed by the specification
t3521.set(registration_accept.t3512_value.timer_value);
registration_proc.run();
state.set_registered(mm5g_state_t::registered_substate_t::normal_service);
// Parse the message header
if (nas_msg.unpack(pdu) != SRSRAN_SUCCESS) {
logger.error("Unable to unpack complete NAS pdu");
return SRSRAN_ERROR;
if (send_reg_complete == true) {
send_registration_complete();
}
// TODO: use the state machine to trigger that transition
trigger_pdu_session_est();
return SRSRAN_SUCCESS;
}
switch (nas_msg.hdr.message_type) {
case msg_opts::options::registration_accept:
handle_registration_accept(nas_msg.registration_accept());
break;
case msg_opts::options::registration_reject:
handle_registration_reject(nas_msg.registration_reject());
break;
case msg_opts::options::authentication_request:
handle_authentication_request(nas_msg.authentication_request());
break;
case msg_opts::options::identity_request:
handle_identity_request(nas_msg.identity_request());
break;
case msg_opts::options::security_mode_command:
handle_security_mode_command(nas_msg.security_mode_command(), std::move(pdu));
break;
case msg_opts::options::service_accept:
handle_service_accept(nas_msg.service_accept());
break;
case msg_opts::options::service_reject:
handle_service_reject(nas_msg.service_reject());
break;
case msg_opts::options::deregistration_accept_ue_terminated:
handle_deregistration_accept_ue_terminated(nas_msg.deregistration_accept_ue_terminated());
break;
case msg_opts::options::deregistration_request_ue_terminated:
handle_deregistration_request_ue_terminated(nas_msg.deregistration_request_ue_terminated());
break;
default:
logger.error(
"Not handling NAS message type: %s (0x%02x)", nas_msg.hdr.message_type.to_string(), nas_msg.hdr.message_type);
break;
}
int nas_5g::handle_registration_reject(registration_reject_t& registration_reject)
{
logger.info("Handling Registration Reject");
return SRSRAN_SUCCESS;
}
void nas_5g::fill_security_caps(srsran::nas_5g::ue_security_capability_t& sec_caps)
{
if (ia5g_caps[0] == true) {
sec_caps.ia0_5g_supported = true;
}
if (ia5g_caps[1] == true) {
sec_caps.ia1_128_5g_supported = true;
}
if (ia5g_caps[2] == true) {
sec_caps.ia2_128_5g_supported = true;
}
if (ia5g_caps[3] == true) {
sec_caps.ia3_128_5g_supported = true;
}
if (ia5g_caps[4] == true) {
sec_caps.ia4_5g_supported = true;
}
if (ia5g_caps[5] == true) {
sec_caps.ia5_5g_supported = true;
}
if (ia5g_caps[6] == true) {
sec_caps.ia6_5g_supported = true;
}
if (ia5g_caps[7] == true) {
sec_caps.ia7_5g_supported = true;
}
if (ea5g_caps[0] == true) {
sec_caps.ea0_5g_supported = true;
}
if (ea5g_caps[1] == true) {
sec_caps.ea1_128_5g_supported = true;
}
if (ea5g_caps[2] == true) {
sec_caps.ea2_128_5g_supported = true;
}
if (ea5g_caps[3] == true) {
sec_caps.ea3_128_5g_supported = true;
}
if (ea5g_caps[4] == true) {
sec_caps.ea4_5g_supported = true;
}
if (ea5g_caps[5] == true) {
sec_caps.ea5_5g_supported = true;
}
if (ea5g_caps[6] == true) {
sec_caps.ea6_5g_supported = true;
}
if (ea5g_caps[7] == true) {
sec_caps.ea7_5g_supported = true;
}
}
/*******************************************************************************
* UE Stack and RRC common Interface
******************************************************************************/
bool nas_5g::is_registered()
{
return state.get_state() == mm5g_state_t::state_t::registered;
}
/*******************************************************************************
* NAS Timers
******************************************************************************/
void nas_5g::timer_expired(uint32_t timeout_id)
{
// TODO
}
/*******************************************************************************
* UE Stack Interface
******************************************************************************/
int nas_5g::switch_on()
{
logger.info("Switching on");
state.set_deregistered(mm5g_state_t::deregistered_substate_t::plmn_search);
return SRSRAN_SUCCESS;
}
int nas_5g::switch_off()
{
logger.info("Switching off");
// TODO
return SRSRAN_SUCCESS;
}
int nas_5g::enable_data()
{
logger.info("Enabling data services");
return switch_on();
}
int nas_5g::disable_data()
{
logger.info("Disabling data services");
// TODO
return SRSRAN_SUCCESS;
}
int nas_5g::start_service_request()
{
logger.info("Service Request");
// TODO
return SRSRAN_SUCCESS;
}
// Message handler
int nas_5g::handle_registration_accept(registration_accept_t& registration_accept)
{
if (state.get_state() != mm5g_state_t::state_t::registered_initiated) {
logger.warning("Not compatibale with current state %s", state.get_full_state_text());
return SRSRAN_ERROR;
}
bool send_reg_complete = false;
logger.info("Handling Registration Accept");
if (registration_accept.guti_5g_present) {
guti_5g = registration_accept.guti_5g.guti_5g();
send_reg_complete = true;
}
if (send_reg_complete == true) {
send_registration_complete();
}
// TODO: reset counters and everything what is needed by the specification
t3521.set(registration_accept.t3512_value.timer_value);
registration_proc.run();
state.set_registered(mm5g_state_t::registered_substate_t::normal_service);
return SRSRAN_SUCCESS;
}
int nas_5g::handle_registration_reject(registration_reject_t& registration_reject)
{
logger.info("Handling Registration Reject");
return SRSRAN_SUCCESS;
}
int nas_5g::handle_authentication_request(authentication_request_t& authentication_request)
int nas_5g::handle_authentication_request(authentication_request_t& authentication_request)
{
logger.info("Handling Registration Request");
@ -742,12 +742,14 @@ int nas_5g::handle_security_mode_command(security_mode_command_t& security_m
ctxt.rx_count++;
return SRSRAN_SUCCESS;
}
int nas_5g::handle_deregistration_accept_ue_terminated(
deregistration_accept_ue_terminated_t& deregistration_accept_ue_terminated)
{
logger.info("Handling Deregistration Accept UE Terminated");
return SRSRAN_SUCCESS;
}
int nas_5g::handle_deregistration_request_ue_terminated(
deregistration_request_ue_terminated_t& deregistration_request_ue_terminated)
{
@ -755,4 +757,277 @@ int nas_5g::handle_deregistration_request_ue_terminated(
return SRSRAN_SUCCESS;
}
int nas_5g::handle_dl_nas_transport(srsran::nas_5g::dl_nas_transport_t& dl_nas_transport)
{
logger.info("Handling DL NAS transport");
switch (dl_nas_transport.payload_container_type.payload_container_type) {
case payload_container_type_t::Payload_container_type_type_::options::n1_sm_information:
return handle_n1_sm_information(dl_nas_transport.payload_container.payload_container_contents);
break;
default:
logger.warning("Not handling payload container %x",
dl_nas_transport.payload_container_type.payload_container_type.value);
break;
}
return SRSRAN_SUCCESS;
}
int nas_5g::handle_n1_sm_information(std::vector<uint8_t> payload_container_contents)
{
logger.info(payload_container_contents.data(),
payload_container_contents.size(),
"Payload contents (length %d)",
payload_container_contents.size());
nas_5gs_msg nas_msg;
nas_msg.unpack(payload_container_contents);
switch (nas_msg.hdr.message_type) {
case msg_opts::options::pdu_session_establishment_accept:
pdu_session_establishment_proc.trigger(nas_msg.pdu_session_establishment_accept());
break;
case msg_opts::options::pdu_session_establishment_reject:
pdu_session_establishment_proc.trigger(nas_msg.pdu_session_establishment_reject());
break;
default:
logger.error(
"Not handling NAS message type: %s (0x%02x)", nas_msg.hdr.message_type.to_string(), nas_msg.hdr.message_type);
break;
}
return SRSRAN_SUCCESS;
}
/*******************************************************************************
* NAS Timers
******************************************************************************/
void nas_5g::timer_expired(uint32_t timeout_id)
{
// TODO
}
/*******************************************************************************
* UE Stack & RRC Interface
******************************************************************************/
bool nas_5g::is_registered()
{
return state.get_state() == mm5g_state_t::state_t::registered;
}
int nas_5g::switch_on()
{
logger.info("Switching on");
state.set_deregistered(mm5g_state_t::deregistered_substate_t::plmn_search);
return SRSRAN_SUCCESS;
}
int nas_5g::switch_off()
{
logger.info("Switching off");
// TODO
return SRSRAN_SUCCESS;
}
int nas_5g::enable_data()
{
logger.info("Enabling data services");
return switch_on();
}
int nas_5g::disable_data()
{
logger.info("Disabling data services");
// TODO
return SRSRAN_SUCCESS;
}
int nas_5g::start_service_request()
{
logger.info("Service Request");
// TODO
return SRSRAN_SUCCESS;
}
/*******************************************************************************
* Helpers
******************************************************************************/
void nas_5g::fill_security_caps(srsran::nas_5g::ue_security_capability_t& sec_caps)
{
if (ia5g_caps[0] == true) {
sec_caps.ia0_5g_supported = true;
}
if (ia5g_caps[1] == true) {
sec_caps.ia1_128_5g_supported = true;
}
if (ia5g_caps[2] == true) {
sec_caps.ia2_128_5g_supported = true;
}
if (ia5g_caps[3] == true) {
sec_caps.ia3_128_5g_supported = true;
}
if (ia5g_caps[4] == true) {
sec_caps.ia4_5g_supported = true;
}
if (ia5g_caps[5] == true) {
sec_caps.ia5_5g_supported = true;
}
if (ia5g_caps[6] == true) {
sec_caps.ia6_5g_supported = true;
}
if (ia5g_caps[7] == true) {
sec_caps.ia7_5g_supported = true;
}
if (ea5g_caps[0] == true) {
sec_caps.ea0_5g_supported = true;
}
if (ea5g_caps[1] == true) {
sec_caps.ea1_128_5g_supported = true;
}
if (ea5g_caps[2] == true) {
sec_caps.ea2_128_5g_supported = true;
}
if (ea5g_caps[3] == true) {
sec_caps.ea3_128_5g_supported = true;
}
if (ea5g_caps[4] == true) {
sec_caps.ea4_5g_supported = true;
}
if (ea5g_caps[5] == true) {
sec_caps.ea5_5g_supported = true;
}
if (ea5g_caps[6] == true) {
sec_caps.ea6_5g_supported = true;
}
if (ea5g_caps[7] == true) {
sec_caps.ea7_5g_supported = true;
}
}
/*******************************************************************************
* Helpers for Session Management
******************************************************************************/
int nas_5g::trigger_pdu_session_est()
{
if (unestablished_pdu_sessions() == true) {
pdu_session_cfg_t pdu_session_cfg;
uint16_t pdu_session_id;
get_unestablished_pdu_session(pdu_session_id, pdu_session_cfg);
pdu_session_establishment_proc.launch(pdu_session_id, pdu_session_cfg);
}
return SRSRAN_SUCCESS;
}
int nas_5g::init_pdu_sessions(std::vector<pdu_session_cfg_t> pdu_session_cfgs)
{
uint16_t i = 0;
for (auto pdu_session_cfg : pdu_session_cfgs) {
pdu_sessions[i].configured = true;
pdu_sessions[i].pdu_session_id = i + 1;
pdu_sessions[i].pdu_session_cfg = pdu_session_cfg;
}
return SRSRAN_SUCCESS;
}
int nas_5g::configure_pdu_session(uint16_t pdu_session_id)
{
for (auto pdu_session : pdu_sessions) {
if (pdu_session.pdu_session_id == pdu_session_id) {
pdu_session.established = true;
}
}
return SRSRAN_SUCCESS;
}
bool nas_5g::unestablished_pdu_sessions()
{
for (auto pdu_session : pdu_sessions) {
if (pdu_session.configured == true && pdu_session.established == false) {
return true;
}
}
return false;
}
int nas_5g::get_unestablished_pdu_session(uint16_t& pdu_session_id, pdu_session_cfg_t& pdu_session_cfg)
{
for (auto pdu_session : pdu_sessions) {
if (pdu_session.configured == true && pdu_session.established == false) {
pdu_session_id = pdu_session.pdu_session_id;
pdu_session_cfg = pdu_session.pdu_session_cfg;
}
}
return SRSRAN_SUCCESS;
}
int nas_5g::add_pdu_session(uint16_t pdu_session_id,
uint16_t pdu_session_type,
srsran::nas_5g::pdu_address_t pdu_address)
{
char* err_str = nullptr;
// Copy IPv4
uint32_t ip_addr = 0;
ip_addr |= pdu_address.ipv4.data()[0] << 24u;
ip_addr |= pdu_address.ipv4.data()[1] << 16u;
ip_addr |= pdu_address.ipv4.data()[2] << 8u;
ip_addr |= pdu_address.ipv4.data()[3];
// Copy IPv6
uint8_t ipv6_if_id[8] = {};
memcpy(ipv6_if_id, pdu_address.ipv6.data(), 8);
if (!(pdu_session_type == LIBLTE_MME_PDN_TYPE_IPV4V6 || pdu_session_type == LIBLTE_MME_PDN_TYPE_IPV4 ||
pdu_session_type == LIBLTE_MME_PDN_TYPE_IPV6)) {
logger.warning("PDU session typed expected to be of IPV4 or IPV6 or IPV4V6");
return SRSRAN_ERROR;
}
if (gw->setup_if_addr(pdu_session_id, pdu_session_type, ip_addr, ipv6_if_id, err_str)) {
logger.error("%s - %s", gw_setup_failure_str.c_str(), err_str ? err_str : "");
srsran::console("%s\n", gw_setup_failure_str.c_str());
return SRSRAN_ERROR;
}
if (pdu_session_type == LIBLTE_MME_PDN_TYPE_IPV4V6 || pdu_session_type == LIBLTE_MME_PDN_TYPE_IPV4) {
logger.info("PDU Session Establishment successful. IP: %u.%u.%u.%u",
pdu_address.ipv4.data()[0],
pdu_address.ipv4.data()[1],
pdu_address.ipv4.data()[2],
pdu_address.ipv4.data()[3]);
srsran::console("PDU Session Establishment successful. IP: %u.%u.%u.%u\n",
pdu_address.ipv4.data()[0],
pdu_address.ipv4.data()[1],
pdu_address.ipv4.data()[2],
pdu_address.ipv4.data()[3]);
}
if (pdu_session_type == LIBLTE_MME_PDN_TYPE_IPV4V6 || pdu_session_type == LIBLTE_MME_PDN_TYPE_IPV6) {
logger.info("PDU Session Establishment successful. IPv6 interface id: %02x%02x:%02x%02x:%02x%02x:%02x%02x",
pdu_address.ipv6.data()[0],
pdu_address.ipv6.data()[1],
pdu_address.ipv6.data()[2],
pdu_address.ipv6.data()[3],
pdu_address.ipv6.data()[4],
pdu_address.ipv6.data()[5],
pdu_address.ipv6.data()[6],
pdu_address.ipv6.data()[7]);
srsran::console("PDU Session Establishment successful. IPv6 interface id: %02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
pdu_address.ipv6.data()[0],
pdu_address.ipv6.data()[1],
pdu_address.ipv6.data()[2],
pdu_address.ipv6.data()[3],
pdu_address.ipv6.data()[4],
pdu_address.ipv6.data()[5],
pdu_address.ipv6.data()[6],
pdu_address.ipv6.data()[7]);
}
return SRSRAN_SUCCESS;
}
} // namespace srsue

@ -35,5 +35,54 @@ srsran::proc_outcome_t nas_5g::registration_procedure::step()
return srsran::proc_outcome_t::success;
}
// PDU Sessions Establishment Procedure
nas_5g::pdu_session_establishment_procedure::pdu_session_establishment_procedure(
nas_5g_interface_procedures* parent_nas_,
srslog::basic_logger& logger_) :
logger(logger_), parent_nas(parent_nas_)
{}
srsran::proc_outcome_t nas_5g::pdu_session_establishment_procedure::init(const uint16_t pdu_session_id_,
const pdu_session_cfg_t pdu_session_cfg)
{
// Get PDU transaction identity
transaction_identity = parent_nas->allocate_next_proc_trans_id();
pdu_session_id = pdu_session_id_;
parent_nas->send_pdu_session_establishment_request(transaction_identity, pdu_session_id, pdu_session_cfg);
return srsran::proc_outcome_t::yield;
}
srsran::proc_outcome_t nas_5g::pdu_session_establishment_procedure::react(
const srsran::nas_5g::pdu_session_establishment_accept_t& pdu_session_est_accept)
{
// TODO check the pdu session values
if (pdu_session_est_accept.dnn_present == false) {
logger.warning("Expected DNN in PDU session establishment accept");
return proc_outcome_t::error;
}
if (pdu_session_est_accept.pdu_address_present == false) {
logger.warning("Expected PDU Address in PDU session establishment accept");
return proc_outcome_t::error;
}
if (parent_nas->add_pdu_session(pdu_session_id,
pdu_session_est_accept.selected_pdu_session_type.pdu_session_type_value,
pdu_session_est_accept.pdu_address) != SRSRAN_SUCCESS) {
logger.warning("Adding PDU session failed\n");
return srsran::proc_outcome_t::error;
}
return srsran::proc_outcome_t::success;
}
srsran::proc_outcome_t nas_5g::pdu_session_establishment_procedure::react(
const srsran::nas_5g::pdu_session_establishment_reject_t& session_est_reject)
{
return srsran::proc_outcome_t::success;
}
srsran::proc_outcome_t nas_5g::pdu_session_establishment_procedure::step()
{
return srsran::proc_outcome_t::success;
}
} // namespace srsue
Loading…
Cancel
Save