diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 4eb02167f..1c62d3b81 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -557,6 +557,8 @@ public: * SeNB --> MME */ virtual bool release_erabs(uint16_t rnti, const std::vector& erabs_successfully_released) = 0; + + virtual bool send_ue_cap_info_indication(uint16_t rnti, srslte::unique_byte_buffer_t ue_radio_cap) = 0; }; // Combined interface for PHY to access stack (MAC and RRC) diff --git a/srsenb/hdr/stack/upper/s1ap.h b/srsenb/hdr/stack/upper/s1ap.h index f29261506..8f964a320 100644 --- a/srsenb/hdr/stack/upper/s1ap.h +++ b/srsenb/hdr/stack/upper/s1ap.h @@ -81,9 +81,9 @@ public: srslte::span admitted_bearers) override; void send_ho_notify(uint16_t rnti, uint64_t target_eci) override; void send_ho_cancel(uint16_t rnti) override; - // void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps); bool release_erabs(uint16_t rnti, const std::vector& erabs_successfully_released) override; bool send_error_indication(uint16_t rnti, const asn1::s1ap::cause_c& cause); + bool send_ue_cap_info_indication(uint16_t rnti, srslte::unique_byte_buffer_t ue_radio_cap) override; // Stack interface bool @@ -145,7 +145,6 @@ private: bool handle_erabmodifyrequest(const asn1::s1ap::erab_modify_request_s& msg); bool handle_uecontextmodifyrequest(const asn1::s1ap::ue_context_mod_request_s& msg); - // bool send_ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) // handover bool handle_hopreparationfailure(const asn1::s1ap::ho_prep_fail_s& msg); bool handle_s1hocommand(const asn1::s1ap::ho_cmd_s& msg); @@ -200,6 +199,7 @@ private: bool send_erab_modify_response(const std::vector& erabs_successfully_released, const std::vector& erabs_failed_to_release); bool send_erab_release_indication(const std::vector& erabs_successfully_released); + bool send_ue_cap_info_indication(srslte::unique_byte_buffer_t ue_radio_cap); bool was_uectxtrelease_requested() const { return release_requested; } diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 8011e45ad..4bac96c07 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -676,8 +676,8 @@ bool rrc::ue::handle_ue_cap_info(ue_cap_info_s* msg) parent->logger.warning("Not handling UE capability information for RAT type %s", msg_r8->ue_cap_rat_container_list[i].rat_type.to_string().c_str()); } else { - asn1::cbit_ref bref(msg_r8->ue_cap_rat_container_list[0].ue_cap_rat_container.data(), - msg_r8->ue_cap_rat_container_list[0].ue_cap_rat_container.size()); + asn1::cbit_ref bref(msg_r8->ue_cap_rat_container_list[i].ue_cap_rat_container.data(), + msg_r8->ue_cap_rat_container_list[i].ue_cap_rat_container.size()); if (eutra_capabilities.unpack(bref) != asn1::SRSASN_SUCCESS) { parent->logger.error("Failed to unpack EUTRA capabilities message"); return false; @@ -691,15 +691,15 @@ bool rrc::ue::handle_ue_cap_info(ue_cap_info_s* msg) ue_capabilities = srslte::make_rrc_ue_capabilities(eutra_capabilities); parent->logger.info("UE rnti: 0x%x category: %d", rnti, eutra_capabilities.ue_category); + + srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool); + pdu->N_bytes = msg_r8->ue_cap_rat_container_list[0].ue_cap_rat_container.size(); + memcpy(pdu->msg, msg_r8->ue_cap_rat_container_list[0].ue_cap_rat_container.data(), pdu->N_bytes); + parent->s1ap->send_ue_cap_info_indication(rnti, std::move(pdu)); } } return true; - - // TODO: Add liblte_rrc support for unpacking UE cap info and repacking into - // inter-node UERadioAccessCapabilityInformation (36.331 v10.0.0 Section 10.2.2). - // This is then passed to S1AP for transfer to EPC. - // parent->s1ap->ue_capabilities(rnti, &eutra_capabilities); } /* diff --git a/srsenb/src/stack/upper/s1ap.cc b/srsenb/src/stack/upper/s1ap.cc index 2ae3a5cce..317ca6ef2 100644 --- a/srsenb/src/stack/upper/s1ap.cc +++ b/srsenb/src/stack/upper/s1ap.cc @@ -404,11 +404,6 @@ void s1ap::ue_erab_setup_complete(uint16_t rnti, const asn1::s1ap::erab_setup_re u->send_erab_setup_response(res); } -// void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) -//{ - -//} - bool s1ap::is_mme_connected() { return mme_connected; @@ -1059,6 +1054,15 @@ bool s1ap::release_erabs(uint16_t rnti, const std::vector& erabs_succe return user_ptr->send_erab_release_indication(erabs_successfully_released); } +bool s1ap::send_ue_cap_info_indication(uint16_t rnti, srslte::unique_byte_buffer_t ue_radio_cap) +{ + ue* user_ptr = users.find_ue_rnti(rnti); + if (user_ptr == nullptr) { + return false; + } + return user_ptr->send_ue_cap_info_indication(std::move(ue_radio_cap)); +} + bool s1ap::send_error_indication(uint16_t rnti, const asn1::s1ap::cause_c& cause) { if (not mme_connected) { @@ -1432,7 +1436,26 @@ bool s1ap::ue::send_erab_release_indication(const std::vector& erabs_s container.erab_released_list.value[i].value.erab_item().erab_id = erabs_successfully_released[i]; } - return true; + return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E-RABReleaseIndication"); +} + +bool s1ap::ue::send_ue_cap_info_indication(srslte::unique_byte_buffer_t ue_radio_cap) +{ + if (not s1ap_ptr->mme_connected) { + return false; + } + + asn1::s1ap::s1ap_pdu_c tx_pdu; + tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CAP_INFO_IND); + ue_cap_info_ind_ies_container& container = tx_pdu.init_msg().value.ue_cap_info_ind().protocol_ies; + + container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; + container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id; + + asn1::cbit_ref bref{ue_radio_cap->msg, ue_radio_cap->N_bytes}; + container.ue_radio_cap.value.unpack(bref); + + return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UECapabilityInfoIndication"); } /********************* @@ -1473,38 +1496,6 @@ bool s1ap::send_enb_status_transfer_proc(uint16_t rnti, std::vectorsend_enb_status_transfer_proc(bearer_status_list); } -// bool s1ap::send_ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) -//{ -// srslte::byte_buffer_t msg; - -// LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; -// tx_pdu.ext = false; -// tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; - -// LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage; -// init->procedureCode = LIBLTE_S1AP_PROC_ID_UPLINKNASTRANSPORT; -// init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECAPABILITYINFOINDICATION; - -// LIBLTE_S1AP_MESSAGE_UECAPABILITYINFOINDICATION_STRUCT *caps = &init->choice.UECapabilityInfoIndication; -// caps->ext = false; -// caps->mme_ue_s1ap_id.mme_ue_s1ap_id = ue_ctxt_map[rnti]->mme_ue_s1ap_id; -// caps->enb_ue_s1ap_id.ENB_UE_S1AP_ID = ue_ctxt_map[rnti]->enb_ue_s1ap_id; -// // TODO: caps->UERadioCapability. - -// liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)&msg); -// logger.info_hex(msg.msg, msg.N_bytes, "Sending UERadioCapabilityInfo for RNTI:0x%x", rnti); - -// ssize_t n_sent = sctp_sendmsg(socket_fd, msg.msg, msg.N_bytes, -// (struct sockaddr*)&mme_addr, sizeof(struct sockaddr_in), -// htonl(PPID), 0, ue_ctxt_map[rnti]->stream_id, 0, 0); -// if(n_sent == -1) { -// logger.error("Failed to send UplinkNASTransport for RNTI:0x%x", rnti); -// return false; -// } - -// return true; -//} - /********************************************************* * s1ap::user_list class *********************************************************/ diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index 0846d1b07..c29d1cc93 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -117,6 +117,10 @@ public: void send_ho_cancel(uint16_t rnti) override {} bool release_erabs(uint16_t rnti, const std::vector& erabs_successfully_released) override { return true; } + bool send_ue_cap_info_indication(uint16_t rnti, const srslte::unique_byte_buffer_t ue_radio_cap) override + { + return true; + } }; class phy_dummy : public phy_interface_rrc_lte