From 052491addedfa90503ad3629f015d9c2bd629df1 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 14 Nov 2024 23:48:25 +0100 Subject: [PATCH] Add enc/dec/eq/free functions for 5GS NAS Service Accept lib * add new files for Service Accept enc/dec fgmm_service_accept.c/.h * add to CMakeLists.txt --- .../NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt | 1 + .../NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c | 184 ++++++++++++++++++ .../NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h | 57 ++++++ 3 files changed, 242 insertions(+) create mode 100644 openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c create mode 100644 openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt index 6288ece940..6947a3421c 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(fgs_5gmm_lib OBJECT fgmm_lib.c fgs_service_request.c + fgmm_service_accept.c RegistrationRequest.c RegistrationAccept.c FGSIdentityResponse.c 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 new file mode 100644 index 0000000000..7130586326 --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c @@ -0,0 +1,184 @@ +/* + * 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_service_accept.h" +#include +#include // For htons and ntohs +#include // For malloc and free +#include "common/utils/utils.h" // For malloc_or_fail +#include "common/utils/ds/byte_array.h" // For byte_array_t +#include "fgmm_lib.h" + +/** @brief Encode Service Accept (8.2.17 of 3GPP TS 24.501) */ +int encode_fgs_service_accept(byte_array_t *buffer, const fgs_service_accept_msg_t *msg) +{ + if (buffer->len < 1) + return -1; // No IEs present + + byte_array_t ba = *buffer; // Local copy of buffer + uint32_t encoded = 0; + + // Encode PDU Session Status (Optional) + if (msg->has_psi_status) { + ENCODE_NAS_IE(ba, encode_pdu_session_ie(&ba, IEI_PDU_SESSION_STATUS, msg->psi_status), encoded); + } + + // Encode PDU Session Reactivation Result (Optional) + if (msg->has_psi_res) { + ENCODE_NAS_IE(ba, encode_pdu_session_ie(&ba, IEI_PDU_SESSION_REACT_RESULT, msg->psi_res), encoded); + } + + // Encode PDU Session Reactivation Result Error Cause (Optional) + if (msg->num_errors) { + int start = encoded; + buffer->buf[encoded++] = IEI_PDU_SESSION_REACT_RESULT_ERROR_CAUSE; + // encode length of PDU session reactivation result error cause + uint16_t error_len = msg->num_errors * sizeof(msg->cause[0]); + if (error_len > MAX_NUM_PDU_ERRORS) { + PRINT_NAS_ERROR("encoded length is out of bound (IEI_PDU_SESSION_REACT_RESULT_ERROR_CAUSE)\n"); + return -1; + } + uint16_t n_len = htons(error_len); + memcpy(&buffer->buf[encoded], &n_len, sizeof(n_len)); // length payload PDU Session Status + encoded += sizeof(error_len); + // encode PDU Session IDs and Causes + for (int i = 0; i < msg->num_errors; i++) { + buffer->buf[encoded++] = msg->cause[i].pdu_session_id; + buffer->buf[encoded++] = msg->cause[i].cause; + } + UPDATE_BYTE_ARRAY(ba, encoded - start); + } + + /* Encode T3448 Timer (Optional) + 3GPP TS 24.008 10.5.7.3 GPRS Timer */ + if (msg->t3448) { + ENCODE_NAS_IE(ba, encode_gprs_timer_ie(&ba, IEI_T3448_VALUE, msg->t3448), encoded); + } + + return encoded; +} + +/** @brief Decode Service Accept (8.2.17 of 3GPP TS 24.501) */ +int decode_fgs_service_accept(fgs_service_accept_msg_t *msg, const byte_array_t *buffer) +{ + if (buffer->len < 1) + return -1; // nothing to decode + + byte_array_t ba = *buffer; // Local copy of buffer (to be used in the decoding sub-functions) + uint32_t decoded = 0; + + // Default output message before decoding + msg->has_psi_res = false; + msg->has_psi_status = false; + msg->num_errors = 0; + msg->t3448 = NULL; + + // Decode Optional IEs + while (decoded < buffer->len) { + uint8_t iei = buffer->buf[decoded++]; + UPDATE_BYTE_ARRAY(ba, 1); + + switch (iei) { + case IEI_PDU_SESSION_STATUS: + msg->has_psi_status = true; + DECODE_NAS_IE(ba, decode_pdu_session_ie(msg->psi_status, &ba), decoded); + break; + + case IEI_PDU_SESSION_REACT_RESULT: + msg->has_psi_res = true; + DECODE_NAS_IE(ba, decode_pdu_session_ie(msg->psi_res, &ba), decoded); + break; + + case IEI_PDU_SESSION_REACT_RESULT_ERROR_CAUSE: { + int start = decoded; + // Decode the length of the IE + uint16_t tmp; + memcpy(&tmp, &buffer->buf[decoded], sizeof(tmp)); + uint16_t error_len = ntohs(tmp); + decoded += sizeof(error_len); + if (error_len > MAX_NUM_PDU_ERRORS * sizeof(msg->cause[0])) { + PRINT_NAS_ERROR("IEI_PDU_SESSION_REACT_RESULT_ERROR_CAUSE: decoded length is out of bound\n"); + return -1; + } + // Decode each PDU Session ID and Cause + for (int i = 0; i < error_len; i += 2) { + msg->cause[msg->num_errors].pdu_session_id = buffer->buf[decoded++]; + msg->cause[msg->num_errors].cause = buffer->buf[decoded++]; + msg->num_errors++; + } + UPDATE_BYTE_ARRAY(ba, decoded - start); + } break; + + case IEI_T3448_VALUE: + msg->t3448 = malloc_or_fail(sizeof(*msg->t3448)); + DECODE_NAS_IE(ba, decode_gprs_timer_ie(msg->t3448, &ba), decoded); + break; + + case IEI_EAPMSG: + DECODE_NAS_IE(ba, decode_eap_msg_ie(&ba), decoded); + break; + + default: + PRINT_NAS_ERROR("Unkwown or invalid IEI %d\n", iei); + return -1; + } + } + + return decoded; +} + +/** + * @brief Equality check for Service Accept (enc/dec) + */ +bool eq_service_accept(const fgs_service_accept_msg_t *a, const fgs_service_accept_msg_t *b) +{ + _NAS_EQ_CHECK_INT(a->has_psi_status, b->has_psi_status); + if (a->has_psi_status && b->has_psi_status) { + for (int i = 0; i < MAX_NUM_PSI; i++) + _NAS_EQ_CHECK_INT(a->psi_status[i], b->psi_status[i]); + } + _NAS_EQ_CHECK_INT(a->has_psi_res, b->has_psi_res); + if (a->has_psi_res && b->has_psi_res) { + for (int i = 0; i < MAX_NUM_PSI; i++) + _NAS_EQ_CHECK_INT(a->psi_res[i], b->psi_res[i]); + } + _NAS_EQ_CHECK_INT(a->num_errors, b->num_errors); + if (a->num_errors && b->num_errors) { + for (int i = 0; i < a->num_errors; i++) { + _NAS_EQ_CHECK_INT(a->cause[i].cause, b->cause[i].cause); + _NAS_EQ_CHECK_INT(a->cause[i].pdu_session_id, b->cause[i].pdu_session_id); + } + } + if (a->t3448 != NULL || b->t3448 != NULL) { + if (a->t3448 == NULL || b->t3448 == NULL) { + PRINT_NAS_ERROR("t3448 equality check failed\n"); + return false; + } + _NAS_EQ_CHECK_INT(a->t3448->value, b->t3448->value); + _NAS_EQ_CHECK_INT(a->t3448->unit, b->t3448->unit); + } + return true; +} + +void free_fgs_service_accept(fgs_service_accept_msg_t *msg) +{ + free(msg->t3448); +} 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 new file mode 100644 index 0000000000..9f82f47eb1 --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h @@ -0,0 +1,57 @@ +/* + * 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 FGS_SERVICE_ACCEPT_H +#define FGS_SERVICE_ACCEPT_H + +#include +#include "fgs_nas_utils.h" +#include "common/utils/ds/byte_array.h" +#include "fgmm_lib.h" + +typedef struct { + uint8_t pdu_session_id; + uint8_t cause; +} pdu_error_cause_t; + +typedef struct { + // PDU Session Status (Optional) + uint8_t psi_status[MAX_NUM_PSI]; // index 0 is spare + bool has_psi_status; + + // PDU Session Reactivation Result (Optional) + uint8_t psi_res[MAX_NUM_PSI]; // index 0 is spare + bool has_psi_res; + + // PDU Session Reactivation Result Error Cause (Optional) + pdu_error_cause_t cause[MAX_NUM_PDU_ERRORS]; + uint16_t num_errors; + + // T3448 Value (Optional) + gprs_timer_t *t3448; +} fgs_service_accept_msg_t; + +int decode_fgs_service_accept(fgs_service_accept_msg_t *msg, const byte_array_t *buffer); +int encode_fgs_service_accept(byte_array_t *buffer, const fgs_service_accept_msg_t *msg); +void free_fgs_service_accept(fgs_service_accept_msg_t *msg); +bool eq_service_accept(const fgs_service_accept_msg_t *a, const fgs_service_accept_msg_t *b); + +#endif /* FGS_SERVICE_ACCEPT_H */