Commit 2334f6f5 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/nas-issue-881' into integration_2025_w07 (!3176)

Refactor and extend NAS Registration Request

Extended NAS Registration Request generation and encoding according to
8.2.6 of 3GPP TS 24.501. Main topics:

- NAS Registration Type
- NAS KSI
- integrity protection
- NAS container encoding

Improvements:

- Add 5GMM Modes in NAS
- Introduced 5GMM state machine

Fixes:

- add 5GMM Capability IE to Registration Request
- closes #881, #819
parents bab13b80 bd429488
......@@ -1106,7 +1106,8 @@ static void rrc_ue_generate_RRCSetupComplete(const NR_UE_RRC_INST_t *rrc, const
if (IS_SA_MODE(get_softmodem_params())) {
as_nas_info_t initialNasMsg;
nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id);
generateRegistrationRequest(&initialNasMsg, nas);
// Send Initial NAS message (Registration Request) before Security Mode control procedure
generateRegistrationRequest(&initialNasMsg, nas, false);
nas_msg = (char *)initialNasMsg.nas_data;
nas_msg_length = initialNasMsg.length;
} else {
......
......@@ -35,16 +35,55 @@
#include "TLVDecoder.h"
#include "FGMMCapability.h"
int encode_5gmm_capability(const FGMMCapability *fgmmcapability, uint8_t iei, uint8_t *buffer, uint32_t len)
#define MIN_LENGTH_5GMM_CAPABILITY 3
/**
* @brief Encode 5GMM Capability IE (9.11.3 of 3GPP TS 24.501)
*/
int encode_5gmm_capability(uint8_t *buffer, const FGMMCapability *fgmmcapability, uint32_t len)
{
int encoded = 0;
if (iei) {
// Ensure buffer length is sufficient
if (len < MIN_LENGTH_5GMM_CAPABILITY) {
printf("Buffer length insufficient for encoding 5GMM capability\n");
return -1;
}
if (fgmmcapability->iei) {
*buffer = fgmmcapability->iei;
encoded++;
*(buffer + encoded) = fgmmcapability->length;
} else {
printf("Missing IEI in fgmmcapability\n");
}
buffer[encoded] = fgmmcapability->length;
encoded++;
// Encode octet 3 (mandatory)
buffer[encoded] = (fgmmcapability->sgc << 7) | (fgmmcapability->iphc_cp_cIoT << 6) | (fgmmcapability->n3_data << 5)
| (fgmmcapability->cp_cIoT << 4) | (fgmmcapability->restrict_ec << 3) | (fgmmcapability->lpp << 2)
| (fgmmcapability->ho_attach << 1) | fgmmcapability->s1_mode;
encoded++;
// Encode octet 4
if (fgmmcapability->length >= 2) {
buffer[encoded] = (fgmmcapability->racs << 7) | (fgmmcapability->nssaa << 6) | (fgmmcapability->lcs << 5)
| (fgmmcapability->v2x_cnpc5 << 4) | (fgmmcapability->v2x_cepc5 << 3) | (fgmmcapability->v2x << 2)
| (fgmmcapability->up_cIoT << 1) | fgmmcapability->srvcc;
encoded++;
*(buffer + encoded) = fgmmcapability->value;
}
// Encode octet 5
if (fgmmcapability->length >= 3) {
buffer[encoded] = (fgmmcapability->ehc_CP_ciot << 3) | (fgmmcapability->multiple_eUP << 2) | (fgmmcapability->wusa << 1)
| fgmmcapability->cag;
encoded++;
}
// Encode octets 6 - 15
if (fgmmcapability->length >= 4)
memset(&buffer[encoded], 0, fgmmcapability->length - 3);
return encoded;
}
......@@ -30,6 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "OctetString.h"
......@@ -39,9 +40,28 @@
typedef struct {
uint8_t iei;
uint8_t length;
uint8_t value;
bool sgc;
bool iphc_cp_cIoT;
bool n3_data;
bool cp_cIoT;
bool restrict_ec;
bool lpp;
bool ho_attach;
bool s1_mode;
bool racs;
bool nssaa;
bool lcs;
bool v2x_cnpc5;
bool v2x_cepc5;
bool v2x;
bool up_cIoT;
bool srvcc;
bool ehc_CP_ciot;
bool multiple_eUP;
bool wusa;
bool cag;
} FGMMCapability;
int encode_5gmm_capability(const FGMMCapability *fgmmcapability, uint8_t iei, uint8_t *buffer, uint32_t len);
int encode_5gmm_capability(uint8_t *buffer, const FGMMCapability *fgmmcapability, uint32_t len);
#endif /* FGMM_CAPABILITY_H_ */
......@@ -30,11 +30,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "TLVEncoder.h"
#include "TLVDecoder.h"
#include "FGSRegistrationType.h"
#define NO_FOLLOW_ON_REQUEST 0x0
#define FOLLOW_ON_REQUEST 0x08
int decode_5gs_registration_type(FGSRegistrationType *fgsregistrationtype, uint8_t iei, uint8_t value, uint32_t len)
{
int decoded = 0;
......@@ -49,14 +52,14 @@ int decode_5gs_registration_type(FGSRegistrationType *fgsregistrationtype, uint8
return decoded;
}
int encode_5gs_registration_type(const FGSRegistrationType *fgsregistrationtype)
/**
* @brief Encode 5GS registration type (9.11.3.7 of 3GPP TS 24.501)
* Note: mandatory IE (IEI = 0)
*/
int encode_5gs_registration_type(const FGSRegistrationType *fgsregistrationtype, bool follow_on_request)
{
uint8_t bufferReturn;
uint8_t *buffer = &bufferReturn;
uint8_t encoded = 0;
uint8_t iei = 0;
*(buffer + encoded) = 0x00 | (iei & 0xf0) | 0x8 | (*fgsregistrationtype & 0x7);
encoded++;
return bufferReturn;
// Follow-on request bit
uint8_t foR = follow_on_request ? FOLLOW_ON_REQUEST : NO_FOLLOW_ON_REQUEST;
// Return encoded value
return (foR | (*fgsregistrationtype & 0x7));
}
......@@ -29,7 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "OctetString.h"
#ifndef FGS_REGISTRATION_TYPE_H_
......@@ -41,13 +41,15 @@
typedef uint8_t FGSRegistrationType;
// clang-format off
/* 3GPP TS 24.501 Table 9.11.3.7.1: 5GS registration type IE */
#define INITIAL_REGISTRATION 0b001
#define MOBILITY_REGISTRATION_UPDATING 0b010
#define PERIODIC_REGISTRATION_UPDATING 0b011
#define EMERGENCY_REGISTRATION 0b100
#define REG_TYPE_RESERVED 0b111
// clang-format on
int encode_5gs_registration_type(const FGSRegistrationType *fgsregistrationtype);
int encode_5gs_registration_type(const FGSRegistrationType *fgsregistrationtype, bool follow_on_request);
int decode_5gs_registration_type(FGSRegistrationType *fgsregistrationtype, uint8_t iei, uint8_t value, uint32_t len);
......
......@@ -72,9 +72,10 @@ int encode_registration_request(const registration_request_msg *registration_req
{
int encoded = 0;
int encode_result = 0;
bool is_for = true; // Follow-on request pending
*(buffer + encoded) = ((encode_nas_key_set_identifier(&registration_request->naskeysetidentifier, IEI_NULL) & 0x0f) << 4)
| (encode_5gs_registration_type(&registration_request->fgsregistrationtype) & 0x0f);
| (encode_5gs_registration_type(&registration_request->fgsregistrationtype, is_for) & 0x0f);
encoded++;
if ((encode_result = encode_5gs_mobile_identity(&registration_request->fgsmobileidentity, 0, buffer + encoded, len - encoded))
......@@ -86,12 +87,7 @@ int encode_registration_request(const registration_request_msg *registration_req
if ((registration_request->presencemask & REGISTRATION_REQUEST_5GMM_CAPABILITY_PRESENT)
== REGISTRATION_REQUEST_5GMM_CAPABILITY_PRESENT) {
if ((encode_result = encode_5gmm_capability(&registration_request->fgmmcapability,
REGISTRATION_REQUEST_5GMM_CAPABILITY_IEI,
buffer + encoded,
len - encoded))
< 0)
// Return in case of error
if ((encode_result = encode_5gmm_capability(buffer + encoded, &registration_request->fgmmcapability, len - encoded)) < 0)
return encode_result;
else
encoded += encode_result;
......
......@@ -35,6 +35,7 @@
#include "NasKeySetIdentifier.h"
#include "NrUESecurityCapability.h"
#include "SecurityHeaderType.h"
#include "FGCNasMessageContainer.h"
#ifndef REGISTRATION_REQUEST_H_
#define REGISTRATION_REQUEST_H_
......@@ -102,6 +103,7 @@ typedef struct registration_request_msg_tag {
NasKeySetIdentifier naskeysetidentifier;
FGSMobileIdentity fgsmobileidentity;
/* Optional fields */
FGCNasMessageContainer fgsnasmessagecontainer;
uint32_t presencemask;
FGMMCapability fgmmcapability;
NrUESecurityCapability nruesecuritycapability;
......
......@@ -199,6 +199,24 @@ static int fill_suci(FGSMobileIdentity *mi, const uicc_t *uicc)
mi->suci.mccdigit2 = uicc->imsiStr[1] - '0';
mi->suci.mccdigit3 = uicc->imsiStr[2] - '0';
memcpy(mi->suci.schemeoutput, uicc->imsiStr + 3 + uicc->nmc_size, strlen(uicc->imsiStr) - (3 + uicc->nmc_size));
LOG_D(NAS,
"SUCI in registration request: SUPI type: %d Type of Identity: %u MCC: %u%u%u, MNC: %u%u%u, \
Routing Indicator %d%d%d%d Protection Scheme ID: %u, Home Network PKI: %u, Scheme Output: %s\n",
mi->suci.supiformat,
mi->suci.typeofidentity,
mi->suci.mccdigit1,
mi->suci.mccdigit2,
mi->suci.mccdigit3,
mi->suci.mncdigit1,
mi->suci.mncdigit2,
uicc->nmc_size == 2 ? 0 : mi->suci.mncdigit3,
mi->suci.routingindicatordigit1,
mi->suci.routingindicatordigit2,
mi->suci.routingindicatordigit3,
mi->suci.routingindicatordigit4,
mi->suci.protectionschemeId,
mi->suci.homenetworkpki,
mi->suci.schemeoutput);
return sizeof(Suci5GSMobileIdentity_t);
}
......@@ -206,6 +224,18 @@ static int fill_guti(FGSMobileIdentity *mi, const Guti5GSMobileIdentity_t *guti)
{
AssertFatal(guti != NULL, "UE has no GUTI\n");
mi->guti = *guti;
LOG_D(NAS,
"5G-GUTI in registration request: MCC: %u%u%u, MNC: %u%u, AMF Region ID: %u, AMF Set ID: %u, AMF Pointer: %u, 5G-TMSI: "
"%u\n",
mi->guti.mccdigit1,
mi->guti.mccdigit2,
mi->guti.mccdigit3,
mi->guti.mncdigit1,
mi->guti.mncdigit2,
mi->guti.amfregionid,
mi->guti.amfsetid,
mi->guti.amfpointer,
mi->guti.tmsi);
return 13;
}
......@@ -458,53 +488,210 @@ nr_ue_nas_t *get_ue_nas_info(module_id_t module_id)
return &nr_ue_nas[module_id];
}
void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
static FGSRegistrationType set_fgs_ksi(nr_ue_nas_t *nas)
{
int size = sizeof(fgmm_msg_header_t);
fgmm_nas_message_plain_t plain = {0};
if (nas->fiveGMM_mode == FGS_IDLE) {
/**
* the UE is IDLE, therefore ngKSI was deleted, along all K_AMF, ciphering key, integrity key
* (i.e. the 5G NAS security context associated with the ngKSI is no longer valid)
* see 4.4.2 of 3GPP TS 24.501
*/
return NAS_KEY_SET_IDENTIFIER_NOT_AVAILABLE;
}
return 0x0;
}
// Plain 5GMM header
plain.header = set_mm_header(FGS_REGISTRATION_REQUEST, PLAIN_5GS_MSG);
size += sizeof(plain.header);
/**
* @brief Set contents of 5GMM capability
* @note Currently hardcoded, sending min length only (1 octet)
*/
static FGMMCapability set_fgmm_capability(nr_ue_nas_t *nas)
{
FGMMCapability cap = {0};
cap.iei = REGISTRATION_REQUEST_5GMM_CAPABILITY_IEI;
cap.length = 1;
cap.sgc = 0;
cap.iphc_cp_cIoT = 0;
cap.n3_data = 0;
cap.cp_cIoT = 0;
cap.restrict_ec = 0;
cap.lpp = 1;
cap.ho_attach = 1;
cap.s1_mode = 1;
if (cap.length == 1)
return cap; // Send minimum length only, 1 octet
cap.racs = 0;
cap.nssaa = 0;
cap.lcs = 0;
cap.v2x_cnpc5 = 0;
cap.v2x_cepc5 = 0;
cap.v2x = 0;
cap.up_cIoT = 0;
cap.srvcc = 0;
cap.ehc_CP_ciot = 0;
cap.multiple_eUP = 0;
cap.wusa = 0;
cap.cag = 0;
return cap;
}
// Plain 5GMM msg
registration_request_msg *mm_msg = &plain.mm_msg.registration_request;
mm_msg->fgsregistrationtype = INITIAL_REGISTRATION;
mm_msg->naskeysetidentifier.naskeysetidentifier = 1;
static FGSRegistrationType set_fgs_registration_type(nr_ue_nas_t *nas)
{
if (nas->fiveGMM_state == FGS_REGISTERED && nas->fiveGMM_mode == FGS_IDLE && nas->t3512) {
// TODO: if the timer expires, do PERIODIC_REGISTRATION_UPDATING
/** The UE shall initiate the registration procedure for
* mobility and periodic registration update according to
* 5.5.1.3.2 of 3GPP TS 24.501: Mobility and periodic
* registration update initiation */
LOG_E(NAS, "Registration type periodic registration updating is not handled\n");
return REG_TYPE_RESERVED;
} else if (nas->fiveGMM_state == FGS_REGISTERED) {
// in any other case, The UE in state 5GMM-REGISTERED shall indicate "mobility registration updating".
return MOBILITY_REGISTRATION_UPDATING;
}
if (nas->fiveGMM_mode == FGS_CONNECTED && nas->is_rrc_inactive) {
/** the UE shall do the registration procedure for mobility
* and/or periodic registration update depending on the
* indication received from the lower layers according to
* 5.3.1.4 of 3GPP TS 24.501: 5GMM-CONNECTED mode with RRC inactive indication */
LOG_E(NAS, "RRC inactive indication not handled by NAS\n");
return REG_TYPE_RESERVED;
}
return INITIAL_REGISTRATION;
}
/**
* @brief Generate 5GS Registration Request (8.2.6 of 3GPP TS 24.501)
*/
void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas, bool is_security_mode)
{
LOG_I(NAS, "Generate Initial NAS Message: Registration Request\n");
int size = sizeof(fgmm_msg_header_t); // cleartext size
fgmm_nas_msg_security_protected_t sp = {0};
/** Check whether the UE has a valid current 5G NAS security context
and set security protected 5GS NAS message header (see 9.1.1 of 3GPP TS 24.501) */
bool has_security_context = nas->security_container && nas->security_container->integrity_context;
if (has_security_context) {
sp.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
sp.header.security_header_type = INTEGRITY_PROTECTED;
sp.header.sequence_number = nas->security.nas_count_ul & 0xff;
size += 7;
}
// Plain 5GMM message
sp.plain.header = set_mm_header(FGS_REGISTRATION_REQUEST, PLAIN_5GS_MSG);
size += sizeof(sp.plain.header);
registration_request_msg *rr = &sp.plain.mm_msg.registration_request;
// 5GMM Registration Type
rr->fgsregistrationtype = set_fgs_registration_type(nas);
size += 1;
if (rr->fgsregistrationtype == REG_TYPE_RESERVED) {
// currently only REG_TYPE_RESERVED is supported
LOG_E(NAS, "Initial NAS Message: Registration Request failed\n");
return;
}
// NAS Key Set Identifier
rr->naskeysetidentifier.tsc = NAS_KEY_SET_IDENTIFIER_NATIVE;
rr->naskeysetidentifier.naskeysetidentifier = set_fgs_ksi(nas);
size += 1;
if (nas->guti) {
size += fill_guti(&mm_msg->fgsmobileidentity, nas->guti);
// 5GMM Mobile Identity
if(nas->guti){
size += fill_guti(&rr->fgsmobileidentity, nas->guti);
} else {
size += fill_suci(&mm_msg->fgsmobileidentity, nas->uicc);
size += fill_suci(&rr->fgsmobileidentity, nas->uicc);
}
#if 0
/* This cannot be sent in clear, the core network Open5GS rejects the UE.
* TODO: do we have to send this at some point?
* For the time being, let's keep it here for later proper fix.
*/
mm_msg->registration_request.presencemask |= REGISTRATION_REQUEST_5GMM_CAPABILITY_PRESENT;
mm_msg->registration_request.fgmmcapability.iei = REGISTRATION_REQUEST_5GMM_CAPABILITY_IEI;
mm_msg->registration_request.fgmmcapability.length = 1;
mm_msg->registration_request.fgmmcapability.value = 0x7;
size += 3;
#endif
mm_msg->presencemask |= REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_PRESENT;
mm_msg->nruesecuritycapability.iei = REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_IEI;
mm_msg->nruesecuritycapability.length = 8;
mm_msg->nruesecuritycapability.fg_EA = 0xe0;
mm_msg->nruesecuritycapability.fg_IA = 0x60;
mm_msg->nruesecuritycapability.EEA = 0;
mm_msg->nruesecuritycapability.EIA = 0;
// Security Capability
rr->presencemask |= REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_PRESENT;
rr->nruesecuritycapability.iei = REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_IEI;
rr->nruesecuritycapability.length = 8;
rr->nruesecuritycapability.fg_EA = 0xe0;
rr->nruesecuritycapability.fg_IA = 0x60;
rr->nruesecuritycapability.EEA = 0;
rr->nruesecuritycapability.EIA = 0;
size += 10;
// encode the message
initialNasMsg->nas_data = malloc16_clear(size * sizeof(*initialNasMsg->nas_data));
nas->registration_request_buf = initialNasMsg->nas_data;
/* Create a copy of the cleartext 5GMM message, add non-cleartext IEs if necessary */
fgmm_nas_message_plain_t full_mm = sp.plain;
registration_request_msg *full_rr = &full_mm.mm_msg.registration_request;
int size_nct = size; // non-cleartext size
bool cleartext_only = true;
/* 5GMM Capability (non-cleartext IE) - 24.501 8.2.6.3
The UE shall include this IE, unless the UE performs a periodic registration updating procedure. */
if (full_rr->fgsregistrationtype != PERIODIC_REGISTRATION_UPDATING) {
cleartext_only = false; // The UE needs to send non-cleartext IE
full_rr->presencemask |= REGISTRATION_REQUEST_5GMM_CAPABILITY_PRESENT;
full_rr->fgmmcapability = set_fgmm_capability(nas);
FGMMCapability *cap = &full_rr->fgmmcapability;
size_nct += sizeof(cap->length) + sizeof(cap->iei) + cap->length;
}
initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size);
nas->registration_request_len = initialNasMsg->length;
if (is_security_mode) {
/* Encode both cleartext IEs and non-cleartext IEs Registration Request message in Security Mode Complete.
The UE includes the full Registration Request in the NAS container IE
and sends it within the Security Mode Complete message. (24.501 4.4.6, 23.502 4.2.2.2.2) */
LOG_D(NAS, "Full Initial NAS Message: Registration Request in the NAS container of Security Mode Complete\n");
initialNasMsg->nas_data = malloc_or_fail(size_nct * sizeof(*initialNasMsg->nas_data));
initialNasMsg->length = mm_msg_encode(&full_mm, initialNasMsg->nas_data, size_nct);
} else if (!has_security_context) {
/* If no valid 5G NAS security context exists, the UE sends a plain Registration Request including cleartext IEs only. */
LOG_D(NAS, "Plain Initial NAS Message: Registration Request\n");
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
initialNasMsg->length = mm_msg_encode(&sp.plain, initialNasMsg->nas_data, size);
} else {
/* If the UE has a valid current 5G NAS security context, then it includes the entire 5GMM NAS Registration Request
(with both cleartext and non-cleartext IEs) in the NAS message container IE. The value of the NAS message container IE is
then ciphered. The UE sends a 5GMM NAS Registration Request message containing cleartext IEs along with the NAS message
container IE. */
LOG_D(NAS, "Initial NAS Message: Registration Request with ciphered NAS container\n");
// NAS message container
if (!cleartext_only) {
OctetString *nasmessagecontainercontents = &rr->fgsnasmessagecontainer.nasmessagecontainercontents;
nasmessagecontainercontents->value = calloc_or_fail(size_nct, sizeof(*nasmessagecontainercontents->value));
nasmessagecontainercontents->length = mm_msg_encode(&full_mm, nasmessagecontainercontents->value, size_nct);
size += (nasmessagecontainercontents->length + 2);
rr->presencemask |= REGISTRATION_REQUEST_NAS_MESSAGE_CONTAINER_PRESENT;
}
// Allocate buffer (including NAS message container size)
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
// Security protected header encoding
int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, &sp.header, size);
initialNasMsg->length =
security_header_len
+ mm_msg_encode(&sp.plain, initialNasMsg->nas_data + security_header_len, size - security_header_len);
/* integrity protection */
nas_stream_cipher_t stream_cipher;
AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n");
uint8_t mac[4];
stream_cipher.context = nas->security_container->integrity_context;
stream_cipher.count = nas->security.nas_count_ul++;
stream_cipher.bearer = 1;
stream_cipher.direction = 0;
// Security protected header is cleartext except the SN field
uint8_t cleartext_len = sizeof(sp.header) - 1;
// Message to be integrity protected
stream_cipher.message = initialNasMsg->nas_data + cleartext_len;
// Length of integrity protected message in bits
stream_cipher.blength = (initialNasMsg->length - cleartext_len) << 3;
stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac);
uint8_t mac_len = sizeof(sp.header.message_authentication_code);
uint8_t mac_start_octet = 2;
LOG_D(NAS, "Integrity protected initial NAS message: mac = %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]);
for (int i = 0; i < mac_len; i++) {
initialNasMsg->nas_data[mac_start_octet + i] = mac[i];
}
}
}
void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
......@@ -530,6 +717,8 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
// 5G-S-TMSI
size += fill_fgstmsi(&mm_msg->fiveg_s_tmsi, nas->guti);
/* message encoding */
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
if (security_protected) {
fgmm_nas_msg_security_protected_t sp = {0};
......@@ -542,9 +731,6 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
// Payload: plain message
sp.plain = plain;
// Allocate NAS message for encoding
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
// security protected encoding
int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, &sp.header, size);
initialNasMsg->length =
......@@ -578,8 +764,6 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
initialNasMsg->nas_data[2 + i] = mac[i];
} else {
// plain encoding
// Allocate NAS message for encoding
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size);
LOG_I(NAS, "PLAIN_5GS_MSG initial NAS message: Service Request with length %d \n", initialNasMsg->length);
}
......@@ -665,9 +849,14 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
fgs_security_mode_complete_msg *mm_msg = &plain->mm_msg.fgs_security_mode_complete;
size += fill_imeisv(&mm_msg->fgsmobileidentity, nas->uicc);
mm_msg->fgsnasmessagecontainer.nasmessagecontainercontents.value = nas->registration_request_buf;
mm_msg->fgsnasmessagecontainer.nasmessagecontainercontents.length = nas->registration_request_len;
size += (nas->registration_request_len + 2);
/* After activating a 5G NAS security context resulting from a security mode control send the full
NAS Registration Request in the message container IE of the SECURITY MODE COMPLETE message (24.501 4.4.6) */
as_nas_info_t rr;
generateRegistrationRequest(&rr, nas, true);
FGCNasMessageContainer *container = &mm_msg->fgsnasmessagecontainer;
container->nasmessagecontainercontents.value = rr.nas_data;
container->nasmessagecontainercontents.length = rr.length;
size += (rr.length + 2);
// encode the message
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
......@@ -812,6 +1001,8 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas,
for (int i = 0; i < 4; i++) {
initialNasMsg->nas_data[2 + i] = mac[i];
}
/* Set NAS 5GMM state */
nas->fiveGMM_state = FGS_REGISTERED;
}
/**
......@@ -1010,6 +1201,8 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi
for (int i = 0; i < 4; i++) {
initialNasMsg->nas_data[2 + i] = mac[i];
}
/* Set NAS 5GMM state */
nas->fiveGMM_state = FGS_DEREGISTERED_INITIATED;
}
static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, nas_pdu_session_req_t *pdu_req)
......@@ -1438,6 +1631,8 @@ void *nas_nrue(void *args_p)
break;
case FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING:
LOG_I(NAS, "received deregistration accept\n");
/* Set NAS 5GMM state */
nas->fiveGMM_state = FGS_DEREGISTERED;
break;
case FGS_PDU_SESSION_ESTABLISHMENT_ACC:
handle_pdu_session_accept(pdu_buffer, pdu_length);
......
......@@ -51,6 +51,24 @@
/* 3GPP TS 24.501: 9.11.3.50 Service type */
#define SERVICE_TYPE_DATA 0x1
typedef enum fgs_mm_state_e {
FGS_DEREGISTERED,
FGS_DEREGISTERED_INITIATED,
FGS_REGISTERED_INITIATED,
FGS_REGISTERED,
FGS_SERVICE_REQUEST_INITIATED,
} fgs_mm_state_t;
/*
* 5GS mobility management (5GMM) modes
* 5.1.3.2.1.1 of TS 24.501
*/
typedef enum fgs_mm_mode_e {
FGS_NOT_CONNECTED,
FGS_IDLE,
FGS_CONNECTED,
} fgs_mm_mode_t;
/* Security Key for SA UE */
typedef struct {
uint8_t kausf[32];
......@@ -66,18 +84,24 @@ typedef struct {
} ue_sa_security_key_t;
typedef struct {
/* 5GS Mobility Management States (5.1.3.2.1 of 3GPP TS 24.501) */
fgs_mm_state_t fiveGMM_state;
/* 5GS Mobility Management mode */
fgs_mm_mode_t fiveGMM_mode;
uicc_t *uicc;
ue_sa_security_key_t security;
stream_security_container_t *security_container;
Guti5GSMobileIdentity_t *guti;
bool termination_procedure;
uint8_t *registration_request_buf;
uint32_t registration_request_len;
instance_t UE_id;
/* RRC Inactive Indication */
bool is_rrc_inactive;
/* Timer T3512 */
int t3512;
} nr_ue_nas_t;
nr_ue_nas_t *get_ue_nas_info(module_id_t module_id);
void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas);
void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas, bool is_security_mode);
void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas);
void *nas_nrue_task(void *args_p);
void *nas_nrue(void *args_p);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment