Paging (NGAP): add paging encode/decode library and unit tests (3GPP TS 38.413)
- Refactor ngap_paging_ind_t (openair2/COMMON/ngap_messages_types.h):
- optional paging_drx and paging_priority as pointers
- TAI list as tai_list[] and n_tai
- add optional IEs: Paging Origin, Paging Attempt Information,
UE Radio Capability for Paging.
- Introduce nr_tai_t, ngap_paging_attempt_info_t, ngap_paging_origin_t;
- generate paging enums via FOREACH macros.
- Add NGAP Paging encode/decode/eq/free in openair3/NGAP/ngap_gNB_paging.c
(encode_ng_paging, decode_ng_paging, eq_ng_paging, free_ng_paging).
- Replace inline Paging decode in ngap_gNB_handle_paging() with
decode_ng_paging() and add error handling; add eq_ngap_plmn() in
ngap_common.
- Update rrc_gNB_NGAP.c to use tai_list/n_tai and optional paging_drx
when forwarding paging to F1AP.
- Add ASN.1 includes for Paging in ngap_msg_includes.h; register
ngap_gNB_paging.c in root CMakeLists.txt.
- Add NGAP unit test (openair3/NGAP/tests/ngap_lib_test.c): encode/decode
roundtrip for Paging; tests subdirectory and executable under
ENABLE_TESTS in openair3/NGAP/CMakeLists.txt.
This commit is contained in:
@@ -434,6 +434,7 @@ add_library(ngap
|
||||
${NGAP_DIR}/ngap_gNB_handlers.c
|
||||
${NGAP_DIR}/ngap_gNB_itti_messaging.c
|
||||
${NGAP_DIR}/ngap_gNB_management_procedures.c
|
||||
${NGAP_DIR}/ngap_gNB_paging.c
|
||||
${NGAP_DIR}/ngap_gNB_nas_procedures.c
|
||||
${NGAP_DIR}/ngap_gNB_pdu_session_management.c
|
||||
${NGAP_DIR}/ngap_gNB_nnsf.c
|
||||
@@ -443,6 +444,9 @@ add_library(ngap
|
||||
)
|
||||
target_link_libraries(ngap PUBLIC asn1_ngap)
|
||||
target_link_libraries(ngap PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
if(ENABLE_TESTS)
|
||||
target_compile_definitions(ngap PRIVATE ENABLE_TESTS)
|
||||
endif()
|
||||
|
||||
#M2AP
|
||||
##############
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "common/5g_platform_types.h"
|
||||
#include "common/platform_constants.h"
|
||||
#include "common/platform_types.h"
|
||||
#include "common/5g_platform_types.h"
|
||||
#include "s1ap_messages_types.h"
|
||||
#include "ds/byte_array.h"
|
||||
#include "utils.h"
|
||||
@@ -89,39 +88,46 @@
|
||||
|
||||
#define NGAP_MAX_NB_AMF_IP_ADDRESS 10
|
||||
|
||||
#define NGAP_MAX_NO_TAI_PAGING 16 // 9.2.4.1 3GPP TS 38.413
|
||||
|
||||
/* Security key length used within gNB
|
||||
* Even if only 16 bytes will be effectively used,
|
||||
* the key length is 32 bytes (256 bits)
|
||||
*/
|
||||
#define SECURITY_KEY_LENGTH 32
|
||||
|
||||
typedef enum ngap_paging_drx_e {
|
||||
NGAP_PAGING_DRX_32 = 0x0,
|
||||
NGAP_PAGING_DRX_64 = 0x1,
|
||||
NGAP_PAGING_DRX_128 = 0x2,
|
||||
NGAP_PAGING_DRX_256 = 0x3
|
||||
} ngap_paging_drx_t;
|
||||
#define NGAP_MAX_NO_TAI_PAGING 16 // 9.2.4.1 3GPP TS 38.413
|
||||
|
||||
/* Lower value codepoint
|
||||
* indicates higher priority.
|
||||
*/
|
||||
typedef enum ngap_paging_priority_s {
|
||||
NGAP_PAGING_PRIO_LEVEL1 = 0,
|
||||
NGAP_PAGING_PRIO_LEVEL2 = 1,
|
||||
NGAP_PAGING_PRIO_LEVEL3 = 2,
|
||||
NGAP_PAGING_PRIO_LEVEL4 = 3,
|
||||
NGAP_PAGING_PRIO_LEVEL5 = 4,
|
||||
NGAP_PAGING_PRIO_LEVEL6 = 5,
|
||||
NGAP_PAGING_PRIO_LEVEL7 = 6,
|
||||
NGAP_PAGING_PRIO_LEVEL8 = 7
|
||||
} ngap_paging_priority_t;
|
||||
/* Paging DRX values (3GPP TS 38.413) */
|
||||
#define FOREACH_PAGING_DRX(DRX_DEF) \
|
||||
DRX_DEF(NGAP_PAGING_DRX_32, 0x0) \
|
||||
DRX_DEF(NGAP_PAGING_DRX_64, 0x1) \
|
||||
DRX_DEF(NGAP_PAGING_DRX_128, 0x2) \
|
||||
DRX_DEF(NGAP_PAGING_DRX_256, 0x3)
|
||||
|
||||
typedef enum ngap_cn_domain_s {
|
||||
NGAP_CN_DOMAIN_PS = 1,
|
||||
NGAP_CN_DOMAIN_CS = 2
|
||||
} ngap_cn_domain_t;
|
||||
/* Lower value codepoint indicates higher priority (3GPP TS 38.413) */
|
||||
#define FOREACH_PAGING_PRIORITY(PRIO_DEF) \
|
||||
PRIO_DEF(NGAP_PAGING_PRIO_LEVEL1, 0) \
|
||||
PRIO_DEF(NGAP_PAGING_PRIO_LEVEL2, 1) \
|
||||
PRIO_DEF(NGAP_PAGING_PRIO_LEVEL3, 2) \
|
||||
PRIO_DEF(NGAP_PAGING_PRIO_LEVEL4, 3) \
|
||||
PRIO_DEF(NGAP_PAGING_PRIO_LEVEL5, 4) \
|
||||
PRIO_DEF(NGAP_PAGING_PRIO_LEVEL6, 5) \
|
||||
PRIO_DEF(NGAP_PAGING_PRIO_LEVEL7, 6) \
|
||||
PRIO_DEF(NGAP_PAGING_PRIO_LEVEL8, 7)
|
||||
|
||||
/* Paging Origin (9.3.3.22 of 3GPP TS 38.413) */
|
||||
#define FOREACH_PAGING_ORIGIN(ORIGIN_DEF) ORIGIN_DEF(NGAP_PAGING_ORIGIN_NON_3GPP, 0)
|
||||
|
||||
static const text_info_t paging_drx_text[] = {FOREACH_PAGING_DRX(TO_TEXT)};
|
||||
|
||||
static const text_info_t paging_prio_text[] = {FOREACH_PAGING_PRIORITY(TO_TEXT)};
|
||||
|
||||
static const text_info_t paging_origin_text[] = {FOREACH_PAGING_ORIGIN(TO_TEXT)};
|
||||
|
||||
typedef enum { FOREACH_PAGING_DRX(TO_ENUM) } ngap_paging_drx_t;
|
||||
|
||||
typedef enum { FOREACH_PAGING_PRIORITY(TO_ENUM) } ngap_paging_priority_t;
|
||||
|
||||
typedef enum { FOREACH_PAGING_ORIGIN(TO_ENUM) } ngap_paging_origin_t;
|
||||
|
||||
typedef struct ngap_net_ip_address_s {
|
||||
unsigned ipv4:1;
|
||||
@@ -171,10 +177,6 @@ typedef struct fiveg_s_tmsi_s {
|
||||
uint32_t m_tmsi;
|
||||
} fiveg_s_tmsi_t;
|
||||
|
||||
typedef struct ngap_ue_paging_identity_s {
|
||||
fiveg_s_tmsi_t s_tmsi;
|
||||
} ngap_ue_paging_identity_t;
|
||||
|
||||
typedef enum ngap_ue_identities_presenceMask_e {
|
||||
NGAP_UE_IDENTITIES_FiveG_s_tmsi = 1 << 1,
|
||||
NGAP_UE_IDENTITIES_guami = 1 << 2,
|
||||
@@ -797,29 +799,6 @@ typedef struct ngap_initial_context_setup_req_s {
|
||||
byte_array_t nas_pdu;
|
||||
} ngap_initial_context_setup_req_t;
|
||||
|
||||
|
||||
typedef struct ngap_paging_ind_s {
|
||||
/* UE paging identity */
|
||||
ngap_ue_paging_identity_t ue_paging_identity;
|
||||
|
||||
/* Indicates origin of paging */
|
||||
ngap_cn_domain_t cn_domain;
|
||||
|
||||
/* PLMN_identity in TAI of Paging*/
|
||||
plmn_id_t plmn_identity[NGAP_MAX_NO_TAI_PAGING];
|
||||
|
||||
/* TAC in TAIList of Paging*/
|
||||
int16_t tac[NGAP_MAX_NO_TAI_PAGING];
|
||||
|
||||
/* size of TAIList*/
|
||||
int16_t tai_size;
|
||||
|
||||
/* Optional fields */
|
||||
ngap_paging_drx_t paging_drx;
|
||||
|
||||
ngap_paging_priority_t paging_priority;
|
||||
} ngap_paging_ind_t;
|
||||
|
||||
typedef struct ngap_pdusession_setup_req_s {
|
||||
/* UE id for initial connection to NGAP */
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
@@ -946,6 +925,45 @@ typedef struct ngap_pdusession_release_resp_s {
|
||||
pdusession_release_t pdusession_release[NGAP_MAX_PDU_SESSION];
|
||||
} ngap_pdusession_release_resp_t;
|
||||
|
||||
/** NG PAGING PROCEDURES (9.2.4. of 3GPP TS 38.413) */
|
||||
|
||||
typedef struct {
|
||||
plmn_id_t plmn;
|
||||
uint16_t tac;
|
||||
} nr_tai_t;
|
||||
|
||||
typedef struct ngap_ue_paging_identity_s {
|
||||
fiveg_s_tmsi_t s_tmsi;
|
||||
} ngap_ue_paging_identity_t;
|
||||
|
||||
/** 9.3.1.72 Paging Attempt Information (3GPP TS 38.413) */
|
||||
typedef struct {
|
||||
/* Paging Attempt Count */
|
||||
uint8_t paging_attempt_count;
|
||||
/* Intended Number of Paging Attempts */
|
||||
uint8_t intended_paging_attempts;
|
||||
} ngap_paging_attempt_info_t;
|
||||
|
||||
/** 9.2.4.1 3GPP TS 38.413 */
|
||||
typedef struct {
|
||||
/* UE paging identity */
|
||||
ngap_ue_paging_identity_t ue_paging_identity;
|
||||
|
||||
/* TAI List for Paging */
|
||||
nr_tai_t tai_list[NGAP_MAX_NO_TAI_PAGING];
|
||||
int16_t n_tai;
|
||||
|
||||
/* Optional fields */
|
||||
ngap_paging_drx_t *paging_drx;
|
||||
ngap_paging_priority_t *paging_priority;
|
||||
/* UE Radio Capability for Paging (optional) */
|
||||
byte_array_t *ue_radio_capability;
|
||||
/* Paging Origin (optional) */
|
||||
ngap_paging_origin_t *origin;
|
||||
/* Assistance Data for Paging (optional) */
|
||||
ngap_paging_attempt_info_t *paging_attempt_info;
|
||||
} ngap_paging_ind_t;
|
||||
|
||||
/** 9.2.3.14 Uplink RAN Status Transfer (3GPP TS 38.413)
|
||||
* COUNT value used for both UL and DL PDCP SN + HFN (12-bit or 18-bit SN) */
|
||||
|
||||
|
||||
@@ -1632,19 +1632,20 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_comm
|
||||
int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance)
|
||||
{
|
||||
ngap_paging_ind_t *msg = &NGAP_PAGING_IND(msg_p);
|
||||
for (uint16_t tai_size = 0; tai_size < msg->tai_size; tai_size++) {
|
||||
plmn_id_t *p = &msg->plmn_identity[tai_size];
|
||||
for (uint16_t tai_idx = 0; tai_idx < msg->n_tai; tai_idx++) {
|
||||
nr_tai_t *tai = &msg->tai_list[tai_idx];
|
||||
plmn_id_t *p = &tai->plmn;
|
||||
LOG_I(NR_RRC,
|
||||
"[gNB %ld] TAI List for Paging: MCC=%03d, MNC=%0*d, TAC=%d\n",
|
||||
instance,
|
||||
p->mcc,
|
||||
p->mnc_digit_length,
|
||||
p->mnc,
|
||||
msg->tac[tai_size]);
|
||||
tai->tac);
|
||||
nr_rrc_config_t *req = &RC.nrrrc[instance]->configuration;
|
||||
for (uint8_t j = 0; j < req->num_plmn; j++) {
|
||||
plmn_id_t *req_plmn = &req->plmn[j];
|
||||
if (req_plmn->mcc == p->mcc && req_plmn->mnc == p->mnc && req->tac == msg->tac[tai_size]) {
|
||||
if (req_plmn->mcc == p->mcc && req_plmn->mnc == p->mnc && req->tac == tai->tac) {
|
||||
for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
AssertFatal(false, "to be implemented properly\n");
|
||||
if (NODE_IS_CU(RC.nrrrc[instance]->node_type)) {
|
||||
@@ -1669,7 +1670,7 @@ int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance)
|
||||
F1AP_PAGING_IND(m).nr_cellid = cell->info.cell_id;
|
||||
F1AP_PAGING_IND(m).ueidentityindexvalue = (uint16_t)(msg->ue_paging_identity.s_tmsi.m_tmsi % 1024);
|
||||
F1AP_PAGING_IND(m).fiveg_s_tmsi = msg->ue_paging_identity.s_tmsi.m_tmsi;
|
||||
F1AP_PAGING_IND(m).paging_drx = msg->paging_drx;
|
||||
F1AP_PAGING_IND(m).paging_drx = msg->paging_drx ? (uint8_t)*msg->paging_drx : 0;
|
||||
LOG_E(F1AP, "ueidentityindexvalue %u fiveg_s_tmsi %ld paging_drx %u\n", F1AP_PAGING_IND (m).ueidentityindexvalue, F1AP_PAGING_IND (m).fiveg_s_tmsi, F1AP_PAGING_IND (m).paging_drx);
|
||||
itti_send_msg_to_task(TASK_CU_F1, instance, m);
|
||||
} else {
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
add_subdirectory(MESSAGES)
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "conversions.h"
|
||||
@@ -331,3 +332,14 @@ byte_array_t encode_ngap_pdusession_setup_response_transfer(const pdusession_set
|
||||
out.len = res.result.encoded;
|
||||
return out;
|
||||
}
|
||||
|
||||
bool eq_ngap_plmn(const plmn_id_t *a, const plmn_id_t *b)
|
||||
{
|
||||
if (a == NULL || b == NULL) {
|
||||
return false;
|
||||
}
|
||||
_EQ_CHECK_INT(a->mcc, b->mcc);
|
||||
_EQ_CHECK_INT(a->mnc, b->mnc);
|
||||
_EQ_CHECK_INT(a->mnc_digit_length, b->mnc_digit_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,5 +63,7 @@ void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_ST
|
||||
bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in);
|
||||
byte_array_t encode_ngap_pdusession_setup_response_transfer(const pdusession_setup_t *pdusession);
|
||||
|
||||
bool eq_ngap_plmn(const plmn_id_t *a, const plmn_id_t *b);
|
||||
|
||||
/** @}*/
|
||||
#endif /* NGAP_COMMON_H_ */
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "ngap_gNB_mobility_management.h"
|
||||
#include "ngap_gNB_pdu_session_management.h"
|
||||
#include "ngap_gNB_nas_procedures.h"
|
||||
#include "ngap_gNB_paging.h"
|
||||
#include "ngap_gNB_trace.h"
|
||||
#include "ngap_gNB_ue_context.h"
|
||||
#include "ngap_messages_types.h"
|
||||
@@ -1101,10 +1102,7 @@ static int ngap_gNB_handle_paging(sctp_assoc_t assoc_id, uint32_t stream, NGAP_N
|
||||
{
|
||||
ngap_gNB_amf_data_t *amf_desc_p = NULL;
|
||||
ngap_gNB_instance_t *ngap_gNB_instance = NULL;
|
||||
NGAP_Paging_t *container;
|
||||
NGAP_PagingIEs_t *ie;
|
||||
DevAssert(pdu != NULL);
|
||||
container = &pdu->choice.initiatingMessage->value.choice.Paging;
|
||||
// received Paging Message from AMF
|
||||
NGAP_DEBUG("[SCTP %u] Received Paging Message From AMF\n",assoc_id);
|
||||
|
||||
@@ -1130,67 +1128,20 @@ static int ngap_gNB_handle_paging(sctp_assoc_t assoc_id, uint32_t stream, NGAP_N
|
||||
}
|
||||
|
||||
MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_PAGING_IND);
|
||||
ngap_paging_ind_t * msg=&NGAP_PAGING_IND(message_p);
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
ngap_paging_ind_t *msg = &NGAP_PAGING_IND(message_p);
|
||||
|
||||
/* convert NGAP_PagingIEs_t to ngap_paging_ind_t */
|
||||
/* id-UEIdentityIndexValue : convert UE Identity Index value */
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEPagingIdentity, true);
|
||||
|
||||
struct NGAP_FiveG_S_TMSI *fiveG_S_TMSI = ie->value.choice.UEPagingIdentity.choice.fiveG_S_TMSI;
|
||||
OCTET_STRING_TO_INT16(&fiveG_S_TMSI->aMFSetID, msg->ue_paging_identity.s_tmsi.amf_set_id);
|
||||
OCTET_STRING_TO_INT8(&fiveG_S_TMSI->aMFPointer, msg->ue_paging_identity.s_tmsi.amf_pointer);
|
||||
OCTET_STRING_TO_INT32(&fiveG_S_TMSI->fiveG_TMSI, msg->ue_paging_identity.s_tmsi.m_tmsi);
|
||||
|
||||
NGAP_DEBUG("[SCTP %u] Received Paging Identity amf_set_id %d, amf_pointer %d, m_tmsi %d\n",
|
||||
assoc_id,
|
||||
msg->ue_paging_identity.s_tmsi.amf_set_id,
|
||||
msg->ue_paging_identity.s_tmsi.amf_pointer,
|
||||
msg->ue_paging_identity.s_tmsi.m_tmsi);
|
||||
|
||||
msg->paging_drx = NGAP_PAGING_DRX_256;
|
||||
/* id-pagingDRX */
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PagingDRX, false);
|
||||
|
||||
/* optional */
|
||||
if (ie) {
|
||||
msg->paging_drx = ie->value.choice.PagingDRX;
|
||||
} else {
|
||||
msg->paging_drx = NGAP_PAGING_DRX_256;
|
||||
/* Decode NGAP Paging message */
|
||||
if (!decode_ng_paging(msg, pdu)) {
|
||||
NGAP_ERROR("[SCTP %u] Failed to decode NGAP Paging message\n", assoc_id);
|
||||
free_ng_paging(msg);
|
||||
itti_free(TASK_NGAP, message_p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* id-TAIList */
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container,
|
||||
NGAP_ProtocolIE_ID_id_TAIListForPaging, true);
|
||||
/* send message to RRC */
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, ngap_gNB_instance->instance, message_p);
|
||||
|
||||
NGAP_INFO("[SCTP %u] Received Paging taiList For Paging: count %d\n", assoc_id, ie->value.choice.TAIListForPaging.list.count);
|
||||
|
||||
for (int i = 0; i < ie->value.choice.TAIListForPaging.list.count; i++) {
|
||||
NGAP_TAIListForPagingItem_t *item_p;
|
||||
item_p = (NGAP_TAIListForPagingItem_t *)ie->value.choice.TAIListForPaging.list.array[i];
|
||||
TBCD_TO_MCC_MNC(&(item_p->tAI.pLMNIdentity), msg->plmn_identity[i].mcc, msg->plmn_identity[i].mnc, msg->plmn_identity[i].mnc_digit_length);
|
||||
OCTET_STRING_TO_INT16(&(item_p->tAI.tAC), msg->tac[i]);
|
||||
msg->tai_size++;
|
||||
plmn_id_t *p = &msg->plmn_identity[i];
|
||||
LOG_D(NGAP,
|
||||
"[SCTP %u] PLMN in TAI list for Paging: MCC=%03d, MNC=%0*d, TAC=%d\n",
|
||||
assoc_id,
|
||||
p->mcc,
|
||||
p->mnc_digit_length,
|
||||
p->mnc,
|
||||
msg->tac[i]);
|
||||
}
|
||||
|
||||
//paging parameter values
|
||||
NGAP_DEBUG("[SCTP %u] Received Paging parameters: Paging Identity amf_set_id %d amf_pointer %d m_tmsi %d paging_drx %d paging_priority %d\n",assoc_id,
|
||||
msg->ue_paging_identity.s_tmsi.amf_set_id,
|
||||
msg->ue_paging_identity.s_tmsi.amf_pointer,
|
||||
msg->ue_paging_identity.s_tmsi.m_tmsi,
|
||||
msg->paging_drx, msg->paging_priority);
|
||||
/* send message to RRC */
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, ngap_gNB_instance->instance, message_p);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool decodePDUSessionResourceModify(pdusession_transfer_t *out, const OCTET_STRING_t in)
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* 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 Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "assertions.h"
|
||||
#include "common/utils/utils.h"
|
||||
#include "common/utils/ds/byte_array.h"
|
||||
#include "conversions.h"
|
||||
#include "ngap_common.h"
|
||||
#include "ngap_gNB_paging.h"
|
||||
#include "ngap_msg_includes.h"
|
||||
#include "oai_asn1.h"
|
||||
|
||||
/* Paging Attempt range (TS 38.413 §9.3.1.72) */
|
||||
#define NGAP_PAGING_ATTEMPT_MIN 1
|
||||
#define NGAP_PAGING_ATTEMPT_MAX 16
|
||||
|
||||
/** @brief Return text label at index in text_info array */
|
||||
static const char *text_info_at(int index, const text_info_t *info_array, size_t array_size)
|
||||
{
|
||||
DevAssert(index >= 0 && index < array_size);
|
||||
return info_array[index].text;
|
||||
}
|
||||
|
||||
/** @brief Encode NGAP Paging message (9.2.4.1 of 3GPP TS 38.413)
|
||||
* @param msg Pointer to paging indication structure to encode
|
||||
* @return Pointer to allocated NGAP_NGAP_PDU_t */
|
||||
NGAP_NGAP_PDU_t *encode_ng_paging(const ngap_paging_ind_t *msg)
|
||||
{
|
||||
DevAssert(msg != NULL);
|
||||
|
||||
NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(NGAP_NGAP_PDU_t));
|
||||
|
||||
pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage;
|
||||
asn1cCalloc(pdu->choice.initiatingMessage, head);
|
||||
head->procedureCode = NGAP_ProcedureCode_id_Paging;
|
||||
head->criticality = NGAP_Criticality_ignore;
|
||||
head->value.present = NGAP_InitiatingMessage__value_PR_Paging;
|
||||
NGAP_Paging_t *container = &head->value.choice.Paging;
|
||||
|
||||
// UE Paging Identity (M)
|
||||
asn1cSequenceAdd(container->protocolIEs.list, NGAP_PagingIEs_t, ie);
|
||||
ie->id = NGAP_ProtocolIE_ID_id_UEPagingIdentity;
|
||||
ie->criticality = NGAP_Criticality_reject;
|
||||
ie->value.present = NGAP_PagingIEs__value_PR_UEPagingIdentity;
|
||||
ie->value.choice.UEPagingIdentity.present = NGAP_UEPagingIdentity_PR_fiveG_S_TMSI;
|
||||
asn1cCalloc(ie->value.choice.UEPagingIdentity.choice.fiveG_S_TMSI, fiveg_s_tmsi);
|
||||
const fiveg_s_tmsi_t *s_tmsi = &msg->ue_paging_identity.s_tmsi;
|
||||
AMF_SETID_TO_BIT_STRING(s_tmsi->amf_set_id, &fiveg_s_tmsi->aMFSetID);
|
||||
AMF_POINTER_TO_BIT_STRING(s_tmsi->amf_pointer, &fiveg_s_tmsi->aMFPointer);
|
||||
M_TMSI_TO_OCTET_STRING(s_tmsi->m_tmsi, &fiveg_s_tmsi->fiveG_TMSI);
|
||||
|
||||
// TAI List for Paging (M)
|
||||
asn1cSequenceAdd(container->protocolIEs.list, NGAP_PagingIEs_t, ie1);
|
||||
ie1->id = NGAP_ProtocolIE_ID_id_TAIListForPaging;
|
||||
ie1->criticality = NGAP_Criticality_reject;
|
||||
ie1->value.present = NGAP_PagingIEs__value_PR_TAIListForPaging;
|
||||
|
||||
for (int i = 0; i < msg->n_tai; i++) {
|
||||
asn1cSequenceAdd(ie1->value.choice.TAIListForPaging.list, NGAP_TAIListForPagingItem_t, item);
|
||||
NGAP_TAI_t *tai = &item->tAI;
|
||||
const plmn_id_t *plmn = &msg->tai_list[i].plmn;
|
||||
MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &tai->pLMNIdentity);
|
||||
INT24_TO_OCTET_STRING(msg->tai_list[i].tac, &tai->tAC);
|
||||
}
|
||||
|
||||
// Paging DRX (O)
|
||||
if (msg->paging_drx != NULL) {
|
||||
asn1cSequenceAdd(container->protocolIEs.list, NGAP_PagingIEs_t, ie2);
|
||||
ie2->id = NGAP_ProtocolIE_ID_id_PagingDRX;
|
||||
ie2->criticality = NGAP_Criticality_ignore;
|
||||
ie2->value.present = NGAP_PagingIEs__value_PR_PagingDRX;
|
||||
ie2->value.choice.PagingDRX = *msg->paging_drx;
|
||||
}
|
||||
|
||||
// Paging Priority (O)
|
||||
if (msg->paging_priority != NULL) {
|
||||
asn1cSequenceAdd(container->protocolIEs.list, NGAP_PagingIEs_t, ie3);
|
||||
ie3->id = NGAP_ProtocolIE_ID_id_PagingPriority;
|
||||
ie3->criticality = NGAP_Criticality_ignore;
|
||||
ie3->value.present = NGAP_PagingIEs__value_PR_PagingPriority;
|
||||
ie3->value.choice.PagingPriority = *msg->paging_priority;
|
||||
}
|
||||
|
||||
// UERadioCapabilityForPaging (O)
|
||||
if (msg->ue_radio_capability != NULL && msg->ue_radio_capability->buf != NULL) {
|
||||
const byte_array_t *ue_radio_cap_ba = msg->ue_radio_capability;
|
||||
asn1cSequenceAdd(container->protocolIEs.list, NGAP_PagingIEs_t, ie4);
|
||||
ie4->id = NGAP_ProtocolIE_ID_id_UERadioCapabilityForPaging;
|
||||
ie4->criticality = NGAP_Criticality_ignore;
|
||||
ie4->value.present = NGAP_PagingIEs__value_PR_UERadioCapabilityForPaging;
|
||||
NGAP_UERadioCapabilityForPaging_t *ue_radio_cap = &ie4->value.choice.UERadioCapabilityForPaging;
|
||||
// UERadioCapabilityForPaging is a SEQUENCE with optional OCTET_STRING fields (Encode as NR)
|
||||
asn1cCalloc(ue_radio_cap->uERadioCapabilityForPagingOfNR, nr_field);
|
||||
OCTET_STRING_fromBuf(nr_field, (const char *)ue_radio_cap_ba->buf, ue_radio_cap_ba->len);
|
||||
}
|
||||
|
||||
// PagingOrigin (O)
|
||||
if (msg->origin != NULL) {
|
||||
asn1cSequenceAdd(container->protocolIEs.list, NGAP_PagingIEs_t, ie5);
|
||||
ie5->id = NGAP_ProtocolIE_ID_id_PagingOrigin;
|
||||
ie5->criticality = NGAP_Criticality_ignore;
|
||||
ie5->value.present = NGAP_PagingIEs__value_PR_PagingOrigin;
|
||||
ie5->value.choice.PagingOrigin = *msg->origin;
|
||||
}
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/** @brief Free memory allocated for NGAP paging indication
|
||||
* @param msg Pointer to paging indication structure to free */
|
||||
void free_ng_paging(ngap_paging_ind_t *msg)
|
||||
{
|
||||
DevAssert(msg != NULL);
|
||||
free(msg->paging_drx);
|
||||
free(msg->paging_priority);
|
||||
if (msg->ue_radio_capability != NULL) {
|
||||
free_byte_array(*msg->ue_radio_capability);
|
||||
free(msg->ue_radio_capability);
|
||||
}
|
||||
free(msg->origin);
|
||||
free(msg->paging_attempt_info);
|
||||
}
|
||||
|
||||
/** @brief Decode NGAP Paging message (9.2.4.1 of 3GPP TS 38.413)
|
||||
* @param out Pointer to output structure to fill
|
||||
* @param pdu Pointer to NGAP PDU containing the Paging message
|
||||
* @return true on success, false on failure */
|
||||
bool decode_ng_paging(ngap_paging_ind_t *out, const NGAP_NGAP_PDU_t *pdu)
|
||||
{
|
||||
DevAssert(pdu != NULL);
|
||||
DevAssert(out != NULL);
|
||||
|
||||
if (pdu->present != NGAP_NGAP_PDU_PR_initiatingMessage) {
|
||||
NGAP_ERROR("Invalid PDU present value for Paging message\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const NGAP_Paging_t *container = &pdu->choice.initiatingMessage->value.choice.Paging;
|
||||
NGAP_PagingIEs_t *ie;
|
||||
fiveg_s_tmsi_t *s_tmsi = &out->ue_paging_identity.s_tmsi;
|
||||
|
||||
// Reset output structure
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
// UE Paging Identity (M)
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEPagingIdentity, true);
|
||||
|
||||
if (ie->value.choice.UEPagingIdentity.present == NGAP_UEPagingIdentity_PR_fiveG_S_TMSI) {
|
||||
const struct NGAP_FiveG_S_TMSI *fiveG_S_TMSI = ie->value.choice.UEPagingIdentity.choice.fiveG_S_TMSI;
|
||||
s_tmsi->amf_set_id = BIT_STRING_to_uint16(&fiveG_S_TMSI->aMFSetID);
|
||||
s_tmsi->amf_pointer = BIT_STRING_to_uint8(&fiveG_S_TMSI->aMFPointer);
|
||||
OCTET_STRING_TO_INT32(&fiveG_S_TMSI->fiveG_TMSI, s_tmsi->m_tmsi);
|
||||
} else {
|
||||
NGAP_ERROR("Unsupported UE Paging Identity type\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TAI List for Paging (M)
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_TAIListForPaging, true);
|
||||
|
||||
// Validate TAI list count
|
||||
int tai_count = ie->value.choice.TAIListForPaging.list.count;
|
||||
if (tai_count > NGAP_MAX_NO_TAI_PAGING) {
|
||||
NGAP_ERROR("Invalid TAI list count: %d (must be <= %d)\n", tai_count, NGAP_MAX_NO_TAI_PAGING);
|
||||
return false;
|
||||
}
|
||||
|
||||
out->n_tai = 0;
|
||||
for (int i = 0; i < tai_count; i++) {
|
||||
const NGAP_TAIListForPagingItem_t *item_p = ie->value.choice.TAIListForPaging.list.array[i];
|
||||
DevAssert(item_p != NULL);
|
||||
const NGAP_TAI_t *tai = &item_p->tAI;
|
||||
nr_tai_t *tai_out = &out->tai_list[i];
|
||||
TBCD_TO_MCC_MNC(&tai->pLMNIdentity, tai_out->plmn.mcc, tai_out->plmn.mnc, tai_out->plmn.mnc_digit_length);
|
||||
OCTET_STRING_TO_INT24(&tai->tAC, tai_out->tac);
|
||||
NGAP_DEBUG("TAI[%d] for paging: MCC=%03d, MNC=%0*d, TAC=%d\n",
|
||||
i,
|
||||
tai_out->plmn.mcc,
|
||||
tai_out->plmn.mnc_digit_length,
|
||||
tai_out->plmn.mnc,
|
||||
tai_out->tac);
|
||||
out->n_tai++;
|
||||
}
|
||||
|
||||
// Paging DRX (O)
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PagingDRX, false);
|
||||
if (ie != NULL) {
|
||||
out->paging_drx = malloc_or_fail(sizeof(ngap_paging_drx_t));
|
||||
*out->paging_drx = ie->value.choice.PagingDRX;
|
||||
const char *s = text_info_at(*out->paging_drx, paging_drx_text, sizeofArray(paging_drx_text));
|
||||
NGAP_DEBUG("Decoded Paging DRX: %s", s);
|
||||
}
|
||||
|
||||
// Paging Priority (O)
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PagingPriority, false);
|
||||
if (ie != NULL) {
|
||||
out->paging_priority = malloc_or_fail(sizeof(ngap_paging_priority_t));
|
||||
*out->paging_priority = ie->value.choice.PagingPriority;
|
||||
const char *s = text_info_at(*out->paging_priority, paging_prio_text, sizeofArray(paging_prio_text));
|
||||
NGAP_DEBUG("Decoded Paging Priority: %s", s);
|
||||
}
|
||||
|
||||
// UERadioCapabilityForPaging (O)
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UERadioCapabilityForPaging, false);
|
||||
if (ie != NULL) {
|
||||
const NGAP_UERadioCapabilityForPaging_t *ue_radio_cap = &ie->value.choice.UERadioCapabilityForPaging;
|
||||
const OCTET_STRING_t *nr_field = ue_radio_cap->uERadioCapabilityForPagingOfNR;
|
||||
const OCTET_STRING_t *eutra_field = ue_radio_cap->uERadioCapabilityForPagingOfEUTRA;
|
||||
if (nr_field != NULL) {
|
||||
out->ue_radio_capability = malloc_or_fail(sizeof(byte_array_t));
|
||||
*out->ue_radio_capability = create_byte_array(nr_field->size, nr_field->buf);
|
||||
NGAP_DEBUG("Decoded UERadioCapabilityForPaging (NR): %zu bytes\n", nr_field->size);
|
||||
} else if (eutra_field != NULL) {
|
||||
out->ue_radio_capability = malloc_or_fail(sizeof(byte_array_t));
|
||||
*out->ue_radio_capability = create_byte_array(eutra_field->size, eutra_field->buf);
|
||||
NGAP_DEBUG("Decoded UERadioCapabilityForPaging (EUTRA): %zu bytes\n", eutra_field->size);
|
||||
} else {
|
||||
NGAP_WARN("UERadioCapabilityForPaging present but both NR and EUTRA fields are NULL\n");
|
||||
}
|
||||
}
|
||||
|
||||
// PagingOrigin (O)
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PagingOrigin, false);
|
||||
if (ie != NULL) {
|
||||
// PagingOrigin shall be transferred to UE according to TS 38.331 and TS 36.331
|
||||
out->origin = calloc_or_fail(1, sizeof(*out->origin));
|
||||
*out->origin = ie->value.choice.PagingOrigin;
|
||||
}
|
||||
|
||||
// AssistanceDataForPaging (O) - contains PagingAttemptInformation
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AssistanceDataForPaging, false);
|
||||
if (ie != NULL) {
|
||||
const NGAP_AssistanceDataForPaging_t *assistance_data = &ie->value.choice.AssistanceDataForPaging;
|
||||
|
||||
// Extract PagingAttemptInformation if present (TS 38.413 §9.3.1.72)
|
||||
if (assistance_data->pagingAttemptInformation != NULL) {
|
||||
const NGAP_PagingAttemptInformation_t *paging_attempt_info = assistance_data->pagingAttemptInformation;
|
||||
out->paging_attempt_info = calloc_or_fail(1, sizeof(ngap_paging_attempt_info_t));
|
||||
|
||||
// Paging Attempt Count (mandatory)
|
||||
uint8_t attempt_count = paging_attempt_info->pagingAttemptCount;
|
||||
DevAssert(attempt_count >= NGAP_PAGING_ATTEMPT_MIN && attempt_count <= NGAP_PAGING_ATTEMPT_MAX);
|
||||
out->paging_attempt_info->paging_attempt_count = attempt_count;
|
||||
NGAP_DEBUG("Decoded Paging Attempt Count: %u\n", out->paging_attempt_info->paging_attempt_count);
|
||||
|
||||
// Intended Number of Paging Attempts (mandatory)
|
||||
uint8_t intended_attempts = paging_attempt_info->intendedNumberOfPagingAttempts;
|
||||
DevAssert(intended_attempts >= NGAP_PAGING_ATTEMPT_MIN && intended_attempts <= NGAP_PAGING_ATTEMPT_MAX);
|
||||
out->paging_attempt_info->intended_paging_attempts = intended_attempts;
|
||||
NGAP_DEBUG("Decoded Intended Number of Paging Attempts: %u\n", out->paging_attempt_info->intended_paging_attempts);
|
||||
}
|
||||
}
|
||||
|
||||
NGAP_DEBUG("Decoded Paging: m_tmsi=0x%08x, TAI=%d", s_tmsi->m_tmsi, out->n_tai);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Check equality of two NGAP paging indication structures
|
||||
* @param a First structure
|
||||
* @param b Second structure
|
||||
* @return true if equal, false otherwise */
|
||||
bool eq_ng_paging(const ngap_paging_ind_t *a, const ngap_paging_ind_t *b)
|
||||
{
|
||||
if (a == NULL || b == NULL) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
// UE Paging Identity
|
||||
const fiveg_s_tmsi_t *a_tmsi = &a->ue_paging_identity.s_tmsi;
|
||||
const fiveg_s_tmsi_t *b_tmsi = &b->ue_paging_identity.s_tmsi;
|
||||
_EQ_CHECK_INT(a_tmsi->amf_set_id, b_tmsi->amf_set_id);
|
||||
_EQ_CHECK_INT(a_tmsi->amf_pointer, b_tmsi->amf_pointer);
|
||||
_EQ_CHECK_UINT32(a_tmsi->m_tmsi, b_tmsi->m_tmsi);
|
||||
|
||||
// TAI List
|
||||
_EQ_CHECK_INT(a->n_tai, b->n_tai);
|
||||
for (int i = 0; i < a->n_tai; i++) {
|
||||
if (!eq_ngap_plmn(&a->tai_list[i].plmn, &b->tai_list[i].plmn)) {
|
||||
return false;
|
||||
}
|
||||
_EQ_CHECK_INT(a->tai_list[i].tac, b->tai_list[i].tac);
|
||||
}
|
||||
|
||||
// Paging DRX (optional)
|
||||
_EQ_CHECK_OPTIONAL_IE(a, b, paging_drx, _EQ_CHECK_INT);
|
||||
|
||||
// Paging Priority (optional)
|
||||
_EQ_CHECK_OPTIONAL_IE(a, b, paging_priority, _EQ_CHECK_INT);
|
||||
|
||||
// UERadioCapabilityForPaging (optional)
|
||||
_EQ_CHECK_OPTIONAL_PTR(a, b, ue_radio_capability);
|
||||
if (a->ue_radio_capability != NULL && b->ue_radio_capability != NULL) {
|
||||
if (!eq_byte_array(a->ue_radio_capability, b->ue_radio_capability)) {
|
||||
NGAP_ERROR("Equality condition 'eq_byte_array' failed: byte array contents differ\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// PagingOrigin (optional)
|
||||
_EQ_CHECK_OPTIONAL_IE(a, b, origin, _EQ_CHECK_INT);
|
||||
|
||||
// Assistance Data for Paging (optional)
|
||||
_EQ_CHECK_OPTIONAL_PTR(a, b, paging_attempt_info);
|
||||
if (a->paging_attempt_info != NULL && b->paging_attempt_info != NULL) {
|
||||
_EQ_CHECK_INT(a->paging_attempt_info->paging_attempt_count, b->paging_attempt_info->paging_attempt_count);
|
||||
_EQ_CHECK_INT(a->paging_attempt_info->intended_paging_attempts, b->paging_attempt_info->intended_paging_attempts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef NGAP_GNB_PAGING_H_
|
||||
#define NGAP_GNB_PAGING_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "ngap_messages_types.h"
|
||||
|
||||
/** @brief Encode NGAP Paging message (9.2.4.1 of 3GPP TS 38.413)
|
||||
* @param msg Pointer to paging indication structure to encode
|
||||
* @return Pointer to allocated NGAP_NGAP_PDU_t, or NULL on failure */
|
||||
NGAP_NGAP_PDU_t *encode_ng_paging(const ngap_paging_ind_t *msg);
|
||||
|
||||
/** @brief Decode NGAP Paging message (9.2.4.1 of 3GPP TS 38.413)
|
||||
* @param out Pointer to output structure to fill
|
||||
* @param pdu Pointer to NGAP PDU containing the Paging message
|
||||
* @return true on success, false on failure */
|
||||
bool decode_ng_paging(ngap_paging_ind_t *out, const NGAP_NGAP_PDU_t *pdu);
|
||||
|
||||
/** @brief Free memory allocated for NGAP paging indication
|
||||
* @param msg Pointer to paging indication structure to free */
|
||||
void free_ng_paging(ngap_paging_ind_t *msg);
|
||||
|
||||
/** @brief Check equality of two NGAP paging indication structures
|
||||
* @param a First structure
|
||||
* @param b Second structure
|
||||
* @return true if equal, false otherwise */
|
||||
bool eq_ng_paging(const ngap_paging_ind_t *a, const ngap_paging_ind_t *b);
|
||||
|
||||
#endif /* NGAP_GNB_PAGING_H_ */
|
||||
@@ -41,6 +41,12 @@
|
||||
#include "NGAP_GTPTunnel.h"
|
||||
#include "NGAP_InitiatingMessage.h"
|
||||
#include "NGAP_NGAP-PDU.h"
|
||||
#include "NGAP_Paging.h"
|
||||
#include "NGAP_AssistanceDataForPaging.h"
|
||||
#include "NGAP_PagingAttemptInformation.h"
|
||||
#include "NGAP_FiveG-S-TMSI.h"
|
||||
#include "NGAP_TAI.h"
|
||||
#include "NGAP_UEPagingIdentity.h"
|
||||
#include "NGAP_PDUSessionResourceFailedToModifyItemModRes.h"
|
||||
#include "NGAP_PDUSessionResourceFailedToSetupItemCxtRes.h"
|
||||
#include "NGAP_PDUSessionResourceFailedToSetupItemSURes.h"
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <string.h>
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "assertions.h"
|
||||
#include "common/utils/eq_check.h"
|
||||
|
||||
#define NGAP_UE_ID_FMT "0x%06" PRIX32
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
add_executable(ngap_lib_test ngap_lib_test.c)
|
||||
add_dependencies(tests ngap_lib_test)
|
||||
add_test(NAME ngap_lib_test COMMAND ngap_lib_test)
|
||||
target_link_libraries(ngap_lib_test PRIVATE ngap asn1_ngap asn1_lte_rrc_hdrs UTIL ds)
|
||||
target_include_directories(ngap_lib_test PRIVATE ${CMAKE_SOURCE_DIR})
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <stdlib.h> // abort
|
||||
#include <stdint.h> // uint*_t
|
||||
#include <stdio.h> // printf
|
||||
#include <stdbool.h> // bool
|
||||
|
||||
#include "common/utils/assertions.h" // AssertFatal, DevAssert
|
||||
#include "common/utils/utils.h" // malloc_or_fail, calloc_or_fail
|
||||
#include "common/utils/ds/byte_array.h" // create_byte_array
|
||||
#include "conversions.h" // TBCD_TO_MCC_MNC, OCTET_STRING_TO_INT*
|
||||
#include "ngap_common.h" // NGAP_ERROR, NGAP_DEBUG, ngap_messages_types.h
|
||||
#include "ngap_gNB_paging.h" // encode_ng_paging, decode_ng_paging, free_ng_paging
|
||||
#include "ngap_msg_includes.h" // NGAP_NGAP_PDU_t, NGAP_Paging_t, etc.
|
||||
#include "oai_asn1.h" // ASN_STRUCT_FREE, asn_DEF_NGAP_NGAP_PDU
|
||||
#include "config/config_load_configmodule.h" // configmodule_interface_t
|
||||
#include "common/utils/LOG/log.h" // log_init
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
printf("detected error at %s:%d:%s: %s\n", file, line, function, s);
|
||||
abort();
|
||||
}
|
||||
|
||||
static NGAP_NGAP_PDU_t *ngap_encode_decode(const NGAP_NGAP_PDU_t *enc_pdu)
|
||||
{
|
||||
DevAssert(enc_pdu != NULL);
|
||||
char errbuf[1024];
|
||||
size_t errlen = sizeof(errbuf);
|
||||
int ret = asn_check_constraints(&asn_DEF_NGAP_NGAP_PDU, enc_pdu, errbuf, &errlen);
|
||||
AssertFatal(ret == 0, "asn_check_constraints() failed: %s\n", errbuf);
|
||||
|
||||
uint8_t msgbuf[16384];
|
||||
asn_enc_rval_t enc = aper_encode_to_buffer(&asn_DEF_NGAP_NGAP_PDU, NULL, enc_pdu, msgbuf, sizeof(msgbuf));
|
||||
AssertFatal(enc.encoded > 0, "aper_encode_to_buffer() failed\n");
|
||||
|
||||
NGAP_NGAP_PDU_t *dec_pdu = NULL;
|
||||
asn_codec_ctx_t st = {.max_stack_size = 100 * 1000};
|
||||
asn_dec_rval_t dec = aper_decode(&st, &asn_DEF_NGAP_NGAP_PDU, (void **)&dec_pdu, msgbuf, enc.encoded, 0, 0);
|
||||
AssertFatal(dec.code == RC_OK, "aper_decode() failed\n");
|
||||
|
||||
return dec_pdu;
|
||||
}
|
||||
|
||||
static void ngap_msg_free(NGAP_NGAP_PDU_t *pdu)
|
||||
{
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
}
|
||||
|
||||
/** @brief Test NGAP Paging encoding/decoding roundtrip */
|
||||
static void test_ngap_paging_encode_decode(void)
|
||||
{
|
||||
// Create test paging indication
|
||||
ngap_paging_ind_t orig = {0};
|
||||
orig.ue_paging_identity.s_tmsi.amf_set_id = 123; // Valid range: 0-1023 (10 bits)
|
||||
orig.ue_paging_identity.s_tmsi.amf_pointer = 45; // Valid range: 0-63 (6 bits)
|
||||
orig.ue_paging_identity.s_tmsi.m_tmsi = 0x12345678;
|
||||
orig.n_tai = 2;
|
||||
orig.tai_list[0].plmn.mcc = 208;
|
||||
orig.tai_list[0].plmn.mnc = 95;
|
||||
orig.tai_list[0].plmn.mnc_digit_length = 2;
|
||||
orig.tai_list[0].tac = 12345;
|
||||
orig.tai_list[1].plmn.mcc = 001;
|
||||
orig.tai_list[1].plmn.mnc = 01;
|
||||
orig.tai_list[1].plmn.mnc_digit_length = 2;
|
||||
orig.tai_list[1].tac = 23456;
|
||||
orig.paging_drx = malloc_or_fail(sizeof(ngap_paging_drx_t));
|
||||
*orig.paging_drx = NGAP_PAGING_DRX_128;
|
||||
orig.paging_priority = malloc_or_fail(sizeof(ngap_paging_priority_t));
|
||||
*orig.paging_priority = NGAP_PAGING_PRIO_LEVEL2;
|
||||
uint8_t ue_cap_data[] = {0x01, 0x02, 0x03, 0x04};
|
||||
orig.ue_radio_capability = malloc_or_fail(sizeof(byte_array_t));
|
||||
*orig.ue_radio_capability = create_byte_array(sizeof(ue_cap_data), ue_cap_data);
|
||||
orig.origin = calloc_or_fail(1, sizeof(*orig.origin));
|
||||
*orig.origin = NGAP_PAGING_ORIGIN_NON_3GPP;
|
||||
|
||||
// Encode
|
||||
NGAP_NGAP_PDU_t *enc_pdu = encode_ng_paging(&orig);
|
||||
AssertFatal(enc_pdu != NULL, "encode_ng_paging(): failed to encode message\n");
|
||||
LOG_A(NGAP, "encoded: m_tmsi=0x%x, n_tai=%d\n", orig.ue_paging_identity.s_tmsi.m_tmsi, orig.n_tai);
|
||||
|
||||
// Encode/decode roundtrip
|
||||
NGAP_NGAP_PDU_t *dec_pdu = ngap_encode_decode(enc_pdu);
|
||||
ngap_msg_free(enc_pdu);
|
||||
|
||||
// Decode
|
||||
ngap_paging_ind_t decoded = {0};
|
||||
bool decode_ret = decode_ng_paging(&decoded, dec_pdu);
|
||||
AssertFatal(decode_ret, "decode_ng_paging(): could not decode message\n");
|
||||
ngap_msg_free(dec_pdu);
|
||||
LOG_A(NGAP, "decoded: m_tmsi=0x%x, n_tai=%d\n", decoded.ue_paging_identity.s_tmsi.m_tmsi, decoded.n_tai);
|
||||
|
||||
// Verify decoded values using equality function
|
||||
bool eq_ret = eq_ng_paging(&orig, &decoded);
|
||||
AssertFatal(eq_ret, "eq_ng_paging(): decoded message doesn't match original\n");
|
||||
LOG_A(NGAP, "eq_ng_paging(): decoded message matches original\n");
|
||||
|
||||
free_ng_paging(&decoded);
|
||||
free_ng_paging(&orig);
|
||||
}
|
||||
|
||||
// Stub for uniqCfg required by logging/config system
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialize logging system
|
||||
logInit();
|
||||
set_log(NGAP, OAILOG_INFO);
|
||||
|
||||
test_ngap_paging_encode_decode();
|
||||
LOG_A(NGAP, "All NGAP paging tests passed!\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user