Refactor NAS 5GMM messages structs definitions

as per legacy code, the NAS functions in nr_nas_msg.c were encoding
the header in the plain header contained in MM_msg
(e.g. plain -> mm_msg -> header in fgs_nas_message_t). The same
header was encoded in the mobility management message contained
in the same struct (e.g. plain -> mm_msg -> registration_request
-> protocoldiscriminator). As this was more complicated than
necessary, the goal of this commit is to simplify the code and
improve readability. Namely:

* Refactor MM_msg into fgmm_nas_message_plain_t to contain
  (1) 5GMM Header
  (2) 5GMM Payload union
* Use fgmm_nas_message_plain_t and fgmm_nas_msg_security_protected_t
  in the 5GMM NAS procedures
* Remove NAS header IEs from 5GMM messages structs and use
  the header in fgs_nas_message_plain_t.
  This reduce also the repetitions of header members in each
  of the 5GMM messages structs.
* Rename struct to distinguish between 5GMM and 5GSM
* Remove fgs_nas_message_t and nas_msg_header_t,
  use directly basic 5GS struct definitions, simplify the code
* The callbacks in nr_nas_msg.c are now doing
  (1) encode header with the common NAS lib
  (2) encode contents with the 5GMM libs
* improve code readibility in the process
This commit is contained in:
Guido Casati
2025-01-30 15:21:39 +01:00
parent 9719f5e574
commit 63d7f26cfd
10 changed files with 191 additions and 262 deletions
@@ -50,10 +50,6 @@
typedef struct fgs_authentication_response_msg_tag {
/* Mandatory fields */
uint8_t protocoldiscriminator;
SecurityHeaderType securityheadertype: 4;
uint8_t sparehalfoctet: 4;
MessageType messagetype;
AuthenticationResponseParameter authenticationresponseparameter;
} fgs_authentication_response_msg;
@@ -38,10 +38,6 @@
typedef struct fgs_deregistration_request_ue_originating_msg_tag {
/* Mandatory fields */
uint8_t protocoldiscriminator;
SecurityHeaderType securityheadertype: 4;
uint8_t sparehalfoctet: 4;
MessageType messagetype;
FGSDeregistrationType deregistrationtype;
NasKeySetIdentifier naskeysetidentifier;
FGSMobileIdentity fgsmobileidentity;
@@ -45,10 +45,6 @@
typedef struct fgmm_identity_response_msg_s {
/* Mandatory fields */
uint8_t protocoldiscriminator;
SecurityHeaderType securityheadertype: 4;
uint8_t sparehalfoctet: 4;
MessageType messagetype;
FGSMobileIdentity fgsmobileidentity;
} fgmm_identity_response_msg;
@@ -46,10 +46,6 @@
typedef struct fgs_security_mode_complete_msg_tag {
/* Mandatory fields */
uint8_t protocoldiscriminator;
SecurityHeaderType securityheadertype: 4;
uint8_t sparehalfoctet: 4;
MessageType messagetype;
FGSMobileIdentity fgsmobileidentity;
FGCNasMessageContainer fgsnasmessagecontainer;
} fgs_security_mode_complete_msg;
@@ -53,10 +53,6 @@ typedef struct FGSPayloadContainer_tag {
typedef struct fgs_uplink_nas_transport_msg_tag {
/* Mandatory fields */
uint8_t protocoldiscriminator;
SecurityHeaderType securityheadertype: 4;
uint8_t sparehalfoctet: 4;
MessageType messagetype;
PayloadContainerType payloadcontainertype;
FGSPayloadContainer fgspayloadcontainer;
/* Optional fields */
@@ -49,12 +49,7 @@
typedef struct registration_accept_msg_tag {
/* Mandatory fields */
uint8_t protocoldiscriminator;
SecurityHeaderType securityheadertype: 4;
uint8_t sparehalfoctet: 4;
MessageType messagetype;
FGSRegistrationResult fgsregistrationresult;
/* Optional fields */
FGSMobileIdentity *guti;
} registration_accept_msg;
@@ -98,14 +98,9 @@ typedef enum registration_request_iei_tag {
typedef struct registration_request_msg_tag {
/* Mandatory fields */
uint8_t protocoldiscriminator;
SecurityHeaderType securityheadertype: 4;
uint8_t sparehalfoctet: 4;
MessageType messagetype;
FGSRegistrationType fgsregistrationtype;
NasKeySetIdentifier naskeysetidentifier;
FGSMobileIdentity fgsmobileidentity;
/* Optional fields */
uint32_t presencemask;
FGMMCapability fgmmcapability;
+19 -38
View File
@@ -258,45 +258,26 @@ typedef struct {
uint8_t message_type;
} fgmm_msg_header_t;
/// 5GS legacy defs
typedef union {
/* Plain 5GMM NAS message (5GS) */
typedef struct {
fgmm_msg_header_t header;
registration_request_msg registration_request;
fgs_service_request_msg_t service_request;
fgmm_identity_response_msg fgs_identity_response;
fgs_authentication_response_msg fgs_auth_response;
fgs_deregistration_request_ue_originating_msg fgs_deregistration_request_ue_originating;
fgs_security_mode_complete_msg fgs_security_mode_complete;
registration_complete_msg registration_complete;
fgs_uplink_nas_transport_msg uplink_nas_transport;
} MM_msg;
typedef struct {
MM_msg mm_msg; /* 5GS Mobility Management messages */
} fgs_nas_message_plain_t;
typedef struct {
fgs_nas_message_security_header_t header;
fgs_nas_message_plain_t plain;
} fgs_nas_message_security_protected_t;
typedef union {
fgs_nas_message_security_header_t header;
fgs_nas_message_security_protected_t security_protected;
fgs_nas_message_plain_t plain;
} fgs_nas_message_t;
typedef struct {
union {
fgmm_msg_header_t plain_nas_msg_header;
struct security_protected_nas_msg_header_s {
uint8_t ex_protocol_discriminator;
uint8_t security_header_type;
uint16_t message_authentication_code1;
uint16_t message_authentication_code2;
uint8_t sequence_number;
} security_protected_nas_msg_header_t;
} choice;
} nas_msg_header_t;
registration_request_msg registration_request;
fgs_service_request_msg_t service_request;
fgmm_identity_response_msg fgs_identity_response;
fgs_authentication_response_msg fgs_auth_response;
fgs_deregistration_request_ue_originating_msg fgs_deregistration_request_ue_originating;
fgs_security_mode_complete_msg fgs_security_mode_complete;
registration_complete_msg registration_complete;
fgs_uplink_nas_transport_msg uplink_nas_transport;
} mm_msg; /* 5GS Mobility Management messages */
} fgmm_nas_message_plain_t;
/* Security protected 5GMM NAS message (5GS) */
typedef struct {
fgs_nas_message_security_header_t header;
fgmm_nas_message_plain_t plain;
} fgmm_nas_msg_security_protected_t;
/// 5GSM - 5GS session management
@@ -317,7 +298,7 @@ typedef struct {
/// Function prototypes
int mm_msg_encode(const MM_msg *mm_msg, uint8_t *buffer, uint32_t len);
int mm_msg_encode(const fgmm_nas_message_plain_t *mm_msg, uint8_t *buffer, uint32_t len);
int nas_protected_security_header_encode(uint8_t *buffer, const fgs_nas_message_security_header_t *header, int length);
int _nas_mm_msg_encode_header(const fgmm_msg_header_t *header, uint8_t *buffer, uint32_t len);
+13 -13
View File
@@ -48,15 +48,15 @@ int _nas_mm_msg_encode_header(const fgmm_msg_header_t *header, uint8_t *buffer,
return (size);
}
int mm_msg_encode(const MM_msg *mm_msg, uint8_t *buffer, uint32_t len)
int mm_msg_encode(const fgmm_nas_message_plain_t *p, uint8_t *buffer, uint32_t len)
{
LOG_FUNC_IN;
int header_result;
int encode_result;
uint8_t msg_type = mm_msg->header.message_type;
uint8_t msg_type = p->header.message_type;
/* First encode the EMM message header */
header_result = _nas_mm_msg_encode_header(&mm_msg->header, buffer, len);
/* First encode the 5GMM message header */
header_result = _nas_mm_msg_encode_header(&p->header, buffer, len);
if (header_result < 0) {
LOG_TRACE(ERROR,
@@ -71,29 +71,29 @@ int mm_msg_encode(const MM_msg *mm_msg, uint8_t *buffer, uint32_t len)
switch (msg_type) {
case FGS_REGISTRATION_REQUEST:
encode_result = encode_registration_request(&mm_msg->registration_request, buffer, len);
encode_result = encode_registration_request(&p->mm_msg.registration_request, buffer, len);
break;
case FGS_IDENTITY_RESPONSE:
encode_result = encode_fgmm_identity_response(buffer, &mm_msg->fgs_identity_response, len);
encode_result = encode_fgmm_identity_response(buffer, &p->mm_msg.fgs_identity_response, len);
break;
case FGS_AUTHENTICATION_RESPONSE:
encode_result = encode_fgs_authentication_response(&mm_msg->fgs_auth_response, buffer, len);
encode_result = encode_fgs_authentication_response(&p->mm_msg.fgs_auth_response, buffer, len);
break;
case FGS_SECURITY_MODE_COMPLETE:
encode_result = encode_fgs_security_mode_complete(&mm_msg->fgs_security_mode_complete, buffer, len);
encode_result = encode_fgs_security_mode_complete(&p->mm_msg.fgs_security_mode_complete, buffer, len);
break;
case FGS_UPLINK_NAS_TRANSPORT:
encode_result = encode_fgs_uplink_nas_transport(&mm_msg->uplink_nas_transport, buffer, len);
encode_result = encode_fgs_uplink_nas_transport(&p->mm_msg.uplink_nas_transport, buffer, len);
break;
case FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING:
encode_result =
encode_fgs_deregistration_request_ue_originating(&mm_msg->fgs_deregistration_request_ue_originating, buffer, len);
encode_fgs_deregistration_request_ue_originating(&p->mm_msg.fgs_deregistration_request_ue_originating, buffer, len);
break;
case FGS_SERVICE_REQUEST:
encode_result = encode_fgs_service_request(buffer, &mm_msg->service_request, len);
encode_result = encode_fgs_service_request(buffer, &p->mm_msg.service_request, len);
break;
default:
LOG_TRACE(ERROR, " Unexpected message type: 0x%x", mm_msg->header.message_type);
LOG_TRACE(ERROR, " Unexpected message type: 0x%x", p->header.message_type);
encode_result = TLV_ENCODE_WRONG_MESSAGE_TYPE;
break;
/* TODO: Handle not standard layer 3 messages: SERVICE_REQUEST */
@@ -103,7 +103,7 @@ int mm_msg_encode(const MM_msg *mm_msg, uint8_t *buffer, uint32_t len)
LOG_TRACE(ERROR,
" Failed to encode L3 EMM message 0x%x "
"(%d)",
mm_msg->header.message_type,
p->header.message_type,
encode_result);
}
+159 -181
View File
@@ -47,6 +47,7 @@
#include "PduSessionEstablishmentAccept.h"
#include "RegistrationAccept.h"
#include "SORTransparentContainer.h"
#include "FGSIdentityResponse.h"
#include "T.h"
#include "aka_functions.h"
#include "assertions.h"
@@ -428,29 +429,24 @@ 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)
{
int size = sizeof(fgmm_msg_header_t);
fgs_nas_message_t nas_msg = {0};
MM_msg *mm_msg;
fgmm_nas_message_plain_t plain = {0};
mm_msg = &nas_msg.plain.mm_msg;
// set header
mm_msg->header.ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_msg->header.security_header_type = PLAIN_5GS_MSG;
mm_msg->header.message_type = FGS_REGISTRATION_REQUEST;
// Plain 5GMM header
fgmm_msg_header_t *mm_header = &plain.header;
mm_header->ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_header->security_header_type = PLAIN_5GS_MSG;
mm_header->message_type = FGS_REGISTRATION_REQUEST;
size += 3;
// set registration request
mm_msg->registration_request.protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
size += 1;
mm_msg->registration_request.securityheadertype = PLAIN_5GS_MSG;
size += 1;
mm_msg->registration_request.messagetype = FGS_REGISTRATION_REQUEST;
size += 1;
mm_msg->registration_request.fgsregistrationtype = INITIAL_REGISTRATION;
mm_msg->registration_request.naskeysetidentifier.naskeysetidentifier = 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->registration_request.fgsmobileidentity, nas->guti);
size += fill_guti(&mm_msg->fgsmobileidentity, nas->guti);
} else {
size += fill_suci(&mm_msg->registration_request.fgsmobileidentity, nas->uicc);
size += fill_suci(&mm_msg->fgsmobileidentity, nas->uicc);
}
#if 0
@@ -465,20 +461,20 @@ void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
size += 3;
#endif
mm_msg->registration_request.presencemask |= REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_PRESENT;
mm_msg->registration_request.nruesecuritycapability.iei = REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_IEI;
mm_msg->registration_request.nruesecuritycapability.length = 8;
mm_msg->registration_request.nruesecuritycapability.fg_EA = 0xe0;
mm_msg->registration_request.nruesecuritycapability.fg_IA = 0x60;
mm_msg->registration_request.nruesecuritycapability.EEA = 0;
mm_msg->registration_request.nruesecuritycapability.EIA = 0;
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;
size += 10;
// encode the message
initialNasMsg->nas_data = malloc16_clear(size * sizeof(*initialNasMsg->nas_data));
nas->registration_request_buf = initialNasMsg->nas_data;
initialNasMsg->length = mm_msg_encode(mm_msg, initialNasMsg->nas_data, size);
initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size);
nas->registration_request_len = initialNasMsg->length;
}
@@ -486,47 +482,52 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
{
LOG_I(NAS, "Generate initial NAS message: Service Request\n");
int size = 0;
fgs_nas_message_t nas_msg = {0};
memset(&nas_msg, 0, sizeof(nas_msg));
// NAS is security protected if has valid security contexts
bool security_protected = nas->security_container->ciphering_context && nas->security_container->integrity_context;
MM_msg *mm_msg;
fgmm_nas_message_plain_t plain = {0};
fgs_service_request_msg_t *mm_msg;
fgmm_nas_msg_security_protected_t sp = {0};
fgmm_msg_header_t *mm_header;
if (security_protected) {
/* Set security protected 5GS NAS message header (see 9.1.1 of 3GPP TS 24.501) */
nas_msg.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
nas_msg.header.security_header_type = INTEGRITY_PROTECTED;
nas_msg.header.sequence_number = nas->security.nas_count_ul & 0xff;
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 += sizeof(fgs_nas_message_security_header_t);
mm_msg = &nas_msg.security_protected.plain.mm_msg;
mm_msg = &sp.plain.mm_msg.service_request;
// Plain 5GMM header
mm_header = &sp.plain.header;
} else {
// Set Mobility Management plain message header
mm_msg = &nas_msg.plain.mm_msg;
mm_msg = &plain.mm_msg.service_request;
// Plain 5GMM header
mm_header = &plain.header;
}
// Fill MM plain message header
mm_msg->header.ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_msg->header.security_header_type = PLAIN_5GS_MSG;
mm_msg->header.message_type = FGS_SERVICE_REQUEST;
size += sizeof(mm_msg->header);
mm_header->ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_header->security_header_type = PLAIN_5GS_MSG;
mm_header->message_type = FGS_SERVICE_REQUEST;
size += sizeof(*mm_header);
// Fill Service Request
// Service Type
mm_msg->service_request.serviceType = SERVICE_TYPE_DATA;
mm_msg->serviceType = SERVICE_TYPE_DATA;
// NAS key set identifier
mm_msg->service_request.naskeysetidentifier.naskeysetidentifier = NAS_KEY_SET_IDENTIFIER_NOT_AVAILABLE;
mm_msg->service_request.naskeysetidentifier.tsc = NAS_KEY_SET_IDENTIFIER_NATIVE;
mm_msg->naskeysetidentifier.naskeysetidentifier = NAS_KEY_SET_IDENTIFIER_NOT_AVAILABLE;
mm_msg->naskeysetidentifier.tsc = NAS_KEY_SET_IDENTIFIER_NATIVE;
size += 1;
// 5G-S-TMSI
size += fill_fgstmsi(&mm_msg->service_request.fiveg_s_tmsi, nas->guti);
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) {
// security protected encoding
int security_header_len = nas_protected_security_header_encode((char *)(initialNasMsg->nas_data), &(nas_msg.header), size);
int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, &sp.header, size);
initialNasMsg->length =
security_header_len
+ mm_msg_encode(mm_msg, (uint8_t *)(initialNasMsg->nas_data + security_header_len), size - security_header_len);
+ mm_msg_encode(&sp.plain, (uint8_t *)(initialNasMsg->nas_data + security_header_len), size - security_header_len);
/* ciphering */
uint8_t buf[initialNasMsg->length - 7];
nas_stream_cipher_t stream_cipher;
@@ -555,7 +556,7 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
initialNasMsg->nas_data[2 + i] = mac[i];
} else {
// plain encoding
initialNasMsg->length = mm_msg_encode(mm_msg, (uint8_t *)(initialNasMsg->nas_data), size);
initialNasMsg->length = mm_msg_encode(&plain, (uint8_t *)(initialNasMsg->nas_data), size);
LOG_I(NAS, "PLAIN_5GS_MSG initial NAS message: Service Request with length %d \n", initialNasMsg->length);
}
}
@@ -563,31 +564,25 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype, uicc_t *uicc)
{
int size = sizeof(fgmm_msg_header_t);
fgs_nas_message_t nas_msg;
memset(&nas_msg, 0, sizeof(fgs_nas_message_t));
MM_msg *mm_msg;
fgmm_nas_message_plain_t plain = {0};
mm_msg = &nas_msg.plain.mm_msg;
// set header
mm_msg->header.ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_msg->header.security_header_type = PLAIN_5GS_MSG;
mm_msg->header.message_type = FGS_IDENTITY_RESPONSE;
// Plain 5GMM header
fgmm_msg_header_t *mm_header = &plain.header;
mm_header->ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_header->security_header_type = PLAIN_5GS_MSG;
mm_header->message_type = FGS_IDENTITY_RESPONSE;
size += 3;
// set identity response
mm_msg->fgs_identity_response.protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
size += 1;
mm_msg->fgs_identity_response.securityheadertype = PLAIN_5GS_MSG;
size += 1;
mm_msg->fgs_identity_response.messagetype = FGS_IDENTITY_RESPONSE;
size += 1;
fgmm_identity_response_msg *mm_msg = &plain.mm_msg.fgs_identity_response;
if (identitytype == FGS_MOBILE_IDENTITY_SUCI) {
size += fill_suci(&mm_msg->fgs_identity_response.fgsmobileidentity, uicc);
size += fill_suci(&mm_msg->fgsmobileidentity, uicc);
}
// encode the message
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
initialNasMsg->length = mm_msg_encode(mm_msg, initialNasMsg->nas_data, size);
initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size);
}
static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *buf)
@@ -599,31 +594,23 @@ static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialN
memcpy(res.value, nas->security.res, 16);
int size = sizeof(fgmm_msg_header_t);
fgs_nas_message_t nas_msg;
memset(&nas_msg, 0, sizeof(fgs_nas_message_t));
MM_msg *mm_msg;
fgmm_nas_message_plain_t plain = {0};
mm_msg = &nas_msg.plain.mm_msg;
// set header
mm_msg->header.ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_msg->header.security_header_type = PLAIN_5GS_MSG;
mm_msg->header.message_type = FGS_AUTHENTICATION_RESPONSE;
// set authentication response
mm_msg->fgs_identity_response.protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
size += 1;
mm_msg->fgs_identity_response.securityheadertype = PLAIN_5GS_MSG;
size += 1;
mm_msg->fgs_identity_response.messagetype = FGS_AUTHENTICATION_RESPONSE;
size += 1;
// Plain 5GMM header
fgmm_msg_header_t *mm_header = &plain.header;
mm_header->ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_header->security_header_type = PLAIN_5GS_MSG;
mm_header->message_type = FGS_AUTHENTICATION_RESPONSE;
size += 3;
// set response parameter
mm_msg->fgs_auth_response.authenticationresponseparameter.res = res;
fgs_authentication_response_msg *mm_msg = &plain.mm_msg.fgs_auth_response;
mm_msg->authenticationresponseparameter.res = res;
size += 18;
// encode the message
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
initialNasMsg->length = mm_msg_encode(mm_msg, initialNasMsg->nas_data, size);
initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size);
// Free res value after encode
free(res.value);
}
@@ -639,37 +626,32 @@ int nas_itti_kgnb_refresh_req(instance_t instance, const uint8_t kgnb[32])
static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg)
{
int size = sizeof(fgmm_msg_header_t);
fgs_nas_message_t nas_msg;
memset(&nas_msg, 0, sizeof(fgs_nas_message_t));
MM_msg *mm_msg;
fgmm_nas_msg_security_protected_t nas_msg = {0};
nas_stream_cipher_t stream_cipher;
uint8_t mac[4];
// set security protected header
nas_msg.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
nas_msg.header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX;
nas_msg.header.sequence_number = nas->security.nas_count_ul & 0xff;
fgs_nas_message_security_header_t *sp = &nas_msg.header;
sp->protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
sp->security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX;
sp->sequence_number = nas->security.nas_count_ul & 0xff;
size += 7;
mm_msg = &nas_msg.security_protected.plain.mm_msg;
// Plain 5GMM Security Mode Complete msg
fgmm_nas_message_plain_t *plain = &nas_msg.plain;
// set header
mm_msg->header.ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_msg->header.security_header_type = PLAIN_5GS_MSG;
mm_msg->header.message_type = FGS_SECURITY_MODE_COMPLETE;
// Plain 5GMM header
fgmm_msg_header_t *mm_header = &plain->header;
mm_header->ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_header->security_header_type = PLAIN_5GS_MSG;
mm_header->message_type = FGS_SECURITY_MODE_COMPLETE;
size += 3;
// set security mode complete
mm_msg->fgs_security_mode_complete.protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
size += 1;
mm_msg->fgs_security_mode_complete.securityheadertype = PLAIN_5GS_MSG;
size += 1;
mm_msg->fgs_security_mode_complete.messagetype = FGS_SECURITY_MODE_COMPLETE;
size += 1;
// Plain 5GMM payload
fgs_security_mode_complete_msg *mm_msg = &plain->mm_msg.fgs_security_mode_complete;
size += fill_imeisv(&mm_msg->fgsmobileidentity, nas->uicc);
size += fill_imeisv(&mm_msg->fgs_security_mode_complete.fgsmobileidentity, nas->uicc);
mm_msg->fgs_security_mode_complete.fgsnasmessagecontainer.nasmessagecontainercontents.value = nas->registration_request_buf;
mm_msg->fgs_security_mode_complete.fgsnasmessagecontainer.nasmessagecontainercontents.length = nas->registration_request_len;
mm_msg->fgsnasmessagecontainer.nasmessagecontainercontents.value = nas->registration_request_buf;
mm_msg->fgsnasmessagecontainer.nasmessagecontainercontents.length = nas->registration_request_len;
size += (nas->registration_request_len + 2);
// encode the message
@@ -679,7 +661,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
initialNasMsg->length =
security_header_len
+ mm_msg_encode(mm_msg, (uint8_t *)(initialNasMsg->nas_data + security_header_len), size - security_header_len);
+ mm_msg_encode(plain, (uint8_t *)(initialNasMsg->nas_data + security_header_len), size - security_header_len);
/* ciphering */
uint8_t buf[initialNasMsg->length - 7];
@@ -774,29 +756,26 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas,
SORTransparentContainer *sortransparentcontainer)
{
int length = 0;
fgs_nas_message_t nas_msg;
nas_stream_cipher_t stream_cipher;
uint8_t mac[4];
memset(&nas_msg, 0, sizeof(fgs_nas_message_t));
fgs_nas_message_security_protected_t *sp_msg;
fgmm_nas_msg_security_protected_t sp = {0};
sp_msg = &nas_msg.security_protected;
// set security protected header
sp_msg->header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
sp_msg->header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
sp_msg->header.message_authentication_code = 0;
sp_msg->header.sequence_number = nas->security.nas_count_ul & 0xff;
sp.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
sp.header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
sp.header.message_authentication_code = 0;
sp.header.sequence_number = nas->security.nas_count_ul & 0xff;
length = 7;
// set plain 5GMM header
sp_msg->plain.mm_msg.header.ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
length += 1;
sp_msg->plain.mm_msg.header.security_header_type = PLAIN_5GS_MSG;
length += 1;
sp_msg->plain.mm_msg.header.message_type = FGS_REGISTRATION_COMPLETE;
length += 1;
fgmm_msg_header_t *mm_header = &sp.plain.header;
mm_header->ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_header->security_header_type = PLAIN_5GS_MSG;
mm_header->message_type = FGS_REGISTRATION_COMPLETE;
length += 3;
registration_complete_msg *mm_msg = &sp.plain.mm_msg.registration_complete;
if (sortransparentcontainer) {
sp_msg->plain.mm_msg.registration_complete.sortransparentcontainer = sortransparentcontainer;
mm_msg->sortransparentcontainer = sortransparentcontainer;
length += sortransparentcontainer->sortransparentcontainercontents.length;
}
@@ -804,19 +783,19 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas,
initialNasMsg->nas_data = malloc_or_fail(length * sizeof(*initialNasMsg->nas_data));
initialNasMsg->length = length;
// encode security protected header
int encoded = nas_protected_security_header_encode(initialNasMsg->nas_data, &sp_msg->header, length);
int encoded = nas_protected_security_header_encode(initialNasMsg->nas_data, &sp.header, length);
if (encoded < 0) {
LOG_E(NAS, "generateRegistrationComplete: failed to encode security protected header\n");
return;
}
// encode 5GMM plain header
encoded = _nas_mm_msg_encode_header(&sp_msg->plain.mm_msg.header, initialNasMsg->nas_data + encoded, length - encoded);
encoded = _nas_mm_msg_encode_header(mm_header, initialNasMsg->nas_data + encoded, length - encoded);
if (encoded < 0) {
LOG_E(NAS, "generateRegistrationComplete: failed to encode 5GMM plain header\n");
return;
}
encode_registration_complete(&sp_msg->plain.mm_msg.registration_complete, initialNasMsg->nas_data + encoded, length - encoded);
encode_registration_complete(mm_msg, initialNasMsg->nas_data + encoded, length - encoded);
/* ciphering */
uint8_t buf[initialNasMsg->length - 7];
@@ -863,36 +842,37 @@ static void handleDownlinkNASTransport(uint8_t *pdu_buffer, uint32_t msg_length)
static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, const nas_deregistration_req_t *req)
{
fgs_nas_message_t nas_msg = {0};
fgs_nas_message_security_protected_t *sp_msg;
sp_msg = &nas_msg.security_protected;
sp_msg->header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
sp_msg->header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
sp_msg->header.message_authentication_code = 0;
sp_msg->header.sequence_number = nas->security.nas_count_ul & 0xff;
int size = sizeof(sp_msg->header);
fgmm_nas_msg_security_protected_t sp_msg = {0};
fgs_nas_message_security_header_t *sp_header = &sp_msg.header;
sp_header->protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
sp_header->security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
sp_header->message_authentication_code = 0;
sp_header->sequence_number = nas->security.nas_count_ul & 0xff;
int size = sizeof(sp_msg.header);
fgs_deregistration_request_ue_originating_msg *dereg_req = &sp_msg->plain.mm_msg.fgs_deregistration_request_ue_originating;
dereg_req->protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
// Plain 5GMM header
fgmm_msg_header_t *mm_header = &sp_msg.plain.header;
mm_header->ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_header->security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX;
mm_header->message_type = FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING;
size += 3;
// Plain 5GMM
fgs_deregistration_request_ue_originating_msg *mm_msg = &sp_msg.plain.mm_msg.fgs_deregistration_request_ue_originating;
mm_msg->deregistrationtype.switchoff = NORMAL_DEREGISTRATION;
mm_msg->deregistrationtype.reregistration_required = REREGISTRATION_NOT_REQUIRED;
mm_msg->deregistrationtype.access_type = TGPP_ACCESS;
mm_msg->naskeysetidentifier.naskeysetidentifier = 1;
size += 1;
dereg_req->securityheadertype = INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX;
size += 1;
dereg_req->messagetype = FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING;
size += 1;
dereg_req->deregistrationtype.switchoff = NORMAL_DEREGISTRATION;
dereg_req->deregistrationtype.reregistration_required = REREGISTRATION_NOT_REQUIRED;
dereg_req->deregistrationtype.access_type = TGPP_ACCESS;
dereg_req->naskeysetidentifier.naskeysetidentifier = 1;
size += 1;
size += fill_guti(&dereg_req->fgsmobileidentity, nas->guti);
size += fill_guti(&mm_msg->fgsmobileidentity, nas->guti);
// encode the message
initialNasMsg->nas_data = calloc_or_fail(size, sizeof(*initialNasMsg->nas_data));
int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, &nas_msg.header, size);
int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, sp_header, size);
initialNasMsg->length =
security_header_len
+ mm_msg_encode(&sp_msg->plain.mm_msg, (uint8_t *)(initialNasMsg->nas_data + security_header_len), size - security_header_len);
+ mm_msg_encode(&sp_msg.plain, (uint8_t *)(initialNasMsg->nas_data + security_header_len), size - security_header_len);
nas_stream_cipher_t stream_cipher;
@@ -929,7 +909,6 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi
static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, nas_pdu_session_req_t *pdu_req)
{
int size = 0;
fgs_nas_message_t nas_msg = {0};
// setup pdu session establishment request
uint16_t req_length = 7;
@@ -943,69 +922,68 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
pdu_session_establish.pdusessiontype = pdu_req->pdusession_type;
encode_pdu_session_establishment_request(&pdu_session_establish, req_buffer);
MM_msg *mm_msg;
nas_stream_cipher_t stream_cipher;
uint8_t mac[4];
nas_msg.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
nas_msg.header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
nas_msg.header.sequence_number = nas->security.nas_count_ul & 0xff;
// 5GMM security protected message
fgmm_nas_msg_security_protected_t sp_msg = {0};
// 5GMM security protected message header
fgs_nas_message_security_header_t *sp_header = &sp_msg.header;
sp_header->protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
sp_header->security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
sp_header->sequence_number = nas->security.nas_count_ul & 0xff;
size += 7;
mm_msg = &nas_msg.security_protected.plain.mm_msg;
fgmm_nas_message_plain_t *plain = &sp_msg.plain;
// set header
mm_msg->header.ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_msg->header.security_header_type = PLAIN_5GS_MSG;
mm_msg->header.message_type = FGS_UPLINK_NAS_TRANSPORT;
// Plain 5GMM header
fgmm_msg_header_t *mm_header = &plain->header;
mm_header->ex_protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
mm_header->security_header_type = PLAIN_5GS_MSG;
mm_header->message_type = FGS_UPLINK_NAS_TRANSPORT;
size += 3;
// set uplink nas transport
mm_msg->uplink_nas_transport.protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
fgs_uplink_nas_transport_msg *mm_msg = &plain->mm_msg.uplink_nas_transport;
mm_msg->payloadcontainertype.iei = 0;
mm_msg->payloadcontainertype.type = 1;
size += 1;
mm_msg->uplink_nas_transport.securityheadertype = PLAIN_5GS_MSG;
size += 1;
mm_msg->uplink_nas_transport.messagetype = FGS_UPLINK_NAS_TRANSPORT;
size += 1;
mm_msg->uplink_nas_transport.payloadcontainertype.iei = 0;
mm_msg->uplink_nas_transport.payloadcontainertype.type = 1;
size += 1;
mm_msg->uplink_nas_transport.fgspayloadcontainer.payloadcontainercontents.length = req_length;
mm_msg->uplink_nas_transport.fgspayloadcontainer.payloadcontainercontents.value = req_buffer;
mm_msg->fgspayloadcontainer.payloadcontainercontents.length = req_length;
mm_msg->fgspayloadcontainer.payloadcontainercontents.value = req_buffer;
size += (2 + req_length);
mm_msg->uplink_nas_transport.pdusessionid = pdu_req->pdusession_id;
mm_msg->uplink_nas_transport.requesttype = 1;
mm_msg->pdusessionid = pdu_req->pdusession_id;
mm_msg->requesttype = 1;
size += 3;
const bool has_nssai_sd = pdu_req->sd != 0xffffff; // 0xffffff means "no SD", TS 23.003
const size_t nssai_len = has_nssai_sd ? 4 : 1;
mm_msg->uplink_nas_transport.snssai.length = nssai_len;
mm_msg->snssai.length = nssai_len;
// Fixme: it seems there are a lot of memory errors in this: this value was on the stack,
// but pushed in a itti message to another thread
// this kind of error seems in many places in 5G NAS
mm_msg->uplink_nas_transport.snssai.value = calloc(1, nssai_len);
mm_msg->uplink_nas_transport.snssai.value[0] = pdu_req->sst;
mm_msg->snssai.value = calloc(1, nssai_len);
mm_msg->snssai.value[0] = pdu_req->sst;
if (has_nssai_sd)
INT24_TO_BUFFER(pdu_req->sd, &mm_msg->uplink_nas_transport.snssai.value[1]);
INT24_TO_BUFFER(pdu_req->sd, &mm_msg->snssai.value[1]);
size += 1 + 1 + nssai_len;
int dnnSize = strlen(nas->uicc->dnnStr);
mm_msg->uplink_nas_transport.dnn.value = calloc(1, dnnSize + 1);
mm_msg->uplink_nas_transport.dnn.length = dnnSize + 1;
mm_msg->uplink_nas_transport.dnn.value[0] = dnnSize;
memcpy(mm_msg->uplink_nas_transport.dnn.value + 1, nas->uicc->dnnStr, dnnSize);
mm_msg->dnn.value = calloc(1, dnnSize + 1);
mm_msg->dnn.length = dnnSize + 1;
mm_msg->dnn.value[0] = dnnSize;
memcpy(mm_msg->dnn.value + 1, nas->uicc->dnnStr, dnnSize);
size += (1 + 1 + dnnSize + 1);
// encode the message
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, &nas_msg.header, size);
int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, sp_header, size);
initialNasMsg->length =
security_header_len
+ mm_msg_encode(mm_msg, (uint8_t *)(initialNasMsg->nas_data + security_header_len), size - security_header_len);
+ mm_msg_encode(plain, (uint8_t *)(initialNasMsg->nas_data + security_header_len), size - security_header_len);
// Free allocated memory after encode
free(req_buffer);
free(mm_msg->uplink_nas_transport.dnn.value);
free(mm_msg->uplink_nas_transport.snssai.value);
free(mm_msg->dnn.value);
free(mm_msg->snssai.value);
/* ciphering */
uint8_t buf[initialNasMsg->length - 7];
@@ -1153,7 +1131,7 @@ static void get_allowed_nssai(nr_nas_msg_snssai_t nssai[8], const uint8_t *pdu_b
return;
const uint8_t *end = pdu_buffer + pdu_length;
if (((nas_msg_header_t *)(pdu_buffer))->choice.security_protected_nas_msg_header_t.security_header_type > 0) {
if (((fgs_nas_message_security_header_t *)(pdu_buffer))->security_header_type > 0) {
pdu_buffer += SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH;
}