Commit 46335741 authored by Robert Schmidt's avatar Robert Schmidt

Implementation of dedicated RRC Reconfiguration using internal F1 UE context modification

parent 3d352b0d
...@@ -84,7 +84,7 @@ int nr_rlc_get_available_tx_space(const rnti_t rntiP, const logical_chan_id_t ch ...@@ -84,7 +84,7 @@ int nr_rlc_get_available_tx_space(const rnti_t rntiP, const logical_chan_id_t ch
return 0; return 0;
} }
void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, NR_CellGroupConfig_t *cell_groupConfig_from_DU) void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP)
{ {
abort(); abort();
} }
......
...@@ -33,25 +33,27 @@ static NR_RLC_BearerConfig_t *get_bearerconfig_from_srb(const f1ap_srb_to_be_set ...@@ -33,25 +33,27 @@ static NR_RLC_BearerConfig_t *get_bearerconfig_from_srb(const f1ap_srb_to_be_set
return get_SRB_RLC_BearerConfig(srb->srb_id, priority, bucket); return get_SRB_RLC_BearerConfig(srb->srb_id, priority, bucket);
} }
static void handle_ue_context_srbs_setup(const f1ap_ue_context_setup_t *req, static int handle_ue_context_srbs_setup(int rnti,
f1ap_ue_context_setup_t *resp, int srbs_len,
NR_CellGroupConfig_t *cellGroupConfig) const f1ap_srb_to_be_setup_t *req_srbs,
f1ap_srb_to_be_setup_t **resp_srbs,
NR_CellGroupConfig_t *cellGroupConfig)
{ {
DevAssert(req != NULL && resp != NULL && cellGroupConfig != NULL); DevAssert(req_srbs != NULL && resp_srbs != NULL && cellGroupConfig != NULL);
resp->srbs_to_be_setup_length = req->srbs_to_be_setup_length; *resp_srbs = calloc(srbs_len, sizeof(**resp_srbs));
resp->srbs_to_be_setup = calloc(req->srbs_to_be_setup_length, sizeof(*resp->srbs_to_be_setup)); AssertFatal(*resp_srbs != NULL, "out of memory\n");
AssertFatal(resp->srbs_to_be_setup != NULL, "out of memory\n"); for (int i = 0; i < srbs_len; i++) {
for (int i = 0; i < req->srbs_to_be_setup_length; i++) { const f1ap_srb_to_be_setup_t *srb = &req_srbs[i];
f1ap_srb_to_be_setup_t *srb = &req->srbs_to_be_setup[i];
NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_srb(srb); NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_srb(srb);
nr_rlc_add_srb(req->rnti, srb->srb_id, rlc_BearerConfig); nr_rlc_add_srb(rnti, srb->srb_id, rlc_BearerConfig);
resp->srbs_to_be_setup[i] = *srb; (*resp_srbs)[i] = *srb;
int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig);
DevAssert(ret == 0); DevAssert(ret == 0);
} }
return srbs_len;
} }
static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_be_setup_t *drb) static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_be_setup_t *drb)
...@@ -61,27 +63,31 @@ static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_be_set ...@@ -61,27 +63,31 @@ static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_be_set
return get_DRB_RLC_BearerConfig(3 + drb->drb_id, drb->drb_id, rlc_conf, priority); return get_DRB_RLC_BearerConfig(3 + drb->drb_id, drb->drb_id, rlc_conf, priority);
} }
static void handle_ue_context_drbs_setup(const f1ap_ue_context_setup_t *req, static int handle_ue_context_drbs_setup(int rnti,
f1ap_ue_context_setup_t *resp, int drbs_len,
NR_CellGroupConfig_t *cellGroupConfig) const f1ap_drb_to_be_setup_t *req_drbs,
f1ap_drb_to_be_setup_t **resp_drbs,
NR_CellGroupConfig_t *cellGroupConfig)
{ {
DevAssert(req != NULL && resp != NULL && cellGroupConfig != NULL); DevAssert(req_drbs != NULL && resp_drbs != NULL && cellGroupConfig != NULL);
/* Note: the actual GTP tunnels are created in the F1AP breanch of /* Note: the actual GTP tunnels are created in the F1AP breanch of
* ue_context_*_response() */ * ue_context_*_response() */
resp->drbs_to_be_setup_length = req->drbs_to_be_setup_length; *resp_drbs = calloc(drbs_len, sizeof(**resp_drbs));
resp->drbs_to_be_setup = calloc(req->drbs_to_be_setup_length, sizeof(*resp->drbs_to_be_setup)); AssertFatal(*resp_drbs != NULL, "out of memory\n");
AssertFatal(resp->drbs_to_be_setup != NULL, "out of memory\n"); for (int i = 0; i < drbs_len; i++) {
for (int i = 0; i < req->drbs_to_be_setup_length; i++) { const f1ap_drb_to_be_setup_t *drb = &req_drbs[i];
f1ap_drb_to_be_setup_t *drb = &req->drbs_to_be_setup[i];
NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_drb(drb); NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_drb(drb);
nr_rlc_add_drb(req->rnti, drb->drb_id, rlc_BearerConfig); nr_rlc_add_drb(rnti, drb->drb_id, rlc_BearerConfig);
resp->drbs_to_be_setup[i] = *drb; (*resp_drbs)[i] = *drb;
// just put same number of tunnels in DL as in UL
(*resp_drbs)[i].up_dl_tnl_length = drb->up_ul_tnl_length;
int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig);
DevAssert(ret == 0); DevAssert(ret == 0);
} }
return drbs_len;
} }
void ue_context_setup_request(const f1ap_ue_context_setup_t *req) void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
...@@ -105,11 +111,20 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) ...@@ -105,11 +111,20 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, req->rnti); NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, req->rnti);
AssertFatal(UE != NULL, "did not find UE with RNTI %04x, but UE Context Setup Failed not implemented\n", req->rnti); AssertFatal(UE != NULL, "did not find UE with RNTI %04x, but UE Context Setup Failed not implemented\n", req->rnti);
if (req->srbs_to_be_setup_length > 0) if (req->srbs_to_be_setup_length > 0) {
handle_ue_context_srbs_setup(req, &resp, UE->CellGroup); resp.srbs_to_be_setup_length = handle_ue_context_srbs_setup(req->rnti,
req->srbs_to_be_setup_length,
req->srbs_to_be_setup,
&resp.srbs_to_be_setup,
UE->CellGroup);
}
if (req->drbs_to_be_setup_length > 0) { if (req->drbs_to_be_setup_length > 0) {
handle_ue_context_drbs_setup(req, &resp, NULL); resp.drbs_to_be_setup_length = handle_ue_context_drbs_setup(req->rnti,
req->drbs_to_be_setup_length,
req->drbs_to_be_setup,
&resp.drbs_to_be_setup,
UE->CellGroup);
} }
if (req->rrc_container != NULL) if (req->rrc_container != NULL)
...@@ -149,8 +164,81 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) ...@@ -149,8 +164,81 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req)
{ {
(void)req; gNB_MAC_INST *mac = RC.nrmac[0];
AssertFatal(false, "not implemented\n"); f1ap_ue_context_modif_resp_t resp = {
.gNB_CU_ue_id = req->gNB_CU_ue_id,
.gNB_DU_ue_id = req->gNB_DU_ue_id,
.rnti = req->rnti,
};
if (req->cu_to_du_rrc_information != NULL) {
AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n");
AssertFatal(req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList == NULL, "UE capabilities not handled yet\n");
AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL, "MeasConfig not handled\n");
}
NR_SCHED_LOCK(&mac->sched_lock);
NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, req->rnti);
if (req->srbs_to_be_setup_length > 0) {
resp.srbs_to_be_setup_length = handle_ue_context_srbs_setup(req->rnti,
req->srbs_to_be_setup_length,
req->srbs_to_be_setup,
&resp.srbs_to_be_setup,
UE->CellGroup);
}
if (req->drbs_to_be_setup_length > 0) {
resp.drbs_to_be_setup_length = handle_ue_context_drbs_setup(req->rnti,
req->drbs_to_be_setup_length,
req->drbs_to_be_setup,
&resp.drbs_to_be_setup,
UE->CellGroup);
}
if (req->rrc_container != NULL)
nr_rlc_srb_recv_sdu(req->rnti, DCCH, req->rrc_container, req->rrc_container_length);
if (req->ReconfigComplOutcome != RRCreconf_info_not_present && req->ReconfigComplOutcome != RRCreconf_success) {
LOG_E(NR_MAC,
"RRC reconfiguration outcome unsuccessful, but no rollback mechanism implemented to come back to old configuration\n");
}
if (req->srbs_to_be_setup_length > 0 || req->drbs_to_be_setup_length > 0) {
/* TODO: if we change e.g. BWP or MCS table, need to automatically call
* configure_UE_BWP() (form nr_mac_update_timers()) after some time? */
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);
AssertFatal(resp.du_to_cu_rrc_information->cellGroupConfig != NULL, "out of memory\n");
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig,
NULL,
UE->CellGroup,
resp.du_to_cu_rrc_information->cellGroupConfig,
1024);
AssertFatal(enc_rval.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval.failed_type->name);
resp.du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded + 7) >> 3;
/* works? */
nr_mac_update_cellgroup(RC.nrmac[0], req->rnti, UE->CellGroup);
}
NR_SCHED_UNLOCK(&mac->sched_lock);
/* some sanity checks, since we use the same type for request and response */
DevAssert(resp.cu_to_du_rrc_information == NULL);
// resp.du_to_cu_rrc_information can be either NULL or not
DevAssert(resp.rrc_container == NULL && resp.rrc_container_length == 0);
mac->mac_rrc.ue_context_modification_response(req, &resp);
/* free the memory we allocated above */
free(resp.srbs_to_be_setup);
free(resp.drbs_to_be_setup);
if (resp.du_to_cu_rrc_information != NULL) {
free(resp.du_to_cu_rrc_information->cellGroupConfig);
free(resp.du_to_cu_rrc_information);
}
} }
void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd) void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd)
......
...@@ -59,8 +59,57 @@ static void ue_context_modification_response_direct(const f1ap_ue_context_modif_ ...@@ -59,8 +59,57 @@ static void ue_context_modification_response_direct(const f1ap_ue_context_modif_
const f1ap_ue_context_modif_resp_t *resp) const f1ap_ue_context_modif_resp_t *resp)
{ {
(void)req; /* we don't need the request -- it is to set up GTP in F1 case */ (void)req; /* we don't need the request -- it is to set up GTP in F1 case */
(void)resp; MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_MODIFICATION_RESP);
AssertFatal(false, "not implemented yet\n"); f1ap_ue_context_modif_resp_t *f1ap_msg = &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg);
f1ap_msg->gNB_CU_ue_id = resp->gNB_CU_ue_id;
f1ap_msg->gNB_DU_ue_id = resp->gNB_DU_ue_id;
f1ap_msg->rnti = resp->rnti;
f1ap_msg->mcc = resp->mcc;
f1ap_msg->mnc = resp->mnc;
f1ap_msg->mnc_digit_length = resp->mnc_digit_length;
f1ap_msg->nr_cellid = resp->nr_cellid;
f1ap_msg->servCellIndex = resp->servCellIndex;
AssertFatal(resp->cellULConfigured == NULL, "not handled\n");
f1ap_msg->servCellId = resp->servCellId;
DevAssert(resp->cu_to_du_rrc_information == NULL && resp->cu_to_du_rrc_information_length == 0);
if (resp->du_to_cu_rrc_information) {
f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information));
AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n");
f1ap_msg->du_to_cu_rrc_information_length = resp->du_to_cu_rrc_information_length;
du_to_cu_rrc_information_t *du2cu = f1ap_msg->du_to_cu_rrc_information;
du2cu->cellGroupConfig_length = resp->du_to_cu_rrc_information->cellGroupConfig_length;
du2cu->cellGroupConfig = calloc(du2cu->cellGroupConfig_length, sizeof(*du2cu->cellGroupConfig));
AssertFatal(du2cu->cellGroupConfig != NULL, "out of memory\n");
memcpy(du2cu->cellGroupConfig, resp->du_to_cu_rrc_information->cellGroupConfig, du2cu->cellGroupConfig_length);
}
if (resp->drbs_to_be_setup_length > 0) {
DevAssert(resp->drbs_to_be_setup != NULL);
f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length;
f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup));
for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i)
f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i];
}
DevAssert(resp->drbs_to_be_modified == NULL && resp->drbs_to_be_modified_length == 0);
f1ap_msg->QoS_information_type = resp->QoS_information_type;
AssertFatal(resp->drbs_failed_to_be_setup_length == 0 && resp->drbs_failed_to_be_setup == NULL, "not implemented yet\n");
if (resp->srbs_to_be_setup_length > 0) {
DevAssert(resp->srbs_to_be_setup != NULL);
f1ap_msg->srbs_to_be_setup_length = resp->srbs_to_be_setup_length;
f1ap_msg->srbs_to_be_setup = calloc(f1ap_msg->srbs_to_be_setup_length, sizeof(*f1ap_msg->srbs_to_be_setup));
for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i)
f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i];
}
AssertFatal(resp->srbs_failed_to_be_setup_length == 0 && resp->srbs_failed_to_be_setup == NULL, "not implemented yet\n");
DevAssert(resp->rrc_container == NULL && resp->rrc_container_length == 0);
itti_send_msg_to_task(TASK_RRC_GNB, 0, msg);
} }
static void ue_context_release_request_direct(const f1ap_ue_context_release_req_t* req) static void ue_context_release_request_direct(const f1ap_ue_context_release_req_t* req)
......
...@@ -187,6 +187,19 @@ static void cucp_cuup_bearer_context_setup_direct(e1ap_bearer_setup_req_t *const ...@@ -187,6 +187,19 @@ static void cucp_cuup_bearer_context_setup_direct(e1ap_bearer_setup_req_t *const
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, GNB_FLAG_YES, UE->rnti, 0, 0, 0); PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, GNB_FLAG_YES, UE->rnti, 0, 0, 0);
fill_DRB_configList(&ctxt, ue_context_p, xid); fill_DRB_configList(&ctxt, ue_context_p, xid);
e1ap_bearer_setup_resp_t resp = {0};
resp.numPDUSessions = req->numPDUSessions;
for (int i = 0; i < resp.numPDUSessions; ++i) {
resp.pduSession[i].numDRBSetup = req->pduSession[i].numDRB2Setup;
for (int j = 0; j < req->pduSession[i].numDRB2Setup; j++) {
DRB_nGRAN_to_setup_t *req_drb = req->pduSession[i].DRBnGRanList + j;
DRB_nGRAN_setup_t *resp_drb = resp.pduSession[i].DRBnGRanList + j;
resp_drb->id = req_drb->id;
resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup;
for (int k = 0; k < resp_drb->numQosFlowSetup; k++)
resp_drb->qosFlows[k].id = req_drb->qosFlows[k].id;
}
}
gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id];
// Fixme: xid not random, but almost! // Fixme: xid not random, but almost!
...@@ -195,21 +208,26 @@ static void cucp_cuup_bearer_context_setup_direct(e1ap_bearer_setup_req_t *const ...@@ -195,21 +208,26 @@ static void cucp_cuup_bearer_context_setup_direct(e1ap_bearer_setup_req_t *const
int ret = drb_config_gtpu_create(&ctxt, ue_context_p, req, UE->DRB_configList, *SRB_configList2, rrc->e1_inst); int ret = drb_config_gtpu_create(&ctxt, ue_context_p, req, UE->DRB_configList, *SRB_configList2, rrc->e1_inst);
if (ret < 0) AssertFatal(false, "Unable to configure DRB or to create GTP Tunnel\n"); if (ret < 0) AssertFatal(false, "Unable to configure DRB or to create GTP Tunnel\n");
// Used to store teids: if monolithic, will simply be NULL
if(!NODE_IS_CU(RC.nrrrc[ctxt.module_id]->node_type)) { if(!NODE_IS_CU(RC.nrrrc[ctxt.module_id]->node_type)) {
rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, NULL); // intentionally empty
} else { } else {
e1ap_bearer_setup_resp_t resp; // Used to store teids
int remote_port = RC.nrrrc[ctxt.module_id]->eth_params_s.remote_portd; int remote_port = RC.nrrrc[ctxt.module_id]->eth_params_s.remote_portd;
in_addr_t my_addr = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.my_addr); in_addr_t my_addr = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.my_addr);
instance_t gtpInst = getCxt(CUtype, instance)->gtpInst; instance_t gtpInst = getCxt(CUtype, instance)->gtpInst;
// GTP tunnel for DL // GTP tunnel for DL
fill_e1ap_bearer_setup_resp(&resp, req, gtpInst, UE->rnti, remote_port, my_addr); fill_e1ap_bearer_setup_resp(&resp, req, gtpInst, UE->rnti, remote_port, my_addr);
prepare_and_send_ue_context_modification_f1(ue_context_p, &resp);
} }
// actually, we should receive the corresponding context setup response
// message at the RRC and always react to this one. So in the following, we
// just call the corresponding message handler
prepare_and_send_ue_context_modification_f1(ue_context_p, &resp);
} }
static void cucp_cuup_bearer_context_mod_direct(e1ap_bearer_setup_req_t *const req, instance_t instance, uint8_t xid) { static void cucp_cuup_bearer_context_mod_direct(e1ap_bearer_setup_req_t *const req, instance_t instance, uint8_t xid) {
// only update GTP tunnels if it is really a CU
if (!NODE_IS_CU(RC.nrrrc[0]->node_type))
return;
instance_t gtpInst = getCxt(CUtype, instance)->gtpInst; instance_t gtpInst = getCxt(CUtype, instance)->gtpInst;
CU_update_UP_DL_tunnel(req, gtpInst, req->rnti); CU_update_UP_DL_tunnel(req, gtpInst, req->rnti);
} }
......
...@@ -142,11 +142,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( ...@@ -142,11 +142,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release(
uint32_t nas_length, uint32_t nas_length,
uint8_t *nas_buffer); uint8_t *nas_buffer);
void void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP);
rrc_gNB_generate_dedicatedRRCReconfiguration(
const protocol_ctxt_t *const ctxt_pP,
rrc_gNB_ue_context_t *ue_context_pP,
NR_CellGroupConfig_t *cell_groupConfig_from_DU);
void bearer_context_setup_direct(e1ap_bearer_setup_req_t *req, void bearer_context_setup_direct(e1ap_bearer_setup_req_t *req,
instance_t instance); instance_t instance);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment