Refactor capture_pdu_session_establishment_accept_msg
* the goal of this commit is to refactor capture_pdu_session_establishment_accept_msg into a decoding function * PduSessionEstablishmentAccept.c is in the 5GSM library and shall only do encoding operations * handling of PDU Session Establishment accept message is done in nr_nas_msg.c * adopted new NAS decoding functions in the process * improved QoS rules decoding * convert getShort into a macro and add to NAS utils
This commit is contained in:
@@ -3,8 +3,4 @@ add_library(fgs_5gsm_lib OBJECT PduSessionEstablishRequest.c
|
||||
|
||||
target_link_libraries(fgs_5gsm_lib PUBLIC nas_common_ies_lib)
|
||||
|
||||
target_include_directories(fgs_5gsm_lib PUBLIC .
|
||||
../../5GMM/MSG # NOTE: to be removed in a later commit
|
||||
../../5GMM/IES # NOTE: to be removed in a later commit
|
||||
../../
|
||||
)
|
||||
target_include_directories(fgs_5gsm_lib PUBLIC . ../../)
|
||||
|
||||
@@ -24,101 +24,83 @@
|
||||
#include "PduSessionEstablishmentAccept.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "NR_NAS_defs.h"
|
||||
#include "fgs_nas_utils.h"
|
||||
|
||||
static uint16_t getShort(uint8_t *input)
|
||||
/**
|
||||
* @brief Returns the size of the single QoS rule IE
|
||||
*/
|
||||
static uint8_t get_len_qos_rule(qos_rule_t *rule)
|
||||
{
|
||||
uint16_t tmp16;
|
||||
memcpy(&tmp16, input, sizeof(tmp16));
|
||||
return htons(tmp16);
|
||||
return rule->length + sizeof(rule->id) + sizeof(rule->length);
|
||||
}
|
||||
|
||||
static int capture_ipv4_addr(const uint8_t *addr, char *ip, size_t len)
|
||||
/**
|
||||
* @brief Decode QoS Rule (9.11.4.13 of 3GPP TS 24.501)
|
||||
*/
|
||||
static qos_rule_t decode_qos_rule(uint8_t *buf)
|
||||
{
|
||||
return snprintf(ip, len, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
|
||||
}
|
||||
|
||||
static int capture_ipv6_addr(const uint8_t *addr, char *ip, size_t len)
|
||||
{
|
||||
// 24.501 Sec 9.11.4.10: "an interface identifier for the IPv6 link local
|
||||
// address": link local starts with fe80::, and only the last 64bits are
|
||||
// given (middle is zero)
|
||||
return snprintf(ip,
|
||||
len,
|
||||
"fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
addr[0],
|
||||
addr[1],
|
||||
addr[2],
|
||||
addr[3],
|
||||
addr[4],
|
||||
addr[5],
|
||||
addr[6],
|
||||
addr[7]);
|
||||
qos_rule_t qos_rule = {0};
|
||||
// octet 4
|
||||
qos_rule.id = *buf++;
|
||||
// octet 5 - 6
|
||||
GET_SHORT(buf, qos_rule.length);
|
||||
buf += sizeof(qos_rule.length);
|
||||
// octet 7
|
||||
qos_rule.oc = (*(buf)&0xE0) >> 5;
|
||||
qos_rule.dqr = (*(buf)&0x10) >> 4;
|
||||
qos_rule.nb_pf = *buf++ & 0x0F;
|
||||
// octet 8 - m
|
||||
for (int i = 0; i < qos_rule.nb_pf; i++) {
|
||||
packet_filter_t pf;
|
||||
if (qos_rule.oc == ROC_CREATE_NEW_QOS_RULE || qos_rule.oc == ROC_MODIFY_QOS_RULE_ADD_PF
|
||||
|| qos_rule.oc == ROC_MODIFY_QOS_RULE_REPLACE_PF) {
|
||||
pf.pf_type.type_1.pf_dir = (*buf & 0x30) >> 4;
|
||||
pf.pf_type.type_1.pf_id = *buf++ & 0x0F;
|
||||
pf.pf_type.type_1.length = *buf++;
|
||||
buf += pf.pf_type.type_1.length; // skip PF content
|
||||
} else if (qos_rule.oc == ROC_MODIFY_QOS_RULE_DELETE_PF) {
|
||||
pf.pf_type.type_2.pf_id = *buf++;
|
||||
}
|
||||
}
|
||||
// octet m + 1
|
||||
qos_rule.precendence = *buf++;
|
||||
// octet m + 2
|
||||
qos_rule.qfi = *buf++ & 0x3F;
|
||||
return qos_rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PDU session establishment accept (8.3.2 of 3GPP TS 24.501)
|
||||
* network to UE
|
||||
*/
|
||||
void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_length)
|
||||
int decode_pdu_session_establishment_accept_msg(pdu_session_establishment_accept_msg_t *psea_msg, uint8_t *buffer, uint32_t msg_length)
|
||||
{
|
||||
fgs_nas_message_security_header_t sec_nas_hdr;
|
||||
pdu_session_establishment_accept_msg_t psea_msg;
|
||||
uint8_t *curPtr = buffer;
|
||||
// Security protected NAS header (7 bytes)
|
||||
sec_nas_hdr.protocol_discriminator = *curPtr++;
|
||||
sec_nas_hdr.security_header_type = *curPtr++;
|
||||
uint32_t tmp;
|
||||
memcpy(&tmp, buffer, sizeof(tmp));
|
||||
sec_nas_hdr.message_authentication_code = htonl(tmp);
|
||||
curPtr += sizeof(sec_nas_hdr.message_authentication_code);
|
||||
sec_nas_hdr.sequence_number = *curPtr++;
|
||||
// Security protected plain NAS message
|
||||
fgmm_msg_header_t header;
|
||||
header.ex_protocol_discriminator = *curPtr++;
|
||||
header.security_header_type = *curPtr++;
|
||||
header.message_type = *curPtr++;
|
||||
// Payload container type and spare (1 octet)
|
||||
curPtr++;
|
||||
// Payload container length
|
||||
curPtr += sizeof(getShort(curPtr));
|
||||
/* Mandatory Presence IEs */
|
||||
fgsm_msg_header_t *sm_header = &psea_msg.header;
|
||||
sm_header->ex_protocol_discriminator = *curPtr++;
|
||||
sm_header->pdu_session_id = *curPtr++;
|
||||
sm_header->pti = *curPtr++;
|
||||
sm_header->message_type = *curPtr++;
|
||||
psea_msg.pdu_type = *curPtr & 0x0f;
|
||||
psea_msg.ssc_mode = (*curPtr++ & 0xf0) >> 4;
|
||||
psea_msg.qos_rules.length = getShort(curPtr);
|
||||
curPtr += sizeof(psea_msg.qos_rules.length);
|
||||
/* Supports the capture of only one QoS Rule, it should be changed for multiple QoS Rules */
|
||||
qos_rule_t qos_rule;
|
||||
qos_rule.id = *curPtr++;
|
||||
qos_rule.length = getShort(curPtr);
|
||||
curPtr += sizeof(qos_rule.length);
|
||||
qos_rule.oc = (*(curPtr)&0xE0) >> 5;
|
||||
qos_rule.dqr = (*(curPtr)&0x10) >> 4;
|
||||
qos_rule.nb_pf = *curPtr++ & 0x0F;
|
||||
|
||||
if (qos_rule.nb_pf) {
|
||||
packet_filter_t pf;
|
||||
|
||||
if (qos_rule.oc == ROC_CREATE_NEW_QOS_RULE || qos_rule.oc == ROC_MODIFY_QOS_RULE_ADD_PF
|
||||
|| qos_rule.oc == ROC_MODIFY_QOS_RULE_REPLACE_PF) {
|
||||
pf.pf_type.type_1.pf_dir = (*curPtr & 0x30) >> 4;
|
||||
pf.pf_type.type_1.pf_id = *curPtr++ & 0x0F;
|
||||
pf.pf_type.type_1.length = *curPtr++;
|
||||
curPtr += (qos_rule.nb_pf * pf.pf_type.type_1.length); /* Ommit the Packet filter List */
|
||||
} else if (qos_rule.oc == ROC_MODIFY_QOS_RULE_DELETE_PF) {
|
||||
curPtr += qos_rule.nb_pf;
|
||||
}
|
||||
/* Mandatory PDU Session Establishment Accept IEs */
|
||||
// PDU Session Type (half octet)
|
||||
psea_msg->pdu_type = *curPtr & 0x0f;
|
||||
// SSC Mode (half octet)
|
||||
psea_msg->ssc_mode = (*curPtr++ & 0xf0) >> 4;
|
||||
// Authorized QoS Rules
|
||||
auth_qos_rule_t *qos_rules = &psea_msg->qos_rules;
|
||||
// Length of the rule IEs (2 octets)
|
||||
GET_SHORT(curPtr, qos_rules->length);
|
||||
curPtr += sizeof(qos_rules->length);
|
||||
/* Decode rule IEs as long as the total length
|
||||
of all IEs (qos_rules->length) is not reached */
|
||||
uint16_t rules_tot_len = 0;
|
||||
while (rules_tot_len < qos_rules->length)
|
||||
{
|
||||
qos_rules->rule[0] = decode_qos_rule(curPtr);
|
||||
rules_tot_len += get_len_qos_rule(&qos_rules->rule[0]);
|
||||
curPtr += rules_tot_len;
|
||||
}
|
||||
// Session-AMBR (M)
|
||||
psea_msg->sess_ambr.length = *curPtr++;
|
||||
curPtr += psea_msg->sess_ambr.length; // skip content
|
||||
|
||||
qos_rule.prcd = *curPtr++;
|
||||
qos_rule.qfi = *curPtr++;
|
||||
psea_msg.sess_ambr.length = *curPtr++;
|
||||
curPtr += psea_msg.sess_ambr.length; /* Ommit the Seassion-AMBR */
|
||||
uint8_t *resPtr = curPtr;
|
||||
|
||||
/* Optional Presence IEs */
|
||||
while (curPtr < buffer + msg_length) {
|
||||
@@ -130,11 +112,11 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_
|
||||
break;
|
||||
|
||||
case IEI_PDU_ADDRESS:
|
||||
psea_msg.pdu_addr_ie.pdu_length = *curPtr++;
|
||||
psea_msg->pdu_addr_ie.pdu_length = *curPtr++;
|
||||
|
||||
/* Octet 3 */
|
||||
// PDU type (3 bits)
|
||||
psea_msg.pdu_addr_ie.pdu_type = *curPtr & 0x07;
|
||||
psea_msg->pdu_addr_ie.pdu_type = *curPtr & 0x07;
|
||||
// SMF's IPv6 link local address (1 bit)
|
||||
uint8_t si6lla = (*curPtr >> 3) & 0x01;
|
||||
if (si6lla)
|
||||
@@ -143,37 +125,29 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_
|
||||
|
||||
/* Octet 4 to n */
|
||||
// PDU address information
|
||||
uint8_t *addr = psea_msg.pdu_addr_ie.pdu_addr_oct;
|
||||
if (psea_msg.pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV4) {
|
||||
uint8_t *addr = psea_msg->pdu_addr_ie.pdu_addr_oct;
|
||||
if (psea_msg->pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV4) {
|
||||
for (int i = 0; i < IPv4_ADDRESS_LENGTH; ++i)
|
||||
addr[i] = *curPtr++;
|
||||
char ip[20];
|
||||
capture_ipv4_addr(&addr[0], ip, sizeof(ip));
|
||||
tun_config(1, ip, NULL, "oaitun_ue");
|
||||
setup_ue_ipv4_route(1, ip, "oaitun_ue");
|
||||
LOG_I(NAS, "Received PDU Session Establishment Accept, UE IP: %u.%u.%u.%u\n", addr[0], addr[1], addr[2], addr[3]);
|
||||
} else if (psea_msg.pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV6) {
|
||||
LOG_I(NAS, "Received PDU Session Establishment Accept, UE IPv4: %u.%u.%u.%u\n", addr[0], addr[1], addr[2], addr[3]);
|
||||
} else if (psea_msg->pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV6) {
|
||||
for (int i = 0; i < IPv6_INTERFACE_ID_LENGTH; ++i)
|
||||
addr[i] = *curPtr++;
|
||||
char ipv6[40];
|
||||
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
|
||||
tun_config(1, NULL, ipv6, "oaitun_ue");
|
||||
} else if (psea_msg.pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV4V6) {
|
||||
LOG_I(NAS, "Received PDU Session Establishment Accept, UE IPv6: %u.%u.%u.%u.%u.%u.%u.%u\n",
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
|
||||
} else if (psea_msg->pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV4V6) {
|
||||
// 24.501 Sec 9.11.4.10: "If the PDU session type value indicates
|
||||
// IPv4v6, the PDU address information in octet 4 to octet 11
|
||||
// contains an interface identifier for the IPv6 link local address
|
||||
// and in octet 12 to octet 15 contains an IPv4 address."
|
||||
for (int i = 0; i < IPv4_ADDRESS_LENGTH + IPv6_INTERFACE_ID_LENGTH; ++i)
|
||||
addr[i] = *curPtr++;
|
||||
char ipv6[40];
|
||||
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
|
||||
char ipv4[20];
|
||||
capture_ipv4_addr(&addr[IPv6_INTERFACE_ID_LENGTH], ipv4, sizeof(ipv4));
|
||||
tun_config(1, ipv4, ipv6, "oaitun_ue");
|
||||
setup_ue_ipv4_route(1, ipv4, "oaitun_ue");
|
||||
LOG_I(NAS, "Received PDU Session Establishment Accept, UE IPv4v6: %u.%u.%u.%u/%u.%u.%u.%u.%u.%u.%u.%u\n",
|
||||
addr[0], addr[1], addr[2], addr[3],
|
||||
addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11]);
|
||||
} else {
|
||||
LOG_E(NAS, "unknown/unhandled PDU session establishment accept PDU type %d\n", psea_msg.pdu_addr_ie.pdu_type);
|
||||
curPtr += psea_msg.pdu_addr_ie.pdu_length;
|
||||
LOG_E(NAS, "unknown/unhandled PDU session establishment accept PDU type %d\n", psea_msg->pdu_addr_ie.pdu_type);
|
||||
curPtr += psea_msg->pdu_addr_ie.pdu_length;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -192,48 +166,50 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_
|
||||
break;
|
||||
|
||||
case IEI_MAPPED_EPS: {
|
||||
uint16_t mapped_eps_length = getShort(curPtr);
|
||||
uint16_t mapped_eps_length = 0;
|
||||
GET_SHORT(curPtr, mapped_eps_length);
|
||||
curPtr += mapped_eps_length;
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_EAP_MSG: {
|
||||
uint16_t eap_length = getShort(curPtr);
|
||||
uint16_t eap_length = 0;
|
||||
GET_SHORT(curPtr, eap_length);
|
||||
curPtr += (eap_length + sizeof(eap_length));
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_AUTH_QOS_DESC: {
|
||||
psea_msg.qos_fd_ie.length = getShort(curPtr);
|
||||
curPtr += (psea_msg.qos_fd_ie.length + sizeof(psea_msg.qos_fd_ie.length));
|
||||
GET_SHORT(curPtr, psea_msg->qos_fd_ie.length);
|
||||
curPtr += (psea_msg->qos_fd_ie.length + sizeof(psea_msg->qos_fd_ie.length));
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_EXT_CONF_OPT: {
|
||||
psea_msg.ext_pp_ie.length = getShort(curPtr);
|
||||
curPtr += (psea_msg.ext_pp_ie.length + sizeof(psea_msg.ext_pp_ie.length));
|
||||
GET_SHORT(curPtr, psea_msg->ext_pp_ie.length);
|
||||
curPtr += (psea_msg->ext_pp_ie.length + sizeof(psea_msg->ext_pp_ie.length));
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_DNN: {
|
||||
psea_msg.dnn_ie.dnn_length = *curPtr++;
|
||||
psea_msg->dnn_ie.dnn_length = *curPtr++;
|
||||
char apn[APN_MAX_LEN];
|
||||
|
||||
if (psea_msg.dnn_ie.dnn_length <= APN_MAX_LEN && psea_msg.dnn_ie.dnn_length >= APN_MIN_LEN) {
|
||||
memcpy(apn, curPtr, psea_msg.dnn_ie.dnn_length);
|
||||
if (psea_msg->dnn_ie.dnn_length <= APN_MAX_LEN && psea_msg->dnn_ie.dnn_length >= APN_MIN_LEN) {
|
||||
memcpy(apn, curPtr, psea_msg->dnn_ie.dnn_length);
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - APN: %s\n", apn);
|
||||
} else
|
||||
LOG_E(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - DNN IE has invalid length\n");
|
||||
|
||||
resPtr = curPtr;
|
||||
curPtr = buffer + msg_length; // we force stop processing
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
PRINT_NAS_ERROR("Unknown IEI %d\n", psea_iei);
|
||||
curPtr = buffer + msg_length; // we force stop processing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return resPtr - buffer;
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
#define PDU_SESSION_ESTABLISHMENT_ACCEPT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "fgs_nas_utils.h"
|
||||
#include "NR_NAS_defs.h" // TEMP: to be removed in later commit
|
||||
|
||||
/* PDU Session Establish Accept Optional IE Identifiers - TS 24.501 Table 8.3.2.1.1 */
|
||||
|
||||
@@ -79,6 +79,8 @@ typedef enum { FOREACH_IEI(TO_ENUM) } pduSessionEstablishment_IEI_t;
|
||||
#define APN_MAX_LEN 100
|
||||
#define APN_MIN_LEN 1
|
||||
|
||||
#define MAX_NUM_QOS_RULES 64
|
||||
|
||||
/* Mandatory Presence IE - TS 24.501 Table 8.3.2.1.1 */
|
||||
|
||||
typedef struct packet_filter_create_qos_rule_s {
|
||||
@@ -99,17 +101,26 @@ typedef struct packet_filter_s {
|
||||
} packet_filter_t;
|
||||
|
||||
typedef struct qos_rule_s {
|
||||
uint8_t id; /* QoS rule identifier */
|
||||
uint16_t length; /* Length of QoS Rule */
|
||||
uint8_t oc; /* Rule operation code (3bits) */
|
||||
uint8_t dqr; /* DQR bit (1 bit) */
|
||||
uint8_t nb_pf; /* Number of packet filters (4 bits) */
|
||||
uint8_t prcd; /* QoS rule precedence */
|
||||
uint8_t qfi; /* QoS Flow Identifier */
|
||||
// QoS rule identifier
|
||||
uint8_t id;
|
||||
// Length of QoS Rule
|
||||
uint16_t length;
|
||||
// Rule operation code
|
||||
uint8_t oc;
|
||||
// Default QoS Rule
|
||||
bool dqr;
|
||||
// Number of packet filters
|
||||
uint8_t nb_pf;
|
||||
// QoS rule precedence
|
||||
uint8_t precendence;
|
||||
// QoS Flow Identifier
|
||||
uint8_t qfi;
|
||||
} qos_rule_t;
|
||||
|
||||
typedef struct auth_qos_rules_s {
|
||||
uint16_t length; /* Length of QoS rules IE */
|
||||
// QoS rules (M)
|
||||
qos_rule_t rule[MAX_NUM_QOS_RULES];
|
||||
} auth_qos_rule_t; /* QoS Rule as defined in 24.501 Figure 9.11.4.13.2 */
|
||||
|
||||
typedef struct session_ambr_s {
|
||||
@@ -147,20 +158,24 @@ typedef struct qos_fd_s {
|
||||
} qos_fd_t; /* TS 24.501 9.11.4.12 - Ommited, only length is processed*/
|
||||
|
||||
typedef struct pdu_session_establishment_accept_msg_s {
|
||||
/* Mandatory presence */
|
||||
fgsm_msg_header_t header;
|
||||
uint8_t pdu_type; /* PDU Session Type */
|
||||
uint8_t ssc_mode; /* SSC mode */
|
||||
auth_qos_rule_t qos_rules; /* Authorized QoS rules */
|
||||
session_ambr_t sess_ambr; /* Session-AMBR */
|
||||
|
||||
/* Optional presence */
|
||||
dnn_t dnn_ie; /* Data Network Name */
|
||||
pdu_address_t pdu_addr_ie; /* PDU Address */
|
||||
ext_pP_t ext_pp_ie; /* Extended Protocol Configuration Options */
|
||||
qos_fd_t qos_fd_ie; /* QoS flow descriptions */
|
||||
// PDU Session Type (M)
|
||||
uint8_t pdu_type;
|
||||
// Selected SSC Mode (M)
|
||||
uint8_t ssc_mode;
|
||||
// Authorized QoS rules (M)
|
||||
auth_qos_rule_t qos_rules;
|
||||
// Session-AMBR (M)
|
||||
session_ambr_t sess_ambr;
|
||||
// Data Network Name (O)
|
||||
dnn_t dnn_ie;
|
||||
// PDU Address (O)
|
||||
pdu_address_t pdu_addr_ie;
|
||||
// Extended Protocol Configuration Options (O)
|
||||
ext_pP_t ext_pp_ie;
|
||||
// QoS flow descriptions (O)
|
||||
qos_fd_t qos_fd_ie;
|
||||
} pdu_session_establishment_accept_msg_t; /* 24.501 Table 8.3.2.1.1 */
|
||||
|
||||
void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_length);
|
||||
int decode_pdu_session_establishment_accept_msg(pdu_session_establishment_accept_msg_t *psea_msg, uint8_t *buffer, uint32_t msg_length);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#define FGS_NAS_UTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h> // For memcpy
|
||||
|
||||
#define PRINT_NAS_ERROR(...) fprintf(stderr, ##__VA_ARGS__)
|
||||
|
||||
@@ -51,4 +53,10 @@ typedef struct {
|
||||
#define TO_TEXT(LabEl, nUmID) {nUmID, #LabEl},
|
||||
#define TO_ENUM(LabEl, nUmID ) LabEl = nUmID,
|
||||
|
||||
#define GET_SHORT(input, size) ({ \
|
||||
uint16_t tmp16; \
|
||||
memcpy(&tmp16, (input), sizeof(tmp16)); \
|
||||
size += htons(tmp16); \
|
||||
})
|
||||
|
||||
#endif // FGS_NAS_UTILS_H
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
#include "openair3/UTILS/conversions.h"
|
||||
#include "secu_defs.h"
|
||||
#include "utils.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
|
||||
#include "fgs_nas_utils.h"
|
||||
|
||||
#define MAX_NAS_UE 4
|
||||
|
||||
@@ -815,6 +817,121 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Capture IPv4 PDU Session Address
|
||||
*/
|
||||
static int capture_ipv4_addr(const uint8_t *addr, char *ip, size_t len)
|
||||
{
|
||||
return snprintf(ip, len, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Capture IPv6 PDU Session Address
|
||||
*/
|
||||
static int capture_ipv6_addr(const uint8_t *addr, char *ip, size_t len)
|
||||
{
|
||||
// 24.501 Sec 9.11.4.10: "an interface identifier for the IPv6 link local
|
||||
// address": link local starts with fe80::, and only the last 64bits are
|
||||
// given (middle is zero)
|
||||
return snprintf(ip,
|
||||
len,
|
||||
"fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
addr[0],
|
||||
addr[1],
|
||||
addr[2],
|
||||
addr[3],
|
||||
addr[4],
|
||||
addr[5],
|
||||
addr[6],
|
||||
addr[7]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Process PDU Session Address in PDU Session Establishment Accept message
|
||||
* and configure the tun interface
|
||||
*/
|
||||
static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg)
|
||||
{
|
||||
uint8_t *addr = msg->pdu_addr_ie.pdu_addr_oct;
|
||||
|
||||
switch (msg->pdu_addr_ie.pdu_type) {
|
||||
case PDU_SESSION_TYPE_IPV4: {
|
||||
char ip[20];
|
||||
capture_ipv4_addr(&addr[0], ip, sizeof(ip));
|
||||
tun_config(1, ip, NULL, "oaitun_ue");
|
||||
setup_ue_ipv4_route(1, ip, "oaitun_ue");
|
||||
} break;
|
||||
|
||||
case PDU_SESSION_TYPE_IPV6: {
|
||||
char ipv6[40];
|
||||
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
|
||||
tun_config(1, NULL, ipv6, "oaitun_ue");
|
||||
} break;
|
||||
|
||||
case PDU_SESSION_TYPE_IPV4V6: {
|
||||
char ipv6[40];
|
||||
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
|
||||
char ipv4[20];
|
||||
capture_ipv4_addr(&addr[IPv6_INTERFACE_ID_LENGTH], ipv4, sizeof(ipv4));
|
||||
tun_config(1, ipv4, ipv6, "oaitun_ue");
|
||||
setup_ue_ipv4_route(1, ipv4, "oaitun_ue");
|
||||
} break;
|
||||
|
||||
default:
|
||||
LOG_E(NAS, "Unknown PDU Session Address type %d\n", msg->pdu_addr_ie.pdu_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle PDU Session Establishment Accept and process decoded message
|
||||
*/
|
||||
static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length)
|
||||
{
|
||||
pdu_session_establishment_accept_msg_t msg = {0};
|
||||
int size = 0;
|
||||
int decoded = 0;
|
||||
|
||||
// Security protected NAS header (7 bytes)
|
||||
fgs_nas_message_security_header_t sec_nas_hdr = {0};
|
||||
if ((decoded = decode_5gs_security_protected_header(&sec_nas_hdr, pdu_buffer, msg_length)) < 0) {
|
||||
LOG_E(NAS, "decode_5gs_security_protected_header failure in PDU Session Establishment Accept decoding\n");
|
||||
return;
|
||||
}
|
||||
size += decoded;
|
||||
|
||||
// decode plain 5GMM message header
|
||||
fgmm_msg_header_t mm_header = {0};
|
||||
if ((decoded = decode_5gmm_msg_header(&mm_header, pdu_buffer + size, msg_length - size)) < 0) {
|
||||
LOG_E(NAS, "decode_5gmm_msg_header failure in PDU Session Establishment Accept decoding\n");
|
||||
return;
|
||||
}
|
||||
size += decoded;
|
||||
|
||||
/* Process container (5GSM message) */
|
||||
// Payload container type and spare (1 octet)
|
||||
size++;
|
||||
// Payload container length
|
||||
uint16_t iei_len = 0;
|
||||
GET_SHORT(pdu_buffer + size, iei_len);
|
||||
size += sizeof(iei_len);
|
||||
// decode plain 5GSM message header
|
||||
fgsm_msg_header_t sm_header = {0};
|
||||
if ((decoded = decode_5gsm_msg_header(&sm_header, pdu_buffer + size, msg_length - size)) < 0) {
|
||||
LOG_E(NAS, "decode_5gsm_msg_header failure in PDU Session Establishment Accept decoding\n");
|
||||
return;
|
||||
}
|
||||
size += decoded;
|
||||
|
||||
// decode PDU Session Establishment Accept
|
||||
if (!decode_pdu_session_establishment_accept_msg(&msg, pdu_buffer + size, msg_length))
|
||||
LOG_E(NAS, "decode_pdu_session_establishment_accept_msg failure\n");
|
||||
|
||||
// process PDU Session
|
||||
process_pdu_session_addr(&msg);
|
||||
set_qfi_pduid(msg.qos_rules.rule->qfi, sm_header.pdu_session_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle DL NAS Transport and process piggybacked 5GSM messages
|
||||
*/
|
||||
@@ -823,7 +940,7 @@ static void handleDownlinkNASTransport(uint8_t *pdu_buffer, uint32_t msg_length)
|
||||
uint8_t msg_type = *(pdu_buffer + 16);
|
||||
if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
|
||||
LOG_A(NAS, "Received PDU Session Establishment Accept in DL NAS Transport\n");
|
||||
capture_pdu_session_establishment_accept_msg(pdu_buffer, msg_length);
|
||||
handle_pdu_session_accept(pdu_buffer, msg_length);
|
||||
} else {
|
||||
LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type);
|
||||
}
|
||||
@@ -1281,7 +1398,7 @@ void *nas_nrue(void *args_p)
|
||||
if (msg_type == FGS_REGISTRATION_ACCEPT) {
|
||||
handle_registration_accept(nas, pdu_buffer, pdu_length);
|
||||
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
|
||||
capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length);
|
||||
handle_pdu_session_accept(pdu_buffer, pdu_length);
|
||||
}
|
||||
|
||||
// Free NAS buffer memory after use (coming from RRC)
|
||||
@@ -1378,7 +1495,7 @@ void *nas_nrue(void *args_p)
|
||||
LOG_I(NAS, "received deregistration accept\n");
|
||||
break;
|
||||
case FGS_PDU_SESSION_ESTABLISHMENT_ACC:
|
||||
capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length);
|
||||
handle_pdu_session_accept(pdu_buffer, pdu_length);
|
||||
break;
|
||||
case FGS_PDU_SESSION_ESTABLISHMENT_REJ:
|
||||
LOG_E(NAS, "Received PDU Session Establishment reject\n");
|
||||
|
||||
Reference in New Issue
Block a user