add S1 Handover Request handling in target eNB

master
Francisco Paisana 4 years ago
parent 857cc141c7
commit 26f46ea067

@ -299,7 +299,7 @@ public:
* Allocate a C-RNTI for a new user, without adding it to the phy layer and scheduler yet
* @return value of the allocated C-RNTI
*/
virtual uint16_t allocate_rnti() = 0;
virtual uint16_t reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg) = 0;
};
class mac_interface_rlc
@ -435,6 +435,10 @@ public:
* @param container TargeteNB RRCConnectionReconfiguration message with MobilityControlInfo
*/
virtual void ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t container) = 0;
virtual uint16_t
start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd) = 0;
};
// GTPU interface for PDCP

@ -397,6 +397,7 @@ bool protocol_ie_single_container_s<ies_set_paramT_>::load_info_obj(const uint32
value = ies_set_paramT_::get_value(id);
return value.type().value != ies_set_paramT_::value_c::types_opts::nulltype;
}
template bool protocol_ie_single_container_s<erab_admitted_item_ies_o>::load_info_obj(const uint32_t& id_);
// ProtocolIE-FieldPair{S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= SEQUENCE{{S1AP-PROTOCOL-IES-PAIR}}
template <class ies_set_paramT_>

@ -93,19 +93,20 @@ public:
int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) override;
int rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) override;
/* Handover-related */
uint16_t reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg) override;
bool process_pdus();
void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]);
void
write_mcch(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s* mcch) override;
/* Allocate C-RNTI */
uint16_t allocate_rnti() final;
private:
static const uint32_t cfi = 3;
bool check_ue_exists(uint16_t rnti);
uint16_t allocate_rnti();
std::mutex rnti_mutex;

@ -88,6 +88,9 @@ public:
bool release_erabs(uint32_t rnti) override;
void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& UEPagingID) override;
void ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t rrc_container) override;
uint16_t start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd) override;
// rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override;
@ -95,7 +98,7 @@ public:
uint32_t get_nof_users();
// logging
typedef enum { Rx = 0, Tx } direction_t;
typedef enum { Rx = 0, Tx, S1AP } direction_t;
template <class T>
void log_rrc_message(const std::string& source,
const direction_t dir,

@ -86,6 +86,10 @@ public:
rrc* get_rrc() { return rrc_ptr; }
const rrc* get_rrc() const { return rrc_ptr; }
uint16_t start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd);
private:
// args
rrc* rrc_ptr = nullptr;
@ -107,6 +111,11 @@ public:
void handle_ho_preparation_complete(bool is_success, srslte::unique_byte_buffer_t container);
bool is_ho_running() const { return not is_in_state<idle_st>(); }
// S1-Handover
bool start_s1_tenb_ho(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd);
private:
// Handover from source cell
bool start_ho_preparation(uint32_t target_eci, uint8_t measobj_id, bool fwd_direct_path_available);

@ -81,6 +81,8 @@ public:
srslte::plmn_id_t target_plmn,
srslte::unique_byte_buffer_t rrc_container) override;
bool send_enb_status_transfer_proc(uint16_t rnti, std::vector<bearer_status_info>& bearer_status_list) override;
bool send_ho_failure(uint32_t mme_ue_s1ap_id);
bool send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, uint16_t rnti, srslte::unique_byte_buffer_t ho_cmd);
// void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps);
// Stack interface
@ -145,6 +147,7 @@ private:
// handover
bool handle_hopreparationfailure(const asn1::s1ap::ho_prep_fail_s& msg);
bool handle_s1hocommand(const asn1::s1ap::ho_cmd_s& msg);
bool handle_ho_request(const asn1::s1ap::ho_request_s& msg);
// UE-specific data and procedures
struct ue {
@ -193,9 +196,6 @@ private:
ue_ctxt_t ctxt = {};
uint16_t stream_id = 1;
// user procedures
srslte::proc_t<ho_prep_proc_t> ho_prep_proc;
private:
bool
send_ho_required(uint32_t target_eci_, srslte::plmn_id_t target_plmn_, srslte::unique_byte_buffer_t rrc_container);
@ -209,6 +209,10 @@ private:
bool release_requested = false;
srslte::unique_timer ts1_reloc_prep; ///< TS1_{RELOCprep} - max time for HO preparation
srslte::unique_timer ts1_reloc_overall; ///< TS1_{RELOCOverall}
public:
// user procedures
srslte::proc_t<ho_prep_proc_t> ho_prep_proc;
};
class user_list

