Refactor registration accept decoding
previously we had decodeRegistrationAccept acting as a handler and calling decode_registration_accept to do the decoding. However the logic was mixed between the two functions, the naming was confusing and the code was hard understand. The goal of this commit is to simplify the code, improve readability and maintainability, while adapting the relevant function to the new OAI NAS libs structure. To this purpose: * move enc/dec logic to NAS lib openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c - the logic of parse_allowed_nssai, get_allowed_nssai has been moved to decode_registration_accept and decode_nssai_ie * add decode_nssai_ie and use it for both Allowed/Configured NSSAIs list (IE handling was added) * do processing in the handler handle_registration_accept * simplify the code by removing nested calls * improve handling of PDU length Currently only Registration Result, 5GS Mobile Identity, Allowed/Configured NSSAI are decoded. The other optional IEIs are skipped (only the length is processed).
This commit is contained in:
@@ -32,37 +32,116 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "conversions.h"
|
||||
#include "TLVEncoder.h"
|
||||
#include "TLVDecoder.h"
|
||||
#include "RegistrationAccept.h"
|
||||
#include "assertions.h"
|
||||
#include "fgs_nas_utils.h"
|
||||
|
||||
#define IEI_5G_GUTI 0x77
|
||||
|
||||
/**
|
||||
* @brief Allowed NSSAI from Registration Accept according to 3GPP TS 24.501 Table 8.2.7.1.1
|
||||
*/
|
||||
static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf)
|
||||
{
|
||||
const int length = *buf; // Length of S-NSSAI IE contents (list of S-NSSAIs)
|
||||
const uint32_t decoded = length + 1; // Length IE (1 octet)
|
||||
buf++;
|
||||
int nssai_cnt = 0;
|
||||
const uint8_t *end = buf + length;
|
||||
while (buf < end) {
|
||||
nr_nas_msg_snssai_t *item = nssai + nssai_cnt;
|
||||
item->sd = 0xffffff;
|
||||
const int item_len = *buf++; // Length of S-NSSAI IE item
|
||||
switch (item_len) {
|
||||
case 1:
|
||||
item->sst = *buf++;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
item->sst = *buf++;
|
||||
item->hplmn_sst = *buf++;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
item->sst = *buf++;
|
||||
item->sd = 0xffffff & ntoh_int24_buf(buf);
|
||||
buf += 3;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
item->sst = *buf++;
|
||||
item->sd = 0xffffff & ntoh_int24_buf(buf);
|
||||
buf += 3;
|
||||
item->hplmn_sst = *buf++;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
item->sst = *buf++;
|
||||
item->sd = 0xffffff & ntoh_int24_buf(buf);
|
||||
buf += 3;
|
||||
item->hplmn_sst = *buf++;
|
||||
item->hplmn_sd = 0xffffff & ntoh_int24_buf(buf);
|
||||
buf += 3;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINT_NAS_ERROR("Unknown length in Allowed S-NSSAI list item\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
int decode_registration_accept(registration_accept_msg *registration_accept, const uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
uint32_t decoded = 0;
|
||||
int decoded_result = 0;
|
||||
int dec = 0;
|
||||
const uint8_t *end = buffer + len;
|
||||
|
||||
/* Decoding mandatory fields */
|
||||
if ((decoded_result =
|
||||
decode_fgs_registration_result(®istration_accept->fgsregistrationresult, 0, *(buffer + decoded), len - decoded))
|
||||
< 0)
|
||||
return decoded_result;
|
||||
if ((dec = decode_fgs_registration_result(®istration_accept->fgsregistrationresult, 0, *buffer, len)) < 0)
|
||||
return dec;
|
||||
buffer += dec;
|
||||
|
||||
decoded += decoded_result;
|
||||
|
||||
if (decoded < len && buffer[decoded] == 0x77) {
|
||||
registration_accept->guti = calloc(1, sizeof(*registration_accept->guti));
|
||||
if (!registration_accept->guti)
|
||||
if (buffer < end && *buffer == IEI_5G_GUTI) {
|
||||
registration_accept->guti = calloc_or_fail(1, sizeof(*registration_accept->guti));
|
||||
if ((dec = decode_5gs_mobile_identity(registration_accept->guti, IEI_5G_GUTI, buffer, end - buffer)) < 0) {
|
||||
PRINT_NAS_ERROR("Failed to decode 5GS Mobile Identity in Registration Accept\n");
|
||||
return -1;
|
||||
int mi_dec = decode_5gs_mobile_identity(registration_accept->guti, 0x77, buffer + decoded, len - decoded);
|
||||
if (mi_dec < 0)
|
||||
return -1;
|
||||
decoded += mi_dec;
|
||||
}
|
||||
buffer += dec;
|
||||
}
|
||||
|
||||
// todo ,Decoding optional fields
|
||||
return decoded;
|
||||
// Allowed NSSAI (O)
|
||||
/* Optional Presence IEs */
|
||||
while (buffer < end) {
|
||||
const int iei = *buffer++;
|
||||
switch (iei) {
|
||||
|
||||
case 0x15: // allowed NSSAI
|
||||
dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, buffer);
|
||||
buffer += dec;
|
||||
break;
|
||||
|
||||
case 0x31: // configured NSSAI
|
||||
dec = decode_nssai_ie(registration_accept->config_nssai, buffer);
|
||||
buffer += dec;
|
||||
break;
|
||||
|
||||
default:
|
||||
dec = *buffer++; // content length + 1 byte (Length IE)
|
||||
buffer += dec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int encode_registration_accept(const registration_accept_msg *registration_accept, uint8_t *buffer, uint32_t len)
|
||||
|
||||
@@ -40,6 +40,14 @@
|
||||
#ifndef REGISTRATION_ACCEPT_H_
|
||||
#define REGISTRATION_ACCEPT_H_
|
||||
|
||||
// 9.11.3.37 of 3GPP TS 24.501
|
||||
typedef struct {
|
||||
int sst;
|
||||
int hplmn_sst;
|
||||
int sd;
|
||||
int hplmn_sd;
|
||||
} nr_nas_msg_snssai_t;
|
||||
|
||||
/*
|
||||
* Message name: Registration accept
|
||||
* Description: The REGISTRATION ACCEPT message is sent by the AMF to the UE. See table 8.2.7.1.1.
|
||||
@@ -52,6 +60,10 @@ typedef struct registration_accept_msg_tag {
|
||||
FGSRegistrationResult fgsregistrationresult;
|
||||
/* Optional fields */
|
||||
FGSMobileIdentity *guti;
|
||||
// Allowed NSSAI (O)
|
||||
nr_nas_msg_snssai_t nas_allowed_nssai[8];
|
||||
// Configured NSSAI (O)
|
||||
nr_nas_msg_snssai_t config_nssai[8];
|
||||
} registration_accept_msg;
|
||||
|
||||
int decode_registration_accept(registration_accept_msg *registrationaccept, const uint8_t *buffer, uint32_t len);
|
||||
|
||||
+48
-129
@@ -69,7 +69,6 @@
|
||||
|
||||
extern uint16_t NB_UE_INST;
|
||||
static nr_ue_nas_t nr_ue_nas[MAX_NAS_UE] = {0};
|
||||
static nr_nas_msg_snssai_t nas_allowed_nssai[8];
|
||||
|
||||
#define FOREACH_STATE(TYPE_DEF) \
|
||||
TYPE_DEF(NAS_SECURITY_NO_SECURITY_CONTEXT, 0) \
|
||||
@@ -737,30 +736,6 @@ static void handle_security_mode_command(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
generateSecurityModeComplete(nas, initialNasMsg);
|
||||
}
|
||||
|
||||
static void decodeRegistrationAccept(const uint8_t *buf, int len, nr_ue_nas_t *nas)
|
||||
{
|
||||
registration_accept_msg reg_acc = {0};
|
||||
/* it seems there is no 5G corresponding emm_msg_decode() function, so here
|
||||
* we just jump to the right decision */
|
||||
buf += 7; /* skip security header */
|
||||
buf += 2; /* skip prot discriminator, security header, half octet */
|
||||
AssertFatal(*buf == 0x42, "this is not a NAS Registration Accept\n");
|
||||
buf++;
|
||||
int decoded = decode_registration_accept(®_acc, buf, len);
|
||||
AssertFatal(decoded > 0, "could not decode registration accept\n");
|
||||
if (reg_acc.guti) {
|
||||
AssertFatal(reg_acc.guti->guti.typeofidentity == FGS_MOBILE_IDENTITY_5G_GUTI,
|
||||
"registration accept 5GS Mobile Identity is not GUTI, but %d\n",
|
||||
reg_acc.guti->guti.typeofidentity);
|
||||
nas->guti = malloc(sizeof(*nas->guti));
|
||||
AssertFatal(nas->guti, "out of memory\n");
|
||||
*nas->guti = reg_acc.guti->guti;
|
||||
free(reg_acc.guti); /* no proper memory management for NAS decoded messages */
|
||||
} else {
|
||||
LOG_W(NAS, "no GUTI in registration accept\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void generateRegistrationComplete(nr_ue_nas_t *nas,
|
||||
as_nas_info_t *initialNasMsg,
|
||||
SORTransparentContainer *sortransparentcontainer)
|
||||
@@ -1185,109 +1160,13 @@ static void send_nas_detach_req(nr_ue_nas_t *nas, bool wait_release)
|
||||
itti_send_msg_to_task(TASK_RRC_NRUE, nas->UE_id, msg);
|
||||
}
|
||||
|
||||
static void parse_allowed_nssai(nr_nas_msg_snssai_t nssaiList[8], const uint8_t *buf, const uint32_t len)
|
||||
{
|
||||
int nssai_cnt = 0;
|
||||
const uint8_t *end = buf + len;
|
||||
while (buf < end) {
|
||||
const int length = *buf++;
|
||||
nr_nas_msg_snssai_t *nssai = nssaiList + nssai_cnt;
|
||||
nssai->sd = 0xffffff;
|
||||
|
||||
switch (length) {
|
||||
case 1:
|
||||
nssai->sst = *buf++;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
nssai->sst = *buf++;
|
||||
nssai->hplmn_sst = *buf++;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
nssai->sst = *buf++;
|
||||
nssai->sd = 0xffffff & ntoh_int24_buf(buf);
|
||||
buf += 3;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
nssai->sst = *buf++;
|
||||
nssai->sd = 0xffffff & ntoh_int24_buf(buf);
|
||||
buf += 3;
|
||||
nssai->hplmn_sst = *buf++;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
nssai->sst = *buf++;
|
||||
nssai->sd = 0xffffff & ntoh_int24_buf(buf);
|
||||
buf += 3;
|
||||
nssai->hplmn_sst = *buf++;
|
||||
nssai->hplmn_sd = 0xffffff & ntoh_int24_buf(buf);
|
||||
buf += 3;
|
||||
nssai_cnt++;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(NAS, "UE received unknown length in an allowed S-NSSAI\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract Allowed NSSAI from Regestration Accept according to
|
||||
3GPP TS 24.501 Table 8.2.7.1.1
|
||||
*/
|
||||
static void get_allowed_nssai(nr_nas_msg_snssai_t nssai[8], const uint8_t *pdu_buffer, const uint32_t pdu_length)
|
||||
{
|
||||
if ((pdu_buffer == NULL) || (pdu_length <= 0))
|
||||
return;
|
||||
|
||||
const uint8_t *end = pdu_buffer + pdu_length;
|
||||
if (((fgs_nas_message_security_header_t *)(pdu_buffer))->security_header_type > 0) {
|
||||
pdu_buffer += SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
pdu_buffer += 1 + 1 + 1 + 2; // Mandatory fields offset
|
||||
/* optional fields */
|
||||
while (pdu_buffer < end) {
|
||||
const int type = *pdu_buffer++;
|
||||
int length = 0;
|
||||
switch (type) {
|
||||
case 0x77: // 5GS mobile identity
|
||||
pdu_buffer += ntoh_int16_buf(pdu_buffer) + sizeof(uint16_t);
|
||||
break;
|
||||
|
||||
case 0x4A: // PLMN list
|
||||
case 0x54: // 5GS tracking area identity
|
||||
pdu_buffer += *pdu_buffer + 1; // offset length + 1 byte which contains the length
|
||||
break;
|
||||
|
||||
case 0x15: // allowed NSSAI
|
||||
length = *pdu_buffer++;
|
||||
parse_allowed_nssai(nssai, pdu_buffer, length);
|
||||
pdu_buffer += length;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_W(NAS, "This NAS IEI (0x%2.2x) is not handled when extracting list of allowed NSSAI\n", type);
|
||||
length = *pdu_buffer++;
|
||||
pdu_buffer += length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void request_default_pdusession(nr_ue_nas_t *nas, int nssai_idx)
|
||||
static void request_default_pdusession(nr_ue_nas_t *nas)
|
||||
{
|
||||
MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_PDU_SESSION_REQ);
|
||||
NAS_PDU_SESSION_REQ(message_p).pdusession_id = 10; /* first or default pdu session */
|
||||
NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6
|
||||
NAS_PDU_SESSION_REQ(message_p).sst = nas_allowed_nssai[nssai_idx].sst;
|
||||
NAS_PDU_SESSION_REQ(message_p).sd = nas_allowed_nssai[nssai_idx].sd;
|
||||
NAS_PDU_SESSION_REQ(message_p).sst = nas->uicc->nssai_sst;
|
||||
NAS_PDU_SESSION_REQ(message_p).sd = nas->uicc->nssai_sd;
|
||||
itti_send_msg_to_task(TASK_NAS_NRUE, nas->UE_id, message_p);
|
||||
}
|
||||
|
||||
@@ -1308,11 +1187,52 @@ void *nas_nrue_task(void *args_p)
|
||||
}
|
||||
}
|
||||
|
||||
static void process_guti(Guti5GSMobileIdentity_t *guti, nr_ue_nas_t *nas)
|
||||
{
|
||||
AssertFatal(guti->typeofidentity == FGS_MOBILE_IDENTITY_5G_GUTI,
|
||||
"registration accept 5GS Mobile Identity is not GUTI, but %d\n",
|
||||
guti->typeofidentity);
|
||||
nas->guti = malloc_or_fail(sizeof(*nas->guti));
|
||||
*nas->guti = *guti;
|
||||
}
|
||||
|
||||
static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buffer, uint32_t msg_length)
|
||||
{
|
||||
LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n");
|
||||
decodeRegistrationAccept(pdu_buffer, msg_length, nas);
|
||||
get_allowed_nssai(nas_allowed_nssai, pdu_buffer, msg_length);
|
||||
registration_accept_msg msg = {0};
|
||||
fgs_nas_message_security_header_t sp_header = {0};
|
||||
const uint8_t *end = pdu_buffer + msg_length;
|
||||
// security protected header
|
||||
int decoded = decode_5gs_security_protected_header(&sp_header, pdu_buffer, msg_length);
|
||||
if (!decoded) {
|
||||
LOG_E(NAS, "NAS Registration Accept: failed to decode security protected header\n");
|
||||
return;
|
||||
}
|
||||
pdu_buffer += decoded;
|
||||
// plain header
|
||||
fgmm_msg_header_t mm_header = {0};
|
||||
if ((decoded = decode_5gmm_msg_header(&mm_header, pdu_buffer, end - pdu_buffer)) < 0) {
|
||||
LOG_E(NAS, "Failed to decode NAS Registration Accept\n");
|
||||
return;
|
||||
}
|
||||
if (mm_header.message_type != FGS_REGISTRATION_ACCEPT) {
|
||||
LOG_E(NAS, "Failed to process NAS Registration Accept: wrong message type\n");
|
||||
return;
|
||||
}
|
||||
pdu_buffer += decoded;
|
||||
// plain payload
|
||||
if ((decoded = decode_registration_accept(&msg, pdu_buffer, end - pdu_buffer)) < 0) {
|
||||
LOG_E(NAS, "Failed to decode NAS Registration Accept\n");
|
||||
return;
|
||||
}
|
||||
pdu_buffer += decoded;
|
||||
// process GUTI
|
||||
if (msg.guti) {
|
||||
process_guti(&msg.guti->guti, nas);
|
||||
free(msg.guti);
|
||||
} else {
|
||||
LOG_W(NAS, "no GUTI in registration accept\n");
|
||||
}
|
||||
|
||||
as_nas_info_t initialNasMsg = {0};
|
||||
generateRegistrationComplete(nas, &initialNasMsg, NULL);
|
||||
@@ -1320,11 +1240,10 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff
|
||||
send_nas_uplink_data_req(nas, &initialNasMsg);
|
||||
LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n");
|
||||
}
|
||||
const int nssai_idx = get_user_nssai_idx(nas_allowed_nssai, nas);
|
||||
if (nssai_idx < 0) {
|
||||
if (get_user_nssai_idx(msg.nas_allowed_nssai, nas) < 0) {
|
||||
LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n");
|
||||
} else {
|
||||
request_default_pdusession(nas, nssai_idx);
|
||||
request_default_pdusession(nas);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,14 +51,6 @@
|
||||
/* 3GPP TS 24.501: 9.11.3.50 Service type */
|
||||
#define SERVICE_TYPE_DATA 0x1
|
||||
|
||||
/* List of allowed NSSAI from NAS messaging. */
|
||||
typedef struct {
|
||||
int sst;
|
||||
int hplmn_sst;
|
||||
int sd;
|
||||
int hplmn_sd;
|
||||
} nr_nas_msg_snssai_t;
|
||||
|
||||
/* Security Key for SA UE */
|
||||
typedef struct {
|
||||
uint8_t kausf[32];
|
||||
|
||||
Reference in New Issue
Block a user