diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c2baa4de3..27a7c471d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1216,6 +1216,10 @@ set(NR_PDCP_SRC ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c + openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c + openair2/LAYER2/nr_pdcp/cuup_cucp_if.c + openair2/LAYER2/nr_pdcp/cuup_cucp_direct.c + openair2/LAYER2/nr_pdcp/cuup_cucp_e1ap.c ) set(NR_SDAP_SRC @@ -1277,6 +1281,7 @@ set(L2_NR_SRC ${NR_RRC_DIR}/rrc_gNB_UE_context.c ${NR_RRC_DIR}/rrc_gNB_NGAP.c ${NR_RRC_DIR}/rrc_gNB_radio_bearers.c + ${NR_RRC_DIR}/rrc_gNB_cuup.c ) set(L2_SRC_UE @@ -1445,12 +1450,6 @@ add_library(e1_if target_link_libraries(e1_if PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap SECURITY ${OPENSSL_LIBRARIES} e1ap GTPV1U) -add_library(e1_pdcp_if - ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_e1_api.c - ) - -target_link_libraries(e1_pdcp_if PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) - target_link_libraries(L2_NR PRIVATE f1ap x2ap s1ap ngap nr_rrc e1ap nr_rlc) if(E2_AGENT) target_link_libraries(L2_NR PUBLIC e2_agent e2_ran_func) @@ -2106,7 +2105,7 @@ add_executable(nr-cuup target_link_libraries(nr-cuup PRIVATE CONFIG_LIB ITTI SCTP_CLIENT - GTPV1U e1ap e1_pdcp_if f1ap SIMU_ETH + GTPV1U e1ap f1ap SIMU_ETH z sctp dl pthread shlib_loader ${T_LIB}) target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) diff --git a/ci-scripts/conf_files/gnb-cucp.sa.f1.conf b/ci-scripts/conf_files/gnb-cucp.sa.f1.conf index 5eb123dba1..469ab8d187 100644 --- a/ci-scripts/conf_files/gnb-cucp.sa.f1.conf +++ b/ci-scripts/conf_files/gnb-cucp.sa.f1.conf @@ -8,7 +8,7 @@ gNBs = ( { ////////// Identification parameters: - gNB_CU_ID = 0xe00; + gNB_ID = 0xe00; # cell_type = "CELL_MACRO_GNB"; diff --git a/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf b/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf index 9d0c13cd74..8b9e865e0d 100644 --- a/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf +++ b/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf @@ -8,7 +8,7 @@ gNBs = ( { ////////// Identification parameters: - gNB_CU_ID = 0xe00; + gNB_ID = 0xe00; # cell_type = "CELL_MACRO_GNB"; diff --git a/ci-scripts/conf_files/gnb-cuup.sa.f1.conf b/ci-scripts/conf_files/gnb-cuup.sa.f1.conf index 6759654e0d..357518bcf2 100644 --- a/ci-scripts/conf_files/gnb-cuup.sa.f1.conf +++ b/ci-scripts/conf_files/gnb-cuup.sa.f1.conf @@ -7,7 +7,7 @@ gNBs = ( { ////////// Identification parameters: - gNB_CU_ID = 0xe00; + gNB_ID = 0xe00; # cell_type = "CELL_MACRO_GNB"; @@ -56,32 +56,9 @@ gNBs = } ); -security = { - # preferred ciphering algorithms - # the first one of the list that an UE supports in chosen - # valid values: nea0, nea1, nea2, nea3 - ciphering_algorithms = ( "nea0" ); - - # preferred integrity algorithms - # the first one of the list that an UE supports in chosen - # valid values: nia0, nia1, nia2, nia3 - integrity_algorithms = ( "nia2", "nia0" ); - - # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter - # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' - drb_ciphering = "yes"; - drb_integrity = "no"; +log_config : { + global_log_level = "info"; + pdcp_log_level = "info"; + f1ap_log_level = "info"; + ngap_log_level = "info"; }; - log_config : - { - global_log_level ="info"; - hw_log_level ="info"; - phy_log_level ="info"; - mac_log_level ="info"; - rlc_log_level ="debug"; - pdcp_log_level ="info"; - rrc_log_level ="info"; - f1ap_log_level ="info"; - ngap_log_level ="debug"; - }; - diff --git a/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf b/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf index 535ef68bd0..4e65547db9 100644 --- a/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf +++ b/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf @@ -7,7 +7,7 @@ gNBs = ( { ////////// Identification parameters: - gNB_CU_ID = 0xe00; + gNB_ID = 0xe00; # cell_type = "CELL_MACRO_GNB"; @@ -56,23 +56,6 @@ gNBs = } ); -security = { - # preferred ciphering algorithms - # the first one of the list that an UE supports in chosen - # valid values: nea0, nea1, nea2, nea3 - ciphering_algorithms = ( "nea0" ); - - # preferred integrity algorithms - # the first one of the list that an UE supports in chosen - # valid values: nia0, nia1, nia2, nia3 - integrity_algorithms = ( "nia2", "nia0" ); - - # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter - # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' - drb_ciphering = "yes"; - drb_integrity = "no"; -}; - log_config: { global_log_level = "info"; }; diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf index a1e66c7ade..eb664f1ccb 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf @@ -6,7 +6,7 @@ gNBs = ( { ////////// Identification parameters: - gNB_CU_ID = 0xe00; + gNB_ID = 0xe00; gNB_name = "gNB-OAI"; diff --git a/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf b/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf index 4f615b8dba..dcdb8307dc 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf @@ -10,7 +10,7 @@ gNBs = ( { ////////// Identification parameters: - gNB_CU_ID = 0xe00; + gNB_ID = 0xe00; gNB_name = "gNB-Eurecom-n78_20"; diff --git a/doc/E1-design.md b/doc/E1-design.md index 6f9e8f4edd..983013dce7 100644 --- a/doc/E1-design.md +++ b/doc/E1-design.md @@ -2,38 +2,55 @@ # 1. Introduction -E1 is named for the interface that lies between the nodes CU Control Plane (CUCP) and CU User Plane (CUUP). Once the nodes are configured, all user plane traffic flows through CUUP. +E1 is the interface that lies between the nodes CU Control Plane (CUCP) and CU User Plane (CUUP). Once the nodes are configured, all user plane traffic flows through CUUP. -The E1 design in OAI follows the 3GPP specification in TS 38.460. The code design on E1 in OAI is very similar to -F1. The ITTI message passing mechanism is used to exchange messages between E1AP thread, SCTP thread and RRC thread. - -The following sequence chart shows the current E1AP message flow. +The E1 design in OAI follows the 3GPP specification in TS 38.460/463. The code +design on E1 in OAI is very similar to F1: OAI uses E1 internally to set up +bearers, even in monolithic gNB, where the actual "way" the messages are passed +is abstracted through function pointers. More specifically, there are handlers +that handle the E1 messages as shown below, *which are the same* no matter if +the CU is integrated or separate in CU-CP/UP. The below sequence diagram lists +the handlers that are executed and the current E1AP message flow (SCTP +connection setup only in split-mode, the rest is the same for CU): ```mermaid sequenceDiagram participant c as CUCP participant u as CUUP - u->>c: SCTP new association - c->>u: SCTP new association response - Note over u: Create UDP sockets for F1-U and N3 + u->c: SCTP connection setup (in split mode) u->>c: E1AP Setup Request + Note over c: Execute rrc_gNB_process_e1_setup_req() c->>u: E1AP Setup Response + Note over c: Receives PDU session setup request from AMF c->>u: Bearer Context Setup Request - Note over u: Configure DRBs and create GTP Tunnels for F1-U and N3 + Note over u: Execute e1_bearer_context_setup()
Configure DRBs and create GTP Tunnels for F1-U and N3 u->>c: Bearer Context Setup Response - Note over c: Sends F1-U UL TNL info to DU and receives DL TNL info + Note over c: Execute rrc_gNB_process_e1_setup_req()
Sends F1-U UL TNL info to DU and receives DL TNL info + c->>u: Bearer Context Modification Request - Note over u: Updates GTP Tunnels with received info + Note over u: Execute e1_bearer_context_modif()
Updates GTP Tunnels with received info + u->>c: Bearer Context Modification Response + Note over c: Execute rrc_gNB_process_e1_bearer_context_modif_resp() + + Note over c: UE release triggered + c->>u: Bearer Context Release Request + Note over u: Execute e1_bearer_release_cmd()
Frees GTP tunnels, PDCP data etc + u->>c: Bearer Context Release Complete + Note over c: Execute rrc_gNB_process_e1_bearer_context_release_cplt() ``` -_Note that the E1 bearer release procedures are currently not implemented._ +The files that implement the callback towards these handlers are in +- `cucp_cuup_direct.c`: integrated CU (for CP=>UP messages) +- `cucp_cuup_e1ap.c`: E1 split mode (for CP=>UP messages) +- `cuup_cucp_direct.c`: integrated CU (for UP=>CP messages) +- `cuup_cucp_e1ap.c`: E1 split mode (for UP=>CP messages) # 2. Running the E1 Split ## 2.1 Configuration File -The gNB is started based on the node type that is specified in the configuration file. To start a gNB instance in CUCP or CUUP, the `tr_s_preference` should be set to "f1" and the config member `E1_INTERFACE` should be present in the config file. The `type` parameter within the `E1_INTERFACE` should be set to `cp`, and `nr-softmodem` should be used to run a CU-CP. The type should be `up` and `nr-cuup` should be used to run the CU-UP. Further, there are the parameters `ipv4_cucp` and `ipv4_cuup` to specify the IP addresses of the respective network functions. +The gNB is started based on the node type that is specified in the configuration file. To start a gNB instance in CUCP or CUUP, the `tr_s_preference` should be set to "f1" and the config member `E1_INTERFACE` should be present in the config file. The `type` parameter within the `E1_INTERFACE` should be set to `cp`, and executable `nr-softmodem` should be used to run a CU-CP. The type should be `up` and executable `nr-cuup` should be used to run the CU-UP. Further, there are the parameters `ipv4_cucp` and `ipv4_cuup` to specify the IP addresses of the respective network functions. For CUCP, a typical `E1_INTERFACE` config looks like ``` @@ -62,7 +79,7 @@ One could take an existing CU configuration file and add the above parameters to The CUUP uses the IP address specified in `local_s_address` for F1-U and `GNB_IPV4_ADDRESS_FOR_NGU` for N3 links. Note that `local_s_address` is under `gNBs` and `GNB_IPV4_ADDRESS_FOR_NGU` is part of the `NETWORK_INTERFACES` config member. -Alternatively, you can use the config files `ci-scripts/conf_files/gnb-cucp.sa.conf` and `ci-scripts/conf_files/gnb-cuup.sa.conf` which are already in the repository. +Alternatively, you can use the config files `ci-scripts/conf_files/gnb-cucp.sa.f1.conf` and `ci-scripts/conf_files/gnb-cuup.sa.f1.conf`. ## 2.2 Steps to Run the Split in rfsimulator with OAI UE @@ -73,7 +90,7 @@ Note: A 5G core must be running at this point. Steps to start the OAI 5G core ca 1. Start the CUCP first by running the following command ``` -sudo ./nr-softmodem -O ../../../ci-scripts/conf_files/gnb-cucp.sa.conf --gNBs.[0].min_rxtxtime 6 --sa +sudo ./nr-softmodem -O ../../../ci-scripts/conf_files/gnb-cucp.sa.f1.conf --gNBs.[0].min_rxtxtime 6 --sa ``` Note that `min_rxtxtime` should be set to `6` only when you are connecting an OAI UE to the gNB. @@ -82,7 +99,7 @@ Note that `min_rxtxtime` should be set to `6` only when you are connecting an OA CUUP (has its own executable): ``` -sudo ./nr-cuup -O ../../../ci-scripts/conf_files/gnb-cuup.sa.conf --sa +sudo ./nr-cuup -O ../../../ci-scripts/conf_files/gnb-cuup.sa.f1.conf --sa ``` DU: @@ -106,3 +123,25 @@ You can also run the nodes on different machines. If you do so please change the ![E1/F1/NG parameters](images/e1-archi.png){width=1200} [PDF version](images/e1-archi.pdf) | [LaTeX/TikZ version](img/e1-archi.tex) if you want to modify to reflect your setup + +# 4. Multiple CU-UP + +It is possible to connect multiple CU-UP to the same CU-CP. In the handler of +the E1 Setup Request, the CU-CP verifies that the PLMN(s) (MCC, MNC) between +both nodes match, and that no CU-UP with the same ID exists. Note that the +NSSAIs for the CU-UPs can be different. + +During attach, the following rules are used to select a CU-UP at the CU-CP, in +order: +- Select a CU-UP based on slice identifiers: + - If both the SST and SD match exactly, that CU-UP is selected. (If multiple + have the same NSSAI, the first is always selected.) + - Otherwise, the first CU-UP with the same SST but different SD is selected. +- Round-robin across all CU-UPs. +- The first CU-UP. +- If no CU-UP is selected, the CU-CP asserts. + +Note that CU-UPs are not released from CU-CP internal structures. That means +that you have to restart the CU-CP if you want to connect the CU-UP again +(e.g., after a crash). The CU-CP might also misfunction during attach if a +CU-UP was connected, but disconnected in the meantime. diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 2992953ef0..d83137c328 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -95,12 +95,6 @@ void nr_rlc_add_drb(int rnti, int drb_id, const NR_RLC_BearerConfig_t *rlc_Beare abort(); } -int nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(const protocol_ctxt_t *const ctxt_pP, const gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp_p, int offset) -{ - abort(); - return 0; -} - void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_context_p, e1ap_bearer_setup_resp_t *e1ap_resp) { abort(); @@ -108,14 +102,14 @@ void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_contex f1ap_cudu_inst_t *getCxt(instance_t instanceP) { - abort(); - return NULL; -} - -NR_DRB_ToAddModList_t *fill_DRB_configList(gNB_RRC_UE_t *ue) -{ - abort(); - return NULL; + // the E1 module uses F1's getCxt() to decide whether there is F1-U and if + // so, what is the GTP instance. In the CU-UP, we don't start the F1 module, + // and instead, E1 handles the GTP-U endpoint. In the following, we fake the + // instance and put the right GTP-U instance number in. + const e1ap_upcp_inst_t *e1inst = getCxtE1(instanceP); + static f1ap_cudu_inst_t fake = {0}; + fake.gtpInst = e1inst->gtpInstF1U; + return &fake; } int main(int argc, char **argv) @@ -134,7 +128,7 @@ int main(int argc, char **argv) AssertFatal(rc >= 0, "Create task for GTPV1U failed\n"); rc = itti_create_task(TASK_CUUP_E1, E1AP_CUUP_task, NULL); AssertFatal(rc >= 0, "Create task for CUUP E1 failed\n"); - nr_pdcp_layer_init(); + nr_pdcp_layer_init(true); cu_init_f1_ue_data(); // for CU-UP/CP mapping: we use the same MessageDef *msg = RCconfig_NR_CU_E1(true); AssertFatal(msg != NULL, "Send init to task for E1AP UP failed\n"); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 553f21a9fb..75a9e0dc24 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -80,7 +80,6 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "nfapi/oai_integration/vendor_ext.h" #include "gnb_config.h" #include "openair2/E1AP/e1ap_common.h" -#include "openair2/E1AP/e1ap_api.h" #ifdef E2_AGENT #include "openair2/E2AP/flexric/src/agent/e2_agent_api.h" @@ -403,12 +402,16 @@ static int create_gNB_tasks(ngran_node_t node_type) if (node_type == ngran_gNB_CU || node_type == ngran_gNB) { MessageDef *msg = RCconfig_NR_CU_E1(false); instance_t inst = 0; - createE1inst(UPtype, inst, &E1AP_SETUP_REQ(msg)); + createE1inst(UPtype, inst, &E1AP_REGISTER_REQ(msg).net_config, NULL); cuup_init_n3(inst); - itti_free(TASK_UNKNOWN, msg); - getCxtE1(inst)->same_process = true; - ; RC.nrrrc[gnb_id_start]->e1_inst = inst; // stupid instance !!!*/ + + /* send E1 Setup Request to RRC */ + MessageDef *new_msg = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_SETUP_REQ); + E1AP_SETUP_REQ(new_msg) = E1AP_REGISTER_REQ(msg).setup_req; + new_msg->ittiMsgHeader.originInstance = -1; /* meaning, it is local */ + itti_send_msg_to_task(TASK_RRC_GNB, 0 /*unused by callee*/, new_msg); + itti_free(TASK_UNKNOWN, msg); } //Use check on x2ap to consider the NSA scenario @@ -562,7 +565,7 @@ void init_pdcp(void) { LINK_ENB_PDCP_TO_GTPV1U_BIT; if (!NODE_IS_DU(get_node_type())) { - nr_pdcp_layer_init(); + nr_pdcp_layer_init(get_node_type() == ngran_gNB_CUCP); nr_pdcp_module_init(pdcp_initmask, 0); } } diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index e5332e8e5e..a267211ce5 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -380,7 +380,7 @@ static void init_pdcp(int ue_id) { if (get_softmodem_params()->nsa && rlc_module_init(0) != 0) { LOG_I(RLC, "Problem at RLC initiation \n"); } - nr_pdcp_layer_init(); + nr_pdcp_layer_init(false); nr_pdcp_module_init(pdcp_initmask, ue_id); pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t) rlc_data_req); pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) pdcp_data_ind); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 6d80ac619c..21a237785d 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -108,6 +108,10 @@ void nr_rrc_ue_generate_RRCSetupRequest(module_id_t module_id, const uint8_t gNB return; } +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_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) { return 0; } diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 77a1d6d821..668c1cb633 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -104,6 +104,10 @@ void nr_rrc_ue_generate_RRCSetupRequest(module_id_t module_id, const uint8_t gNB return; } +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_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) { return 0; } diff --git a/openair2/COMMON/e1ap_messages_def.h b/openair2/COMMON/e1ap_messages_def.h index 70533f8add..ea24ac9e18 100644 --- a/openair2/COMMON/e1ap_messages_def.h +++ b/openair2/COMMON/e1ap_messages_def.h @@ -20,6 +20,9 @@ */ /* gNB_CUUP application layer -> E1AP messages */ +MESSAGE_DEF(E1AP_REGISTER_REQ, MESSAGE_PRIORITY_MED, e1ap_register_req_t, e1ap_register_req) + +/* E1AP messages -> RRC (CU-CP) */ MESSAGE_DEF(E1AP_SETUP_REQ , MESSAGE_PRIORITY_MED , e1ap_setup_req_t , e1ap_setup_req) /* E1AP -> eNB_DU or eNB_CU_RRC -> E1AP application layer messages */ @@ -30,4 +33,7 @@ MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_REQ , MESSAGE_PRIORITY_MED , e1ap_bearer_s MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_RESP , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_resp_t , e1ap_bearer_setup_resp) MESSAGE_DEF(E1AP_BEARER_CONTEXT_MODIFICATION_REQ , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_req_t , e1ap_bearer_mod_req) +MESSAGE_DEF(E1AP_BEARER_CONTEXT_MODIFICATION_RESP, MESSAGE_PRIORITY_MED, e1ap_bearer_modif_resp_t, e1ap_bearer_modif_resp) +MESSAGE_DEF(E1AP_BEARER_CONTEXT_RELEASE_CMD, MESSAGE_PRIORITY_MED, e1ap_bearer_release_cmd_t, e1ap_bearer_release_cmd) +MESSAGE_DEF(E1AP_BEARER_CONTEXT_RELEASE_CPLT, MESSAGE_PRIORITY_MED, e1ap_bearer_release_cplt_t, e1ap_bearer_release_cplt) diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index fba56ccb14..f98058b85c 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -32,6 +32,7 @@ #define E1AP_MAX_NUM_TRANSAC_IDS 4 #define E1AP_MAX_NUM_PLMNS 4 +#define E1AP_MAX_NUM_SLICES 1024 #define E1AP_MAX_NUM_CELL_GROUPS 4 #define E1AP_MAX_NUM_QOS_FLOWS 4 #define E1AP_MAX_NUM_NGRAN_DRB 4 @@ -40,11 +41,15 @@ #define E1AP_MAX_NUM_DRBS 4 #define E1AP_MAX_NUM_UP_PARAM 4 +#define E1AP_REGISTER_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_register_req #define E1AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_req #define E1AP_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_resp #define E1AP_BEARER_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_req #define E1AP_BEARER_CONTEXT_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_resp #define E1AP_BEARER_CONTEXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_req +#define E1AP_BEARER_CONTEXT_MODIFICATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_modif_resp +#define E1AP_BEARER_CONTEXT_RELEASE_CMD(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_release_cmd +#define E1AP_BEARER_CONTEXT_RELEASE_CPLT(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_release_cplt typedef f1ap_net_ip_address_t e1ap_net_ip_address_t; @@ -54,27 +59,39 @@ typedef struct PLMN_ID_s { int mnc_digit_length; } PLMN_ID_t; -typedef struct e1ap_setup_req_s { - uint64_t gNB_cu_up_id; - char * gNB_cu_up_name; - sctp_assoc_t assoc_id; - uint64_t transac_id; - int supported_plmns; - PLMN_ID_t plmns[E1AP_MAX_NUM_PLMNS]; - uint16_t sctp_in_streams; - uint16_t sctp_out_streams; - uint16_t default_sctp_stream_id; +typedef struct e1ap_nssai_t { + uint8_t sst; + uint32_t sd; // optional: "No SD" is 0xffffff, see 23.003 Sec 28.4.2 +} e1ap_nssai_t; + +typedef struct e1ap_net_config_t { net_ip_address_t CUUP_e1_ip_address; net_ip_address_t CUCP_e1_ip_address; - long cn_support; uint16_t remotePortF1U; char* localAddressF1U; uint16_t localPortF1U; char* localAddressN3; uint16_t localPortN3; uint16_t remotePortN3; +} e1ap_net_config_t; + +typedef struct e1ap_setup_req_s { + uint64_t gNB_cu_up_id; + char * gNB_cu_up_name; + uint64_t transac_id; + int supported_plmns; + struct { + PLMN_ID_t id; + int supported_slices; + e1ap_nssai_t *slice; + } plmn[E1AP_MAX_NUM_PLMNS]; } e1ap_setup_req_t; +typedef struct e1ap_register_req_t { + e1ap_setup_req_t setup_req; + e1ap_net_config_t net_config; +} e1ap_register_req_t; + typedef struct e1ap_setup_resp_s { long transac_id; } e1ap_setup_resp_t; @@ -140,7 +157,7 @@ typedef struct DRB_nGRAN_to_setup_s { typedef struct pdu_session_to_setup_s { long sessionId; long sessionType; - int8_t sst; + e1ap_nssai_t nssai; long integrityProtectionIndication; long confidentialityProtectionIndication; in_addr_t tlAddress; @@ -165,8 +182,6 @@ typedef struct e1ap_bearer_setup_req_s { long ueDlAggMaxBitRate; PLMN_ID_t servingPLMNid; long activityNotificationLevel; - int numDRBs; - drb_to_setup_t DRBList[E1AP_MAX_NUM_DRBS]; int numPDUSessions; pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; int numPDUSessionsMod; @@ -180,13 +195,10 @@ typedef struct e1ap_bearer_release_cmd_s { long cause; } e1ap_bearer_release_cmd_t; -typedef struct drb_setup_s { - int drbId; - in_addr_t tlAddress; - int teId; - int numUpParam; - up_params_t UpParamList[E1AP_MAX_NUM_UP_PARAM]; -} drb_setup_t; +typedef struct e1ap_bearer_release_cplt_s { + uint32_t gNB_cu_cp_ue_id; + uint32_t gNB_cu_up_ue_id; +} e1ap_bearer_release_cplt_t; typedef struct qos_flow_setup_s { long id; @@ -200,6 +212,10 @@ typedef struct DRB_nGRAN_setup_s { qos_flow_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; } DRB_nGRAN_setup_t; +typedef struct DRB_nGRAN_modified_s { + long id; +} DRB_nGRAN_modified_t; + typedef struct DRB_nGRAN_failed_s { long id; long cause_type; @@ -216,13 +232,25 @@ typedef struct pdu_session_setup_s { DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_NGRAN_DRB]; } pdu_session_setup_t; +typedef struct pdu_session_modif_s { + long id; + // setup as part of PDU session modification not supported yet + int numDRBModified; + DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_NGRAN_DRB]; +} pdu_session_modif_t; + typedef struct e1ap_bearer_setup_resp_s { uint32_t gNB_cu_cp_ue_id; uint32_t gNB_cu_up_ue_id; - int numDRBs; - drb_setup_t DRBList[E1AP_MAX_NUM_DRBS]; int numPDUSessions; pdu_session_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; } e1ap_bearer_setup_resp_t; +typedef struct e1ap_bearer_modif_resp_s { + uint32_t gNB_cu_cp_ue_id; + uint32_t gNB_cu_up_ue_id; + int numPDUSessionsMod; + pdu_session_modif_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS]; +} e1ap_bearer_modif_resp_t; + #endif /* E1AP_MESSAGES_TYPES_H */ diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 465c6c5342..037dfbe86c 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -403,13 +403,13 @@ typedef struct NbIoTRrcConfigurationReq_s { // gNB: GNB_APP -> RRC messages typedef struct NRRrcConfigurationReq_s { - uint64_t cell_identity; uint32_t tac; uint16_t mcc[PLMN_LIST_MAX_SIZE]; uint16_t mnc[PLMN_LIST_MAX_SIZE]; uint8_t mnc_digit_length[PLMN_LIST_MAX_SIZE]; uint8_t num_plmn; + bool um_on_default_drb; bool enable_sdap; int drbs; } gNB_RrcConfigurationReq; diff --git a/openair2/E1AP/CMakeLists.txt b/openair2/E1AP/CMakeLists.txt index 01a969de7e..c7657eed5a 100644 --- a/openair2/E1AP/CMakeLists.txt +++ b/openair2/E1AP/CMakeLists.txt @@ -1,7 +1,7 @@ add_subdirectory(MESSAGES) -add_library(e1ap e1ap.c e1ap_common.c e1ap_api.c) +add_library(e1ap e1ap.c e1ap_common.c) target_link_libraries(e1ap PUBLIC asn1_e1ap f1ap - PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap UTIL e1_pdcp_if e1_if) + PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap UTIL e1_if) target_include_directories(e1ap PUBLIC ${CMAKE_CURRENT_DIR}) diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 2390b23d2e..077c67ca98 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -23,7 +23,6 @@ #include "e1ap.h" #include "e1ap_common.h" -#include "e1ap_api.h" #include "gnb_config.h" #include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" #include "openair3/UTILS/conversions.h" @@ -33,9 +32,10 @@ #include "openair2/F1AP/f1ap_common.h" #include "e1ap_default_values.h" #include "gtp_itf.h" +#include "openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h" #define E1AP_NUM_MSG_HANDLERS 14 -typedef int (*e1ap_message_processing_t)(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *message_p); +typedef int (*e1ap_message_processing_t)(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *message_p); const e1ap_message_processing_t e1ap_message_processing[E1AP_NUM_MSG_HANDLERS][3] = { {0, 0, 0}, /* Reset */ @@ -49,7 +49,9 @@ const e1ap_message_processing_t e1ap_message_processing[E1AP_NUM_MSG_HANDLERS][3 {e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST, e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE, e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE}, /* bearerContextSetup */ - {e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST, 0, 0}, /* bearerContextModification */ + {e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST, + e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE, + 0}, /* bearerContextModification */ {0, 0, 0}, /* bearerContextModificationRequired */ {e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND, e1apCUCP_handle_BEARER_CONTEXT_RELEASE_COMPLETE, 0}, /* bearerContextRelease */ {0, 0, 0}, /* bearerContextReleaseRequired */ @@ -91,8 +93,8 @@ int e1ap_handle_message(instance_t instance, sctp_assoc_t assoc_id, const uint8_ ret=-1; } else { /* Calling the right handler */ - LOG_I(E1AP, "Calling handler with instance %ld\n",instance); - ret = (*e1ap_message_processing[procedureCode][pdu.present - 1])(getCxtE1(instance), &pdu); + LOG_D(E1AP, "Calling handler with instance %ld\n",instance); + ret = (*e1ap_message_processing[procedureCode][pdu.present - 1])(assoc_id, getCxtE1(instance), &pdu); } ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_E1AP_E1AP_PDU, &pdu); @@ -109,18 +111,11 @@ void e1_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_dat AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } -void e1ap_itti_send_sctp_close_association(bool isCu, instance_t instance) { - MessageDef *message = itti_alloc_new_message(TASK_S1AP, 0, SCTP_CLOSE_ASSOCIATION); - sctp_close_association_t *sctp_close_association = &message->ittiMsg.sctp_close_association; - sctp_close_association->assoc_id = e1ap_assoc_id(isCu,instance); - itti_send_msg_to_task(TASK_SCTP, instance, message); -} - -int e1ap_send_RESET(bool isCu, e1ap_setup_req_t *setupReq, E1AP_Reset_t *Reset) +int e1ap_send_RESET(bool isCu, sctp_assoc_t assoc_id, E1AP_Reset_t *Reset) { AssertFatal(false,"Not implemented yet\n"); E1AP_E1AP_PDU_t pdu= {0}; - return e1ap_encode_send(isCu, setupReq, &pdu, 0, __func__); + return e1ap_encode_send(isCu, assoc_id, &pdu, 0, __func__); } int e1ap_send_RESET_ACKNOWLEDGE(instance_t instance, E1AP_Reset_t *Reset) { @@ -177,7 +172,7 @@ static void fill_SETUP_REQUEST(e1ap_setup_req_t *setup, E1AP_E1AP_PDU_t *pdu) ieC1->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_TransactionID; setup->transac_id = E1AP_get_next_transaction_identifier(); ieC1->value.choice.TransactionID = setup->transac_id; - LOG_I(E1AP, "Transaction ID of setup request %ld\n", setup->transac_id); + LOG_D(E1AP, "Transaction ID of setup request %ld\n", setup->transac_id); /* mandatory */ /* c2. GNB_CU_ID (integer value) */ asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC2); @@ -185,13 +180,23 @@ static void fill_SETUP_REQUEST(e1ap_setup_req_t *setup, E1AP_E1AP_PDU_t *pdu) ieC2->criticality = E1AP_Criticality_reject; ieC2->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_GNB_CU_UP_ID; asn_int642INTEGER(&ieC2->value.choice.GNB_CU_UP_ID, setup->gNB_cu_up_id); + + /* optional */ + if (setup->gNB_cu_up_name) { + asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC3); + ieC3->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name; + ieC3->criticality = E1AP_Criticality_ignore; + ieC3->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_GNB_CU_UP_Name; + OCTET_STRING_fromBuf(&ieC3->value.choice.GNB_CU_UP_Name, setup->gNB_cu_up_name, strlen(setup->gNB_cu_up_name)); + } + /* mandatory */ /* c4. CN Support */ asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC4); ieC4->id = E1AP_ProtocolIE_ID_id_CNSupport; ieC4->criticality = E1AP_Criticality_reject; ieC4->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_CNSupport; - ieC4->value.choice.CNSupport = setup->cn_support; + ieC4->value.choice.CNSupport = E1AP_CNSupport_c_5gc; /* only 5GC supported */ /* mandatory */ /* c5. Supported PLMNs */ @@ -205,7 +210,24 @@ static void fill_SETUP_REQUEST(e1ap_setup_req_t *setup, E1AP_E1AP_PDU_t *pdu) for (int i=0; i < numSupportedPLMNs; i++) { asn1cSequenceAdd(ieC5->value.choice.SupportedPLMNs_List.list, E1AP_SupportedPLMNs_Item_t, supportedPLMN); /* 5.1 PLMN Identity */ - MCC_MNC_TO_PLMNID(setup->plmns[i].mcc, setup->plmns[i].mnc, setup->plmns[i].mnc_digit_length, &supportedPLMN->pLMN_Identity); + PLMN_ID_t *id = &setup->plmn[i].id; + MCC_MNC_TO_PLMNID(id->mcc, id->mnc, id->mnc_digit_length, &supportedPLMN->pLMN_Identity); + + int n = setup->plmn[i].supported_slices; + if (setup->plmn[i].slice != NULL && n > 0) { + supportedPLMN->slice_Support_List = calloc(1, sizeof(*supportedPLMN->slice_Support_List)); + AssertFatal(supportedPLMN->slice_Support_List != NULL, "out of memory\n"); + for (int s = 0; s < n; ++s) { + asn1cSequenceAdd(supportedPLMN->slice_Support_List->list, E1AP_Slice_Support_Item_t, slice); + e1ap_nssai_t *nssai = &setup->plmn[i].slice[s]; + INT8_TO_OCTET_STRING(nssai->sst, &slice->sNSSAI.sST); + if (nssai->sd != 0xffffff) { + slice->sNSSAI.sD = malloc(sizeof(*slice->sNSSAI.sD)); + AssertFatal(slice->sNSSAI.sD != NULL, "out of memory\n"); + INT24_TO_OCTET_STRING(nssai->sd, slice->sNSSAI.sD); + } + } + } } } @@ -228,13 +250,11 @@ static void fill_SETUP_RESPONSE(const e1ap_setup_resp_t *e1ap_setup_resp, E1AP_E ieC1->value.choice.TransactionID = e1ap_setup_resp->transac_id; } -void e1ap_send_SETUP_RESPONSE(instance_t inst, const e1ap_setup_resp_t *e1ap_setup_resp) +void e1ap_send_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_setup_resp_t *e1ap_setup_resp) { - AssertFatal(getCxtE1(inst), ""); - e1ap_setup_req_t *setupReq = &getCxtE1(inst)->setupReq; E1AP_E1AP_PDU_t pdu = {0}; fill_SETUP_RESPONSE(e1ap_setup_resp, &pdu); - e1ap_encode_send(getCxtE1(inst)->type, setupReq, &pdu, 0, __func__); + e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); } static void fill_SETUP_FAILURE(long transac_id, E1AP_E1AP_PDU_t *pdu) @@ -264,19 +284,17 @@ static void fill_SETUP_FAILURE(long transac_id, E1AP_E1AP_PDU_t *pdu) ieC2->value.choice.Cause.choice.radioNetwork = E1AP_CauseRadioNetwork_unspecified; } -void e1apCUCP_send_SETUP_FAILURE(e1ap_setup_req_t *setupReq, long transac_id) +void e1apCUCP_send_SETUP_FAILURE(sctp_assoc_t assoc_id, long transac_id) { E1AP_E1AP_PDU_t pdu = {0}; fill_SETUP_FAILURE(transac_id, &pdu); - e1ap_encode_send(CPtype, setupReq, &pdu, 0, __func__); + e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); } void extract_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_req_t *req) { E1AP_GNB_CU_UP_E1SetupRequestIEs_t *ie; E1AP_GNB_CU_UP_E1SetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.GNB_CU_UP_E1SetupRequest; - /* assoc_id */ - /* req->assoc_id = assoc_id; */ /* transac_id */ F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, @@ -290,11 +308,21 @@ void extract_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, asn_INTEGER2ulong(&ie->value.choice.GNB_CU_UP_ID, &req->gNB_cu_up_id); LOG_D(E1AP, "gNB CU UP ID: %ld\n", req->gNB_cu_up_id); + /* gNB CU UP name */ + F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, + E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name, false); + req->gNB_cu_up_name = NULL; + if (ie != NULL) { + req->gNB_cu_up_name = calloc(ie->value.choice.GNB_CU_UP_Name.size + 1, sizeof(char)); + AssertFatal(req->gNB_cu_up_name != NULL, "out of memory\n"); + memcpy(req->gNB_cu_up_name, ie->value.choice.GNB_CU_UP_Name.buf, ie->value.choice.GNB_CU_UP_Name.size); + LOG_D(E1AP, "req->gNB_cu_up_name %s\n", req->gNB_cu_up_name); + } + /* CN Support */ F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_CNSupport, true); - req->cn_support = ie->value.choice.CNSupport; - LOG_D(E1AP, "E1ap CN support: %ld\n", req->cn_support); + AssertFatal(ie->value.choice.CNSupport == E1AP_CNSupport_c_5gc, "only 5GC CN Support supported\n"); /* Supported PLMNs */ F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, @@ -306,26 +334,41 @@ void extract_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, E1AP_SupportedPLMNs_Item_t *supported_plmn_item = (E1AP_SupportedPLMNs_Item_t *)(ie->value.choice.SupportedPLMNs_List.list.array[i]); /* PLMN Identity */ - PLMNID_TO_MCC_MNC(&supported_plmn_item->pLMN_Identity, - req->plmns[i].mcc, - req->plmns[i].mnc, - req->plmns[i].mnc_digit_length); - LOG_D(E1AP, "MCC: %d\nMNC: %d\n", req->plmns[i].mcc, req->plmns[i].mnc); + PLMN_ID_t *id = &req->plmn[i].id; + PLMNID_TO_MCC_MNC(&supported_plmn_item->pLMN_Identity, id->mcc, id->mnc, id->mnc_digit_length); + LOG_D(E1AP, "MCC %d MNC %d\n", id->mcc, id->mnc); + + /* NSSAI */ + if (supported_plmn_item->slice_Support_List) { + int n = supported_plmn_item->slice_Support_List->list.count; + req->plmn[i].supported_slices = n; + req->plmn[i].slice = calloc(n, sizeof(*req->plmn[i].slice)); + AssertFatal(req->plmn[i].slice != NULL, "out of memory\n"); + for (int s = 0; s < n; ++s) { + e1ap_nssai_t *slice = &req->plmn[i].slice[s]; + const E1AP_SNSSAI_t *es = &supported_plmn_item->slice_Support_List->list.array[s]->sNSSAI; + OCTET_STRING_TO_INT8(&es->sST, slice->sst); + slice->sd = 0xffffff; + if (es->sD != NULL) + OCTET_STRING_TO_INT24(es->sD, slice->sd); + LOG_D(E1AP, "SST %d SD %06x\n", slice->sst, slice->sd); + } + } } } -int e1apCUCP_handle_SETUP_REQUEST(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUCP_handle_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) { DevAssert(pdu != NULL); - extract_SETUP_REQUEST(pdu, &inst->setupReq); /* Create ITTI message and send to queue */ MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, 0 /*unused by callee*/, E1AP_SETUP_REQ); - memcpy(&E1AP_SETUP_REQ(msg_p), &inst->setupReq, sizeof(e1ap_setup_req_t)); + extract_SETUP_REQUEST(pdu, &E1AP_SETUP_REQ(msg_p)); + msg_p->ittiMsgHeader.originInstance = assoc_id; - if (inst->setupReq.supported_plmns > 0) { + if (E1AP_SETUP_REQ(msg_p).supported_plmns > 0) { itti_send_msg_to_task(TASK_RRC_GNB, 0 /*unused by callee*/, msg_p); } else { - e1apCUCP_send_SETUP_FAILURE(&inst->setupReq, inst->setupReq.transac_id); + e1apCUCP_send_SETUP_FAILURE(assoc_id, E1AP_SETUP_REQ(msg_p).transac_id); itti_free(TASK_CUCP_E1, msg_p); return -1; } @@ -333,7 +376,7 @@ int e1apCUCP_handle_SETUP_REQUEST(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t return 0; } -int e1apCUUP_handle_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUUP_handle_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) { LOG_D(E1AP, "%s\n", __func__); DevAssert(pdu->present == E1AP_E1AP_PDU_PR_successfulOutcome); @@ -345,7 +388,7 @@ int e1apCUUP_handle_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t /* transac_id */ long transaction_id; - long old_transaction_id = inst->setupReq.transac_id; + long old_transaction_id = inst->cuup.setupReq.transac_id; F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true); transaction_id = ie->value.choice.TransactionID; @@ -361,7 +404,7 @@ int e1apCUUP_handle_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t return 0; } -int e1apCUUP_handle_SETUP_FAILURE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUUP_handle_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) { E1AP_GNB_CU_UP_E1SetupFailureIEs_t *ie; DevAssert(pdu != NULL); @@ -428,26 +471,26 @@ static void fill_CONFIGURATION_UPDATE(E1AP_E1AP_PDU_t *pdu) E1 configuration update: can be sent in both ways, to be refined */ -void e1apCUUP_send_CONFIGURATION_UPDATE(e1ap_setup_req_t *setupReq) +void e1apCUUP_send_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id) { E1AP_E1AP_PDU_t pdu = {0}; fill_CONFIGURATION_UPDATE(&pdu); - e1ap_encode_send(UPtype, setupReq, &pdu, 0, __func__); + e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__); } -int e1apCUCP_send_gNB_DU_CONFIGURATION_FAILURE(e1ap_setup_req_t *setupReq) +int e1apCUCP_send_gNB_DU_CONFIGURATION_FAILURE(void) { AssertFatal(false,"Not implemented yet\n"); return -1; } -int e1apCUCP_send_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(e1ap_setup_req_t *setupReq) +int e1apCUCP_send_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(void) { AssertFatal(false,"Not implemented yet\n"); return -1; } -int e1apCUCP_handle_CONFIGURATION_UPDATE(e1ap_setup_req_t *setupReq, E1AP_E1AP_PDU_t *pdu) +int e1apCUCP_handle_CONFIGURATION_UPDATE(E1AP_E1AP_PDU_t *pdu) { /* E1AP_GNB_CU_UP_E1SetupRequestIEs_t *ie; @@ -459,8 +502,7 @@ int e1apCUCP_handle_CONFIGURATION_UPDATE(e1ap_setup_req_t *setupReq, E1AP_E1AP_P return -1; } -int e1apCUUP_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(e1ap_setup_req_t *setupReq, - sctp_assoc_t assoc_id, +int e1apCUUP_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu) { @@ -468,8 +510,7 @@ int e1apCUUP_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(e1ap_setup_req_t *se return -1; } -int e1apCUUP_handle_gNB_DU_CONFIGURATION_FAILURE(e1ap_setup_req_t *setupReq, - sctp_assoc_t assoc_id, +int e1apCUUP_handle_gNB_DU_CONFIGURATION_FAILURE(sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu) { @@ -507,7 +548,7 @@ int e1ap_handle_RELEASE_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, BEARER CONTEXT SETUP REQUEST */ -static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_setup_req_t *setup, e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) +static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) { pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; asn1cCalloc(pdu->choice.initiatingMessage, msg); @@ -548,7 +589,7 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_setup_req_t *setup, e1ap_beare ieC4->id = E1AP_ProtocolIE_ID_id_Serving_PLMN; ieC4->criticality = E1AP_Criticality_ignore; ieC4->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity; - PLMN_ID_t *servingPLMN = setup->plmns; // First PLMN is serving PLMN. TODO: Remove hard coding here + PLMN_ID_t *servingPLMN = &bearerCxt->servingPLMNid; MCC_MNC_TO_PLMNID(servingPLMN->mcc, servingPLMN->mnc, servingPLMN->mnc_digit_length, &ieC4->value.choice.PLMN_Identity); /* mandatory */ /* Activity Notification Level */ @@ -576,7 +617,12 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_setup_req_t *setup, e1ap_beare ieC6_1->pDU_Session_ID = i->sessionId; ieC6_1->pDU_Session_Type = i->sessionType; - INT8_TO_OCTET_STRING(i->sst, &ieC6_1->sNSSAI.sST); + INT8_TO_OCTET_STRING(i->nssai.sst, &ieC6_1->sNSSAI.sST); + if (i->nssai.sd != 0xffffff) { + ieC6_1->sNSSAI.sD = malloc(sizeof(*ieC6_1->sNSSAI.sD)); + AssertFatal(ieC6_1->sNSSAI.sD != NULL, "out of memory\n"); + INT24_TO_OCTET_STRING(i->nssai.sd, ieC6_1->sNSSAI.sD); + } ieC6_1->securityIndication.integrityProtectionIndication = i->integrityProtectionIndication; ieC6_1->securityIndication.confidentialityProtectionIndication = i->confidentialityProtectionIndication; @@ -633,21 +679,14 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_setup_req_t *setup, e1ap_beare return 0; } -void e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(instance_t instance, e1ap_bearer_setup_req_t *const bearerCxt) +void e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_bearer_setup_req_t *const bearerCxt) { - if (!getCxtE1(instance)) { - LOG_E(E1AP, "Received a UE bearer to establish while no CU-UP is connected, response on NGAP to send failure is not developped\n"); - // Fixme: add response on NGAP to send failure - return; - } - E1AP_E1AP_PDU_t pdu = {0}; - e1ap_setup_req_t *setupReq = &getCxtE1(instance)->setupReq; - fill_BEARER_CONTEXT_SETUP_REQUEST(setupReq, bearerCxt, &pdu); - e1ap_encode_send(CPtype, setupReq, &pdu, 0, __func__); + fill_BEARER_CONTEXT_SETUP_REQUEST(bearerCxt, &pdu); + e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); } -static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const resp, E1AP_E1AP_PDU_t *pdu) +static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *resp, E1AP_E1AP_PDU_t *pdu) { /* Create */ /* 0. pdu Type */ @@ -676,7 +715,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r ieC3->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse; ieC3->criticality = E1AP_Criticality_reject; ieC3->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse; - if (0) { // EUTRAN + /*if (0) { // EUTRAN ieC3->value.choice.System_BearerContextSetupResponse.present = E1AP_System_BearerContextSetupResponse_PR_e_UTRAN_BearerContextSetupResponse; E1AP_ProtocolIE_Container_4932P21_t *msgEUTRAN_list = calloc(1, sizeof(E1AP_ProtocolIE_Container_4932P21_t)); ieC3->value.choice.System_BearerContextSetupResponse.choice.e_UTRAN_BearerContextSetupResponse = (struct E1AP_ProtocolIE_Container *) msgEUTRAN_list; @@ -703,7 +742,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r INT32_TO_OCTET_STRING(j->teId, &gTPTunnel->gTP_TEID); } } - } else { + } else */{ ieC3->value.choice.System_BearerContextSetupResponse.present = E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse; E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list = calloc(1, sizeof(E1AP_ProtocolIE_Container_4932P22_t)); ieC3->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse = (struct E1AP_ProtocolIE_Container *) msgNGRAN_list; @@ -713,7 +752,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List; E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List; - for (pdu_session_setup_t *i=resp->pduSession; i < resp->pduSession+resp->numPDUSessions; i++) { + for (const pdu_session_setup_t *i=resp->pduSession; i < resp->pduSession+resp->numPDUSessions; i++) { asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1); ieC3_1->pDU_Session_ID = i->id; @@ -722,11 +761,11 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress); INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID); - for (DRB_nGRAN_setup_t *j=i->DRBnGRanList; j < i->DRBnGRanList+i->numDRBSetup; j++) { + for (const DRB_nGRAN_setup_t *j=i->DRBnGRanList; j < i->DRBnGRanList+i->numDRBSetup; j++) { asn1cSequenceAdd(ieC3_1->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1); ieC3_1_1->dRB_ID = j->id; - for (up_params_t *k=j->UpParamList; k < j->UpParamList+j->numUpParam; k++) { + 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); @@ -734,7 +773,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); } - for (qos_flow_setup_t *k=j->qosFlows; k < j->qosFlows+j->numQosFlowSetup; k++) { + for (const qos_flow_setup_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->id; } @@ -743,7 +782,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r if (i->numDRBFailed > 0) ieC3_1->dRB_Failed_List_NG_RAN = calloc(1, sizeof(E1AP_DRB_Failed_List_NG_RAN_t)); - for (DRB_nGRAN_failed_t *j=i->DRBnGRanFailedList; j < i->DRBnGRanFailedList+i->numDRBFailed; j++) { + for (const DRB_nGRAN_failed_t *j=i->DRBnGRanFailedList; j < i->DRBnGRanFailedList+i->numDRBFailed; j++) { asn1cSequenceAdd(ieC3_1->dRB_Failed_List_NG_RAN->list, E1AP_DRB_Failed_Item_NG_RAN_t, ieC3_1_1); ieC3_1_1->dRB_ID = j->id; @@ -774,11 +813,11 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r } } -void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, e1ap_bearer_setup_resp_t *const resp) +void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_bearer_setup_resp_t *resp) { E1AP_E1AP_PDU_t pdu = {0}; fill_BEARER_CONTEXT_SETUP_RESPONSE(resp, &pdu); - e1ap_encode_send(UPtype, &inst->setupReq, &pdu, 0, __func__); + e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__); } int e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance) { @@ -791,7 +830,7 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest; E1AP_BearerContextSetupRequestIEs_t *ie; - LOG_I(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); + LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); for (int i=0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -862,7 +901,10 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, pdu_session->sessionId = pdu2Setup->pDU_Session_ID; pdu_session->sessionType = pdu2Setup->pDU_Session_Type; - OCTET_STRING_TO_INT8(&pdu2Setup->sNSSAI.sST, pdu_session->sst); + OCTET_STRING_TO_INT8(&pdu2Setup->sNSSAI.sST, pdu_session->nssai.sst); + pdu_session->nssai.sd = 0xffffff; + if (pdu2Setup->sNSSAI.sD != NULL) + OCTET_STRING_TO_INT24(pdu2Setup->sNSSAI.sD, pdu_session->nssai.sd); pdu_session->integrityProtectionIndication = pdu2Setup->securityIndication.integrityProtectionIndication; pdu_session->confidentialityProtectionIndication = pdu2Setup->securityIndication.confidentialityProtectionIndication; @@ -946,7 +988,7 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, } -int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) { DevAssert(pdu != NULL); DevAssert(pdu->present == E1AP_E1AP_PDU_PR_initiatingMessage); @@ -956,7 +998,8 @@ int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(e1ap_upcp_inst_t *e1_inst, cons e1ap_bearer_setup_req_t bearerCxt = {0}; extract_BEARER_CONTEXT_SETUP_REQUEST(pdu, &bearerCxt); - process_e1_bearer_context_setup_req(e1_inst->instance, &bearerCxt); + + e1_bearer_context_setup(&bearerCxt); return 0; } @@ -965,7 +1008,7 @@ void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu, const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse; E1AP_BearerContextSetupResponseIEs_t *ie; - LOG_I(E1AP, "Bearer context setup response number of IEs %d\n", in->protocolIEs.list.count); + LOG_D(E1AP, "Bearer context setup response number of IEs %d\n", in->protocolIEs.list.count); for (int i=0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -1046,7 +1089,7 @@ void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu, } } -int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) { DevAssert(pdu->present == E1AP_E1AP_PDU_PR_successfulOutcome); DevAssert(pdu->choice.successfulOutcome->procedureCode == E1AP_ProcedureCode_id_bearerContextSetup); @@ -1056,6 +1099,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_RESP); e1ap_bearer_setup_resp_t *bearerCxt = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg); extract_BEARER_CONTEXT_SETUP_RESPONSE(pdu, bearerCxt); + msg->ittiMsgHeader.originInstance = assoc_id; // Fixme: instance is the NGAP instance, no good way to set it here instance_t instance = 0; itti_send_msg_to_task(TASK_RRC_GNB, instance, msg); @@ -1063,7 +1107,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const return 0; } -int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) { AssertFatal(false,"Not implemented yet\n"); return -1; @@ -1073,7 +1117,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(e1ap_upcp_inst_t *inst, const E BEARER CONTEXT MODIFICATION REQUEST */ -static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_setup_req_t *setupReq, e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) +static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) { pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; asn1cCalloc(pdu->choice.initiatingMessage, msg); @@ -1135,18 +1179,76 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_setup_req_t *setupReq, return 0; } -static void e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_REQUEST(instance_t inst, e1ap_bearer_setup_req_t *const bearerCxt) +static void e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, e1ap_bearer_setup_req_t *const bearerCxt) { - AssertFatal(getCxtE1(inst), ""); - e1ap_setup_req_t *setupReq = &getCxtE1(inst)->setupReq; E1AP_E1AP_PDU_t pdu = {0}; - fill_BEARER_CONTEXT_MODIFICATION_REQUEST(setupReq, bearerCxt, &pdu); - e1ap_encode_send(CPtype, setupReq, &pdu, 0, __func__); + fill_BEARER_CONTEXT_MODIFICATION_REQUEST(bearerCxt, &pdu); + e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); } -int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { - AssertFatal(false,"Not implemented yet\n"); - return -1; +static void fill_BEARER_CONTEXT_MODIFICATION_RESPONSE(const e1ap_bearer_modif_resp_t *resp, E1AP_E1AP_PDU_t *pdu) +{ + pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, msg); + msg->procedureCode = E1AP_ProcedureCode_id_bearerContextModification; + msg->criticality = E1AP_Criticality_reject; + msg->value.present = E1AP_SuccessfulOutcome__value_PR_BearerContextModificationResponse; + E1AP_BearerContextModificationResponse_t *out = &pdu->choice.successfulOutcome->value.choice.BearerContextModificationResponse; + + /* mandatory */ + /* c1. gNB-CU-CP UE E1AP ID */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationResponseIEs_t, ieCuCpId); + ieCuCpId->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; + ieCuCpId->criticality = E1AP_Criticality_reject; + ieCuCpId->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; + ieCuCpId->value.choice.GNB_CU_CP_UE_E1AP_ID = resp->gNB_cu_cp_ue_id; + + /* mandatory */ + /* c2. gNB-CU-UP UE E1AP ID */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationResponseIEs_t, ieCuUpId); + ieCuUpId->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID; + ieCuUpId->criticality = E1AP_Criticality_reject; + ieCuUpId->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; + ieCuUpId->value.choice.GNB_CU_UP_UE_E1AP_ID = resp->gNB_cu_up_ue_id; + + /* optional */ + /* PDU sessions that have been modified */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationResponseIEs_t, ieSys); + ieSys->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationResponse; + ieSys->criticality = E1AP_Criticality_ignore; + ieSys->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_System_BearerContextModificationResponse; + + E1AP_System_BearerContextModificationResponse_t *sys = &ieSys->value.choice.System_BearerContextModificationResponse; + E1AP_ProtocolIE_Container_4932P29_t *piel = calloc(1, sizeof(*piel)); + sys->present = E1AP_System_BearerContextModificationResponse_PR_nG_RAN_BearerContextModificationResponse; + sys->choice.nG_RAN_BearerContextModificationResponse = (struct E1AP_ProtocolIE_Container *)piel; + asn1cSequenceAdd(piel->list, E1AP_NG_RAN_BearerContextModificationResponse_t, ngran_bcmr); + ngran_bcmr->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Modified_List; + ngran_bcmr->criticality = E1AP_Criticality_reject; + ngran_bcmr->value.present = E1AP_NG_RAN_BearerContextModificationResponse__value_PR_PDU_Session_Resource_Modified_List; + E1AP_PDU_Session_Resource_Modified_List_t *pdu_mod_l = &ngran_bcmr->value.choice.PDU_Session_Resource_Modified_List; + for (int i = 0; i < resp->numPDUSessionsMod; ++i) { + const pdu_session_modif_t *pdu = &resp->pduSessionMod[i]; + asn1cSequenceAdd(pdu_mod_l->list, E1AP_PDU_Session_Resource_Modified_Item_t, iePdu); + iePdu->pDU_Session_ID = pdu->id; + if (pdu->numDRBModified > 0) { + iePdu->dRB_Modified_List_NG_RAN = calloc(1, sizeof(*iePdu->dRB_Modified_List_NG_RAN)); + AssertFatal(iePdu->dRB_Modified_List_NG_RAN != NULL, "out of memory\n"); + E1AP_DRB_Modified_List_NG_RAN_t *drb_mod_l = iePdu->dRB_Modified_List_NG_RAN; + for (int j = 0; j < pdu->numDRBModified; ++j) { + const DRB_nGRAN_modified_t *drb = &pdu->DRBnGRanModList[j]; + asn1cSequenceAdd(drb_mod_l->list, E1AP_DRB_Modified_Item_NG_RAN_t, drb_mod); + drb_mod->dRB_ID = drb->id; + } + } + } +} + +static int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, const e1ap_bearer_modif_resp_t *resp) +{ + E1AP_E1AP_PDU_t pdu = {0}; + fill_BEARER_CONTEXT_MODIFICATION_RESPONSE(resp, &pdu); + return e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__); } int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_FAILURE(instance_t instance) { @@ -1159,7 +1261,7 @@ void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *pdu, const E1AP_BearerContextModificationRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextModificationRequest; E1AP_BearerContextModificationRequestIEs_t *ie; - LOG_I(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); + LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); for (int i=0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -1232,7 +1334,7 @@ void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *pdu, } } -int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) { DevAssert(pdu != NULL); DevAssert(pdu->present == E1AP_E1AP_PDU_PR_initiatingMessage); @@ -1242,17 +1344,91 @@ int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_upcp_inst_t *e1_ins e1ap_bearer_setup_req_t bearerCxt = {0}; extract_BEARER_CONTEXT_MODIFICATION_REQUEST(pdu, &bearerCxt); - CUUP_process_bearer_context_mod_req(e1_inst->instance, &bearerCxt); + + e1_bearer_context_modif(&bearerCxt); return 0; } -int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, - sctp_assoc_t assoc_id, - uint32_t stream, - E1AP_E1AP_PDU_t *pdu) +static void extract_BEARER_CONTEXT_MODIFICATION_RESPONSE(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_modif_resp_t *resp) { - AssertFatal(false,"Not implemented yet\n"); - return -1; + memset(resp, 0, sizeof(*resp)); + const E1AP_BearerContextModificationResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextModificationResponse; + + for (int i = 0; i < in->protocolIEs.list.count; ++i) { + E1AP_BearerContextModificationResponseIEs_t *ie = in->protocolIEs.list.array[i]; + + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID: + DevAssert(ie->criticality == E1AP_Criticality_reject); + DevAssert(ie->value.present == E1AP_BearerContextModificationResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID); + resp->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: + DevAssert(ie->criticality == E1AP_Criticality_reject); + DevAssert(ie->value.present == E1AP_BearerContextModificationResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID); + resp->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID; + break; + + case E1AP_ProtocolIE_ID_id_System_BearerContextModificationResponse: + DevAssert(ie->criticality == E1AP_Criticality_ignore); + DevAssert(ie->value.present == E1AP_BearerContextModificationResponseIEs__value_PR_System_BearerContextModificationResponse); + DevAssert(ie->value.choice.System_BearerContextModificationResponse.present + == E1AP_System_BearerContextModificationResponse_PR_nG_RAN_BearerContextModificationResponse); + E1AP_ProtocolIE_Container_4932P29_t *msgNGRAN_list = + (E1AP_ProtocolIE_Container_4932P29_t *) + ie->value.choice.System_BearerContextModificationResponse.choice.nG_RAN_BearerContextModificationResponse; + DevAssert(msgNGRAN_list->list.count == 1); + E1AP_NG_RAN_BearerContextModificationResponse_t *msgNGRAN = msgNGRAN_list->list.array[0]; + DevAssert(msgNGRAN->id == E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Modified_List); + DevAssert(msgNGRAN->criticality == E1AP_Criticality_reject); + DevAssert(msgNGRAN->value.present == E1AP_NG_RAN_BearerContextModificationResponse__value_PR_PDU_Session_Resource_Modified_List); + E1AP_PDU_Session_Resource_Modified_List_t *pduModifiedList = &msgNGRAN->value.choice.PDU_Session_Resource_Modified_List; + resp->numPDUSessionsMod = pduModifiedList->list.count; + + for (int i=0; i < pduModifiedList->list.count; i++) { + pdu_session_modif_t *pduModified = &resp->pduSessionMod[i]; + E1AP_PDU_Session_Resource_Modified_Item_t *mod_it = pduModifiedList->list.array[i]; + pduModified->id = mod_it->pDU_Session_ID; + + AssertFatal(mod_it->nG_DL_UP_TNL_Information == NULL, "not implemented\n"); + AssertFatal(mod_it->securityResult == NULL, "not implemented\n"); + AssertFatal(mod_it->pDU_Session_Data_Forwarding_Information_Response == NULL, "not implemented\n"); + AssertFatal(mod_it->dRB_Setup_List_NG_RAN == NULL, "not implemented\n"); + AssertFatal(mod_it->dRB_Failed_List_NG_RAN == NULL, "not implemented\n"); + AssertFatal(mod_it->dRB_Failed_To_Modify_List_NG_RAN == NULL, "not implemented\n"); + + pduModified->numDRBModified = mod_it->dRB_Modified_List_NG_RAN->list.count; + for (int j=0; j < mod_it->dRB_Modified_List_NG_RAN->list.count; j++) { + DRB_nGRAN_modified_t *drbModified = &pduModified->DRBnGRanModList[j]; + E1AP_DRB_Modified_Item_NG_RAN_t *drb = mod_it->dRB_Modified_List_NG_RAN->list.array[j]; + + drbModified->id = drb->dRB_ID; + + AssertFatal(drb->uL_UP_Transport_Parameters == NULL, "not implemented\n"); + AssertFatal(drb->pDCP_SN_Status_Information == NULL, "not implemented\n"); + AssertFatal(drb->flow_Setup_List == NULL, "not implemented\n"); + AssertFatal(drb->flow_Failed_List == NULL, "not implemented\n"); + } + } + break; + } + } +} + +int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + DevAssert(pdu->present == E1AP_E1AP_PDU_PR_successfulOutcome); + DevAssert(pdu->choice.successfulOutcome->procedureCode == E1AP_ProcedureCode_id_bearerContextModification); + DevAssert(pdu->choice.successfulOutcome->criticality == E1AP_Criticality_reject); + DevAssert(pdu->choice.successfulOutcome->value.present == E1AP_SuccessfulOutcome__value_PR_BearerContextModificationResponse); + + MessageDef *msg = itti_alloc_new_message(TASK_CUUP_E1, 0, E1AP_BEARER_CONTEXT_MODIFICATION_RESP); + e1ap_bearer_modif_resp_t *modif = &E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg); + extract_BEARER_CONTEXT_MODIFICATION_RESPONSE(pdu, modif); + itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); + return 0; } int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_FAILURE(instance_t instance, @@ -1295,7 +1471,7 @@ int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_CONFIRM(instance_t instance, BEARER CONTEXT RELEASE */ -static int fill_BEARER_CONTEXT_RELEASE_COMMAND(e1ap_setup_req_t *setupReq, e1ap_bearer_release_cmd_t *const cmd, E1AP_E1AP_PDU_t *pdu) +static int fill_BEARER_CONTEXT_RELEASE_COMMAND(e1ap_bearer_release_cmd_t *const cmd, E1AP_E1AP_PDU_t *pdu) { pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; asn1cCalloc(pdu->choice.initiatingMessage, msg); @@ -1321,14 +1497,14 @@ static int fill_BEARER_CONTEXT_RELEASE_COMMAND(e1ap_setup_req_t *setupReq, e1ap_ return 0; } -int e1apCUCP_send_BEARER_CONTEXT_RELEASE_COMMAND(e1ap_setup_req_t *setupReq, e1ap_bearer_release_cmd_t *const cmd) +int e1apCUCP_send_BEARER_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, e1ap_bearer_release_cmd_t *const cmd) { E1AP_E1AP_PDU_t pdu = {0}; - fill_BEARER_CONTEXT_RELEASE_COMMAND(setupReq, cmd, &pdu); - return e1ap_encode_send(CPtype, setupReq, &pdu, 0, __func__); + fill_BEARER_CONTEXT_RELEASE_COMMAND(cmd, &pdu); + return e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); } -int fill_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_setup_req_t *setupReq, e1ap_bearer_release_cmd_t *const cmd, E1AP_E1AP_PDU_t *pdu) +static int fill_BEARER_CONTEXT_RELEASE_COMPLETE(const e1ap_bearer_release_cplt_t *cplt, E1AP_E1AP_PDU_t *pdu) { pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome; asn1cCalloc(pdu->choice.successfulOutcome, msg); @@ -1342,23 +1518,23 @@ int fill_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_setup_req_t *setupReq, e1ap_bearer ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; ieC1->criticality = E1AP_Criticality_reject; ieC1->value.present = E1AP_BearerContextReleaseCompleteIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; - ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = cmd->gNB_cu_cp_ue_id; + ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = cplt->gNB_cu_cp_ue_id; /* mandatory */ /* c2. gNB-CU-UP UE E1AP ID */ asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextReleaseCompleteIEs_t, ieC2); ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID; ieC2->criticality = E1AP_Criticality_reject; ieC2->value.present = E1AP_BearerContextReleaseCompleteIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; - ieC2->value.choice.GNB_CU_UP_UE_E1AP_ID = cmd->gNB_cu_cp_ue_id; + ieC2->value.choice.GNB_CU_UP_UE_E1AP_ID = cplt->gNB_cu_cp_ue_id; return 0; } -int e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_upcp_inst_t *inst, e1ap_bearer_release_cmd_t *const cmd) +int e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, const e1ap_bearer_release_cplt_t *cplt) { E1AP_E1AP_PDU_t pdu = {0}; - fill_BEARER_CONTEXT_RELEASE_COMPLETE(&inst->setupReq, cmd, &pdu); - return e1ap_encode_send(CPtype, &inst->setupReq, &pdu, 0, __func__); + fill_BEARER_CONTEXT_RELEASE_COMPLETE(cplt, &pdu); + return e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); } int e1apCUUP_send_BEARER_CONTEXT_RELEASE_REQUEST(instance_t instance) { @@ -1371,7 +1547,7 @@ void extract_BEARER_CONTEXT_RELEASE_COMMAND(const E1AP_E1AP_PDU_t *pdu, const E1AP_BearerContextReleaseCommand_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextReleaseCommand; E1AP_BearerContextReleaseCommandIEs_t *ie; - LOG_I(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); + LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); for (int i=0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -1405,7 +1581,7 @@ void extract_BEARER_CONTEXT_RELEASE_COMMAND(const E1AP_E1AP_PDU_t *pdu, } } -int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) { DevAssert(pdu != NULL); DevAssert(pdu->present == E1AP_E1AP_PDU_PR_initiatingMessage); @@ -1415,16 +1591,16 @@ int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(e1ap_upcp_inst_t *e1_inst, co e1ap_bearer_release_cmd_t bearerCxt = {0}; extract_BEARER_CONTEXT_RELEASE_COMMAND(pdu, &bearerCxt); - CUUP_process_bearer_release_command(e1_inst->instance, &bearerCxt); + e1_bearer_release_cmd(&bearerCxt); return 0; } void extract_BEARER_CONTEXT_RELEASE_COMPLETE(const E1AP_E1AP_PDU_t *pdu, - e1ap_bearer_release_cmd_t *bearerCxt) { + e1ap_bearer_release_cplt_t *bearerCxt) { const E1AP_BearerContextReleaseComplete_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextReleaseComplete; E1AP_BearerContextReleaseCompleteIEs_t *ie; - LOG_I(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); + LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); for (int i=0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -1449,7 +1625,7 @@ void extract_BEARER_CONTEXT_RELEASE_COMPLETE(const E1AP_E1AP_PDU_t *pdu, } } -int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) +int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) { DevAssert(pdu != NULL); DevAssert(pdu->present == E1AP_E1AP_PDU_PR_successfulOutcome); @@ -1457,9 +1633,12 @@ int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_upcp_inst_t *e1_inst, c DevAssert(pdu->choice.successfulOutcome->criticality == E1AP_Criticality_reject); DevAssert(pdu->choice.successfulOutcome->value.present == E1AP_SuccessfulOutcome__value_PR_BearerContextReleaseComplete); - e1ap_bearer_release_cmd_t bearerCxt = {0}; + e1ap_bearer_release_cplt_t bearerCxt = {0}; extract_BEARER_CONTEXT_RELEASE_COMPLETE(pdu, &bearerCxt); - //TODO: CUCP_process_bearer_release_complete(&beareCxt, instance); + MessageDef *msg = itti_alloc_new_message(TASK_CUUP_E1, 0, E1AP_BEARER_CONTEXT_RELEASE_CPLT); + e1ap_bearer_release_cplt_t *cplt = &E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg); + *cplt = bearerCxt; + itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); return 0; } @@ -1519,32 +1698,31 @@ static instance_t cuup_task_create_gtpu_instance_to_du(eth_params_t *IPaddrs) { openAddr_t tmp= {0}; strncpy(tmp.originHost, IPaddrs->my_addr, sizeof(tmp.originHost)-1); sprintf(tmp.originService, "%d", IPaddrs->my_portd); + sprintf(tmp.destinationService, "%d", IPaddrs->remote_portd); return gtpv1Init(tmp); } -static void e1_task_send_sctp_association_req(long task_id, instance_t instance, e1ap_setup_req_t *e1ap_setup_req) +static void e1_task_send_sctp_association_req(long task_id, instance_t instance, e1ap_net_config_t *e1ap_nc) { - DevAssert(e1ap_setup_req != NULL); + DevAssert(e1ap_nc != NULL); getCxtE1(instance)->sockState = SCTP_STATE_CLOSED; MessageDef *message_p = itti_alloc_new_message(task_id, 0, SCTP_NEW_ASSOCIATION_REQ); sctp_new_association_req_t *sctp_new_req = &message_p->ittiMsg.sctp_new_association_req; sctp_new_req->ulp_cnx_id = instance; sctp_new_req->port = E1AP_PORT_NUMBER; sctp_new_req->ppid = E1AP_SCTP_PPID; - sctp_new_req->in_streams = e1ap_setup_req->sctp_in_streams; - sctp_new_req->out_streams = e1ap_setup_req->sctp_out_streams; // remote - sctp_new_req->remote_address = e1ap_setup_req->CUCP_e1_ip_address; + sctp_new_req->remote_address = e1ap_nc->CUCP_e1_ip_address; // local - sctp_new_req->local_address = e1ap_setup_req->CUUP_e1_ip_address; + sctp_new_req->local_address = e1ap_nc->CUUP_e1_ip_address; itti_send_msg_to_task(TASK_SCTP, instance, message_p); } -static void e1apCUUP_send_SETUP_REQUEST(e1ap_setup_req_t *setup) +static void e1apCUUP_send_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_setup_req_t *setup) { E1AP_E1AP_PDU_t pdu = {0}; fill_SETUP_REQUEST(setup, &pdu); - e1ap_encode_send(UPtype, setup, &pdu, 0, __func__); + e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__); } static void e1_task_handle_sctp_association_resp(E1_t type, instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) @@ -1562,15 +1740,14 @@ static void e1_task_handle_sctp_association_resp(E1_t type, instance_t instance, } if (type == UPtype) { - e1ap_setup_req_t *e1ap_cuup_setup_req = &getCxtE1(instance)->setupReq; - e1ap_cuup_setup_req->assoc_id = sctp_new_association_resp->assoc_id; - e1ap_cuup_setup_req->sctp_in_streams = sctp_new_association_resp->in_streams; - e1ap_cuup_setup_req->sctp_out_streams = sctp_new_association_resp->out_streams; - e1ap_cuup_setup_req->default_sctp_stream_id = 0; + e1ap_upcp_inst_t *inst = getCxtE1(instance); + inst->cuup.assoc_id = sctp_new_association_resp->assoc_id; - eth_params_t IPaddr; - IPaddr.my_addr = e1ap_cuup_setup_req->localAddressF1U; - IPaddr.my_portd = e1ap_cuup_setup_req->localPortF1U; + e1ap_net_config_t *nc = &inst->net_config; + eth_params_t IPaddr = {0}; + IPaddr.my_addr = nc->localAddressF1U; + IPaddr.my_portd = nc->localPortF1U; + IPaddr.remote_portd = nc->remotePortF1U; if (getCxtE1(instance)->gtpInstF1U < 0) getCxtE1(instance)->gtpInstF1U = cuup_task_create_gtpu_instance_to_du(&IPaddr); if (getCxtE1(instance)->gtpInstF1U < 0) @@ -1578,18 +1755,18 @@ static void e1_task_handle_sctp_association_resp(E1_t type, instance_t instance, extern instance_t CUuniqInstance; CUuniqInstance = getCxtE1(instance)->gtpInstF1U; cuup_init_n3(instance); - e1apCUUP_send_SETUP_REQUEST(&getCxtE1(instance)->setupReq); + e1apCUUP_send_SETUP_REQUEST(inst->cuup.assoc_id, &inst->cuup.setupReq); } } void cuup_init_n3(instance_t instance) { if (getCxtE1(instance)->gtpInstN3 < 0) { - e1ap_setup_req_t *setup = &getCxtE1(instance)->setupReq; + e1ap_net_config_t *nc = &getCxtE1(instance)->net_config; openAddr_t tmp = {0}; - strcpy(tmp.originHost, setup->localAddressN3); - sprintf(tmp.originService, "%d", setup->localPortN3); - sprintf(tmp.destinationService, "%d", setup->remotePortN3); + strcpy(tmp.originHost, nc->localAddressN3); + sprintf(tmp.originService, "%d", nc->localPortN3); + sprintf(tmp.destinationService, "%d", nc->remotePortN3); LOG_I(GTPU, "Configuring GTPu address : %s, port : %s\n", tmp.originHost, tmp.originService); // Fixme: fully inconsistent instances management // dirty global var is a bad fix @@ -1623,24 +1800,19 @@ void cucp_task_send_sctp_init_req(instance_t instance, char *my_addr) { void e1_task_handle_sctp_association_ind(E1_t type, instance_t instance, sctp_new_association_ind_t *sctp_new_ind) { - if (getCxtE1(instance)) - LOG_W(E1AP, "CUCP incoming call, re-use older socket context, finish implementation required\n"); - else - createE1inst(type, instance, NULL); - getCxtE1(instance)->sockState = SCTP_STATE_ESTABLISHED; - getCxtE1(instance)->incoming_sock = true; - e1ap_setup_req_t *setup_req = &getCxtE1(instance)->setupReq; - setup_req->assoc_id = sctp_new_ind->assoc_id; - setup_req->sctp_in_streams = sctp_new_ind->in_streams; - setup_req->sctp_out_streams = sctp_new_ind->out_streams; - setup_req->default_sctp_stream_id = 0; + if (!getCxtE1(instance)) + createE1inst(type, instance, NULL, NULL); + e1ap_upcp_inst_t *inst = getCxtE1(instance); + inst->sockState = SCTP_STATE_ESTABLISHED; + if (type == UPtype) + inst->cuup.assoc_id = sctp_new_ind->assoc_id; } void e1apHandleTimer(instance_t myInstance) { LOG_W(E1AP, "Try to reconnect to CP\n"); if (getCxtE1(myInstance)->sockState != SCTP_STATE_ESTABLISHED) - e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, &getCxtE1(myInstance)->setupReq); + e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, &getCxtE1(myInstance)->net_config); } void *E1AP_CUCP_task(void *arg) { @@ -1653,7 +1825,8 @@ void *E1AP_CUCP_task(void *arg) { itti_receive_msg(TASK_CUCP_E1, &msg); instance_t myInstance=ITTI_MSG_DESTINATION_INSTANCE(msg); const int msgType = ITTI_MSG_ID(msg); - LOG_I(E1AP, "CUCP received %s for instance %ld\n", messages_info[msgType].name, myInstance); + LOG_D(E1AP, "CUCP received %s for instance %ld\n", messages_info[msgType].name, myInstance); + sctp_assoc_t assoc_id = msg->ittiMsgHeader.originInstance; switch (ITTI_MSG_ID(msg)) { case SCTP_NEW_ASSOCIATION_IND: @@ -1664,29 +1837,37 @@ void *E1AP_CUCP_task(void *arg) { e1_task_handle_sctp_association_resp(CPtype, ITTI_MSG_ORIGIN_INSTANCE(msg), &msg->ittiMsg.sctp_new_association_resp); break; - case E1AP_SETUP_REQ: { - e1ap_setup_req_t *req = &E1AP_SETUP_REQ(msg); - if (req->CUCP_e1_ip_address.ipv4 == 0) { - LOG_E(E1AP, "No IPv4 address configured\n"); - return NULL; - } - cucp_task_send_sctp_init_req(0, req->CUCP_e1_ip_address.ipv4_address); + case E1AP_REGISTER_REQ: { + // note: we use E1AP_REGISTER_REQ only to set up sockets, the + // E1AP_SETUP_REQ is not used and comes through the socket from the + // CU-UP later! + e1ap_net_config_t *nc = &E1AP_REGISTER_REQ(msg).net_config; + AssertFatal(nc->CUCP_e1_ip_address.ipv4 != 0, "No IPv4 address configured\n"); + cucp_task_send_sctp_init_req(0, nc->CUCP_e1_ip_address.ipv4_address); } break; + case E1AP_SETUP_REQ: + AssertFatal(false, "should not receive E1AP_SETUP_REQ in CU-CP!\n"); + break; + case SCTP_DATA_IND: e1_task_handle_sctp_data_ind(myInstance, &msg->ittiMsg.sctp_data_ind); break; case E1AP_SETUP_RESP: - e1ap_send_SETUP_RESPONSE(myInstance, &E1AP_SETUP_RESP(msg)); + e1ap_send_SETUP_RESPONSE(assoc_id, &E1AP_SETUP_RESP(msg)); break; case E1AP_BEARER_CONTEXT_SETUP_REQ: - e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(myInstance, &E1AP_BEARER_CONTEXT_SETUP_REQ(msg)); + e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(assoc_id, &E1AP_BEARER_CONTEXT_SETUP_REQ(msg)); break; case E1AP_BEARER_CONTEXT_MODIFICATION_REQ: - e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_REQUEST(myInstance, &E1AP_BEARER_CONTEXT_SETUP_REQ(msg)); + e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_REQUEST(assoc_id, &E1AP_BEARER_CONTEXT_SETUP_REQ(msg)); + break; + + case E1AP_BEARER_CONTEXT_RELEASE_CMD: + e1apCUCP_send_BEARER_CONTEXT_RELEASE_COMMAND(assoc_id, &E1AP_BEARER_CONTEXT_RELEASE_CMD(msg)); break; default: @@ -1712,13 +1893,12 @@ void *E1AP_CUUP_task(void *arg) { itti_receive_msg(TASK_CUUP_E1, &msg); const instance_t myInstance = ITTI_MSG_DESTINATION_INSTANCE(msg); const int msgType = ITTI_MSG_ID(msg); - LOG_I(E1AP, "CUUP received %s for instance %ld\n", messages_info[msgType].name, myInstance); + LOG_D(E1AP, "CUUP received %s for instance %ld\n", messages_info[msgType].name, myInstance); switch (msgType) { - case E1AP_SETUP_REQ: { - e1ap_setup_req_t *msgSetup = &E1AP_SETUP_REQ(msg); - createE1inst(UPtype, myInstance, msgSetup); - - e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, msgSetup); + case E1AP_REGISTER_REQ: { + e1ap_register_req_t *reg_req = &E1AP_REGISTER_REQ(msg); + createE1inst(UPtype, myInstance, ®_req->net_config, ®_req->setup_req); + e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, ®_req->net_config); } break; case SCTP_NEW_ASSOCIATION_RESP: @@ -1733,6 +1913,27 @@ void *E1AP_CUUP_task(void *arg) { e1apHandleTimer(myInstance); break; + case E1AP_BEARER_CONTEXT_SETUP_RESP: { + const e1ap_bearer_setup_resp_t *resp = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg); + const e1ap_upcp_inst_t *inst = getCxtE1(myInstance); + AssertFatal(inst != NULL, "no E1 instance found for instance %ld\n", myInstance); + e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(inst->cuup.assoc_id, resp); + } break; + + case E1AP_BEARER_CONTEXT_MODIFICATION_RESP: { + const e1ap_bearer_modif_resp_t *resp = &E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg); + const e1ap_upcp_inst_t *inst = getCxtE1(myInstance); + AssertFatal(inst != NULL, "no E1 instance found for instance %ld\n", myInstance); + e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_RESPONSE(inst->cuup.assoc_id, resp); + } break; + + case E1AP_BEARER_CONTEXT_RELEASE_CPLT: { + const e1ap_bearer_release_cplt_t *cplt = &E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg); + const e1ap_upcp_inst_t *inst = getCxtE1(myInstance); + AssertFatal(inst != NULL, "no E1 instance found for instance %ld\n", myInstance); + e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(inst->cuup.assoc_id, cplt); + } break; + default: LOG_E(E1AP, "Unknown message received in TASK_CUUP_E1\n"); break; diff --git a/openair2/E1AP/e1ap.h b/openair2/E1AP/e1ap.h index af1dcae363..b41559de09 100644 --- a/openair2/E1AP/e1ap.h +++ b/openair2/E1AP/e1ap.h @@ -28,27 +28,29 @@ #include "e1ap_asnc.h" #include "openair2/E1AP/e1ap_common.h" -int e1apCUCP_handle_SETUP_REQUEST(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +int e1apCUCP_handle_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); -int e1apCUUP_handle_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +int e1apCUUP_handle_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); -int e1apCUUP_handle_SETUP_FAILURE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +int e1apCUUP_handle_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); -int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); -int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); -int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); -int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); -void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, e1ap_bearer_setup_resp_t *const resp); +int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu); -int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_bearer_setup_resp_t *resp); -int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); +int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); -int e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_upcp_inst_t *inst, e1ap_bearer_release_cmd_t *const cmd); +int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu); + +int e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, const e1ap_bearer_release_cplt_t *cplt); void *E1AP_CUUP_task(void *arg); diff --git a/openair2/E1AP/e1ap_api.c b/openair2/E1AP/e1ap_api.c deleted file mode 100644 index 9cec6b69f3..0000000000 --- a/openair2/E1AP/e1ap_api.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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 - * - * Author and copyright: Laurent Thomas, open-cells.com - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include -#include "e1ap_api.h" - -#include "nr_pdcp/nr_pdcp_entity.h" -#include "openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h" -#include "openair2/RRC/NR/cucp_cuup_if.h" -#include "openair2/RRC/LTE/MESSAGES/asn1_msg.h" -#include "openair3/SECU/key_nas_deriver.h" -#include "openair3/ocp-gtpu/gtp_itf.h" -#include "openair2/F1AP/f1ap_ids.h" -#include "e1ap_asnc.h" -#include "e1ap_common.h" -#include "e1ap.h" - -struct NR_DRB_ToAddMod; -static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, pdu_session_to_setup_t *pdu) { - - for (int i=0; i < pdu->numDRB2Setup; i++) { - DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + i; - asn1cSequenceAdd(DRB_configList->list, struct NR_DRB_ToAddMod, ie); - ie->drb_Identity = drb->id; - ie->cnAssociation = CALLOC(1, sizeof(*ie->cnAssociation)); - ie->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config; - - // sdap_Config - asn1cCalloc(ie->cnAssociation->choice.sdap_Config, sdap_config); - sdap_config->pdu_Session = pdu->sessionId; - sdap_config->sdap_HeaderDL = drb->sDAP_Header_DL; - sdap_config->sdap_HeaderUL = drb->sDAP_Header_UL; - sdap_config->defaultDRB = drb->defaultDRB; - - asn1cCalloc(sdap_config->mappedQoS_FlowsToAdd, FlowsToAdd); - for (int j=0; j < drb->numQosFlow2Setup; j++) { - asn1cSequenceAdd(FlowsToAdd->list, NR_QFI_t, qfi); - *qfi = drb->qosFlows[j].fiveQI; - } - sdap_config->mappedQoS_FlowsToRelease = NULL; - - // pdcp_Config - ie->reestablishPDCP = NULL; - ie->recoverPDCP = NULL; - asn1cCalloc(ie->pdcp_Config, pdcp_config); - asn1cCalloc(pdcp_config->drb, drbCfg); - asn1cCallocOne(drbCfg->discardTimer, drb->discardTimer); - asn1cCallocOne(drbCfg->pdcp_SN_SizeUL, drb->pDCP_SN_Size_UL); - asn1cCallocOne(drbCfg->pdcp_SN_SizeDL, drb->pDCP_SN_Size_DL); - drbCfg->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; - drbCfg->headerCompression.choice.notUsed = 0; - - drbCfg->integrityProtection = NULL; - drbCfg->statusReportRequired = NULL; - drbCfg->outOfOrderDelivery = NULL; - pdcp_config->moreThanOneRLC = NULL; - - pdcp_config->t_Reordering = calloc(1, sizeof(*pdcp_config->t_Reordering)); - *pdcp_config->t_Reordering = drb->reorderingTimer; - pdcp_config->ext1 = NULL; - - if (pdu->integrityProtectionIndication == 0 || // Required - pdu->integrityProtectionIndication == 1) { // Preferred - asn1cCallocOne(drbCfg->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled); - } - - if (pdu->confidentialityProtectionIndication == 2) { // Not Needed - asn1cCalloc(pdcp_config->ext1, ext1); - asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true); - } - } -} - -static int drb_config_N3gtpu_create(e1ap_bearer_setup_req_t * const req, - gtpv1u_gnb_create_tunnel_resp_t *create_tunnel_resp, - instance_t instance) { - - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req={0}; - - NR_DRB_ToAddModList_t DRB_configList = {0}; - for (int i=0; i < req->numPDUSessions; i++) { - pdu_session_to_setup_t *const pdu = &req->pduSession[i]; - create_tunnel_req.pdusession_id[i] = pdu->sessionId; - create_tunnel_req.incoming_rb_id[i] = pdu->DRBnGRanList[0].id; // taking only the first DRB. TODO:change this - memcpy(&create_tunnel_req.dst_addr[i].buffer, - &pdu->tlAddress, - sizeof(uint8_t)*4); - create_tunnel_req.dst_addr[i].length = 32; // 8bits * 4bytes - create_tunnel_req.outgoing_teid[i] = pdu->teId; - fill_DRB_configList_e1(&DRB_configList, pdu); - } - create_tunnel_req.num_tunnels = req->numPDUSessions; - create_tunnel_req.ue_id = req->gNB_cu_cp_ue_id; - - // Create N3 tunnel - int ret = gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, create_tunnel_resp, nr_pdcp_data_req_drb, sdap_data_req); - if (ret != 0) { - LOG_E(NR_RRC, - "drb_config_N3gtpu_create=>gtpv1u_create_ngu_tunnel failed, cannot set up GTP tunnel for data transmissions of UE %ld\n", - create_tunnel_req.ue_id); - return ret; - } - - // Configure DRBs - nr_pdcp_e1_add_drbs(true, // set this to notify PDCP that his not UE - create_tunnel_req.ue_id, - &DRB_configList, - (req->integrityProtectionAlgorithm << 4) | req->cipheringAlgorithm, - (uint8_t *)req->encryptionKey, - (uint8_t *)req->integrityProtectionKey); - return ret; -} - -void process_e1_bearer_context_setup_req(instance_t instance, e1ap_bearer_setup_req_t *const req) -{ - e1ap_upcp_inst_t *inst = getCxtE1(instance); - AssertFatal(inst, ""); - gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp_N3={0}; - - uint32_t gNB_cu_up_ue_id = req ->gNB_cu_cp_ue_id; - LOG_I(E1AP, "adding UE with CU-CP UE ID %d and CU-UP UE ID %d\n", req->gNB_cu_cp_ue_id, gNB_cu_up_ue_id); - f1_ue_data_t ue_data = {.secondary_ue = req->gNB_cu_cp_ue_id}; - cu_add_f1_ue_data(gNB_cu_up_ue_id, &ue_data); - - // GTP tunnel for UL - drb_config_N3gtpu_create(req, &create_tunnel_resp_N3, inst->gtpInstN3); - - MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_RESP); - e1ap_bearer_setup_resp_t *resp = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg); - - in_addr_t my_addr; - if (inet_pton(AF_INET, inst->setupReq.localAddressF1U, &my_addr) != 1) - LOG_E(E1AP, "can't use the F1-U local interface: %s\n", inst->setupReq.localAddressF1U); - fill_e1ap_bearer_setup_resp(resp, req, inst->gtpInstF1U, req->gNB_cu_cp_ue_id, inst->setupReq.remotePortF1U, my_addr); - - resp->gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id; - resp->gNB_cu_up_ue_id = gNB_cu_up_ue_id; - resp->numPDUSessions = req->numPDUSessions; - for (int i=0; i < req->numPDUSessions; i++) { - pdu_session_setup_t *pduSetup = resp->pduSession + i; - pdu_session_to_setup_t *pdu2Setup = req->pduSession + i; - - pduSetup->id = pdu2Setup->sessionId; - if (inet_pton(AF_INET, inst->setupReq.localAddressN3, &pduSetup->tlAddress) != 1) - LOG_E(E1AP, "can't use the N3 local interface: %s\n", inst->setupReq.localAddressN3); - pduSetup->teId = create_tunnel_resp_N3.gnb_NGu_teid[i]; - pduSetup->numDRBSetup = pdu2Setup->numDRB2Setup; - - // At this point we don't have a way to know the DRBs that failed to setup - // We assume all DRBs to setup have are setup successfully so we always send successful outcome in response - // TODO: Modify nr_pdcp_add_drbs() to return DRB list that failed to setup to support E1AP - pduSetup->numDRBFailed = 0; - } - - e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(inst, resp); -} - -void CUUP_process_bearer_context_mod_req(instance_t instance, e1ap_bearer_setup_req_t *const req) -{ - e1ap_upcp_inst_t *inst = getCxtE1(instance); - AssertFatal(inst, ""); - // assume we receive modification of F1-U but it is wrong, we can also get modification of N3 when HO will occur - CU_update_UP_DL_tunnel(req, inst->gtpInstF1U, req->gNB_cu_cp_ue_id); - // TODO: send bearer cxt mod response -} - -void CUUP_process_bearer_release_command(instance_t instance, e1ap_bearer_release_cmd_t *const cmd) -{ - e1ap_upcp_inst_t *inst = getCxtE1(instance); - AssertFatal(inst, ""); - newGtpuDeleteAllTunnels(inst->gtpInstN3, cmd->gNB_cu_up_ue_id); - newGtpuDeleteAllTunnels(inst->gtpInstF1U, cmd->gNB_cu_up_ue_id); - e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(inst, cmd); -} diff --git a/openair2/E1AP/e1ap_asnc.h b/openair2/E1AP/e1ap_asnc.h index 00dbcc13f3..ed5d1817a8 100644 --- a/openair2/E1AP/e1ap_asnc.h +++ b/openair2/E1AP/e1ap_asnc.h @@ -47,10 +47,14 @@ #include #include #include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -61,5 +65,7 @@ #include #include #include +#include +#include #endif diff --git a/openair2/E1AP/e1ap_common.c b/openair2/E1AP/e1ap_common.c index caf97b680d..cf8982339d 100644 --- a/openair2/E1AP/e1ap_common.c +++ b/openair2/E1AP/e1ap_common.c @@ -37,18 +37,19 @@ e1ap_upcp_inst_t *getCxtE1(instance_t instance) return e1ap_inst[instance]; } -int e1ap_assoc_id(E1_t type, instance_t instance) { - AssertFatal(e1ap_inst[instance] != NULL, "Trying to access uninitiated instance of CUCP\n"); - return e1ap_inst[instance]->setupReq.assoc_id; -} - -void createE1inst(E1_t type, instance_t instance, e1ap_setup_req_t *req) { +void createE1inst(E1_t type, instance_t instance, e1ap_net_config_t *nc, e1ap_setup_req_t *req) +{ AssertFatal(e1ap_inst[instance] == NULL, "Double call to E1 instance %d\n", (int)instance); e1ap_inst[instance] = calloc(1, sizeof(e1ap_upcp_inst_t)); e1ap_inst[instance]->type = type; e1ap_inst[instance]->instance = instance; - if (req) - memcpy(&e1ap_inst[instance]->setupReq, req, sizeof(*req)); + e1ap_inst[instance]->cuup.assoc_id = -1; + if (nc) + memcpy(&e1ap_inst[instance]->net_config, nc, sizeof(*nc)); + if (req) { + AssertFatal(type == UPtype, "E1 setup request only to be stored for CU-UP\n"); + memcpy(&e1ap_inst[instance]->cuup.setupReq, req, sizeof(*req)); + } e1ap_inst[instance]->gtpInstN3 = -1; e1ap_inst[instance]->gtpInstF1U = -1; } @@ -59,8 +60,8 @@ void e1ap_common_init() { srand(time(NULL)); } -bool check_transac_id(E1AP_TransactionID_t id, int *freeIdx) { - +static bool check_transac_id(E1AP_TransactionID_t id, int *freeIdx) +{ bool isFreeIdxSet = false; for (int i=0; i < E1AP_MAX_NUM_TRANSAC_IDS; i++) { if (id == transacID[i]) @@ -74,10 +75,10 @@ bool check_transac_id(E1AP_TransactionID_t id, int *freeIdx) { return true; } -E1AP_TransactionID_t E1AP_get_next_transaction_identifier() { +long E1AP_get_next_transaction_identifier() { E1AP_TransactionID_t genTransacId; bool isTransacIdValid = false; - int freeIdx; + int freeIdx = 0; while (!isTransacIdValid) { genTransacId = rand() & 255; @@ -89,7 +90,7 @@ E1AP_TransactionID_t E1AP_get_next_transaction_identifier() { return genTransacId; } -void E1AP_free_transaction_identifier(E1AP_TransactionID_t id) { +void E1AP_free_transaction_identifier(long id) { for (int i=0; i < E1AP_MAX_NUM_TRANSAC_IDS; i++) { if (id == transacID[i]) { @@ -116,6 +117,9 @@ int e1ap_decode_initiating_message(E1AP_E1AP_PDU_t *pdu) { case E1AP_ProcedureCode_id_bearerContextModification: break; + case E1AP_ProcedureCode_id_bearerContextRelease: + break; + default: LOG_E(E1AP, "Unsupported procedure code (%d) for initiating message\n", (int)pdu->choice.initiatingMessage->procedureCode); @@ -133,6 +137,12 @@ int e1ap_decode_successful_outcome(E1AP_E1AP_PDU_t *pdu) { case E1AP_ProcedureCode_id_bearerContextSetup: break; + case E1AP_ProcedureCode_id_bearerContextModification: + break; + + case E1AP_ProcedureCode_id_bearerContextRelease: + break; + default: LOG_E(E1AP, "Unsupported procedure code (%d) for successful message\n", (int)pdu->choice.successfulOutcome->procedureCode); @@ -195,7 +205,7 @@ int e1ap_decode_pdu(E1AP_E1AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t return -1; } -int e1ap_encode_send(E1_t type, e1ap_setup_req_t *setupReq, E1AP_E1AP_PDU_t *pdu, uint16_t stream, const char *func) +int e1ap_encode_send(E1_t type, sctp_assoc_t assoc_id, E1AP_E1AP_PDU_t *pdu, uint16_t stream, const char *func) { DevAssert(pdu != NULL); @@ -223,11 +233,11 @@ int e1ap_encode_send(E1_t type, e1ap_setup_req_t *setupReq, E1AP_E1AP_PDU_t *pdu } MessageDef *message = itti_alloc_new_message((type == CPtype) ? TASK_CUCP_E1 : TASK_CUUP_E1, 0, SCTP_DATA_REQ); sctp_data_req_t *s = &message->ittiMsg.sctp_data_req; - s->assoc_id = setupReq->assoc_id; + s->assoc_id = assoc_id; s->buffer = buffer; s->buffer_length = encoded; s->stream = stream; - LOG_I(E1AP, "%s: Sending ITTI message to SCTP Task\n", func); + LOG_D(E1AP, "%s: Sending ITTI message to SCTP Task\n", func); itti_send_msg_to_task(TASK_SCTP, 0 /*unused by callee*/, message); return encoded; diff --git a/openair2/E1AP/e1ap_common.h b/openair2/E1AP/e1ap_common.h index cddf5b9ea6..e0aea6990f 100644 --- a/openair2/E1AP/e1ap_common.h +++ b/openair2/E1AP/e1ap_common.h @@ -24,41 +24,39 @@ #ifndef E1AP_COMMON_H_ #define E1AP_COMMON_H_ #include "openair2/COMMON/e1ap_messages_types.h" -#include "e1ap_asnc.h" #include "openair2/COMMON/sctp_messages_types.h" #include "common/ngran_types.h" typedef struct e1ap_upcp_inst_s { - bool incoming_sock; instance_t instance; - bool same_process; E1_t type; enum sctp_state_e sockState; - sctp_assoc_t assoc_id; + struct { + sctp_assoc_t assoc_id; + e1ap_setup_req_t setupReq; + } cuup; instance_t gtpInstN3; instance_t gtpInstF1U; - e1ap_setup_req_t setupReq; - e1ap_bearer_setup_req_t bearerSetupReq; - e1ap_bearer_setup_resp_t bearerSetupResp; + e1ap_net_config_t net_config; } e1ap_upcp_inst_t; extern int asn1_xer_print; -int e1ap_decode_pdu(E1AP_E1AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length); +// forward declaration so we don't require E1AP ASN.1 when including this +// header +struct E1AP_E1AP_PDU; +int e1ap_decode_pdu(struct E1AP_E1AP_PDU *pdu, const uint8_t *const buffer, uint32_t length); e1ap_upcp_inst_t *getCxtE1(instance_t instance); -E1AP_TransactionID_t E1AP_get_next_transaction_identifier(); +long E1AP_get_next_transaction_identifier(); +void E1AP_free_transaction_identifier(long id); -void createE1inst(E1_t type, instance_t instance, e1ap_setup_req_t *req); +void createE1inst(E1_t type, instance_t instance, e1ap_net_config_t *nc, e1ap_setup_req_t *req); -bool check_transac_id(E1AP_TransactionID_t id, int *freeIdx); - -int e1ap_assoc_id(E1_t type, instance_t instance); - -int e1ap_encode_send(E1_t type, e1ap_setup_req_t *setupReq, E1AP_E1AP_PDU_t *pdu, uint16_t stream, const char *func); +int e1ap_encode_send(E1_t type, sctp_assoc_t assoc_id, struct E1AP_E1AP_PDU *pdu, uint16_t stream, const char *func); void e1ap_common_init(); +void cuup_init_n3(instance_t instance); -void E1AP_free_transaction_identifier(E1AP_TransactionID_t id); #endif /* E1AP_COMMON_H_ */ diff --git a/openair2/E1AP/e1ap_setup.c b/openair2/E1AP/e1ap_setup.c index da643636fc..f2b9d05503 100644 --- a/openair2/E1AP/e1ap_setup.c +++ b/openair2/E1AP/e1ap_setup.c @@ -68,7 +68,7 @@ static void get_NGU_S1U_addr(char **addr, uint16_t *port) MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process) { - MessageDef *msgConfig = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_SETUP_REQ); + MessageDef *msgConfig = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_REGISTER_REQ); if (!msgConfig) return NULL; @@ -85,9 +85,11 @@ MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process) config_getlist(&GNBParamList, GNBParams, sizeofArray(GNBParams), NULL); paramdef_t *gnbParms = GNBParamList.paramarray[0]; AssertFatal(gnbParms[GNB_GNB_ID_IDX].uptr != NULL, "gNB id %d is not defined in configuration file\n", 0); - e1ap_setup_req_t *e1Setup = &E1AP_SETUP_REQ(msgConfig); + e1ap_setup_req_t *e1Setup = &E1AP_REGISTER_REQ(msgConfig).setup_req; msgConfig->ittiMsgHeader.destinationInstance = 0; e1Setup->gNB_cu_up_id = *(gnbParms[GNB_GNB_ID_IDX].uptr); + if (*gnbParms[GNB_GNB_NAME_IDX].strptr) + e1Setup->gNB_cu_up_name = *(gnbParms[GNB_GNB_NAME_IDX].strptr); paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; @@ -102,27 +104,41 @@ MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process) e1Setup->supported_plmns = numPLMNs; for (int I = 0; I < numPLMNs; I++) { - e1Setup->plmns[I].mcc = *PLMNParamList.paramarray[I][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - e1Setup->plmns[I].mnc = *PLMNParamList.paramarray[I][GNB_MOBILE_NETWORK_CODE_IDX].uptr; - e1Setup->plmns[I].mnc = *PLMNParamList.paramarray[I][GNB_MNC_DIGIT_LENGTH].u8ptr; + e1Setup->plmn[I].id.mcc = *PLMNParamList.paramarray[I][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + e1Setup->plmn[I].id.mnc = *PLMNParamList.paramarray[I][GNB_MOBILE_NETWORK_CODE_IDX].uptr; + e1Setup->plmn[I].id.mnc_digit_length = *PLMNParamList.paramarray[I][GNB_MNC_DIGIT_LENGTH].uptr; + + char snssaistr[MAX_OPTNAME_SIZE*2 + 8]; + sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_PLMN_LIST, I); + paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0}; + paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC; + config_getlist(&SNSSAIParamList, SNSSAIParams, sizeof(SNSSAIParams)/sizeof(paramdef_t), snssaistr); + e1Setup->plmn[I].supported_slices = SNSSAIParamList.numelt; + e1Setup->plmn[I].slice = calloc(SNSSAIParamList.numelt, sizeof(*e1Setup->plmn[I].slice)); + AssertFatal(e1Setup->plmn[I].slice != NULL, "out of memory\n"); + for (int s = 0; s < SNSSAIParamList.numelt; ++s) { + e1ap_nssai_t *slice = &e1Setup->plmn[I].slice[s]; + slice->sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr; + slice->sd = *SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr; + } } - e1Setup->remotePortF1U = *(GNBParamList.paramarray[0][GNB_REMOTE_S_PORTD_IDX].uptr); - e1Setup->localAddressF1U = strdup(*(GNBParamList.paramarray[0][GNB_LOCAL_S_ADDRESS_IDX].strptr)); - e1Setup->localPortF1U = *(GNBParamList.paramarray[0][GNB_LOCAL_S_PORTD_IDX].uptr); - get_NGU_S1U_addr(&e1Setup->localAddressN3, &e1Setup->localPortN3); - e1Setup->remotePortN3 = e1Setup->localPortN3 ; + e1ap_net_config_t *e1ap_nc = &E1AP_REGISTER_REQ(msgConfig).net_config; + e1ap_nc->remotePortF1U = *(GNBParamList.paramarray[0][GNB_REMOTE_S_PORTD_IDX].uptr); + e1ap_nc->localAddressF1U = strdup(*(GNBParamList.paramarray[0][GNB_LOCAL_S_ADDRESS_IDX].strptr)); + e1ap_nc->localPortF1U = *(GNBParamList.paramarray[0][GNB_LOCAL_S_PORTD_IDX].uptr); + get_NGU_S1U_addr(&e1ap_nc->localAddressN3, &e1ap_nc->localPortN3); + e1ap_nc->remotePortN3 = e1ap_nc->localPortN3 ; if (separate_CUUP_process) { paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0}; paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC; config_getlist(&GNBE1ParamList, GNBE1Params, sizeofArray(GNBE1Params), aprefix); paramdef_t *e1Parms = GNBE1ParamList.paramarray[0]; - strcpy(e1Setup->CUCP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUCP].strptr)); - e1Setup->CUCP_e1_ip_address.ipv4 = 1; - strcpy(e1Setup->CUUP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUUP].strptr)); - e1Setup->CUUP_e1_ip_address.ipv4 = 1; - e1Setup->cn_support = *e1Parms[GNB_CONFIG_E1_CN_SUPPORT].uptr; + strcpy(e1ap_nc->CUCP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUCP].strptr)); + e1ap_nc->CUCP_e1_ip_address.ipv4 = 1; + strcpy(e1ap_nc->CUUP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUUP].strptr)); + e1ap_nc->CUUP_e1_ip_address.ipv4 = 1; } } return msgConfig; diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c index 2d47398d51..3d1f0b6aac 100644 --- a/openair2/F1AP/f1ap_cu_task.c +++ b/openair2/F1AP/f1ap_cu_task.c @@ -45,6 +45,7 @@ static instance_t cu_task_create_gtpu_instance(eth_params_t *IPaddrs) { openAddr_t tmp= {0}; strncpy(tmp.originHost, IPaddrs->my_addr, sizeof(tmp.originHost)-1); sprintf(tmp.originService, "%d", IPaddrs->my_portd); + sprintf(tmp.destinationService, "%d", IPaddrs->remote_portd); return gtpv1Init(tmp); } diff --git a/openair2/F1AP/f1ap_ids.h b/openair2/F1AP/f1ap_ids.h index 96b146f6ba..60d35de737 100644 --- a/openair2/F1AP/f1ap_ids.h +++ b/openair2/F1AP/f1ap_ids.h @@ -27,10 +27,13 @@ #include #include +#include +#include +#include typedef struct f1_ue_data_t { uint32_t secondary_ue; - /* can be extended with F1-specific data also relevant for monolithic */ + sctp_assoc_t e1_assoc_id; } f1_ue_data_t; void cu_init_f1_ue_data(void); diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c index cd701f01f5..74a8a997bd 100644 --- a/openair2/GNB_APP/gnb_app.c +++ b/openair2/GNB_APP/gnb_app.c @@ -147,10 +147,10 @@ void *gNB_app_task(void *args_p) if (itti_create_task(TASK_CUCP_E1, E1AP_CUCP_task, NULL) < 0) AssertFatal(false, "Create task for E1AP CP failed\n"); MessageDef *msg = RCconfig_NR_CU_E1(true); - if (msg) - itti_send_msg_to_task(TASK_CUCP_E1, 0, msg); - else - AssertFatal(false, "Send inti to task for E1AP CP failed\n"); + AssertFatal(msg != NULL, "Send inti to task for E1AP CP failed\n"); + // this sends the E1AP_REGISTER_REQ to CU-CP so it sets up the socket + // it does NOT use the E1AP part + itti_send_msg_to_task(TASK_CUCP_E1, 0, msg); } if (node_type == ngran_gNB_CUUP) { diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index e190b21748..64fa933970 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1523,7 +1523,7 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc) char aprefix[MAX_OPTNAME_SIZE*2 + 8]; sprintf(aprefix,"%s.[%u].%s",GNB_CONFIG_STRING_GNB_LIST,i,GNB_CONFIG_STRING_SCTP_CONFIG); config_get(SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix); - rrc->node_id = *(GNBParamList.paramarray[0][GNB_GNB_ID_IDX].uptr); + rrc->node_id = gnb_id; LOG_I(GNB_APP,"F1AP: gNB_CU_id[%d] %d\n",k,rrc->node_id); rrc->node_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr)); LOG_I(GNB_APP,"F1AP: gNB_CU_name[%d] %s\n",k,rrc->node_name); @@ -1541,7 +1541,6 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc) rrc->nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr); - rrc->um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr); if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_mac") == 0) { } else if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "cudu") == 0) { @@ -1575,7 +1574,6 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc) for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I) PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); - nrrrc_config.cell_identity = gnb_id; nrrrc_config.tac = *GNBParamList.paramarray[i][GNB_TRACKING_AREA_CODE_IDX].uptr; AssertFatal(!GNBParamList.paramarray[i][GNB_MOBILE_COUNTRY_CODE_IDX_OLD].strptr && !GNBParamList.paramarray[i][GNB_MOBILE_NETWORK_CODE_IDX_OLD].strptr, @@ -1606,6 +1604,7 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc) nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr; LOG_I(GNB_APP, "SDAP layer is %s\n", nrrrc_config.enable_sdap ? "enabled" : "disabled"); nrrrc_config.drbs = *GNBParamList.paramarray[i][GNB_DRBS].iptr; + nrrrc_config.um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr); LOG_I(GNB_APP, "Data Radio Bearer count %d\n", nrrrc_config.drbs); }// diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index d59ecb9eb3..4ce9da2124 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -161,7 +161,7 @@ typedef enum { {GNB_CONFIG_STRING_NRCELLID, NULL, 0, .u64ptr=NULL,.defint64val=1, TYPE_UINT64, 0}, \ {GNB_CONFIG_STRING_MINRXTXTIME, NULL, 0, .iptr=NULL, .defintval=2, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, .strptr=NULL,.defstrval="", TYPE_STRING, 0}, \ -{GNB_CONFIG_STRING_UMONDEFAULTDRB, NULL, 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ +{GNB_CONFIG_STRING_UMONDEFAULTDRB, NULL, PARAMFLAG_BOOL, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ {GNB_CONFIG_STRING_FORCE256QAMOFF, GNB_CONFIG_HLP_FORCE256QAMOFF, PARAMFLAG_BOOL, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_ENABLE_SDAP, GNB_CONFIG_HLP_STRING_ENABLE_SDAP, PARAMFLAG_BOOL,.iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_DRBS, GNB_CONFIG_HLP_STRING_DRBS, 0, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \ @@ -376,19 +376,16 @@ typedef enum { #define GNB_CONFIG_E1_CU_TYPE_IDX 0 #define GNB_CONFIG_E1_IPV4_ADDRESS_CUCP 1 #define GNB_CONFIG_E1_IPV4_ADDRESS_CUUP 2 -#define GNB_CONFIG_E1_CN_SUPPORT 3 #define GNB_CONFIG_STRING_E1_CU_TYPE "type" #define GNB_CONFIG_STRING_E1_IPV4_ADDRESS_CUCP "ipv4_cucp" #define GNB_CONFIG_STRING_E1_IPV4_ADDRESS_CUUP "ipv4_cuup" -#define GNB_CONFIG_STRING_E1_CN_SUPPORT "cn_support" // clang-format off #define GNBE1PARAMS_DESC { \ {GNB_CONFIG_STRING_E1_CU_TYPE, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_E1_IPV4_ADDRESS_CUCP, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_E1_IPV4_ADDRESS_CUUP, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \ - {GNB_CONFIG_STRING_E1_CN_SUPPORT, NULL, 0, .uptr =NULL, .defintval=1L, TYPE_UINT, 0} \ } // clang-format on /* L1 configuration section names */ diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index b4ec1cb9eb..77c6fd6c8d 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -96,7 +96,7 @@ NR_UE_MAC_INST_t * nr_l2_init_ue(NR_UE_RRC_INST_t* rrc_inst) { fill_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig); // set up PDCP, RLC, MAC - nr_pdcp_layer_init(); + nr_pdcp_layer_init(false); nr_pdcp_add_drbs(ENB_FLAG_NO, nr_ue_mac_inst->crnti, rbconfig->drb_ToAddModList, 0, NULL, NULL); nr_rlc_add_drb(nr_ue_mac_inst->crnti, rbconfig->drb_ToAddModList->list.array[0]->drb_Identity, rlc_rbconfig); struct NR_CellGroupConfig__rlc_BearerToAddModList rlc_toadd_list; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h index b90e490302..62a4ae0248 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h @@ -16,7 +16,7 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ #ifndef MAC_RRC_UL_H diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index 905b9255e4..ab3b7646e7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -16,7 +16,7 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ #include "nr_mac_gNB.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index b98de08a0d..8ee2913e0c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -16,7 +16,7 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ #include diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index d0ee9587ef..fba6dde507 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -271,7 +271,7 @@ void mac_top_init_gNB(ngran_node_t node_type, AssertFatal(rlc_module_init(1) == 0,"Could not initialize RLC layer\n"); // These should be out of here later - if (get_softmodem_params()->usim_test == 0 ) nr_pdcp_layer_init(); + if (get_softmodem_params()->usim_test == 0 ) nr_pdcp_layer_init(false); if(IS_SOFTMODEM_NOS1 && get_softmodem_params()->phy_test) { // get default noS1 configuration diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c new file mode 100644 index 0000000000..7e00b0ee8d --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -0,0 +1,280 @@ +/* + * 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 "cucp_cuup_handler.h" + +#include "NR_DRB-ToAddModList.h" + +#include "platform_types.h" +#include "intertask_interface.h" +#include "openair2/COMMON/e1ap_messages_types.h" +#include "openair3/ocp-gtpu/gtp_itf.h" +#include "openair2/F1AP/f1ap_ids.h" +#include "nr_pdcp_oai_api.h" +#include "cuup_cucp_if.h" +#include "common/utils/oai_asn1.h" +#include "openair2/SDAP/nr_sdap/nr_sdap.h" +#include "openair2/E1AP/e1ap_common.h" +#include "openair2/F1AP/f1ap_common.h" + +static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, const pdu_session_to_setup_t *pdu) +{ + for (int i=0; i < pdu->numDRB2Setup; i++) { + const DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + i; + asn1cSequenceAdd(DRB_configList->list, struct NR_DRB_ToAddMod, ie); + ie->drb_Identity = drb->id; + ie->cnAssociation = CALLOC(1, sizeof(*ie->cnAssociation)); + ie->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config; + + // sdap_Config + asn1cCalloc(ie->cnAssociation->choice.sdap_Config, sdap_config); + sdap_config->pdu_Session = pdu->sessionId; + sdap_config->sdap_HeaderDL = drb->sDAP_Header_DL; + sdap_config->sdap_HeaderUL = drb->sDAP_Header_UL; + sdap_config->defaultDRB = drb->defaultDRB; + + asn1cCalloc(sdap_config->mappedQoS_FlowsToAdd, FlowsToAdd); + for (int j=0; j < drb->numQosFlow2Setup; j++) { + asn1cSequenceAdd(FlowsToAdd->list, NR_QFI_t, id); + *id = drb->qosFlows[j].id; + } + sdap_config->mappedQoS_FlowsToRelease = NULL; + + // pdcp_Config + ie->reestablishPDCP = NULL; + ie->recoverPDCP = NULL; + asn1cCalloc(ie->pdcp_Config, pdcp_config); + asn1cCalloc(pdcp_config->drb, drbCfg); + asn1cCallocOne(drbCfg->discardTimer, drb->discardTimer); + asn1cCallocOne(drbCfg->pdcp_SN_SizeUL, drb->pDCP_SN_Size_UL); + asn1cCallocOne(drbCfg->pdcp_SN_SizeDL, drb->pDCP_SN_Size_DL); + drbCfg->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; + drbCfg->headerCompression.choice.notUsed = 0; + + drbCfg->integrityProtection = NULL; + drbCfg->statusReportRequired = NULL; + drbCfg->outOfOrderDelivery = NULL; + pdcp_config->moreThanOneRLC = NULL; + + pdcp_config->t_Reordering = calloc(1, sizeof(*pdcp_config->t_Reordering)); + *pdcp_config->t_Reordering = drb->reorderingTimer; + pdcp_config->ext1 = NULL; + + if (pdu->integrityProtectionIndication == 0 || // Required + pdu->integrityProtectionIndication == 1) { // Preferred + asn1cCallocOne(drbCfg->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled); + } + + if (pdu->confidentialityProtectionIndication == 2) { // Not Needed + asn1cCalloc(pdcp_config->ext1, ext1); + asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true); + } + } +} + +static int drb_gtpu_create(instance_t instance, + uint32_t ue_id, + int incoming_id, + int outgoing_id, + int qfi, + in_addr_t tlAddress, // only IPv4 now + teid_t outgoing_teid, + gtpCallback callBack, + gtpCallbackSDAP callBackSDAP, + gtpv1u_gnb_create_tunnel_resp_t *create_tunnel_resp) +{ + gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0}; + create_tunnel_req.incoming_rb_id[0] = incoming_id; + create_tunnel_req.pdusession_id[0] = outgoing_id; + memcpy(&create_tunnel_req.dst_addr[0].buffer, &tlAddress, sizeof(uint8_t) * 4); + create_tunnel_req.dst_addr[0].length = 32; + create_tunnel_req.outgoing_teid[0] = outgoing_teid; + create_tunnel_req.outgoing_qfi[0] = qfi; + create_tunnel_req.num_tunnels = 1; + create_tunnel_req.ue_id = ue_id; + + // we use gtpv1u_create_ngu_tunnel because it returns the interface + // address and port of the interface; apart from that, we also might call + // newGtpuCreateTunnel() directly + return gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, create_tunnel_resp, callBack, callBackSDAP); +} + +static instance_t get_n3_gtp_instance(void) +{ + const e1ap_upcp_inst_t *inst = getCxtE1(0); + AssertFatal(inst != NULL, "need to have E1 instance\n"); + return inst->gtpInstN3; +} + +static instance_t get_f1_gtp_instance(void) +{ + const f1ap_cudu_inst_t *inst = getCxt(0); + if (!inst) + return -1; // means no F1 + return inst->gtpInst; +} + +void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) +{ + /* mirror the CU-CP UE ID for CU-UP */ + uint32_t cu_up_ue_id = req->gNB_cu_cp_ue_id; + f1_ue_data_t ued = {.secondary_ue = req->gNB_cu_cp_ue_id}; + cu_add_f1_ue_data(cu_up_ue_id, &ued); + LOG_I(E1AP, "adding UE with CU-CP UE ID %d and CU-UP UE ID %d\n", req->gNB_cu_cp_ue_id, cu_up_ue_id); + + instance_t n3inst = get_n3_gtp_instance(); + instance_t f1inst = get_f1_gtp_instance(); + + e1ap_bearer_setup_resp_t resp = { + .gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id, + .gNB_cu_up_ue_id = cu_up_ue_id, + }; + resp.numPDUSessions = req->numPDUSessions; + for (int i = 0; i < resp.numPDUSessions; ++i) { + pdu_session_setup_t *resp_pdu = resp.pduSession + i; + 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]; + DRB_nGRAN_setup_t *resp_drb = &resp_pdu->DRBnGRanList[0]; + resp_drb->id = req_drb->id; + resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup; + for (int k = 0; k < resp_drb->numQosFlowSetup; k++) + resp_drb->qosFlows[k].id = req_drb->qosFlows[k].id; + + // GTP tunnel for N3/to core + gtpv1u_gnb_create_tunnel_resp_t resp_n3 = {0}; + int qfi = 0; // put PDU session marker + int ret = drb_gtpu_create(n3inst, + cu_up_ue_id, + req_drb->id, + req_pdu->sessionId, + qfi, + req_pdu->tlAddress, + req_pdu->teId, + nr_pdcp_data_req_drb, + sdap_data_req, + &resp_n3); + AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n"); + AssertFatal(resp_n3.num_tunnels == req->numPDUSessions, "could not create all tunnels\n"); + resp_pdu->teId = resp_n3.gnb_NGu_teid[i]; + memcpy(&resp_pdu->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_add_drbs(true, // set this to notify PDCP that his not UE + cu_up_ue_id, + &DRB_configList, + (req->integrityProtectionAlgorithm << 4) | req->cipheringAlgorithm, + (uint8_t *)req->encryptionKey, + (uint8_t *)req->integrityProtectionKey); + + if (f1inst >= 0) { /* we have F1(-U) */ + teid_t dummy_teid = 0xffff; // we will update later with answer from DU + in_addr_t dummy_address = {0}; // IPv4, updated later with answer from DU + gtpv1u_gnb_create_tunnel_resp_t resp_f1 = {0}; + int qfi = -1; // don't put PDU session marker in GTP + int ret = drb_gtpu_create(f1inst, + cu_up_ue_id, + req_drb->id, + req_drb->id, + qfi, + dummy_address, + dummy_teid, + cu_f1u_data_req, + NULL, + &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]; + } + + // We assume all DRBs to setup have been setup successfully, so we always + // send successful outcome in response and no failed DRBs + resp_pdu->numDRBFailed = 0; + } + + get_e1_if()->bearer_setup_response(&resp); +} + +void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) +{ + AssertFatal(req->numPDUSessionsMod > 0, "need at least one PDU session to modify\n"); + + e1ap_bearer_modif_resp_t modif = { + .gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id, + .gNB_cu_up_ue_id = req->gNB_cu_up_ue_id, + .numPDUSessionsMod = req->numPDUSessionsMod, + }; + + instance_t f1inst = get_f1_gtp_instance(); + + for (int i=0; i < req->numPDUSessionsMod; i++) { + LOG_I(E1AP, + "UE %d: updating PDU session ID %ld (%ld bearers)\n", + req->gNB_cu_up_ue_id, + req->pduSessionMod[i].sessionId, + req->pduSessionMod[i].numDRB2Modify); + modif.pduSessionMod[i].id = req->pduSessionMod[i].sessionId; + modif.pduSessionMod[i].numDRBModified = req->pduSessionMod[i].numDRB2Modify; + for (int j=0; j < req->pduSessionMod[i].numDRB2Modify; j++) { + const DRB_nGRAN_to_setup_t *to_modif = &req->pduSessionMod[i].DRBnGRanModList[j]; + DRB_nGRAN_modified_t *modified = &modif.pduSessionMod[i].DRBnGRanModList[j]; + modified->id = to_modif->id; + + if (f1inst < 0) // no F1-U? + continue; // nothing to do + + in_addr_t addr = {0}; + memcpy(&addr, &to_modif->DlUpParamList[0].tlAddress, sizeof(in_addr_t)); + + GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[0].teId); + } + } + + get_e1_if()->bearer_modif_response(&modif); +} + +void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) +{ + instance_t n3inst = get_n3_gtp_instance(); + instance_t f1inst = get_f1_gtp_instance(); + + LOG_I(E1AP, "releasing UE %d\n", cmd->gNB_cu_up_ue_id); + + newGtpuDeleteAllTunnels(n3inst, cmd->gNB_cu_up_ue_id); + if (f1inst >= 0) // is there F1-U? + newGtpuDeleteAllTunnels(f1inst, cmd->gNB_cu_up_ue_id); + nr_pdcp_remove_UE(cmd->gNB_cu_up_ue_id); + cu_remove_f1_ue_data(cmd->gNB_cu_up_ue_id); + + e1ap_bearer_release_cplt_t cplt = { + .gNB_cu_cp_ue_id = cmd->gNB_cu_cp_ue_id, + .gNB_cu_up_ue_id = cmd->gNB_cu_up_ue_id, + }; + + get_e1_if()->bearer_release_complete(&cplt); +} diff --git a/openair2/E1AP/e1ap_api.h b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h similarity index 66% rename from openair2/E1AP/e1ap_api.h rename to openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h index 1b9f219fcc..7290043371 100644 --- a/openair2/E1AP/e1ap_api.h +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h @@ -9,8 +9,6 @@ * * http://www.openairinterface.org/?page_id=698 * - * Author and copyright: Laurent Thomas, open-cells.com - * * 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. @@ -21,15 +19,17 @@ * contact@openairinterface.org */ -#ifndef E1AP_API_H -#define E1AP_API_H +#ifndef CUCP_CUUP_HANDLER_H +#define CUCP_CUUP_HANDLER_H -#include "platform_types.h" -#include "openair2/COMMON/e1ap_messages_types.h" -#include "openair2/E1AP/e1ap_common.h" -void cuup_init_n3(instance_t instance); -void process_e1_bearer_context_setup_req(instance_t, e1ap_bearer_setup_req_t *const req); -void CUUP_process_bearer_context_mod_req(instance_t, e1ap_bearer_setup_req_t *const req); +#include -void CUUP_process_bearer_release_command(instance_t, e1ap_bearer_release_cmd_t *const cmd); -#endif +void nr_pdcp_e1_if_init(bool uses_e1); + +struct e1ap_bearer_setup_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_release_cmd(const struct e1ap_bearer_release_cmd_s *cmd); + +#endif /* CUCP_CUUP_HANDLER_H */ diff --git a/openair2/LAYER2/nr_pdcp/cuup_cucp_direct.c b/openair2/LAYER2/nr_pdcp/cuup_cucp_direct.c new file mode 100644 index 0000000000..b6ad66e18c --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/cuup_cucp_direct.c @@ -0,0 +1,55 @@ +/* + * 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 "cuup_cucp_if.h" +#include "e1ap_messages_types.h" +#include "intertask_interface.h" + +static void bearer_setup_response_direct(const e1ap_bearer_setup_resp_t *resp) +{ + MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, E1AP_BEARER_CONTEXT_SETUP_RESP); + e1ap_bearer_setup_resp_t *msg_resp = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg); + *msg_resp = *resp; + itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); +} + +static void bearer_modif_response_direct(const e1ap_bearer_modif_resp_t *resp) +{ + MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, E1AP_BEARER_CONTEXT_MODIFICATION_RESP); + e1ap_bearer_modif_resp_t *msg_resp = &E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg); + *msg_resp = *resp; + itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); +} + +static void bearer_release_complete_direct(const e1ap_bearer_release_cplt_t *cplt) +{ + MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, E1AP_BEARER_CONTEXT_RELEASE_CPLT); + e1ap_bearer_release_cplt_t *msg_cplt = &E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg); + *msg_cplt = *cplt; + itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); +} + +void cuup_cucp_init_direct(e1_if_t *iface) +{ + iface->bearer_setup_response = bearer_setup_response_direct; + iface->bearer_modif_response = bearer_modif_response_direct; + iface->bearer_release_complete = bearer_release_complete_direct; +} diff --git a/openair2/LAYER2/nr_pdcp/cuup_cucp_e1ap.c b/openair2/LAYER2/nr_pdcp/cuup_cucp_e1ap.c new file mode 100644 index 0000000000..8454d5a7d8 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/cuup_cucp_e1ap.c @@ -0,0 +1,55 @@ +/* + * 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 "cuup_cucp_if.h" +#include "intertask_interface.h" +#include "e1ap_messages_types.h" + +static void bearer_setup_response_e1ap(const e1ap_bearer_setup_resp_t *resp) +{ + MessageDef *msg_p = itti_alloc_new_message(TASK_CUUP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_RESP); + e1ap_bearer_setup_resp_t *bearer_resp = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p); + *bearer_resp = *resp; + itti_send_msg_to_task (TASK_CUUP_E1, 0, msg_p); +} + +static void bearer_modif_response_e1ap(const e1ap_bearer_modif_resp_t *resp) +{ + MessageDef *msg_p = itti_alloc_new_message(TASK_CUUP_E1, 0, E1AP_BEARER_CONTEXT_MODIFICATION_RESP); + e1ap_bearer_modif_resp_t *modif_resp = &E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg_p); + *modif_resp = *resp; + itti_send_msg_to_task (TASK_CUUP_E1, 0, msg_p); +} + +static void bearer_release_complete_e1ap(const e1ap_bearer_release_cplt_t *cplt) +{ + MessageDef *msg_p = itti_alloc_new_message(TASK_CUUP_E1, 0, E1AP_BEARER_CONTEXT_RELEASE_CPLT); + e1ap_bearer_release_cplt_t *msg_cplt = &E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg_p); + *msg_cplt = *cplt; + itti_send_msg_to_task (TASK_CUUP_E1, 0, msg_p); +} + +void cuup_cucp_init_e1ap(e1_if_t *iface) +{ + iface->bearer_setup_response = bearer_setup_response_e1ap; + iface->bearer_modif_response = bearer_modif_response_e1ap; + iface->bearer_release_complete = bearer_release_complete_e1ap; +} diff --git a/openair2/LAYER2/nr_pdcp/cuup_cucp_if.c b/openair2/LAYER2/nr_pdcp/cuup_cucp_if.c new file mode 100644 index 0000000000..ddeb59205e --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/cuup_cucp_if.c @@ -0,0 +1,37 @@ +/* + * 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 "cuup_cucp_if.h" + +static e1_if_t e1_if; + +e1_if_t *get_e1_if(void) +{ + return &e1_if; +} + +void nr_pdcp_e1_if_init(bool uses_e1) +{ + if (uses_e1) + cuup_cucp_init_e1ap(&e1_if); + else + cuup_cucp_init_direct(&e1_if); +} diff --git a/openair2/LAYER2/nr_pdcp/cuup_cucp_if.h b/openair2/LAYER2/nr_pdcp/cuup_cucp_if.h new file mode 100644 index 0000000000..c33694dac3 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/cuup_cucp_if.h @@ -0,0 +1,46 @@ +/* + * 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 + */ + +#ifndef CUUP_CUCP_IF_H +#define CUUP_CUCP_IF_H + +#include + +struct e1ap_bearer_setup_resp_s; +struct e1ap_bearer_modif_resp_s; +struct e1ap_bearer_release_cplt_s; +typedef void (*e1_bearer_setup_response_func_t)(const struct e1ap_bearer_setup_resp_s *resp); +typedef void (*e1_bearer_modif_response_func_t)(const struct e1ap_bearer_modif_resp_s *resp); +typedef void (*e1_bearer_release_complete_func_t)(const struct e1ap_bearer_release_cplt_s *cplt); + +typedef struct e1_if_t { + e1_bearer_setup_response_func_t bearer_setup_response; + e1_bearer_modif_response_func_t bearer_modif_response; + e1_bearer_release_complete_func_t bearer_release_complete; +} e1_if_t; + +e1_if_t *get_e1_if(void); +void nr_pdcp_e1_if_init(bool uses_e1); + +void cuup_cucp_init_direct(e1_if_t *iface); +void cuup_cucp_init_e1ap(e1_if_t *iface); + +#endif /* CUUP_CUCP_IF_H */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.c deleted file mode 100644 index c7c91a38a0..0000000000 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include "nr_pdcp_e1_api.h" - -void e1_add_drb(int is_gnb, - uint64_t ue_id, - struct NR_DRB_ToAddMod *s, - int ciphering_algorithm, - int integrity_algorithm, - unsigned char *ciphering_key, - unsigned char *integrity_key) -{ - add_drb(is_gnb, ue_id, s, ciphering_algorithm, integrity_algorithm, ciphering_key, integrity_key); - LOG_I(PDCP, "%s:%s:%d: added DRB for UE ID %ld\n", __FILE__, __FUNCTION__, __LINE__, ue_id); -} - -void nr_pdcp_e1_add_drbs(eNB_flag_t enb_flag, - uint64_t ue_id, - NR_DRB_ToAddModList_t *const drb2add_list, - const uint8_t security_modeP, - uint8_t *const kUPenc, - uint8_t *const kUPint) { - - if (drb2add_list != NULL) { - for (int i = 0; i < drb2add_list->list.count; i++) { - e1_add_drb(enb_flag, ue_id, drb2add_list->list.array[i], - security_modeP & 0x0f, (security_modeP >> 4) & 0x0f, - kUPenc, kUPint); - } - } else - LOG_W(PDCP, "%s with void list\n", __FUNCTION__); -} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h deleted file mode 100644 index 3c16996126..0000000000 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include "common/utils/oai_asn1.h" -#include "NR_RadioBearerConfig.h" - -#include "nr_pdcp_oai_api.h" -#include "LAYER2/nr_rlc/nr_rlc_oai_api.h" -#include -#include "openair2/SDAP/nr_sdap/nr_sdap.h" - -void e1_add_drb(int is_gnb, - uint64_t ue_id, - struct NR_DRB_ToAddMod *s, - int ciphering_algorithm, - int integrity_algorithm, - unsigned char *ciphering_key, - unsigned char *integrity_key); - -void nr_pdcp_e1_add_drbs(eNB_flag_t enb_flag, - uint64_t ue_id, - NR_DRB_ToAddModList_t *const drb2add_list, - const uint8_t security_modeP, - uint8_t *const kUPenc, - uint8_t *const kUPint); - -void add_drb_am(int is_gnb, ue_id_t rntiMaybeUEid, struct NR_DRB_ToAddMod *s, - int ciphering_algorithm, - int integrity_algorithm, - unsigned char *ciphering_key, - unsigned char *integrity_key); - diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 21331ee607..eb1367c724 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -39,9 +39,9 @@ #include "openair2/F1AP/f1ap_ids.h" #include #include "openair2/SDAP/nr_sdap/nr_sdap.h" -#include "nr_pdcp_e1_api.h" #include "gnb_config.h" #include "executables/softmodem-common.h" +#include "cuup_cucp_if.h" #define TODO do { \ printf("%s:%d:%s: todo\n", __FILE__, __LINE__, __FUNCTION__); \ @@ -538,7 +538,7 @@ void pdcp_layer_init(void) abort(); } -void nr_pdcp_layer_init(void) +void nr_pdcp_layer_init(bool uses_e1) { /* hack: be sure to initialize only once */ static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; @@ -559,6 +559,7 @@ void nr_pdcp_layer_init(void) init_nr_rlc_data_req_queue(); } + nr_pdcp_e1_if_init(uses_e1); init_nr_pdcp_data_ind_queue(); nr_pdcp_init_timer_thread(nr_pdcp_ue_manager); } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index 6035e34bf4..85e2c4b46b 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -25,7 +25,7 @@ #include "pdcp.h" #include "nr_pdcp_ue_manager.h" -void nr_pdcp_layer_init(void); +void nr_pdcp_layer_init(bool uses_e1); uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id); void du_rlc_data_req(const protocol_ctxt_t *const ctxt_pP, diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h index b233cd502d..8e41bf69d3 100644 --- a/openair2/RRC/LTE/rrc_defs.h +++ b/openair2/RRC/LTE/rrc_defs.h @@ -16,7 +16,7 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ /*! \file RRC/LTE/defs.h diff --git a/openair2/RRC/NR/cucp_cuup_direct.c b/openair2/RRC/NR/cucp_cuup_direct.c index 485edc08a4..ee3555a14b 100644 --- a/openair2/RRC/NR/cucp_cuup_direct.c +++ b/openair2/RRC/NR/cucp_cuup_direct.c @@ -16,204 +16,35 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ -#include - #include "cucp_cuup_if.h" -#include "platform_types.h" + #include "nr_rrc_defs.h" - -#include "softmodem-common.h" -#include "nr_rrc_proto.h" -#include "nr_rrc_extern.h" #include "openair2/COMMON/e1ap_messages_types.h" -#include "openair3/SECU/key_nas_deriver.h" +#include "openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h" -#include "nr_pdcp/nr_pdcp_entity.h" -#include "openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h" -#include -#include "openair3/ocp-gtpu/gtp_itf.h" -#include "rrc_gNB_GTPV1U.h" -#include "common/ran_context.h" -#include "openair2/F1AP/f1ap_common.h" -#include "openair2/E1AP/e1ap_common.h" - -extern RAN_CONTEXT_t RC; - -void fill_e1ap_bearer_setup_resp(e1ap_bearer_setup_resp_t *resp, - e1ap_bearer_setup_req_t *const req, - instance_t gtpInst, - ue_id_t ue_id, - int remote_port, - in_addr_t my_addr) { - - resp->numPDUSessions = req->numPDUSessions; - transport_layer_addr_t dummy_address = {0}; - dummy_address.length = 32; // IPv4 - for (int i=0; i < req->numPDUSessions; i++) { - resp->pduSession[i].numDRBSetup = req->pduSession[i].numDRB2Setup; - for (int j=0; j < req->pduSession[i].numDRB2Setup; j++) { - DRB_nGRAN_to_setup_t *drb2Setup = req->pduSession[i].DRBnGRanList + j; - DRB_nGRAN_setup_t *drbSetup = resp->pduSession[i].DRBnGRanList + j; - - drbSetup->numUpParam = 1; - drbSetup->UpParamList[0].tlAddress = my_addr; - drbSetup->UpParamList[0].teId = newGtpuCreateTunnel(gtpInst, - ue_id, - drb2Setup->id, - drb2Setup->id, - 0xFFFF, // We will set the right value from DU answer - -1, // no qfi - dummy_address, // We will set the right value from DU answer - remote_port, - cu_f1u_data_req, - NULL); - drbSetup->id = drb2Setup->id; - - drbSetup->numQosFlowSetup = drb2Setup->numQosFlow2Setup; - for (int k=0; k < drbSetup->numQosFlowSetup; k++) { - drbSetup->qosFlows[k].id = drb2Setup->qosFlows[k].id; - } - } - } -} - -void CU_update_UP_DL_tunnel(e1ap_bearer_setup_req_t *const req, instance_t instance, ue_id_t ue_id) { - for (int i=0; i < req->numPDUSessionsMod; i++) { - for (int j=0; j < req->pduSessionMod[i].numDRB2Modify; j++) { - DRB_nGRAN_to_setup_t *drb_p = req->pduSessionMod[i].DRBnGRanModList + j; - - in_addr_t addr = {0}; - memcpy(&addr, &drb_p->DlUpParamList[0].tlAddress, sizeof(in_addr_t)); - - GtpuUpdateTunnelOutgoingAddressAndTeid(instance, - (ue_id & 0xFFFF), - (ebi_t)drb_p->id, - addr, - drb_p->DlUpParamList[0].teId); - } - } -} - -static int drb_config_gtpu_create(const protocol_ctxt_t *const ctxt_p, - rrc_gNB_ue_context_t *ue_context_p, - e1ap_bearer_setup_req_t *const req, - NR_DRB_ToAddModList_t *DRB_configList, - instance_t instance) +static void cucp_cuup_bearer_context_setup_direct(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req) { - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req={0}; - gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp={0}; - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - LOG_W(NR_RRC, "recreate existing tunnels, while adding new ones\n"); - for (int i = 0; i < UE->nb_of_pdusessions; i++) { - rrc_pdu_session_param_t *pdu = UE->pduSession + i; - create_tunnel_req.pdusession_id[i] = pdu->param.pdusession_id; - create_tunnel_req.incoming_rb_id[i] = i + 1; - create_tunnel_req.outgoing_qfi[i] = req->pduSession[i].DRBnGRanList[0].qosFlows[0].id; - memcpy(&create_tunnel_req.dst_addr[i].buffer, &pdu->param.upf_addr.buffer, sizeof(create_tunnel_req.dst_addr[0].buffer)); - create_tunnel_req.dst_addr[i].length = pdu->param.upf_addr.length; - create_tunnel_req.outgoing_teid[i] = pdu->param.gtp_teid; - } - create_tunnel_req.num_tunnels = UE->nb_of_pdusessions; - create_tunnel_req.ue_id = UE->rrc_ue_id; - int ret = gtpv1u_create_ngu_tunnel(getCxtE1(instance)->gtpInstN3, - &create_tunnel_req, - &create_tunnel_resp, - nr_pdcp_data_req_drb, - sdap_data_req); - - if (ret != 0) { - LOG_E(NR_RRC, - "drb_config_gtpu_create=>gtpv1u_create_ngu_tunnel failed, cannot set up GTP tunnel for data transmissions of UE %ld\n", - create_tunnel_req.ue_id); - return ret; - } - - nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(ctxt_p, &create_tunnel_resp, 0); - - uint8_t kRRCenc[16] = {0}; - uint8_t kRRCint[16] = {0}; - uint8_t kUPenc[16] = {0}; - uint8_t kUPint[16] = {0}; - /* Derive the keys from kgnb */ - if (DRB_configList != NULL) { - nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kUPenc); - nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, kUPint); - } - - nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kRRCenc); - nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, kRRCint); - - /* Refresh SRBs/DRBs */ - - LOG_D(NR_RRC, "Configuring PDCP DRBs for UE %x\n", UE->rnti); - nr_pdcp_add_drbs(ctxt_p->enb_flag, - UE->rrc_ue_id, - DRB_configList, - (UE->integrity_algorithm << 4) | UE->ciphering_algorithm, - kUPenc, - kUPint); - - return ret; + AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id); + e1_bearer_context_setup(req); } -static void cucp_cuup_bearer_context_setup_direct(e1ap_bearer_setup_req_t *const req, instance_t instance) +static void cucp_cuup_bearer_context_modif_direct(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req) { - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], req->gNB_cu_cp_ue_id); - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - protocol_ctxt_t ctxt = {0}; - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0, 0); - - e1ap_bearer_setup_resp_t resp = {0}; - resp.numPDUSessions = req->numPDUSessions; - for (int i = 0; i < resp.numPDUSessions; ++i) { - resp.pduSession[i].numDRBSetup = req->pduSession[i].numDRB2Setup; - for (int j = 0; j < req->pduSession[i].numDRB2Setup; j++) { - DRB_nGRAN_to_setup_t *req_drb = req->pduSession[i].DRBnGRanList + j; - DRB_nGRAN_setup_t *resp_drb = resp.pduSession[i].DRBnGRanList + j; - resp_drb->id = req_drb->id; - resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup; - for (int k = 0; k < resp_drb->numQosFlowSetup; k++) - resp_drb->qosFlows[k].id = req_drb->qosFlows[k].id; - } - } - - gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; - // GTP tunnel for UL - NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(UE); - int ret = drb_config_gtpu_create(&ctxt, ue_context_p, req, DRB_configList, rrc->e1_inst); - if (ret < 0) AssertFatal(false, "Unable to configure DRB or to create GTP Tunnel\n"); - // the code is very badly organized, it is not possible here to call freeDRBlist() - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList,DRB_configList ); - - // Used to store teids: if monolithic, will simply be NULL - if(!NODE_IS_CU(RC.nrrrc[ctxt.module_id]->node_type)) { - // intentionally empty - } else { - int remote_port = RC.nrrrc[ctxt.module_id]->eth_params_s.remote_portd; - in_addr_t my_addr = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.my_addr); - instance_t gtpInst = getCxt(instance)->gtpInst; - // GTP tunnel for DL - fill_e1ap_bearer_setup_resp(&resp, req, gtpInst, UE->rrc_ue_id, remote_port, my_addr); - } - // actually, we should receive the corresponding context setup response - // message at the RRC and always react to this one. So in the following, we - // just call the corresponding message handler - prepare_and_send_ue_context_modification_f1(ue_context_p, &resp); + AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id); + e1_bearer_context_modif(req); } -static void cucp_cuup_bearer_context_mod_direct(e1ap_bearer_setup_req_t *const req, instance_t instance) +static void cucp_cuup_bearer_context_release_cmd_direct(sctp_assoc_t assoc_id, const e1ap_bearer_release_cmd_t *cmd) { - // only update GTP tunnels if it is really a CU - if (!NODE_IS_CU(RC.nrrrc[0]->node_type)) - return; - instance_t gtpInst = getCxt(instance)->gtpInst; - CU_update_UP_DL_tunnel(req, gtpInst, req->gNB_cu_cp_ue_id); + AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id); + e1_bearer_release_cmd(cmd); } void cucp_cuup_message_transfer_direct_init(gNB_RRC_INST *rrc) { rrc->cucp_cuup.bearer_context_setup = cucp_cuup_bearer_context_setup_direct; - rrc->cucp_cuup.bearer_context_mod = cucp_cuup_bearer_context_mod_direct; + rrc->cucp_cuup.bearer_context_mod = cucp_cuup_bearer_context_modif_direct; + rrc->cucp_cuup.bearer_context_release = cucp_cuup_bearer_context_release_cmd_direct; } diff --git a/openair2/RRC/NR/cucp_cuup_e1ap.c b/openair2/RRC/NR/cucp_cuup_e1ap.c index 200729ec11..fb099178d4 100644 --- a/openair2/RRC/NR/cucp_cuup_e1ap.c +++ b/openair2/RRC/NR/cucp_cuup_e1ap.c @@ -16,44 +16,49 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ #include "cucp_cuup_if.h" -#include - -#include "platform_types.h" #include "nr_rrc_defs.h" #include "nr_rrc_proto.h" #include "nr_rrc_extern.h" #include "cucp_cuup_if.h" -#include "openair2/COMMON/e1ap_messages_types.h" -#include "openair3/SECU/secu_defs.h" -#include -#include "common/ran_context.h" - -extern RAN_CONTEXT_t RC; - -static void cucp_cuup_bearer_context_setup_e1ap(e1ap_bearer_setup_req_t *const req, instance_t instance) +static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req) { - MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, instance, E1AP_BEARER_CONTEXT_SETUP_REQ); + AssertFatal(assoc_id > 0, "illegal assoc_id %d\n", assoc_id); + 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)); - itti_send_msg_to_task (TASK_CUCP_E1, instance, msg_p); + itti_send_msg_to_task (TASK_CUCP_E1, 0, msg_p); } -static void cucp_cuup_bearer_context_mod_e1ap(e1ap_bearer_setup_req_t *const req, instance_t instance) +static void cucp_cuup_bearer_context_mod_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req) { - MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, instance, E1AP_BEARER_CONTEXT_MODIFICATION_REQ); + AssertFatal(assoc_id > 0, "illegal assoc_id %d\n", assoc_id); + MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_MODIFICATION_REQ); + msg->ittiMsgHeader.originInstance = assoc_id; e1ap_bearer_setup_req_t *req_msg = &E1AP_BEARER_CONTEXT_SETUP_REQ(msg); memcpy(req_msg, req, sizeof(*req)); - itti_send_msg_to_task(TASK_CUCP_E1, instance, msg); + itti_send_msg_to_task(TASK_CUCP_E1, 0, msg); +} + +static void cucp_cuup_bearer_context_release_cmd_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_release_cmd_t *cmd) +{ + AssertFatal(assoc_id > 0, "illegal assoc_id %d\n", assoc_id); + MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_RELEASE_CMD); + msg->ittiMsgHeader.originInstance = assoc_id; + e1ap_bearer_release_cmd_t *cmd_msg = &E1AP_BEARER_CONTEXT_RELEASE_CMD(msg); + memcpy(cmd_msg, cmd, sizeof(*cmd)); + itti_send_msg_to_task(TASK_CUCP_E1, 0, msg); } void cucp_cuup_message_transfer_e1ap_init(gNB_RRC_INST *rrc) { rrc->cucp_cuup.bearer_context_setup = cucp_cuup_bearer_context_setup_e1ap; rrc->cucp_cuup.bearer_context_mod = cucp_cuup_bearer_context_mod_e1ap; + rrc->cucp_cuup.bearer_context_release = cucp_cuup_bearer_context_release_cmd_e1ap; } diff --git a/openair2/RRC/NR/cucp_cuup_if.h b/openair2/RRC/NR/cucp_cuup_if.h index 079a32e850..cbf84a289e 100644 --- a/openair2/RRC/NR/cucp_cuup_if.h +++ b/openair2/RRC/NR/cucp_cuup_if.h @@ -16,27 +16,26 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ #ifndef CUCP_CUUP_IF_H #define CUCP_CUUP_IF_H #include +#include +#include +#include #include "platform_types.h" struct e1ap_bearer_setup_req_s; struct e1ap_bearer_setup_resp_s; -typedef void (*cucp_cuup_bearer_context_setup_func_t)(struct e1ap_bearer_setup_req_s *const req, instance_t instance); +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_release_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_release_cmd_s *cmd); struct gNB_RRC_INST_s; void cucp_cuup_message_transfer_direct_init(struct gNB_RRC_INST_s *rrc); void cucp_cuup_message_transfer_e1ap_init(struct gNB_RRC_INST_s *rrc); -void fill_e1ap_bearer_setup_resp(struct e1ap_bearer_setup_resp_s *resp, - struct e1ap_bearer_setup_req_s *const req, - instance_t gtpInst, - ue_id_t ue_id, - int remote_port, - in_addr_t my_addr); -void CU_update_UP_DL_tunnel(struct e1ap_bearer_setup_req_s *const req, instance_t instance, ue_id_t ue_id); + #endif diff --git a/openair2/RRC/NR/mac_rrc_dl.h b/openair2/RRC/NR/mac_rrc_dl.h index 9fc75b3073..6e43212f5e 100644 --- a/openair2/RRC/NR/mac_rrc_dl.h +++ b/openair2/RRC/NR/mac_rrc_dl.h @@ -16,7 +16,7 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ #ifndef MAC_RRC_DL_H diff --git a/openair2/RRC/NR/mac_rrc_dl_direct.c b/openair2/RRC/NR/mac_rrc_dl_direct.c index c18a33954c..ee9a29c6ae 100644 --- a/openair2/RRC/NR/mac_rrc_dl_direct.c +++ b/openair2/RRC/NR/mac_rrc_dl_direct.c @@ -16,7 +16,7 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ #include "nr_rrc_defs.h" diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index 6ead51e3da..951e9639c5 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -16,7 +16,7 @@ * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: - * conmnc_digit_lengtht@openairinterface.org + * contact@openairinterface.org */ #include diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index c37979598a..16b7f040ee 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -330,11 +330,6 @@ typedef struct { uint8_t *SIB23; uint8_t sizeof_SIB23; - NR_SIB2_t *sib2; - NR_SIB3_t *sib3; - NR_BCCH_DL_SCH_Message_t systemInformation; // SIB23 - NR_CellGroupConfig_t *secondaryCellGroup[MAX_NR_RRC_UE_CONTEXTS]; - } rrc_gNB_carrier_data_t; //--------------------------------------------------- @@ -367,6 +362,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_release_func_t bearer_context_release; } cucp_cuup_if_t; typedef struct nr_rrc_du_container_t { @@ -376,6 +372,14 @@ typedef struct nr_rrc_du_container_t { NR_SIB1_t *sib1; } nr_rrc_du_container_t; +typedef struct nr_rrc_cuup_container_t { + /* Tree-related data */ + RB_ENTRY(nr_rrc_cuup_container_t) entries; + + e1ap_setup_req_t *setup_req; + sctp_assoc_t assoc_id; +} nr_rrc_cuup_container_t; + //---NR---(completely change)--------------------- typedef struct gNB_RRC_INST_s { @@ -396,24 +400,6 @@ typedef struct gNB_RRC_INST_s { // gNB N3 GTPU instance instance_t e1_inst; - // other PLMN parameters - /// Mobile country code - int mcc; - /// Mobile network code - int mnc; - /// number of mnc digits - int mnc_digit_length; - - // other RAN parameters - int srb1_timer_poll_retransmit; - int srb1_poll_pdu; - int srb1_poll_byte; - int srb1_max_retx_threshold; - int srb1_timer_reordering; - int srb1_timer_status_prohibit; - int um_on_default_drb; - int srs_enable[MAX_NUM_CCs]; - char *uecap_file; // security configuration (preferred algorithms) @@ -423,6 +409,8 @@ typedef struct gNB_RRC_INST_s { cucp_cuup_if_t cucp_cuup; nr_rrc_du_container_t *du; + RB_HEAD(rrc_cuup_tree, nr_rrc_cuup_container_t) cuups; // CU-UPs, indexed by assoc_id + size_t num_cuups; } gNB_RRC_INST; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 510e058495..2bbbe5ab36 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -132,6 +132,10 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP); +sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); +sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd); +int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req); + void bearer_context_setup_direct(e1ap_bearer_setup_req_t *req, instance_t instance); @@ -144,8 +148,6 @@ void ue_cxt_mod_send_e1ap(MessageDef *msg, void ue_cxt_mod_direct(MessageDef *msg, instance_t instance); -NR_DRB_ToAddModList_t *fill_DRB_configList(gNB_RRC_UE_t *ue); - void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_context_p, e1ap_bearer_setup_resp_t *e1ap_resp); void nr_pdcp_add_srbs(eNB_flag_t enb_flag, ue_id_t rntiMaybeUEid, NR_SRB_ToAddModList_t *const srb2add_list, const uint8_t security_modeP, uint8_t *const kRRCenc, uint8_t *const kUPint); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b057d023b3..7af9350136 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -93,7 +93,6 @@ #include #include #include -#include "openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h" #include "openair2/F1AP/f1ap_common.h" #include "openair2/F1AP/f1ap_ids.h" #include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" @@ -337,6 +336,7 @@ void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *c rrc_gNB_CU_DU_init(rrc); uid_linear_allocator_init(&rrc->uid_allocator); RB_INIT(&rrc->rrc_ue_head); + RB_INIT(&rrc->cuups); rrc->configuration = *configuration; /// System Information INIT init_NR_SI(rrc); @@ -575,7 +575,6 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co dedicatedNAS_MessageList, ue_p->masterCellGroup); AssertFatal(size > 0, "cannot encode RRCReconfiguration in %s()\n", __func__); - LOG_W(NR_RRC, "do_RRCReconfiguration(): size %d\n", size); free_defaultMeasConfig(measconfig); if (LOG_DEBUGFLAG(DEBUG_ASN1)) { @@ -1041,6 +1040,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context } } + // TODO: should send E1 UE Bearer Modification with PDCP Reestablishment flag nr_pdcp_reestablishment(ue_p->rrc_ue_id); f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); @@ -2033,8 +2033,6 @@ static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p) } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - nr_pdcp_remove_UE(UE->rrc_ue_id); - newGtpuDeleteAllTunnels(instance, UE->rrc_ue_id); rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance, UE->rrc_ue_id); LOG_I(NR_RRC, "removed UE CU UE ID %u/RNTI %04x \n", UE->rrc_ue_id, UE->rnti); rrc_delete_ue_data(UE); @@ -2055,10 +2053,13 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i if (resp->drbs_to_be_setup_length > 0) { e1ap_bearer_setup_req_t req = {0}; + // TODO: bug: we receive the DRBs, but we don't associate to a PDU session + // -> we are not sure which PDU session this is, and fill "all" req.numPDUSessionsMod = UE->nb_of_pdusessions; req.gNB_cu_cp_ue_id = UE->rrc_ue_id; req.gNB_cu_up_ue_id = UE->rrc_ue_id; for (int i = 0; i < req.numPDUSessionsMod; i++) { + req.pduSessionMod[i].sessionId = UE->pduSession[i].param.pdusession_id; req.pduSessionMod[i].numDRB2Modify = resp->drbs_to_be_setup_length; for (int j = 0; j < resp->drbs_to_be_setup_length; j++) { f1ap_drb_to_be_setup_t *drb_f1 = resp->drbs_to_be_setup + j; @@ -2073,7 +2074,8 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i // send the F1 response message up to update F1-U tunnel info // it seems the rrc transaction id (xid) is not needed here - rrc->cucp_cuup.bearer_context_mod(&req, instance); + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); + rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); } if (resp->du_to_cu_rrc_information != NULL && resp->du_to_cu_rrc_information->cellGroupConfig != NULL) { @@ -2314,47 +2316,42 @@ static int get_dl_mimo_layers(const f1ap_served_cell_info_t *cell_info, const NR return(1); } -int rrc_gNB_process_e1_setup_req(e1ap_setup_req_t *req, instance_t instance) { - - AssertFatal(req->supported_plmns <= PLMN_LIST_MAX_SIZE, "Supported PLMNs is more than PLMN_LIST_MAX_SIZE\n"); - gNB_RRC_INST *rrc = RC.nrrrc[0]; //TODO: remove hardcoding of RC index here - MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, instance, E1AP_SETUP_RESP); - - e1ap_setup_resp_t *resp = &E1AP_SETUP_RESP(msg_p); - resp->transac_id = req->transac_id; - - for (int i=0; i < req->supported_plmns; i++) { - if (rrc->configuration.mcc[i] == req->plmns[i].mcc && - rrc->configuration.mnc[i] == req->plmns[i].mnc) { - LOG_E(NR_RRC, "PLMNs received from CUUP (mcc:%d, mnc:%d) did not match with PLMNs in RRC (mcc:%d, mnc:%d)\n", - req->plmns[i].mcc, req->plmns[i].mnc, rrc->configuration.mcc[i], rrc->configuration.mnc[i]); - return -1; - } - } - - itti_send_msg_to_task(TASK_CUCP_E1, instance, msg_p); - - return 0; -} - -void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_context_p, e1ap_bearer_setup_resp_t *e1ap_resp) +void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp, instance_t instance) { - /* Generate a UE context modification request message towards the DU to - * instruct the DU for SRB2 and DRB configuration and get the updates on - * master cell group config from the DU*/ - gNB_RRC_INST *rrc = RC.nrrrc[0]; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, resp->gNB_cu_cp_ue_id); + AssertFatal(ue_context_p != NULL, "did not find UE with CU UE ID %d\n", resp->gNB_cu_cp_ue_id); gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + // currently: we don't have "infrastructure" to save the CU-UP UE ID, so we + // assume (and below check) that CU-UP UE ID == CU-CP UE ID + AssertFatal(resp->gNB_cu_cp_ue_id == resp->gNB_cu_up_ue_id, + "cannot handle CU-UP UE ID different from CU-CP UE ID (%d vs %d)\n", + resp->gNB_cu_cp_ue_id, + resp->gNB_cu_up_ue_id); + + // save the tunnel address for the PDU sessions + for (int i=0; i < resp->numPDUSessions; i++) { + pdu_session_setup_t *e1_pdu = &resp->pduSession[i]; + rrc_pdu_session_param_t *rrc_pdu = find_pduSession(UE, e1_pdu->id, false); + if (rrc_pdu == NULL) { + 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_addr_N3.length = sizeof(in_addr_t); + } + /* Instruction towards the DU for DRB configuration and tunnel creation */ - int nb_drb = e1ap_resp->pduSession[0].numDRBSetup; + int nb_drb = resp->pduSession[0].numDRBSetup; f1ap_drb_to_be_setup_t drbs[nb_drb]; for (int i = 0; i < nb_drb; i++) { - drbs[i].drb_id = e1ap_resp->pduSession[0].DRBnGRanList[i].id; - drbs[i].rlc_mode = rrc->um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; - drbs[i].up_ul_tnl[0].tl_address = e1ap_resp->pduSession[0].DRBnGRanList[i].UpParamList[0].tlAddress; + drbs[i].drb_id = resp->pduSession[0].DRBnGRanList[i].id; + drbs[i].rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; + drbs[i].up_ul_tnl[0].tl_address = resp->pduSession[0].DRBnGRanList[i].UpParamList[0].tlAddress; drbs[i].up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drbs[i].up_ul_tnl[0].teid = e1ap_resp->pduSession[0].DRBnGRanList[i].UpParamList[0].teId; + drbs[i].up_ul_tnl[0].teid = resp->pduSession[0].DRBnGRanList[i].UpParamList[0].teId; drbs[i].up_ul_tnl_length = 1; } @@ -2368,6 +2365,7 @@ void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_contex srbs[0].lcid = 2; } + /* Gather UE capability if present */ cu_to_du_rrc_information_t cu2du = {0}; cu_to_du_rrc_information_t *cu2du_p = NULL; if (UE->ue_cap_buffer.len > 0 && UE->ue_cap_buffer.buf != NULL) { @@ -2394,36 +2392,29 @@ void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_contex rrc->mac_rrc.ue_context_modification_request(&ue_context_modif_req); } -void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp, instance_t instance) { - // Find the UE context from UE ID and send ITTI message to F1AP to send UE context modification message to DU - - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], resp->gNB_cu_cp_ue_id); - AssertFatal(ue_context_p != NULL, "did not find UE with CU UE ID %d\n", resp->gNB_cu_cp_ue_id); - protocol_ctxt_t ctxt = {0}; - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, GNB_FLAG_YES, resp->gNB_cu_cp_ue_id, 0, 0, 0); - - // currently: we don't have "infrastructure" to save the CU-UP UE ID, so we - // assume (and below check) that CU-UP UE ID == CU-CP UE ID - AssertFatal(resp->gNB_cu_cp_ue_id == resp->gNB_cu_up_ue_id, - "cannot handle CU-UP UE ID different from CU-CP UE ID (%d vs %d)\n", - resp->gNB_cu_cp_ue_id, - resp->gNB_cu_up_ue_id); - - gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp={0}; - create_tunnel_resp.num_tunnels = resp->numPDUSessions; - for (int i=0; i < resp->numPDUSessions; i++) { - create_tunnel_resp.pdusession_id[i] = resp->pduSession[i].id; - create_tunnel_resp.gnb_NGu_teid[i] = resp->pduSession[i].teId; - memcpy(create_tunnel_resp.gnb_addr.buffer, - &resp->pduSession[i].tlAddress, - sizeof(in_addr_t)); - create_tunnel_resp.gnb_addr.length = sizeof(in_addr_t); // IPv4 byte length +void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t *resp) +{ + gNB_RRC_INST *rrc = RC.nrrrc[0]; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, resp->gNB_cu_cp_ue_id); + if (ue_context_p == NULL) { + LOG_E(RRC, "no UE with CU-CP UE ID %d found\n", resp->gNB_cu_cp_ue_id); + return; } - nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0); + // there is not really anything to do here as of now + for (int i = 0; i < resp->numPDUSessionsMod; ++i) { + const pdu_session_modif_t *pdu = &resp->pduSessionMod[i]; + LOG_I(RRC, "UE %d: PDU session ID %ld modified %d bearers\n", resp->gNB_cu_cp_ue_id, pdu->id, pdu->numDRBModified); + } +} - // TODO: SV: combine e1ap_bearer_setup_req_t and e1ap_bearer_setup_resp_t and minimize assignments - prepare_and_send_ue_context_modification_f1(ue_context_p, resp); +void rrc_gNB_process_e1_bearer_context_release_cplt(const e1ap_bearer_release_cplt_t *cplt) +{ + // there is not really anything to do here as of now + // note that we don't check for the UE: it does not exist anymore if the F1 + // UE context release complete arrived from the DU first, after which we free + // the UE context + LOG_I(RRC, "UE %d: received bearer release complete\n", cplt->gNB_cu_cp_ue_id); } static void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id) @@ -2698,11 +2689,20 @@ void *rrc_gnb_task(void *args_p) { break; case E1AP_SETUP_REQ: - rrc_gNB_process_e1_setup_req(&E1AP_SETUP_REQ(msg_p), instance); + rrc_gNB_process_e1_setup_req(msg_p->ittiMsgHeader.originInstance, &E1AP_SETUP_REQ(msg_p)); break; case E1AP_BEARER_CONTEXT_SETUP_RESP: rrc_gNB_process_e1_bearer_context_setup_resp(&E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p), instance); + break; + + case E1AP_BEARER_CONTEXT_MODIFICATION_RESP: + rrc_gNB_process_e1_bearer_context_modif_resp(&E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg_p)); + break; + + case E1AP_BEARER_CONTEXT_RELEASE_CPLT: + rrc_gNB_process_e1_bearer_context_release_cplt(&E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg_p)); + break; case NGAP_PAGING_IND: rrc_gNB_process_PAGING_IND(msg_p, instance); @@ -2855,6 +2855,13 @@ rrc_gNB_generate_RRCRelease( deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd}; nr_pdcp_data_req_srb(ctxt_pP->rntiMaybeUEid, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data); + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); + e1ap_bearer_release_cmd_t cmd = { + .gNB_cu_cp_ue_id = UE->rrc_ue_id, + .gNB_cu_up_ue_id = UE->rrc_ue_id, + }; + rrc->cucp_cuup.bearer_context_release(assoc_id, &cmd); + /* UE will be freed after UE context release complete */ } @@ -2936,7 +2943,8 @@ void rrc_gNB_trigger_new_bearer(int rnti) ue->xids[xid] = RRC_PDUSESSION_MODIFY; ue->pduSession[0].xid = xid; // hack: fake xid for ongoing PDU session LOG_W(RRC, "trigger new bearer %ld for UE %04x xid %d\n", drb->id, ue->rnti, xid); - rrc->cucp_cuup.bearer_context_setup(&bearer_req, 0); + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue); + rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); } void rrc_gNB_trigger_release_bearer(int rnti) diff --git a/openair2/RRC/NR/rrc_gNB_GTPV1U.c b/openair2/RRC/NR/rrc_gNB_GTPV1U.c index 3ef3e62d51..6c8627aa09 100644 --- a/openair2/RRC/NR/rrc_gNB_GTPV1U.c +++ b/openair2/RRC/NR/rrc_gNB_GTPV1U.c @@ -75,35 +75,3 @@ int rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(const protocol_ctxt_t *const ctxt_ return 0; } - -int nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(const protocol_ctxt_t *const ctxt_pP, const gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp_pP, int offset) -{ - if (!create_tunnel_resp_pP) { - LOG_E(NR_RRC, "create_tunnel_resp_pP error\n"); - return -1; - } - - LOG_D(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT " RX CREATE_TUNNEL_RESP num tunnels %u \n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), create_tunnel_resp_pP->num_tunnels); - /* we look up by CU UE ID! Do NOT change back to RNTI! */ - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[ctxt_pP->module_id], ctxt_pP->rntiMaybeUEid); - if (!ue_context_p) { - LOG_E(NR_RRC, "UE table error\n"); - return -1; - } - - for (int i = 0; i < create_tunnel_resp_pP->num_tunnels; i++) { - ue_context_p->ue_context.pduSession[i + offset].param.gNB_teid_N3 = create_tunnel_resp_pP->gnb_NGu_teid[i]; - ue_context_p->ue_context.pduSession[i + offset].param.gNB_addr_N3 = create_tunnel_resp_pP->gnb_addr; - AssertFatal(ue_context_p->ue_context.pduSession[i + offset].param.pdusession_id == create_tunnel_resp_pP->pdusession_id[i], ""); - LOG_I(NR_RRC, - PROTOCOL_NR_RRC_CTXT_UE_FMT - " nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP tunnel (%u) bearer UE context index %u, id %u, gtp addr len %d \n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), - create_tunnel_resp_pP->gnb_NGu_teid[i], - i, - create_tunnel_resp_pP->pdusession_id[i], - create_tunnel_resp_pP->gnb_addr.length); - } - - return 0; -} diff --git a/openair2/RRC/NR/rrc_gNB_GTPV1U.h b/openair2/RRC/NR/rrc_gNB_GTPV1U.h index d538127d76..d7d1013db8 100644 --- a/openair2/RRC/NR/rrc_gNB_GTPV1U.h +++ b/openair2/RRC/NR/rrc_gNB_GTPV1U.h @@ -38,6 +38,4 @@ rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP( uint8_t *inde_list ); -int nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(const protocol_ctxt_t *const ctxt_pP, const gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp_pP, int offset_in_rrc); - #endif diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index cac6884631..49d3ccad99 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -378,6 +378,9 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t uint8_t nb_pdusessions_tosetup = req->nb_of_pdusessions; if (nb_pdusessions_tosetup) { AssertFatal(false, "PDU sessions in Initial context setup request not handled by E1 yet\n"); + /* this code should pass by E1: commenting here for future reference, but + * already handled in E1 for the "normal case" of a separate request for + * PDU session setup. gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0}; for (int i = 0; i < nb_pdusessions_tosetup; i++) { UE->nb_of_pdusessions++; @@ -404,6 +407,7 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t } nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0); + */ } /* NAS PDU */ @@ -757,6 +761,8 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; e1ap_bearer_setup_req_t bearer_req = {0}; + + e1ap_nssai_t cuup_nssai = {0}; for (int i = 0; i < msg->nb_pdusessions_tosetup; i++) { rrc_pdu_session_param_t *pduSession = find_pduSession(UE, msg->pdusession_setup_params[i].pdusession_id, true); pdusession_t *session = &pduSession->param; @@ -775,7 +781,13 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; bearer_req.numPDUSessions++; pdu->sessionId = session->pdusession_id; - pdu->sst = msg->allowed_nssai[i].sST; + ngap_allowed_NSSAI_t *nssai = &msg->allowed_nssai[i]; + pdu->nssai.sst = nssai->sST; + pdu->nssai.sd = 0xffffff; + if (nssai->sD_flag) + pdu->nssai.sd = nssai->sD[0] << 16 | nssai->sD[1] << 8 | nssai->sD[2]; + if (cuup_nssai.sst == 0) + cuup_nssai = pdu->nssai; /* for CU-UP selection below */ pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; @@ -787,7 +799,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins drb->id = i + j + UE->nb_of_pdusessions; - drb->defaultDRB = E1AP_DefaultDRB_true; + drb->defaultDRB = true; drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap); drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap); @@ -823,7 +835,13 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins } int xid = rrc_gNB_get_next_transaction_identifier(instance); UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; - rrc->cucp_cuup.bearer_context_setup(&bearer_req, instance); + /* Limitation: we assume one fixed CU-UP per UE. We base the selection on + * NSSAI, but the UE might have multiple PDU sessions with differing slices, + * in which we might need to select different CU-UPs. In this case, we would + * actually need to group the E1 bearer context setup for the different + * CU-UPs, and send them to the different CU-UPs. */ + sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd); + rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); return; } diff --git a/openair2/RRC/NR/rrc_gNB_cuup.c b/openair2/RRC/NR/rrc_gNB_cuup.c new file mode 100644 index 0000000000..3ab6dfe7bb --- /dev/null +++ b/openair2/RRC/NR/rrc_gNB_cuup.c @@ -0,0 +1,174 @@ +/* + * 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 "common/ran_context.h" +#include "nr_rrc_defs.h" +#include "openair2/F1AP/f1ap_ids.h" + +static int cuup_compare(const nr_rrc_cuup_container_t *a, const nr_rrc_cuup_container_t *b) +{ + if (a->assoc_id > b->assoc_id) + return 1; + if (a->assoc_id == b->assoc_id) + return 0; + return -1; /* a->assoc_id < b->assoc_id */ +} + +/* Tree management functions */ +RB_GENERATE/*_STATIC*/(rrc_cuup_tree, nr_rrc_cuup_container_t, entries, cuup_compare); + +static const nr_rrc_cuup_container_t *select_cuup_slice(const struct rrc_cuup_tree *t, const gNB_RRC_UE_t *ue, int sst, int sd) +{ + nr_rrc_cuup_container_t *second_best_match = NULL; /* if no NSSAI matches exactly */ + nr_rrc_cuup_container_t *cuup = NULL; + RB_FOREACH(cuup, rrc_cuup_tree, (struct rrc_cuup_tree *)&t) { + e1ap_setup_req_t *sr = cuup->setup_req; + for (int p = 0; p < sr->supported_plmns; ++p) { + /* actually we should also check that the PLMN selected by the UE matches */ + for (int s = 0; s < sr->plmn[p].supported_slices; ++s) { + e1ap_nssai_t *nssai = &sr->plmn[p].slice[s]; + if (nssai->sst == sst && nssai->sd == sd) { + LOG_I(RRC, "selecting CU-UP ID %ld based on exact NSSAI match (%d:0x%06x)\n", sr->gNB_cu_up_id, sst, sd); + return cuup; /* exact match */ + } else if (nssai->sst == sst && second_best_match == NULL) { + LOG_I(RRC, "second best match: CU-UP ID %ld matches SST %d\n", sr->gNB_cu_up_id, sst); + second_best_match = cuup; /* only the SST matches -> "good enough" */ + } + } + } + } + return second_best_match; +} + +static const nr_rrc_cuup_container_t *select_cuup_round_robin(size_t n_t, const struct rrc_cuup_tree *t, const gNB_RRC_UE_t *ue) +{ + /* pick the CU-UP following a "round-robin" fashion: select CU-UP M = RRC UE + * ID % N with N number of CU-UPs */ + int m = (ue->rrc_ue_id - 1) % n_t; + nr_rrc_cuup_container_t *cuup = NULL; + RB_FOREACH(cuup, rrc_cuup_tree, (struct rrc_cuup_tree *)&t) { + if (m == 0) { + LOG_I(RRC, "round-robin match: select CU-UP ID %ld (no NSSAI match)\n", cuup->setup_req->gNB_cu_up_id); + return cuup; + } + m--; + } + /* this should not happen: no CU-UP available? */ + return NULL; +} + +sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue) +{ + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); + if (ue_data.e1_assoc_id == 0) { + LOG_W(RRC, "UE %d should be associated to CU-UP, but is not\n", ue->rrc_ue_id); + /* we could possibly check the SST/SD from the PDU session */ + return get_new_cuup_for_ue(rrc, ue, 0, 0); + } + LOG_D(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id); + return ue_data.e1_assoc_id; +} + +sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd) +{ + /* check if there is already a UE associated */ + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); + if (ue_data.e1_assoc_id != 0) { + LOG_I(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id); + return ue_data.e1_assoc_id; + } + + /* it is zero -> no CUUP for this UE yet, get the (only) CU-UP that is + * connected */ + if (RB_EMPTY(&rrc->cuups)) { + LOG_W(RRC, "no CU-UPs connected: UE %d cannot have a DRB\n", ue->rrc_ue_id); + return 0; /* no CUUP connected */ + } + + const nr_rrc_cuup_container_t *selected = NULL; + if (sst != 0) /* only do if there is slice information */ + selected = select_cuup_slice(&rrc->cuups, ue, sst, sd); + if (selected == NULL) /* nothing found yet */ + selected = select_cuup_round_robin(rrc->num_cuups, &rrc->cuups, ue); + if (selected == NULL) { + selected = RB_ROOT(&rrc->cuups); + } + AssertFatal(selected != NULL, "logic error: could not select CU-UP, is one connected?\n"); + + /* update the association for the UE so it will be picked up later */ + ue_data.e1_assoc_id = selected->assoc_id; + cu_remove_f1_ue_data(ue->rrc_ue_id); + cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data); + LOG_I(RRC, "UE %d associating to CU-UP assoc_id %d out of %ld CU-UPs\n", ue->rrc_ue_id, ue_data.e1_assoc_id, rrc->num_cuups); + + return ue_data.e1_assoc_id; +} + +int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req) +{ + AssertFatal(req->supported_plmns <= PLMN_LIST_MAX_SIZE, "Supported PLMNs is more than PLMN_LIST_MAX_SIZE\n"); + gNB_RRC_INST *rrc = RC.nrrrc[0]; + + nr_rrc_cuup_container_t *c = NULL; + RB_FOREACH(c, rrc_cuup_tree, &rrc->cuups) { + if (req->gNB_cu_up_id == c->setup_req->gNB_cu_up_id) { + LOG_E(NR_RRC, + "Connecting CU-UP ID %ld name %s (assoc_id %d) has same ID as existing CU-UP ID %ld name %s (assoc_id %d)\n", + req->gNB_cu_up_id, + req->gNB_cu_up_name, + assoc_id, + c->setup_req->gNB_cu_up_id, + c->setup_req->gNB_cu_up_name, + c->assoc_id); + return -1; + } + } + + for (int i = 0; i < req->supported_plmns; i++) { + PLMN_ID_t *id = &req->plmn[i].id; + if (rrc->configuration.mcc[i] != id->mcc || rrc->configuration.mnc[i] != id->mnc) { + LOG_E(NR_RRC, + "PLMNs received from CUUP (mcc:%d, mnc:%d) did not match with PLMNs in RRC (mcc:%d, mnc:%d)\n", + id->mcc, + id->mnc, + rrc->configuration.mcc[i], + rrc->configuration.mnc[i]); + return -1; + } + } + + LOG_I(RRC, "Accepting new CU-UP ID %ld name %s (assoc_id %d)\n", req->gNB_cu_up_id, req->gNB_cu_up_name, assoc_id); + nr_rrc_cuup_container_t *cuup = malloc(sizeof(*cuup)); + AssertFatal(cuup, "out of memory\n"); + cuup->setup_req = malloc(sizeof(*cuup->setup_req)); + *cuup->setup_req = *req; + cuup->assoc_id = assoc_id; + RB_INSERT(rrc_cuup_tree, &rrc->cuups, cuup); + rrc->num_cuups++; + + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, E1AP_SETUP_RESP); + msg_p->ittiMsgHeader.originInstance = assoc_id; + e1ap_setup_resp_t *resp = &E1AP_SETUP_RESP(msg_p); + resp->transac_id = req->transac_id; + itti_send_msg_to_task(TASK_CUCP_E1, 0, msg_p); + + return 0; +} diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 4367222404..d542dd4b30 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -510,7 +510,7 @@ static int udpServerSocket(openAddr_s addr) { freeaddrinfo(servinfo); // all done with this structure - if (strlen(addr.destinationHost)>1) { + if (false) { struct addrinfo hints; memset(&hints,0,sizeof(hints)); hints.ai_family=AF_UNSPEC; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf index 01259ac5a6..aa3e5de456 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf @@ -6,7 +6,7 @@ gNBs = ( { ////////// Identification parameters: - gNB_CU_ID = 0xe00; + gNB_ID = 0xe00; # cell_type = "CELL_MACRO_GNB"; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band78.fr1.106PRB.usrpx310.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band78.fr1.106PRB.usrpx310.conf index c2fa1bb623..65a2a49d50 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band78.fr1.106PRB.usrpx310.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band78.fr1.106PRB.usrpx310.conf @@ -6,7 +6,7 @@ gNBs = ( { ////////// Identification parameters: - gNB_CU_ID = 0xe00; + gNB_ID = 0xe00; # cell_type = "CELL_MACRO_GNB";