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
This commit is contained in:
@@ -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;
|
||||
encoded++;
|
||||
*(buffer + encoded) = fgmmcapability->value;
|
||||
} 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++;
|
||||
}
|
||||
|
||||
// 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(®istration_request->naskeysetidentifier, IEI_NULL) & 0x0f) << 4)
|
||||
| (encode_5gs_registration_type(®istration_request->fgsregistrationtype) & 0x0f);
|
||||
| (encode_5gs_registration_type(®istration_request->fgsregistrationtype, is_for) & 0x0f);
|
||||
encoded++;
|
||||
|
||||
if ((encode_result = encode_5gs_mobile_identity(®istration_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(®istration_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, ®istration_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;
|
||||
|
||||
+241
-46
@@ -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;
|
||||
|
||||
// Plain 5GMM msg
|
||||
registration_request_msg *mm_msg = &plain.mm_msg.registration_request;
|
||||
mm_msg->fgsregistrationtype = INITIAL_REGISTRATION;
|
||||
mm_msg->naskeysetidentifier.naskeysetidentifier = 1;
|
||||
size += 1;
|
||||
if (nas->guti) {
|
||||
size += fill_guti(&mm_msg->fgsmobileidentity, nas->guti);
|
||||
} else {
|
||||
size += fill_suci(&mm_msg->fgsmobileidentity, nas->uicc);
|
||||
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;
|
||||
}
|
||||
|
||||
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 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
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
// 5GMM Mobile Identity
|
||||
if(nas->guti){
|
||||
size += fill_guti(&rr->fgsmobileidentity, nas->guti);
|
||||
} else {
|
||||
size += fill_suci(&rr->fgsmobileidentity, nas->uicc);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
Reference in New Issue
Block a user