Telnet module to manually/release DRBs of UE
This commit is contained in:
@@ -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)
|
target_link_libraries(telnetsrv_ci PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||||
add_dependencies(telnetsrv telnetsrv_ci)
|
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
|
# 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 ../../..
|
PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../../..
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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 <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||||
#include "common/utils/LOG/log.h"
|
#include "common/utils/LOG/log.h"
|
||||||
#include "RRC/NR/MESSAGES/asn1_msg.h"
|
#include "RRC/NR/MESSAGES/asn1_msg.h"
|
||||||
|
#include "openair2/E1AP/e1ap_asnc.h"
|
||||||
|
|
||||||
#include "NR_BCCH-BCH-Message.h"
|
#include "NR_BCCH-BCH-Message.h"
|
||||||
#include "NR_UL-DCCH-Message.h"
|
#include "NR_UL-DCCH-Message.h"
|
||||||
@@ -2858,6 +2859,147 @@ rrc_gNB_generate_RRCRelease(
|
|||||||
/* UE will be freed after UE context release complete */
|
/* 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){
|
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};
|
const unsigned int Ttab[4] = {32,64,128,256};
|
||||||
uint8_t Tc;
|
uint8_t Tc;
|
||||||
|
|||||||
Reference in New Issue
Block a user