Merge remote-tracking branch 'origin/e1ap-lib-improvements' into integration_2025_w06 (!3219)

E1AP enc/dec lib improvements

This MR is including some fixes and improvements for the E1AP library,
focusing mostly on Bearer Context Management:

- struct reorganization: split setup and modification request messages
  into distinct structures, ensuring compliance with 3GPP TS 38.463
  specifications
- add encoding/decoding sub-functions for different IEs
- improvements to Bearer Context Management: Implemented various
  improvements to the E1 Bearer Context Setup Response and Request,
  including the adoption of encoding/decoding sub-functions for
  different IEs
- use lib functions whenever need (e.g. cp_bearer_context_setup_request
  in cucp_cuup_e1ap.c)
- handle optional struct members as pointers
- updated copy/equality check utility functions

EDIT: The MR is also including the changes from !3222 (closed):

> While testing E1 with security enabled for DRBs, it was found that
> data traffic was not functional.
>
> The problem was that security settings were modified in the PDCP
> reestablishment happening when receiving Bearer Context Modification
> Request.
>
> So some restructuring was done.
>
> The actual fix is in 18176297, the others are for support. Basically
> we introduce a boolean to check if the security settings are present in
> Bearer Context Modification Request and we change PDCP security settings
> only if they are.
>
> (Note that in OAI CU security settings are not sent in Bearer Context
> Modification Request, so we could also remove all this, but we need to
> be compatible with other cu-up and/or cu-cp.)
This commit is contained in:
Robert Schmidt
2025-02-11 17:53:40 +01:00
22 changed files with 1615 additions and 528 deletions
+2 -2
View File
@@ -26,6 +26,7 @@
#include "e1ap_messages_types.h"
#include "intertask_interface.h"
#include "nr_rrc_defs.h"
#include "E1AP/lib/e1ap_bearer_context_management.h"
static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req)
{
@@ -33,8 +34,7 @@ static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1a
MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_REQ);
msg_p->ittiMsgHeader.originInstance = assoc_id;
e1ap_bearer_setup_req_t *bearer_req = &E1AP_BEARER_CONTEXT_SETUP_REQ(msg_p);
memcpy(bearer_req, req, sizeof(e1ap_bearer_setup_req_t));
*bearer_req = cp_bearer_context_setup_request(req);
itti_send_msg_to_task (TASK_CUCP_E1, 0, msg_p);
}
+2
View File
@@ -29,9 +29,11 @@
#include "common/platform_types.h"
struct e1ap_bearer_setup_req_s;
struct e1ap_bearer_mod_req_s;
struct e1ap_bearer_setup_resp_s;
struct e1ap_bearer_release_cmd_s;
typedef void (*cucp_cuup_bearer_context_setup_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_setup_req_s *req);
typedef void (*cucp_cuup_bearer_context_mod_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_mod_req_s *req);
typedef void (*cucp_cuup_bearer_context_release_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_release_cmd_s *cmd);
struct gNB_RRC_INST_s;
+1 -1
View File
@@ -343,7 +343,7 @@ typedef struct nr_mac_rrc_dl_if_s {
typedef struct cucp_cuup_if_s {
cucp_cuup_bearer_context_setup_func_t bearer_context_setup;
cucp_cuup_bearer_context_setup_func_t bearer_context_mod;
cucp_cuup_bearer_context_mod_func_t bearer_context_mod;
cucp_cuup_bearer_context_release_func_t bearer_context_release;
} cucp_cuup_if_t;
+36 -22
View File
@@ -736,6 +736,14 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc,
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, buffer, size);
}
static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo)
{
secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0;
secInfo->integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0;
nr_derive_key(UP_ENC_ALG, secInfo->cipheringAlgorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey);
nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey);
}
/* \brief find existing PDU session inside E1AP Bearer Modif message, or
* point to new one.
* \param bearer_modif E1AP Bearer Modification Message
@@ -793,20 +801,27 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify];
drb_e1->id = drb_id;
drb_e1->numDlUpParam = 1;
memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4);
drb_e1->DlUpParamList[0].teId = drb->du_tunnel_config.teid;
memcpy(&drb_e1->DlUpParamList[0].tl_info.tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4);
drb_e1->DlUpParamList[0].tl_info.teId = drb->du_tunnel_config.teid;
/* PDCP configuration */
bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config;
if (!drb_e1->pdcp_config)
drb_e1->pdcp_config = malloc_or_fail(sizeof(*drb_e1->pdcp_config));
bearer_context_pdcp_config_t *pdcp_config = drb_e1->pdcp_config;
set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb);
pdcp_config->pDCP_Reestablishment = true;
/* increase DRB to modify counter */
pdu_e1->numDRB2Modify += 1;
}
req.cipheringAlgorithm = rrc->security.do_drb_ciphering ? ue_p->ciphering_algorithm : 0;
req.integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? ue_p->integrity_algorithm : 0;
nr_derive_key(UP_ENC_ALG, req.cipheringAlgorithm, ue_p->kgnb, (uint8_t *)req.encryptionKey);
nr_derive_key(UP_INT_ALG, req.integrityProtectionAlgorithm, ue_p->kgnb, (uint8_t *)req.integrityProtectionKey);
#if 0
/* According to current understanding of E1 specifications, it is not needed
* to send security information because this does not change.
* But let's keep the code here in case it's needed.
*/
// Always send security information
req.secInfo = malloc_or_fail(sizeof(*req.secInfo));
fill_security_info(rrc, ue_p, req.secInfo);
#endif
/* Send E1 Bearer Context Modification Request (3GPP TS 38.463) */
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue_p);
@@ -1855,12 +1870,12 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC
/* \brief fill E1 bearer modification's DRB from F1 DRB
* \param drb_e1 pointer to a DRB inside an E1 bearer modification message
* \param drb_f1 pointer to a DRB inside an F1 UE Ctxt modification Response */
static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1)
static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1)
{
drb_e1->id = drb_f1->drb_id;
drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length;
drb_e1->DlUpParamList[0].tlAddress = drb_f1->up_dl_tnl[0].tl_address;
drb_e1->DlUpParamList[0].teId = drb_f1->up_dl_tnl[0].teid;
drb_e1->DlUpParamList[0].tl_info.tlAddress = drb_f1->up_dl_tnl[0].tl_address;
drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid;
}
/**
@@ -1892,8 +1907,8 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R
*/
static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p)
{
f1u->teid = p->teId;
memcpy(&f1u->addr.buffer, &p->tlAddress, sizeof(uint8_t) * 4);
f1u->teid = p->tl_info.teId;
memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4);
f1u->addr.length = sizeof(in_addr_t);
}
@@ -1919,10 +1934,10 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f
LOG_E(RRC, "UE %d: UE Context Modif Response: no PDU session for DRB ID %ld\n", UE->rrc_ue_id, drb_f1->drb_id);
continue;
}
pdu_session_to_setup_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id);
pdu_session_to_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id);
DevAssert(pdu_e1 != NULL);
pdu_e1->sessionId = pdu_ue->param.pdusession_id;
DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify];
DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify];
/* Fill E1 bearer context modification */
fill_e1_bearer_modif(drb_e1, drb_f1);
pdu_e1->numDRB2Modify += 1;
@@ -1930,10 +1945,9 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f
DevAssert(req.numPDUSessionsMod > 0);
DevAssert(req.numPDUSessions == 0);
req.cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0;
req.integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0;
nr_derive_key(UP_ENC_ALG, req.cipheringAlgorithm, UE->kgnb, (uint8_t *)req.encryptionKey);
nr_derive_key(UP_INT_ALG, req.integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)req.integrityProtectionKey);
// Always send security information
req.secInfo = malloc_or_fail(sizeof(*req.secInfo));
fill_security_info(rrc, UE, req.secInfo);
// send the E1 bearer modification request message to update F1-U tunnel info
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE);
@@ -2270,9 +2284,9 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc,
f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb];
drb->drb_id = pduSession[p].DRBnGRanList[i].id;
drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM;
drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress;
drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tl_info.tlAddress;
drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd;
drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId;
drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].tl_info.teId;
drb->up_ul_tnl_length = 1;
/* pass QoS info to MAC */
@@ -2323,8 +2337,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id);
continue;
}
rrc_pdu->param.gNB_teid_N3 = e1_pdu->teId;
memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tlAddress, sizeof(uint8_t) * 4);
rrc_pdu->param.gNB_teid_N3 = e1_pdu->tl_info.teId;
memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4);
rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t);
// save the tunnel address for the DRBs
+5 -4
View File
@@ -353,10 +353,11 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
session->nssai = sessions[i].nssai;
decodePDUSessionResourceSetup(session);
bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id;
bearer_req.cipheringAlgorithm = UE->ciphering_algorithm;
bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm;
nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey);
nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey);
security_information_t *secInfo = &bearer_req.secInfo;
secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0;
secInfo->integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0;
nr_derive_key(UP_ENC_ALG, secInfo->cipheringAlgorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey);
nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey);
bearer_req.ueDlAggMaxBitRate = ueAggMaxBitRateDownlink;
pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions;
bearer_req.numPDUSessions++;