@ -443,6 +443,46 @@ uint16_t mac::allocate_rnti()
return rnti;
}
uint16_t mac::reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg)
{
// Get pre-allocated UE object
if (ue_pool.empty()) {
Error("Ignoring RACH attempt. UE pool empty.\n");
return SRSLTE_INVALID_RNTI;
}
auto ue_ptr = ue_pool.wait_pop();
uint16_t rnti = ue_ptr->get_rnti();
// Set PCAP if available
if (pcap != nullptr) {
ue_ptr->start_pcap(pcap);
}
{
srslte::rwlock_write_guard lock(rwlock);
ue_db[rnti] = std::move(ue_ptr);
}
// Add new user to the scheduler so that it can RX/TX SRB0
if (scheduler.ue_cfg(rnti, ue_cfg) != SRSLTE_SUCCESS) {
Error("Registering new user rnti=0x%x to SCHED\n", rnti);
return SRSLTE_INVALID_RNTI;
}
// Register new user in RRC
rrc_h->add_user(rnti, ue_cfg);
// Add temporal rnti to the PHY
if (phy_h->add_rnti(rnti, ue_cfg.supported_cc_list[0].enb_cc_idx) != SRSLTE_SUCCESS) {
Error("Registering c-rnti=0x%x to PHY\n", rnti);
return SRSLTE_INVALID_RNTI;
}
// Allocate one new UE object in advance
prealloc_ue(1);
return rnti;
}
void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx, uint32_t time_adv)
{
static srslte::mutexed_tprof<srslte::avg_time_stats> rach_tprof("rach_tprof", "MAC", 1);

@ -462,6 +462,13 @@ void rrc::ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique
users.at(rnti)->mobility_handler->handle_ho_preparation_complete(is_success, std::move(rrc_container));
}
uint16_t rrc::start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd)
{
return enb_mobility_cfg->start_ho_ue_resource_alloc(msg, container, ho_cmd);
}
/*******************************************************************************
Private functions
All private functions are not mutexed and must be called from a mutexed environment

@ -409,6 +409,18 @@ var_meas_cfg_t var_meas_cfg_t::make(const asn1::rrc::meas_cfg_s& meas_cfg)
var.var_meas.quant_cfg_present = true;
var.var_meas.quant_cfg = meas_cfg.quant_cfg;
}
if (meas_cfg.s_measure_present) {
var.var_meas.s_measure_present = true;
var.var_meas.s_measure = meas_cfg.s_measure;
}
if (meas_cfg.speed_state_pars_present) {
var.var_meas.speed_state_pars_present = true;
var.var_meas.speed_state_pars.set(meas_cfg.speed_state_pars.type().value);
if (var.var_meas.speed_state_pars.type().value == setup_opts::setup) {
var.var_meas.speed_state_pars.setup().mob_state_params = meas_cfg.speed_state_pars.setup().mob_state_params;
var.var_meas.speed_state_pars.setup().time_to_trigger_sf = meas_cfg.speed_state_pars.setup().time_to_trigger_sf;
}
}
if (meas_cfg.report_cfg_to_rem_list_present or meas_cfg.meas_obj_to_rem_list_present or
meas_cfg.meas_id_to_rem_list_present) {
srslte::logmap::get("RRC")->warning("Remove lists not handled by the var_meas_cfg_t method\n");
@ -456,6 +468,54 @@ rrc::enb_mobility_handler::enb_mobility_handler(rrc* rrc_) : rrc_ptr(rrc_), cfg(
}
}
uint16_t rrc::enb_mobility_handler::start_ho_ue_resource_alloc(
const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd)
{
// TODO: Decision Making on whether the same QoS of the source eNB can be provided by target eNB
/* Evaluate if cell exists */
uint32_t target_eci = container.target_cell_id.cell_id.to_number();
const cell_info_common* target_cell = rrc_ptr->cell_common_list->get_cell_id(rrc_details::eci_to_cellid(target_eci));
if (target_cell == nullptr) {
rrc_ptr->rrc_log->error("The S1-handover target cell_id=0x%x does not exist\n",
rrc_details::eci_to_cellid(target_eci));
return SRSLTE_INVALID_RNTI;
}
/* Allocate C-RNTI */
sched_interface::ue_cfg_t ue_cfg = {};
ue_cfg.supported_cc_list.resize(1);
ue_cfg.supported_cc_list[0].active = true;
ue_cfg.supported_cc_list[0].enb_cc_idx = target_cell->enb_cc_idx;
ue_cfg.ue_bearers[0].direction = sched_interface::ue_bearer_cfg_t::BOTH;
ue_cfg.supported_cc_list[0].dl_cfg.tm = SRSLTE_TM1;
uint16_t rnti = rrc_ptr->mac->reserve_new_crnti(ue_cfg);
if (rnti == SRSLTE_INVALID_RNTI) {
rrc_ptr->rrc_log->error("Failed to allocate C-RNTI resources\n");
return SRSLTE_INVALID_RNTI;
}
// /* Setup e-RABs & DRBs / establish an UL/DL S1 bearer to the S-GW */
// if (not setup_ue_erabs(rnti, msg)) {
// rrc_ptr->rrc_log->error("Failed to setup e-RABs for rnti=0x%x\n", );
// }
// TODO: KeNB derivations
auto it = rrc_ptr->users.find(rnti);
if (it == rrc_ptr->users.end()) {
rrc_ptr->rrc_log->error("Did not find rnti=0x%x in ue_db\n", rnti);
return SRSLTE_INVALID_RNTI;
}
ue* ue_ptr = it->second.get();
if (not ue_ptr->mobility_handler->start_s1_tenb_ho(msg, container, ho_cmd)) {
return SRSLTE_INVALID_RNTI;
}
return rnti;
}
/*************************************************************************************************
* rrc_mobility class
************************************************************************************************/
@ -529,9 +589,10 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg)
continue;
}
meas_ev.meas_cell = cell_it;
meas_ev.target_eci = std::find_if(meas_list_cfg.begin(), meas_list_cfg.end(), [pci](const meas_cell_cfg_t& c) {
return c.pci == pci;
})->eci;
meas_ev.target_eci = std::find_if(meas_list_cfg.begin(),
meas_list_cfg.end(),
[pci](const meas_cell_cfg_t& c) { return c.pci == pci; })
->eci;
// eNB found the respective cell. eNB takes "HO Decision"
// NOTE: From now we just choose the strongest.
@ -713,6 +774,70 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success, srsl
trigger(std::move(container));
}
/**
* Description: Handover Requested Acknowledgment (with success or failure)
* - TeNB --> MME
* - Response from TeNB on whether it was able to allocate resources for user doing handover
* - Preparation of HandoverCommand that goes inside the transparent container
* @return rnti of created ue
*/
bool rrc::ue::rrc_mobility::start_s1_tenb_ho(
const asn1::s1ap::ho_request_s& msg,
const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container,
srslte::byte_buffer_t& ho_cmd_pdu)
{
const cell_ctxt_dedicated* target_cell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX);
/* TS 36.331 10.2.2. - Decode HandoverPreparationInformation */
asn1::cbit_ref bref{container.rrc_container.data(), container.rrc_container.size()};
asn1::rrc::ho_prep_info_s hoprep;
if (hoprep.unpack(bref) != asn1::SRSASN_SUCCESS) {
rrc_enb->rrc_log->error("Failed to decode HandoverPreparatiobinformation in S1AP SourceENBToTargetENBContainer\n");
return false;
}
if (hoprep.crit_exts.type().value != c1_or_crit_ext_opts::c1 or
hoprep.crit_exts.c1().type().value != ho_prep_info_s::crit_exts_c_::c1_c_::types_opts::ho_prep_info_r8) {
rrc_enb->rrc_log->error("Only release 8 supported\n");
return false;
}
const ho_prep_info_r8_ies_s& hoprep_r8 = hoprep.crit_exts.c1().ho_prep_info_r8();
/* Prepare Handover Request Acknowledgment - Handover Command */
dl_dcch_msg_s dl_dcch_msg;
rrc_conn_recfg_r8_ies_s& recfg_r8 =
dl_dcch_msg.msg.set_c1().set_rrc_conn_recfg().crit_exts.set_c1().set_rrc_conn_recfg_r8();
// Fill fields common to all types of handover
fill_mobility_reconf_common(dl_dcch_msg, *target_cell->cell_common);
// Encode MeasConfig
var_meas_cfg_t current_var_meas = var_meas_cfg_t::make(hoprep_r8.as_cfg.source_meas_cfg);
recfg_r8.meas_cfg_present =
update_ue_var_meas_cfg(current_var_meas, target_cell->cell_common->enb_cc_idx, &recfg_r8.meas_cfg);
/* Prepare Handover Command to be sent via S1AP */
asn1::bit_ref bref2{ho_cmd_pdu.msg, ho_cmd_pdu.get_tailroom()};
if (dl_dcch_msg.pack(bref2) != asn1::SRSASN_SUCCESS) {
rrc_enb->rrc_log->error("Failed to pack HandoverCommand\n");
return false;
}
ho_cmd_pdu.N_bytes = bref2.distance_bytes();
rrc_enb->log_rrc_message("RRC container", direction_t::S1AP, &ho_cmd_pdu, dl_dcch_msg, "HandoverCommand");
asn1::rrc::ho_cmd_s ho_cmd;
asn1::rrc::ho_cmd_r8_ies_s& ho_cmd_r8 = ho_cmd.crit_exts.set_c1().set_ho_cmd_r8();
ho_cmd_r8.ho_cmd_msg.resize(bref2.distance_bytes());
memcpy(ho_cmd_r8.ho_cmd_msg.data(), ho_cmd_pdu.msg, bref2.distance_bytes());
bref2 = {ho_cmd_pdu.msg, ho_cmd_pdu.get_tailroom()};
if (ho_cmd.pack(bref2) != asn1::SRSASN_SUCCESS) {
rrc_enb->rrc_log->error("Failed to pack HandoverCommand\n");
return false;
}
ho_cmd_pdu.N_bytes = bref2.distance_bytes();
return true;
}
bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg,
uint32_t target_enb_cc_idx,
asn1::rrc::meas_cfg_s* diff_meas_cfg)
@ -740,6 +865,18 @@ bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const var_meas_cfg_t& source
return meas_cfg_present;
}
/**
* @brief Fills RRCConnectionReconfigurationMessage with Handover Command fields that are common to
* all types of handover (e.g. S1, intra-enb, X2), namely:
* - mobilityControlInformation
* - SecurityConfigHandover
* - RadioReconfiguration.PhyConfig
* - Scheduling Request setup
* - CQI report cfg
* - AntennaConfig
* @param msg
* @param target_cell
*/
void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg,
const cell_info_common& target_cell)
{
@ -760,6 +897,7 @@ void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s
mob_info.rr_cfg_common.p_max_present = true;
mob_info.rr_cfg_common.p_max = rrc_enb->cfg.sib1.p_max;
mob_info.carrier_freq_present = false; // same frequency handover for now
asn1::number_to_enum(mob_info.carrier_bw.dl_bw, target_cell.mib.dl_bw.to_number());
// Set security cfg
recfg_r8.security_cfg_ho_present = true;
@ -863,6 +1001,7 @@ bool rrc::ue::rrc_mobility::needs_intraenb_ho(idle_st& s, const ho_meas_report_e
void rrc::ue::rrc_mobility::s1_source_ho_st::wait_ho_req_ack_st::enter(s1_source_ho_st* f, const ho_meas_report_ev& ev)
{
f->log_h->console("Starting S1 Handover of rnti=0x%x to 0x%x.\n", f->parent_fsm()->rrc_ue->rnti, ev.target_eci);
f->log_h->info("Starting S1 Handover of rnti=0x%x to 0x%x.\n", f->parent_fsm()->rrc_ue->rnti, ev.target_eci);
f->report = ev;

@ -559,6 +559,13 @@ bool s1ap::handle_initiatingmessage(const init_msg_s& msg)
return handle_erabsetuprequest(msg.value.erab_setup_request());
case s1ap_elem_procs_o::init_msg_c::types_opts::ue_context_mod_request:
return handle_uecontextmodifyrequest(msg.value.ue_context_mod_request());
case s1ap_elem_procs_o::init_msg_c::types_opts::ho_request: {
bool outcome = handle_ho_request(msg.value.ho_request());
if (not outcome) {
send_ho_failure(msg.value.ho_request().protocol_ies.mme_ue_s1ap_id.value.value);
}
return outcome;
}
default:
s1ap_log->error("Unhandled initiating message: %s\n", msg.value.type().to_string().c_str());
}
@ -790,6 +797,106 @@ bool s1ap::handle_s1hocommand(const asn1::s1ap::ho_cmd_s& msg)
return true;
}
/**************************************************************
* TS 36.413 - Section 8.4.2 - "Handover Resource Allocation"
*************************************************************/
bool s1ap::handle_ho_request(const asn1::s1ap::ho_request_s& msg)
{
s1ap_log->info("Received S1 HO Request\n");
s1ap_log->console("Received S1 HO Request\n");
if (msg.ext or msg.protocol_ies.ho_restrict_list_present or
msg.protocol_ies.handov_type.value.value != handov_type_opts::intralte) {
s1ap_log->error("Not handling S1AP non-intra LTE handovers and extensions\n");
return false;
}
// Confirm the UE does not exist in TeNB
if (users.find_ue_mmeid(msg.protocol_ies.mme_ue_s1ap_id.value.value) != nullptr) {
s1ap_log->error("The provided MME_UE_S1AP_ID=%ld is already connected to the cell\n",
msg.protocol_ies.mme_ue_s1ap_id.value.value);
return false;
}
// Create user ctxt object and associated MME context
std::unique_ptr<ue> ue_ptr{new ue{this}};
ue_ptr->ctxt.mme_ue_s1ap_id_present = true;
ue_ptr->ctxt.mme_ue_s1ap_id = msg.protocol_ies.mme_ue_s1ap_id.value.value;
if (users.add_user(std::move(ue_ptr)) == nullptr) {
return false;
}
// Unpack Transparent Container
sourceenb_to_targetenb_transparent_container_s container;
asn1::cbit_ref bref{msg.protocol_ies.source_to_target_transparent_container.value.data(),
msg.protocol_ies.source_to_target_transparent_container.value.size()};
if (container.unpack(bref) != asn1::SRSASN_SUCCESS) {
s1ap_log->error("Failed to unpack SourceToTargetTransparentContainer\n");
return false;
}
// Handle Handover Resource Allocation
srslte::unique_byte_buffer_t ho_cmd = srslte::allocate_unique_buffer(*pool);
uint16_t rnti = rrc->start_ho_ue_resource_alloc(msg, container, *ho_cmd);
if (rnti == SRSLTE_INVALID_RNTI) {
return false;
}
return send_ho_req_ack(msg, rnti, std::move(ho_cmd));
}
bool s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id)
{
s1ap_pdu_c tx_pdu;
tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC);
ho_fail_ies_container& container = tx_pdu.unsuccessful_outcome().value.ho_fail().protocol_ies;
container.mme_ue_s1ap_id.value = mme_ue_s1ap_id;
// TODO: Setup cause
container.cause.value.set_radio_network().value = cause_radio_network_opts::ho_target_not_allowed;
return sctp_send_s1ap_pdu(tx_pdu, SRSLTE_INVALID_RNTI, "HandoverFailure");
}
bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg, uint16_t rnti, srslte::unique_byte_buffer_t ho_cmd)
{
s1ap_pdu_c tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC);
ho_request_ack_ies_container& container = tx_pdu.successful_outcome().value.ho_request_ack().protocol_ies;
ue* ue_ptr = users.find_ue_mmeid(msg.protocol_ies.mme_ue_s1ap_id.value.value);
ue_ptr->ctxt.rnti = rnti;
container.mme_ue_s1ap_id.value = msg.protocol_ies.mme_ue_s1ap_id.value.value;
container.enb_ue_s1ap_id.value = ue_ptr->ctxt.enb_ue_s1ap_id;
// TODO: Add admitted E-RABs
for (const auto& erab : msg.protocol_ies.erab_to_be_setup_list_ho_req.value) {
const erab_to_be_setup_item_ho_req_s& erabsetup = erab.value.erab_to_be_setup_item_ho_req();
container.erab_admitted_list.value.push_back({});
container.erab_admitted_list.value.back().load_info_obj(ASN1_S1AP_ID_ERAB_ADMITTED_ITEM);
auto& c = container.erab_admitted_list.value.back().value.erab_admitted_item();
c.erab_id = erabsetup.erab_id;
c.gtp_teid = erabsetup.gtp_teid;
c.transport_layer_address = erabsetup.transport_layer_address;
}
asn1::s1ap::targetenb_to_sourceenb_transparent_container_s transparent_container;
transparent_container.rrc_container.resize(ho_cmd->N_bytes);
memcpy(transparent_container.rrc_container.data(), ho_cmd->msg, ho_cmd->N_bytes);
auto& pdu = ho_cmd; // reuse pdu
asn1::bit_ref bref{pdu->msg, pdu->get_tailroom()};
if (transparent_container.pack(bref) != asn1::SRSASN_SUCCESS) {
s1ap_log->error("Failed to pack TargeteNBToSourceeNBTransparentContainer\n");
return false;
}
container.target_to_source_transparent_container.value.resize(bref.distance_bytes());
memcpy(container.target_to_source_transparent_container.value.data(), pdu->msg, bref.distance_bytes());
return sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverRequestAcknowledge");
}
/*******************************************************************************
/* S1AP message senders
********************************************************************************/
@ -1166,12 +1273,12 @@ bool s1ap::sctp_send_s1ap_pdu(const asn1::s1ap::s1ap_pdu_c& tx_pdu, uint32_t rnt
pcap->write_s1ap(buf->msg, buf->N_bytes);
}
if (rnti > 0) {
if (rnti != SRSLTE_INVALID_RNTI) {
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending %s for rnti=0x%x", procedure_name, rnti);
} else {
s1ap_log->info_hex(buf->msg, buf->N_bytes, "Sending %s to MME", procedure_name);
}
uint16_t streamid = rnti == 0 ? NONUE_STREAM_ID : users.find_ue_rnti(rnti)->stream_id;
uint16_t streamid = rnti == SRSLTE_INVALID_RNTI ? NONUE_STREAM_ID : users.find_ue_rnti(rnti)->stream_id;
ssize_t n_sent = sctp_sendmsg(s1ap_socket.fd(),
buf->msg,

@ -39,7 +39,7 @@ public:
void phy_config_enabled(uint16_t rnti, bool enabled) override {}
void write_mcch(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s* mcch) override
{}
uint16_t allocate_rnti() override { return last_rnti++; }
uint16_t reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg) override { return last_rnti++; }
uint16_t last_rnti = 70;
};

Loading…
Cancel
Save