diff --git a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt index 7c8cb59cfd..93dfe6f8a1 100644 --- a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt +++ b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt @@ -28,6 +28,7 @@ add_library(e2_ran_func_du_cucp_cuup STATIC O-RAN/ran_func_rc.c # this file should only contain RRC/PDCP-C; to be done in the future # when nr-softmodem is divided in separate executables ../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented + ../flexric/src/sm/rc_sm/ie/rc_data_ie.c CUSTOMIZED/ran_func_mac.c CUSTOMIZED/ran_func_rlc.c CUSTOMIZED/ran_func_slice.c @@ -36,5 +37,5 @@ add_library(e2_ran_func_du_cucp_cuup STATIC ../flexric/test/rnd/fill_rnd_data_slice.c ) -target_link_libraries(e2_ran_func_du_cucp_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj) +target_link_libraries(e2_ran_func_du_cucp_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj e2sm_rc_ir_obj sm_common_ie_obj) target_compile_definitions(e2_ran_func_du_cucp_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_DU NGRAN_GNB_CUCP NGRAN_GNB_CUUP) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c index 7c22fe5726..90f8d1ae00 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c @@ -20,6 +20,7 @@ */ #include "ran_func_rc.h" +#include "ran_func_rc_extern.h" #include "../../flexric/test/rnd/fill_rnd_data_rc.h" // this dependancy will be taken out once RAN Function Definition is implemented #include "../../flexric/src/sm/rc_sm/ie/ir/lst_ran_param.h" #include "../../flexric/src/sm/rc_sm/ie/ir/ran_param_list.h" @@ -29,8 +30,118 @@ #include #include #include +#include "common/utils/assertions.h" +#include "common/ran_context.h" -// Please note: current implementation doesn't take split architecture into account, neither CU/DU nor CU-UP/CU-CP +static const int rrc_state_changed_to = 202; +static bool subs_rrc_state_change = false; +static uint32_t ric_req_id = 0; + +static ue_id_e2sm_t fill_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context) +{ + ue_id_e2sm_t ue_id = {0}; + + // Check the E2 node type + #if defined (NGRAN_GNB_CUUP) && defined (NGRAN_GNB_CUCP) + ue_id.type = GNB_UE_ID_E2SM; + if (RC.nrrrc[0]->node_type == ngran_gNB_CU) { + // gNB-CU UE F1AP ID List + // C-ifCUDUseparated + ue_id.gnb.gnb_cu_ue_f1ap_lst_len = 1; + ue_id.gnb.gnb_cu_ue_f1ap_lst = calloc(ue_id.gnb.gnb_cu_ue_f1ap_lst_len, sizeof(uint32_t)); + assert(ue_id.gnb.gnb_cu_ue_f1ap_lst != NULL && "Memory exhausted"); + + for(size_t i = 0; i < ue_id.gnb.gnb_cu_ue_f1ap_lst_len; i++) { + ue_id.gnb.gnb_cu_ue_f1ap_lst[i] = rrc_ue_context->rrc_ue_id; + } + } else if (RC.nrrrc[0]->node_type == ngran_gNB_CUCP) { + //gNB-CU-CP UE E1AP ID List + //C-ifCPUPseparated + ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len = 1; + ue_id.gnb.gnb_cu_cp_ue_e1ap_lst = calloc(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len, sizeof(uint32_t)); + assert(ue_id.gnb.gnb_cu_cp_ue_e1ap_lst != NULL && "Memory exhausted"); + + for(size_t i = 0; i < ue_id.gnb.gnb_cu_cp_ue_e1ap_lst_len; i++) { + ue_id.gnb.gnb_cu_cp_ue_e1ap_lst[i] = rrc_ue_context->rrc_ue_id; + } + } else if (RC.nrrrc[0]->node_type == ngran_gNB_DU) { + assert(false && "Cannot access RRC layer in DU\n"); + } + + #elif defined (NGRAN_GNB_CUUP) + assert(false && "Cannot access RRC layer in CU-UP\n"); + + #endif + + ue_id.gnb.amf_ue_ngap_id = rrc_ue_context->rrc_ue_id; + ue_id.gnb.guami.amf_ptr = rrc_ue_context->ue_guami.amf_pointer; + ue_id.gnb.guami.amf_region_id = rrc_ue_context->ue_guami.amf_region_id; + ue_id.gnb.guami.amf_set_id = rrc_ue_context->ue_guami.amf_set_id; + ue_id.gnb.guami.plmn_id.mcc = rrc_ue_context->ue_guami.mcc; + ue_id.gnb.guami.plmn_id.mnc = rrc_ue_context->ue_guami.mnc; + ue_id.gnb.guami.plmn_id.mnc_digit_len = rrc_ue_context->ue_guami.mnc_len; + + return ue_id; +} + +static seq_ran_param_t fill_rrc_state_change_seq_ran(const rc_sm_rrc_state_e rrc_state) +{ + seq_ran_param_t seq_ran_param = {0}; + + seq_ran_param.ran_param_id = rrc_state_changed_to; + seq_ran_param.ran_param_val.type = ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE; + seq_ran_param.ran_param_val.flag_false = calloc(1, sizeof(ran_parameter_value_t)); + assert(seq_ran_param.ran_param_val.flag_false != NULL && "Memory exhausted"); + seq_ran_param.ran_param_val.flag_false->type = INTEGER_RAN_PARAMETER_VALUE; + seq_ran_param.ran_param_val.flag_false->int_ran = rrc_state; + + return seq_ran_param; +} + +static rc_ind_data_t* fill_ue_rrc_state_change(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm_rrc_state_e rrc_state) +{ + rc_ind_data_t* rc_ind = calloc(1, sizeof(rc_ind_data_t)); + assert(rc_ind != NULL && "Memory exhausted"); + + // Generate Indication Header + rc_ind->hdr.format = FORMAT_1_E2SM_RC_IND_HDR; + rc_ind->hdr.frmt_1.ev_trigger_id = NULL; + + // Generate Indication Message + rc_ind->msg.format = FORMAT_2_E2SM_RC_IND_MSG; + + //Sequence of UE Identifier + //[1-65535] + rc_ind->msg.frmt_2.sz_seq_ue_id = 1; + rc_ind->msg.frmt_2.seq_ue_id = calloc(rc_ind->msg.frmt_2.sz_seq_ue_id, sizeof(seq_ue_id_t)); + assert(rc_ind->msg.frmt_2.seq_ue_id != NULL && "Memory exhausted"); + + // UE ID + // Mandatory + // 9.3.10 + rc_ind->msg.frmt_2.seq_ue_id[0].ue_id = fill_ue_id_data(rrc_ue_context); + + // Sequence of + // RAN Parameter + // [1- 65535] + rc_ind->msg.frmt_2.seq_ue_id[0].sz_seq_ran_param = 1; + rc_ind->msg.frmt_2.seq_ue_id[0].seq_ran_param = calloc(rc_ind->msg.frmt_2.seq_ue_id[0].sz_seq_ran_param, sizeof(seq_ran_param_t)); + assert(rc_ind->msg.frmt_2.seq_ue_id[0].seq_ran_param != NULL && "Memory exhausted"); + rc_ind->msg.frmt_2.seq_ue_id[0].seq_ran_param[0] = fill_rrc_state_change_seq_ran(rrc_state); + + return rc_ind; +} + + +void signal_rrc_state_changed_to(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm_rrc_state_e rrc_state) +{ + AssertFatal(subs_rrc_state_change == true, "xApp should be subscribed to E2 node before sending the RIC INDICATION Message\n"); + + rc_ind_data_t* rc_ind_data = fill_ue_rrc_state_change(rrc_ue_context, rrc_state); + + async_event_agent_api(ric_req_id, rc_ind_data); + printf("Event for RIC Req ID %u generated\n", ric_req_id); +} bool read_rc_sm(void* data) { @@ -94,42 +205,36 @@ sm_ag_if_ans_t write_ctrl_rc_sm(void const* data) return ans; } -static -void* emulate_rrc_msg(void* ptr) -{ - uint32_t* ric_id = (uint32_t*)ptr; - for(size_t i = 0; i < 5; ++i){ - usleep(rand()%4000); - rc_ind_data_t* d = calloc(1, sizeof(rc_ind_data_t)); - assert(d != NULL && "Memory exhausted"); - *d = fill_rnd_rc_ind_data(); - async_event_agent_api(*ric_id, d); - printf("Event for RIC Req ID %u generated\n", *ric_id); - } - - free(ptr); - return NULL; -} - -static -pthread_t t_ran_ctrl; - sm_ag_if_ans_t write_subs_rc_sm(void const* src) { assert(src != NULL); // && src->type == RAN_CTRL_SUBS_V1_03); wr_rc_sub_data_t* wr_rc = (wr_rc_sub_data_t*)src; - printf("ric req id %d \n", wr_rc->ric_req_id); - uint32_t* ptr = malloc(sizeof(uint32_t)); - assert(ptr != NULL); - *ptr = wr_rc->ric_req_id; + ric_req_id = wr_rc->ric_req_id; // store the ric_req_id to generate asynchronous event - int rc = pthread_create(&t_ran_ctrl, NULL, emulate_rrc_msg, ptr); - assert(rc == 0); + assert(wr_rc->rc.ad != NULL && "Cannot be NULL"); + + // 9.2.1.2 RIC ACTION DEFINITION IE + switch (wr_rc->rc.ad->format) { + case FORMAT_1_E2SM_RC_ACT_DEF: { + // Parameters to be Reported List + // [1-65535] + for(size_t i = 0; i < wr_rc->rc.ad->frmt_1.sz_param_report_def; i++) { + if (wr_rc->rc.ad->frmt_1.param_report_def[i].ran_param_id == rrc_state_changed_to) { + subs_rrc_state_change = true; + } else { + AssertFatal(wr_rc->rc.ad->frmt_1.param_report_def[i].ran_param_id == rrc_state_changed_to, "RAN Parameter ID %d not yet implemented\n", wr_rc->rc.ad->frmt_1.param_report_def[i].ran_param_id); + } + } + break; + } + + default: + AssertFatal(wr_rc->rc.ad->format == FORMAT_1_E2SM_RC_ACT_DEF, "Action Definition Format %d not yet implemented", wr_rc->rc.ad->format); + } sm_ag_if_ans_t ans = {0}; return ans; } - diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h new file mode 100644 index 0000000000..bd7f6e8bda --- /dev/null +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h @@ -0,0 +1,30 @@ +/* + * 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 + */ + +#ifndef RAN_FUNC_SM_RAN_CTRL_EXTERN_AGENT_H +#define RAN_FUNC_SM_RAN_CTRL_EXTERN_AGENT_H + +#include "openair2/RRC/NR/nr_rrc_defs.h" + +typedef enum { RC_SM_RRC_CONNECTED, RC_SM_RRC_INACTIVE, RC_SM_RRC_IDLE, RC_SM_RRC_ANY } rc_sm_rrc_state_e; +void signal_rrc_state_changed_to(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm_rrc_state_e rrc_state); + +#endif diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index d673f470ff..660a427d30 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -102,6 +102,10 @@ #include "BIT_STRING.h" #include "assertions.h" +#ifdef E2_AGENT +#include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" +#endif + //#define XER_PRINT extern RAN_CONTEXT_t RC; @@ -500,6 +504,10 @@ static void rrc_gNB_process_RRCSetupComplete(const protocol_ctxt_t *const ctxt_p AssertFatal(ctxt_pP->rntiMaybeUEid == ue_context_pP->ue_context.rrc_ue_id, "logic bug: inconsistent IDs, must use CU UE ID!\n"); rrc_gNB_send_NGAP_NAS_FIRST_REQ(ctxt_pP, ue_context_pP, rrcSetupComplete); + +#ifdef E2_AGENT + signal_rrc_state_changed_to(&ue_context_pP->ue_context, RC_SM_RRC_CONNECTED); +#endif } //----------------------------------------------------------------------------- @@ -2585,6 +2593,10 @@ rrc_gNB_generate_RRCRelease( rrc->cucp_cuup.bearer_context_release(assoc_id, &cmd); } +#ifdef E2_AGENT + signal_rrc_state_changed_to(UE, RC_SM_RRC_IDLE); +#endif + /* UE will be freed after UE context release complete */ }