Merge remote-tracking branch 'origin/issue-801' into integration_2025_w23 (!3302)

Enhance UE identity management in Initial UE Message and other NGAP improvements

This MR improves the Initial UE Message procedures by supporting simultaneous
presence of both 5G-S-TMSI and GUAMI. Previously, only one identity could be
used, leading to potential AMF selection failures. Now the presenceMask allows
both identities. The AMF selection is prioritizing GUAMI first, then falling
back to 5G-S-TMSI, and finally using PLMN or highest capacity.

Also, fix handling of selected PLMN identity in NGAP.

Refactoring:
- Select the AMF based on (1) absence of UE Identity (2) Presence of GUAMI
  (3) Presence of 5G-S-TMSI
- Also refactored the AMF selection logic for better readability and reliability.
- Refactor and cleanup rrc_gNB_send_NGAP_NAS_FIRST_REQ
- Replace ngap_pdu_t with byte_array_t
- Add guami_t to ngran_types.h: refactor NGAP and RRC code to use one common
  GUAMI type instead of two identical ones

Also:
- Bugfix in ngap_gNB_handle_ng_setup_response: use correct count for PLMNSupportList

Closes issue #801
This commit is contained in:
Jaroslava Fiedlerova
2025-06-02 16:20:24 +02:00
15 changed files with 390 additions and 405 deletions
+58 -36
View File
@@ -52,15 +52,6 @@
#include "oai_asn1.h"
#include "queue.h"
static void allocCopy(ngap_pdu_t *out, OCTET_STRING_t in)
{
if (in.size) {
out->buffer = malloc(in.size);
memcpy(out->buffer, in.buf, in.size);
}
out->length = in.size;
}
char *ngap_direction2String(int ngap_dir) {
static char *ngap_direction_String[] = {
"", /* Nothing */
@@ -145,6 +136,36 @@ static int ngap_gNB_handle_ng_setup_failure(sctp_assoc_t assoc_id, uint32_t stre
return 0;
}
static void ngap_dump_served_guami(const ngap_gNB_amf_data_t *amf_desc_p)
{
const struct served_guami_s *guami_p;
const struct plmn_identity_s *plmn_p;
const struct served_region_id_s *region_p;
const struct amf_set_id_s *set_id_p;
const struct amf_pointer_s *pointer_p;
NGAP_DEBUG("Served GUAMIs for AMF %s (assoc_id=%d):\n",
amf_desc_p->amf_name ? amf_desc_p->amf_name : "(no name)",
amf_desc_p->assoc_id);
STAILQ_FOREACH(guami_p, &amf_desc_p->served_guami, next)
{
NGAP_DEBUG(" GUAMI:\n");
STAILQ_FOREACH(plmn_p, &guami_p->served_plmns, next) {
NGAP_DEBUG(" PLMN: MCC=%03d, MNC=%0*d\n", plmn_p->mcc, plmn_p->mnc_digit_length, plmn_p->mnc);
}
STAILQ_FOREACH(region_p, &guami_p->served_region_ids, next) {
NGAP_DEBUG(" AMF Region ID: %d\n", region_p->amf_region_id);
}
STAILQ_FOREACH(set_id_p, &guami_p->amf_set_ids, next) {
NGAP_DEBUG(" AMF Set ID: %d\n", set_id_p->amf_set_id);
}
STAILQ_FOREACH(pointer_p, &guami_p->amf_pointers, next) {
NGAP_DEBUG(" AMF Pointer: %d\n", pointer_p->amf_pointer);
}
}
}
static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu)
{
NGAP_NGSetupResponse_t *container;
@@ -173,7 +194,6 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str
/* The list of served guami can contain at most 256 elements.
* NR related guami is the first element in the list, i.e with an id of 0.
*/
NGAP_DEBUG("servedGUAMIs.list.count %d\n", ie->value.choice.ServedGUAMIList.list.count);
DevAssert(ie->value.choice.ServedGUAMIList.list.count > 0);
DevAssert(ie->value.choice.ServedGUAMIList.list.count <= NGAP_maxnoofServedGUAMIs);
@@ -197,32 +217,27 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str
STAILQ_INSERT_TAIL(&new_guami_p->served_plmns, new_plmn_identity_p, next);
new_guami_p->nb_served_plmns++;
NGAP_AMFRegionID_t *amf_region_id_p;
struct served_region_id_s *new_region_id_p;
amf_region_id_p = &guami_item_p->gUAMI.aMFRegionID;
new_region_id_p = calloc(1, sizeof(struct served_region_id_s));
OCTET_STRING_TO_INT8(amf_region_id_p, new_region_id_p->amf_region_id);
new_region_id_p->amf_region_id = BIT_STRING_to_uint8(&guami_item_p->gUAMI.aMFRegionID);
STAILQ_INSERT_TAIL(&new_guami_p->served_region_ids, new_region_id_p, next);
new_guami_p->nb_region_id++;
NGAP_AMFSetID_t *amf_set_id_p;
struct amf_set_id_s *new_amf_set_id_p;
amf_set_id_p = &guami_item_p->gUAMI.aMFSetID;
new_amf_set_id_p = calloc(1, sizeof(struct amf_set_id_s));
OCTET_STRING_TO_INT16(amf_set_id_p, new_amf_set_id_p->amf_set_id);
new_amf_set_id_p->amf_set_id = BIT_STRING_to_uint16(&guami_item_p->gUAMI.aMFSetID);
STAILQ_INSERT_TAIL(&new_guami_p->amf_set_ids, new_amf_set_id_p, next);
new_guami_p->nb_amf_set_id++;
NGAP_AMFPointer_t *amf_pointer_p;
struct amf_pointer_s *new_amf_pointer_p;
amf_pointer_p = &guami_item_p->gUAMI.aMFPointer;
new_amf_pointer_p = calloc(1, sizeof(struct amf_pointer_s));
OCTET_STRING_TO_INT8(amf_pointer_p, new_amf_pointer_p->amf_pointer);
new_amf_pointer_p->amf_pointer = BIT_STRING_to_uint8(&guami_item_p->gUAMI.aMFPointer);
STAILQ_INSERT_TAIL(&new_guami_p->amf_pointers, new_amf_pointer_p, next);
new_guami_p->nb_amf_pointer++;
STAILQ_INSERT_TAIL(&amf_desc_p->served_guami, new_guami_p, next);
}
ngap_dump_served_guami(amf_desc_p);
/* Set the capacity of this AMF */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_NGSetupResponseIEs_t, ie, container,
@@ -245,13 +260,12 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_NGSetupResponseIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_PLMNSupportList, true);
NGAP_DEBUG("PLMNSupportList.list.count %d\n", ie->value.choice.PLMNSupportList.list.count);
DevAssert(ie->value.choice.PLMNSupportList.list.count > 0);
DevAssert(ie->value.choice.PLMNSupportList.list.count <= NGAP_maxnoofPLMNs);
STAILQ_INIT(&amf_desc_p->plmn_supports);
for (i = 0; i < ie->value.choice.ServedGUAMIList.list.count; i++) {
for (i = 0; i < ie->value.choice.PLMNSupportList.list.count; i++) {
NGAP_PLMNSupportItem_t *plmn_support_item_p;
struct plmn_support_s *new_plmn_support_p;
NGAP_SliceSupportItem_t *slice_support_item_p;
@@ -260,11 +274,10 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str
plmn_support_item_p = ie->value.choice.PLMNSupportList.list.array[i];
new_plmn_support_p = calloc(1, sizeof(struct plmn_support_s));
TBCD_TO_MCC_MNC(&plmn_support_item_p->pLMNIdentity, new_plmn_support_p->plmn_identity.mcc,
new_plmn_support_p->plmn_identity.mnc, new_plmn_support_p->plmn_identity.mnc_digit_length);
NGAP_DEBUG("PLMNSupportList.list.count %d\n", plmn_support_item_p->sliceSupportList.list.count);
struct plmn_identity_s *plmn = &new_plmn_support_p->plmn_identity;
TBCD_TO_MCC_MNC(&plmn_support_item_p->pLMNIdentity, plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
NGAP_INFO("Supported PLMN %d: MCC=%03d MNC=%0*d\n", i, plmn->mcc, plmn->mnc_digit_length, plmn->mnc);
DevAssert(plmn_support_item_p->sliceSupportList.list.count > 0);
DevAssert(plmn_support_item_p->sliceSupportList.list.count <= NGAP_maxnoofSliceItems);
@@ -282,6 +295,12 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str
new_slice_support_p->sD[1] = slice_support_item_p->s_NSSAI.sD->buf[1];
new_slice_support_p->sD[2] = slice_support_item_p->s_NSSAI.sD->buf[2];
}
NGAP_INFO("Supported slice (PLMN %d): SST=0x%02x SD=%d%d%d\n",
i,
new_slice_support_p->sST,
new_slice_support_p->sD[0],
new_slice_support_p->sD[1],
new_slice_support_p->sD[2]);
STAILQ_INSERT_TAIL(&new_plmn_support_p->slice_supports, new_slice_support_p, next);
}
@@ -772,9 +791,10 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32
}
if (item_p->nAS_PDU) {
allocCopy(&msg->pdusession_param[i].nas_pdu, *item_p->nAS_PDU);
msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf);
}
allocCopy(&msg->pdusession_param[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer);
OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer;
msg->pdusession_param[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf);
}
}
@@ -841,7 +861,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32
NGAP_ProtocolIE_ID_id_NAS_PDU, false);
if (ie)
allocCopy(&msg->nas_pdu, ie->value.choice.NAS_PDU);
msg->nas_pdu = create_byte_array(ie->value.choice.NAS_PDU.size, ie->value.choice.NAS_PDU.buf);
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
@@ -985,9 +1005,9 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3
} else {
msg->pdusession_setup_params[i].nssai.sd = 0xffffff;
}
allocCopy(&msg->pdusession_setup_params[i].nas_pdu, *item_p->pDUSessionNAS_PDU);
allocCopy(&msg->pdusession_setup_params[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer);
OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer;
msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf);
msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf);
}
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
@@ -1164,8 +1184,9 @@ static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint
// check for the NAS PDU
if (item_p->nAS_PDU != NULL && item_p->nAS_PDU->size > 0) {
allocCopy(&msg->pdusession_modify_params[i].nas_pdu, *item_p->nAS_PDU);
allocCopy(&msg->pdusession_modify_params[i].pdusessionTransfer, item_p->pDUSessionResourceModifyRequestTransfer);
msg->pdusession_modify_params[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf);
OCTET_STRING_t *transfer = &item_p->pDUSessionResourceModifyRequestTransfer;
msg->pdusession_modify_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf);
} else {
LOG_W(NGAP, "received pdu session modify with void content for UE %u, pdu session %lu\n", msg->gNB_ue_ngap_id, item_p->pDUSessionID);
continue;
@@ -1241,7 +1262,7 @@ static int ngap_gNB_handle_pdusession_release_command(sctp_assoc_t assoc_id, uin
NGAP_ProtocolIE_ID_id_NAS_PDU, false);
if (ie)
allocCopy(&msg->nas_pdu, ie->value.choice.NAS_PDU);
msg->nas_pdu = create_byte_array(ie->value.choice.NAS_PDU.size, ie->value.choice.NAS_PDU.buf);
/* id-PDUSessionResourceToReleaseListRelCmd */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceReleaseCommandIEs_t, ie, container,
@@ -1252,8 +1273,9 @@ static int ngap_gNB_handle_pdusession_release_command(sctp_assoc_t assoc_id, uin
for (i = 0; i < ie->value.choice.PDUSessionResourceToReleaseListRelCmd.list.count; i++) {
NGAP_PDUSessionResourceToReleaseItemRelCmd_t *item_p;
item_p = ie->value.choice.PDUSessionResourceToReleaseListRelCmd.list.array[i];
msg->pdusession_release_params[i].pdusession_id = item_p->pDUSessionID;
allocCopy(&msg->pdusession_release_params[i].data, item_p->pDUSessionResourceReleaseCommandTransfer);
pdusession_release_t *r = &msg->pdusession_release_params[i];
r->pdusession_id = item_p->pDUSessionID;
r->data = create_byte_array(item_p->pDUSessionResourceReleaseCommandTransfer.size, item_p->pDUSessionResourceReleaseCommandTransfer.buf);
}
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
+1 -3
View File
@@ -64,9 +64,7 @@ void ngap_gNB_itti_send_nas_downlink_ind(instance_t instance, uint32_t gNB_ue_ng
ngap_downlink_nas = &message_p->ittiMsg.ngap_downlink_nas;
ngap_downlink_nas->gNB_ue_ngap_id = gNB_ue_ngap_id;
ngap_downlink_nas->nas_pdu.buffer = malloc(sizeof(uint8_t) * nas_pdu_length);
memcpy(ngap_downlink_nas->nas_pdu.buffer, nas_pdu, nas_pdu_length);
ngap_downlink_nas->nas_pdu.length = nas_pdu_length;
ngap_downlink_nas->nas_pdu = create_byte_array(nas_pdu_length, nas_pdu);
itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p);
}
@@ -38,6 +38,7 @@
#include "ngap_gNB_defs.h"
#include "queue.h"
#include "tree.h"
#include "ds/byte_array.h"
static ngap_gNB_internal_data_t ngap_gNB_internal_data;
@@ -28,6 +28,8 @@
* @ingroup _ngap
*/
#include "ds/byte_array.h"
#ifndef NGAP_GNB_MANAGEMENT_PROCEDURES_H_
#define NGAP_GNB_MANAGEMENT_PROCEDURES_H_
+136 -151
View File
@@ -58,15 +58,6 @@
#include "s1ap_messages_types.h"
#include "xer_encoder.h"
static void allocCopy(OCTET_STRING_t *out, ngap_pdu_t in)
{
if (in.length) {
out->buf = malloc(in.length);
memcpy(out->buf, in.buffer, in.length);
}
out->size = in.length;
}
static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in)
{
if (in.length) {
@@ -77,20 +68,106 @@ static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in)
}
}
//------------------------------------------------------------------------------
int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEfirstReq)
//------------------------------------------------------------------------------
/** @brief Selects the AMF instance for a given UE based on identity information.
* It attempts to select an AMF using the following prioritized criteria:
* 1. GUAMI, if provided and valid (via Region ID, Set ID, Pointer).
* 2. 5G-S-TMSI, using AMF Set ID if GUAMI is unavailable or unusable.
* 3. Selected PLMN identity and local PLMN configuration.
* 4. Fallback to AMF with highest relative capacity, considering load balancing.
* @ref AMF Discovery and Selection (3GPP TS 23.501 clause 6.3.5) */
static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ngap_nas_first_req_t *msg)
{
ngap_gNB_instance_t *instance_p = NULL;
struct ngap_gNB_amf_data_s *amf_desc_p = NULL;
NGAP_NGAP_PDU_t pdu;
uint8_t *buffer = NULL;
uint32_t length = 0;
ngap_gNB_amf_data_t *amf = NULL;
// Select the AMF corresponding to the GUAMI from the RegisteredAMF IE
if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_guami) {
const nr_guami_t *guami = &msg->ue_identity.guami;
NGAP_DEBUG("GUAMI is present: MCC=%03d MNC=%03d RegionID=%d SetID=%d Pointer=%d\n",
guami->mcc,
guami->mnc,
guami->amf_region_id,
guami->amf_set_id,
guami->amf_pointer);
amf = ngap_gNB_nnsf_select_amf_by_guami(instance_p, msg->establishment_cause, *guami);
if (amf) {
NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n",
msg->gNB_ue_ngap_id,
amf->amf_name,
amf->assoc_id,
guami->mcc,
guami->mnc,
guami->amf_region_id,
guami->amf_set_id,
guami->amf_pointer);
return amf;
}
}
// Select the AMF corresponding to the provided 5G-S-TMSI
if (amf == NULL) {
if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) {
const fiveg_s_tmsi_t *fgs_tmsi = &msg->ue_identity.s_tmsi;
amf = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, msg->establishment_cause, msg->plmn, fgs_tmsi->amf_set_id);
if (amf) {
NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN MCC %d MNC %d\n",
msg->gNB_ue_ngap_id,
amf->amf_name,
amf->assoc_id,
fgs_tmsi->amf_set_id,
msg->plmn.mcc,
msg->plmn.mnc);
return amf;
}
}
}
// No UE identity (5G-S-TMSI or GUAMI) is present
if (msg->ue_identity.presenceMask == 0) {
// Select the AMF based on the selected PLMN identity received through RRCSetupComplete
amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->plmn);
if (amf) {
NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN MCC %d MNC %d\n",
msg->gNB_ue_ngap_id,
amf->amf_name,
amf->assoc_id,
msg->plmn.mcc,
msg->plmn.mnc);
return amf;
} else {
// Select the AMF with the highest capacity
amf = ngap_gNB_nnsf_select_amf(instance_p, msg->establishment_cause);
if (amf) {
NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id);
return amf;
}
}
}
return amf;
}
/** @brief NAS Transport Messages: Initial UE Message
* forward the first received (layer 3) uplink NAS message
* from the radio interface to the AMF over N2
* NG-RAN node -> AMF (9.2.5.1, 3GPP TS 38.413) */
int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEfirstReq)
{
NGAP_NGAP_PDU_t pdu = {0};
uint8_t *buffer = NULL;
uint32_t length = 0;
DevAssert(UEfirstReq != NULL);
/* Retrieve the NGAP gNB instance associated with Mod_id */
instance_p = ngap_gNB_get_instance(instance);
ngap_gNB_instance_t *instance_p = ngap_gNB_get_instance(instance);
DevAssert(instance_p != NULL);
memset(&pdu, 0, sizeof(pdu));
// AMF selection from the Initial UE message contents
struct ngap_gNB_amf_data_s *amf = select_amf(instance_p, UEfirstReq);
if (amf == NULL) {
NGAP_WARN("No AMF is associated to the gNB\n");
return -1;
}
// Message Type (M)
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
asn1cCalloc(pdu.choice.initiatingMessage, head);
head->procedureCode = NGAP_ProcedureCode_id_InitialUEMessage;
@@ -98,98 +175,18 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf
head->value.present = NGAP_InitiatingMessage__value_PR_InitialUEMessage;
NGAP_InitialUEMessage_t *out = &head->value.choice.InitialUEMessage;
/* Select the AMF corresponding to the provided GUAMI. */
//TODO have not be test. it's should be test
if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_guami) {
amf_desc_p = ngap_gNB_nnsf_select_amf_by_guami(instance_p, UEfirstReq->establishment_cause, UEfirstReq->ue_identity.guami);
if (amf_desc_p) {
NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n",
UEfirstReq->gNB_ue_ngap_id,
amf_desc_p->amf_name,
amf_desc_p->assoc_id,
UEfirstReq->ue_identity.guami.mcc,
UEfirstReq->ue_identity.guami.mnc,
UEfirstReq->ue_identity.guami.amf_region_id,
UEfirstReq->ue_identity.guami.amf_set_id,
UEfirstReq->ue_identity.guami.amf_pointer);
}
}
if (amf_desc_p == NULL) {
/* Select the AMF corresponding to the provided s-TMSI. */
//TODO have not be test. it's should be test
if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) {
amf_desc_p = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, UEfirstReq->establishment_cause, UEfirstReq->selected_plmn_identity, UEfirstReq->ue_identity.s_tmsi.amf_set_id);
if (amf_desc_p) {
NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n",
UEfirstReq->gNB_ue_ngap_id,
amf_desc_p->amf_name,
amf_desc_p->assoc_id,
UEfirstReq->ue_identity.s_tmsi.amf_set_id,
UEfirstReq->selected_plmn_identity,
instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mcc,
instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mnc);
}
}
}
if (amf_desc_p == NULL) {
/* Select AMF based on the selected PLMN identity, received through RRC
* Connection Setup Complete */
//TODO have not be test. it's should be test
amf_desc_p = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, UEfirstReq->establishment_cause, UEfirstReq->selected_plmn_identity);
if (amf_desc_p) {
NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n",
UEfirstReq->gNB_ue_ngap_id,
amf_desc_p->amf_name,
amf_desc_p->assoc_id,
UEfirstReq->selected_plmn_identity,
instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mcc,
instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mnc);
}
}
if (amf_desc_p == NULL) {
/*
* If no AMF corresponds to the GUAMI, the s-TMSI, or the selected PLMN
* identity, selects the AMF with the highest capacity.
*/
//TODO have not be test. it's should be test
amf_desc_p = ngap_gNB_nnsf_select_amf(instance_p, UEfirstReq->establishment_cause);
if (amf_desc_p) {
NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", UEfirstReq->gNB_ue_ngap_id, amf_desc_p->amf_name, amf_desc_p->assoc_id);
}
}
if (amf_desc_p == NULL) {
/*
* In case gNB has no AMF associated, the gNB should inform RRC and discard
* this request.
*/
NGAP_WARN("No AMF is associated to the gNB\n");
// TODO: Inform RRC
return -1;
}
/* The gNB should allocate a unique gNB UE NGAP ID for this UE. The value
* will be used for the duration of the connectivity.
*/
struct ngap_gNB_ue_context_s *ue_desc_p = calloc(1, sizeof(*ue_desc_p));
/* Store the UE context in NGAP with:
* selected AMF, selected PLMN identity, gNB ID
* the unique gNB UE NGAP ID, used for the duration of the connectivity */
struct ngap_gNB_ue_context_s *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p));
DevAssert(ue_desc_p != NULL);
/* Keep a reference to the selected AMF */
ue_desc_p->amf_ref = amf_desc_p;
ue_desc_p->amf_ref = amf;
ue_desc_p->gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id;
ue_desc_p->gNB_instance = instance_p;
ue_desc_p->selected_plmn_identity = UEfirstReq->selected_plmn_identity;
// insert in master table
ue_desc_p->selected_plmn_identity = UEfirstReq->plmn;
ngap_store_ue_context(ue_desc_p);
/* mandatory */
// RAN UE NGAP ID (M)
{
asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie);
ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID;
@@ -197,47 +194,43 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_RAN_UE_NGAP_ID;
ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p->gNB_ue_ngap_id;
}
/* mandatory */
/* NAS-PDU (M): transferred transparently */
{
asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie);
ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_NAS_PDU;
allocCopy(&ie->value.choice.NAS_PDU, UEfirstReq->nas_pdu);
OCTET_STRING_fromBuf(&ie->value.choice.NAS_PDU, (const char *)UEfirstReq->nas_pdu.buf, UEfirstReq->nas_pdu.len);
}
/* mandatory */
// User Location Information (M)
{
asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie);
ie->id = NGAP_ProtocolIE_ID_id_UserLocationInformation;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_UserLocationInformation;
ie->value.choice.UserLocationInformation.present = NGAP_UserLocationInformation_PR_userLocationInformationNR;
asn1cCalloc(ie->value.choice.UserLocationInformation.choice.userLocationInformationNR, userinfo_nr_p);
/* Set nRCellIdentity. default userLocationInformationNR */
MACRO_GNB_ID_TO_CELL_IDENTITY(instance_p->gNB_id,
0, // Cell ID
&userinfo_nr_p->nR_CGI.nRCellIdentity);
MCC_MNC_TO_TBCD(instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mcc,
instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc,
instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc_digit_length,
&userinfo_nr_p->nR_CGI.pLMNIdentity);
/* Set TAI */
plmn_id_t *plmn = &ue_desc_p->selected_plmn_identity;
MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity);
/* In case of network sharing,
the selected PLMN is indicated by the PLMN Identity IE within the TAI IE */
INT24_TO_OCTET_STRING(instance_p->tac, &userinfo_nr_p->tAI.tAC);
MCC_MNC_TO_PLMNID(instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mcc,
instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc,
instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc_digit_length,
&userinfo_nr_p->tAI.pLMNIdentity);
MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity);
}
/* Set the establishment cause according to those provided by RRC */
DevCheck(UEfirstReq->establishment_cause < NGAP_RRC_CAUSE_LAST, UEfirstReq->establishment_cause, NGAP_RRC_CAUSE_LAST, 0);
/* mandatory */
// RRC Establishment Cause (M)
{
asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie);
ie->id = NGAP_ProtocolIE_ID_id_RRCEstablishmentCause;
@@ -246,7 +239,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf
ie->value.choice.RRCEstablishmentCause = UEfirstReq->establishment_cause;
}
/* optional */
// 5G-S-TMSI (O)
if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) {
NGAP_DEBUG("FIVEG_S_TMSI_PRESENT\n");
asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie);
@@ -258,7 +251,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf
M_TMSI_TO_OCTET_STRING(UEfirstReq->ue_identity.s_tmsi.m_tmsi, &ie->value.choice.FiveG_S_TMSI.fiveG_TMSI);
}
/* optional */
/* UE Context Request (O): instruct the AMF to trigger an
Initial Context Setup procedure towards the NG-RAN node. */
{
asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie);
ie->id = NGAP_ProtocolIE_ID_id_UEContextRequest;
@@ -267,10 +261,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf
ie->value.choice.UEContextRequest = NGAP_UEContextRequest_requested;
}
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
/* Failed to encode message */
DevMessage("Failed to encode initial UE message\n");
}
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0)
DevMessage("Failed to encode initial UE message\n");
/* Update the current NGAP UE state */
ue_desc_p->ue_state = NGAP_UE_WAITING_CSR;
@@ -286,16 +278,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf
* the stream should not be changed during the communication of the
* UE-associated signalling.
*/
amf_desc_p->nextstream = (amf_desc_p->nextstream + 1) % amf_desc_p->out_streams;
if ((amf_desc_p->nextstream == 0) && (amf_desc_p->out_streams > 1)) {
amf_desc_p->nextstream += 1;
amf->nextstream = (amf->nextstream + 1) % amf->out_streams;
if ((amf->nextstream == 0) && (amf->out_streams > 1)) {
amf->nextstream += 1;
}
ue_desc_p->tx_stream = amf_desc_p->nextstream;
ue_desc_p->tx_stream = amf->nextstream;
/* Send encoded message over sctp */
ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf_desc_p->assoc_id,
buffer, length, ue_desc_p->tx_stream);
ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p->tx_stream);
return 0;
}
@@ -436,8 +425,8 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_
ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UplinkNASTransport_IEs__value_PR_NAS_PDU;
ie->value.choice.NAS_PDU.buf = ngap_uplink_nas_p->nas_pdu.buffer;
ie->value.choice.NAS_PDU.size = ngap_uplink_nas_p->nas_pdu.length;
ie->value.choice.NAS_PDU.buf = ngap_uplink_nas_p->nas_pdu.buf;
ie->value.choice.NAS_PDU.size = ngap_uplink_nas_p->nas_pdu.len;
}
/* mandatory */
{
@@ -453,17 +442,12 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_
MACRO_GNB_ID_TO_CELL_IDENTITY(ngap_gNB_instance_p->gNB_id,
0, // Cell ID
&userinfo_nr_p->nR_CGI.nRCellIdentity);
MCC_MNC_TO_TBCD(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mcc,
ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc,
ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc_digit_length,
&userinfo_nr_p->nR_CGI.pLMNIdentity);
plmn_id_t *plmn = &ue_context_p->selected_plmn_identity;
MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity);
/* Set TAI */
INT24_TO_OCTET_STRING(ngap_gNB_instance_p->tac, &userinfo_nr_p->tAI.tAC);
MCC_MNC_TO_PLMNID(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mcc,
ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc,
ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc_digit_length,
&userinfo_nr_p->tAI.pLMNIdentity);
MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity);
}
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
NGAP_ERROR("Failed to encode uplink NAS transport\n");
@@ -532,8 +516,8 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance,
ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_NASNonDeliveryIndication_IEs__value_PR_NAS_PDU;
ie->value.choice.NAS_PDU.buf = ngap_nas_non_delivery_ind->nas_pdu.buffer;
ie->value.choice.NAS_PDU.size = ngap_nas_non_delivery_ind->nas_pdu.length;
ie->value.choice.NAS_PDU.buf = ngap_nas_non_delivery_ind->nas_pdu.buf;
ie->value.choice.NAS_PDU.size = ngap_nas_non_delivery_ind->nas_pdu.len;
}
/* mandatory */
{
@@ -861,8 +845,8 @@ int ngap_gNB_ue_capabilities(instance_t instance, ngap_ue_cap_info_ind_t *ue_cap
ie->id = NGAP_ProtocolIE_ID_id_UERadioCapability;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_UERadioCapabilityInfoIndicationIEs__value_PR_UERadioCapability;
ie->value.choice.UERadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer;
ie->value.choice.UERadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length;
ie->value.choice.UERadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buf;
ie->value.choice.UERadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.len;
}
/* optional */
//NGAP_UERadioCapabilityForPaging TBD
@@ -1224,8 +1208,9 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas
for (i = 0; i < pdusession_release_resp_p->nb_of_pdusessions_released; i++) {
asn1cSequenceAdd(ie->value.choice.PDUSessionResourceReleasedListRelRes.list, NGAP_PDUSessionResourceReleasedItemRelRes_t, item);
item->pDUSessionID = pdusession_release_resp_p->pdusession_release[i].pdusession_id;
allocCopy(&item->pDUSessionResourceReleaseResponseTransfer, pdusession_release_resp_p->pdusession_release[i].data);
pdusession_release_t *r = &pdusession_release_resp_p->pdusession_release[i];
item->pDUSessionID = r->pdusession_id;
OCTET_STRING_fromBuf(&item->pDUSessionResourceReleaseResponseTransfer, (const char *)r->data.buf, r->data.len);
NGAP_DEBUG("pdusession_release_resp: pdusession ID %ld\n", item->pDUSessionID);
}
}
+14 -24
View File
@@ -33,9 +33,7 @@
#include "queue.h"
#include "tree.h"
struct ngap_gNB_amf_data_s *
ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p,
ngap_rrc_establishment_cause_t cause)
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause)
{
struct ngap_gNB_amf_data_s *amf_data_p = NULL;
struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL;
@@ -86,10 +84,9 @@ ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p,
return amf_highest_capacity_p;
}
struct ngap_gNB_amf_data_s *
ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p,
ngap_rrc_establishment_cause_t cause,
int selected_plmn_identity)
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p,
const ngap_rrc_establishment_cause_t cause,
const plmn_id_t selected_plmn_identity)
{
struct ngap_gNB_amf_data_s *amf_data_p = NULL;
struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL;
@@ -135,8 +132,7 @@ ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p,
/* Looking for served GUAMI PLMN Identity selected matching the one provided by the UE */
STAILQ_FOREACH(guami_p, &amf_data_p->served_guami, next) {
STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) {
if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].plmn.mcc)
&& (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].plmn.mnc)) {
if ((served_plmn_p->mcc == selected_plmn_identity.mcc) && (served_plmn_p->mnc == selected_plmn_identity.mnc)) {
break;
}
}
@@ -156,11 +152,10 @@ ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p,
return amf_highest_capacity_p;
}
struct ngap_gNB_amf_data_s *
ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p,
ngap_rrc_establishment_cause_t cause,
int selected_plmn_identity,
uint8_t amf_setid)
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p,
const ngap_rrc_establishment_cause_t cause,
const plmn_id_t selected_plmn_identity,
uint8_t amf_setid)
{
struct ngap_gNB_amf_data_s *amf_data_p = NULL;
@@ -207,8 +202,7 @@ ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p,
struct plmn_identity_s *served_plmn_p = NULL;
STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) {
if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].plmn.mcc)
&& (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].plmn.mnc)) {
if ((served_plmn_p->mcc == selected_plmn_identity.mcc) && (served_plmn_p->mnc == selected_plmn_identity.mnc)) {
break;
}
}
@@ -234,10 +228,9 @@ ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p,
return NULL;
}
struct ngap_gNB_amf_data_s *
ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p,
ngap_rrc_establishment_cause_t cause,
ngap_guami_t guami)
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p,
const ngap_rrc_establishment_cause_t cause,
const nr_guami_t guami)
{
struct ngap_gNB_amf_data_s *amf_data_p = NULL;
@@ -327,10 +320,7 @@ ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p,
return NULL;
}
struct ngap_gNB_amf_data_s *
ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p,
ngap_guami_t guami)
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, const nr_guami_t guami)
{
struct ngap_gNB_amf_data_s *amf_data_p = NULL;
struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL;
+12 -19
View File
@@ -34,28 +34,21 @@
#include "ngap_gNB_defs.h"
#include "ngap_messages_types.h"
struct ngap_gNB_amf_data_s *
ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p,
ngap_rrc_establishment_cause_t cause);
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause);
struct ngap_gNB_amf_data_s *
ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p,
ngap_rrc_establishment_cause_t cause,
int selected_plmn_identity);
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p,
const ngap_rrc_establishment_cause_t cause,
const plmn_id_t selected_plmn_identity);
struct ngap_gNB_amf_data_s*
ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p,
ngap_rrc_establishment_cause_t cause,
int selected_plmn_identity,
uint8_t amf_setid);
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p,
const ngap_rrc_establishment_cause_t cause,
const plmn_id_t selected_plmn_identity,
uint8_t amf_setid);
struct ngap_gNB_amf_data_s*
ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p,
ngap_rrc_establishment_cause_t cause,
ngap_guami_t guami);
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p,
const ngap_rrc_establishment_cause_t cause,
const nr_guami_t guami);
struct ngap_gNB_amf_data_s*
ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p,
ngap_guami_t guami);
ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, const nr_guami_t guami);
#endif /* NGAP_GNB_NNSF_H_ */
+1 -1
View File
@@ -72,7 +72,7 @@ typedef struct ngap_gNB_ue_context_s {
/* Signaled by the UE in RRC Connection Setup Complete and used in NAS Uplink
* to route NAS messages correctly. 0-based, not 1-based as in TS 36.331
* 6.2.2 RRC Connection Setup Complete! */
int selected_plmn_identity;
plmn_id_t selected_plmn_identity;
/* Reference to gNB data this UE is attached to */
ngap_gNB_instance_t *gNB_instance;