Merge remote-tracking branch 'origin/e1-multiple-cuup' into integration_2023_w43
This commit is contained in:
+6
-7
@@ -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)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_CU_ID = 0xe00;
|
||||
gNB_ID = 0xe00;
|
||||
|
||||
# cell_type = "CELL_MACRO_GNB";
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_CU_ID = 0xe00;
|
||||
gNB_ID = 0xe00;
|
||||
|
||||
# cell_type = "CELL_MACRO_GNB";
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_CU_ID = 0xe00;
|
||||
gNB_ID = 0xe00;
|
||||
|
||||
gNB_name = "gNB-OAI";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_CU_ID = 0xe00;
|
||||
gNB_ID = 0xe00;
|
||||
|
||||
gNB_name = "gNB-Eurecom-n78_20";
|
||||
|
||||
|
||||
+55
-16
@@ -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()<br/>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()<br/>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()<br/>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()<br/>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
|
||||
{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.
|
||||
|
||||
+9
-15
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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})
|
||||
|
||||
+366
-165
File diff suppressed because it is too large
Load Diff
+13
-11
@@ -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);
|
||||
|
||||
|
||||
@@ -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 <arpa/inet.h>
|
||||
#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);
|
||||
}
|
||||
@@ -47,10 +47,14 @@
|
||||
#include <E1AP_DRB-Failed-Item-NG-RAN.h>
|
||||
#include <E1AP_BearerContextSetupResponse.h>
|
||||
#include <E1AP_BearerContextSetupRequest.h>
|
||||
#include <E1AP_DRB-Modified-Item-NG-RAN.h>
|
||||
#include <E1AP_DRB-Modified-List-NG-RAN.h>
|
||||
#include <E1AP_DRB-To-Setup-Item-EUTRAN.h>
|
||||
#include <E1AP_DRB-To-Setup-Item-NG-RAN.h>
|
||||
#include <E1AP_Cell-Group-Information-Item.h>
|
||||
#include <E1AP_PDU-Session-Resource-To-Setup-Item.h>
|
||||
#include <E1AP_PDU-Session-Resource-Modified-Item.h>
|
||||
#include <E1AP_PDU-Session-Resource-Modified-List.h>
|
||||
#include <E1AP_PDU-Session-Resource-To-Modify-List.h>
|
||||
#include <E1AP_PDU-Session-Resource-To-Modify-Item.h>
|
||||
#include <E1AP_DRB-To-Modify-List-NG-RAN.h>
|
||||
@@ -61,5 +65,7 @@
|
||||
#include <E1AP_T-ReorderingTimer.h>
|
||||
#include <E1AP_SDAP-Configuration.h>
|
||||
#include <E1AP_PDCP-Configuration.h>
|
||||
#include <E1AP_Slice-Support-List.h>
|
||||
#include <E1AP_Slice-Support-Item.h>
|
||||
|
||||
#endif
|
||||
|
||||
+26
-16
@@ -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;
|
||||
|
||||
+14
-16
@@ -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_ */
|
||||
|
||||
+31
-15
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,13 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/sctp.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
}//
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 <sys/socket.h>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 <stdbool.h>
|
||||
|
||||
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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 <stdbool.h>
|
||||
|
||||
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 */
|
||||
@@ -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__);
|
||||
}
|
||||
@@ -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 <openair3/ocp-gtpu/gtp_itf.h>
|
||||
#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);
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include <openair3/ocp-gtpu/gtp_itf.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <arpa/inet.h>
|
||||
|
||||
#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 <openair2/RRC/NR/rrc_gNB_UE_context.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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 <arpa/inet.h>
|
||||
|
||||
#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 <openair2/RRC/NR/rrc_gNB_UE_context.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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 <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/sctp.h>
|
||||
#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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 <stdlib.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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+75
-67
@@ -93,7 +93,6 @@
|
||||
#include <openair3/SECU/key_nas_deriver.h>
|
||||
#include <openair3/ocp-gtpu/gtp_itf.h>
|
||||
#include <openair2/RRC/NR/nr_rrc_proto.h>
|
||||
#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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -6,7 +6,7 @@ gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_CU_ID = 0xe00;
|
||||
gNB_ID = 0xe00;
|
||||
|
||||
# cell_type = "CELL_MACRO_GNB";
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_CU_ID = 0xe00;
|
||||
gNB_ID = 0xe00;
|
||||
|
||||
# cell_type = "CELL_MACRO_GNB";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user