From 5c4595e69954f5506ee9a01b3cea614da476a33c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 15 Apr 2025 18:34:47 +0200 Subject: [PATCH 1/6] Refactor 5GS registration result enc/dec functions * adopt byte_array * move enc/dec functions to Registration Accept library * simplify code * log result received in Registration Accept --- .../NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt | 1 - .../5GS/5GMM/IES/FGSRegistrationResult.c | 58 ------------------- .../5GS/5GMM/IES/FGSRegistrationResult.h | 55 ------------------ .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 38 ++++++++++-- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 14 +++-- openair3/NAS/NR_UE/nr_nas_msg.c | 8 ++- 6 files changed, 50 insertions(+), 124 deletions(-) delete mode 100644 openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c delete mode 100644 openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt index e865dd0046..40bfcbabcd 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt @@ -1,7 +1,6 @@ add_library(fgs_5gmm_ies_lib OBJECT FGSMobileIdentity.c FGSRegistrationType.c - FGSRegistrationResult.c FGMMCapability.c NrUESecurityCapability.c FGCNasMessageContainer.c diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c b/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c deleted file mode 100644 index 739cee7973..0000000000 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file FGSRegistrationResult.c - -\brief 5GS Registration result for registration request procedures -\author Yoshio INOUE, Masayuki HARADA -\email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com -\date 2020 -\version 0.1 -*/ - -#include -#include -#include - -#include "TLVEncoder.h" -#include "TLVDecoder.h" -#include "FGSRegistrationResult.h" - -int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len) -{ - int decoded = 0; - uint16_t *buffer = &value; - fgsregistrationresult->registrationresult = *buffer & 0x7; - fgsregistrationresult->smsallowed = *buffer & 0x8; - decoded = decoded + 2; - return decoded; -} - -uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult) -{ - uint16_t bufferReturn; - uint16_t *buffer = &bufferReturn; - uint8_t encoded = 0; - *(buffer + encoded) = 0x00 | (fgsregistrationresult->smsallowed & 0x8) | (fgsregistrationresult->registrationresult & 0x7); - encoded = encoded + 2; - - return bufferReturn; -} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h b/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h deleted file mode 100644 index 04f45417b8..0000000000 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file FGSRegistrationResult.h - -\brief 5GS Registration result for registration request procedures -\author Yoshio INOUE, Masayuki HARADA -\email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com -\date 2020 -\version 0.1 -*/ - -#include -#include -#include - -#include "OctetString.h" - -#ifndef FGS_REGISTRATION_RESULT_H_ -#define FGS_REGISTRATION_RESULT_H_ -#define FGS_REGISTRATION_RESULT_3GPP 0b001 -#define FGS_REGISTRATION_RESULT_NON_3GPP 0b010 -#define FGS_REGISTRATION_RESULT_3GPP_AND_NON_3GPP 0b011 - -typedef struct { - uint8_t iei; - uint8_t resultlength; - uint8_t spare: 4; - uint8_t smsallowed: 1; - uint8_t registrationresult: 3; -} FGSRegistrationResult; - -uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult); - -int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len); - -#endif /* FGS REGISTRATION RESULT_H_*/ diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index d92244a15f..dfcb1fce94 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -38,8 +38,36 @@ #include "RegistrationAccept.h" #include "assertions.h" #include "fgs_nas_utils.h" +#include "common/utils/utils.h" +#include "ds/byte_array.h" #define IEI_5G_GUTI 0x77 +#define FGS_REGISTRATION_RESULT_LEN 2 +#define REGISTRATION_ACCEPT_MIN_LEN FGS_REGISTRATION_RESULT_LEN // (5GS registration result) 2 octets + +/** @brief Decode 5GS registration result (9.11.3.6 3GPP TS 24.501) */ +static int decode_fgs_registration_result(registration_accept_msg *out, const byte_array_t buffer) +{ + if (buffer.len < FGS_REGISTRATION_RESULT_LEN) { + PRINT_NAS_ERROR("5GS registration result decoding failure: invalid buffer length\n"); + return -1; + } + out->result = buffer.buf[1] & 0x7; // skip length of contents octet + out->sms_allowed = buffer.buf[1] & 0x8; + return 2; // length 2 octets (no IEI) +} + +static int encode_fgs_registration_result(byte_array_t buffer, const registration_accept_msg *out) +{ + if (buffer.len < FGS_REGISTRATION_RESULT_LEN) { + PRINT_NAS_ERROR("5GS registration result encoding failure: invalid buffer length\n"); + return -1; + } + uint8_t *buf = buffer.buf; + buf[0] = 1; + buf[1] = 0x00 | (out->sms_allowed & 0x8) | (out->result & 0x7); + return 2; // encoded length 2 octets (no IEI) +} /** * @brief Allowed NSSAI from Registration Accept according to 3GPP TS 24.501 Table 8.2.7.1.1 @@ -105,8 +133,9 @@ int decode_registration_accept(registration_accept_msg *registration_accept, con int dec = 0; const uint8_t *end = buffer + len; - /* Decoding mandatory fields */ - if ((dec = decode_fgs_registration_result(®istration_accept->fgsregistrationresult, 0, *buffer, len)) < 0) + // 5GS registration result (Mandatory) + byte_array_t ba = {.buf = buffer, .len = len}; + if ((dec = decode_fgs_registration_result(registration_accept, ba)) < 0) return dec; buffer += dec; @@ -149,9 +178,8 @@ int encode_registration_accept(const registration_accept_msg *registration_accep int encoded = 0; LOG_FUNC_IN; - - *(buffer + encoded) = encode_fgs_registration_result(®istration_accept->fgsregistrationresult); - encoded = encoded + 2; + byte_array_t ba = {.buf = buffer, .len = len}; + encoded += encode_fgs_registration_result(ba, registration_accept); if (registration_accept->guti) { int mi_enc = encode_5gs_mobile_identity(registration_accept->guti, 0x77, buffer + encoded, len - encoded); diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index 6abf1e70ca..5f444e95f9 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -34,12 +34,17 @@ #include "SecurityHeaderType.h" #include "MessageType.h" -#include "FGSRegistrationResult.h" #include "FGSMobileIdentity.h" #ifndef REGISTRATION_ACCEPT_H_ #define REGISTRATION_ACCEPT_H_ +typedef enum { + FGS_REGISTRATION_RESULT_3GPP = 1, + FGS_REGISTRATION_RESULT_NON_3GPP = 2, + FGS_REGISTRATION_RESULT_3GPP_AND_NON_3GPP = 3 +} fgs_registration_result_t; + // 9.11.3.37 of 3GPP TS 24.501 typedef struct { int sst; @@ -56,9 +61,10 @@ typedef struct { */ typedef struct registration_accept_msg_tag { - /* Mandatory fields */ - FGSRegistrationResult fgsregistrationresult; - /* Optional fields */ + // 5GS registration result (Mandatory) + fgs_registration_result_t result; + bool sms_allowed; + // 5G-GUTI (Optional) FGSMobileIdentity *guti; // Allowed NSSAI (O) nr_nas_msg_snssai_t nas_allowed_nssai[8]; diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 941e0d7cdc..08003bbcba 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1438,7 +1438,6 @@ static void process_guti(Guti5GSMobileIdentity_t *guti, nr_ue_nas_t *nas) static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buffer, uint32_t msg_length) { - LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n"); registration_accept_msg msg = {0}; fgs_nas_message_security_header_t sp_header = {0}; const uint8_t *end = pdu_buffer + msg_length; @@ -1465,6 +1464,13 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff LOG_E(NAS, "Failed to decode NAS Registration Accept\n"); return; } + LOG_I(NAS, + "Received Registration Accept with result %s\n", + msg.result == FGS_REGISTRATION_RESULT_3GPP ? "3GPP" + : msg.result == FGS_REGISTRATION_RESULT_NON_3GPP ? "non-3PP" + : "3GPP and non-3GPP"); + LOG_I(NAS, "SMS %s in 5GS Registration Result\n", msg.sms_allowed ? "allowed" : "not allowed"); + pdu_buffer += decoded; // process GUTI if (msg.guti) { From 51661bd83ccffd8fa1d9f10c53c7a9968039139d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 7 Feb 2025 17:18:00 +0100 Subject: [PATCH 2/6] Cleanup and other fixes to decode_registration_accept * adopt byte array * add check on minimum buffer length * improve comments * remove call to LOG utility functions * replace magic numbers with defines * refined includes --- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 56 ++++++++++--------- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 13 +++-- openair3/NAS/NR_UE/nr_nas_msg.c | 3 +- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index dfcb1fce94..ed0de936f5 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -33,13 +33,11 @@ #include #include #include "conversions.h" -#include "TLVEncoder.h" -#include "TLVDecoder.h" #include "RegistrationAccept.h" -#include "assertions.h" #include "fgs_nas_utils.h" #include "common/utils/utils.h" #include "ds/byte_array.h" +#include "fgmm_lib.h" #define IEI_5G_GUTI 0x77 #define FGS_REGISTRATION_RESULT_LEN 2 @@ -128,56 +126,65 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) return decoded; } -int decode_registration_accept(registration_accept_msg *registration_accept, const uint8_t *buffer, uint32_t len) +size_t decode_registration_accept(registration_accept_msg *registration_accept, const byte_array_t buffer) { int dec = 0; - const uint8_t *end = buffer + len; + byte_array_t ba = buffer; // local copy of buffer + + if (ba.len < REGISTRATION_ACCEPT_MIN_LEN) { + PRINT_NAS_ERROR("Registration Accept decoding failed: invalid buffer length\n"); + return -1; + } // 5GS registration result (Mandatory) - byte_array_t ba = {.buf = buffer, .len = len}; if ((dec = decode_fgs_registration_result(registration_accept, ba)) < 0) - return dec; - buffer += dec; + return -1; + UPDATE_BYTE_ARRAY(ba, dec); - if (buffer < end && *buffer == IEI_5G_GUTI) { + // 5G-GUTI (Optional) + if (ba.len > 0 && ba.buf[0] == IEI_5G_GUTI) { registration_accept->guti = calloc_or_fail(1, sizeof(*registration_accept->guti)); - if ((dec = decode_5gs_mobile_identity(registration_accept->guti, IEI_5G_GUTI, buffer, end - buffer)) < 0) { + if ((dec = decode_5gs_mobile_identity(registration_accept->guti, IEI_5G_GUTI, ba.buf, ba.len)) < 0) { PRINT_NAS_ERROR("Failed to decode 5GS Mobile Identity in Registration Accept\n"); return -1; } - buffer += dec; + UPDATE_BYTE_ARRAY(ba, dec); } - // Allowed NSSAI (O) - /* Optional Presence IEs */ - while (buffer < end) { - const int iei = *buffer++; + // Decode other Optional IEs + while (ba.len > 0) { + uint8_t iei = ba.buf[0]; + UPDATE_BYTE_ARRAY(ba, 1); + switch (iei) { case 0x15: // allowed NSSAI - dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, buffer); - buffer += dec; + dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, ba.buf); + UPDATE_BYTE_ARRAY(ba, dec); break; case 0x31: // configured NSSAI - dec = decode_nssai_ie(registration_accept->config_nssai, buffer); - buffer += dec; + dec = decode_nssai_ie(registration_accept->config_nssai, ba.buf); + UPDATE_BYTE_ARRAY(ba, dec); break; default: - dec = *buffer++; // content length + 1 byte (Length IE) - buffer += dec; + dec = ba.buf[0] + 1; // content length + 1 byte (Length IE) + UPDATE_BYTE_ARRAY(ba, dec); break; } } - return len; + if(ba.len != 0) { + PRINT_NAS_ERROR("Failed to decode registration accept: ba.len = %ld\n", ba.len); + return -1; + } + return buffer.len; } int encode_registration_accept(const registration_accept_msg *registration_accept, uint8_t *buffer, uint32_t len) { int encoded = 0; - LOG_FUNC_IN; byte_array_t ba = {.buf = buffer, .len = len}; encoded += encode_fgs_registration_result(ba, registration_accept); @@ -188,6 +195,5 @@ int encode_registration_accept(const registration_accept_msg *registration_accep encoded += mi_enc; } - // todo ,Encoding optional fields - LOG_FUNC_RETURN(encoded); + return encoded; } diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index 5f444e95f9..8c044603de 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -35,6 +35,7 @@ #include "SecurityHeaderType.h" #include "MessageType.h" #include "FGSMobileIdentity.h" +#include "ds/byte_array.h" #ifndef REGISTRATION_ACCEPT_H_ #define REGISTRATION_ACCEPT_H_ @@ -45,6 +46,8 @@ typedef enum { FGS_REGISTRATION_RESULT_3GPP_AND_NON_3GPP = 3 } fgs_registration_result_t; +#define NAS_MAX_NUMBER_SLICES 8 + // 9.11.3.37 of 3GPP TS 24.501 typedef struct { int sst; @@ -66,13 +69,13 @@ typedef struct registration_accept_msg_tag { bool sms_allowed; // 5G-GUTI (Optional) FGSMobileIdentity *guti; - // Allowed NSSAI (O) - nr_nas_msg_snssai_t nas_allowed_nssai[8]; - // Configured NSSAI (O) - nr_nas_msg_snssai_t config_nssai[8]; + // Allowed NSSAI (Optional) + nr_nas_msg_snssai_t nas_allowed_nssai[NAS_MAX_NUMBER_SLICES]; + // Configured NSSAI (Optional) + nr_nas_msg_snssai_t config_nssai[NAS_MAX_NUMBER_SLICES]; } registration_accept_msg; -int decode_registration_accept(registration_accept_msg *registrationaccept, const uint8_t *buffer, uint32_t len); +size_t decode_registration_accept(registration_accept_msg *registrationaccept, const byte_array_t buffer); int encode_registration_accept(const registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 08003bbcba..5ee233172c 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1460,7 +1460,8 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff } pdu_buffer += decoded; // plain payload - if ((decoded = decode_registration_accept(&msg, pdu_buffer, end - pdu_buffer)) < 0) { + const byte_array_t ba = {.buf = (uint8_t *)pdu_buffer, .len = end - pdu_buffer}; + if ((decoded = decode_registration_accept(&msg, ba)) < 0) { LOG_E(NAS, "Failed to decode NAS Registration Accept\n"); return; } From c6271a23e4b1e94997616e332199dee6207c059e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 15 Apr 2025 17:42:56 +0200 Subject: [PATCH 3/6] Add number of slices to decoding of NSSAI --- openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 7 ++++--- openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index ed0de936f5..d65d196701 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -70,7 +70,7 @@ static int encode_fgs_registration_result(byte_array_t buffer, const registratio /** * @brief Allowed NSSAI from Registration Accept according to 3GPP TS 24.501 Table 8.2.7.1.1 */ -static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) +static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, uint8_t *num_slices, uint8_t *buf) { const int length = *buf; // Length of S-NSSAI IE contents (list of S-NSSAIs) const uint32_t decoded = length + 1; // Length IE (1 octet) @@ -123,6 +123,7 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) break; } } + *num_slices = nssai_cnt; return decoded; } @@ -159,12 +160,12 @@ size_t decode_registration_accept(registration_accept_msg *registration_accept, switch (iei) { case 0x15: // allowed NSSAI - dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, ba.buf); + dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, ®istration_accept->num_allowed_slices, ba.buf); UPDATE_BYTE_ARRAY(ba, dec); break; case 0x31: // configured NSSAI - dec = decode_nssai_ie(registration_accept->config_nssai, ba.buf); + dec = decode_nssai_ie(registration_accept->config_nssai, ®istration_accept->num_configured_slices, ba.buf); UPDATE_BYTE_ARRAY(ba, dec); break; diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index 8c044603de..4c50de9384 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -71,8 +71,10 @@ typedef struct registration_accept_msg_tag { FGSMobileIdentity *guti; // Allowed NSSAI (Optional) nr_nas_msg_snssai_t nas_allowed_nssai[NAS_MAX_NUMBER_SLICES]; + uint8_t num_allowed_slices; // Configured NSSAI (Optional) nr_nas_msg_snssai_t config_nssai[NAS_MAX_NUMBER_SLICES]; + uint8_t num_configured_slices; } registration_accept_msg; size_t decode_registration_accept(registration_accept_msg *registrationaccept, const byte_array_t buffer); From 73b89726ad993f5accdfe9e60bb2ea94662076c6 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 7 Feb 2025 17:24:27 +0100 Subject: [PATCH 4/6] Remove harcoded Slice Differentiator (SD) in NAS decode_nssai_ie and update the processing logic The SD stored in the allowed S-NSSAI list was hardcoded in the decoding function, however this IE is not mandatory but optional, therefore the check of the decoded message contents should take into account this and check the stored value against the one from the UICC only when the field is present. If no SD was received, consider the UICC SD a valid one. Also, add free function to Registration Accept library and adopt in stack to free NAS Registration Accept after use: heap memory is allocated for this message during decoding and shall be free after processing. --- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 40 +++++++++++++++---- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 8 ++-- openair3/NAS/NR_UE/nr_nas_msg.c | 12 ++++-- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index d65d196701..f6b67edb11 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -79,7 +79,6 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, uint8_t *num_slices, uint const uint8_t *end = buf + length; while (buf < end) { nr_nas_msg_snssai_t *item = nssai + nssai_cnt; - item->sd = 0xffffff; const int item_len = *buf++; // Length of S-NSSAI IE item switch (item_len) { case 1: @@ -89,31 +88,38 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, uint8_t *num_slices, uint case 2: item->sst = *buf++; - item->hplmn_sst = *buf++; + item->hplmn_sst = malloc_or_fail(sizeof(*item->hplmn_sst)); + *item->hplmn_sst = *buf++; nssai_cnt++; break; case 4: item->sst = *buf++; - item->sd = 0xffffff & ntoh_int24_buf(buf); + item->sd = malloc_or_fail(sizeof(*item->sd)); + *item->sd = 0xffffff & ntoh_int24_buf(buf); buf += 3; nssai_cnt++; break; case 5: item->sst = *buf++; - item->sd = 0xffffff & ntoh_int24_buf(buf); + item->sd = malloc_or_fail(sizeof(*item->sd)); + *item->sd = 0xffffff & ntoh_int24_buf(buf); buf += 3; - item->hplmn_sst = *buf++; + item->hplmn_sst = malloc_or_fail(sizeof(*item->hplmn_sst)); + *item->hplmn_sst = *buf++; nssai_cnt++; break; case 8: item->sst = *buf++; - item->sd = 0xffffff & ntoh_int24_buf(buf); + item->sd = malloc_or_fail(sizeof(*item->sd)); + *item->sd = 0xffffff & ntoh_int24_buf(buf); buf += 3; - item->hplmn_sst = *buf++; - item->hplmn_sd = 0xffffff & ntoh_int24_buf(buf); + item->hplmn_sst = malloc_or_fail(sizeof(*item->hplmn_sst)); + *item->hplmn_sst = *buf++; + item->hplmn_sd = malloc_or_fail(sizeof(*item->hplmn_sd)); + *item->hplmn_sd = 0xffffff & ntoh_int24_buf(buf); buf += 3; nssai_cnt++; break; @@ -198,3 +204,21 @@ int encode_registration_accept(const registration_accept_msg *registration_accep return encoded; } + +/** Memory management of NAS Registration Accept */ + +static void free_nssai(nr_nas_msg_snssai_t *msg) +{ + free(msg->hplmn_sd); + free(msg->hplmn_sst); + free(msg->sd); +} + +void free_fgmm_registration_accept(registration_accept_msg *msg) +{ + free(msg->guti); + for (int i = 0; i < NAS_MAX_NUMBER_SLICES; i++) { + free_nssai(&msg->nas_allowed_nssai[i]); + free_nssai(&msg->config_nssai[i]); + } +} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index 4c50de9384..c373c067fa 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -51,9 +51,9 @@ typedef enum { // 9.11.3.37 of 3GPP TS 24.501 typedef struct { int sst; - int hplmn_sst; - int sd; - int hplmn_sd; + int *hplmn_sst; + int *sd; + int *hplmn_sd; } nr_nas_msg_snssai_t; /* @@ -81,4 +81,6 @@ size_t decode_registration_accept(registration_accept_msg *registrationaccept, c int encode_registration_accept(const registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); +void free_fgmm_registration_accept(registration_accept_msg *msg); + #endif /* ! defined(REGISTRATION_ACCEPT_H_) */ diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 5ee233172c..55bad1c2eb 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1410,11 +1410,14 @@ static void request_default_pdusession(nr_ue_nas_t *nas) itti_send_msg_to_task(TASK_NAS_NRUE, nas->UE_id, message_p); } -static int get_user_nssai_idx(const nr_nas_msg_snssai_t allowed_nssai[8], const nr_ue_nas_t *nas) +static int get_user_nssai_idx(const nr_nas_msg_snssai_t allowed_nssai[NAS_MAX_NUMBER_SLICES], const nr_ue_nas_t *nas) { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NAS_MAX_NUMBER_SLICES; i++) { const nr_nas_msg_snssai_t *nssai = allowed_nssai + i; - if ((nas->uicc->nssai_sst == nssai->sst) && (nas->uicc->nssai_sd == nssai->sd)) + /* If it was received in Registration Accept, check the SD + in the stored Allowed N-SSAI, else, consider the SD valid */ + bool sd_match = !nssai->sd || (nas->uicc->nssai_sd == *nssai->sd); + if ((nas->uicc->nssai_sst == nssai->sst) && sd_match) return i; } return -1; @@ -1476,7 +1479,6 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff // process GUTI if (msg.guti) { process_guti(&msg.guti->guti, nas); - free(msg.guti); } else { LOG_W(NAS, "no GUTI in registration accept\n"); } @@ -1495,6 +1497,8 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff } else { request_default_pdusession(nas); } + // Free local message after processing + free_fgmm_registration_accept(&msg); } /* 3GPP TS 24.008 10.5.7.3 GPRS Timer */ From 3fe601fa6b6c847e0e491b59375a5d275f4b09e4 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 7 Feb 2025 17:26:42 +0100 Subject: [PATCH 5/6] Add equality check to NAS Registration Accept library --- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 77 +++++++++++++++++++ .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 2 + 2 files changed, 79 insertions(+) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index f6b67edb11..bc5c86f88e 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -205,6 +205,83 @@ int encode_registration_accept(const registration_accept_msg *registration_accep return encoded; } +/** Equality check for NAS Registration Accept */ + +bool eq_snssai(const nr_nas_msg_snssai_t *a, const nr_nas_msg_snssai_t *b) +{ + _NAS_EQ_CHECK_INT(a->sst, b->sst); + + if ((a->hplmn_sst && !b->hplmn_sst) || (!a->hplmn_sst && b->hplmn_sst)) + return false; + if (a->hplmn_sst && b->hplmn_sst) + _NAS_EQ_CHECK_INT(*a->hplmn_sst, *b->hplmn_sst); + + if ((a->sd && !b->sd) || (!a->sd && b->sd)) + return false; + if (a->sd && b->sd) + _NAS_EQ_CHECK_INT(*a->sd, *b->sd); + + if ((a->hplmn_sd && !b->hplmn_sd) || (!a->hplmn_sd && b->hplmn_sd)) + return false; + if (a->hplmn_sd && b->hplmn_sd) + _NAS_EQ_CHECK_INT(*a->hplmn_sd, *b->hplmn_sd); + + return true; +} + + +bool eq_fgmm_registration_accept(const registration_accept_msg *a, const registration_accept_msg *b) +{ + if (!a || !b) { + PRINT_NAS_ERROR("Null pointer in registration_accept_msg_eq\n"); + return false; + } + + // 5GS registration result (mandatory) + _NAS_EQ_CHECK_INT(a->result, b->result); + _NAS_EQ_CHECK_INT(a->sms_allowed, b->sms_allowed); + + // GUTI (optional) + if (a->guti && b->guti) { + _NAS_EQ_CHECK_INT(a->guti->guti.spare, b->guti->guti.spare); + _NAS_EQ_CHECK_INT(a->guti->guti.oddeven, b->guti->guti.oddeven); + _NAS_EQ_CHECK_INT(a->guti->guti.typeofidentity, b->guti->guti.typeofidentity); + _NAS_EQ_CHECK_INT(a->guti->guti.mccdigit2, b->guti->guti.mccdigit2); + _NAS_EQ_CHECK_INT(a->guti->guti.mccdigit1, b->guti->guti.mccdigit1); + _NAS_EQ_CHECK_INT(a->guti->guti.mncdigit3, b->guti->guti.mncdigit3); + _NAS_EQ_CHECK_INT(a->guti->guti.mccdigit3, b->guti->guti.mccdigit3); + _NAS_EQ_CHECK_INT(a->guti->guti.mncdigit2, b->guti->guti.mncdigit2); + _NAS_EQ_CHECK_INT(a->guti->guti.mncdigit1, b->guti->guti.mncdigit1); + _NAS_EQ_CHECK_INT(a->guti->guti.amfregionid, b->guti->guti.amfregionid); + _NAS_EQ_CHECK_INT(a->guti->guti.amfsetid, b->guti->guti.amfsetid); + _NAS_EQ_CHECK_INT(a->guti->guti.amfpointer, b->guti->guti.amfpointer); + _NAS_EQ_CHECK_INT(a->guti->guti.tmsi, b->guti->guti.tmsi); + } else if ((a->guti && !b->guti) || (!a->guti && b->guti)) { + PRINT_NAS_ERROR("NAS Equality Check failure: One of the two GUTIs is NULL\n"); + return false; + } + + _NAS_EQ_CHECK_INT(a->num_allowed_slices, b->num_allowed_slices); + _NAS_EQ_CHECK_INT(a->num_configured_slices, b->num_configured_slices); + + // Configured NSSAI (optional) + for (int i = 0; i < a->num_configured_slices; i++) { + if (!eq_snssai(&a->config_nssai[i], &b->config_nssai[i])) { + PRINT_NAS_ERROR("NAS Equality Check failure: Configured NSSAI\n"); + return false; + } + } + // Allowed NSSAI (optional) + for (int i = 0; i < a->num_allowed_slices; i++) { + if (!eq_snssai(&a->nas_allowed_nssai[i], &b->nas_allowed_nssai[i])) { + PRINT_NAS_ERROR("NAS Equality Check failure: Allowed NSSAI\n"); + return false; + } + } + + return true; +} + /** Memory management of NAS Registration Accept */ static void free_nssai(nr_nas_msg_snssai_t *msg) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index c373c067fa..42b02407d9 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "SecurityHeaderType.h" #include "MessageType.h" @@ -81,6 +82,7 @@ size_t decode_registration_accept(registration_accept_msg *registrationaccept, c int encode_registration_accept(const registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); +bool eq_fgmm_registration_accept(const registration_accept_msg *a, const registration_accept_msg *b); void free_fgmm_registration_accept(registration_accept_msg *msg); #endif /* ! defined(REGISTRATION_ACCEPT_H_) */ From a19c7866006b83af081d755c15b8c9eca58bac57 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 7 Feb 2025 17:27:08 +0100 Subject: [PATCH 6/6] Add regression test for NAS Registration Accept decoding This test verifies that a NAS Registration Accept message, as received from the OAI CN5G, is correctly decoded and matches the expected output structure. It ensures that future changes to the NAS decoder do not break compatibility or correctness with existing decoding behavior. --- openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c | 61 +++++++++++++++++++++ 1 file changed, 61 insertions(+) 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 a73ee9b2be..2ccf78fa59 100644 --- a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c +++ b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c @@ -3,6 +3,7 @@ #include #include #include "common/utils/ds/byte_array.h" +#include "RegistrationAccept.h" #include "fgs_service_request.h" #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" @@ -26,6 +27,65 @@ static bool eq_service_request(const fgs_service_request_msg_t *a, const fgs_ser return result; } +/** @brief Test regression of NAS Registration Accept decoding + * This test verifies that the NAS Registration Accept message + * is correctly decoded. It decodes a message as it received from + * the OAI CN5G and compares the output with the expected Registration Accept structure. + * The purpose of this regression test is to ensure that changes + * to the NAS decoder do not break the existing decoding behavior with OAI CN5G */ +static void test_regression_registration_accept(void) +{ + // Registration Accept message + registration_accept_msg orig = { + .guti = malloc_or_fail(sizeof(*orig.guti)), + .result = 0x01, + .nas_allowed_nssai[0].sst = 0x01, + .nas_allowed_nssai[1].sst = 0x02, + .nas_allowed_nssai[2].sst = 0x03, + .num_allowed_slices = 3, + .config_nssai[0].sst = 0x01, + .config_nssai[1].sst = 0x02, + .config_nssai[2].sst = 0x03, + .num_configured_slices = 3, + }; + + orig.guti->guti.typeofidentity = FGS_MOBILE_IDENTITY_5G_GUTI; + orig.guti->guti.amfpointer = 0x01; + orig.guti->guti.amfregionid = 0x02; + orig.guti->guti.amfsetid = 0x01; + orig.guti->guti.mccdigit1 = 0x00; + orig.guti->guti.mccdigit2 = 0x00; + orig.guti->guti.mccdigit3 = 0x01; + orig.guti->guti.mncdigit1 = 0x00; + orig.guti->guti.mncdigit2 = 0x01; + orig.guti->guti.mncdigit3 = 0x0F; + orig.guti->guti.tmsi = 0xb0207806; + orig.guti->guti.spare = 0b1111; + orig.guti->guti.oddeven = 0; + + // Encoded Registration Accept message from OAI CN5G + uint8_t cn5g_msg[] = {0x01, 0x01, // Registration Result + 0x77, 0x00, 0x0B, 0xF2, 0x00, 0xF1, 0x10, // 5G-GUTI + 0x02, 0x00, 0x41, 0xB0, 0x20, 0x78, 0x06, // 5G-GUTI + 0x15, 0x06, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, // Allowed N-NSSAI + 0x31, 0x06, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03}; // Configured N-NSSAI + + // Decode NAS Registration Accept + int encoded_length; + registration_accept_msg decoded = {0}; + byte_array_t ba = {.buf = cn5g_msg, .len = sizeof(cn5g_msg)}; + encoded_length = decode_registration_accept(&decoded, ba); + AssertFatal(encoded_length >= 0, "encode_fgs_service_request() failed\n"); + + // Compare the raw encoded buffer with expected encoded data + bool ret = eq_fgmm_registration_accept(&orig, &decoded); + AssertFatal(ret, "Encoding mismatch!\n"); + + // Free dynamic allocated memory + free_fgmm_registration_accept(&orig); + free_fgmm_registration_accept(&decoded); +} + /** * @brief Test NAS Service Request enc/dec */ @@ -172,6 +232,7 @@ static void test_service_reject(void) int main() { + test_regression_registration_accept(); test_service_request(); test_service_accept(); test_service_reject();