diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index d310e1162c..d7b9b3cf9d 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -59,8 +59,13 @@ add_library(telnetsrv_ci MODULE telnetsrv_ci.c) target_link_libraries(telnetsrv_ci PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_dependencies(telnetsrv telnetsrv_ci) +message(STATUS "Add bearer specific telnet functions in libtelnetsrv_bearer.so") +add_library(telnetsrv_bearer MODULE telnetsrv_bearer.c) +target_link_libraries(telnetsrv_bearer PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +add_dependencies(telnetsrv telnetsrv_bearer) + # all libraries should be written to root build dir -set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci +set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_bearer PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../../.. ) diff --git a/common/utils/telnetsrv/telnetsrv_bearer.c b/common/utils/telnetsrv/telnetsrv_bearer.c new file mode 100644 index 0000000000..f019d3d48b --- /dev/null +++ b/common/utils/telnetsrv/telnetsrv_bearer.c @@ -0,0 +1,121 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "openair2/RRC/NR/rrc_gNB_UE_context.h" + +#define TELNETSERVERCODE +#include "telnetsrv.h" + +#define ERROR_MSG_RET(mSG, aRGS...) do { prnt(mSG, ##aRGS); return 1; } while (0) + +static int get_single_ue_rnti(void) +{ + rrc_gNB_ue_context_t *ue_context_p = NULL; + RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &(RC.nrrrc[0]->rrc_ue_head)) { + return ue_context_p->ue_context.rnti; + } + return -1; +} + +int get_single_rnti(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (buf) + ERROR_MSG_RET("no parameter allowed\n"); + + int rnti = get_single_ue_rnti(); + if (rnti < 1) + ERROR_MSG_RET("different number of UEs\n"); + + prnt("single UE RNTI %04x\n", rnti); + return 0; +} + +void rrc_gNB_trigger_new_bearer(int rnti); +int add_bearer(char *buf, int debug, telnet_printfunc_t prnt) +{ + int rnti = -1; + if (!buf) { + rnti = get_single_ue_rnti(); + if (rnti < 1) + ERROR_MSG_RET("no UE found\n"); + } else { + rnti = strtol(buf, NULL, 16); + if (rnti < 1 || rnti >= 0xfffe) + ERROR_MSG_RET("RNTI needs to be [1,0xfffe]\n"); + } + + // verify it exists in RRC as well + rrc_gNB_ue_context_t *rrcue = rrc_gNB_get_ue_context_by_rnti(RC.nrrrc[0], rnti); + if (!rrcue) + ERROR_MSG_RET("could not find UE with RNTI %04x\n", rnti); + + rrc_gNB_trigger_new_bearer(rnti); + prnt("called rrc_gNB_trigger_new_bearer(%04x)\n", rnti); + return 0; +} + +void rrc_gNB_trigger_release_bearer(int rnti); +int release_bearer(char *buf, int debug, telnet_printfunc_t prnt) +{ + int rnti = -1; + if (!buf) { + rnti = get_single_ue_rnti(); + if (rnti < 1) + ERROR_MSG_RET("no UE found\n"); + } else { + rnti = strtol(buf, NULL, 16); + if (rnti < 1 || rnti >= 0xfffe) + ERROR_MSG_RET("RNTI needs to be [1,0xfffe]\n"); + } + + // verify it exists in RRC as well + rrc_gNB_ue_context_t *rrcue = rrc_gNB_get_ue_context_by_rnti(RC.nrrrc[0], rnti); + if (!rrcue) + ERROR_MSG_RET("could not find UE with RNTI %04x\n", rnti); + + rrc_gNB_trigger_release_bearer(rnti); + prnt("called rrc_gNB_trigger_release_bearer(%04x)\n", rnti); + return 0; +} + +static telnetshell_cmddef_t bearercmds[] = { + {"get_single_rnti", "", get_single_rnti}, + {"add_bearer", "[rnti(hex,opt)]", add_bearer}, + {"release_bearer", "[rnti(hex,opt)]", release_bearer}, + {"", "", NULL}, +}; + +static telnetshell_vardef_t bearervars[] = { + + {"", 0, 0, NULL} +}; + +void add_bearer_cmds(void) { + add_telnetcmd("bearer", bearervars, bearercmds); +} diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index b47a763089..8f8a047ee5 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -301,6 +301,10 @@ typedef struct f1ap_rb_failed_to_be_setup_s { long rb_id; } f1ap_rb_failed_to_be_setup_t; +typedef struct f1ap_drb_to_be_released_t { + long rb_id; +} f1ap_drb_to_be_released_t; + typedef struct cu_to_du_rrc_information_s { uint8_t * cG_ConfigInfo; uint32_t cG_ConfigInfo_length; @@ -354,6 +358,8 @@ typedef struct f1ap_ue_context_setup_s { f1ap_srb_to_be_setup_t *srbs_to_be_setup; uint8_t srbs_to_be_setup_length; uint8_t srbs_failed_to_be_setup_length; + uint8_t drbs_to_be_released_length; + f1ap_drb_to_be_released_t *drbs_to_be_released; f1ap_rb_failed_to_be_setup_t *srbs_failed_to_be_setup; ReconfigurationCompl_t ReconfigComplOutcome; uint8_t *rrc_container; diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 9e9a85d9e5..1fb4981330 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -1531,14 +1531,14 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context } /* optional */ - if(0){ + if (f1ap_ue_context_modification_req->drbs_to_be_released_length > 0) { /* c15. DRBs_ToBeReleased_List */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie15); ie15->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List; ie15->criticality = F1AP_Criticality_reject; ie15->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List; - for (int i=0; i<1; i++) { + for (int i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_released_length; i++) { // asn1cSequenceAdd(ie15->value.choice.DRBs_ToBeReleased_List.list, F1AP_DRBs_ToBeReleased_ItemIEs_t, drbs_toBeReleased_item_ies); @@ -1549,7 +1549,10 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context F1AP_DRBs_ToBeReleased_Item_t *drbs_toBeReleased_item= &drbs_toBeReleased_item_ies->value.choice.DRBs_ToBeReleased_Item; /* dRBID */ - drbs_toBeReleased_item->dRBID = 30L; + drbs_toBeReleased_item->dRBID = f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id; + newGtpuDeleteOneTunnel(getCxt(instance)->gtpInst, + f1ap_ue_context_modification_req->gNB_CU_ue_id, + f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id); } } diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index f3ee222bea..b9d29303f0 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -881,6 +881,24 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t } } } + + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieDrb, container, + F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List, false); + if (ieDrb != NULL) { + f1ap_ue_context_modification_req->drbs_to_be_released_length = ieDrb->value.choice.DRBs_ToBeReleased_List.list.count; + f1ap_ue_context_modification_req->drbs_to_be_released = + calloc(f1ap_ue_context_modification_req->drbs_to_be_released_length, sizeof(f1ap_drb_to_be_released_t)); + AssertFatal(f1ap_ue_context_modification_req->drbs_to_be_released, + "could not allocate memory for f1ap_ue_context_released_req->drbs_to_be_released\n"); + for (i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_released_length; ++i) { + F1AP_DRBs_ToBeReleased_ItemIEs_t *tbrel = (F1AP_DRBs_ToBeReleased_ItemIEs_t *)ieDrb->value.choice.DRBs_ToBeReleased_List.list.array[i]; + DevAssert(tbrel->id == F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item); + DevAssert(tbrel->value.present == F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item); + f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id = tbrel->value.choice.DRBs_ToBeReleased_Item.dRBID; + newGtpuDeleteOneTunnel(0, f1ap_ue_context_modification_req->gNB_DU_ue_id, f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id); + } + } + /* RRC Reconfiguration Complete indicator */ F1AP_UEContextModificationRequestIEs_t *ieReconf; F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieReconf, container, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index b1b60a9816..b9bb149310 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2750,6 +2750,14 @@ static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)UE->CellGroup); + + /* remove the rlc_BearerToReleaseList, we don't need it anymore */ + if (UE->CellGroup->rlc_BearerToReleaseList != NULL) { + struct NR_CellGroupConfig__rlc_BearerToReleaseList *l = UE->CellGroup->rlc_BearerToReleaseList; + asn_sequence_del(&l->list, l->list.count, /* free */1); + free(UE->CellGroup->rlc_BearerToReleaseList); + UE->CellGroup->rlc_BearerToReleaseList = NULL; + } } NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 0e383e4eaf..e18c9ea5b7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -138,6 +138,42 @@ static int handle_ue_context_drbs_setup(int rnti, return drbs_len; } +static int handle_ue_context_drbs_release(int rnti, + int drbs_len, + const f1ap_drb_to_be_released_t *req_drbs, + NR_CellGroupConfig_t *cellGroupConfig) +{ + DevAssert(req_drbs != NULL && cellGroupConfig != NULL); + + cellGroupConfig->rlc_BearerToReleaseList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToReleaseList)); + AssertFatal(cellGroupConfig->rlc_BearerToReleaseList != NULL, "out of memory\n"); + + /* Note: the actual GTP tunnels are already removed in the F1AP message + * decoding */ + for (int i = 0; i < drbs_len; i++) { + const f1ap_drb_to_be_released_t *drb = &req_drbs[i]; + + long lcid = drb->rb_id + 3; /* LCID is DRB + 3 */ + int idx = 0; + while (idx < cellGroupConfig->rlc_BearerToAddModList->list.count) { + const NR_RLC_BearerConfig_t *bc = cellGroupConfig->rlc_BearerToAddModList->list.array[idx]; + if (bc->logicalChannelIdentity == lcid) + break; + ++idx; + } + if (idx < cellGroupConfig->rlc_BearerToAddModList->list.count) { + nr_rlc_release_entity(rnti, lcid); + asn_sequence_del(&cellGroupConfig->rlc_BearerToAddModList->list, idx, 1); + long *plcid = malloc(sizeof(*plcid)); + AssertFatal(plcid != NULL, "out of memory\n"); + *plcid = lcid; + int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToReleaseList->list, plcid); + DevAssert(ret == 0); + } + } + return drbs_len; +} + static NR_UE_NR_Capability_t *get_ue_nr_cap(int rnti, uint8_t *buf, uint32_t len) { if (buf == NULL || len == 0) @@ -287,6 +323,11 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) NR_SCHED_LOCK(&mac->sched_lock); NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, req->gNB_DU_ue_id); + if (!UE) { + LOG_E(NR_MAC, "could not find UE with RNTI %04x\n", req->gNB_DU_ue_id); + NR_SCHED_UNLOCK(&mac->sched_lock); + return; + } NR_CellGroupConfig_t *new_CellGroup = clone_CellGroupConfig(UE->CellGroup); @@ -306,6 +347,11 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) new_CellGroup); } + if (req->drbs_to_be_released_length > 0) { + resp.drbs_to_be_released_length = + handle_ue_context_drbs_release(req->gNB_DU_ue_id, req->drbs_to_be_released_length, req->drbs_to_be_released, new_CellGroup); + } + if (req->rrc_container != NULL) nr_rlc_srb_recv_sdu(req->gNB_DU_ue_id, DCCH, req->rrc_container, req->rrc_container_length); @@ -323,7 +369,7 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc); } - if (req->srbs_to_be_setup_length > 0 || req->drbs_to_be_setup_length > 0 || ue_cap != NULL) { + if (req->srbs_to_be_setup_length > 0 || req->drbs_to_be_setup_length > 0 || req->drbs_to_be_released_length > 0) { resp.du_to_cu_rrc_information = calloc(1, sizeof(du_to_cu_rrc_information_t)); AssertFatal(resp.du_to_cu_rrc_information != NULL, "out of memory\n"); resp.du_to_cu_rrc_information->cellGroupConfig = calloc(1, 1024); diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 14c75deb26..5aa4f10a8c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -166,21 +166,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset UE->rnti, stats->ulsch_total_bytes_scheduled, stats->ul.total_bytes); - for (int lc_id = 0; lc_id < 63; lc_id++) { - if (stats->dl.lc_bytes[lc_id] > 0) - output += snprintf(output, - end - output, - "UE %04x: LCID %d: %"PRIu64" bytes TX\n", - UE->rnti, - lc_id, - stats->dl.lc_bytes[lc_id]); - if (stats->ul.lc_bytes[lc_id] > 0) - output += snprintf(output, - end - output, - "UE %04x: LCID %d: %"PRIu64" bytes RX\n", - UE->rnti, - lc_id, - stats->ul.lc_bytes[lc_id]); + for (int i = 0; i < sched_ctrl->dl_lc_num; i++) { + int lc_id = sched_ctrl->dl_lc_ids[i]; + output += snprintf(output, + end - output, + "UE %04x: LCID %d: TX %14"PRIu64" RX %14"PRIu64" bytes\n", + UE->rnti, + lc_id, + stats->dl.lc_bytes[lc_id], + stats->ul.lc_bytes[lc_id]); } } NR_SCHED_UNLOCK(&gNB->UE_info.mutex); diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 481d27483f..d5766a7814 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -1081,7 +1081,7 @@ void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, long t_Reordering) nr_pdcp_manager_unlock(nr_pdcp_ue_manager); } -void nr_release_srb(ue_id_t ue_id, int srb_id) +void nr_pdcp_release_srb(ue_id_t ue_id, int srb_id) { nr_pdcp_manager_lock(nr_pdcp_ue_manager); nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id); @@ -1094,7 +1094,7 @@ void nr_release_srb(ue_id_t ue_id, int srb_id) nr_pdcp_manager_unlock(nr_pdcp_ue_manager); } -void nr_release_drb(ue_id_t ue_id, int drb_id) +void nr_pdcp_release_drb(ue_id_t ue_id, int drb_id) { nr_pdcp_manager_lock(nr_pdcp_ue_manager); nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id); diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index e2fecb0ded..36568b58ba 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -68,8 +68,8 @@ void nr_pdcp_reestablishment(ue_id_t ue_id); void nr_pdcp_reconfigure_srb(ue_id_t ue_id, int srb_id, long t_Reordering); void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, long t_Reordering); -void nr_release_srb(ue_id_t ue_id, int srb_id); -void nr_release_drb(ue_id_t ue_id, int drb_id); +void nr_pdcp_release_srb(ue_id_t ue_id, int srb_id); +void nr_pdcp_release_drb(ue_id_t ue_id, int drb_id); void add_srb(int is_gnb, ue_id_t rntiMaybeUEid, diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index fc5b29c806..2aec005e6d 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -100,7 +100,7 @@ static nr_rlc_entity_t *get_rlc_entity_from_lcid(nr_rlc_ue_t *ue, logical_chan_i } } -void nr_release_rlc_entity(int rnti, logical_chan_id_t channel_id) +void nr_rlc_release_entity(int rnti, logical_chan_id_t channel_id) { nr_rlc_manager_lock(nr_rlc_ue_manager); nr_rlc_ue_t *ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, rnti); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h index 9e378e5237..be12b236e8 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h @@ -51,7 +51,7 @@ bool nr_rlc_update_rnti(int from_rnti, int to_rnti); /* test function for CI to trigger reestablishments */ void nr_rlc_test_trigger_reestablishment(int rnti); -void nr_release_rlc_entity(int rnti, logical_chan_id_t channel_id); +void nr_rlc_release_entity(int rnti, logical_chan_id_t channel_id); void nr_rlc_reconfigure_entity(int rnti, int lc_id, struct NR_RLC_Config *rlc_Config, struct NR_LogicalChannelConfig *lc_Config); diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index 88c5ad125e..6ead51e3da 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -94,6 +94,13 @@ static void ue_context_modification_request_f1ap(const f1ap_ue_context_modif_req AssertFatal(f1ap_msg->srbs_to_be_setup != NULL, "out of memory\n"); memcpy(f1ap_msg->srbs_to_be_setup, req->srbs_to_be_setup, n * sizeof(*f1ap_msg->srbs_to_be_setup)); } + if (req->drbs_to_be_released_length > 0) { + int n = req->drbs_to_be_released_length; + f1ap_msg->drbs_to_be_released_length = n; + f1ap_msg->drbs_to_be_released = calloc(n, sizeof(*f1ap_msg->drbs_to_be_released)); + AssertFatal(f1ap_msg->drbs_to_be_released != NULL, "out of memory\n"); + memcpy(f1ap_msg->drbs_to_be_released, req->drbs_to_be_released, n * sizeof(*f1ap_msg->drbs_to_be_released)); + } if (req->rrc_container_length > 0) { f1ap_msg->rrc_container = calloc(req->rrc_container_length, sizeof(*f1ap_msg->rrc_container)); AssertFatal(f1ap_msg->rrc_container != NULL, "out of memory\n"); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 215fc9851d..c37979598a 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -238,6 +238,7 @@ typedef enum { typedef struct gNB_RRC_UE_s { drb_t established_drbs[MAX_DRBS_PER_UE]; uint8_t DRB_active[MAX_DRBS_PER_UE]; + NR_DRB_ToReleaseList_t *DRB_ReleaseList; NR_SRB_INFO_TABLE_ENTRY Srb[maxSRBs]; // 3gpp max is 3 SRBs, number 1..3, we waste the entry 0 for code simplicity NR_MeasConfig_t *measConfig; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 9160d7213e..a4809f3852 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -46,6 +46,7 @@ #include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "common/utils/LOG/log.h" #include "RRC/NR/MESSAGES/asn1_msg.h" +#include "openair2/E1AP/e1ap_asnc.h" #include "NR_BCCH-BCH-Message.h" #include "NR_UL-DCCH-Message.h" @@ -672,7 +673,7 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c xid, SRBs, DRBs, - NULL, + ue_p->DRB_ReleaseList, NULL, NULL, dedicatedNAS_MessageList, @@ -680,6 +681,9 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n"); freeSRBlist(SRBs); freeDRBlist(DRBs); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, ue_p->DRB_ReleaseList); + ue_p->DRB_ReleaseList = NULL; + LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCReconfiguration (bytes %d, UE RNTI %x)\n", ctxt_pP->module_id, ctxt_pP->frame, size, ue_p->rnti); LOG_D(NR_RRC, "[FRAME %05d][RRC_gNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", @@ -2855,6 +2859,147 @@ rrc_gNB_generate_RRCRelease( /* UE will be freed after UE context release complete */ } +void rrc_gNB_trigger_new_bearer(int rnti) +{ + /* get RRC and UE */ + gNB_RRC_INST *rrc = RC.nrrrc[0]; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, rnti); + if (ue_context_p == NULL) { + LOG_E(RRC, "unknown UE RNTI %04x\n", rnti); + return; + } + gNB_RRC_UE_t *ue = &ue_context_p->ue_context; + + /* get the existing PDU sessoin */ + if (ue->nb_of_pdusessions < 1) { + LOG_E(RRC, "no PDU session set up yet, cannot create additional bearer\n"); + return; + } + + if (ue->established_drbs[0].status != DRB_INACTIVE + && ue->established_drbs[1].status != DRB_INACTIVE) { + LOG_E(RRC, "already have two established bearers, aborting\n"); + return; + } + + e1ap_bearer_setup_req_t bearer_req = {0}; + bearer_req.gNB_cu_cp_ue_id = ue->rrc_ue_id; + bearer_req.cipheringAlgorithm = ue->ciphering_algorithm; + memcpy(bearer_req.encryptionKey, ue->kgnb, sizeof(ue->kgnb)); + bearer_req.integrityProtectionAlgorithm = ue->integrity_algorithm; + memcpy(bearer_req.integrityProtectionKey, ue->kgnb, sizeof(ue->kgnb)); + bearer_req.ueDlAggMaxBitRate = 10000; /* probably does not matter */ + + pdu_session_to_setup_t *pdu = &bearer_req.pduSession[0]; + //bearer_req.numPDUSessions++; + bearer_req.numPDUSessions = 1; + //pdu->sessionId = session->pdusession_id; + //pdu->sst = msg->allowed_nssai[i].sST; + //pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; + + //pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; + //pdu->teId = session->gtp_teid; + pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding + DRB_nGRAN_to_setup_t *drb = &pdu->DRBnGRanList[0]; + int drb_id = 2; + drb->id = drb_id; + + drb->defaultDRB = E1AP_DefaultDRB_false; + drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap); + drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap); + + drb->pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_18; + drb->pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_18; + + drb->discardTimer = E1AP_DiscardTimer_infinity; + drb->reorderingTimer = E1AP_T_Reordering_ms0; + + drb->rLC_Mode = E1AP_RLC_Mode_rlc_am; + + drb->numCellGroups = 1; // assume one cell group associated with a DRB + + for (int k=0; k < drb->numCellGroups; k++) { + cell_group_t *cellGroup = drb->cellGroupList + k; + cellGroup->id = 0; // MCG + } + + int xid = rrc_gNB_get_next_transaction_identifier(0); + /* generate a new bearer, it will be put into internal RRC state and picked + * up later */ + generateDRB(ue, + drb_id, + &ue->pduSession[0], + rrc->configuration.enable_sdap, + rrc->security.do_drb_integrity, + rrc->security.do_drb_ciphering); + + /* associate the new bearer to it */ + ue->xids[xid] = RRC_PDUSESSION_MODIFY; + ue->pduSession[0].xid = xid; // hack: fake xid for ongoing PDU session + LOG_W(RRC, "trigger new bearer %ld for UE %04x xid %d\n", drb->id, ue->rnti, xid); + rrc->cucp_cuup.bearer_context_setup(&bearer_req, 0); +} + +void rrc_gNB_trigger_release_bearer(int rnti) +{ + /* get RRC and UE */ + gNB_RRC_INST *rrc = RC.nrrrc[0]; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, rnti); + if (ue_context_p == NULL) { + LOG_E(RRC, "unknown UE RNTI %04x\n", rnti); + return; + } + gNB_RRC_UE_t *ue = &ue_context_p->ue_context; + + if (ue->established_drbs[1].status == DRB_INACTIVE) { + LOG_E(RRC, "no second bearer, aborting\n"); + return; + } + + // don't use E1: bearer release is not implemented, call directly + // into PDCP/SDAP and then send corresponding message via F1 + + int drb_id = 2; + ue->established_drbs[1].status = DRB_INACTIVE; + ue->DRB_ReleaseList = calloc(1, sizeof(*ue->DRB_ReleaseList)); + AssertFatal(ue->DRB_ReleaseList != NULL, "out of memory\n"); + NR_DRB_Identity_t *asn1_drb = malloc(sizeof(*asn1_drb)); + AssertFatal(asn1_drb != NULL, "out of memory\n"); + int idx = 0; + NR_DRB_ToAddModList_t *drb_list = createDRBlist(ue, false); + while (idx < drb_list->list.count) { + const NR_DRB_ToAddMod_t *drbc = drb_list->list.array[idx]; + if (drbc->drb_Identity == drb_id) + break; + ++idx; + } + if (idx < drb_list->list.count) { + nr_pdcp_release_drb(rnti, drb_id); + asn_sequence_del(&drb_list->list, idx, 1); + } + *asn1_drb = drb_id; + asn1cSeqAdd(&ue->DRB_ReleaseList->list, asn1_drb); + + f1ap_drb_to_be_released_t drbs_to_be_released[1] = {{.rb_id = drb_id}}; + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); + f1ap_ue_context_modif_req_t ue_context_modif_req = { + .gNB_CU_ue_id = ue->rrc_ue_id, + .gNB_DU_ue_id = ue_data.secondary_ue, + .plmn.mcc = rrc->configuration.mcc[0], + .plmn.mnc = rrc->configuration.mnc[0], + .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], + .nr_cellid = rrc->nr_cellid, + .servCellId = 0, /* TODO: correct value? */ + .srbs_to_be_setup_length = 0, + .srbs_to_be_setup = NULL, + .drbs_to_be_setup_length = 0, + .drbs_to_be_setup = NULL, + .drbs_to_be_released_length = 1, + .drbs_to_be_released = drbs_to_be_released, + }; + rrc->mac_rrc.ue_context_modification_request(&ue_context_modif_req); +} + int rrc_gNB_generate_pcch_msg(uint32_t tmsi, uint8_t paging_drx, instance_t instance, uint8_t CC_id){ const unsigned int Ttab[4] = {32,64,128,256}; uint8_t Tc; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 17bfc108ea..a6a0d9dd07 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -759,7 +759,7 @@ void nr_rrc_manage_rlc_bearers(const NR_CellGroupConfig_t *cellGroupConfig, for (int i = 0; i < cellGroupConfig->rlc_BearerToReleaseList->list.count; i++) { NR_LogicalChannelIdentity_t *lcid = cellGroupConfig->rlc_BearerToReleaseList->list.array[i]; AssertFatal(lcid, "LogicalChannelIdentity shouldn't be null here\n"); - nr_release_rlc_entity(rnti, *lcid); + nr_rlc_release_entity(rnti, *lcid); } } @@ -1460,7 +1460,7 @@ void nr_rrc_ue_generate_RRCSetupRequest(module_id_t module_id, const uint8_t gNB NR_UE_RRC_INST_t *ue_rrc = &NR_UE_rrc_inst[ctxt_pP->module_id]; if (radioBearerConfig->srb3_ToRelease) - nr_release_srb(ctxt_pP->rntiMaybeUEid, 3); + nr_pdcp_release_srb(ctxt_pP->rntiMaybeUEid, 3); uint8_t kRRCenc[16] = {0}; uint8_t kRRCint[16] = {0}; @@ -1514,7 +1514,7 @@ void nr_rrc_ue_generate_RRCSetupRequest(module_id_t module_id, const uint8_t gNB for (int cnt = 0; cnt < radioBearerConfig->drb_ToReleaseList->list.count; cnt++) { NR_DRB_Identity_t *DRB_id = radioBearerConfig->drb_ToReleaseList->list.array[cnt]; if (DRB_id) - nr_release_drb(ctxt_pP->rntiMaybeUEid, *DRB_id); + nr_pdcp_release_drb(ctxt_pP->rntiMaybeUEid, *DRB_id); } } diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index b1920b6522..20e9c8c127 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -803,6 +803,32 @@ int gtpv1u_create_x2u_tunnel( AssertFatal( false, "to be developped\n"); } +int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id) +{ + pthread_mutex_lock(&globGtp.gtp_lock); + getInstRetInt(compatInst(instance)); + map::iterator ue_it = inst->ue2te_mapping.find(ue_id); + if (ue_it == inst->ue2te_mapping.end()) { + LOG_E(GTPU, "%s() no such UE %ld\n", __func__, ue_id); + pthread_mutex_unlock(&globGtp.gtp_lock); + return !GTPNOK; + } + map::iterator rb_it = ue_it->second.bearers.find(rb_id); + if (rb_it == ue_it->second.bearers.end()) { + LOG_E(GTPU, "%s() UE %ld has no bearer %d, available\n", __func__, ue_id, rb_id); + pthread_mutex_unlock(&globGtp.gtp_lock); + return !GTPNOK; + } + int teid = rb_it->second.teid_incoming; + globGtp.te2ue_mapping.erase(teid); + ue_it->second.bearers.erase(rb_id); + pthread_mutex_unlock(&globGtp.gtp_lock); + LOG_I(GTPU, "Deleted tunnel TEID %d (RB %d) for ue id %ld, remaining bearers:\n", teid, rb_id, ue_id); + for (auto b: ue_it->second.bearers) + LOG_I(GTPU, "bearer %ld\n", b.first); + return !GTPNOK; +} + int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id) { LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n", instance, ue_id); diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index d57769c509..7ac025f14a 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -98,6 +98,7 @@ extern "C" { in_addr_t newOutgoingAddr, teid_t newOutgoingTeid); + int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id); int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id); int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id); instance_t gtpv1Init(openAddr_t context);