diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index f3d30d6170..817555554d 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -498,10 +498,10 @@ class Containerize(): elif image != 'ran-build': cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}') if image == 'oai-gnb-aerial': - cmd.run('cp -f /opt/nvidia-ipc/nvipc_src.*.tar.gz .') + cmd.run('cp -f /opt/nvidia-ipc/nvipc.src.2025.05.20.tar.gz .') ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > cmake_targets/log/{name}.log 2>&1', timeout=1200) if image == 'oai-gnb-aerial': - cmd.run('rm -f nvipc_src.*.tar.gz') + cmd.run('rm -f nvipc.src.2025.05.20.tar.gz') if image == 'ran-build' and ret.returncode == 0: cmd.run(f"docker run --name test-log -d {name}:{imageTag} /bin/true") cmd.run(f"docker cp test-log:/oai-ran/cmake_targets/log/ cmake_targets/log/{name}/") diff --git a/ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml b/ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml index d5677ac239..d11a97c186 100644 --- a/ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml +++ b/ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml @@ -23,7 +23,7 @@ services: - ../../../cmake_targets/share:/opt/cuBB/share userns_mode: host ipc: "shareable" - image: cubb-build:24-3 + image: cubb-build:25-1 environment: - cuBB_SDK=/opt/nvidia/cuBB command: bash -c "sudo rm -rf /tmp/phy.log && sudo chmod +x /opt/nvidia/cuBB/aerial_l1_entrypoint.sh && /opt/nvidia/cuBB/aerial_l1_entrypoint.sh" @@ -33,7 +33,7 @@ services: timeout: 5s retries: 5 oai-gnb-aerial: - cpuset: "13-20" + cpuset: "13-14" image: ${REGISTRY:-oaisoftwarealliance}/oai-gnb-aerial:${TAG:-develop} depends_on: nv-cubb: diff --git a/common/5g_platform_types.h b/common/5g_platform_types.h index a5b7b7a1fc..b46490a2e8 100644 --- a/common/5g_platform_types.h +++ b/common/5g_platform_types.h @@ -45,6 +45,14 @@ typedef struct nr_guami_s { uint8_t amf_pointer; } nr_guami_t; +typedef enum { + PDUSessionType_ipv4 = 0, + PDUSessionType_ipv6 = 1, + PDUSessionType_ipv4v6 = 2, + PDUSessionType_ethernet = 3, + PDUSessionType_unstructured = 4 +} pdu_session_type_t; + typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t; #endif diff --git a/common/platform_types.h b/common/platform_types.h index e345288061..9827dba974 100644 --- a/common/platform_types.h +++ b/common/platform_types.h @@ -218,25 +218,27 @@ typedef struct nr_lcid_rb_t { } nr_lcid_rb_t; typedef struct transport_layer_addr_s { - /** - * Transport Layer Address as a bitstring: - * - 32 bits for IPv4 (RFC 791), - * - 128 bits for IPv6 (RFC 2460), - * - 160 bits for both IPv4 and IPv6, with IPv4 in the first 32 bits. - * The S1AP/NGAP layer forwards this address (bitstring<1..160>) - * to S1-U/NG-U without interpreting it. - */ + /** Transport Layer Address in bytes: + * - 4 bytes for IPv4 (RFC 791), 16 bytes for IPv6 (RFC 2460), + * - 20 bytes for both IPv4 and IPv6, with IPv4 in the first 4 bytes. */ uint8_t length; /// Buffer: address in network byte order uint8_t buffer[20]; } transport_layer_addr_t; +/** @brief GTP tunnel configuration */ +typedef struct { + // Tunnel endpoint identifier + uint32_t teid; + // Transport layer address + transport_layer_addr_t addr; +} gtpu_tunnel_t; + //----------------------------------------------------------------------------- // GTPV1U TYPES //----------------------------------------------------------------------------- typedef uint32_t teid_t; // tunnel endpoint identifier typedef uint8_t ebi_t; // eps bearer id -typedef uint8_t pdusessionid_t; //----------------------------------------------------------------------------- // diff --git a/common/utils/ds/seq_arr.c b/common/utils/ds/seq_arr.c index 708552a24e..50a332a16b 100644 --- a/common/utils/ds/seq_arr.c +++ b/common/utils/ds/seq_arr.c @@ -123,11 +123,10 @@ void seq_arr_erase_it(seq_arr_t* arr, void* start_it, void* end_it, void (*free_ return; if (free_func != NULL) { - void* start_it = seq_arr_front(arr); - void* end_it = seq_arr_end(arr); - while (start_it != end_it) { - free_func(start_it); - start_it = seq_arr_next(arr, start_it); + void* it = start_it; + while (it != end_it) { + free_func(it); + it = seq_arr_next(arr, it); } } diff --git a/common/utils/ds/tests/test_seq_array.c b/common/utils/ds/tests/test_seq_array.c index 28a7c98b1e..e06f72c881 100644 --- a/common/utils/ds/tests/test_seq_array.c +++ b/common/utils/ds/tests/test_seq_array.c @@ -36,6 +36,13 @@ static int compar(const void* m0, const void* m1) return 1; } +static int free_func_call_count = 0; + +static void dummy_free_func(void* it) +{ + ++free_func_call_count; +} + int main() { seq_arr_t arr = {0}; @@ -83,6 +90,19 @@ int main() void* it = bsearch(&key, base, nmemb, size, compar); assert(seq_arr_dist(&arr, seq_arr_front(&arr), it) == 4); + // Regression test: erase a partial range only + // Erase 92, 93, 94 (i.e., indices 1 to 3) + int* start = seq_arr_at(&arr, 1); + int* end = seq_arr_at(&arr, 4); + seq_arr_erase_it(&arr, start, end, dummy_free_func); + + // Now values should be: [91, 95, 96, 97, 98, 99] + assert(free_func_call_count == 3); + assert(seq_arr_size(&arr) == 6); + assert(*(int*)seq_arr_at(&arr, 0) == 91); + assert(*(int*)seq_arr_at(&arr, 1) == 95); + assert(*(int*)seq_arr_at(&arr, 5) == 99); + // Free data structure seq_arr_free(&arr, NULL); diff --git a/docker/Dockerfile.gNB.aerial.ubuntu22 b/docker/Dockerfile.gNB.aerial.ubuntu22 index c5b090f551..07bc569586 100644 --- a/docker/Dockerfile.gNB.aerial.ubuntu22 +++ b/docker/Dockerfile.gNB.aerial.ubuntu22 @@ -45,7 +45,7 @@ WORKDIR /oai-ran COPY . . RUN /bin/sh oaienv && \ - tar -xvzf nvipc_src.*.tar.gz && \ + tar -xvzf nvipc* && \ cd nvipc_src.* && \ rm -rf build && mkdir build && cd build && \ cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \ diff --git a/docker/Dockerfile.gNB.aerial.ubuntu22.sanitize-address b/docker/Dockerfile.gNB.aerial.ubuntu22.sanitize-address index 4d613718b4..c8d35aee55 100644 --- a/docker/Dockerfile.gNB.aerial.ubuntu22.sanitize-address +++ b/docker/Dockerfile.gNB.aerial.ubuntu22.sanitize-address @@ -45,7 +45,7 @@ WORKDIR /oai-ran COPY . . RUN /bin/sh oaienv && \ - tar -xvzf nvipc_src.*.tar.gz && \ + tar -xvzf nvipc* && \ cd nvipc_src.* && \ rm -rf build && mkdir build && cd build && \ cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \ diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index 5f12d1e9a2..30471c9c4f 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -163,7 +163,7 @@ typedef struct gtpv1u_gnb_create_tunnel_req_s { int num_tunnels; teid_t outgoing_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; int outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE]; - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; ebi_t incoming_rb_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; transport_layer_addr_t dst_addr[NR_GTPV1U_MAX_BEARERS_PER_UE]; } gtpv1u_gnb_create_tunnel_req_t; @@ -173,13 +173,13 @@ typedef struct gtpv1u_gnb_create_tunnel_resp_s { ue_id_t ue_id; int num_tunnels; teid_t gnb_NGu_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; transport_layer_addr_t gnb_addr; } gtpv1u_gnb_create_tunnel_resp_t; typedef struct gtpv1u_gnb_delete_tunnel_req_s { ue_id_t ue_id; uint8_t num_pdusession; - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; } gtpv1u_gnb_delete_tunnel_req_t; typedef struct gtpv1u_gnb_delete_tunnel_resp_s { @@ -192,7 +192,7 @@ typedef struct gtpv1u_gnb_delete_tunnel_resp_s { typedef struct gtpv1u_DU_buffer_report_req_s { uint32_t buffer_availability; ue_id_t ue_id; - pdusessionid_t pdusession_id; + int pdusession_id; } gtpv1u_DU_buffer_report_req_t; #endif /* GTPV1_U_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/ngap_messages_def.h b/openair2/COMMON/ngap_messages_def.h index 62498698f2..4f05a564c4 100644 --- a/openair2/COMMON/ngap_messages_def.h +++ b/openair2/COMMON/ngap_messages_def.h @@ -71,9 +71,6 @@ MESSAGE_DEF(NGAP_UE_CTXT_MODIFICATION_FAIL , MESSAGE_PRIORITY_MED, ngap_ue_ctxt_ MESSAGE_DEF(NGAP_PDUSESSION_SETUP_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_setup_resp_t , ngap_pdusession_setup_resp) MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_resp_t , ngap_pdusession_modify_resp) MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, ngap_pdusession_release_resp_t , ngap_pdusession_release_resp) -MESSAGE_DEF(NGAP_PATH_SWITCH_REQ , MESSAGE_PRIORITY_MED, ngap_path_switch_req_t , ngap_path_switch_req) -MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_ACK , MESSAGE_PRIORITY_MED, ngap_path_switch_req_ack_t , ngap_path_switch_req_ack) -MESSAGE_DEF(NGAP_PDUSESSION_MODIFICATION_IND , MESSAGE_PRIORITY_MED, ngap_pdusession_modification_ind_t , ngap_pdusession_modification_ind) /* NGAP -> RRC messages */ MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas ) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index b899bb33e2..2ad2db97bd 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -231,36 +231,6 @@ typedef struct ngap_mobility_restriction_s{ ngap_plmn_identity_t serving_plmn; }ngap_mobility_restriction_t; -typedef enum pdu_session_type_e { - PDUSessionType_ipv4 = 0, - PDUSessionType_ipv6 = 1, - PDUSessionType_ipv4v6 = 2, - PDUSessionType_ethernet = 3, - PDUSessionType_unstructured = 4 -}pdu_session_type_t; - -typedef struct pdusession_s { - /* Unique pdusession_id for the UE. */ - int pdusession_id; - byte_array_t nas_pdu; - byte_array_t pdusessionTransfer; - uint8_t nb_qos; - /* Quality of service for this pdusession */ - pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; - /* The transport layer address for the IP packets */ - pdu_session_type_t pdu_session_type; - transport_layer_addr_t upf_addr; - /* Outgoing (UL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gtp_teid; - /* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gNB_teid_N3; - transport_layer_addr_t gNB_addr_N3; - /* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t UPF_teid_N3; - transport_layer_addr_t UPF_addr_N3; - nssai_t nssai; -} pdusession_t; - typedef enum pdusession_qosflow_mapping_ind_e{ QOSFLOW_MAPPING_INDICATION_UL = 0, QOSFLOW_MAPPING_INDICATION_DL = 1, @@ -278,10 +248,9 @@ typedef struct pdusession_setup_s { /* The transport layer address for the IP packets */ uint8_t pdu_session_type; - transport_layer_addr_t gNB_addr; - /* Incoming NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gtp_teid; + // NG-U (N3) Tunnel Endpoint on the RAN side + gtpu_tunnel_t n3_outgoing; /* qos flow list number */ uint8_t nb_of_qos_flow; @@ -290,18 +259,6 @@ typedef struct pdusession_setup_s { pdusession_associate_qosflow_t associated_qos_flows[QOSFLOW_MAX_VALUE]; } pdusession_setup_t; -typedef struct pdusession_tobeswitched_s { - /* Unique pdusession_id for the UE. */ - uint8_t pdusession_id; - - /* The transport layer address for the IP packets */ - uint8_t pdu_session_type; - transport_layer_addr_t upf_addr; - - /* S-GW Tunnel endpoint identifier */ - uint32_t gtp_teid; -} pdusession_tobeswitched_t; - typedef struct qos_flow_tobe_modified_s { uint8_t qfi; // 0~63 } qos_flow_tobe_modified_t; @@ -580,6 +537,22 @@ typedef struct ngap_downlink_nas_s { byte_array_t nas_pdu; } ngap_downlink_nas_t; +/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ +typedef struct { + uint8_t nb_qos; + pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; + pdu_session_type_t pdu_session_type; + // UPF endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_incoming; +} pdusession_transfer_t; + +/* PDU Session Resource Setup/Modify Request Item */ +typedef struct { + int pdusession_id; + byte_array_t nas_pdu; + nssai_t nssai; + pdusession_transfer_t pdusessionTransfer; +} pdusession_resource_item_t; typedef struct ngap_initial_context_setup_req_s { /* UE id for initial connection to NGAP */ @@ -605,8 +578,8 @@ typedef struct ngap_initial_context_setup_req_s { /* Number of pdusession to be setup in the list */ uint8_t nb_of_pdusessions; - /* list of pdusession to be setup by RRC layers */ - pdusession_t pdusession_param[NGAP_MAX_PDU_SESSION]; + // PDU Session Resource Setup Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; /* Mobility Restriction List */ uint8_t mobility_restriction_flag; @@ -640,13 +613,6 @@ typedef struct ngap_paging_ind_s { ngap_paging_priority_t paging_priority; } ngap_paging_ind_t; -typedef struct { - /* Unique pdusession_id for the UE. */ - int pdusession_id; - byte_array_t nas_pdu; - byte_array_t pdusessionTransfer; -} pdusession_setup_req_t; - typedef struct ngap_pdusession_setup_req_s { /* UE id for initial connection to NGAP */ uint32_t gNB_ue_ngap_id; @@ -661,8 +627,8 @@ typedef struct ngap_pdusession_setup_req_s { /* Number of pdusession to be setup in the list */ uint8_t nb_pdusessions_tosetup; - /* E RAB setup request */ - pdusession_t pdusession_setup_params[NGAP_MAX_PDU_SESSION]; + // PDU Session Resource Setup Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; /* UE Aggregated Max Bitrates */ ngap_ambr_t ueAggMaxBitRate; @@ -682,78 +648,6 @@ typedef struct ngap_pdusession_setup_resp_s { pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_setup_resp_t; -typedef struct ngap_path_switch_req_s { - uint32_t gNB_ue_ngap_id; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_of_pdusessions; - - /* list of pdusession setup-ed by RRC layers */ - pdusession_setup_t pdusessions_tobeswitched[NGAP_MAX_PDU_SESSION]; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - nr_guami_t ue_guami; - - uint16_t ue_initial_id; - /* Security algorithms */ - ngap_security_capabilities_t security_capabilities; - -} ngap_path_switch_req_t; - -typedef struct ngap_path_switch_req_ack_s { - - /* UE id for initial connection to NGAP */ - uint16_t ue_initial_id; - - uint32_t gNB_ue_ngap_id; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - /* UE aggregate maximum bitrate */ - ngap_ambr_t ue_ambr; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_pdusessions_tobeswitched; - - /* list of pdusession to be switched by RRC layers */ - pdusession_tobeswitched_t pdusessions_tobeswitched[NGAP_MAX_PDU_SESSION]; - - /* Number of pdusessions to be released by RRC */ - uint8_t nb_pdusessions_tobereleased; - - /* list of pdusessions to be released */ - pdusession_failed_t pdusessions_tobereleased[NGAP_MAX_PDU_SESSION]; - - /* Security key */ - int next_hop_chain_count; - uint8_t next_security_key[SECURITY_KEY_LENGTH]; - -} ngap_path_switch_req_ack_t; - -typedef struct ngap_pdusession_modification_ind_s { - - uint32_t gNB_ue_ngap_id; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_of_pdusessions_tobemodified; - - uint8_t nb_of_pdusessions_nottobemodified; - - /* list of pdusession setup-ed by RRC layers */ - pdusession_setup_t pdusessions_tobemodified[NGAP_MAX_PDU_SESSION]; - - pdusession_setup_t pdusessions_nottobemodified[NGAP_MAX_PDU_SESSION]; - - uint16_t ue_initial_id; - -} ngap_pdusession_modification_ind_t; - // NGAP --> RRC messages typedef struct ngap_ue_release_command_s { @@ -789,8 +683,8 @@ typedef struct ngap_pdusession_modify_req_s { /* Number of pdusession to be modify in the list */ uint8_t nb_pdusessions_tomodify; - /* pdu session modify request */ - pdusession_t pdusession_modify_params[NGAP_MAX_PDU_SESSION]; + // PDU Session Resource Modify Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_modify_req_t; typedef struct ngap_pdusession_modify_resp_s { diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c index 31d96433c1..158c126c39 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c @@ -65,8 +65,8 @@ bool read_gtp_sm(void * data) int nb_pdu_session = ue_context_p->ue_context.nb_of_pdusessions; if (nb_pdu_session > 0) { int nb_pdu_idx = nb_pdu_session - 1; - gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gNB_teid_N3; - gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.UPF_teid_N3; + gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.n3_outgoing.teid; + gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.n3_incoming.teid; // TODO: one PDU session has multiple QoS Flow int nb_qos_flow = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos; if (nb_qos_flow > 0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 3fa16f6a51..534b955f7b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -269,7 +269,7 @@ static rnti_t lcid_crnti_lookahead(uint8_t *pdu, uint32_t pdu_len) if (lcid == UL_SCH_LCID_C_RNTI) { // Extract C-RNTI value rnti_t crnti = ((pdu[1] & 0xFF) << 8) | (pdu[2] & 0xFF); - LOG_D(NR_MAC, "Received a MAC CE for C-RNTI with %04x\n", crnti); + LOG_A(NR_MAC, "Received a MAC CE for C-RNTI with %04x\n", crnti); return crnti; } else if (lcid == UL_SCH_LCID_PADDING) { // End of MAC PDU, can ignore the remaining bytes @@ -783,26 +783,33 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, // Reset HARQ processes reset_dl_harq_list(&old_UE->UE_sched_ctrl); reset_ul_harq_list(&old_UE->UE_sched_ctrl); - // Trigger RRC Reconfiguration - LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti); - nr_mac_trigger_reconfiguration(mac, old_UE); + + // Only trigger RRCReconfiguration if UE is not performing RRCReestablishment + // The RRCReconfiguration will be triggered by the RRCReestablishmentComplete + if (!old_UE->reconfigSpCellConfig) { + LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti); + // Trigger RRCReconfiguration + nr_mac_trigger_reconfiguration(mac, old_UE); + // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration + configure_UE_BWP(mac, scc, old_UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); + } nr_release_ra_UE(mac, rnti); - LOG_A(NR_MAC, "%4d.%2d UE %04x: RA with C-RNTI complete\n", frame, slot, crnti); - // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration - configure_UE_BWP(mac, scc, old_UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); - // TODO do we actually need to still process the PDU? + LOG_A(NR_MAC, "%4d.%2d RA with C-RNTI %04x complete\n", frame, slot, crnti); + + // Decode the entire MAC PDU + // It may have multiple MAC subPDUs, for example, a MAC subPDU with LCID 1 caring a RRCReestablishmentComplete nr_process_mac_pdu(mod_id, old_UE, CC_id, frame, slot, sdu, sdu_len, -1); return; - } else { - // UE Contention Resolution Identity - // Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4 - // First byte corresponds to R/LCID MAC sub-header - memcpy(ra->cont_res_id, &sdu[1], sizeof(uint8_t) * 6); } - // Decode MAC PDU for the correct UE, after checking for MAC CE for C-RNTI - // harq_pid set a non valid value because it is not used in this call + // UE Contention Resolution Identity + // Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4 + // First byte corresponds to R/LCID MAC sub-header + memcpy(ra->cont_res_id, &sdu[1], sizeof(uint8_t) * 6); + + // Decode MAC PDU // the function is only called to decode the contention resolution sub-header + // harq_pid set a non-valid value because it is not used in this call nr_process_mac_pdu(mod_id, UE, CC_id, frame, slot, sdu, sdu_len, -1); LOG_I(NR_MAC, diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index f3402bcf81..41d41cf922 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -136,10 +136,10 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, } if (entity->has_ciphering) - entity->cipher(entity->security_context, - buffer + header_size + sdap_header_size, - size - (header_size + sdap_header_size), - entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); + entity->decipher(entity->security_context, + buffer + header_size + sdap_header_size, + size - (header_size + sdap_header_size), + entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); if (entity->has_integrity) { unsigned char integrity[PDCP_INTEGRITY_SIZE] = {0}; @@ -380,10 +380,12 @@ static void nr_pdcp_entity_set_security(struct nr_pdcp_entity_t *entity, if (parameters->ciphering_algorithm == 2) { entity->security_context = nr_pdcp_security_nea2_init(entity->security_keys_and_algos.ciphering_key); entity->cipher = nr_pdcp_security_nea2_cipher; + entity->decipher = nr_pdcp_security_nea2_cipher; entity->free_security = nr_pdcp_security_nea2_free_security; } else if (parameters->ciphering_algorithm == 1) { entity->security_context = nr_pdcp_security_nea1_init(entity->security_keys_and_algos.ciphering_key); entity->cipher = nr_pdcp_security_nea1_cipher; + entity->decipher = nr_pdcp_security_nea1_cipher; entity->free_security = nr_pdcp_security_nea1_free_security; } else { LOG_E(PDCP, "FATAL: only nea1 and nea2 supported for the moment\n"); diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h index f05ba07b02..7f1297ac3e 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h @@ -156,6 +156,9 @@ typedef struct nr_pdcp_entity_t { void (*cipher)(stream_security_context_t *security_context, unsigned char *buffer, int length, int bearer, uint32_t count, int direction); + void (*decipher)(stream_security_context_t *security_context, + unsigned char *buffer, int length, + int bearer, uint32_t count, int direction); void (*free_security)(stream_security_context_t *security_context); stream_security_context_t *integrity_context; void (*integrity)(stream_security_context_t *integrity_context, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index f2434eceaf..804657e8ce 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -99,6 +99,22 @@ typedef enum pdu_session_satus_e { PDU_SESSION_STATUS_RELEASED } pdu_session_status_t; +typedef struct pdusession_s { + /* Unique pdusession_id for the UE. */ + int pdusession_id; + byte_array_t nas_pdu; + uint8_t nb_qos; + /* Quality of service for this pdusession */ + pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; + /* The transport layer address for the IP packets */ + pdu_session_type_t pdu_session_type; + // NG-RAN endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_outgoing; + // UPF endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_incoming; + nssai_t nssai; +} pdusession_t; + typedef struct pdu_session_param_s { pdusession_t param; pdu_session_status_t status; @@ -106,16 +122,6 @@ typedef struct pdu_session_param_s { ngap_cause_t cause; } rrc_pdu_session_param_t; -/** - * @brief F1-U tunnel configuration -*/ -typedef struct f1u_tunnel_s { - /* F1-U Tunnel Endpoint Identifier (on DU side) */ - uint32_t teid; - /* Downlink F1-U Transport Layer (on DU side) */ - transport_layer_addr_t addr; -} f1u_tunnel_t; - typedef struct drb_s { int status; int drb_id; @@ -145,9 +151,9 @@ typedef struct drb_s { } ext1; } pdcp_config; // F1-U Downlink Tunnel Config (on DU side) - f1u_tunnel_t du_tunnel_config; + gtpu_tunnel_t du_tunnel_config; // F1-U Uplink Tunnel Config (on CU-UP side) - f1u_tunnel_t cuup_tunnel_config; + gtpu_tunnel_t cuup_tunnel_config; } drb_t; typedef enum { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2ef11ce605..520dc469d0 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2004,14 +2004,13 @@ static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_b drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid; } -/** - * @brief Store F1-U DL TL and TEID in RRC -*/ -static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p) +static gtpu_tunnel_t f1u_gtp_update(uint32_t teid, const in_addr_t addr) { - f1u->teid = p->teid; - memcpy(&f1u->addr.buffer, &p->tl_address, sizeof(uint8_t) * 4); - f1u->addr.length = sizeof(in_addr_t); + gtpu_tunnel_t out = {0}; + out.teid = teid; + memcpy(&out.addr.buffer, &addr, 4); + out.addr.length = sizeof(addr); + return out; } /** @@ -2024,20 +2023,10 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R AssertFatal(drb_f1->up_dl_tnl_length == 1, "can handle only one UP param\n"); AssertFatal(drb_f1->drb_id < MAX_DRBS_PER_UE, "illegal DRB ID %ld\n", drb_f1->drb_id); drb_t *drb = get_drb(ue, drb_f1->drb_id); - f1u_dl_gtp_update(&drb->du_tunnel_config, &drb_f1->up_dl_tnl[0]); + drb->du_tunnel_config = f1u_gtp_update(drb_f1->up_dl_tnl[0].teid, drb_f1->up_dl_tnl[0].tl_address); } } -/* - * @brief Store F1-U UL TEID and address in RRC - */ -static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p) -{ - f1u->teid = p->tl_info.teId; - memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4); - f1u->addr.length = sizeof(in_addr_t); -} - /* \brief use list of DRBs and send the corresponding bearer update message via * E1 to the CU of this UE. Also updates TEID info internally */ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) @@ -2460,9 +2449,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id); continue; } - rrc_pdu->param.gNB_teid_N3 = e1_pdu->tl_info.teId; - memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4); - rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t); + rrc_pdu->param.n3_outgoing = f1u_gtp_update(e1_pdu->tl_info.teId, e1_pdu->tl_info.tlAddress); // save the tunnel address for the DRBs for (int i = 0; i < e1_pdu->numDRBSetup; i++) { @@ -2470,7 +2457,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp // numUpParam only relevant in F1, but not monolithic AssertFatal(drb_config->numUpParam <= 1, "can only up to one UP param\n"); drb_t *drb = get_drb(UE, drb_config->id); - f1u_ul_gtp_update(&drb->cuup_tunnel_config, &drb_config->UpParamList[0]); + UP_TL_information_t *tl_info = &drb_config->UpParamList[0].tl_info; + drb->cuup_tunnel_config = f1u_gtp_update(tl_info->teId, tl_info->tlAddress); } } diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 9fd4306962..72aad97750 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "E1AP_ConfidentialityProtectionIndication.h" #include "E1AP_IntegrityProtectionIndication.h" #include "NGAP_CauseRadioNetwork.h" @@ -161,6 +162,20 @@ static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn) return guami; } +/** @brief Copy NGAP PDU Session Resource item to RRC pdusession_t struct */ +static void cp_pdusession_resource_item_to_pdusession(pdusession_t *dst, const pdusession_resource_item_t *src) +{ + dst->pdusession_id = src->pdusession_id; + dst->nas_pdu = src->nas_pdu; + dst->nb_qos = src->pdusessionTransfer.nb_qos; + for (uint8_t i = 0; i < src->pdusessionTransfer.nb_qos && i < QOSFLOW_MAX_VALUE; ++i) { + dst->qos[i] = src->pdusessionTransfer.qos[i]; + } + dst->pdu_session_type = src->pdusessionTransfer.pdu_session_type; + dst->n3_incoming = src->pdusessionTransfer.n3_incoming; + dst->nssai = src->nssai; +} + /** * @brief Prepare the Initial UE Message (Uplink NAS) to be forwarded to the AMF over N2 * extracts NAS PDU, Selected PLMN and Registered AMF from the RRCSetupComplete @@ -225,114 +240,6 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC itti_send_msg_to_task(TASK_NGAP, rrc->module_id, message_p); } -static void fill_qos(NGAP_QosFlowSetupRequestList_t *qos, pdusession_t *session) -{ - DevAssert(qos->list.count > 0); - DevAssert(qos->list.count <= NGAP_maxnoofQosFlows); - for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) { - NGAP_QosFlowSetupRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx]; - // Set the QOS informations - session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; - NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics; - AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx); - if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { - AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = NON_DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI; - } else { - AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI); - } - - ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority; - NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters.allocationAndRetentionPriority; - tmp->priority_level = tmp2->priorityLevelARP; - tmp->pre_emp_capability = tmp2->pre_emptionCapability; - tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability; - } - session->nb_qos = qos->list.count; -} - -static int decodePDUSessionResourceSetup(pdusession_t *session) -{ - NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = NULL; - asn_codec_ctx_t st = {.max_stack_size = 100 * 1000}; - asn_dec_rval_t dec_rval = aper_decode(&st, - &asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, - (void **)&pdusessionTransfer, - session->pdusessionTransfer.buf, - session->pdusessionTransfer.len, - 0, - 0); - - if (dec_rval.code != RC_OK) { - LOG_E(NR_RRC, "can not decode PDUSessionResourceSetupRequestTransfer\n"); - return -1; - } - - for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) { - NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i]; - switch (pdusessionTransfer_ies->id) { - /* optional PDUSessionAggregateMaximumBitRate */ - case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate: - break; - - /* mandatory UL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: { - NGAP_GTPTunnel_t *gTPTunnel_p = pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel; - - /* Set the transport layer address */ - memcpy(session->upf_addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); - - session->upf_addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused; - - /* GTP tunnel endpoint ID */ - OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, session->gtp_teid); - } - - break; - - /* optional AdditionalUL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation: - break; - - /* optional DataForwardingNotPossible */ - case NGAP_ProtocolIE_ID_id_DataForwardingNotPossible: - break; - - /* mandatory PDUSessionType */ - case NGAP_ProtocolIE_ID_id_PDUSessionType: - session->pdu_session_type = (uint8_t)pdusessionTransfer_ies->value.choice.PDUSessionType; - break; - - /* optional SecurityIndication */ - case NGAP_ProtocolIE_ID_id_SecurityIndication: - break; - - /* optional NetworkInstance */ - case NGAP_ProtocolIE_ID_id_NetworkInstance: - break; - - /* mandatory QosFlowSetupRequestList */ - case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: - fill_qos(&pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList, session); - break; - - /* optional CommonNetworkInstance */ - case NGAP_ProtocolIE_ID_id_CommonNetworkInstance: - break; - - default: - LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id); - return -1; - } - } - ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer); - - return 0; -} - /** * @brief Triggers bearer setup for the specified UE. * @@ -360,13 +267,7 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession for (int i = 0; i < n; i++) { rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true); pdusession_t *session = &pduSession->param; - session->pdusession_id = sessions[i].pdusession_id; - LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); - session->pdu_session_type = sessions[i].pdu_session_type; - session->nas_pdu = sessions[i].nas_pdu; - session->pdusessionTransfer = sessions[i].pdusessionTransfer; - session->nssai = sessions[i].nssai; - decodePDUSessionResourceSetup(session); + cp_pdusession(session, &sessions[i]); bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; security_information_t *secInfo = &bearer_req.secInfo; secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; @@ -386,8 +287,12 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession : SECURITY_NOT_NEEDED; sec->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? SECURITY_REQUIRED : SECURITY_NOT_NEEDED; - pdu->UP_TL_information.teId = session->gtp_teid; - memcpy(&pdu->UP_TL_information.tlAddress, session->upf_addr.buffer, sizeof(in_addr_t)); + gtpu_tunnel_t *n3_incoming = &session->n3_incoming; + pdu->UP_TL_information.teId = n3_incoming->teid; + memcpy(&pdu->UP_TL_information.tlAddress, n3_incoming->addr.buffer, sizeof(in_addr_t)); + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, n3_incoming->addr.buffer, ip_str, sizeof(ip_str)); + LOG_I(NR_RRC, "Bearer Context Setup: PDU Session ID=%d, incoming TEID=0x%08x, Addr=%s\n", session->pdusession_id, n3_incoming->teid, ip_str); /* we assume for the moment one DRB per PDU session. Activate the bearer, * and configure in RRC. */ @@ -480,7 +385,7 @@ static void send_ngap_initial_context_setup_resp_fail(instance_t instance, resp->gNB_ue_ngap_id = msg->gNB_ue_ngap_id; for (int i = 0; i < msg->nb_of_pdusessions; i++) { - fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession_param[i].pdusession_id, cause); + fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession[i].pdusession_id, cause); } resp->nb_of_pdusessions = 0; resp->nb_of_pdusessions_failed = msg->nb_of_pdusessions; @@ -519,10 +424,9 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t /* if there are PDU sessions to setup, store them to be created once * security (and UE capabilities) are received */ UE->n_initial_pdu = req->nb_of_pdusessions; - UE->initial_pdus = calloc(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); - AssertFatal(UE->initial_pdus != NULL, "out of memory\n"); + UE->initial_pdus = calloc_or_fail(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); for (int i = 0; i < UE->n_initial_pdu; ++i) - UE->initial_pdus[i] = req->pdusession_param[i]; + cp_pdusession_resource_item_to_pdusession(&UE->initial_pdus[i], &req->pdusession[i]); } /* security */ @@ -567,6 +471,15 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t return 0; } +static gtpu_tunnel_t cp_gtp_tunnel(const gtpu_tunnel_t in) +{ + gtpu_tunnel_t out = {0}; + out.teid = in.teid; + out.addr.length = in.addr.length; + memcpy(out.addr.buffer, in.addr.buffer, out.addr.length); + return out; +} + void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) { MessageDef *msg_p = NULL; @@ -582,11 +495,7 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_ if (session->status == PDU_SESSION_STATUS_DONE) { pdu_sessions_done++; resp->pdusessions[pdusession].pdusession_id = session->param.pdusession_id; - resp->pdusessions[pdusession].gtp_teid = session->param.gNB_teid_N3; - memcpy(resp->pdusessions[pdusession].gNB_addr.buffer, - session->param.gNB_addr_N3.buffer, - sizeof(resp->pdusessions[pdusession].gNB_addr.buffer)); - resp->pdusessions[pdusession].gNB_addr.length = 4; // Fixme: IPv4 hard coded here + resp->pdusessions[pdusession].n3_outgoing = cp_gtp_tunnel(session->param.n3_outgoing); resp->pdusessions[pdusession].nb_of_qos_flow = session->param.nb_qos; for (int qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) { resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; @@ -777,25 +686,18 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE pdusession_setup_t *tmp = &resp->pdusessions[pdu_sessions_done]; tmp->pdusession_id = session->param.pdusession_id; tmp->nb_of_qos_flow = session->param.nb_qos; - tmp->gtp_teid = session->param.gNB_teid_N3; + tmp->n3_outgoing = cp_gtp_tunnel(session->param.n3_outgoing); tmp->pdu_session_type = session->param.pdu_session_type; - tmp->gNB_addr.length = session->param.gNB_addr_N3.length; - memcpy(tmp->gNB_addr.buffer, session->param.gNB_addr_N3.buffer, tmp->gNB_addr.length); + for (int qos_flow_index = 0; qos_flow_index < tmp->nb_of_qos_flow; qos_flow_index++) { tmp->associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; tmp->associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; } session->status = PDU_SESSION_STATUS_ESTABLISHED; - LOG_I(NR_RRC, - "msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d, pdusession_id %d, teid: %u \n ", - pdu_sessions_done, - pdusession, - session->status, - xid, - UE->nb_of_pdusessions, - tmp->pdusession_id, - tmp->gtp_teid); + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, tmp->n3_outgoing.addr.buffer, ip_str, sizeof(ip_str)); + LOG_I(NR_RRC, "PDU Session Setup Response: ID=%d, outgoing TEID=0x%08x, Addr=%s\n", tmp->pdusession_id, tmp->n3_outgoing.teid, ip_str); pdu_sessions_done++; } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { session->status = PDU_SESSION_STATUS_FAILED; @@ -807,10 +709,6 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE } resp->nb_of_pdusessions = pdu_sessions_done; resp->nb_of_pdusessions_failed = pdu_sessions_failed; - // } else { - // LOG_D(NR_RRC,"xid does not corresponds (context pdu_sessions index %d, status %d, xid %d/%d) \n ", - // pdusession, UE->pdusession[pdusession].status, xid, UE->pdusession[pdusession].xid); - // } } if ((pdu_sessions_done > 0 || pdu_sessions_failed)) { @@ -860,9 +758,7 @@ static void send_ngap_pdu_session_setup_resp_fail(instance_t instance, ngap_pdus resp->nb_of_pdusessions_failed = msg->nb_pdusessions_tosetup; resp->nb_of_pdusessions = 0; for (int i = 0; i < resp->nb_of_pdusessions_failed; ++i) { - fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], - msg->pdusession_setup_params[i].pdusession_id, - cause); + fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession[i].pdusession_id, cause); } itti_send_msg_to_task(TASK_NGAP, instance, msg_resp); } @@ -908,7 +804,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins // At least one because marking one as existing, and setting up another, that // might be more work than is worth it. See 8.2.1.4 in 38.413 for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) { - const pdusession_t *p = &msg->pdusession_setup_params[i]; + const pdusession_resource_item_t *p = &msg->pdusession[i]; rrc_pdu_session_param_t *exist = find_pduSession(UE, p->pdusession_id, false /* don't create */); if (exist) { LOG_E(NR_RRC, "UE %d: already has existing PDU session %d rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id, p->pdusession_id); @@ -941,7 +837,11 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return; } - if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRate.br_dl)) { + pdusession_t to_setup[NGAP_MAX_PDU_SESSION] = {0}; + for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) + cp_pdusession_resource_item_to_pdusession(&to_setup[i], &msg->pdusession[i]); + + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, to_setup, msg->ueAggMaxBitRate.br_dl)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE}; @@ -952,104 +852,6 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins } } -static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *session) -{ - // we need to duplicate the function fill_qos because all data types are slightly different - DevAssert(qos->list.count > 0); - DevAssert(qos->list.count <= NGAP_maxnoofQosFlows); - for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) { - NGAP_QosFlowAddOrModifyRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx]; - // Set the QOS informations - session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; - NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters->qosCharacteristics; - AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx); - if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { - AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = NON_DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI; - } else { - AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI); - } - - ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority; - NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters->allocationAndRetentionPriority; - tmp->priority_level = tmp2->priorityLevelARP; - tmp->pre_emp_capability = tmp2->pre_emptionCapability; - tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability; - } - session->nb_qos = qos->list.count; -} - -static void decodePDUSessionResourceModify(pdusession_t *param, const byte_array_t pdu) -{ - NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = NULL; - asn_dec_rval_t dec_rval = aper_decode(NULL, - &asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, - (void **)&pdusessionTransfer, - pdu.buf, - pdu.len, - 0, - 0); - - if (dec_rval.code != RC_OK) { - LOG_E(NR_RRC, "could not decode PDUSessionResourceModifyRequestTransfer\n"); - return; - } - - for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) { - NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j]; - switch (pdusessionTransfer_ies->id) { - /* optional PDUSessionAggregateMaximumBitRate */ - case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate\n"); - break; - - /* optional UL-NGU-UP-TNLModifyList */ - case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList\n"); - break; - - /* optional NetworkInstance */ - case NGAP_ProtocolIE_ID_id_NetworkInstance: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_NetworkInstance\n"); - break; - - /* optional QosFlowAddOrModifyRequestList */ - case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList: - fill_qos2(&pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList, param); - break; - - /* optional QosFlowToReleaseList */ - case NGAP_ProtocolIE_ID_id_QosFlowToReleaseList: - // TODO - LOG_E(NR_RRC, "Can't handle NGAP_ProtocolIE_ID_id_QosFlowToReleaseList\n"); - break; - - /* optional AdditionalUL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation\n"); - break; - - /* optional CommonNetworkInstance */ - case NGAP_ProtocolIE_ID_id_CommonNetworkInstance: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_CommonNetworkInstance\n"); - break; - - default: - LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id); - return; - } - } - ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer,pdusessionTransfer ); -} - //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t instance) //------------------------------------------------------------------------------ @@ -1069,7 +871,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins bool all_failed = true; for (int i = 0; i < req->nb_pdusessions_tomodify; i++) { rrc_pdu_session_param_t *sess; - const pdusession_t *sessMod = req->pdusession_modify_params + i; + const pdusession_resource_item_t *sessMod = req->pdusession + i; for (sess = UE->pduSession; sess < UE->pduSession + UE->nb_of_pdusessions; sess++) if (sess->param.pdusession_id == sessMod->pdusession_id) break; @@ -1093,10 +895,8 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins if (sessMod->nas_pdu.buf != NULL) { UE->pduSession[i].param.nas_pdu = sessMod->nas_pdu; } - // Save new pdu session parameters, qos, upf addr, teid - decodePDUSessionResourceModify(&sess->param, UE->pduSession[i].param.pdusessionTransfer); - sess->param.UPF_addr_N3 = sessMod->upf_addr; - sess->param.UPF_teid_N3 = sessMod->gtp_teid; + for (int i = 0; i < req->nb_pdusessions_tomodify; ++i) + cp_pdusession_resource_item_to_pdusession(&UE->pduSession[i].param, &req->pdusession[i]); } } @@ -1457,16 +1257,6 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ return 0; } -void nr_rrc_rx_tx(void) { - // check timers - - // check if UEs are lost, to remove them from upper layers - - // - -} - -/*------------------------------------------------------------------------------*/ int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance) { for (uint16_t tai_size = 0; tai_size < NGAP_PAGING_IND(msg_p).tai_size; tai_size++) { diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index e22ee7ffd6..7bed45ee64 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -32,6 +32,15 @@ #include "oai_asn1.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h" +/** @brief Deep copy pdusession_t */ +void cp_pdusession(pdusession_t *dst, const pdusession_t *src) +{ + // Shallow copy + *dst = *src; + // nas_pdu + dst->nas_pdu = copy_byte_array(src->nas_pdu); +} + rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create) { int j; @@ -208,11 +217,3 @@ int get_number_active_drbs(gNB_RRC_UE_t *ue) n++; return n; } - -bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) -{ - drb_t *drb = get_drb(ue, drb_id); - if (drb == NULL) - return DRB_INACTIVE; - return drb->status != DRB_INACTIVE; -} diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index 4a249496ff..1eac60a609 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -65,9 +65,6 @@ uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue); /// @brief returns the number of active DRBs for this UE int get_number_active_drbs(gNB_RRC_UE_t *ue); -/// @brief check if DRB with ID drb_id of UE ue is active -bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id); - /// @brief retrieve PDU session of UE ue with ID id, optionally creating it if /// create is true rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create); @@ -81,4 +78,7 @@ void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_S /// @brief set PDCP configuration in a bearer context management message void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb); +/// @brief Deep copy an instance of struct pdusession_t +void cp_pdusession(pdusession_t *dst, const pdusession_t *src); + #endif diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt index 0f4445c353..7aafc588e2 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt @@ -14,6 +14,7 @@ add_library(fgs_5gmm_lib OBJECT FGSUplinkNasTransport.c FGSDeregistrationRequestUEOriginating.c fgmm_authentication_failure.c + fgmm_authentication_reject.c ) target_link_libraries(fgs_5gmm_lib PUBLIC fgs_5gmm_ies_lib) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.c new file mode 100644 index 0000000000..193df8f7dd --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.c @@ -0,0 +1,69 @@ +/* + * 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 "fgmm_authentication_reject.h" +#include +#include // For htons and ntohs +#include // For malloc and free +#include "fgmm_lib.h" + +#define MIN_AUTH_REJECT_LEN 3 + +/** @brief Encode Authentication Reject (8.2.5 of 3GPP TS 24.501) */ +int encode_fgmm_auth_reject(byte_array_t *buffer, const fgmm_auth_reject_msg_t *msg) +{ + uint32_t encoded = 0; + + const byte_array_t *eap_msg = &msg->eap_msg; + if (eap_msg->len > 0) { + return encode_eap_msg_ie(buffer, eap_msg); + } + return encoded; +} + +/** @brief Decode Authentication Reject (8.2.5 of 3GPP TS 24.501) + * the message contains only optional IEIs (EAP MSG) */ +int decode_fgmm_auth_reject(fgmm_auth_reject_msg_t *msg, const byte_array_t *buffer) +{ + if (buffer->len < MIN_AUTH_REJECT_LEN) { + // No optional IEIs present + return 0; + } + byte_array_t ba = *buffer; // Local copy of buffer + uint32_t decoded = 0; + // Decode the IEI + uint8_t iei = buffer->buf[decoded++]; + UPDATE_BYTE_ARRAY(ba, decoded); + if (iei == IEI_EAPMSG) { + return (decoded + decode_eap_msg_ie(&msg->eap_msg, &ba)); + } + PRINT_NAS_ERROR("Expected EAP MSG but it is not present"); + return -1; +} + +bool eq_auth_reject(fgmm_auth_reject_msg_t *a, fgmm_auth_reject_msg_t *b) +{ + _NAS_EQ_CHECK_LONG(a->eap_msg.len, b->eap_msg.len); + if (a->eap_msg.len > 0) { + return !memcmp(a->eap_msg.buf, b->eap_msg.buf, a->eap_msg.len); + } + return true; +} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.h new file mode 100644 index 0000000000..33ae7a5181 --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.h @@ -0,0 +1,38 @@ +/* + * 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 FGMM_AUTH_REJECT_H +#define FGMM_AUTH_REJECT_H + +#include +#include "fgmm_lib.h" +#include "common/utils/ds/byte_array.h" + +typedef struct { + // EAP Message (Optional) + byte_array_t eap_msg; +} fgmm_auth_reject_msg_t; + +int decode_fgmm_auth_reject(fgmm_auth_reject_msg_t *msg, const byte_array_t *buffer); +int encode_fgmm_auth_reject(byte_array_t *buffer, const fgmm_auth_reject_msg_t *msg); +bool eq_auth_reject(fgmm_auth_reject_msg_t *a, fgmm_auth_reject_msg_t *b); + +#endif /* FGMM_AUTH_REJECT_H */ diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c index 1b607589d9..63c6ec0d32 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c @@ -25,8 +25,11 @@ #include // For malloc and free #include "common/utils/ds/byte_array.h" +#define IEI_LEN 1 #define GPRS_TIMER_LENGTH 3 // octets #define FGS_NAS_CAUSE_LENGTH 1 +#define MIN_EAP_MSG_LEN 7 +#define MIN_EAP_CONTENTS_LEN 4 /** * Encode PDU Session Status and PDU session reactivation result (optional IEs) @@ -152,12 +155,72 @@ bool eq_gprs_timer(const gprs_timer_t *a, const gprs_timer_t *b) return true; } -/* Decode EAP Message (todo) */ -int decode_eap_msg_ie(const byte_array_t *buffer) +/** @brief Encode EAP message IE (3GPP TS 24.501 9.11.2.2) */ +int encode_eap_msg_ie(byte_array_t *buffer, const byte_array_t *msg) { - int eap_msg_len = (buffer->buf[0] << 8) | buffer->buf[1]; - PRINT_NAS_ERROR("EAP message IE in NAS Service Reject is not handled\n"); - return eap_msg_len + 2; // content length + 2 octets for the length IE + int encoded = 0; + + // Sanity check on buffer length + if (buffer->len < MIN_EAP_MSG_LEN) { + PRINT_NAS_ERROR("Invalid buffer length %ld", buffer->len); + return -1; + } + + // Sanity check on input length + if (msg->len < MIN_EAP_CONTENTS_LEN || msg->len > MAX_EAP_CONTENTS_LEN) { + PRINT_NAS_ERROR("Invalid EAP message length %ld", msg->len); + return -1; + } + + // Encode IEI + buffer->buf[encoded++] = IEI_EAPMSG; + + // Encode length of EAP message content + uint16_t len = htons(msg->len); + memcpy(&buffer->buf[encoded], &len, sizeof(len)); + encoded += sizeof(len); + + // Encode EAP message content + memcpy(&buffer->buf[encoded], msg->buf, msg->len); + encoded += msg->len; + + return encoded; +} + +/** @brief Decode EAP message IE (3GPP TS 24.501 9.11.2.2): + length of contents and message payload */ +int decode_eap_msg_ie(byte_array_t *eap_msg, const byte_array_t *buffer) +{ + int decoded = 0; + int min_len_to_decode = MIN_EAP_MSG_LEN - IEI_LEN; + + // Check buffer length validity + if (buffer->len < min_len_to_decode) { + PRINT_NAS_ERROR("Invalid buffer for decoding EAP message IE"); + return -1; + } + + // Decode length IE + eap_msg->len = (buffer->buf[decoded] << 8) | buffer->buf[decoded + 1]; + decoded += 2; + + // Check payload length validity + if (eap_msg->len < MIN_EAP_CONTENTS_LEN || eap_msg->len > MAX_EAP_CONTENTS_LEN) { + PRINT_NAS_ERROR("Invalid EAP message length %ld", eap_msg->len); + return -1; + } + + // Check for buffer overflow + if (buffer->len < decoded + eap_msg->len) { + PRINT_NAS_ERROR("Buffer too short for EAP message: %ld < %ld", buffer->len, decoded + eap_msg->len); + return -1; + } + + // Copy EAP payload + memcpy(eap_msg->buf, &buffer->buf[decoded], eap_msg->len); + decoded += eap_msg->len; + + return decoded; } int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h index 25118f2742..8d833e74aa 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h @@ -39,6 +39,7 @@ both PDU Session Status and PDU session Reactivation Result IEs */ #define MAX_PDU_SESSION_CONTENTS_LEN 32 #define MAX_NUM_PSI 16 #define MAX_NUM_PDU_ERRORS 256 +#define MAX_EAP_CONTENTS_LEN 1500 /* This macro updates the local copy of a byte_array_t pointer used for enc/dec */ @@ -164,7 +165,8 @@ int decode_pdu_session_ie(uint8_t *psi, const byte_array_t *buffer); int encode_gprs_timer_ie(byte_array_t *buffer, nas_service_IEI_t iei, const gprs_timer_t *timer); int decode_gprs_timer_ie(gprs_timer_t *timer, const byte_array_t *buffer); bool eq_gprs_timer(const gprs_timer_t *a, const gprs_timer_t *b); -int decode_eap_msg_ie(const byte_array_t *buffer); +int decode_eap_msg_ie(byte_array_t *eap_msg, const byte_array_t *buffer); +int encode_eap_msg_ie(byte_array_t *buffer, const byte_array_t *msg); int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause); int decode_fgs_nas_cause(cause_id_t *cause, const byte_array_t *buffer); diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c index 797deede84..63e2901f61 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c @@ -133,7 +133,7 @@ int decode_fgs_service_accept(fgs_service_accept_msg_t *msg, const byte_array_t break; case IEI_EAPMSG: - DECODE_NAS_IE(ba, decode_eap_msg_ie(&ba), decoded); + DECODE_NAS_IE(ba, decode_eap_msg_ie(&msg->eap_msg, &ba), decoded); break; default: diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h index 9f82f47eb1..c5d042b674 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h @@ -47,6 +47,9 @@ typedef struct { // T3448 Value (Optional) gprs_timer_t *t3448; + + // EAP Message (Optional) + byte_array_t eap_msg; } fgs_service_accept_msg_t; int decode_fgs_service_accept(fgs_service_accept_msg_t *msg, const byte_array_t *buffer); diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.c index 74175fda36..14078637a3 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.c @@ -59,6 +59,11 @@ int encode_fgs_service_reject(byte_array_t *buffer, const fgs_service_reject_msg ENCODE_NAS_IE(ba, encode_gprs_timer_ie(&ba, IEI_T3448_VALUE, msg->t3448), encoded); } + // EAP message (Optional) + if (msg->eap_msg) { + ENCODE_NAS_IE(ba, encode_eap_msg_ie(&ba, msg->eap_msg), encoded); + } + return encoded; } @@ -99,7 +104,7 @@ int decode_fgs_service_reject(fgs_service_reject_msg_t *msg, const byte_array_t break; case IEI_EAPMSG: - DECODE_NAS_IE(ba, decode_eap_msg_ie((const byte_array_t *)&ba), decoded); + DECODE_NAS_IE(ba, decode_eap_msg_ie(msg->eap_msg, &ba), decoded); break; case IEI_CAG_INFO_LIST: { diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.h index 61337d8525..29c8ab9b72 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.h @@ -35,6 +35,8 @@ typedef struct { bool has_psi_status; // T3448 Value (Optional) gprs_timer_t *t3448; + // EAP message (optional) + byte_array_t *eap_msg; } fgs_service_reject_msg_t; int decode_fgs_service_reject(fgs_service_reject_msg_t *msg, const byte_array_t *buffer); diff --git a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c index f733bdd3a5..d9f837d6b0 100644 --- a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c +++ b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c @@ -9,6 +9,7 @@ #include "fgmm_service_reject.h" #include "fgmm_authentication_failure.h" #include "FGSNASSecurityModeReject.h" +#include "fgmm_authentication_reject.h" #include "nr_nas_msg.h" void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) @@ -298,6 +299,44 @@ static void test_security_mode_reject(void) AssertFatal(eq_sec_mode_reject(&orig, &dec), "test_sec_mode_reject() failed: original and decoded messages do not match\n"); } +/** + * @brief Test NAS Authentication Reject enc/dec + */ +static void test_auth_reject(void) +{ + // Dummy NAS Authentication Reject message + uint8_t dummy_eap_msg[] = {0x12, 0x34, 0x56, 0x78, 0x91, 0x01, 0x23}; // Example EAP message + fgmm_auth_reject_msg_t orig = { + .eap_msg.len = sizeof(dummy_eap_msg), + }; + orig.eap_msg.buf = dummy_eap_msg; + + // Expected encoded data + uint8_t expected_enc[] = {0x78, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78, 0x91, 0x01, 0x23}; + + // Buffer + uint8_t buf[10] = {0}; + byte_array_t buffer = {.buf = buf, .len = sizeof(buf)}; + + // Encode + int encoded_length = encode_fgmm_auth_reject(&buffer, &orig); + AssertFatal(encoded_length >= 0, "encode_fgmm_auth_reject() failed\n"); + + // Compare the raw encoded buffer with expected encoded data + AssertFatal(encoded_length == sizeof(expected_enc), "Encoded length mismatch %d != %ld \n", encoded_length, sizeof(expected_enc)); + AssertFatal(memcmp(buffer.buf, expected_enc, encoded_length) == 0, "Encoding mismatch!\n"); + + // Decode + fgmm_auth_reject_msg_t dec = {0}; + uint8_t eap_msg[1500] = {0}; + dec.eap_msg.buf = eap_msg; + int decoded_length = decode_fgmm_auth_reject(&dec, &buffer); + AssertFatal(decoded_length >= 0, "decode_fgmm_auth_reject() failed\n"); + + // Compare original and decoded messages + AssertFatal(eq_auth_reject(&orig, &dec), "test_auth_reject() failed: original and decoded messages do not match\n"); +} + int main() { test_regression_registration_accept(); @@ -305,6 +344,7 @@ int main() test_service_accept(); test_service_reject(); test_auth_failure(); + test_auth_reject(); test_security_mode_reject(); return 0; } diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index d7fb313fa8..69a910a0e7 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -71,6 +71,7 @@ #include "fgs_nas_utils.h" #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" +#include "fgmm_authentication_reject.h" #include "ds/byte_array.h" #include "key_nas_deriver.h" @@ -1063,6 +1064,33 @@ static void handle_fgmm_authentication_request(nr_ue_nas_t *nas, as_nas_info_t * generateAuthenticationResp(nas, initialNasMsg, buffer->buf); } +/** @brief Handle authentication not accepted by the network + * This function assumes the message is not integrity protected, processes the received + * NAS message and logs whether a EAP-failure is enclosed. The UE enters state: 5GMM-DEREGISTERED. + * @todo The UE shall performs actions as per 5.4.1.3.5 of 3GPP TS 24.501, including + * (1) Abort any ongoing 5GMM procedure (2) Stop all active timers: T3510, T3516, T3517, + * T3519, T3520, T3521 (3) Delete stored SUCI. (4) handle EAP-failure message. */ +static void handle_authentication_reject(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *pdu, int pdu_length) +{ + LOG_E(NAS, "Received Authentication Reject message from the network\n"); + uint8_t eap_msg[MAX_EAP_CONTENTS_LEN] = {0}; + fgmm_auth_reject_msg_t msg = {.eap_msg.buf = eap_msg}; + + byte_array_t ba = {.buf = pdu + 3 /* skip header */, .len = pdu_length}; + if (decode_fgmm_auth_reject(&msg, &ba) < 0) { + LOG_E(NAS, "Could not decode Authentication Reject\n"); + return; + } + + if (msg.eap_msg.len > 0) { + /** @todo UE handling EAP-failure message (5.4.1.2.2.11 of 3GPP TS 24.501) */ + LOG_W(NAS, "NAS Authentication Reject contains an EAP message: handling is not implemented\n"); + log_hex_buffer("EAP-Failure", msg.eap_msg.buf, msg.eap_msg.len); + } + + nas->fiveGMM_state = FGS_DEREGISTERED; +} + int nas_itti_kgnb_refresh_req(instance_t instance, const uint8_t kgnb[32]) { MessageDef *message_p; @@ -2064,6 +2092,9 @@ void *nas_nrue(void *args_p) case FGS_AUTHENTICATION_REQUEST: handle_fgmm_authentication_request(nas, &initialNasMsg, &buffer); break; + case FGS_AUTHENTICATION_REJECT: + handle_authentication_reject(nas, &initialNasMsg, pdu_buffer, pdu_length); + break; case FGS_SECURITY_MODE_COMMAND: handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length); break; diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index ae8d806e18..8edb5c3aa3 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -344,14 +344,6 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { ngap_gNB_nas_non_delivery_ind(instance, &NGAP_NAS_NON_DELIVERY_IND(received_msg)); break; - case NGAP_PATH_SWITCH_REQ: - ngap_gNB_path_switch_req(instance, &NGAP_PATH_SWITCH_REQ(received_msg)); - break; - - case NGAP_PDUSESSION_MODIFICATION_IND: - ngap_gNB_generate_PDUSESSION_Modification_Indication(instance, &NGAP_PDUSESSION_MODIFICATION_IND(received_msg)); - break; - case NGAP_UE_CONTEXT_RELEASE_COMPLETE: ngap_ue_context_release_complete(instance, &NGAP_UE_CONTEXT_RELEASE_COMPLETE(received_msg)); break; diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 3f6b718861..f4c4ebb20f 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -694,6 +694,99 @@ static int ngap_gNB_handle_error_indication(sctp_assoc_t assoc_id, uint32_t stre return 0; } +static void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf) +{ + void *decoded = NULL; + asn_codec_ctx_t ctx = {.max_stack_size = 100 * 1000}; + asn_dec_rval_t rval = aper_decode(&ctx, td, &decoded, buf.buf, buf.size, 0, 0); + if (rval.code != RC_OK) { + NGAP_ERROR("Decoding failed for %s\n", td->name); + return NULL; + } + return decoded; +} + +static pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params) +{ + pdusession_level_qos_parameter_t out = {0}; + // QFI + out.qfi = qfi; + AssertFatal(params != NULL, "QoS parameters are NULL\n"); + // QosCharacteristics + const NGAP_QosCharacteristics_t *qosChar = ¶ms->qosCharacteristics; + AssertFatal(qosChar != NULL, "QoS characteristics are NULL\n"); + if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { + AssertFatal(qosChar->choice.nonDynamic5QI != NULL, "nonDynamic5QI is NULL\n"); + out.fiveQI_type = NON_DYNAMIC; + out.fiveQI = qosChar->choice.nonDynamic5QI->fiveQI; + } else if (qosChar->present == NGAP_QosCharacteristics_PR_dynamic5QI) { + AssertFatal(qosChar->choice.dynamic5QI != NULL, "dynamic5QI is NULL\n"); + out.fiveQI_type = DYNAMIC; + out.fiveQI = *qosChar->choice.dynamic5QI->fiveQI; + } else { + AssertFatal(0, "Unsupported QoS Characteristics present value: %d\n", qosChar->present); + } + // Allocation and Retention Priority + const NGAP_AllocationAndRetentionPriority_t *arp = ¶ms->allocationAndRetentionPriority; + out.allocation_retention_priority.priority_level = arp->priorityLevelARP; + out.allocation_retention_priority.pre_emp_capability = arp->pre_emptionCapability; + out.allocation_retention_priority.pre_emp_vulnerability = arp->pre_emptionVulnerability; + + return out; +} + +static gtpu_tunnel_t decode_TNLInformation(const NGAP_GTPTunnel_t *gTPTunnel_p) +{ + gtpu_tunnel_t out = {0}; + // Transport layer address + memcpy(out.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); + out.addr.length = gTPTunnel_p->transportLayerAddress.size - gTPTunnel_p->transportLayerAddress.bits_unused; + // GTP tunnel endpoint ID + OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, out.teid); + return out; +} + +/** @brief Decode PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ +static bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in) +{ + void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, in); + if (!decoded) { + LOG_E(NR_RRC, "Failed to decode PDUSessionResourceSetupRequestTransfer\n"); + return false; + } + + NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceSetupRequestTransfer_t *)decoded; + for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) { + NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i]; + switch (pdusessionTransfer_ies->id) { + // UL NG-U UP TNL Information (Mandatory) + case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: + out->n3_incoming = decode_TNLInformation(pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel); + break; + + // PDU Session Type (Mandatory) + case NGAP_ProtocolIE_ID_id_PDUSessionType: + out->pdu_session_type = pdusessionTransfer_ies->value.choice.PDUSessionType; + break; + + // QoS Flow Setup Request List (Mandatory) + case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: + out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.count; + for (int i = 0; i < out->nb_qos; i++) { + NGAP_QosFlowSetupRequestItem_t *item = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.array[i]; + out->qos[i] = fill_qos(item->qosFlowIdentifier, &item->qosFlowLevelQosParameters); + } + break; + + default: + LOG_D(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id); + } + } + ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer); + + return true; +} + static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { int i; @@ -762,13 +855,16 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 for (i = 0; i < ie->value.choice.PDUSessionResourceSetupListCxtReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemCxtReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.array[i]; - msg->pdusession_param[i].pdusession_id = item_p->pDUSessionID; - msg->pdusession_param[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); if (item_p->nAS_PDU) { - msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + } + bool ret = decodePDUSessionResourceSetup(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + if (!ret) { + NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Initial Context Setup Request\n"); + return -1; } - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; - msg->pdusession_param[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } } @@ -936,16 +1032,19 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 for (int i = 0; i < ie->value.choice.PDUSessionResourceSetupListSUReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemSUReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListSUReq.list.array[i]; - msg->pdusession_setup_params[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; // S-NSSAI - msg->pdusession_setup_params[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; - msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); - msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); + bool ret = decodePDUSessionResourceSetup(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + if (!ret) { + NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Setup Request\n"); + return -1; + } } - itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); + itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); return 0; } @@ -1039,6 +1138,37 @@ static int ngap_gNB_handle_paging(sctp_assoc_t assoc_id, uint32_t stream, NGAP_N return 0; } +static bool decodePDUSessionResourceModify(pdusession_transfer_t *out, const OCTET_STRING_t in) +{ + void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, in); + if (!decoded) { + LOG_E(NR_RRC, "Failed to decode PDUSessionResourceModifyRequestTransfer\n"); + return false; + } + + NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceModifyRequestTransfer_t *)decoded; + for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) { + NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j]; + switch (pdusessionTransfer_ies->id) { + /* optional QosFlowAddOrModifyRequestList */ + case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList: + out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.count; + for (int i = 0; i < out->nb_qos; i++) { + NGAP_QosFlowAddOrModifyRequestItem_t *item = + pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.array[i]; + out->qos[i] = fill_qos(item->qosFlowIdentifier, item->qosFlowLevelQosParameters); + } + break; + + default: + LOG_E(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id); + return false; + } + } + ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, pdusessionTransfer); + return true; +} + static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { ngap_gNB_amf_data_t *amf_desc_p = NULL; @@ -1116,13 +1246,15 @@ static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint for (int i = 0; i < ie->value.choice.PDUSessionResourceModifyListModReq.list.count; i++) { NGAP_PDUSessionResourceModifyItemModReq_t *item_p = ie->value.choice.PDUSessionResourceModifyListModReq.list.array[i]; - msg->pdusession_modify_params[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; // check for the NAS PDU if (item_p->nAS_PDU != NULL && item_p->nAS_PDU->size > 0) { - msg->pdusession_modify_params[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceModifyRequestTransfer; - msg->pdusession_modify_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + if (!decodePDUSessionResourceModify(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceModifyRequestTransfer)) { + NGAP_ERROR("Failed to decode pDUSessionResourceModifyRequestTransfer\n"); + return -1; + } } else { LOG_W(NGAP, "received pdu session modify with void content for UE %u, pdu session %lu\n", msg->gNB_ue_ngap_id, item_p->pDUSessionID); continue; diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index b00ce13f32..1aafeca8c9 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "BIT_STRING.h" #include "INTEGER.h" #include "ngap_msg_includes.h" @@ -57,6 +58,7 @@ #include "oai_asn1.h" #include "s1ap_messages_types.h" #include "xer_encoder.h" +#include "ds/byte_array.h" /** @brief Selects the AMF instance for a given UE based on identity information. * It attempts to select an AMF using the following prioritized criteria: @@ -537,6 +539,46 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance, return 0; } +/** @brief PDU Session Resource Setup Response Transfer encoding (9.3.4.2 3GPP TS 38.413) */ +static byte_array_t encode_ngap_pdusession_setup_response_transfer(const pdusession_setup_t *pdusession) +{ + NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; + byte_array_t out = {0}; + + // DL QoS Flow per TNL Information (Mandatory) + NGAP_QosFlowPerTNLInformation_t *dLQosFlowPerTNLInformation = &pdusessionTransfer.dLQosFlowPerTNLInformation; + + // UP Transport Layer Information (Mandatory) + dLQosFlowPerTNLInformation->uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc(dLQosFlowPerTNLInformation->uPTransportLayerInformation.choice.gTPTunnel, gtp); + GTP_TEID_TO_ASN1(pdusession->n3_outgoing.teid, >p->gTP_TEID); + tnl_to_bitstring(>p->transportLayerAddress, pdusession->n3_outgoing.addr); + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, gtp->transportLayerAddress.buf, ip_str, sizeof(ip_str)); + NGAP_DEBUG("Encoded PDU Session Transfer (%d): TEID=0x%08x, Addr=%s\n", + pdusession->pdusession_id, + pdusession->n3_outgoing.teid, + ip_str); + + // Associated QoS Flow List (Mandatory) + for (int j = 0; j < pdusession->nb_of_qos_flow; j++) { + asn1cSequenceAdd(dLQosFlowPerTNLInformation->associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, qos_item); + // QoS Flow Identifier (Mandatory) + qos_item->qosFlowIdentifier = pdusession->associated_qos_flows[j].qfi; + } + + // Encode + asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, + ATS_ALIGNED_CANONICAL_PER, + &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, + &pdusessionTransfer); + AssertFatal(res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + out.buf = res.buffer; + out.len = res.result.encoded; + return out; +} + //------------------------------------------------------------------------------ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_resp_t *initial_ctxt_resp_p) //------------------------------------------------------------------------------ @@ -606,39 +648,10 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r asn1cSequenceAdd(ie->value.choice.PDUSessionResourceSetupListCxtRes.list, NGAP_PDUSessionResourceSetupItemCxtRes_t, item); /* pDUSessionID */ item->pDUSessionID = initial_ctxt_resp_p->pdusessions[i].pdusession_id; - - /* dLQosFlowPerTNLInformation */ - NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; - - pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; - - asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); - GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].gtp_teid, &tmp->gTP_TEID); - tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); - - NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", - item->pDUSessionID, - tmp->transportLayerAddress.buf[0], - tmp->transportLayerAddress.buf[1], - tmp->transportLayerAddress.buf[2], - tmp->transportLayerAddress.buf[3], - tmp->transportLayerAddress.size, - initial_ctxt_resp_p->pdusessions[i].gtp_teid); - - /* associatedQosFlowList. number of 1? */ - for(int j=0; j < initial_ctxt_resp_p->pdusessions[i].nb_of_qos_flow; j++) { - asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); - /* qosFlowIdentifier */ - ass_qos_item_p->qosFlowIdentifier = initial_ctxt_resp_p->pdusessions[i].associated_qos_flows[j].qfi; - } - - void *pdusessionTransfer_buffer; - ssize_t encoded = aper_encode_to_new_buffer(&asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, NULL, &pdusessionTransfer, &pdusessionTransfer_buffer); - AssertFatal(encoded > 0, "ASN1 message encoding failed !\n"); - item->pDUSessionResourceSetupResponseTransfer.buf = pdusessionTransfer_buffer; - item->pDUSessionResourceSetupResponseTransfer.size = encoded; - - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + // PDU Session Resource Setup Response Transfer (Mandatory) + byte_array_t ba = encode_ngap_pdusession_setup_response_transfer(&initial_ctxt_resp_p->pdusessions[i]); + item->pDUSessionResourceSetupResponseTransfer.buf = ba.buf; + item->pDUSessionResourceSetupResponseTransfer.size = ba.len; } } /* optional */ @@ -924,40 +937,10 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re /* pDUSessionID */ item->pDUSessionID = pdusession->pdusession_id; - /* dLQosFlowPerTNLInformation */ - NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; - pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); - GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID); - tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->gNB_addr); - NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", - item->pDUSessionID, - tmp->transportLayerAddress.buf[0], - tmp->transportLayerAddress.buf[1], - tmp->transportLayerAddress.buf[2], - tmp->transportLayerAddress.buf[3], - tmp->transportLayerAddress.size, - pdusession->gtp_teid); - /* associatedQosFlowList. number of 1? */ - for(int j=0; j < pdusession_setup_resp_p->pdusessions[i].nb_of_qos_flow; j++) { - asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); - - /* qosFlowIdentifier */ - ass_qos_item_p->qosFlowIdentifier = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qfi; - - /* qosFlowMappingIndication */ - // if(pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind != QOSFLOW_MAPPING_INDICATION_NON) { - // ass_qos_item_p->qosFlowMappingIndication = malloc(sizeof(*ass_qos_item_p->qosFlowMappingIndication)); - // *ass_qos_item_p->qosFlowMappingIndication = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind; - // } - } - - asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); - AssertFatal (res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); - item->pDUSessionResourceSetupResponseTransfer.buf = res.buffer; - item->pDUSessionResourceSetupResponseTransfer.size = res.result.encoded; - - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + // PDU Session Resource Setup Response Transfer (Mandatory) + byte_array_t ba = encode_ngap_pdusession_setup_response_transfer(pdusession); + item->pDUSessionResourceSetupResponseTransfer.buf = ba.buf; + item->pDUSessionResourceSetupResponseTransfer.size = ba.len; } } @@ -1225,17 +1208,3 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas return 0; } -int ngap_gNB_path_switch_req(instance_t instance, ngap_path_switch_req_t *path_switch_req_p) -//------------------------------------------------------------------------------ -{ - //TODO - - return 0; -} - -int ngap_gNB_generate_PDUSESSION_Modification_Indication(instance_t instance, ngap_pdusession_modification_ind_t *pdusession_modification_ind) -//----------------------------------------------------------------------------- -{ - //TODO - return 0; -} diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.h b/openair3/NGAP/ngap_gNB_nas_procedures.h index 3cd03838b4..5189e6b311 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.h +++ b/openair3/NGAP/ngap_gNB_nas_procedures.h @@ -63,10 +63,4 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_release_resp_t *pdusession_release_resp_p); -int ngap_gNB_path_switch_req(instance_t instance, - ngap_path_switch_req_t *path_switch_req_p); - -int ngap_gNB_generate_PDUSESSION_Modification_Indication( - instance_t instance, ngap_pdusession_modification_ind_t *pdusession_modification_ind); - #endif /* NGAP_GNB_NAS_PROCEDURES_H_ */ diff --git a/openair3/NGAP/ngap_msg_includes.h b/openair3/NGAP/ngap_msg_includes.h index c7ef77be6a..1debc2e9f1 100644 --- a/openair3/NGAP/ngap_msg_includes.h +++ b/openair3/NGAP/ngap_msg_includes.h @@ -71,5 +71,12 @@ #include "NGAP_UnsuccessfulOutcome.h" #include "NGAP_UserLocationInformationNR.h" #include "NGAP_asn_constant.h" +#include "NGAP_PDUSessionResourceSetupRequestTransfer.h" +#include "NGAP_QosFlowSetupRequestItem.h" +#include "NGAP_QosCharacteristics.h" +#include "NGAP_NonDynamic5QIDescriptor.h" +#include "NGAP_Dynamic5QIDescriptor.h" +#include "NGAP_PDUSessionResourceModifyRequestTransfer.h" +#include "NGAP_QosFlowAddOrModifyRequestItem.h" #endif // NGAP_MSG_INCLUDES_H diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index a7cf27a1ff..3fb35adee2 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -57,7 +57,7 @@ #define NR_FC_ALG_KEY_DER (0x69) #define NR_FC_ALG_KEY_NG_RAN_STAR_DER (0x70) -static void log_hex_buffer(const char *label, const uint8_t *buf, const int len) +void log_hex_buffer(const char *label, const uint8_t *buf, const int len) { char hex_str[len * 2 + 1]; for (int i = 0; i < len; i++) { diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 0ab14ad51a..eff72c68bb 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -36,4 +36,6 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh); +void log_hex_buffer(const char *label, const uint8_t *buf, const int len); + #endif diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index fd571e8d0e..58be5ed638 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -897,7 +897,8 @@ int gtpv1u_delete_all_s1u_tunnel(const instance_t instance, const rnti_t rnti) return newGtpuDeleteAllTunnels(instance, rnti); } -int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id) { +int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id) +{ LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n", instance, ue_id); pthread_mutex_lock(&globGtp.gtp_lock); diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index d5226bb972..7a8c4da627 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -103,7 +103,7 @@ extern "C" { int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id); int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id); - int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id); + int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id); void gtpv1uSendDirect(instance_t instance, ue_id_t ue_id, int bearer_id, uint8_t *buf, size_t len, bool seqNumFlag, bool npduNumFlag);