Files
openairinterface5g/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c
T
Guido Casati 88f294bed1 Handle NAS Authentication Reject in stack
Handle authentication not accepted by the network. The handler assumes the message
is not integrity protected, processes the received NAS message and logs whether a
EAP-failure is enclosed. The UE enters state: 5GMM-DEREGISTERED.

Not done in this commit: the UE shall performs actions as per 5.4.1.3.5 of
3GPP TS 24.501, including (1) Abort any ongoing 5GMM procedure
(2) Stop all active timers: T3510, T3516, T3517, T3519, T3520, T3521
(3) Delete stored SUCI. (4) handle EAP-failure message.
2025-06-18 16:29:00 +02:00

249 lines
7.6 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "fgmm_lib.h"
#include <string.h>
#include <arpa/inet.h> // For htons and ntohs
#include <stdlib.h> // For malloc and free
#include "common/utils/ds/byte_array.h"
#define IEI_LEN 1
#define GPRS_TIMER_LENGTH 3 // octets
#define FGS_NAS_CAUSE_LENGTH 1
#define MIN_EAP_MSG_LEN 7
#define MIN_EAP_CONTENTS_LEN 4
/**
* Encode PDU Session Status and PDU session reactivation result (optional IEs)
* According to 9.11.3.42 and 9.11.3.44 of 3GPP TS 24.501, both IEs share the same
* structure, therefore this function covers them both.
* @param iei IE identifier to distinguish between PDU Session Status and PDU session reactivation result.
* @param psi pointer to PDU Session Status IE buffer to be encoded: index i corresponds to PDU Session i
*/
int encode_pdu_session_ie(byte_array_t *buffer, nas_service_IEI_t iei, const uint8_t *psi)
{
if (buffer->len < MIN_PDU_SESSION_CONTENTS_LEN + 2) {
PRINT_NAS_ERROR("%s failed: buffer is too small", __func__);
return -1;
}
uint8_t *buf = buffer->buf;
int encoded = 0;
buf[encoded++] = iei;
buf[encoded++] = MIN_PDU_SESSION_CONTENTS_LEN; // no spare octets
// Initialize the PDU session status octets to zero
buf[encoded] = 0x00;
buf[encoded + 1] = 0x00;
/* Encode Octet 3 (PSI 1-7) and Octet 4 (PSI 8-15).
Set each PSI bit according to the psi array containing the content IEs.
Start from bit 1 of octet 3 (i.e. PSI(0)), which is spare and shall be coded as zero.
The enabled bit translates to either PDU Session Active or PDU Session Reactivation Result */
for (int i = 1; i < 8; i++) { // skip spare bit
buf[encoded] |= psi[i] << i;
}
encoded++;
for (int i = 8; i < MAX_NUM_PSI; i++) {
buf[encoded] |= psi[i] << i % 8;
}
encoded++;
return encoded;
}
/**
* Decode PDU Session Status and PDU session reactivation result (optional IEs)
* According to 9.11.3.42 and 9.11.3.44 of 3GPP TS 24.501, both IEs share the same
* structure, therefore this function covers them both.
* @param psi pointer to buffer for the PDU Session Status IE to be decoded
*/
int decode_pdu_session_ie(uint8_t *psi, const byte_array_t *buffer)
{
int decoded = 0;
uint8_t *buf = buffer->buf;
if (buffer->len < MIN_PDU_SESSION_CONTENTS_LEN + 2) {
PRINT_NAS_ERROR("%s failed: buffer length is too small", __func__);
return -1;
}
// start decoding from length IE (IEI is decoded in the caller)
uint8_t pdu_session_status_len = buf[decoded++];
if (pdu_session_status_len > MAX_PDU_SESSION_CONTENTS_LEN) {
PRINT_NAS_ERROR("decoded length is out of bound for PDU Session Status/Reactivation result\n");
return -1;
}
/* Decode PDU Session Status content IEs bits in octet 3 (PSI 1-7).
Store the result psi array.
Skip bit 1 of octet 3 (i.e. PSI(0)), which is spare and shall be coded as zero. */
for (int i = 1; i < 8; i++) { // skip spare bit
psi[i] = (buf[decoded] >> i) & 0x01;
}
decoded++;
/* Decode PDU Session Status content IEs bits in octet 4 (PSI 8-15).
Store the result psi array. */
for (int i = 8; i < MAX_NUM_PSI; i++) {
psi[i] = (buf[decoded] >> i % 8) & 0x01;
}
decoded++;
return decoded;
}
/* Encode GPRS Timer IE (3GPP TS 24.008 10.5.7.3) */
int encode_gprs_timer_ie(byte_array_t *buffer, nas_service_IEI_t iei, const gprs_timer_t *timer)
{
if (buffer->len < GPRS_TIMER_LENGTH) {
PRINT_NAS_ERROR("Buffer length is too short to encode the GPRS Timer IE\n");
return -1;
}
uint8_t *buf = buffer->buf;
int encoded = 0;
// IEI
buf[encoded++] = iei;
// length
buf[encoded++] = 1; // length field (1 octet)
// Unit and value (1 octet)
uint8_t encoded_byte = 0;
encoded_byte |= (timer->unit & 0x07) << 5;
encoded_byte |= timer->value & 0x1F;
buf[encoded++] = encoded_byte;
return encoded;
}
/* Decode GPRS Timer IE (3GPP TS 24.008 10.5.7.3) */
int decode_gprs_timer_ie(gprs_timer_t *timer, const byte_array_t *buffer)
{
int decoded = 1; // Skip length ie (1 octet)
// Extract unit and value
uint8_t *buf = buffer->buf;
timer->unit = (buf[decoded] >> 5) & 0x07;
timer->value = buf[decoded++] & 0x1F;
return decoded;
}
/** @brief Equality check for GPRS Timer */
bool eq_gprs_timer(const gprs_timer_t *a, const gprs_timer_t *b)
{
_NAS_EQ_CHECK_INT(a->value, b->value);
_NAS_EQ_CHECK_INT(a->unit, b->unit);
return true;
}
/** @brief Encode EAP message IE (3GPP TS 24.501 9.11.2.2) */
int encode_eap_msg_ie(byte_array_t *buffer, const byte_array_t *msg)
{
int encoded = 0;
// Sanity check on buffer length
if (buffer->len < MIN_EAP_MSG_LEN) {
PRINT_NAS_ERROR("Invalid buffer length %ld", buffer->len);
return -1;
}
// Sanity check on input length
if (msg->len < MIN_EAP_CONTENTS_LEN || msg->len > MAX_EAP_CONTENTS_LEN) {
PRINT_NAS_ERROR("Invalid EAP message length %ld", msg->len);
return -1;
}
// Encode IEI
buffer->buf[encoded++] = IEI_EAPMSG;
// Encode length of EAP message content
uint16_t len = htons(msg->len);
memcpy(&buffer->buf[encoded], &len, sizeof(len));
encoded += sizeof(len);
// Encode EAP message content
memcpy(&buffer->buf[encoded], msg->buf, msg->len);
encoded += msg->len;
return encoded;
}
/** @brief Decode EAP message IE (3GPP TS 24.501 9.11.2.2):
length of contents and message payload */
int decode_eap_msg_ie(byte_array_t *eap_msg, const byte_array_t *buffer)
{
int decoded = 0;
int min_len_to_decode = MIN_EAP_MSG_LEN - IEI_LEN;
// Check buffer length validity
if (buffer->len < min_len_to_decode) {
PRINT_NAS_ERROR("Invalid buffer for decoding EAP message IE");
return -1;
}
// Decode length IE
eap_msg->len = (buffer->buf[decoded] << 8) | buffer->buf[decoded + 1];
decoded += 2;
// Check payload length validity
if (eap_msg->len < MIN_EAP_CONTENTS_LEN || eap_msg->len > MAX_EAP_CONTENTS_LEN) {
PRINT_NAS_ERROR("Invalid EAP message length %ld", eap_msg->len);
return -1;
}
// Check for buffer overflow
if (buffer->len < decoded + eap_msg->len) {
PRINT_NAS_ERROR("Buffer too short for EAP message: %ld < %ld", buffer->len, decoded + eap_msg->len);
return -1;
}
// Copy EAP payload
memcpy(eap_msg->buf, &buffer->buf[decoded], eap_msg->len);
decoded += eap_msg->len;
return decoded;
}
int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause)
{
uint32_t encoded = 0;
if (buffer->len < FGS_NAS_CAUSE_LENGTH)
return -1;
buffer->buf[encoded++] = *cause;
return encoded;
}
int decode_fgs_nas_cause(cause_id_t *cause, const byte_array_t *buffer)
{
int decoded = 0;
if (buffer->len < FGS_NAS_CAUSE_LENGTH)
return -1; // nothing to decode
*cause = buffer->buf[decoded++];
return decoded;
}