Commit 85949411 authored by Robert Schmidt's avatar Robert Schmidt

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.)
parents 805ed557 ac6b1b18
......@@ -9,6 +9,7 @@ services:
environment:
USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.listenport 9090 --telnetsrv.shrmod ci
--log_config.global_log_options level,nocolor,time,line_num,function
--security.drb_integrity yes
volumes:
- ../../conf_files/gnb-cucp.sa.f1.quectel.conf:/opt/oai-gnb/etc/gnb.conf
# for performance reasons, we use host mode: in bridge mode, we have
......
......@@ -125,7 +125,7 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t
int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); }
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); }
void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); }
void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); }
void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); }
int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) {
......
......@@ -51,7 +51,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
{
abort();
}
void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req)
void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
{
abort();
}
......
......@@ -126,7 +126,7 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t
extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); }
void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); }
void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); }
void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); }
int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) {
......
......@@ -138,12 +138,6 @@ typedef enum BEARER_CONTEXT_STATUS_e {
BEARER_RESUME,
} BEARER_CONTEXT_STATUS_t;
typedef enum activity_notification_level_e {
ANL_DRB = 0,
ANL_PDU_SESSION,
ANL_UE,
} activity_notification_level_t;
typedef enum cell_group_id_e {
MCG = 0,
SCG,
......@@ -258,10 +252,16 @@ typedef struct e1ap_setup_fail_s {
criticality_diagnostics_t *crit_diag;
} e1ap_setup_fail_t;
typedef struct up_params_s {
typedef struct UP_TL_information_s {
in_addr_t tlAddress;
long teId;
int cell_group_id;
int32_t teId;
} UP_TL_information_t;
typedef struct up_params_s {
// Transport layer info
UP_TL_information_t tl_info;
// Cell Group ID (M)
cell_group_id_t cell_group_id;
} up_params_t;
/* IE SDAP Configuration (clause 9.3.1.39 of 3GPP TS 38.463) */
......@@ -331,38 +331,63 @@ typedef struct qos_flow_level_qos_parameters_s {
ngran_allocation_retention_priority_t alloc_reten_priority; // additional members should be added!!
} qos_flow_level_qos_parameters_t;
// QoS Flow QoS Parameters List 9.3.1.25
typedef struct qos_flow_setup_e {
long qfi; // qos flow identifier
qos_flow_level_qos_parameters_t qos_params;
} qos_flow_to_setup_t;
/* DRB To Setup List according to 3GPP TS 38.463 */
// 9.3.1.60 QoS Flow Mapping Indication
typedef enum qos_flow_mapping_indication_e {
QF_UL = 0,
QF_DL,
QF_BOTH
} qos_flow_mapping_indication_t;
typedef struct qos_flow_list_s {
long qfi; // qos flow identifier
qos_flow_mapping_indication_t *indication;
} qos_flow_list_t;
/**
* DRB To Setup List according to 3GPP TS 38.463
*/
typedef struct DRB_nGRAN_to_setup_s {
/* DRB ID (clause 9.3.1.16) */
// DRB ID (M) (clause 9.3.1.16)
long id;
/* SDAP Configuration (clause 9.3.1.39) */
// SDAP Configuration (M) (clause 9.3.1.39)
bearer_context_sdap_config_t sdap_config;
/* PDCP Configuration (clause 9.3.1.38) */
// PDCP Configuration (M) (clause 9.3.1.38)
bearer_context_pdcp_config_t pdcp_config;
/* DRB Data Forwarding Information (clause 9.3.2.6) */
/* Transport Layer Address (clause 9.3.2.4) */
in_addr_t tlAddress;
/* GTP-TEID (clause 9.3.2.3) */
int teId;
/* DL UP Transport Layer Information (clause 9.3.2.1) */
int numDlUpParam;
up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM];
/* Cell Group Information (clause 9.3.1.11) */
// DRB Inactivity Timer (O)
int *drb_inactivity_timer;
// Cell Group Information (M) (clause 9.3.1.11)
int numCellGroups;
cell_group_id_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS];
// QoS Flows Information To Be Setup (M) (clause 9.3.1.25, 9.3.1.26)
int numQosFlow2Setup;
qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS];
} DRB_nGRAN_to_setup_t;
/* DRB QoS Flows Parameters (clause 9.3.1.26) */
/**
* DRB To Modify List according to 3GPP TS 38.463
*/
typedef struct DRB_nGRAN_to_modify_s {
// DRB ID (M) (clause 9.3.1.16)
long id;
// SDAP Configuration (O) (clause 9.3.1.39)
bearer_context_sdap_config_t *sdap_config;
// PDCP Configuration (O) (clause 9.3.1.38)
bearer_context_pdcp_config_t *pdcp_config;
// PDCP SN Status Request (O)
bool pdcp_sn_status_requested;
// DL UP Transport Layer Information (O) (clause 9.3.1.13, 9.3.2.1)
int numDlUpParam;
up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM];
// QoS Flows Information To Modify (O) (clause 9.3.1.25, 9.3.1.26)
int numQosFlow2Setup;
qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS];
} DRB_nGRAN_to_setup_t, DRB_nGRAN_to_mod_t;
} DRB_nGRAN_to_mod_t;
typedef enum e1ap_indication_e {
SECURITY_REQUIRED = 0,
......@@ -377,48 +402,108 @@ typedef struct security_indication_s {
long maxIPrate;
} security_indication_t;
typedef struct UP_TL_information_s {
in_addr_t tlAddress;
int32_t teId;
} UP_TL_information_t;
// Security Information (9.3.1.10)
typedef struct security_information_s {
uint64_t cipheringAlgorithm;
uint64_t integrityProtectionAlgorithm;
char encryptionKey[E1AP_SECURITY_KEY_SIZE];
char integrityProtectionKey[E1AP_SECURITY_KEY_SIZE];
} security_information_t;
/**
* PDU Session Resource To Setup List (clause 9.3.3.10)
* PDU Session Resource To Modify List (clause 9.3.3.11)
*/
*/
typedef struct pdu_session_to_setup_s {
// PDU Session ID (M)
long sessionId;
// PDU Session Type (M)
long sessionType;
// S-NSSAI (M)
e1ap_nssai_t nssai;
// Security Indication (M)
security_indication_t securityIndication;
// PDU Session Resource DL Aggregate Maximum Bit Rate (O)
long *dlAggregateMaxBitRate;
// NG UL UP Transport Layer Information (M)
UP_TL_information_t UP_TL_information;
long numDRB2Setup;
// PDU Session Inactivity Timer (O)
int *inactivityTimer;
// DRB To Setup List (M)
int numDRB2Setup;
// DRB To Setup Item (1..<E1AP_MAX_NUM_DRBS>)
DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS];
} pdu_session_to_setup_t;
/**
* PDU Session Resource To Modify List (clause 9.3.3.11)
*/
typedef struct pdu_session_to_mod_s {
// PDU Session ID (M)
long sessionId;
// Security Indication (O)
security_indication_t *securityIndication;
// NG UL UP Transport Layer Information (O)
UP_TL_information_t *UP_TL_information;
// DRB To Setup List (0..1)
int numDRB2Setup;
// DRB To Setup Item (1..<E1AP_MAX_NUM_DRBS>)
DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS];
// DRB To Modify List (0..1)
long numDRB2Modify;
// DRB To Modify Item (1..<E1AP_MAX_NUM_DRBS>)
DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS];
} pdu_session_to_setup_t, pdu_session_to_mod_t;
} pdu_session_to_mod_t;
/**
* Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463
* out of simplicity, this same struct is used for clause 9.2.2.4
* i.e. Bearer Context Modification Request message
*/
typedef struct e1ap_bearer_setup_req_s {
// gNB-CU-CP UE E1AP ID (M)
uint32_t gNB_cu_cp_ue_id;
uint32_t gNB_cu_up_ue_id; // Bearer Context Modification Request only
uint64_t cipheringAlgorithm;
uint64_t integrityProtectionAlgorithm;
char encryptionKey[E1AP_SECURITY_KEY_SIZE];
char integrityProtectionKey[E1AP_SECURITY_KEY_SIZE];
// Security Information (M)
security_information_t secInfo;
// UE DL Aggregate Maximum Bit Rate (M)
long ueDlAggMaxBitRate;
// UE DL Maximum Integrity Protected Data Rate (O)
long *ueDlMaxIPBitRate;
// Serving PLMN (M)
PLMN_ID_t servingPLMNid;
// Bearer Context Status Change (O)
BEARER_CONTEXT_STATUS_t bearerContextStatus;
activity_notification_level_t activityNotificationLevel;
// UE Inactivity Timer (O)
int *inactivityTimerUE;
// NG-RAN PDU Session Resource To Setup List (M)
int numPDUSessions;
pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS];
} e1ap_bearer_setup_req_t;
/**
* Bearer Context Modification Request, clause 9.2.2.4 of 3GPP TS 38.463
*/
typedef struct e1ap_bearer_mod_req_s {
// gNB-CU-CP UE E1AP ID (M)
uint32_t gNB_cu_cp_ue_id;
// gNB-CU-UP UE E1AP ID (M)
uint32_t gNB_cu_up_ue_id;
// Security Information (O)
security_information_t *secInfo;
// UE DL Aggregate Maximum Bit Rate (O)
uint32_t *ueDlAggMaxBitRate;
// UE DL Maximum Integrity Protected Data Rate (O)
uint32_t *ueDlMaxIPBitRate;
// Bearer Context Status Change (O)
BEARER_CONTEXT_STATUS_t *bearerContextStatus;
// UE Inactivity Timer (O)
int *inactivityTimer;
// Data Discard Required (O)
bool dataDiscardRequired;
// NG-RAN PDU Session Resource To Setup List (O)
int numPDUSessions;
pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS];
// NG-RAN PDU Session Resource To Modify List (O)
int numPDUSessionsMod;
pdu_session_to_mod_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS];
} e1ap_bearer_setup_req_t, e1ap_bearer_mod_req_t;
} e1ap_bearer_mod_req_t;
typedef struct e1ap_bearer_release_cmd_s {
uint32_t gNB_cu_cp_ue_id;
......@@ -432,43 +517,61 @@ typedef struct e1ap_bearer_release_cplt_s {
uint32_t gNB_cu_up_ue_id;
} e1ap_bearer_release_cplt_t;
typedef struct qos_flow_setup_s {
long qfi;
} qos_flow_setup_t;
typedef struct DRB_nGRAN_setup_s {
// DRB ID (M)
long id;
int numUpParam;
up_params_t UpParamList[E1AP_MAX_NUM_UP_PARAM];
// Flow Setup List (M)
int numQosFlowSetup;
qos_flow_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS];
qos_flow_list_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS];
} DRB_nGRAN_setup_t;
/* DRB Modified Item */
typedef struct DRB_nGRAN_modified_s {
// DRB ID (M)
long id;
// UL UP Parameters (O)
int numUpParam;
up_params_t ul_UP_Params[E1AP_MAX_NUM_UP_PARAM];
// Flow Setup List (O)
int numQosFlowSetup;
qos_flow_list_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS];
// Old QoS Flow List (O)
int numOldQosFlow;
qos_flow_list_t oldQosFlows[E1AP_MAX_NUM_QOS_FLOWS];
} DRB_nGRAN_modified_t;
typedef struct DRB_nGRAN_failed_s {
long id;
long cause_type;
long cause;
e1ap_cause_t cause;
} DRB_nGRAN_failed_t;
typedef struct pdu_session_setup_s {
long id;
in_addr_t tlAddress;
long teId;
// Transport layer info
UP_TL_information_t tl_info;
int numDRBSetup;
DRB_nGRAN_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS];
int numDRBFailed;
DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_DRBS];
} pdu_session_setup_t;
/* PDU Session Resource Modified List (9.3.3.17) */
typedef struct pdu_session_modif_s {
// PDU Session ID (M)
long id;
// setup as part of PDU session modification not supported yet
// Security Result (O)
e1ap_indication_t *integrityProtectionIndication;
e1ap_indication_t *confidentialityProtectionIndication;
// NG DL UP Transport Layer Information (O)
UP_TL_information_t *ng_DL_UP_TL_info;
// DRB Modified List (O)
int numDRBModified;
DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_DRBS];
// DRB Setup List (O)
int numDRBSetup;
DRB_nGRAN_setup_t DRBnGRanSetupList[E1AP_MAX_NUM_DRBS];
} pdu_session_modif_t;
typedef struct e1ap_bearer_setup_resp_s {
......@@ -479,8 +582,11 @@ typedef struct e1ap_bearer_setup_resp_s {
} e1ap_bearer_setup_resp_t;
typedef struct e1ap_bearer_modif_resp_s {
// gNB-CU-CP UE E1AP ID (M)
uint32_t gNB_cu_cp_ue_id;
// gNB-CU-UP UE E1AP ID (M)
uint32_t gNB_cu_up_ue_id;
// NG-RAN PDU Session Resource Modified List (O)
int numPDUSessionsMod;
pdu_session_modif_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS];
} e1ap_bearer_modif_resp_t;
......
......@@ -10,3 +10,7 @@ target_include_directories(e1ap PUBLIC ${CMAKE_CURRENT_DIR})
if(ENABLE_TESTS)
add_subdirectory(tests)
endif()
if(ENABLE_TESTS)
target_compile_definitions(e1ap PRIVATE E1AP_LOG_ERRORS)
endif()
......@@ -431,7 +431,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upc
BEARER CONTEXT MODIFICATION REQUEST
*/
static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu)
static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_mod_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu)
{
pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage;
asn1cCalloc(pdu->choice.initiatingMessage, msg);
......@@ -454,6 +454,21 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con
ieC2->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID;
ieC2->value.choice.GNB_CU_UP_UE_E1AP_ID = bearerCxt->gNB_cu_up_ue_id;
/* optional */
/* Security Information */
if (bearerCxt->secInfo) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie);
ie->id = E1AP_ProtocolIE_ID_id_SecurityInformation;
ie->criticality = E1AP_Criticality_reject;
ie->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation;
E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie->value.choice.SecurityInformation.securityAlgorithm;
E1AP_UPSecuritykey_t *uPSecuritykey = &ie->value.choice.SecurityInformation.uPSecuritykey;
securityAlgorithm->cipheringAlgorithm = bearerCxt->secInfo->cipheringAlgorithm;
OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, bearerCxt->secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE);
asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, bearerCxt->secInfo->integrityProtectionAlgorithm);
asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey);
OCTET_STRING_fromBuf(protKey, bearerCxt->secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE);
}
/* optional */
/* c3. E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest */
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC3);
ieC3->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest;
......@@ -475,7 +490,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con
asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod);
drb2Mod->dRB_ID = j->id;
asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration);
if (j->pdcp_config.pDCP_Reestablishment) {
if (j->pdcp_config && j->pdcp_config->pDCP_Reestablishment) {
asn1cCallocOne(pDCP_Configuration->pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true);
}
if (j->numDlUpParam > 0) {
......@@ -484,8 +499,8 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con
asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param);
DL_UP_Param->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
asn1cCalloc(DL_UP_Param->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tl_info.tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(k->tl_info.teId, &gTPTunnel->gTP_TEID);
DL_UP_Param->cell_Group_ID = k->cell_group_id;
}
......@@ -493,7 +508,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con
}
}
/* c4. E1AP_ProtocolIE_ID_id_BearerContextStatusChange */
if (bearerCxt->bearerContextStatus == BEARER_SUSPEND) {
if (bearerCxt->bearerContextStatus && *bearerCxt->bearerContextStatus == BEARER_SUSPEND) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC4);
ieC4->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange;
ieC4->criticality = E1AP_Criticality_reject;
......@@ -608,6 +623,26 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p
bearerCxt->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID;
break;
case E1AP_ProtocolIE_ID_id_SecurityInformation: {
DevAssert(ie->criticality == E1AP_Criticality_reject);
DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation);
E1AP_SecurityInformation_t *sec = &ie->value.choice.SecurityInformation;
DevAssert(sec->uPSecuritykey.encryptionKey.size == E1AP_SECURITY_KEY_SIZE);
DevAssert(sec->uPSecuritykey.integrityProtectionKey == NULL
|| sec->uPSecuritykey.integrityProtectionKey->size == E1AP_SECURITY_KEY_SIZE);
bearerCxt->secInfo = malloc_or_fail(sizeof(*bearerCxt->secInfo));
bearerCxt->secInfo->cipheringAlgorithm = sec->securityAlgorithm.cipheringAlgorithm;
bearerCxt->secInfo->integrityProtectionAlgorithm = sec->securityAlgorithm.integrityProtectionAlgorithm == NULL
? 0
: *sec->securityAlgorithm.integrityProtectionAlgorithm;
memcpy(bearerCxt->secInfo->encryptionKey, sec->uPSecuritykey.encryptionKey.buf, E1AP_SECURITY_KEY_SIZE);
if (sec->securityAlgorithm.integrityProtectionAlgorithm == NULL)
memset(bearerCxt->secInfo->integrityProtectionKey, 0, E1AP_SECURITY_KEY_SIZE);
else
memcpy(bearerCxt->secInfo->integrityProtectionKey, sec->uPSecuritykey.integrityProtectionKey->buf, E1AP_SECURITY_KEY_SIZE);
break;
}
case E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest:
DevAssert(ie->criticality == E1AP_Criticality_reject);
DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest);
......@@ -637,7 +672,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p
if (drb2Mod->pDCP_Configuration != NULL
&& drb2Mod->pDCP_Configuration->pDCP_Reestablishment != NULL
&& *drb2Mod->pDCP_Configuration->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true) {
drb->pdcp_config.pDCP_Reestablishment = true;
drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config));
drb->pdcp_config->pDCP_Reestablishment = true;
}
if (drb2Mod->dL_UP_Parameters) { /* Optional IE in the DRB To Modify Item */
E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters;
......@@ -649,8 +685,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p
DevAssert(dl_up_param_in->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel);
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(
&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->transportLayerAddress,
dl_up_param->tlAddress);
OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->teId);
dl_up_param->tl_info.tlAddress);
OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->tl_info.teId);
} else {
AssertFatal(false, "gTPTunnel IE is missing. It is mandatory at this point\n");
}
......@@ -665,7 +701,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p
/* Bearer Context Status Change */
DevAssert(ie->criticality == E1AP_Criticality_reject);
DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange);
bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE;
bearerCxt->bearerContextStatus = malloc_or_fail(*bearerCxt->bearerContextStatus);
*bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE;
break;
default:
......@@ -1131,7 +1168,7 @@ static void e1_task_handle_sctp_association_resp(E1_t type,
if (getCxtE1(instance)->gtpInstF1U < 0)
getCxtE1(instance)->gtpInstF1U = cuup_task_create_gtpu_instance_to_du(&IPaddr);
if (getCxtE1(instance)->gtpInstF1U < 0)
LOG_E(E1AP, "Failed to create CUUP F1-U UDP listener");
LOG_E(E1AP, "Failed to create CUUP F1-U UDP listener\n");
extern instance_t CUuniqInstance;
CUuniqInstance = getCxtE1(instance)->gtpInstF1U;
cuup_init_n3(instance);
......@@ -1154,7 +1191,7 @@ void cuup_init_n3(instance_t instance)
legacyInstanceMapping = getCxtE1(instance)->gtpInstN3 = gtpv1Init(tmp);
}
if (getCxtE1(instance)->gtpInstN3 < 0)
LOG_E(E1AP, "Failed to create CUUP N3 UDP listener");
LOG_E(E1AP, "Failed to create CUUP N3 UDP listener\n");
extern instance_t *N3GTPUInst;
N3GTPUInst = &getCxtE1(instance)->gtpInstN3;
}
......
add_library(e1ap_lib OBJECT
e1ap_bearer_context_management.c
e1ap_interface_management.c
e1ap_lib_common.c
)
target_link_libraries(e1ap_lib PRIVATE asn1_e1ap)
......
......@@ -37,9 +37,130 @@
#include "e1ap_bearer_context_management.h"
#include "e1ap_lib_includes.h"
/* ====================================
* E1AP Bearer Context Setup Request
* ==================================== */
/** @brief Encode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */
static E1AP_SecurityIndication_t e1_encode_security_indication(const security_indication_t *in)
{
E1AP_SecurityIndication_t out = {0};
out.integrityProtectionIndication = in->integrityProtectionIndication;
out.confidentialityProtectionIndication = in->confidentialityProtectionIndication;
if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) {
asn1cCalloc(out.maximumIPdatarate, ipDataRate);
ipDataRate->maxIPrate = in->maxIPrate;
}
return out;
}
/** @brief Decode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */
static bool e1_decode_security_indication(security_indication_t *out, const E1AP_SecurityIndication_t *in)
{
// Confidentiality Protection Indication (M)
out->confidentialityProtectionIndication = in->confidentialityProtectionIndication;
// Maximum Integrity Protected Data Rate (Conditional)
if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) {
if (in->maximumIPdatarate)
out->maxIPrate = in->maximumIPdatarate->maxIPrate;
else {
PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n");
return false;
}
}
return true;
}
/**
* @brief Encode E1AP_SecurityInformation_t
*/
static E1AP_SecurityInformation_t e1_encode_security_info(const security_information_t *secInfo)
{
E1AP_SecurityInformation_t ie = {0};
E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie.securityAlgorithm;
E1AP_UPSecuritykey_t *uPSecuritykey = &ie.uPSecuritykey;
securityAlgorithm->cipheringAlgorithm = secInfo->cipheringAlgorithm;
OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE);
asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, secInfo->integrityProtectionAlgorithm);
asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey);
OCTET_STRING_fromBuf(protKey, secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE);
return ie;
}
/**
* @brief Decode E1AP_SecurityInformation_t
*/
static bool e1_decode_security_info(security_information_t *out, const E1AP_SecurityInformation_t *in)
{
out->cipheringAlgorithm = in->securityAlgorithm.cipheringAlgorithm;
memcpy(out->encryptionKey, in->uPSecuritykey.encryptionKey.buf, in->uPSecuritykey.encryptionKey.size);
if (in->securityAlgorithm.integrityProtectionAlgorithm)
out->integrityProtectionAlgorithm = *in->securityAlgorithm.integrityProtectionAlgorithm;
if (in->uPSecuritykey.integrityProtectionKey) {
E1AP_IntegrityProtectionKey_t *ipKey = in->uPSecuritykey.integrityProtectionKey;
memcpy(out->integrityProtectionKey, ipKey->buf, ipKey->size);
}
return true;
}
/**
* @brief Encode E1AP_UP_TNL_Information_t
*/
static E1AP_UP_TNL_Information_t e1_encode_up_tnl_info(const UP_TL_information_t *in)
{
E1AP_UP_TNL_Information_t out = {0};
out.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
asn1cCalloc(out.choice.gTPTunnel, gTPTunnel);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID);
return out;
}
/**
* @brief Decode E1AP_UP_TNL_Information_t
*/
static bool e1_decode_up_tnl_info(UP_TL_information_t *out, const E1AP_UP_TNL_Information_t *in)
{
/* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */
// GTP Tunnel
struct E1AP_GTPTunnel *gTPTunnel = in->choice.gTPTunnel;
AssertFatal(gTPTunnel != NULL, "item->nG_UL_UP_TNL_Information.choice.gTPTunnel is a mandatory IE");
_E1_EQ_CHECK_INT(in->present, E1AP_UP_TNL_Information_PR_gTPTunnel);
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, out->tlAddress);
// GTP-TEID
OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, out->teId);
return true;
}
/** @brief Encode PDCP Configuration IE */
static E1AP_PDCP_Configuration_t e1_encode_pdcp_config(const bearer_context_pdcp_config_t *in)
{
E1AP_PDCP_Configuration_t out = {0};
out.pDCP_SN_Size_UL = in->pDCP_SN_Size_UL;
out.pDCP_SN_Size_DL = in->pDCP_SN_Size_DL;
asn1cCallocOne(out.discardTimer, in->discardTimer);
E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer));
out.t_ReorderingTimer = roTimer;
roTimer->t_Reordering = in->reorderingTimer;
out.rLC_Mode = in->rLC_Mode;
if (in->pDCP_Reestablishment) {
asn1cCallocOne(out.pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true);
}
return out;
}
/** @brief Decode PDCP Configuration IE */
static bool e1_decode_pdcp_config(bearer_context_pdcp_config_t *out, const E1AP_PDCP_Configuration_t *in)
{
out->pDCP_SN_Size_UL = in->pDCP_SN_Size_UL;
out->pDCP_SN_Size_DL = in->pDCP_SN_Size_DL;
if (in->discardTimer) {
out->discardTimer = *in->discardTimer;
}
if (in->t_ReorderingTimer) {
out->reorderingTimer = in->t_ReorderingTimer->t_Reordering;
}
out->rLC_Mode = in->rLC_Mode;
if (in->pDCP_Reestablishment && *in->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true)
out->pDCP_Reestablishment = true;
return true;
}
/**
* @brief Equality check for bearer_context_pdcp_config_t
......@@ -55,6 +176,25 @@ static bool eq_pdcp_config(const bearer_context_pdcp_config_t *a, const bearer_c
return true;
}
/** @brief Encode SDAP Configuration IE */
static E1AP_SDAP_Configuration_t e1_encode_sdap_config(const bearer_context_sdap_config_t *in)
{
E1AP_SDAP_Configuration_t out = {0};
out.defaultDRB = in->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false;
out.sDAP_Header_UL = in->sDAP_Header_UL;
out.sDAP_Header_DL = in->sDAP_Header_DL;
return out;
}
/** @brief Decode SDAP Configuration IE */
static bool e1_decode_sdap_config(bearer_context_sdap_config_t *out, const E1AP_SDAP_Configuration_t *in)
{
out->defaultDRB = in->defaultDRB == E1AP_DefaultDRB_true;
out->sDAP_Header_UL = in->sDAP_Header_UL;
out->sDAP_Header_DL = in->sDAP_Header_DL;
return true;
}
/**
* @brief Equality check for bearer_context_sdap_config_t
*/
......@@ -66,6 +206,69 @@ static bool eq_sdap_config(const bearer_context_sdap_config_t *a, const bearer_c
return true;
}
static E1AP_QoS_Flow_QoS_Parameter_Item_t e1_encode_qos_flow_to_setup(const qos_flow_to_setup_t *in)
{
E1AP_QoS_Flow_QoS_Parameter_Item_t out = {0};
out.qoS_Flow_Identifier = in->qfi;
// QoS Characteristics
const qos_characteristics_t *qos_char_in = &in->qos_params.qos_characteristics;
if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI
out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI);
non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi;
} else { // dynamic 5QI
out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI;
asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI);
dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level;
dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget;
dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar;
dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent;
}
// QoS Retention Priority
const ngran_allocation_retention_priority_t *rent_priority_in = &in->qos_params.alloc_reten_priority;
E1AP_NGRANAllocationAndRetentionPriority_t *arp = &out.qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority;
arp->priorityLevel = rent_priority_in->priority_level;
arp->pre_emptionCapability = rent_priority_in->preemption_capability;
arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability;
return out;
}
bool e1_decode_qos_flow_to_setup(qos_flow_to_setup_t *out, const E1AP_QoS_Flow_QoS_Parameter_Item_t *in)
{
// QoS Flow Identifier (M)
out->qfi = in->qoS_Flow_Identifier;
qos_characteristics_t *qos_char = &out->qos_params.qos_characteristics;
// QoS Flow Level QoS Parameters (M)
const E1AP_QoSFlowLevelQoSParameters_t *qosParams = &in->qoSFlowLevelQoSParameters;
const E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics;
switch (qoS_Characteristics->present) {
case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI:
qos_char->qos_type = NON_DYNAMIC;
qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI;
break;
case E1AP_QoS_Characteristics_PR_dynamic_5QI: {
E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI;
qos_char->qos_type = DYNAMIC;
qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel;
qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget;
qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar;
qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent;
break;
}
default:
PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present);
return false;
break;
}
// NG-RAN Allocation and Retention Priority (M)
ngran_allocation_retention_priority_t *rent_priority = &out->qos_params.alloc_reten_priority;
const E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority;
rent_priority->priority_level = aRP->priorityLevel;
rent_priority->preemption_capability = aRP->pre_emptionCapability;
rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability;
return true;
}
/**
* @brief Equality check for qos_flow_to_setup_t
*/
......@@ -90,30 +293,66 @@ static bool eq_qos_flow(const qos_flow_to_setup_t *a, const qos_flow_to_setup_t
return true;
}
/** @brief S-NSSAI Encoding (3GPP TS 38.463 9.3.1.9) */
static E1AP_SNSSAI_t e1_encode_snssai(const nssai_t *in)
{
E1AP_SNSSAI_t out = {0};
INT8_TO_OCTET_STRING(in->sst, &out.sST);
if (in->sd != 0xffffff) {
out.sD = malloc_or_fail(sizeof(*out.sD));
INT24_TO_OCTET_STRING(in->sd, out.sD);
}
return out;
}
/** @brief S-NSSAI Decoding (3GPP TS 38.463 9.3.1.9) */
static bool e1_decode_snssai(e1ap_nssai_t *out, const E1AP_SNSSAI_t *in)
{
// SST (M)
OCTET_STRING_TO_INT8(&in->sST, out->sst);
out->sd = 0xffffff;
// SD (O)
if (in->sD != NULL)
OCTET_STRING_TO_INT24(in->sD, out->sd);
return true;
}
/**
* @brief Equality check for DRB_nGRAN_to_setup_t
* @brief Decode E1AP_UP_Parameters_t
*/
static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_setup_t *b)
static int decode_dl_up_parameters(up_params_t *dl_up_param, const E1AP_UP_Parameters_t *dl_up_paramList)
{
bool result = true;
_E1_EQ_CHECK_LONG(a->id, b->id);
_E1_EQ_CHECK_INT(a->numCellGroups, b->numCellGroups);
for (int i = 0; i < a->numCellGroups; i++) {
_E1_EQ_CHECK_INT(a->cellGroupList[i], b->cellGroupList[i]);
for (int k = 0; k < dl_up_paramList->list.count; k++) {
dl_up_param = dl_up_param + k;
E1AP_UP_Parameters_Item_t *dl_up_param_in = dl_up_paramList->list.array[k];
// GTP tunnel
if (!e1_decode_up_tnl_info(&dl_up_param->tl_info, &dl_up_param_in->uP_TNL_Information)) {
PRINT_ERROR("GTP tunnel decoding failed\n");
return -1;
}
_E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup);
for (int i = 0; i < a->numQosFlow2Setup; i++) {
result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]);
// Cell group ID
dl_up_param->cell_group_id = dl_up_param_in->cell_Group_ID;
}
result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config);
result &= eq_sdap_config(&a->sdap_config, &b->sdap_config);
return result;
return dl_up_paramList->list.count;
}
/**
* @brief Equality check for DRB_nGRAN_to_mod_t
* @brief Encode E1AP_UP_Parameters_t IE
*/
static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b)
static E1AP_UP_Parameters_t encode_dl_up_parameters(const int numUpParam, const up_params_t *in)
{
E1AP_UP_Parameters_t out = {0};
for (const up_params_t *k = in; k < in + numUpParam; k++) {
asn1cSequenceAdd(out.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1);
ieC3_1_1_1->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info);
}
return out;
}
/**
* @brief Equality check for DRB_nGRAN_to_setup_t
*/
static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_setup_t *b)
{
bool result = true;
_E1_EQ_CHECK_LONG(a->id, b->id);
......@@ -125,127 +364,63 @@ static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t
for (int i = 0; i < a->numQosFlow2Setup; i++) {
result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]);
}
_E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress);
_E1_EQ_CHECK_INT(a->teId, b->teId);
_E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam);
for (int i = 0; i < a->numDlUpParam; i++) {
_E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id);
_E1_EQ_CHECK_LONG(a->DlUpParamList[i].teId, b->DlUpParamList[i].teId);
_E1_EQ_CHECK_INT(a->DlUpParamList[i].tlAddress, b->DlUpParamList[i].tlAddress);
}
result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config);
result &= eq_sdap_config(&a->sdap_config, &b->sdap_config);
return result;
}
/* PDU Session To Setup Item */
static void free_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg)
{
free(msg->drb_inactivity_timer);
}
/** @brief Encode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */
static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Setup_Item_t *item, const pdu_session_to_setup_t *in)
{
// PDU Session ID (M)
item->pDU_Session_ID = in->sessionId;
// PDU Session Type (M)
item->pDU_Session_Type = in->sessionType;
// SNSSAI
INT8_TO_OCTET_STRING(in->nssai.sst, &item->sNSSAI.sST);
if (in->nssai.sd != 0xffffff) {
item->sNSSAI.sD = malloc_or_fail(sizeof(*item->sNSSAI.sD));
INT24_TO_OCTET_STRING(in->nssai.sd, item->sNSSAI.sD);
}
// Security Indication
E1AP_SecurityIndication_t *siOut = &item->securityIndication;
const security_indication_t *siIn = &in->securityIndication;
siOut->integrityProtectionIndication = siIn->integrityProtectionIndication;
siOut->confidentialityProtectionIndication = siIn->confidentialityProtectionIndication;
if (siIn->integrityProtectionIndication != SECURITY_NOT_NEEDED) {
asn1cCalloc(siOut->maximumIPdatarate, ipDataRate);
ipDataRate->maxIPrate = siIn->maxIPrate;
}
// TNL Information
item->nG_UL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
asn1cCalloc(item->nG_UL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel);
const UP_TL_information_t *UP_TL_information = &in->UP_TL_information;
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(UP_TL_information->tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(UP_TL_information->teId, &gTPTunnel->gTP_TEID);
// DRB to setup
// S-NSSAI (M)
item->sNSSAI = e1_encode_snssai(&in->nssai);
// Security Indication (M)
item->securityIndication = e1_encode_security_indication(&in->securityIndication);
// NG UL UP Transport Layer Information (M)
item->nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information);
// DRB To Setup List (M)
for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) {
asn1cSequenceAdd(item->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1);
// DRB ID (M)
ieC6_1_1->dRB_ID = j->id;
// SDAP Config
E1AP_SDAP_Configuration_t *sdap = &ieC6_1_1->sDAP_Configuration;
sdap->defaultDRB = j->sdap_config.defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false;
sdap->sDAP_Header_UL = j->sdap_config.sDAP_Header_UL;
sdap->sDAP_Header_DL = j->sdap_config.sDAP_Header_DL;
// PDCP Config
E1AP_PDCP_Configuration_t *pdcp = &ieC6_1_1->pDCP_Configuration;
pdcp->pDCP_SN_Size_UL = j->pdcp_config.pDCP_SN_Size_UL;
pdcp->pDCP_SN_Size_DL = j->pdcp_config.pDCP_SN_Size_DL;
asn1cCallocOne(pdcp->discardTimer, j->pdcp_config.discardTimer);
E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer));
pdcp->t_ReorderingTimer = roTimer;
roTimer->t_Reordering = j->pdcp_config.reorderingTimer;
pdcp->rLC_Mode = j->pdcp_config.rLC_Mode;
// Cell Group
// SDAP Configuration (M)
ieC6_1_1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config);
// PDCP Configuration (M)
ieC6_1_1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config);
// Cell Group Information (M)
for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) {
asn1cSequenceAdd(ieC6_1_1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ieC6_1_1_1);
ieC6_1_1_1->cell_Group_ID = *k;
}
// QoS Flows
// QoS Flows Information To Be Setup (M)
for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) {
asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_1);
ieC6_1_1_1->qoS_Flow_Identifier = k->qfi;
// QoS Characteristics
const qos_characteristics_t *qos_char_in = &k->qos_params.qos_characteristics;
if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI
ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI);
non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi;
} else { // dynamic 5QI
ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI;
asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI);
dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level;
dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget;
dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar;
dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent;
}
// QoS Retention Priority
const ngran_allocation_retention_priority_t *rent_priority_in = &k->qos_params.alloc_reten_priority;
E1AP_NGRANAllocationAndRetentionPriority_t *arp = &ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority;
arp->priorityLevel = rent_priority_in->priority_level;
arp->pre_emptionCapability = rent_priority_in->preemption_capability;
arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability;
asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_2);
*ieC6_1_1_2 = e1_encode_qos_flow_to_setup(k);
}
}
return true;
}
/** @brief Decode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */
static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1AP_PDU_Session_Resource_To_Setup_Item_t *item)
{
// PDU Session ID (M)
out->sessionId = item->pDU_Session_ID;
// PDU Session Type (M)
out->sessionType = item->pDU_Session_Type;
/* S-NSSAI (M) */
// SST (M)
OCTET_STRING_TO_INT8(&item->sNSSAI.sST, out->nssai.sst);
out->nssai.sd = 0xffffff;
// SD (O)
if (item->sNSSAI.sD != NULL)
OCTET_STRING_TO_INT24(item->sNSSAI.sD, out->nssai.sd);
/* Security Indication (M) */
E1AP_SecurityIndication_t *securityIndication = &item->securityIndication;
// Integrity Protection Indication (M)
security_indication_t *sec = &out->securityIndication;
sec->integrityProtectionIndication = securityIndication->integrityProtectionIndication;
// Confidentiality Protection Indication (M)
sec->confidentialityProtectionIndication = securityIndication->confidentialityProtectionIndication;
// Maximum Integrity Protected Data Rate (Conditional)
if (sec->integrityProtectionIndication != SECURITY_NOT_NEEDED) {
if (securityIndication->maximumIPdatarate)
sec->maxIPrate = securityIndication->maximumIPdatarate->maxIPrate;
else {
PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n");
return false;
}
}
// S-NSSAI (M)
CHECK_E1AP_DEC(e1_decode_snssai(&out->nssai, &item->sNSSAI));
// Security Indication (M)
CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication));
/* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */
// GTP Tunnel
struct E1AP_GTPTunnel *gTPTunnel = item->nG_UL_UP_TNL_Information.choice.gTPTunnel;
......@@ -254,12 +429,8 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A
return false;
}
_E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel);
// Transport Layer Address
UP_TL_information_t *UP_TL_information = &out->UP_TL_information;
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UP_TL_information->tlAddress);
// GTP-TEID
OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UP_TL_information->teId);
// DRB To Setup List ( > 1 item )
CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information));
/* DRB To Setup List ( > 1 item ) */
E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_List_NG_RAN;
_E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0);
out->numDRB2Setup = drb2SetupList->list.count;
......@@ -269,23 +440,11 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A
E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j];
// DRB ID (M)
drb->id = drb2Setup->dRB_ID;
// >SDAP Configuration (M)
E1AP_SDAP_Configuration_t *sdap = &drb2Setup->sDAP_Configuration;
drb->sdap_config.defaultDRB = sdap->defaultDRB == E1AP_DefaultDRB_true;
drb->sdap_config.sDAP_Header_UL = sdap->sDAP_Header_UL;
drb->sdap_config.sDAP_Header_DL = sdap->sDAP_Header_DL;
// SDAP Configuration (M)
CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration));
// PDCP Configuration (M)
E1AP_PDCP_Configuration_t *pdcp = &drb2Setup->pDCP_Configuration;
drb->pdcp_config.pDCP_SN_Size_UL = pdcp->pDCP_SN_Size_UL;
drb->pdcp_config.pDCP_SN_Size_DL = pdcp->pDCP_SN_Size_DL;
if (pdcp->discardTimer) {
drb->pdcp_config.discardTimer = *pdcp->discardTimer;
}
if (pdcp->t_ReorderingTimer) {
drb->pdcp_config.reorderingTimer = pdcp->t_ReorderingTimer->t_Reordering;
}
drb->pdcp_config.rLC_Mode = pdcp->rLC_Mode;
// Cell Group Information (M) ( > 1 item )
CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration));
// Cell Group Information (M)
E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information;
_E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0);
drb->numCellGroups = cellGroupList->list.count;
......@@ -298,41 +457,47 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A
E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->qos_flow_Information_To_Be_Setup;
drb->numQosFlow2Setup = qos2SetupList->list.count;
for (int k = 0; k < qos2SetupList->list.count; k++) {
qos_flow_to_setup_t *qos_flow = drb->qosFlows + k;
E1AP_QoS_Flow_QoS_Parameter_Item_t *qos2Setup = qos2SetupList->list.array[k];
// QoS Flow Identifier (M)
qos_flow->qfi = qos2Setup->qoS_Flow_Identifier;
qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics;
// QoS Flow Level QoS Parameters (M)
E1AP_QoSFlowLevelQoSParameters_t *qosParams = &qos2Setup->qoSFlowLevelQoSParameters;
E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics;
switch (qoS_Characteristics->present) {
case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI:
qos_char->qos_type = NON_DYNAMIC;
qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI;
break;
case E1AP_QoS_Characteristics_PR_dynamic_5QI: {
E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI;
qos_char->qos_type = DYNAMIC;
qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel;
qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget;
qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar;
qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent;
break;
CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k]));
}
default:
PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present);
return false;
break;
}
// NG-RAN Allocation and Retention Priority (M)
ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority;
E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority;
rent_priority->priority_level = aRP->priorityLevel;
rent_priority->preemption_capability = aRP->pre_emptionCapability;
rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability;
return true;
}
/** @brief Deep copy DRB To Setup List Item (3GPP TS 38.463 9.3.3.2) */
static DRB_nGRAN_to_setup_t cp_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg)
{
DRB_nGRAN_to_setup_t cp = {0};
cp.id = msg->id;
cp.sdap_config = msg->sdap_config;
cp.pdcp_config = msg->pdcp_config;
cp.numCellGroups = msg->numCellGroups;
// Cell Group List
for (int k = 0; k < msg->numCellGroups; k++) {
cp.cellGroupList[k] = msg->cellGroupList[k];
}
cp.numQosFlow2Setup = msg->numQosFlow2Setup;
// QoS Flow To Setup List
for (int k = 0; k < msg->numQosFlow2Setup; k++) {
cp.qosFlows[k].qfi = msg->qosFlows[k].qfi;
cp.qosFlows[k].qos_params = msg->qosFlows[k].qos_params;
}
return cp;
}
/** @brief Free PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */
void free_pdu_session_to_setup_item(const pdu_session_to_setup_t *msg)
{
free(msg->dlAggregateMaxBitRate);
free(msg->inactivityTimer);
for (int i = 0; i < msg->numDRB2Setup; i++)
free_drb_to_setup_item(&msg->DRBnGRanList[i]);
}
/** @brief Equality check for UP Transport Layer Information (3GPP TS 38.463 9.3.2.1)*/
static bool eq_up_tl_info(const UP_TL_information_t *a, const UP_TL_information_t *b)
{
_E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress);
_E1_EQ_CHECK_INT(a->teId, b->teId);
return true;
}
......@@ -343,57 +508,21 @@ static bool eq_pdu_session_item(const pdu_session_to_setup_t *a, const pdu_sessi
{
_E1_EQ_CHECK_LONG(a->sessionId, b->sessionId);
_E1_EQ_CHECK_LONG(a->sessionType, b->sessionType);
_E1_EQ_CHECK_INT(a->UP_TL_information.tlAddress, b->UP_TL_information.tlAddress);
_E1_EQ_CHECK_INT(a->UP_TL_information.teId, b->UP_TL_information.teId);
_E1_EQ_CHECK_LONG(a->numDRB2Setup, b->numDRB2Setup);
if (a->numDRB2Setup != b->numDRB2Setup)
return false;
eq_up_tl_info(&a->UP_TL_information, &b->UP_TL_information);
_E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup);
for (int i = 0; i < a->numDRB2Setup; i++)
if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i]))
return false;
_E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify);
if (a->numDRB2Modify != b->numDRB2Modify)
return false;
for (int i = 0; i < a->numDRB2Modify; i++)
if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i]))
return false;
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer);
if (a->inactivityTimer && b->inactivityTimer)
_E1_EQ_CHECK_INT(a->inactivityTimer, b->inactivityTimer);
_E1_EQ_CHECK_OPTIONAL_IE(a, b, dlAggregateMaxBitRate, _E1_EQ_CHECK_LONG);
return true;
}
static bool cp_pdu_session_item(pdu_session_to_setup_t *cp, const pdu_session_to_setup_t *msg)
{
// Copy basic fields
*cp = *msg;
// Copy DRB to Setup List
for (int j = 0; j < msg->numDRB2Setup; j++) {
cp->DRBnGRanList[j].id = msg->DRBnGRanList[j].id;
cp->DRBnGRanList[j].sdap_config = msg->DRBnGRanList[j].sdap_config;
cp->DRBnGRanList[j].pdcp_config = msg->DRBnGRanList[j].pdcp_config;
cp->DRBnGRanList[j].tlAddress = msg->DRBnGRanList[j].tlAddress;
cp->DRBnGRanList[j].teId = msg->DRBnGRanList[j].teId;
cp->DRBnGRanList[j].numDlUpParam = msg->DRBnGRanList[j].numDlUpParam;
// Copy DL UP Params List
for (int k = 0; k < msg->DRBnGRanList[j].numDlUpParam; k++) {
cp->DRBnGRanList[j].DlUpParamList[k] = msg->DRBnGRanList[j].DlUpParamList[k];
}
cp->DRBnGRanList[j].numCellGroups = msg->DRBnGRanList[j].numCellGroups;
// Copy Cell Group List
for (int k = 0; k < msg->DRBnGRanList[j].numCellGroups; k++) {
cp->DRBnGRanList[j].cellGroupList[k] = msg->DRBnGRanList[j].cellGroupList[k];
}
cp->DRBnGRanList[j].numQosFlow2Setup = msg->DRBnGRanList[j].numQosFlow2Setup;
// Copy QoS Flow To Setup List
for (int k = 0; k < msg->DRBnGRanList[j].numQosFlow2Setup; k++) {
cp->DRBnGRanList[j].qosFlows[k].qfi = msg->DRBnGRanList[j].qosFlows[k].qfi;
cp->DRBnGRanList[j].qosFlows[k].qos_params = msg->DRBnGRanList[j].qosFlows[k].qos_params;
}
}
// Copy DRB to Modify List
for (int j = 0; j < msg->numDRB2Modify; j++) {
cp->DRBnGRanModList[j] = msg->DRBnGRanModList[j];
}
return true;
}
/* ====================================
* E1AP Bearer Context Setup Request
* ==================================== */
/**
* @brief E1AP Bearer Context Setup Request encoding (9.2.2 of 3GPP TS 38.463)
......@@ -421,13 +550,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_
ieC2->id = E1AP_ProtocolIE_ID_id_SecurityInformation;
ieC2->criticality = E1AP_Criticality_reject;
ieC2->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation;
E1AP_SecurityAlgorithm_t *securityAlgorithm = &ieC2->value.choice.SecurityInformation.securityAlgorithm;
E1AP_UPSecuritykey_t *uPSecuritykey = &ieC2->value.choice.SecurityInformation.uPSecuritykey;
securityAlgorithm->cipheringAlgorithm = msg->cipheringAlgorithm;
OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, msg->encryptionKey, E1AP_SECURITY_KEY_SIZE);
asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, msg->integrityProtectionAlgorithm);
asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey);
OCTET_STRING_fromBuf(protKey, msg->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE);
ieC2->value.choice.SecurityInformation = e1_encode_security_info(&msg->secInfo);
/* mandatory */
/* c3. UE DL Aggregate Maximum Bit Rate */
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3);
......@@ -450,8 +573,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_
ieC5->criticality = E1AP_Criticality_reject;
ieC5->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel;
ieC5->value.choice.ActivityNotificationLevel = E1AP_ActivityNotificationLevel_pdu_session; // TODO: Remove hard coding
/* mandatory */
/* */
// System (M)
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC6);
ieC6->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest;
ieC6->criticality = E1AP_Criticality_reject;
......@@ -469,7 +591,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_
for (int i = 0; i < msg->numPDUSessions; i++) {
const pdu_session_to_setup_t *pdu_session = &msg->pduSession[i];
asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Item_t, ieC6_1);
e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session);
CHECK_E1AP_DEC(e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session));
}
return pdu;
}
......@@ -479,7 +601,8 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_
*/
void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg)
{
// Do nothing
free(msg->inactivityTimerUE);
free(msg->ueDlMaxIPBitRate);
}
/**
......@@ -492,8 +615,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea
// Check message type
_E1_EQ_CHECK_INT(pdu->present,E1AP_E1AP_PDU_PR_initiatingMessage);
_E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup);
_E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->criticality, E1AP_Criticality_reject);
_E1_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup);
_E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest);
const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest;
......@@ -519,17 +641,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea
case E1AP_ProtocolIE_ID_id_SecurityInformation:
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation);
E1AP_SecurityInformation_t *SecurityInformation = &ie->value.choice.SecurityInformation;
E1AP_SecurityAlgorithm_t *securityAlgorithm = &SecurityInformation->securityAlgorithm;
E1AP_EncryptionKey_t *encryptionKey = &SecurityInformation->uPSecuritykey.encryptionKey;
E1AP_IntegrityProtectionKey_t *integrityProtectionKey = SecurityInformation->uPSecuritykey.integrityProtectionKey;
out->cipheringAlgorithm = securityAlgorithm->cipheringAlgorithm;
memcpy(out->encryptionKey, encryptionKey->buf, encryptionKey->size);
if (securityAlgorithm->integrityProtectionAlgorithm)
out->integrityProtectionAlgorithm = *securityAlgorithm->integrityProtectionAlgorithm;
if (integrityProtectionKey)
memcpy(out->integrityProtectionKey, integrityProtectionKey->buf, integrityProtectionKey->size);
CHECK_E1AP_DEC(e1_decode_security_info(&out->secInfo, &ie->value.choice.SecurityInformation));
break;
case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate:
......@@ -545,12 +657,6 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea
out->servingPLMNid.mnc_digit_length);
break;
case E1AP_ProtocolIE_ID_id_ActivityNotificationLevel:
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel);
DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel);
out->activityNotificationLevel = ie->value.choice.ActivityNotificationLevel;
break;
case E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest:
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest);
E1AP_System_BearerContextSetupRequest_t *System_BearerContextSetupRequest =
......@@ -590,10 +696,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea
for (int i = 0; i < pdu2SetupList->list.count; i++) {
pdu_session_to_setup_t *pdu_session = out->pduSession + i;
E1AP_PDU_Session_Resource_To_Setup_Item_t *pdu2Setup = pdu2SetupList->list.array[i];
if (!e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup)) {
PRINT_ERROR("Failed to decode PDU Session to setup item %d\n", i);
return false;
}
CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup));
}
break;
default:
......@@ -604,19 +707,35 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea
return true;
}
/**
* @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST
*/
/** @brief Deep copy PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */
static pdu_session_to_setup_t cp_pdu_session_item(const pdu_session_to_setup_t *msg)
{
pdu_session_to_setup_t cp = {0};
// Copy basic fields
cp = *msg;
// Copy DRB to Setup List
for (int j = 0; j < msg->numDRB2Setup; j++)
cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]);
// Copy optional IEs
_E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer);
_E1_CP_OPTIONAL_IE(&cp, msg, dlAggregateMaxBitRate);
return cp;
}
/** @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST */
e1ap_bearer_setup_req_t cp_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg)
{
e1ap_bearer_setup_req_t cp = {0};
// Copy basi fields
cp = *msg;
strncpy(cp.encryptionKey, msg->encryptionKey, sizeof(cp.encryptionKey));
strncpy(cp.integrityProtectionKey, msg->integrityProtectionKey, sizeof(cp.integrityProtectionKey));
strncpy(cp.secInfo.encryptionKey, msg->secInfo.encryptionKey, sizeof(cp.secInfo.encryptionKey));
strncpy(cp.secInfo.integrityProtectionKey, msg->secInfo.integrityProtectionKey, sizeof(cp.secInfo.integrityProtectionKey));
// Copy PDU Sessions
for (int i = 0; i < msg->numPDUSessions; i++)
cp_pdu_session_item(&cp.pduSession[i], &msg->pduSession[i]);
cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]);
// copy optional IEs
_E1_CP_OPTIONAL_IE(&cp, msg, ueDlMaxIPBitRate);
_E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimerUE);
return cp;
}
......@@ -627,30 +746,28 @@ bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1a
{
// Primitive data types
_E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id);
_E1_EQ_CHECK_LONG(a->cipheringAlgorithm, b->cipheringAlgorithm);
_E1_EQ_CHECK_LONG(a->integrityProtectionAlgorithm, b->integrityProtectionAlgorithm);
_E1_EQ_CHECK_LONG(a->secInfo.cipheringAlgorithm, b->secInfo.cipheringAlgorithm);
_E1_EQ_CHECK_LONG(a->secInfo.integrityProtectionAlgorithm, b->secInfo.integrityProtectionAlgorithm);
_E1_EQ_CHECK_LONG(a->ueDlAggMaxBitRate, b->ueDlAggMaxBitRate);
_E1_EQ_CHECK_INT(a->activityNotificationLevel, b->activityNotificationLevel);
_E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions);
_E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod);
// PLMN
_E1_EQ_CHECK_INT(a->servingPLMNid.mcc, b->servingPLMNid.mcc);
_E1_EQ_CHECK_INT(a->servingPLMNid.mnc, b->servingPLMNid.mnc);
_E1_EQ_CHECK_INT(a->servingPLMNid.mnc_digit_length, b->servingPLMNid.mnc_digit_length);
// Security Keys
_E1_EQ_CHECK_STR(a->encryptionKey, b->encryptionKey);
_E1_EQ_CHECK_STR(a->integrityProtectionKey, b->integrityProtectionKey);
_E1_EQ_CHECK_STR(a->secInfo.encryptionKey, b->secInfo.encryptionKey);
_E1_EQ_CHECK_STR(a->secInfo.integrityProtectionKey, b->secInfo.integrityProtectionKey);
// PDU Sessions
if (a->numPDUSessions != b->numPDUSessions)
return false;
for (int i = 0; i < a->numPDUSessions; i++)
if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i]))
return false;
if (a->numPDUSessionsMod != b->numPDUSessionsMod)
return false;
for (int i = 0; i < a->numPDUSessionsMod; i++)
if (!eq_pdu_session_item(&a->pduSessionMod[i], &b->pduSessionMod[i]))
return false;
// Check optional IEs
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimerUE);
if (a->inactivityTimerUE && b->inactivityTimerUE)
_E1_EQ_CHECK_INT(a->inactivityTimerUE, b->inactivityTimerUE);
_E1_EQ_CHECK_OPTIONAL_IE(a, b, ueDlMaxIPBitRate, _E1_EQ_CHECK_LONG);
return true;
}
......@@ -669,12 +786,7 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP
pduSetup->id = in->pDU_Session_ID;
pduSetup->numDRBSetup = in->dRB_Setup_List_NG_RAN.list.count;
// NG DL UP Transport Layer Information (M)
E1AP_UP_TNL_Information_t *DL_UP_TNL_Info = &in->nG_DL_UP_TNL_Information;
if (DL_UP_TNL_Info->choice.gTPTunnel) {
_E1_EQ_CHECK_INT(DL_UP_TNL_Info->present, E1AP_UP_TNL_Information_PR_gTPTunnel);
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&DL_UP_TNL_Info->choice.gTPTunnel->transportLayerAddress, pduSetup->tlAddress);
OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->teId);
}
CHECK_E1AP_DEC(e1_decode_up_tnl_info(&pduSetup->tl_info, &in->nG_DL_UP_TNL_Information));
// DRB Setup List (1..<maxnoofDRBs>)
for (int j = 0; j < in->dRB_Setup_List_NG_RAN.list.count; j++) {
DRB_nGRAN_setup_t *drbSetup = pduSetup->DRBnGRanList + j;
......@@ -682,34 +794,31 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP
// DRB ID (M)
drbSetup->id = drb->dRB_ID;
// UL UP Parameters (M)
drbSetup->numUpParam = drb->uL_UP_Transport_Parameters.list.count;
for (int k = 0; k < drb->uL_UP_Transport_Parameters.list.count; k++) {
up_params_t *UL_UP_param = drbSetup->UpParamList + k;
// UP Parameters List (1..<maxnoofUPParameters>)
E1AP_UP_Parameters_Item_t *UL_UP_item = drb->uL_UP_Transport_Parameters.list.array[k];
// UP Transport Layer Information (M)
DevAssert(UL_UP_item->uP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel);
// GTP Tunnel (M)
E1AP_GTPTunnel_t *gTPTunnel = UL_UP_item->uP_TNL_Information.choice.gTPTunnel;
AssertError(gTPTunnel != NULL, return false, "gTPTunnel information in required in UP Transport Layer Information\n");
if (gTPTunnel) {
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->tlAddress);
OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->teId);
} else {
}
// Cell Group ID (M)
UL_UP_param->cell_group_id = UL_UP_item->cell_Group_ID;
if ((drbSetup->numUpParam = decode_dl_up_parameters(drbSetup->UpParamList, &drb->uL_UP_Transport_Parameters)) < 0) {
PRINT_ERROR("UL UP Parameters decoding failed\n");
return false;
}
// Flow Setup List (M)
drbSetup->numQosFlowSetup = drb->flow_Setup_List.list.count;
for (int q = 0; q < drb->flow_Setup_List.list.count; q++) {
qos_flow_setup_t *qosflowSetup = &drbSetup->qosFlows[q];
qos_flow_list_t *qosflowSetup = &drbSetup->qosFlows[q];
E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q];
qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier;
}
}
return true;
}
// DRB Failed to Setup List (O)
if (in->dRB_Failed_List_NG_RAN) {
for (int j = 0; j < in->dRB_Failed_List_NG_RAN->list.count; j++) {
DRB_nGRAN_failed_t *drbFailed = pduSetup->DRBnGRanFailedList + j;
E1AP_DRB_Failed_Item_NG_RAN_t *item = in->dRB_Failed_List_NG_RAN->list.array[j];
// DRB ID (M)
drbFailed->id = item->dRB_ID;
// Cause (M)
drbFailed->cause = e1_decode_cause_ie(&item->cause);
}
}
return true;
}
/**
* @brief Encode an item of the E1 PDU Session Resource Setup List (9.3.3.5 of 3GPP TS 38.463)
......@@ -719,25 +828,16 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite
// PDU Session ID (M)
item->pDU_Session_ID = in->id;
// NG DL UP Transport Layer Information (M)
item->nG_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
asn1cCalloc(item->nG_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID);
item->nG_DL_UP_TNL_Information = e1_encode_up_tnl_info(&in->tl_info);
// DRB Setup List (1..<maxnoofDRBs>)
for (const DRB_nGRAN_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRBSetup; j++) {
asn1cSequenceAdd(item->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1);
// DRB ID (M)
ieC3_1_1->dRB_ID = j->id;
// UL UP Parameters (M)
for (const up_params_t *k = j->UpParamList; k < j->UpParamList + j->numUpParam; k++) {
asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1);
ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID);
}
ieC3_1_1->uL_UP_Transport_Parameters = encode_dl_up_parameters(j->numUpParam, j->UpParamList);
// Flow Setup List(M)
for (const qos_flow_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) {
for (const qos_flow_list_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) {
asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1);
ieC3_1_1_1->qoS_Flow_Identifier = k->qfi;
}
......@@ -751,24 +851,7 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite
// DRB ID (M)
ieC3_1_1->dRB_ID = j->id;
// Cause (M)
ieC3_1_1->cause.present = j->cause_type;
switch (ieC3_1_1->cause.present) {
case E1AP_Cause_PR_radioNetwork:
ieC3_1_1->cause.choice.radioNetwork = j->cause;
break;
case E1AP_Cause_PR_transport:
ieC3_1_1->cause.choice.transport = j->cause;
break;
case E1AP_Cause_PR_protocol:
ieC3_1_1->cause.choice.protocol = j->cause;
break;
case E1AP_Cause_PR_misc:
ieC3_1_1->cause.choice.misc = j->cause;
break;
default:
PRINT_ERROR("DRB setup failure cause out of expected range\n");
break;
}
ieC3_1_1->cause = e1_encode_cause_ie(&j->cause);
}
return true;
}
......@@ -816,7 +899,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_response(const e1ap_bearer_setup
E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
for (const pdu_session_setup_t *i = in->pduSession; i < in->pduSession + in->numPDUSessions; i++) {
asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1);
e1_encode_pdu_session_setup_item(ieC3_1, i);
CHECK_E1AP_DEC(e1_encode_pdu_session_setup_item(ieC3_1, i));
}
return pdu;
}
......@@ -828,8 +911,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be
{
// Check message type
_E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_successfulOutcome);
_E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup);
_E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->criticality, E1AP_Criticality_reject);
_E1_EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup);
_E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse);
const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse;
......@@ -862,7 +944,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be
ie->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse;
_E1_EQ_CHECK_INT(msgNGRAN_list->list.count, 1);
E1AP_NG_RAN_BearerContextSetupResponse_t *msgNGRAN = msgNGRAN_list->list.array[0];
_E1_EQ_CHECK_INT(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List);
_E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List);
_E1_EQ_CHECK_INT(msgNGRAN->value.present,
E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List);
E1AP_PDU_Session_Resource_Setup_List_t *pduSetupList = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
......@@ -870,7 +952,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be
for (int i = 0; i < pduSetupList->list.count; i++) {
pdu_session_setup_t *pduSetup = out->pduSession + i;
E1AP_PDU_Session_Resource_Setup_Item_t *pdu_session = pduSetupList->list.array[i];
e1_decode_pdu_session_setup_item(pduSetup, pdu_session);
CHECK_E1AP_DEC(e1_decode_pdu_session_setup_item(pduSetup, pdu_session));
}
} break;
......@@ -938,8 +1020,7 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e
const pdu_session_setup_t *ps_a = &a->pduSession[i];
const pdu_session_setup_t *ps_b = &b->pduSession[i];
_E1_EQ_CHECK_LONG(ps_a->id, ps_b->id);
_E1_EQ_CHECK_INT(ps_a->tlAddress, ps_b->tlAddress);
_E1_EQ_CHECK_LONG(ps_a->teId, ps_b->teId);
eq_up_tl_info(&ps_a->tl_info, &ps_b->tl_info);
_E1_EQ_CHECK_INT(ps_a->numDRBSetup, ps_b->numDRBSetup);
_E1_EQ_CHECK_INT(ps_a->numDRBFailed, ps_b->numDRBFailed);
// Check DRB Setup
......@@ -955,8 +1036,8 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e
const DRB_nGRAN_failed_t *drbf_a = &ps_a->DRBnGRanFailedList[j];
const DRB_nGRAN_failed_t *drbf_b = &ps_b->DRBnGRanFailedList[j];
_E1_EQ_CHECK_LONG(drbf_a->id, drbf_b->id);
_E1_EQ_CHECK_LONG(drbf_a->cause_type, drbf_b->cause_type);
_E1_EQ_CHECK_LONG(drbf_a->cause, drbf_b->cause);
_E1_EQ_CHECK_LONG(drbf_a->cause.type, drbf_b->cause.type);
_E1_EQ_CHECK_LONG(drbf_a->cause.value, drbf_b->cause.value);
}
}
return true;
......@@ -969,3 +1050,633 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg)
{
// Do nothing (no dynamic allocation)
}
/* ============================================
* E1AP Bearer Context Modification Request
* ============================================ */
/** @brief Encode PDU Session Item to modify */
static E1AP_PDU_Session_Resource_To_Modify_Item_t e1_encode_pdu_session_to_mod_item(const pdu_session_to_mod_t *in)
{
E1AP_PDU_Session_Resource_To_Modify_Item_t out = {0};
out.pDU_Session_ID = in->sessionId;
for (const DRB_nGRAN_to_mod_t *j = in->DRBnGRanModList; j < in->DRBnGRanModList + in->numDRB2Modify; j++) {
asn1cCalloc(out.dRB_To_Modify_List_NG_RAN, drb2Mod_List);
asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod);
drb2Mod->dRB_ID = j->id;
// PDCP Config (O)
if (j->pdcp_config) {
asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration);
*pDCP_Configuration = e1_encode_pdcp_config(j->pdcp_config);
}
// SDAP Config (O)
if (j->sdap_config) {
asn1cCalloc(drb2Mod->sDAP_Configuration, sDAP_Configuration);
*sDAP_Configuration = e1_encode_sdap_config(j->sdap_config);
}
// PDCP SN Status Request (O)
if (j->pdcp_sn_status_requested) {
asn1cCalloc(drb2Mod->pDCP_SN_Status_Request, pDCP_SN_Status_Request);
*pDCP_SN_Status_Request = E1AP_PDCP_SN_Status_Request_requested;
}
// DL UP TNL parameters (O)
if (j->numDlUpParam > 0) {
asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List);
for (const up_params_t *k = j->DlUpParamList; k < j->DlUpParamList + j->numDlUpParam; k++) {
asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param);
DL_UP_Param->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info);
DL_UP_Param->cell_Group_ID = k->cell_group_id;
}
}
// QoS Flows to setup (O)
for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) {
asn1cCalloc(drb2Mod->flow_Mapping_Information, flow_Mapping_Information);
asn1cSequenceAdd(flow_Mapping_Information->list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2);
*ie1_2 = e1_encode_qos_flow_to_setup(k);
}
}
return out;
}
/** @brief Common encoding for the NG-RAN System IE */
static E1AP_NG_RAN_BearerContextModificationRequest_t *encode_ng_ran_to_mod(E1AP_BearerContextModificationRequestIEs_t *ie)
{
ie->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest;
ie->criticality = E1AP_Criticality_reject;
ie->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest;
E1AP_System_BearerContextModificationRequest_t *reqIE = &ie->value.choice.System_BearerContextModificationRequest;
reqIE->present = E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest;
E1AP_ProtocolIE_Container_4932P26_t *msgNGRAN_list = calloc_or_fail(1, sizeof(*msgNGRAN_list));
reqIE->choice.nG_RAN_BearerContextModificationRequest = (struct E1AP_ProtocolIE_Container *)msgNGRAN_list;
asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextModificationRequest_t, msgNGRAN);
return msgNGRAN;
}
/** @brief Encode PDU Session Resource To Setup Modification List item */
static E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t e1_encode_pdu_session_to_setup_mod_item(const pdu_session_to_setup_t *in)
{
E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t item = {0};
// PDU Session ID (M)
item.pDU_Session_ID = in->sessionId;
// PDU Session Type (M)
item.pDU_Session_Type = in->sessionType;
// SNSSAI (M)
item.sNSSAI = e1_encode_snssai(&in->nssai);
// Security indication (M)
item.securityIndication = e1_encode_security_indication(&in->securityIndication);
// NG UL UP Transport Layer Information (M)
item.nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information);
// DRB to setup
for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) {
asn1cSequenceAdd(item.dRB_To_Setup_Mod_List_NG_RAN.list, E1AP_DRB_To_Setup_Mod_Item_NG_RAN_t, ie1);
// DRB ID (M)
ie1->dRB_ID = j->id;
// SDAP Config (M)
ie1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config);
// PDCP Config (M)
ie1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config);
// Cell Group Information (M)
for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) {
asn1cSequenceAdd(ie1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ie1_1);
ie1_1->cell_Group_ID = *k;
}
// QoS Flows Information To Be Setup (M)
for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) {
asn1cSequenceAdd(ie1->flow_Mapping_Information.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2);
*ie1_2 = e1_encode_qos_flow_to_setup(k);
}
}
return item;
}
/**
* @brief Encodes the E1 Bearer Modification Request message
*/
E1AP_E1AP_PDU_t *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *in)
{
E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
// PDU Type
pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage;
asn1cCalloc(pdu->choice.initiatingMessage, msg);
msg->procedureCode = E1AP_ProcedureCode_id_bearerContextModification;
msg->criticality = E1AP_Criticality_reject;
msg->value.present = E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest;
E1AP_BearerContextModificationRequest_t *out = &msg->value.choice.BearerContextModificationRequest;
// gNB-CU-CP UE E1AP ID (M)
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie1);
ie1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID;
ie1->criticality = E1AP_Criticality_reject;
ie1->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID;
ie1->value.choice.GNB_CU_CP_UE_E1AP_ID = in->gNB_cu_cp_ue_id;
// gNB-CU-UP UE E1AP ID (M)
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie2);
ie2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID;
ie2->criticality = E1AP_Criticality_reject;
ie2->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID;
ie2->value.choice.GNB_CU_UP_UE_E1AP_ID = in->gNB_cu_up_ue_id;
// Security Information (O)
if (in->secInfo) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie3);
ie3->id = E1AP_ProtocolIE_ID_id_SecurityInformation;
ie3->criticality = E1AP_Criticality_reject;
ie3->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation;
ie3->value.choice.SecurityInformation = e1_encode_security_info(in->secInfo);
}
// UE DL Aggregate Maximum Bit Rate (O)
if (in->ueDlAggMaxBitRate) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie4);
ie4->id = E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate;
ie4->criticality = E1AP_Criticality_reject;
ie4->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BitRate;
INT32_TO_OCTET_STRING(*in->ueDlAggMaxBitRate, &ie4->value.choice.BitRate);
}
// UE DL Maximum Integrity Protected Data Rate (O)
if (in->ueDlMaxIPBitRate) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie5);
ie5->id = E1AP_ProtocolIE_ID_id_UEDLMaximumIntegrityProtectedDataRate;
ie5->criticality = E1AP_Criticality_ignore;
ie5->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BitRate;
INT32_TO_OCTET_STRING(*in->ueDlMaxIPBitRate, &ie5->value.choice.BitRate);
}
// Bearer Context Status Change (O)
if (in->bearerContextStatus && *in->bearerContextStatus == BEARER_SUSPEND) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie6);
ie6->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange;
ie6->criticality = E1AP_Criticality_reject;
ie6->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange;
ie6->value.choice.BearerContextStatusChange = E1AP_BearerContextStatusChange_suspend;
}
// UE Inactivity Timer (O)
if (in->inactivityTimer) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie7);
ie7->id = E1AP_ProtocolIE_ID_id_UE_Inactivity_Timer;
ie7->criticality = E1AP_Criticality_ignore;
ie7->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_Inactivity_Timer;
ie7->value.choice.Inactivity_Timer = *in->inactivityTimer;
}
// Data Discard Required (O)
if (in->dataDiscardRequired) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie9);
ie9->id = E1AP_ProtocolIE_ID_id_DataDiscardRequired;
ie9->criticality = E1AP_Criticality_ignore;
ie9->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_DataDiscardRequired;
ie9->value.choice.DataDiscardRequired = in->dataDiscardRequired;
}
// NG-RAN PDU Session Resource To Setup List (O)
if (in->numPDUSessions) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, setupList);
E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(setupList);
msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List;
msgNGRAN->criticality = E1AP_Criticality_reject;
msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Setup_Mod_List;
E1AP_PDU_Session_Resource_To_Setup_Mod_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_Mod_List;
for (int i = 0; i < in->numPDUSessions; i++) {
const pdu_session_to_setup_t *pdu_session = &in->pduSession[i];
asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t, item);
*item = e1_encode_pdu_session_to_setup_mod_item(pdu_session);
}
}
// NG-RAN PDU Session Resource To Modify List (O)
if (in->numPDUSessionsMod) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, modList);
E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(modList);
msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List;
msgNGRAN->criticality = E1AP_Criticality_reject;
msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List;
E1AP_PDU_Session_Resource_To_Modify_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List;
for (const pdu_session_to_mod_t *i = in->pduSessionMod; i < in->pduSessionMod + in->numPDUSessionsMod; i++) {
asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Modify_Item_t, ieC3_1);
*ieC3_1 = e1_encode_pdu_session_to_mod_item(i);
}
}
return pdu;
}
/** @brief Decode PDU Session Item to Setup (Bearer Context Modification Request) */
static bool e1_decode_pdu_session_to_setup_mod_item(pdu_session_to_setup_t *out,
const E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t *item)
{
// PDU Session ID (M)
out->sessionId = item->pDU_Session_ID;
// PDU Session Type (M)
out->sessionType = item->pDU_Session_Type;
// S-NSSAI (M)
CHECK_E1AP_DEC(e1_decode_snssai(&out->nssai, &item->sNSSAI));
// Security Indication (M)
CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication));
/* NG UL UP Transport Layer Information (M) */
_E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel);
CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information));
/* DRB To Setup List ( > 1 item ) */
const E1AP_DRB_To_Setup_Mod_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_Mod_List_NG_RAN;
_E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0);
out->numDRB2Setup = drb2SetupList->list.count;
_E1_EQ_CHECK_INT(out->numDRB2Setup, 1); // can only handle one DRB per PDU session
for (int j = 0; j < drb2SetupList->list.count; j++) {
DRB_nGRAN_to_setup_t *drb = out->DRBnGRanList + j;
const E1AP_DRB_To_Setup_Mod_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j];
// DRB ID (M)
drb->id = drb2Setup->dRB_ID;
// SDAP Configuration (M)
CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration));
// PDCP Configuration (M)
CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration));
// Cell Group Information (M)
const E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information;
_E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0);
drb->numCellGroups = cellGroupList->list.count;
for (int k = 0; k < cellGroupList->list.count; k++) {
const E1AP_Cell_Group_Information_Item_t *cg2Setup = cellGroupList->list.array[k];
// Cell Group ID
drb->cellGroupList[k] = cg2Setup->cell_Group_ID;
}
// QoS Flows Information To Be Setup (M)
const E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->flow_Mapping_Information;
drb->numQosFlow2Setup = qos2SetupList->list.count;
for (int k = 0; k < qos2SetupList->list.count; k++) {
CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k]));
}
}
return true;
}
/** @brief Decode PDU Session Item to modify (Bearer Context Modification Request) */
static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E1AP_PDU_Session_Resource_To_Modify_Item_t *in)
{
// PDU Session ID
out->sessionId = in->pDU_Session_ID;
// DRB to modify list
E1AP_DRB_To_Modify_List_NG_RAN_t *drb2ModList = in->dRB_To_Modify_List_NG_RAN;
out->numDRB2Modify = drb2ModList->list.count;
for (int j = 0; j < drb2ModList->list.count; j++) {
DRB_nGRAN_to_mod_t *drb = out->DRBnGRanModList + j;
// DRB to modify item
E1AP_DRB_To_Modify_Item_NG_RAN_t *drb2Mod = drb2ModList->list.array[j];
drb->id = drb2Mod->dRB_ID;
// PDCP Config (O)
if (drb2Mod->pDCP_Configuration) {
drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config));
CHECK_E1AP_DEC(e1_decode_pdcp_config(drb->pdcp_config, drb2Mod->pDCP_Configuration));
}
// SDAP Config (O)
if (drb2Mod->sDAP_Configuration) {
drb->sdap_config = malloc_or_fail(sizeof(*drb->sdap_config));
CHECK_E1AP_DEC(e1_decode_sdap_config(drb->sdap_config, drb2Mod->sDAP_Configuration));
}
// PDCP SN Status Request (O)
if (drb2Mod->pDCP_SN_Status_Request) {
drb->pdcp_sn_status_requested = true;
}
// DL UP TNL parameters (O)
if (drb2Mod->dL_UP_Parameters) {
E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters;
if((drb->numDlUpParam = decode_dl_up_parameters(drb->DlUpParamList, dl_up_paramList)) < 0) {
PRINT_ERROR("Failed to decode DL UP TNL parameters\n");
return false;
}
}
// QoS Flows Information To Be Setup (O)
E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = drb2Mod->flow_Mapping_Information;
drb->numQosFlow2Setup = qos2SetupList->list.count;
for (int k = 0; k < qos2SetupList->list.count; k++) {
CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k]));
}
}
return true;
}
/**
* @brief E1 Bearer Modification Request message decoding
*/
bool decode_E1_bearer_context_mod_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_mod_req_t *out)
{
DevAssert(pdu != NULL);
// Validate message type
_E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_initiatingMessage);
const E1AP_InitiatingMessage_t *im = pdu->choice.initiatingMessage;
_E1_EQ_CHECK_LONG(im->procedureCode, E1AP_ProcedureCode_id_bearerContextModification);
_E1_EQ_CHECK_INT(im->value.present, E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest);
const E1AP_BearerContextModificationRequest_t *in = &im->value.choice.BearerContextModificationRequest;
E1AP_BearerContextModificationRequestIEs_t *ie = NULL;
// Mandatory IEs
// gNB-CU-CP UE E1AP ID (M)
E1AP_LIB_FIND_IE(E1AP_BearerContextModificationRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true);
// gNB-CU-UP UE E1AP ID (M)
E1AP_LIB_FIND_IE(E1AP_BearerContextModificationRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID, true);
// Loop through all IEs and extract
for (int i = 0; i < in->protocolIEs.list.count; i++) {
ie = in->protocolIEs.list.array[i];
switch (ie->id) {
case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID:
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID);
out->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID;
break;
case E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID:
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID);
out->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID;
break;
case E1AP_ProtocolIE_ID_id_SecurityInformation:
out->secInfo = malloc_or_fail(sizeof(*out->secInfo));
CHECK_E1AP_DEC(e1_decode_security_info(out->secInfo, &ie->value.choice.SecurityInformation));
break;
case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate:
out->ueDlAggMaxBitRate = malloc_or_fail(sizeof(*out->ueDlAggMaxBitRate));
OCTET_STRING_TO_UINT32(&ie->value.choice.BitRate, *out->ueDlAggMaxBitRate);
break;
case E1AP_ProtocolIE_ID_id_UEDLMaximumIntegrityProtectedDataRate:
out->ueDlMaxIPBitRate = malloc_or_fail(sizeof(*out->ueDlMaxIPBitRate));
OCTET_STRING_TO_UINT32(&ie->value.choice.BitRate, *out->ueDlMaxIPBitRate);
break;
case E1AP_ProtocolIE_ID_id_BearerContextStatusChange:
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange);
if (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) {
out->bearerContextStatus = malloc_or_fail(sizeof(*out->bearerContextStatus));
*out->bearerContextStatus = BEARER_SUSPEND;
}
break;
case E1AP_ProtocolIE_ID_id_UE_Inactivity_Timer:
out->inactivityTimer = malloc_or_fail(sizeof(*out->inactivityTimer));
*out->inactivityTimer = ie->value.choice.Inactivity_Timer;
break;
case E1AP_ProtocolIE_ID_id_DataDiscardRequired:
out->dataDiscardRequired = ie->value.choice.DataDiscardRequired;
break;
case E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest: {
_E1_EQ_CHECK_INT(ie->value.present,
E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest);
E1AP_System_BearerContextModificationRequest_t *modReq = &ie->value.choice.System_BearerContextModificationRequest;
DevAssert(ie->value.choice.System_BearerContextModificationRequest.choice.nG_RAN_BearerContextModificationRequest != NULL);
// System IE can contain either UTRAN or NG-RAN
switch (modReq->present) {
case E1AP_System_BearerContextModificationRequest_PR_NOTHING:
PRINT_ERROR("System Bearer Context Setup Request: no choice present\n");
break;
case E1AP_System_BearerContextModificationRequest_PR_e_UTRAN_BearerContextModificationRequest:
PRINT_ERROR("UTRAN in E1 Setup Modification Request not supported\n");
return false;
break;
case E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest:
// NG-RAN
AssertFatal(modReq->choice.nG_RAN_BearerContextModificationRequest != NULL,
"System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest shall not be null");
E1AP_ProtocolIE_Container_4932P26_t *msgNGRAN_list =
(E1AP_ProtocolIE_Container_4932P26_t *)modReq->choice.nG_RAN_BearerContextModificationRequest;
// loop through all items in the NG-RAN list (to setup, to modify, etc)
for (int i = 0; i < msgNGRAN_list->list.count; i++) {
E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = msgNGRAN_list->list.array[i];
switch (msgNGRAN->id) {
case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List:
_E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List);
_E1_EQ_CHECK_INT(msgNGRAN->value.present,
E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Setup_Mod_List);
E1AP_PDU_Session_Resource_To_Setup_Mod_List_t *setupList =
&msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_Mod_List;
// PDU Session Resource To Modify List
out->numPDUSessions = setupList->list.count;
// Loop through all PDU sessions
for (int i = 0; i < setupList->list.count; i++) {
pdu_session_to_setup_t *pdu_session = out->pduSession + i;
E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t *pdu2Setup = setupList->list.array[i];
CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_mod_item(pdu_session, pdu2Setup));
}
break;
case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List:
/* PDU Session Resource To Modify List (see 9.3.3.11 of TS 38.463) */
_E1_EQ_CHECK_INT(msgNGRAN->value.present,
E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List);
E1AP_PDU_Session_Resource_To_Modify_List_t *modList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List;
out->numPDUSessionsMod = modList->list.count;
// Loop through all PDU sessions
for (int i = 0; i < modList->list.count; i++) {
CHECK_E1AP_DEC(e1_decode_pdu_session_to_mod_item(out->pduSessionMod + i, modList->list.array[i]));
}
break;
default:
PRINT_ERROR("Unknown msgNGRAN->id in E1 Setup Modification Request\n");
return false;
break;
}
}
break;
default:
PRINT_ERROR("System Bearer Context Modification Request: No valid choice present.\n");
break;
}
break;
}
default:
PRINT_ERROR("System Bearer Context Modification Request: this IE is not implemented (or) invalid IE detected\n");
return false;
break;
}
}
return true;
}
/** @brief Deep copy for DRB Item to modify */
static DRB_nGRAN_to_mod_t cp_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg)
{
DRB_nGRAN_to_mod_t cp = {0};
// shallow copy
cp = *msg;
_E1_CP_OPTIONAL_IE(&cp, msg, sdap_config);
_E1_CP_OPTIONAL_IE(&cp, msg, pdcp_config);
return cp;
}
/** @brief Deep copy for PDU Session Item to modify */
static pdu_session_to_mod_t cp_pdu_session_to_mod_item(const pdu_session_to_mod_t *msg)
{
pdu_session_to_mod_t cp = {0};
// shallow copy
cp = *msg;
// DRB to setup list
for (int j = 0; j < msg->numDRB2Setup; j++)
cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]);
// DRB to modify list
for (int j = 0; j < msg->numDRB2Modify; j++)
cp.DRBnGRanModList[j] = cp_drb_to_mod_item(&msg->DRBnGRanModList[j]);
_E1_CP_OPTIONAL_IE(&cp, msg, securityIndication);
_E1_CP_OPTIONAL_IE(&cp, msg, UP_TL_information);
return cp;
}
/** @brief Deep copy for Bearer Context Modification Request */
e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg)
{
e1ap_bearer_mod_req_t cp = {0};
// Shallow copy
cp = *msg;
// Deep copy for optional fields
_E1_CP_OPTIONAL_IE(&cp, msg, secInfo);
_E1_CP_OPTIONAL_IE(&cp, msg, bearerContextStatus);
_E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer);
// Deep copy PDU sessions
for (int i = 0; i < msg->numPDUSessions; i++)
cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]);
for (int i = 0; i < msg->numPDUSessionsMod; i++)
cp.pduSessionMod[i] = cp_pdu_session_to_mod_item(&msg->pduSessionMod[i]);
return cp;
}
/** @brief Equality check for Security Indication IE (3GPP TS 38.463 9.3.1.23) */
static bool eq_security_ind(security_indication_t *a, security_indication_t *b)
{
_E1_EQ_CHECK_INT(a->confidentialityProtectionIndication, b->confidentialityProtectionIndication);
_E1_EQ_CHECK_INT(a->integrityProtectionIndication, b->integrityProtectionIndication);
_E1_EQ_CHECK_LONG(a->maxIPrate, b->maxIPrate);
return true;
}
/**
* @brief Equality check for DRB_nGRAN_to_mod_t
*/
static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b)
{
bool result = true;
_E1_EQ_CHECK_LONG(a->id, b->id);
_E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup);
for (int i = 0; i < a->numQosFlow2Setup; i++) {
result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]);
}
_E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam);
for (int i = 0; i < a->numDlUpParam; i++) {
_E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id);
eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info);
}
if (a->pdcp_config && b->pdcp_config)
result &= eq_pdcp_config(a->pdcp_config, b->pdcp_config);
if (a->sdap_config && b->sdap_config)
result &= eq_sdap_config(a->sdap_config, b->sdap_config);
return result;
}
/** @brief Equality check for PDU session item to modify */
static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_session_to_mod_t *b)
{
_E1_EQ_CHECK_LONG(a->sessionId, b->sessionId);
if (a->UP_TL_information && a->UP_TL_information) {
if (!eq_up_tl_info(a->UP_TL_information, b->UP_TL_information))
return false;
}
_E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup);
for (int i = 0; i < a->numDRB2Setup; i++) {
if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i]))
return false;
}
_E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify);
for (int i = 0; i < a->numDRB2Modify; i++) {
if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i]))
return false;
}
if (a->securityIndication && b->securityIndication) {
eq_security_ind(a->securityIndication, b->securityIndication);
}
return true;
}
/**
* @brief E1AP Bearer Modification Request equality check
*/
bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_bearer_mod_req_t *b)
{
// basic members
_E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id);
_E1_EQ_CHECK_INT(a->gNB_cu_up_ue_id, b->gNB_cu_up_ue_id);
_E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions);
_E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod);
// Security Info
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, secInfo);
if (a->secInfo && b->secInfo) {
_E1_EQ_CHECK_LONG(a->secInfo->cipheringAlgorithm, b->secInfo->cipheringAlgorithm);
_E1_EQ_CHECK_LONG(a->secInfo->integrityProtectionAlgorithm, b->secInfo->integrityProtectionAlgorithm);
_E1_EQ_CHECK_STR(a->secInfo->encryptionKey, b->secInfo->encryptionKey);
_E1_EQ_CHECK_STR(a->secInfo->integrityProtectionKey, b->secInfo->integrityProtectionKey);
}
// Bearer Context Status (O)
_E1_EQ_CHECK_OPTIONAL_IE(a, b, bearerContextStatus, _E1_EQ_CHECK_INT);
// Inactivity Timer (O)
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer);
if (a->inactivityTimer && b->inactivityTimer)
_E1_EQ_CHECK_INT(*a->inactivityTimer, *b->inactivityTimer);
// Activity Notification Level (O)
// PDU Sessions
if (a->numPDUSessions != b->numPDUSessions)
return false;
for (int i = 0; i < a->numPDUSessions; i++) {
if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i]))
return false;
}
// Modified PDU Sessions
if (a->numPDUSessionsMod != b->numPDUSessionsMod)
return false;
for (int i = 0; i < a->numPDUSessionsMod; i++) {
if (!eq_pdu_session_to_mod_item(&a->pduSessionMod[i], &b->pduSessionMod[i]))
return false;
}
return true;
}
/* Free DRB to modify item */
static void free_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg)
{
free(msg->pdcp_config);
free(msg->sdap_config);
}
/* Free PDU Session to modify item */
void free_pdu_session_to_mod_item(const pdu_session_to_mod_t *msg)
{
free(msg->securityIndication);
free(msg->UP_TL_information);
for (int i = 0; i < msg->numDRB2Modify; i++)
free_drb_to_mod_item(&msg->DRBnGRanModList[i]);
for (int i = 0; i < msg->numDRB2Setup; i++)
free_drb_to_setup_item(&msg->DRBnGRanList[i]);
}
/**
* @brief E1AP Bearer Context Modification Request memory management
*/
void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg)
{
free(msg->secInfo);
free(msg->ueDlAggMaxBitRate);
free(msg->ueDlMaxIPBitRate);
free(msg->bearerContextStatus);
free(msg->inactivityTimer);
for (int i = 0; i < msg->numPDUSessions; i++)
free_pdu_session_to_setup_item(&msg->pduSession[i]);
for (int i = 0; i < msg->numPDUSessionsMod; i++)
free_pdu_session_to_mod_item(&msg->pduSessionMod[i]);
}
......@@ -40,4 +40,10 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg);
e1ap_bearer_setup_resp_t cp_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg);
bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e1ap_bearer_setup_resp_t *b);
struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg);
bool decode_E1_bearer_context_mod_request(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_mod_req_t *out);
void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg);
e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg);
bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_bearer_mod_req_t *b);
#endif /* E1AP_BEARER_CONTEXT_MANAGEMENT_H_ */
......@@ -508,61 +508,6 @@ bool eq_e1ap_cuup_setup_response(const e1ap_setup_resp_t *a, const e1ap_setup_re
* GNB-CU-UP E1 SETUP FAILURE
* ==================================== */
static E1AP_Cause_t encode_e1ap_cause_ie(const e1ap_cause_t *cause)
{
E1AP_Cause_t ie;
switch (cause->type) {
case E1AP_CAUSE_RADIO_NETWORK:
ie.present = E1AP_Cause_PR_radioNetwork;
ie.choice.radioNetwork = cause->value;
break;
case E1AP_CAUSE_TRANSPORT:
ie.present = E1AP_Cause_PR_transport;
ie.choice.transport = cause->value;
break;
case E1AP_CAUSE_PROTOCOL:
ie.present = E1AP_Cause_PR_protocol;
ie.choice.protocol = cause->value;
break;
case E1AP_CAUSE_MISC:
ie.present = E1AP_Cause_PR_misc;
ie.choice.misc = cause->value;
break;
default:
ie.present = E1AP_Cause_PR_NOTHING;
break;
}
return ie;
}
static e1ap_cause_t decode_e1ap_cause_ie(const E1AP_Cause_t *ie)
{
e1ap_cause_t cause;
// Decode the 'choice' field based on the 'present' value
switch (ie->present) {
case E1AP_Cause_PR_radioNetwork:
cause.value = ie->choice.radioNetwork;
cause.type = E1AP_CAUSE_RADIO_NETWORK;
break;
case E1AP_Cause_PR_transport:
cause.value = ie->choice.transport;
cause.type = E1AP_CAUSE_TRANSPORT;
break;
case E1AP_Cause_PR_protocol:
cause.value = ie->choice.protocol;
cause.type = E1AP_CAUSE_PROTOCOL;
break;
case E1AP_Cause_PR_misc:
cause.value = ie->choice.misc;
cause.type = E1AP_CAUSE_MISC;
break;
default:
cause.type = E1AP_CAUSE_NOTHING;
break;
}
return cause;
}
/**
* @brief Encoder for GNB-CU-UP E1 Setup Failure
* @ref 9.2.1.6 GNB-CU-UP E1 SETUP FAILURE of 3GPP TS 38.463
......@@ -588,7 +533,7 @@ E1AP_E1AP_PDU_t *encode_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *msg)
ie2->id = E1AP_ProtocolIE_ID_id_Cause;
ie2->criticality = E1AP_Criticality_ignore;
ie2->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_Cause;
ie2->value.choice.Cause = encode_e1ap_cause_ie(&msg->cause);
ie2->value.choice.Cause = e1_encode_cause_ie(&msg->cause);
// Time To Wait (O)
if (msg->time_to_wait) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie3);
......@@ -630,7 +575,7 @@ bool decode_e1ap_cuup_setup_failure(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_fail_
case E1AP_ProtocolIE_ID_id_Cause:
// Cause
E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Cause, true);
out->cause = decode_e1ap_cause_ie(&ie->value.choice.Cause);
out->cause = e1_decode_cause_ie(&ie->value.choice.Cause);
break;
case E1AP_ProtocolIE_ID_id_Transport_Layer_Address_Info:
// Time To Wait (O)
......
/*
* 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 "e1ap_lib_common.h"
#include "e1ap_lib_includes.h"
#include "e1ap_messages_types.h"
E1AP_Cause_t e1_encode_cause_ie(const e1ap_cause_t *cause)
{
E1AP_Cause_t ie;
switch (cause->type) {
case E1AP_CAUSE_RADIO_NETWORK:
ie.present = E1AP_Cause_PR_radioNetwork;
ie.choice.radioNetwork = cause->value;
break;
case E1AP_CAUSE_TRANSPORT:
ie.present = E1AP_Cause_PR_transport;
ie.choice.transport = cause->value;
break;
case E1AP_CAUSE_PROTOCOL:
ie.present = E1AP_Cause_PR_protocol;
ie.choice.protocol = cause->value;
break;
case E1AP_CAUSE_MISC:
ie.present = E1AP_Cause_PR_misc;
ie.choice.misc = cause->value;
break;
default:
ie.present = E1AP_Cause_PR_NOTHING;
PRINT_ERROR("encode_e1ap_cause_ie: no cause value provided\n");
break;
}
return ie;
}
e1ap_cause_t e1_decode_cause_ie(const E1AP_Cause_t *ie)
{
e1ap_cause_t cause;
// Decode the 'choice' field based on the 'present' value
switch (ie->present) {
case E1AP_Cause_PR_radioNetwork:
cause.value = ie->choice.radioNetwork;
cause.type = E1AP_CAUSE_RADIO_NETWORK;
break;
case E1AP_Cause_PR_transport:
cause.value = ie->choice.transport;
cause.type = E1AP_CAUSE_TRANSPORT;
break;
case E1AP_Cause_PR_protocol:
cause.value = ie->choice.protocol;
cause.type = E1AP_CAUSE_PROTOCOL;
break;
case E1AP_Cause_PR_misc:
cause.value = ie->choice.misc;
cause.type = E1AP_CAUSE_MISC;
break;
default:
cause.type = E1AP_CAUSE_NOTHING;
PRINT_ERROR("decode_e1ap_cause_ie: no cause value provided\n");
break;
}
return cause;
}
......@@ -26,13 +26,22 @@
#include <stdint.h>
#include <stdio.h>
#include "openair3/UTILS/conversions.h"
#include "e1ap_messages_types.h"
#ifdef ENABLE_TESTS
#ifdef E1AP_LOG_ERRORS
#define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__);
#else
#define PRINT_ERROR(...) // Do nothing
#endif
#define CHECK_E1AP_DEC(exp) \
do { \
if (!(exp)) { \
PRINT_ERROR("Failed executing " #exp " in %s() line %d\n", __func__, __LINE__); \
return false; \
} \
} while (0)
#define _E1_EQ_CHECK_GENERIC(condition, fmt, ...) \
do { \
if (!(condition)) { \
......@@ -66,4 +75,40 @@
} \
} while (0)
/* deep copy of optional E1AP IE */
#define _E1_CP_OPTIONAL_IE(dest, src, field) \
do { \
if ((src)->field) { \
(dest)->field = malloc_or_fail(sizeof(*(dest)->field)); \
*(dest)->field = *(src)->field; \
} \
} while (0)
#define _E1_EQ_CHECK_OPTIONAL_IE(a, b, field, EQ_MACRO) \
do { \
if (((a)->field && !(b)->field) || (!(a)->field && (b)->field)) { \
return false; /* One of the two is not allocated */ \
} \
if ((a)->field && (b)->field) { \
EQ_MACRO(*(a)->field, *(b)->field) \
} \
} while (0)
#define _E1_EQ_CHECK_OPTIONAL_PTR(a, b, field) \
do { \
if (((a)->field && !(b)->field) || (!(a)->field && (b)->field)) { \
PRINT_ERROR("%s:%d: optional IE '%s' not allocated: %p, %p\n", \
__FILE__, \
__LINE__, \
#field, \
(void *)(a)->field, \
(void *)(b)->field); \
return false; /* One of the two is not allocated */ \
} \
} while (0)
struct E1AP_Cause;
struct E1AP_Cause e1_encode_cause_ie(const e1ap_cause_t *cause);
e1ap_cause_t e1_decode_cause_ie(const struct E1AP_Cause *ie);
#endif /* E1AP_LIB_COMMON_H_ */
......@@ -48,6 +48,7 @@
#include "E1AP_System-BearerContextSetupRequest.h"
#include "E1AP_MaximumIPdatarate.h"
#include "E1AP_PDU-Session-Type.h"
#include "E1AP_Data-Forwarding-Information.h"
// E1 Bearer Context Setup Response
#include "E1AP_PDU-Session-Resource-Setup-Item.h"
#include "E1AP_DRB-Setup-Item-NG-RAN.h"
......@@ -66,5 +67,11 @@
#include "E1AP_Transport-UP-Layer-Addresses-Info-To-Remove-Item.h"
#include "E1AP_GTPTLAs.h"
#include "E1AP_GTPTLA-Item.h"
// E1 Bearer Context Modification Request
#include "E1AP_PDU-Session-Resource-To-Modify-Item.h"
#include "E1AP_DRB-To-Modify-List-NG-RAN.h"
#include "E1AP_DRB-To-Modify-Item-NG-RAN.h"
#include "E1AP_PDU-Session-Resource-To-Setup-Mod-Item.h"
#include "E1AP_DRB-To-Setup-Mod-Item-NG-RAN.h"
#endif /* E1AP_LIB_INCLUDES_H_ */
......@@ -70,6 +70,14 @@ static void e1ap_msg_free(E1AP_E1AP_PDU_t *pdu)
ASN_STRUCT_FREE(asn_DEF_E1AP_E1AP_PDU, pdu);
}
static UP_TL_information_t create_up_tl_info(void)
{
UP_TL_information_t tl_info;
tl_info.tlAddress = htonl(0xC0A90001); // 192.169.0.1
tl_info.teId = 0x2345;
return tl_info;
}
/**
* @brief Test E1AP Bearer Context Setup Request encoding/decoding
*/
......@@ -77,7 +85,7 @@ static void test_bearer_context_setup_request(void)
{
bearer_context_pdcp_config_t pdcp = {
.discardTimer = E1AP_DiscardTimer_ms10,
.pDCP_Reestablishment = E1AP_PDCP_Reestablishment_true,
.pDCP_Reestablishment = true,
.pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12,
.pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12,
.reorderingTimer = 10,
......@@ -107,14 +115,13 @@ static void test_bearer_context_setup_request(void)
// Step 1: Initialize the E1AP Bearer Context Setup Request
e1ap_bearer_setup_req_t orig = {
.gNB_cu_cp_ue_id = 1234,
.cipheringAlgorithm = 0x01,
.integrityProtectionAlgorithm = 0x01,
.secInfo.cipheringAlgorithm = 0x01,
.secInfo.integrityProtectionAlgorithm = 0x01,
.ueDlAggMaxBitRate = 1000000000,
.bearerContextStatus = 0,
.servingPLMNid.mcc = 001,
.servingPLMNid.mnc = 01,
.servingPLMNid.mnc_digit_length = 0x02,
.activityNotificationLevel = ANL_PDU_SESSION,
.numPDUSessions = 1,
.pduSession[0].sessionId = 1,
.pduSession[0].sessionType = E1AP_PDU_Session_Type_ipv4,
......@@ -122,8 +129,7 @@ static void test_bearer_context_setup_request(void)
.pduSession[0].nssai.sst = 0x01,
.pduSession[0].securityIndication = security,
.pduSession[0].numDRB2Setup = 1,
.pduSession[0].UP_TL_information.tlAddress = 167772161,
.pduSession[0].UP_TL_information.teId = 0x12345,
.pduSession[0].UP_TL_information = create_up_tl_info(),
.pduSession[0].DRBnGRanList[0].id = 1,
.pduSession[0].DRBnGRanList[0].sdap_config = sdap,
.pduSession[0].DRBnGRanList[0].pdcp_config = pdcp,
......@@ -133,8 +139,8 @@ static void test_bearer_context_setup_request(void)
.pduSession[0].DRBnGRanList[0].numQosFlow2Setup = 1,
.pduSession[0].DRBnGRanList[0].qosFlows[0] = qos,
};
memset(orig.encryptionKey, 0xAB, sizeof(orig.encryptionKey));
memset(orig.integrityProtectionKey, 0xCD, sizeof(orig.integrityProtectionKey));
memset(orig.secInfo.encryptionKey, 0xAB, sizeof(orig.secInfo.encryptionKey));
memset(orig.secInfo.integrityProtectionKey, 0xCD, sizeof(orig.secInfo.integrityProtectionKey));
// E1AP encode the original message
E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_request(&orig);
// E1AP decode the encoded message
......@@ -172,8 +178,7 @@ static void test_bearer_context_setup_response(void)
.gNB_cu_up_ue_id = 5678,
.numPDUSessions = 1,
.pduSession[0].id = 1,
.pduSession[0].tlAddress = 167772161,
.pduSession[0].teId = 0x12345,
.pduSession[0].tl_info = create_up_tl_info(),
.pduSession[0].numDRBSetup = 1,
.pduSession[0].numDRBFailed = 0,
.pduSession[0].DRBnGRanList[0].id = 1,
......@@ -181,8 +186,7 @@ static void test_bearer_context_setup_response(void)
.pduSession[0].DRBnGRanList[0].numQosFlowSetup = 1,
.pduSession[0].DRBnGRanList[0].qosFlows[0].qfi = 1,
.pduSession[0].DRBnGRanList[0].UpParamList[0].cell_group_id = MCG,
.pduSession[0].DRBnGRanList[0].UpParamList[0].teId = 0x34345,
.pduSession[0].DRBnGRanList[0].UpParamList[0].tlAddress = 167772161,
.pduSession[0].DRBnGRanList[0].UpParamList[0].tl_info = create_up_tl_info(),
};
// E1AP encode the original message
E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_response(&orig);
......@@ -335,6 +339,120 @@ static void test_e1_cuup_setup_failure(void)
free_e1ap_cuup_setup_failure(&orig);
}
/**
* @brief Test E1AP Bearer Context Modification Request encoding/decoding
*/
static void test_bearer_context_modification_request(void)
{
const bearer_context_sdap_config_t dummy_sdap_config = {
.defaultDRB = 0,
.sDAP_Header_DL = false,
.sDAP_Header_UL = false,
};
const bearer_context_pdcp_config_t dummy_pdcp_config = {
.discardTimer = E1AP_DiscardTimer_ms100,
.pDCP_Reestablishment = true,
.pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12,
.pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12,
.reorderingTimer = 5,
.rLC_Mode = E1AP_RLC_Mode_rlc_um_bidirectional,
};
const qos_flow_to_setup_t dummy_qos_flows = {
.qfi = 9,
.qos_params.alloc_reten_priority.preemption_capability = E1AP_Pre_emptionCapability_may_trigger_pre_emption,
.qos_params.alloc_reten_priority.preemption_vulnerability = E1AP_Pre_emptionVulnerability_pre_emptable,
.qos_params.alloc_reten_priority.priority_level = E1AP_PriorityLevel_no_priority,
.qos_params.qos_characteristics.non_dynamic.fiveqi = 9,
};
DRB_nGRAN_to_mod_t drb_to_mod = {
.numDlUpParam = 1,
.DlUpParamList[0].cell_group_id = MCG,
.DlUpParamList[0].tl_info = create_up_tl_info(),
.id = 1,
.pdcp_config = malloc_or_fail(sizeof(*drb_to_mod.pdcp_config)),
.pdcp_sn_status_requested = true,
.numQosFlow2Setup = 1,
.qosFlows[0] = dummy_qos_flows,
};
*drb_to_mod.pdcp_config = dummy_pdcp_config;
pdu_session_to_mod_t pdusession_mod_item = {
.sessionId = 1,
.numDRB2Modify = 1,
.DRBnGRanModList[0] = drb_to_mod,
};
DRB_nGRAN_to_setup_t drb_to_setup = {
.id = 1,
.cellGroupList[0] = MCG,
.numCellGroups = 1,
.pdcp_config = dummy_pdcp_config,
.sdap_config = dummy_sdap_config,
.numQosFlow2Setup = 1,
.qosFlows[0] = dummy_qos_flows,
.drb_inactivity_timer = malloc_or_fail(sizeof(*drb_to_setup.drb_inactivity_timer)),
};
*drb_to_setup.drb_inactivity_timer = 500;
pdu_session_to_setup_t pdusession_setup_item = {
.numDRB2Setup = 1,
.nssai.sd = 0x01,
.nssai.sst = 0x01,
.UP_TL_information.teId = 0x12345,
.UP_TL_information.tlAddress = 167772161,
.DRBnGRanList[0] = drb_to_setup,
};
// Initialize the Bearer Context Modification Request
e1ap_bearer_mod_req_t orig = {
.gNB_cu_cp_ue_id = 0x1234,
.gNB_cu_up_ue_id = 0x5678,
.bearerContextStatus = malloc_or_fail(sizeof(*orig.bearerContextStatus)),
.inactivityTimer = malloc_or_fail(sizeof(*orig.inactivityTimer)),
.numPDUSessions = 1,
.pduSession[0] = pdusession_setup_item,
.numPDUSessionsMod = 1,
.pduSessionMod[0] = pdusession_mod_item,
};
*orig.bearerContextStatus = BEARER_SUSPEND;
*orig.inactivityTimer = 1000;
// Encode the original message
E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_mod_request(&orig);
// Decode the encoded message
E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc);
// Free the encoded message
e1ap_msg_free(enc);
// Decode the message into a new struct
e1ap_bearer_mod_req_t decoded = {0};
AssertFatal(decode_E1_bearer_context_mod_request(dec, &decoded), "decode_E1_bearer_context_mod_request(): could not decode message\n");
// Free the decoded E1AP message
e1ap_msg_free(dec);
// Compare the original and decoded structs
AssertFatal(eq_bearer_context_mod_request(&orig, &decoded), "eq_bearer_context_mod_request(): decoded message doesn't match\n");
// Free the memory for the decoded message
free_e1ap_context_mod_request(&decoded);
// Deep copy the original message
e1ap_bearer_mod_req_t cp = cp_bearer_context_mod_request(&orig);
// Verify the deep copy matches the original
AssertFatal(eq_bearer_context_mod_request(&orig, &cp), "eq_bearer_context_mod_request(): copied message doesn't match\n");
// Free the copied and original message
free_e1ap_context_mod_request(&cp);
free_e1ap_context_mod_request(&orig);
}
int main()
{
// E1 Bearer Context Setup
......@@ -344,5 +462,7 @@ int main()
test_e1_cuup_setup_request();
test_e1_cuup_setup_response();
test_e1_cuup_setup_failure();
// E1 Bearer Context Modification Request
test_bearer_context_modification_request();
return 0;
}
......@@ -168,7 +168,6 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
const pdu_session_to_setup_t *req_pdu = req->pduSession + i;
resp_pdu->id = req_pdu->sessionId;
AssertFatal(req_pdu->numDRB2Modify == 0, "DRB modification not implemented\n");
AssertFatal(req_pdu->numDRB2Setup == 1, "can only handle one DRB per PDU session\n");
resp_pdu->numDRBSetup = req_pdu->numDRB2Setup;
const DRB_nGRAN_to_setup_t *req_drb = &req_pdu->DRBnGRanList[0];
......@@ -178,7 +177,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup;
for (int k = 0; k < resp_drb->numQosFlowSetup; k++) {
const qos_flow_to_setup_t *qosflow2Setup = &req_drb->qosFlows[k];
qos_flow_setup_t *qosflowSetup = &resp_drb->qosFlows[k];
qos_flow_list_t *qosflowSetup = &resp_drb->qosFlows[k];
qosflowSetup->qfi = qosflow2Setup->qfi;
}
......@@ -197,17 +196,17 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
&resp_n3);
AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n");
AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n");
resp_pdu->teId = resp_n3.gnb_NGu_teid[0];
memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4);
resp_pdu->tl_info.teId = resp_n3.gnb_NGu_teid[0];
memcpy(&resp_pdu->tl_info.tlAddress, &resp_n3.gnb_addr.buffer, 4);
// create PDCP bearers. This will also create SDAP bearers
NR_DRB_ToAddModList_t DRB_configList = {0};
fill_DRB_configList_e1(&DRB_configList, req_pdu);
nr_pdcp_entity_security_keys_and_algos_t security_parameters;
security_parameters.ciphering_algorithm = req->cipheringAlgorithm;
security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm;
memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE);
memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE);
security_parameters.ciphering_algorithm = req->secInfo.cipheringAlgorithm;
security_parameters.integrity_algorithm = req->secInfo.integrityProtectionAlgorithm;
memcpy(security_parameters.ciphering_key, req->secInfo.encryptionKey, NR_K_KEY_SIZE);
memcpy(security_parameters.integrity_key, req->secInfo.integrityProtectionKey, NR_K_KEY_SIZE);
nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE
cu_up_ue_id,
&DRB_configList,
......@@ -230,8 +229,8 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
&resp_f1);
resp_drb->numUpParam = 1;
AssertFatal(ret >= 0, "Unable to create GTP Tunnel for F1-U\n");
memcpy(&resp_drb->UpParamList[0].tlAddress, &resp_f1.gnb_addr.buffer, 4);
resp_drb->UpParamList[0].teId = resp_f1.gnb_NGu_teid[0];
memcpy(&resp_drb->UpParamList[0].tl_info.tlAddress, &resp_f1.gnb_addr.buffer, 4);
resp_drb->UpParamList[0].tl_info.teId = resp_f1.gnb_NGu_teid[0];
}
// We assume all DRBs to setup have been setup successfully, so we always
......@@ -273,12 +272,18 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
DRB_nGRAN_modified_t *modified = &modif.pduSessionMod[i].DRBnGRanModList[j];
modified->id = to_modif->id;
if (to_modif->pdcp_config.pDCP_Reestablishment) {
if (to_modif->pdcp_config && to_modif->pdcp_config->pDCP_Reestablishment) {
nr_pdcp_entity_security_keys_and_algos_t security_parameters;
security_parameters.ciphering_algorithm = req->cipheringAlgorithm;
security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm;
memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE);
memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE);
if (req->secInfo) {
security_parameters.ciphering_algorithm = req->secInfo->cipheringAlgorithm;
security_parameters.integrity_algorithm = req->secInfo->integrityProtectionAlgorithm;
memcpy(security_parameters.ciphering_key, req->secInfo->encryptionKey, NR_K_KEY_SIZE);
memcpy(security_parameters.integrity_key, req->secInfo->integrityProtectionKey, NR_K_KEY_SIZE);
} else {
/* don't change security settings if not present in the Bearer Context Modification Request */
security_parameters.ciphering_algorithm = -1;
security_parameters.integrity_algorithm = -1;
}
nr_pdcp_reestablishment(req->gNB_cu_up_ue_id,
to_modif->id,
false,
......@@ -291,8 +296,8 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
/* Loop through DL UP Transport Layer params list
* and update GTP tunnel outgoing addr and TEID */
for (int k = 0; k < to_modif->numDlUpParam; k++) {
in_addr_t addr = to_modif->DlUpParamList[k].tlAddress;
GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].teId);
in_addr_t addr = to_modif->DlUpParamList[k].tl_info.tlAddress;
GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].tl_info.teId);
}
}
}
......
......@@ -27,9 +27,10 @@
void nr_pdcp_e1_if_init(bool uses_e1);
struct e1ap_bearer_setup_req_s;
struct e1ap_bearer_mod_req_s;
struct e1ap_bearer_release_cmd_s;
void e1_bearer_context_setup(const struct e1ap_bearer_setup_req_s *req);
void e1_bearer_context_modif(const struct e1ap_bearer_setup_req_s *req);
void e1_bearer_context_modif(const struct e1ap_bearer_mod_req_s *req);
void e1_bearer_release_cmd(const struct e1ap_bearer_release_cmd_s *cmd);
void e1_reset(void);
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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
......
......@@ -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++;
......
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