diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index b370b8da66..a3a8520c86 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -1463,6 +1463,18 @@ uint64_t nr_construct_5g_s_tmsi(uint16_t amf_set_id, uint8_t amf_pointer, uint32 return ((uint64_t)amf_set_id << 38) | ((uint64_t)amf_pointer << 32) | m_tmsi; } +/** @brief Extract 5G-S-TMSI-Part1 from full 5G-S-TMSI + * @param fiveg_s_tmsi Full 5G-S-TMSI (48 bits) + * @return 5G-S-TMSI-Part1 (rightmost 39 bits) + * @note 5G-S-TMSI-Part1 is the rightmost 39 bits of the full 5G-S-TMSI: + * - Bits 32-37: AMF Pointer (6 bits) + * - Bits 0-31: 5G-TMSI (32 bits) + * @ref 3GPP TS 23.003 */ +uint64_t nr_extract_5g_s_tmsi_part1(const uint64_t fiveg_s_tmsi) +{ + return fiveg_s_tmsi & ((1ULL << 39) - 1); +} + /** @brief Construct 5G-S-TMSI-Part1 from 5G-S-TMSI components * @param amf_set_id AMF Set ID (10 bits) * @param amf_pointer AMF Pointer (6 bits) @@ -1476,5 +1488,48 @@ uint64_t nr_construct_5g_s_tmsi_part1(uint16_t amf_set_id, uint8_t amf_pointer, { // Construct full 5G-S-TMSI and extract Part1: rightmost 39 bits uint64_t full_s_tmsi = nr_construct_5g_s_tmsi(amf_set_id, amf_pointer, m_tmsi); - return full_s_tmsi & ((1ULL << 39) - 1); + return nr_extract_5g_s_tmsi_part1(full_s_tmsi); +} + +/** @brief Extract 5G-S-TMSI-Part2 from full 5G-S-TMSI + * @param fiveg_s_tmsi Full 5G-S-TMSI (48 bits) + * @return 5G-S-TMSI-Part2 (leftmost 9 bits) + * @note 5G-S-TMSI-Part2 is the leftmost 9 bits of the full 5G-S-TMSI: + * - Bits 39-47: AMF Set ID (9 bits) + * @ref 3GPP TS 23.003 */ +uint16_t nr_extract_5g_s_tmsi_part2(const uint64_t fiveg_s_tmsi) +{ + return (fiveg_s_tmsi >> 39) & ((1ULL << 9) - 1); +} + +/** @brief Build full 5G-S-TMSI from Part1 and Part2 + * @param part1 5G-S-TMSI-Part1 (rightmost 39 bits) + * @param part2 5G-S-TMSI-Part2 (leftmost 9 bits) + * @return Full 5G-S-TMSI (48 bits) + * @note Combines Part2 (leftmost 9 bits) and Part1 (rightmost 39 bits) + * @ref 3GPP TS 23.003 */ +uint64_t nr_build_full_5g_s_tmsi(const uint64_t part1, const uint16_t part2) +{ + return ((uint64_t)part2 << 39) | part1; +} + +/** @brief Deconstruct full 5G-S-TMSI into its components + * @param fiveg_s_tmsi Full 5G-S-TMSI (48 bits) + * @param[out] amf_set_id Pointer to store AMF Set ID (10 bits) + * @param[out] amf_pointer Pointer to store AMF Pointer (6 bits) + * @param[out] m_tmsi Pointer to store 5G-TMSI (32 bits) + * @note The 5G-S-TMSI is deconstructed from a 48-bit value: + * - Bits 38-47: AMF Set ID (10 bits) + * - Bits 32-37: AMF Pointer (6 bits) + * - Bits 0-31: 5G-TMSI (32 bits) + * @ref 3GPP TS 23.003 */ +void nr_deconstruct_5g_s_tmsi(const uint64_t fiveg_s_tmsi, uint16_t *amf_set_id, uint8_t *amf_pointer, uint32_t *m_tmsi) +{ + DevAssert(amf_set_id != NULL); + DevAssert(amf_pointer != NULL); + DevAssert(m_tmsi != NULL); + + *amf_set_id = fiveg_s_tmsi >> 38; + *amf_pointer = (fiveg_s_tmsi >> 32) & 0x3F; + *m_tmsi = fiveg_s_tmsi; } diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index ada9813373..ca867fa694 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -360,6 +360,18 @@ uint64_t nr_construct_5g_s_tmsi(uint16_t amf_set_id, uint8_t amf_pointer, uint32 /** @brief Construct 5G-S-TMSI-Part1 from 5G-S-TMSI components */ uint64_t nr_construct_5g_s_tmsi_part1(uint16_t amf_set_id, uint8_t amf_pointer, uint32_t m_tmsi); +/** @brief Extract 5G-S-TMSI-Part1 from full 5G-S-TMSI */ +uint64_t nr_extract_5g_s_tmsi_part1(const uint64_t fiveg_s_tmsi); + +/** @brief Extract 5G-S-TMSI-Part2 from full 5G-S-TMSI */ +uint16_t nr_extract_5g_s_tmsi_part2(const uint64_t fiveg_s_tmsi); + +/** @brief Build full 5G-S-TMSI from Part1 and Part2 */ +uint64_t nr_build_full_5g_s_tmsi(const uint64_t part1, const uint16_t part2); + +/** @brief Deconstruct full 5G-S-TMSI into its components */ +void nr_deconstruct_5g_s_tmsi(const uint64_t fiveg_s_tmsi, uint16_t *amf_set_id, uint8_t *amf_pointer, uint32_t *m_tmsi); + #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) #define BOUNDED_EVAL(a, b, c) (min(c, max(a, b))) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 57fb3daf12..a377236485 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -716,7 +716,7 @@ int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv, uint64_ str->buf[3] = rv[3]; str->buf[4] = rv[4] & 0xfe; } else { - uint64_t fiveG_S_TMSI_part1 = fiveG_S_TMSI & ((1ULL << 39) - 1); + uint64_t fiveG_S_TMSI_part1 = nr_extract_5g_s_tmsi_part1(fiveG_S_TMSI); /** set the ue-Identity to ng-5G-S-TMSI-Part1 * ng-5G-S-TMSI-Part1: the rightmost 39 bits of 5G-S-TMSI * BIT STRING (SIZE (39)) - 3GPP TS 38.331 */ @@ -840,7 +840,7 @@ int do_RRCSetupComplete(uint8_t *buffer, str->size = 2; str->bits_unused = 7; str->buf = calloc_or_fail(str->size, sizeof(str->buf[0])); - uint16_t fiveG_s_tmsi_part2 = (fiveG_s_tmsi >> 39) & ((1ULL << 9) - 1); + uint16_t fiveG_s_tmsi_part2 = nr_extract_5g_s_tmsi_part2(fiveG_s_tmsi); str->buf[0] = (fiveG_s_tmsi_part2 >> (8 - str->bits_unused)) & 0xFF; str->buf[1] = (fiveG_s_tmsi_part2 << str->bits_unused) & 0xFF; LOG_D(NR_RRC, "5G-S-TMSI part 2 %d in RRCSetupComplete (5G-S-TMSI %ld)\n", fiveG_s_tmsi_part2, fiveG_s_tmsi); diff --git a/openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt b/openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt index 980d6160e8..ee462ba7a6 100644 --- a/openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt +++ b/openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt @@ -2,7 +2,7 @@ add_executable(test_asn1_msg test_asn1_msg.cpp ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c ${OPENAIR2_DIR}/LAYER2/nr_rlc/asn1_utils.c) -target_link_libraries(test_asn1_msg PRIVATE nr_rrc SECURITY minimal_lib GTest::gtest UTIL) +target_link_libraries(test_asn1_msg PRIVATE nr_rrc SECURITY minimal_lib GTest::gtest UTIL nr_common) add_dependencies(tests test_asn1_msg) add_test(NAME test_asn1_msg COMMAND ./test_asn1_msg) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a68ac6691e..4b0acd44d4 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -60,6 +60,7 @@ #include "common/openairinterface5g_limits.h" #include "common/platform_constants.h" #include "common/ran_context.h" +#include "common/utils/nr/nr_common.h" #include "common_lib.h" #include "constr_SEQUENCE.h" #include "constr_TYPE.h" @@ -2073,7 +2074,7 @@ static void handle_rrcSetupComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const N uint16_t stmsi_part2 = BIT_STRING_to_uint16(part2); LOG_I(RRC, "s_tmsi part2 %d (%02x %02x)\n", stmsi_part2, part2->buf[0], part2->buf[1]); // Part2 is leftmost 9, Part1 is rightmost 39 bits of 5G-S-TMSI - fiveg_s_TMSI = ((uint64_t) stmsi_part2) << 39 | UE->ng_5G_S_TMSI_Part1; + fiveg_s_TMSI = nr_build_full_5g_s_tmsi(UE->ng_5G_S_TMSI_Part1, stmsi_part2); } else { LOG_W(RRC, "UE %d received 5G-S-TMSI-Part2, but no 5G-S-TMSI-Part1 present, won't send 5G-S-TMSI to core\n", UE->rrc_ue_id); UE->Initialue_identity_5g_s_TMSI.presence = false; @@ -2090,9 +2091,10 @@ static void handle_rrcSetupComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const N } if (UE->Initialue_identity_5g_s_TMSI.presence) { - uint16_t amf_set_id = fiveg_s_TMSI >> 38; - uint8_t amf_pointer = (fiveg_s_TMSI >> 32) & 0x3F; - uint32_t fiveg_tmsi = (uint32_t) fiveg_s_TMSI; + uint16_t amf_set_id; + uint8_t amf_pointer; + uint32_t fiveg_tmsi; + nr_deconstruct_5g_s_tmsi(fiveg_s_TMSI, &amf_set_id, &amf_pointer, &fiveg_tmsi); LOG_I(NR_RRC, "5g_s_TMSI: 0x%lX, amf_set_id: 0x%X (%d), amf_pointer: 0x%X (%d), 5g TMSI: 0x%X \n", fiveg_s_TMSI,