Paging (F1AP): add F1 paging library (9.2.6.1 3GPP TS 38.473)
Add F1AP Paging library and new message type to follow the existing F1AP
library pattern and to support multi-cell paging and both RAN UE (I-RNTI)
and CN UE (5G-S-TMSI) paging identities at the library level per TS 38.473.
* New library (f1ap_paging.c/h, f1ap_lib_includes.h, CMakeLists.txt)
- Implement encode/decode/copy/eq/free for F1AP Paging (procedure 9.2.6).
- Add ASN.1 includes for Paging, PagingIdentity, CN/RAN UE identities.
- Enables unit testing of Paging enc/dec in f1ap_lib_test.c.
* New types in f1ap_messages_types.h (existing f1ap_paging_ind_t unchanged)
- f1ap_paging_t: UE Identity Index, paging identity (union + type enum),
optional paging_drx, paging_priority, paging_origin, and paging_cells[].
- f1ap_paging_cell_item_t, f1ap_paging_identity_type_t, f1ap_paging_identity_t
for multi-cell list and RAN/CN identity discrimination.
- Paging Origin IE is optional per F1AP 8.7.1.2.
Tests: test_f1ap_paging() roundtrip and copy for CN UE (5G-S-TMSI) and
RAN UE (I-RNTI) cases, with optional IEs.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/sctp.h>
|
||||
#include <stdbool.h>
|
||||
#include "common/5g_platform_types.h"
|
||||
#include "common/platform_constants.h"
|
||||
#include "common/utils/ds/byte_array.h"
|
||||
@@ -640,6 +641,68 @@ typedef struct f1ap_paging_ind_s {
|
||||
uint8_t paging_drx;
|
||||
} f1ap_paging_ind_t;
|
||||
|
||||
typedef struct f1ap_paging_cell_item_s {
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
} f1ap_paging_cell_item_t;
|
||||
|
||||
typedef enum f1ap_paging_identity_type_e {
|
||||
F1AP_PAGING_IDENTITY_RAN_UE, // RAN UE Paging Identity (I-RNTI)
|
||||
F1AP_PAGING_IDENTITY_CN_UE // CN UE Paging Identity (5G-S-TMSI)
|
||||
} f1ap_paging_identity_type_t;
|
||||
|
||||
typedef union f1ap_paging_identity_u {
|
||||
// RAN UE Paging Identity (I-RNTI)
|
||||
uint64_t ran_ue_paging_identity;
|
||||
// CN UE Paging Identity (5G-S-TMSI)
|
||||
uint64_t cn_ue_paging_identity;
|
||||
} f1ap_paging_identity_t;
|
||||
|
||||
/** @brief Paging DRX (9.3.1.40 TS 38.473)
|
||||
* This IE indicates the Paging DRX as defined in
|
||||
* TS 38.304. Unit in radio frames.*/
|
||||
typedef enum f1ap_paging_drx_e {
|
||||
F1AP_PAGING_DRX_32 = 0,
|
||||
F1AP_PAGING_DRX_64 = 1,
|
||||
F1AP_PAGING_DRX_128 = 2,
|
||||
F1AP_PAGING_DRX_256 = 3
|
||||
} f1ap_paging_drx_t;
|
||||
|
||||
/** @brief Paging Priority (9.3.1.41 TS 38.473)
|
||||
* Lower value codepoint indicates higher priority.
|
||||
* codepoint indicates higher priority.*/
|
||||
typedef enum f1ap_paging_priority_e {
|
||||
F1AP_PAGING_PRIO_LEVEL1 = 0,
|
||||
F1AP_PAGING_PRIO_LEVEL2 = 1,
|
||||
F1AP_PAGING_PRIO_LEVEL3 = 2,
|
||||
F1AP_PAGING_PRIO_LEVEL4 = 3,
|
||||
F1AP_PAGING_PRIO_LEVEL5 = 4,
|
||||
F1AP_PAGING_PRIO_LEVEL6 = 5,
|
||||
F1AP_PAGING_PRIO_LEVEL7 = 6,
|
||||
F1AP_PAGING_PRIO_LEVEL8 = 7
|
||||
} f1ap_paging_priority_t;
|
||||
|
||||
typedef bool f1ap_paging_origin_t;
|
||||
#define F1AP_PAGING_ORIGIN_NON_3GPP true
|
||||
|
||||
/* 9.2.6.1 Paging (3GPP TS 38.473) */
|
||||
typedef struct {
|
||||
// UE Identity Index value (mandatory)
|
||||
uint16_t ue_identity_index_value;
|
||||
// Paging Identity (mandatory)
|
||||
f1ap_paging_identity_type_t identity_type;
|
||||
f1ap_paging_identity_t identity;
|
||||
// Paging DRX: 0 (32), 1 (64), 2 (128), 3 (256) (optional)
|
||||
f1ap_paging_drx_t *drx;
|
||||
// Paging priority (optional)
|
||||
f1ap_paging_priority_t *priority;
|
||||
// Paging origin (optional)
|
||||
f1ap_paging_origin_t *origin;
|
||||
// Paging Cell List (mandatory); max 512 cells
|
||||
uint16_t n_cells;
|
||||
f1ap_paging_cell_item_t *cells;
|
||||
} f1ap_paging_t;
|
||||
|
||||
typedef struct f1ap_lost_connection_t {
|
||||
int dummy;
|
||||
} f1ap_lost_connection_t;
|
||||
|
||||
@@ -4,6 +4,7 @@ add_library(f1ap_lib OBJECT
|
||||
f1ap_interface_management.c
|
||||
f1ap_ue_context.c
|
||||
f1ap_positioning.c
|
||||
f1ap_paging.c
|
||||
)
|
||||
target_link_libraries(f1ap_lib PRIVATE asn1_f1ap ds)
|
||||
target_include_directories(f1ap_lib PUBLIC
|
||||
|
||||
@@ -90,5 +90,9 @@
|
||||
#include "F1AP_UL-RTOA-Measurement.h"
|
||||
#include "F1AP_GNB-RxTxTimeDiff.h"
|
||||
#include "F1AP_LCS-to-GCS-TranslationAoA.h"
|
||||
#include "F1AP_CNUEPagingIdentity.h"
|
||||
#include "F1AP_RANUEPagingIdentity.h"
|
||||
#include "F1AP_PagingIdentity.h"
|
||||
#include "F1AP_Paging.h"
|
||||
|
||||
#endif /* F1AP_LIB_INCLUDES_H_ */
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
#include "openair3/UTILS/conversions.h"
|
||||
#include "common/utils/oai_asn1.h"
|
||||
#include "common/utils/utils.h"
|
||||
|
||||
#include "f1ap_paging.h"
|
||||
#include "f1ap_lib_common.h"
|
||||
#include "f1ap_lib_includes.h"
|
||||
#include "f1ap_messages_types.h"
|
||||
|
||||
/** @brief encode to F1AP_PagingDRX_t */
|
||||
static F1AP_PagingDRX_t encode_f1_paging_drx(const f1ap_paging_drx_t drx)
|
||||
{
|
||||
switch (drx) {
|
||||
case F1AP_PAGING_DRX_32:
|
||||
return F1AP_PagingDRX_v32;
|
||||
case F1AP_PAGING_DRX_64:
|
||||
return F1AP_PagingDRX_v64;
|
||||
case F1AP_PAGING_DRX_128:
|
||||
return F1AP_PagingDRX_v128;
|
||||
case F1AP_PAGING_DRX_256:
|
||||
return F1AP_PagingDRX_v256;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Unknown Paging DRX: %u\n", drx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief decode from F1AP_PagingDRX_t */
|
||||
static f1ap_paging_drx_t decode_f1_paging_drx(const F1AP_PagingDRX_t drx)
|
||||
{
|
||||
switch (drx) {
|
||||
case F1AP_PagingDRX_v32:
|
||||
return F1AP_PAGING_DRX_32;
|
||||
case F1AP_PagingDRX_v64:
|
||||
return F1AP_PAGING_DRX_64;
|
||||
case F1AP_PagingDRX_v128:
|
||||
return F1AP_PAGING_DRX_128;
|
||||
case F1AP_PagingDRX_v256:
|
||||
return F1AP_PAGING_DRX_256;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Unknown Paging DRX: %ld\n", drx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief encode F1 Paging (9.2.6 Paging 3GPP TS 38.473) */
|
||||
F1AP_F1AP_PDU_t *encode_f1ap_paging(const f1ap_paging_t *msg)
|
||||
{
|
||||
DevAssert(msg);
|
||||
F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
|
||||
pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage;
|
||||
asn1cCalloc(pdu->choice.initiatingMessage, initMsg);
|
||||
initMsg->procedureCode = F1AP_ProcedureCode_id_Paging;
|
||||
initMsg->criticality = F1AP_Criticality_reject;
|
||||
initMsg->value.present = F1AP_InitiatingMessage__value_PR_Paging;
|
||||
F1AP_Paging_t *paging = &initMsg->value.choice.Paging;
|
||||
|
||||
/* UEIdentityIndexValue (Mandatory) 10 bits */
|
||||
{
|
||||
AssertFatal(msg->ue_identity_index_value <= 1023,
|
||||
"UE Identity Index Value exceeds 10 bits: %d\n",
|
||||
msg->ue_identity_index_value);
|
||||
asn1cSequenceAdd(paging->protocolIEs.list, F1AP_PagingIEs_t, ie);
|
||||
ie->id = F1AP_ProtocolIE_ID_id_UEIdentityIndexValue;
|
||||
ie->criticality = F1AP_Criticality_reject;
|
||||
ie->value.present = F1AP_PagingIEs__value_PR_UEIdentityIndexValue;
|
||||
F1AP_UEIdentityIndexValue_t *ue_identity_index = &ie->value.choice.UEIdentityIndexValue;
|
||||
ue_identity_index->present = F1AP_UEIdentityIndexValue_PR_indexLength10;
|
||||
UEIDENTITYINDEX_TO_BIT_STRING(msg->ue_identity_index_value, &ue_identity_index->choice.indexLength10);
|
||||
}
|
||||
|
||||
/* PagingIdentity (Mandatory) */
|
||||
{
|
||||
asn1cSequenceAdd(paging->protocolIEs.list, F1AP_PagingIEs_t, ie);
|
||||
ie->id = F1AP_ProtocolIE_ID_id_PagingIdentity;
|
||||
ie->criticality = F1AP_Criticality_reject;
|
||||
ie->value.present = F1AP_PagingIEs__value_PR_PagingIdentity;
|
||||
|
||||
F1AP_PagingIdentity_t *paging_identity = &ie->value.choice.PagingIdentity;
|
||||
const f1ap_paging_identity_t *paging_id = &msg->identity;
|
||||
|
||||
if (msg->identity_type == F1AP_PAGING_IDENTITY_CN_UE) {
|
||||
// CN UE Paging Identity (5G-S-TMSI)
|
||||
paging_identity->present = F1AP_PagingIdentity_PR_cNUEPagingIdentity;
|
||||
asn1cCalloc(paging_identity->choice.cNUEPagingIdentity, id);
|
||||
id->present = F1AP_CNUEPagingIdentity_PR_fiveG_S_TMSI;
|
||||
FIVEG_S_TMSI_TO_BIT_STRING(paging_id->cn_ue_paging_identity, &id->choice.fiveG_S_TMSI);
|
||||
} else {
|
||||
// RAN UE Paging Identity (I-RNTI)
|
||||
paging_identity->present = F1AP_PagingIdentity_PR_rANUEPagingIdentity;
|
||||
asn1cCalloc(paging_identity->choice.rANUEPagingIdentity, ran_id);
|
||||
// I-RNTI is 40 bits, stored in 5 bytes
|
||||
IRNTI_TO_BIT_STRING(paging_id->ran_ue_paging_identity, &ran_id->iRNTI);
|
||||
}
|
||||
}
|
||||
|
||||
/* Paging Priority (Optional) */
|
||||
if (msg->priority != NULL) {
|
||||
AssertFatal(*msg->priority >= F1AP_PAGING_PRIO_LEVEL1 && *msg->priority <= F1AP_PAGING_PRIO_LEVEL8,
|
||||
"Unknown Paging Priority: %d\n",
|
||||
*msg->priority);
|
||||
asn1cSequenceAdd(paging->protocolIEs.list, F1AP_PagingIEs_t, ie);
|
||||
ie->id = F1AP_ProtocolIE_ID_id_PagingPriority;
|
||||
ie->criticality = F1AP_Criticality_ignore;
|
||||
ie->value.present = F1AP_PagingIEs__value_PR_PagingPriority;
|
||||
ie->value.choice.PagingPriority = (F1AP_PagingPriority_t)*msg->priority;
|
||||
}
|
||||
|
||||
/* Paging Origin (Optional) */
|
||||
if (msg->origin != NULL) {
|
||||
AssertFatal(*msg->origin == F1AP_PAGING_ORIGIN_NON_3GPP, "Unknown Paging Origin: %d\n", *msg->origin);
|
||||
asn1cSequenceAdd(paging->protocolIEs.list, F1AP_PagingIEs_t, ie);
|
||||
ie->id = F1AP_ProtocolIE_ID_id_PagingOrigin;
|
||||
ie->criticality = F1AP_Criticality_ignore;
|
||||
ie->value.present = F1AP_PagingIEs__value_PR_PagingOrigin;
|
||||
ie->value.choice.PagingOrigin = F1AP_PagingOrigin_non_3gpp;
|
||||
}
|
||||
|
||||
/* PagingDRX (Optional) */
|
||||
if (msg->drx != NULL) {
|
||||
asn1cSequenceAdd(paging->protocolIEs.list, F1AP_PagingIEs_t, ie);
|
||||
ie->id = F1AP_ProtocolIE_ID_id_PagingDRX;
|
||||
ie->criticality = F1AP_Criticality_ignore;
|
||||
ie->value.present = F1AP_PagingIEs__value_PR_PagingDRX;
|
||||
ie->value.choice.PagingDRX = encode_f1_paging_drx(*msg->drx);
|
||||
}
|
||||
|
||||
/* PagingCell_list (Mandatory) */
|
||||
{
|
||||
AssertFatal(msg->n_cells > 0 && msg->n_cells <= F1AP_MAX_NB_CELLS,
|
||||
"invalid n_cells %u (must be 1..%d)\n",
|
||||
msg->n_cells,
|
||||
F1AP_MAX_NB_CELLS);
|
||||
DevAssert(msg->cells != NULL);
|
||||
asn1cSequenceAdd(paging->protocolIEs.list, F1AP_PagingIEs_t, ie);
|
||||
ie->id = F1AP_ProtocolIE_ID_id_PagingCell_List;
|
||||
ie->criticality = F1AP_Criticality_reject;
|
||||
ie->value.present = F1AP_PagingIEs__value_PR_PagingCell_list;
|
||||
|
||||
// Add all cells in the paging cell list
|
||||
for (uint16_t cell_idx = 0; cell_idx < msg->n_cells; cell_idx++) {
|
||||
asn1cSequenceAdd(ie->value.choice.PagingCell_list, F1AP_PagingCell_ItemIEs_t, item);
|
||||
item->id = F1AP_ProtocolIE_ID_id_PagingCell_Item;
|
||||
item->criticality = F1AP_Criticality_reject;
|
||||
item->value.present = F1AP_PagingCell_ItemIEs__value_PR_PagingCell_Item;
|
||||
// NRCGI (Mandatory)
|
||||
F1AP_NRCGI_t *nRCGI = &item->value.choice.PagingCell_Item.nRCGI;
|
||||
const f1ap_paging_cell_item_t *cell = &msg->cells[cell_idx];
|
||||
MCC_MNC_TO_PLMNID(cell->plmn.mcc, cell->plmn.mnc, cell->plmn.mnc_digit_length, &nRCGI->pLMN_Identity);
|
||||
NR_CELL_ID_TO_BIT_STRING(cell->nr_cellid, &nRCGI->nRCellIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/** @brief decode F1 Paging (9.2.6 Paging 3GPP TS 38.473) */
|
||||
bool decode_f1ap_paging(f1ap_paging_t *out, const F1AP_F1AP_PDU_t *pdu)
|
||||
{
|
||||
DevAssert(out);
|
||||
DevAssert(pdu);
|
||||
DevAssert(pdu->choice.initiatingMessage);
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_initiatingMessage);
|
||||
_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, F1AP_ProcedureCode_id_Paging);
|
||||
_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, F1AP_InitiatingMessage__value_PR_Paging);
|
||||
|
||||
/* Check presence of mandatory IEs */
|
||||
const F1AP_Paging_t *in = &pdu->choice.initiatingMessage->value.choice.Paging;
|
||||
F1AP_PagingIEs_t *ie;
|
||||
F1AP_LIB_FIND_IE(F1AP_PagingIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_UEIdentityIndexValue, true);
|
||||
F1AP_LIB_FIND_IE(F1AP_PagingIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_PagingIdentity, true);
|
||||
F1AP_LIB_FIND_IE(F1AP_PagingIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_PagingCell_List, true);
|
||||
|
||||
/* Loop over all IEs */
|
||||
for (int i = 0; i < in->protocolIEs.list.count; i++) {
|
||||
DevAssert(in->protocolIEs.list.array[i] != NULL);
|
||||
ie = in->protocolIEs.list.array[i];
|
||||
switch (ie->id) {
|
||||
case F1AP_ProtocolIE_ID_id_UEIdentityIndexValue:
|
||||
// (M) UE Identity Index Value
|
||||
_EQ_CHECK_INT(ie->value.present, F1AP_PagingIEs__value_PR_UEIdentityIndexValue);
|
||||
out->ue_identity_index_value = BIT_STRING_to_uint32(&ie->value.choice.UEIdentityIndexValue.choice.indexLength10);
|
||||
break;
|
||||
|
||||
case F1AP_ProtocolIE_ID_id_PagingIdentity:
|
||||
// (M) Paging Identity
|
||||
_EQ_CHECK_INT(ie->value.present, F1AP_PagingIEs__value_PR_PagingIdentity);
|
||||
if (ie->value.choice.PagingIdentity.present == F1AP_PagingIdentity_PR_cNUEPagingIdentity) {
|
||||
// CN UE Paging Identity (5G-S-TMSI)
|
||||
out->identity_type = F1AP_PAGING_IDENTITY_CN_UE;
|
||||
BIT_STRING_t *fiveg_tmsi = &ie->value.choice.PagingIdentity.choice.cNUEPagingIdentity->choice.fiveG_S_TMSI;
|
||||
out->identity.cn_ue_paging_identity = BIT_STRING_to_uint64(fiveg_tmsi);
|
||||
} else if (ie->value.choice.PagingIdentity.present == F1AP_PagingIdentity_PR_rANUEPagingIdentity) {
|
||||
// RAN UE Paging Identity (I-RNTI)
|
||||
out->identity_type = F1AP_PAGING_IDENTITY_RAN_UE;
|
||||
BIT_STRING_t *irnti = &ie->value.choice.PagingIdentity.choice.rANUEPagingIdentity->iRNTI;
|
||||
out->identity.ran_ue_paging_identity = BIT_STRING_to_uint64(irnti);
|
||||
} else {
|
||||
PRINT_ERROR("Unknown PagingIdentity type: %d\n", ie->value.choice.PagingIdentity.present);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case F1AP_ProtocolIE_ID_id_PagingDRX:
|
||||
// (O) Paging DRX
|
||||
_EQ_CHECK_INT(ie->value.present, F1AP_PagingIEs__value_PR_PagingDRX);
|
||||
out->drx = malloc_or_fail(sizeof(*out->drx));
|
||||
*out->drx = decode_f1_paging_drx(ie->value.choice.PagingDRX);
|
||||
break;
|
||||
|
||||
case F1AP_ProtocolIE_ID_id_PagingPriority:
|
||||
// (O) Paging Priority
|
||||
_EQ_CHECK_INT(ie->value.present, F1AP_PagingIEs__value_PR_PagingPriority);
|
||||
AssertFatal(ie->value.choice.PagingPriority >= F1AP_PagingPriority_priolevel1
|
||||
&& ie->value.choice.PagingPriority <= F1AP_PagingPriority_priolevel8,
|
||||
"Unknown Paging Priority: %ld\n",
|
||||
ie->value.choice.PagingPriority);
|
||||
out->priority = malloc_or_fail(sizeof(*out->priority));
|
||||
*out->priority = (f1ap_paging_priority_t)ie->value.choice.PagingPriority;
|
||||
break;
|
||||
|
||||
case F1AP_ProtocolIE_ID_id_PagingOrigin:
|
||||
// (O) Paging Origin
|
||||
_EQ_CHECK_INT(ie->value.present, F1AP_PagingIEs__value_PR_PagingOrigin);
|
||||
AssertFatal(ie->value.choice.PagingOrigin == F1AP_PagingOrigin_non_3gpp,
|
||||
"Unknown Paging Origin: %ld\n",
|
||||
ie->value.choice.PagingOrigin);
|
||||
out->origin = malloc_or_fail(sizeof(*out->origin));
|
||||
*out->origin = F1AP_PAGING_ORIGIN_NON_3GPP;
|
||||
break;
|
||||
|
||||
case F1AP_ProtocolIE_ID_id_PagingCell_List:
|
||||
// (M) Paging Cell List (max 512 cells)
|
||||
_EQ_CHECK_INT(ie->value.present, F1AP_PagingIEs__value_PR_PagingCell_list);
|
||||
out->n_cells = ie->value.choice.PagingCell_list.list.count;
|
||||
AssertError(out->n_cells > 0, return false, "at least 1 cell must be present");
|
||||
AssertError(out->n_cells <= F1AP_MAX_NB_CELLS, return false, "too many cells");
|
||||
out->cells = calloc_or_fail(out->n_cells, sizeof(*out->cells));
|
||||
for (int j = 0; j < out->n_cells; j++) {
|
||||
F1AP_PagingCell_ItemIEs_t *cell_item = (F1AP_PagingCell_ItemIEs_t *)ie->value.choice.PagingCell_list.list.array[j];
|
||||
DevAssert(cell_item);
|
||||
F1AP_NRCGI_t *nRCGI = &cell_item->value.choice.PagingCell_Item.nRCGI;
|
||||
f1ap_paging_cell_item_t *cell = &out->cells[j];
|
||||
PLMNID_TO_MCC_MNC(&nRCGI->pLMN_Identity, cell->plmn.mcc, cell->plmn.mnc, cell->plmn.mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&nRCGI->nRCellIdentity, cell->nr_cellid);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id %ld unknown\n", ie->id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief free F1 Paging */
|
||||
void free_f1ap_paging(f1ap_paging_t *msg)
|
||||
{
|
||||
DevAssert(msg);
|
||||
free(msg->drx);
|
||||
free(msg->priority);
|
||||
free(msg->origin);
|
||||
free(msg->cells);
|
||||
}
|
||||
|
||||
/** @brief Equality check for two F1 Paging */
|
||||
bool eq_f1ap_paging(const f1ap_paging_t *a, const f1ap_paging_t *b)
|
||||
{
|
||||
DevAssert(a);
|
||||
DevAssert(b);
|
||||
_EQ_CHECK_INT(a->ue_identity_index_value, b->ue_identity_index_value);
|
||||
_EQ_CHECK_INT(a->identity_type, b->identity_type);
|
||||
if (a->identity_type == F1AP_PAGING_IDENTITY_CN_UE) {
|
||||
_EQ_CHECK_LONG(a->identity.cn_ue_paging_identity, b->identity.cn_ue_paging_identity);
|
||||
} else {
|
||||
_EQ_CHECK_LONG(a->identity.ran_ue_paging_identity, b->identity.ran_ue_paging_identity);
|
||||
}
|
||||
_EQ_CHECK_OPTIONAL_IE(a, b, drx, _EQ_CHECK_INT);
|
||||
_EQ_CHECK_OPTIONAL_IE(a, b, priority, _EQ_CHECK_INT);
|
||||
_EQ_CHECK_OPTIONAL_IE(a, b, origin, _EQ_CHECK_INT);
|
||||
_EQ_CHECK_INT(a->n_cells, b->n_cells);
|
||||
if ((a->n_cells > 0 && (a->cells == NULL || b->cells == NULL)))
|
||||
return false;
|
||||
for (int i = 0; i < a->n_cells; i++) {
|
||||
if (!eq_f1ap_plmn(&a->cells[i].plmn, &b->cells[i].plmn))
|
||||
return false;
|
||||
_EQ_CHECK_LONG(a->cells[i].nr_cellid, b->cells[i].nr_cellid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief deep copy F1 Paging */
|
||||
f1ap_paging_t cp_f1ap_paging(const f1ap_paging_t *orig)
|
||||
{
|
||||
DevAssert(orig);
|
||||
f1ap_paging_t cp = {0};
|
||||
cp.ue_identity_index_value = orig->ue_identity_index_value;
|
||||
cp.identity_type = orig->identity_type;
|
||||
cp.identity = orig->identity;
|
||||
if (orig->drx != NULL) {
|
||||
cp.drx = malloc_or_fail(sizeof(*cp.drx));
|
||||
*cp.drx = *orig->drx;
|
||||
}
|
||||
if (orig->priority != NULL) {
|
||||
cp.priority = malloc_or_fail(sizeof(*cp.priority));
|
||||
*cp.priority = *orig->priority;
|
||||
}
|
||||
if (orig->origin != NULL) {
|
||||
cp.origin = malloc_or_fail(sizeof(*cp.origin));
|
||||
*cp.origin = *orig->origin;
|
||||
}
|
||||
cp.n_cells = orig->n_cells;
|
||||
if (cp.n_cells > 0) {
|
||||
DevAssert(orig->cells != NULL);
|
||||
cp.cells = calloc_or_fail(cp.n_cells, sizeof(*cp.cells));
|
||||
for (int i = 0; i < cp.n_cells; i++) {
|
||||
cp.cells[i] = orig->cells[i];
|
||||
}
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 F1AP_PAGING_H_
|
||||
#define F1AP_PAGING_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "f1ap_messages_types.h"
|
||||
|
||||
struct F1AP_F1AP_PDU;
|
||||
|
||||
/* F1 Paging */
|
||||
struct F1AP_F1AP_PDU *encode_f1ap_paging(const f1ap_paging_t *msg);
|
||||
bool decode_f1ap_paging(f1ap_paging_t *out, const struct F1AP_F1AP_PDU *pdu);
|
||||
void free_f1ap_paging(f1ap_paging_t *msg);
|
||||
bool eq_f1ap_paging(const f1ap_paging_t *a, const f1ap_paging_t *b);
|
||||
f1ap_paging_t cp_f1ap_paging(const f1ap_paging_t *orig);
|
||||
|
||||
#endif /* F1AP_PAGING_H_ */
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "lib/f1ap_interface_management.h"
|
||||
#include "lib/f1ap_ue_context.h"
|
||||
#include "lib/f1ap_positioning.h"
|
||||
#include "lib/f1ap_paging.h"
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
@@ -2383,6 +2384,79 @@ static void test_f1ap_positioning_measurement_update()
|
||||
printf("%s() successful\n", __func__);
|
||||
}
|
||||
|
||||
/** @brief Test F1 Paging encode/decode roundtrip and copy operations */
|
||||
static void test_f1ap_paging_rt(f1ap_paging_t *orig)
|
||||
{
|
||||
F1AP_F1AP_PDU_t *f1enc = encode_f1ap_paging(orig);
|
||||
F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc);
|
||||
f1ap_msg_free(f1enc);
|
||||
|
||||
f1ap_paging_t decoded = {0};
|
||||
bool ret = decode_f1ap_paging(&decoded, f1dec);
|
||||
AssertFatal(ret, "decode_f1ap_paging(): could not decode message\n");
|
||||
f1ap_msg_free(f1dec);
|
||||
|
||||
ret = eq_f1ap_paging(orig, &decoded);
|
||||
AssertFatal(ret, "eq_f1ap_paging(): decoded message doesn't match\n");
|
||||
free_f1ap_paging(&decoded);
|
||||
|
||||
f1ap_paging_t cp = cp_f1ap_paging(orig);
|
||||
ret = eq_f1ap_paging(orig, &cp);
|
||||
AssertFatal(ret, "eq_f1ap_paging(): copied message doesn't match\n");
|
||||
free_f1ap_paging(&cp);
|
||||
}
|
||||
|
||||
/** @brief Test F1 Paging encoding/decoding */
|
||||
static void test_f1ap_paging(void)
|
||||
{
|
||||
// Test with CN UE Paging Identity (5G-S-TMSI)
|
||||
{
|
||||
f1ap_paging_t orig = {0};
|
||||
orig.ue_identity_index_value = 123;
|
||||
orig.identity_type = F1AP_PAGING_IDENTITY_CN_UE;
|
||||
orig.identity.cn_ue_paging_identity = 0x1234567890AB;
|
||||
orig.drx = malloc_or_fail(sizeof(*orig.drx));
|
||||
*orig.drx = F1AP_PAGING_DRX_32;
|
||||
orig.n_cells = 2;
|
||||
orig.cells = calloc_or_fail(orig.n_cells, sizeof(*orig.cells));
|
||||
orig.cells[0].plmn.mcc = 208;
|
||||
orig.cells[0].plmn.mnc = 95;
|
||||
orig.cells[0].plmn.mnc_digit_length = 2;
|
||||
orig.cells[0].nr_cellid = 123456;
|
||||
orig.cells[1].plmn.mcc = 208;
|
||||
orig.cells[1].plmn.mnc = 93;
|
||||
orig.cells[1].plmn.mnc_digit_length = 2;
|
||||
orig.cells[1].nr_cellid = 789012;
|
||||
|
||||
test_f1ap_paging_rt(&orig);
|
||||
free_f1ap_paging(&orig);
|
||||
}
|
||||
|
||||
// Test with RAN UE Paging Identity (I-RNTI)
|
||||
{
|
||||
f1ap_paging_t orig = {0};
|
||||
orig.ue_identity_index_value = 456;
|
||||
orig.identity_type = F1AP_PAGING_IDENTITY_RAN_UE;
|
||||
orig.identity.ran_ue_paging_identity = 0x1234567890;
|
||||
orig.drx = NULL;
|
||||
orig.priority = malloc_or_fail(sizeof(*orig.priority));
|
||||
*orig.priority = F1AP_PAGING_PRIO_LEVEL3;
|
||||
orig.origin = malloc_or_fail(sizeof(*orig.origin));
|
||||
*orig.origin = F1AP_PAGING_ORIGIN_NON_3GPP;
|
||||
orig.n_cells = 1;
|
||||
orig.cells = calloc_or_fail(orig.n_cells, sizeof(*orig.cells));
|
||||
orig.cells[0].plmn.mcc = 1;
|
||||
orig.cells[0].plmn.mnc = 1;
|
||||
orig.cells[0].plmn.mnc_digit_length = 2;
|
||||
orig.cells[0].nr_cellid = 987654;
|
||||
|
||||
test_f1ap_paging_rt(&orig);
|
||||
free_f1ap_paging(&orig);
|
||||
}
|
||||
|
||||
printf("%s() successful\n", __func__);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_initial_ul_rrc_message_transfer();
|
||||
@@ -2427,5 +2501,6 @@ int main()
|
||||
test_f1ap_positioning_measurement_abort();
|
||||
test_f1ap_positioning_measurement_failure_indication();
|
||||
test_f1ap_positioning_measurement_update();
|
||||
test_f1ap_paging();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -548,6 +548,18 @@ do { \
|
||||
(bITsTRING)->bits_unused = 0; \
|
||||
} while(0)
|
||||
|
||||
#define IRNTI_TO_BIT_STRING(mACRO, bITsTRING) \
|
||||
do { \
|
||||
(bITsTRING)->buf = calloc(5, sizeof(uint8_t)); \
|
||||
(bITsTRING)->buf[0] = ((mACRO) >> 32) & 0xff; \
|
||||
(bITsTRING)->buf[1] = ((mACRO) >> 24) & 0xff; \
|
||||
(bITsTRING)->buf[2] = ((mACRO) >> 16) & 0xff; \
|
||||
(bITsTRING)->buf[3] = ((mACRO) >> 8) & 0xff; \
|
||||
(bITsTRING)->buf[4] = ((mACRO) & 0xff); \
|
||||
(bITsTRING)->size = 5; \
|
||||
(bITsTRING)->bits_unused = 0; \
|
||||
} while (0)
|
||||
|
||||
/* Used to format an uint32_t containing an ipv4 address */
|
||||
#define IPV4_ADDR "%u.%u.%u.%u"
|
||||
#define IPV4_ADDR_FORMAT(aDDRESS) \
|
||||
|
||||
Reference in New Issue
Block a user