s1ap - simplified erab release procedure

master
Francisco 4 years ago committed by Francisco Paisana
parent c5fc543516
commit 76978f0d14

@ -49,6 +49,25 @@ using bearers_subject_to_status_transfer_list_l =
using rrc_establishment_cause_e = enumerated<rrc_establishment_cause_opts, true, 3>;
using cause_radio_network_e = enumerated<cause_radio_network_opts, true, 4>;
/**************************
* S1AP Obj Id
*************************/
template <typename T>
uint32_t get_obj_id(const T& obj);
template <typename T>
bool lower_obj_id(const T& lhs, const T& rhs)
{
return get_obj_id(lhs) < get_obj_id(rhs);
}
template <typename T>
bool equal_obj_id(const T& lhs, const T& rhs)
{
return get_obj_id(lhs) == get_obj_id(rhs);
}
} // namespace s1ap
} // namespace asn1

@ -33,13 +33,18 @@ public:
virtual void
modify_erabs(uint16_t rnti,
srsran::const_span<const asn1::s1ap::erab_to_be_modified_item_bearer_mod_req_s*> erabs_to_modify) = 0;
virtual bool has_erab(uint16_t rnti, uint32_t erab_id) const = 0;
virtual bool release_erabs(uint32_t rnti) = 0;
virtual void release_erabs(uint32_t rnti,
srsran::const_span<uint16_t> erabs_to_release,
const asn1::unbounded_octstring<true>* nas_pdu) = 0;
virtual bool has_erab(uint16_t rnti, uint32_t erab_id) const = 0;
virtual bool release_erabs(uint32_t rnti) = 0;
/**
* Release E-RAB id
* @return error if E-RAB id or rnti were not found
*/
virtual int release_erab(uint16_t rnti, uint16_t erab_id) = 0;
virtual void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& ue_paging_id) = 0;
/// Notify UE of ERAB updates (done via RRC Reconfiguration Message)
virtual int notify_ue_erab_updates(uint16_t rnti, const asn1::unbounded_octstring<true>* nas_pdu) = 0;
/**
* Reports the reception of S1 HandoverCommand / HandoverPreparationFailure or abnormal conditions during
* S1 Handover preparation back to RRC.

@ -46,7 +46,7 @@ INSTALL(TARGETS rrc_asn1 DESTINATION ${LIBRARY_DIR})
# S1AP ASN1 lib
add_library(s1ap_asn1 STATIC
s1ap.cc)
s1ap.cc s1ap_utils.cc)
target_compile_options(s1ap_asn1 PRIVATE "-Os")
target_link_libraries(s1ap_asn1 asn1_utils srsran_common)
INSTALL(TARGETS s1ap_asn1 DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,33 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsran/asn1/s1ap_utils.h"
#include "srsran/asn1/s1ap.h"
namespace asn1 {
namespace s1ap {
template <>
uint32_t get_obj_id<erab_item_s>(const erab_item_s& obj)
{
return obj.erab_id;
}
template <>
uint32_t get_obj_id<protocol_ie_single_container_s<erab_to_be_setup_item_ctxt_su_req_ies_o> >(
const protocol_ie_single_container_s<erab_to_be_setup_item_ctxt_su_req_ies_o>& obj)
{
return obj.value.erab_to_be_setup_item_ctxt_su_req().erab_id;
}
} // namespace s1ap
} // namespace asn1

@ -91,9 +91,7 @@ public:
const asn1::s1ap::erab_level_qos_params_s& qos_params,
const asn1::unbounded_octstring<true>* nas_pdu);
bool release_erabs(uint32_t rnti) override;
void release_erabs(uint32_t rnti,
srsran::const_span<uint16_t> erabs_to_release,
const asn1::unbounded_octstring<true>* nas_pdu) override;
int release_erab(uint16_t rnti, uint16_t erab_id) override;
void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& UEPagingID) override;
void ho_preparation_complete(uint16_t rnti,
rrc::ho_prep_result result,
@ -104,6 +102,8 @@ public:
asn1::s1ap::cause_c& failure_cause) override;
void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs) override;
int notify_ue_erab_updates(uint16_t rnti, const asn1::unbounded_octstring<true>* nas_pdu) override;
// rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override;

@ -85,7 +85,7 @@ public:
uint32_t teid_out,
const asn1::unbounded_octstring<true>* nas_pdu,
asn1::s1ap::cause_c& cause);
bool release_erab(uint8_t erab_id);
int release_erab(uint8_t erab_id);
void release_erabs();
bool modify_erab(uint8_t erab_id,
const asn1::s1ap::erab_level_qos_params_s& qos,

@ -113,7 +113,7 @@ public:
bool setup_erabs(const asn1::s1ap::erab_to_be_setup_list_ctxt_su_req_l& e);
bool setup_erabs(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e);
bool release_erabs();
bool release_erab(uint32_t erab_id);
int release_erab(uint32_t erab_id);
bool modify_erab(uint16_t erab_id,
const asn1::s1ap::erab_level_qos_params_s& qos_params,
const asn1::unbounded_octstring<true>* nas_pdu);

@ -141,6 +141,10 @@ private:
asn1::s1ap::s1_setup_resp_s s1setupresponse;
// Procedure state
srsran::bounded_vector<uint16_t, ASN1_S1AP_MAXNOOF_ERABS> updated_erabs;
srsran::bounded_vector<asn1::s1ap::erab_item_s, ASN1_S1AP_MAXNOOF_ERABS> failed_cfg_erabs;
void build_tai_cgi();
bool connect_mme();
bool setup_s1();
@ -243,9 +247,8 @@ private:
bool send_initial_ctxt_setup_response(const asn1::s1ap::init_context_setup_resp_s& res_);
bool send_initial_ctxt_setup_failure();
bool send_erab_setup_response(const asn1::s1ap::erab_setup_resp_s& res_);
bool send_erab_release_response(
const srsran::bounded_vector<uint16_t, MAX_NOF_ERABS>& erabs_released,
const srsran::static_circular_map<uint16_t, asn1::s1ap::erab_item_s, MAX_NOF_ERABS>& erabs_failed_to_release);
bool send_erab_release_response(srsran::const_span<uint16_t> erabs_released,
srsran::const_span<asn1::s1ap::erab_item_s> erabs_failed);
bool send_erab_modify_response(
srsran::const_span<const asn1::s1ap::erab_to_be_modified_item_bearer_mod_req_s*> erabs_modified,
srsran::const_span<std::pair<uint16_t, asn1::s1ap::cause_c> > erabs_failed_to_modify);

@ -358,23 +358,28 @@ bool rrc::release_erabs(uint32_t rnti)
return ret;
}
void rrc::release_erabs(uint32_t rnti,
srsran::const_span<uint16_t> erabs_to_release,
const asn1::unbounded_octstring<true>* nas_pdu)
int rrc::release_erab(uint16_t rnti, uint16_t erab_id)
{
logger.info("Releasing E-RAB for 0x%x", rnti);
logger.info("Releasing E-RAB id=%d for 0x%x", erab_id, rnti);
auto user_it = users.find(rnti);
if (user_it == users.end()) {
logger.warning("Unrecognised rnti: 0x%x", rnti);
return;
return SRSRAN_ERROR;
}
for (uint16_t erab_id : erabs_to_release) {
bool ret = user_it->second->release_erab(erab_id);
srsran_expect(ret, "E-RAB id=%d not found", erab_id);
return user_it->second->release_erab(erab_id);
}
int rrc::notify_ue_erab_updates(uint16_t rnti, const asn1::unbounded_octstring<true>* nas_pdu)
{
auto user_it = users.find(rnti);
if (user_it == users.end()) {
logger.warning("Unrecognised rnti: 0x%x", rnti);
return SRSRAN_ERROR;
}
user_it->second->send_connection_reconf(nullptr, false, nas_pdu);
return SRSRAN_SUCCESS;
}
bool rrc::has_erab(uint16_t rnti, uint32_t erab_id) const

@ -290,12 +290,12 @@ int bearer_cfg_handler::add_erab(uint8_t
return SRSRAN_SUCCESS;
}
bool bearer_cfg_handler::release_erab(uint8_t erab_id)
int bearer_cfg_handler::release_erab(uint8_t erab_id)
{
auto it = erabs.find(erab_id);
if (it == erabs.end()) {
logger->warning("The user rnti=0x%x does not contain ERAB-ID=%d", rnti, erab_id);
return false;
return SRSRAN_ERROR;
}
uint8_t drb_id = erab_id - 4;
@ -305,7 +305,7 @@ bool bearer_cfg_handler::release_erab(uint8_t erab_id)
erabs.erase(it);
erab_info_list.erase(erab_id);
return true;
return SRSRAN_SUCCESS;
}
void bearer_cfg_handler::release_erabs()

@ -1050,7 +1050,7 @@ bool rrc::ue::release_erabs()
return true;
}
bool rrc::ue::release_erab(uint32_t erab_id)
int rrc::ue::release_erab(uint32_t erab_id)
{
return bearer_list.release_erab(erab_id);
}

@ -60,6 +60,22 @@ asn1::bounded_bitstring<1, 160, true, true> addr_to_asn1(const char* addr_str)
return transport_layer_addr;
}
/// Helper to add ERAB items that are duplicates in the received S1AP message
template <typename List>
void add_repeated_erab_ids(const List& list,
srsran::bounded_vector<erab_item_s, ASN1_S1AP_MAXNOOF_ERABS>& failed_cfg_erabs)
{
for (auto it = list.begin(); it != list.end(); ++it) {
for (auto it2 = it + 1; it2 != list.end(); ++it2) {
if (get_obj_id(*it) == get_obj_id(*it2)) {
failed_cfg_erabs.push_back(erab_item_s());
failed_cfg_erabs.back().erab_id = get_obj_id(*it);
failed_cfg_erabs.back().cause.set_radio_network().value = cause_radio_network_opts::multiple_erab_id_instances;
}
}
}
}
/*********************************************************
* TS 36.413 - Section 8.4.1 - "Handover Preparation"
*********************************************************/
@ -823,65 +839,51 @@ bool s1ap::handle_erabmodifyrequest(const erab_modify_request_s& msg)
*/
bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg)
{
if (msg.ext) {
logger.warning("Not handling S1AP message extension");
}
WarnUnsupportFeature(msg.ext, "S1AP message extension");
ue* u =
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) {
return false;
}
srsran::bounded_vector<uint16_t, MAX_NOF_ERABS> erabs_to_release;
srsran::static_circular_map<uint16_t, erab_item_s, MAX_NOF_ERABS> erabs_failed_to_release;
const auto& msg_erabs = msg.protocol_ies.erab_to_be_released_list.value;
failed_cfg_erabs.clear();
updated_erabs.clear();
for (const auto& msg_erab : msg_erabs) {
const erab_item_s& e = msg_erab.value.erab_item();
if (e.erab_id >= erabs_failed_to_release.capacity()) {
logger.warning("Not handling E-RAB Ids above %zd", erabs_to_release.capacity());
continue;
}
if (erabs_to_release.full()) {
logger.warning("Not handling more than %zd releases per ERAB release request message",
erabs_to_release.capacity());
break;
}
auto is_repeated_erab_id = [this](uint8_t erab_id) {
return (std::count(updated_erabs.begin(), updated_erabs.end(), erab_id) > 0) or
(std::any_of(failed_cfg_erabs.begin(), failed_cfg_erabs.end(), [erab_id](const erab_item_s& e) {
return e.erab_id == erab_id;
}));
};
for (const auto& item : msg.protocol_ies.erab_to_be_released_list.value) {
const auto& erab = item.value.erab_item();
// Check if E-RAB exists. If not, add to "erabs_failed_to_modify" with "unknown_erab_id" cause
if (not rrc->has_erab(u->ctxt.rnti, e.erab_id)) {
erabs_failed_to_release.overwrite(e.erab_id, erab_item_s());
erabs_failed_to_release[e.erab_id].cause.set_radio_network().value = cause_radio_network_opts::unknown_erab_id;
if (is_repeated_erab_id(erab.erab_id)) {
// TS 36.413, 8.2.3.3 - ignore the duplication of E-RAB ID IEs
continue;
}
// Check Repeated E-RABs in the modification list. If repeated, add to the list of "erabs_failed_to_modify"
// with cause "multiple_erab_id_instances"
for (const auto& msg_erab2 : msg_erabs) {
const erab_item_s& e2 = msg_erab2.value.erab_item();
if (&e2 != &e and e2.erab_id == e.erab_id) {
erabs_failed_to_release.overwrite(e.erab_id, erab_item_s());
erabs_failed_to_release[e.erab_id].cause.set_radio_network().value =
cause_radio_network_opts::multiple_erab_id_instances;
break;
}
}
if (erabs_failed_to_release.has_space(e.erab_id)) {
continue;
if (rrc->release_erab(u->ctxt.rnti, erab.erab_id) == SRSRAN_SUCCESS) {
updated_erabs.push_back(erab.erab_id);
} else {
failed_cfg_erabs.push_back(erab_item_s());
failed_cfg_erabs.back().erab_id = erab.erab_id;
failed_cfg_erabs.back().cause.set_radio_network().value = cause_radio_network_opts::unknown_erab_id;
}
// Add to the list to modify
erabs_to_release.push_back(e.erab_id);
}
// Release E-RABs from RRC
std::sort(erabs_to_release.begin(), erabs_to_release.end());
erabs_to_release.erase(std::unique(erabs_to_release.begin(), erabs_to_release.end()), erabs_to_release.end());
rrc->release_erabs(
u->ctxt.rnti, erabs_to_release, msg.protocol_ies.nas_pdu_present ? &msg.protocol_ies.nas_pdu.value : nullptr);
// Sort E-RABs to be sent
std::sort(failed_cfg_erabs.begin(), failed_cfg_erabs.end(), &lower_obj_id<erab_item_s>);
std::sort(updated_erabs.begin(), updated_erabs.end());
// Notify RRC of E-RAB update. (RRC reconf message is going to be sent.
if (not updated_erabs.empty()) {
rrc->notify_ue_erab_updates(u->ctxt.rnti, nullptr);
}
// Send E-RAB release response back to the MME
if (not u->send_erab_release_response(erabs_to_release, erabs_failed_to_release)) {
if (not u->send_erab_release_response(updated_erabs, failed_cfg_erabs)) {
logger.info("Failed to send ERABReleaseResponse");
return false;
}
@ -1479,14 +1481,9 @@ bool s1ap::ue::send_uectxtmodifyfailure(const cause_c& cause)
* @param erabs_failed_to_release
* @return true if message was sent
*/
bool s1ap::ue::send_erab_release_response(
const srsran::bounded_vector<uint16_t, MAX_NOF_ERABS>& erabs_released,
const srsran::static_circular_map<uint16_t, asn1::s1ap::erab_item_s, MAX_NOF_ERABS>& erabs_failed_to_release)
bool s1ap::ue::send_erab_release_response(srsran::const_span<uint16_t> erabs_released,
srsran::const_span<asn1::s1ap::erab_item_s> erabs_failed)
{
if (not s1ap_ptr->mme_connected) {
return false;
}
asn1::s1ap::s1ap_pdu_c tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_ERAB_RELEASE);
@ -1507,14 +1504,12 @@ bool s1ap::ue::send_erab_release_response(
}
// Fill in which E-RABs were *not* successfully released
if (not erabs_failed_to_release.empty()) {
if (not erabs_failed.empty()) {
container.erab_failed_to_release_list_present = true;
container.erab_failed_to_release_list.value.resize(erabs_failed_to_release.size());
size_t count = 0;
for (const auto& erab : erabs_failed_to_release) {
container.erab_failed_to_release_list.value[count].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM);
container.erab_failed_to_release_list.value[count].value.erab_item() = erab->second;
count++;
container.erab_failed_to_release_list.value.resize(erabs_failed.size());
for (size_t i = 0; i < erabs_failed.size(); ++i) {
container.erab_failed_to_release_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM);
container.erab_failed_to_release_list.value[i].value.erab_item() = erabs_failed[i];
}
}

@ -175,10 +175,7 @@ public:
{}
bool has_erab(uint16_t rnti, uint32_t erab_id) const override { return true; }
bool release_erabs(uint32_t rnti) override { return true; }
void release_erabs(uint32_t rnti,
srsran::const_span<uint16_t> erabs_to_release,
const asn1::unbounded_octstring<true>* nas_pdu) override
{}
int release_erab(uint16_t rnti, uint16_t erab_id) override { return SRSRAN_SUCCESS; }
void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& ue_paging_id) override {}
void ho_preparation_complete(uint16_t rnti,
ho_prep_result result,
@ -192,6 +189,8 @@ public:
return SRSRAN_INVALID_RNTI;
}
void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs) override {}
int notify_ue_erab_updates(uint16_t rnti, const asn1::unbounded_octstring<true>* nas_pdu) { return SRSRAN_SUCCESS; }
};
} // namespace srsenb

Loading…
Cancel
Save