Merge remote-tracking branch 'origin/add-support-eth-pdu-sess' into integration_2026_w05 (!3769)
Add Ethernet PDU session support and make PDU session request configurable
This MR adds support for Ethernet PDU sessions, and makes PDU sessions
configurable: per-PDU session ID, type (IPv4/IPv4v6/IPv6/Ethernet [1]),
DNN, NSSAI.
Concretely, it adds a new configuration file section pdu_sessions below
uicc0 that looks like this if everything is specified (default values
are shown):
uicc0:
[...]
pdu_sessions:
- id: 1
type: "IPv4"
nssai_sst: 1
nssai_sd: 0xffffff
dnn: "oai"
It is possible to list multiple PDU sessions (add new line - id: 2 to
request a second PDU session). It is backwards-compatible to the current
PDU session configuration (uicc0.dnn/nssai_sst/etc), the idea being that
either legacy or new configuration could be used, but (1) if
pdu_sessions exist, it will overwrite the legacy configuration, and (2)
multiple PDU sessions, and type, can only be configured using the new
config. The old parameters --extra-pdu-id and --default-pdu-id are not
accepted anymore. Documentation has been added to the UE tutorial.
It is possible to test an Ethernet PDU session [1]. It is possible to
test the PDU session inside the UE by verifying it has an TAP interface
oaitap_ue1, and ARPing the data network (arping has been added to
oai-nr-ue container for that purpose):
ip addr add 192.168.72.140/26 dev oaitap_ue1 # same subnet as data network!
ip link set dev oaitap_ue1 up
arping -c 20 -I oaitap_ue1 192.168.72.135 # will send ARP request in Ethernet frame to get IP address of data network
[1] See description MR !3769 for more information. On the UE side, only
the type has to be changed to "Ethernet".
This commit is contained in:
@@ -23,7 +23,6 @@
|
||||
#include <arpa/inet.h>
|
||||
#include "PduSessionEstablishmentAccept.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "fgs_nas_utils.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,8 @@ typedef enum { FOREACH_IEI(TO_ENUM) } pduSessionEstablishment_IEI_t;
|
||||
#define PDU_SESSION_TYPE_IPV4 0b001
|
||||
#define PDU_SESSION_TYPE_IPV6 0b010
|
||||
#define PDU_SESSION_TYPE_IPV4V6 0b011
|
||||
#define PDU_SESSION_TYPE_UNSTRUCT 0b100
|
||||
#define PDU_SESSION_TYPE_ETHER 0b101
|
||||
#define IPv4_ADDRESS_LENGTH 4 // length of the IPv4 address associated with a PDU session
|
||||
#define IPv6_INTERFACE_ID_LENGTH 8 // interface identifier for the IPv6 link local address
|
||||
#define SMF_IPv6_LLA_LENGTH 16
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
#include "aka_functions.h"
|
||||
#include "assertions.h"
|
||||
#include "common/utils/ds/byte_array.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "commonDef.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "kdf.h"
|
||||
@@ -1473,7 +1472,10 @@ static int capture_ipv6_addr(const uint8_t *addr, char *ip, size_t len)
|
||||
* @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, int instance_id, int pdu_session_id)
|
||||
static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg,
|
||||
int instance_id,
|
||||
int pdu_session_id,
|
||||
bool is_default)
|
||||
{
|
||||
uint8_t *addr = msg->pdu_addr_ie.pdu_addr_oct;
|
||||
|
||||
@@ -1481,13 +1483,13 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg
|
||||
case PDU_SESSION_TYPE_IPV4: {
|
||||
char ip[20];
|
||||
capture_ipv4_addr(&addr[0], ip, sizeof(ip));
|
||||
create_ue_ip_if(ip, NULL, instance_id, pdu_session_id);
|
||||
create_ue_ip_if(ip, NULL, instance_id, pdu_session_id, is_default);
|
||||
} break;
|
||||
|
||||
case PDU_SESSION_TYPE_IPV6: {
|
||||
char ipv6[40];
|
||||
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
|
||||
create_ue_ip_if(NULL, ipv6, instance_id, pdu_session_id);
|
||||
create_ue_ip_if(NULL, ipv6, instance_id, pdu_session_id, is_default);
|
||||
} break;
|
||||
|
||||
case PDU_SESSION_TYPE_IPV4V6: {
|
||||
@@ -1495,7 +1497,7 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg
|
||||
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
|
||||
char ipv4[20];
|
||||
capture_ipv4_addr(&addr[IPv6_INTERFACE_ID_LENGTH], ipv4, sizeof(ipv4));
|
||||
create_ue_ip_if(ipv4, ipv6, instance_id, pdu_session_id);
|
||||
create_ue_ip_if(ipv4, ipv6, instance_id, pdu_session_id, is_default);
|
||||
} break;
|
||||
|
||||
default:
|
||||
@@ -1507,7 +1509,7 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg
|
||||
/**
|
||||
* @brief Handle PDU Session Establishment Accept and process decoded message
|
||||
*/
|
||||
static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length, int instance)
|
||||
static void handle_pdu_session_accept(const nr_ue_nas_t *nas, uint8_t *pdu_buffer, uint32_t msg_length, int instance)
|
||||
{
|
||||
pdu_session_establishment_accept_msg_t msg = {0};
|
||||
int size = 0;
|
||||
@@ -1545,22 +1547,42 @@ static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length,
|
||||
size += decoded;
|
||||
|
||||
// decode PDU Session Establishment Accept
|
||||
if (!decode_pdu_session_establishment_accept_msg(&msg, pdu_buffer + size, msg_length))
|
||||
if (!decode_pdu_session_establishment_accept_msg(&msg, pdu_buffer + size, msg_length)) {
|
||||
LOG_E(NAS, "decode_pdu_session_establishment_accept_msg failure\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int idx;
|
||||
for (idx = 0; idx < nas->uicc->n_pdu_sessions; ++idx) {
|
||||
const pdu_session_config_t *pdu = &nas->uicc->pdu_sessions[idx];
|
||||
if (pdu->id == sm_header.pdu_session_id && pdu->type == msg.pdu_type)
|
||||
break;
|
||||
}
|
||||
if (idx == nas->uicc->n_pdu_sessions) {
|
||||
LOG_E(NAS,
|
||||
"PDU session establishment accept for ID %d type %d not in list of configured PDU sessions, abort transaction\n",
|
||||
sm_header.pdu_session_id,
|
||||
msg.pdu_type);
|
||||
return;
|
||||
}
|
||||
|
||||
// process PDU Session: pass ID -1 to not append PDU ID to interface
|
||||
bool is_default = idx == 0;
|
||||
if (msg.pdu_type == PDU_SESSION_TYPE_ETHER) {
|
||||
create_ue_eth_if(instance, sm_header.pdu_session_id, is_default);
|
||||
} else if (msg.pdu_addr_ie.pdu_length) {
|
||||
process_pdu_session_addr(&msg, instance, sm_header.pdu_session_id, is_default);
|
||||
} else {
|
||||
LOG_W(NAS, "Unhandled PDU session type %d, ignoring PDU session ID %d\n", msg.pdu_type, sm_header.pdu_session_id);
|
||||
}
|
||||
|
||||
// process PDU Session
|
||||
if (msg.pdu_addr_ie.pdu_length)
|
||||
process_pdu_session_addr(&msg, instance, sm_header.pdu_session_id);
|
||||
else
|
||||
LOG_W(NAS, "Optional PDU Address IE was not provided\n");
|
||||
|
||||
set_qfi(msg.qos_rules.rule->qfi, sm_header.pdu_session_id, instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle DL NAS Transport and process piggybacked 5GSM messages
|
||||
*/
|
||||
void handleDownlinkNASTransport(uint8_t * pdu_buffer, int pdu_length, int instance)
|
||||
void handleDownlinkNASTransport(const nr_ue_nas_t *nas, uint8_t * pdu_buffer, int pdu_length, int instance)
|
||||
{
|
||||
if (pdu_length < 17) {
|
||||
LOG_E(NAS, "Received DL NAS Transport message too short (%d)\n", pdu_length);
|
||||
@@ -1569,7 +1591,7 @@ void handleDownlinkNASTransport(uint8_t * pdu_buffer, int pdu_length, int instan
|
||||
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");
|
||||
handle_pdu_session_accept(pdu_buffer, pdu_length, instance);
|
||||
handle_pdu_session_accept(nas, pdu_buffer, pdu_length, instance);
|
||||
} else {
|
||||
LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type);
|
||||
}
|
||||
@@ -1688,19 +1710,16 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
|
||||
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->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->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->snssai.value[1]);
|
||||
size += 1 + 1 + nssai_len;
|
||||
int dnnSize = strlen(nas->uicc->dnnStr);
|
||||
int dnnSize = strlen(pdu_req->dnn);
|
||||
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);
|
||||
memcpy(mm_msg->dnn.value + 1, pdu_req->dnn, dnnSize);
|
||||
size += (1 + 1 + dnnSize + 1);
|
||||
|
||||
// encode the message
|
||||
@@ -1772,24 +1791,33 @@ static void send_nas_5gmm_ind(instance_t instance, const Guti5GSMobileIdentity_t
|
||||
itti_send_msg_to_task(TASK_RRC_NRUE, instance, msg);
|
||||
}
|
||||
|
||||
void request_pdusession(nr_ue_nas_t *nas, int pdusession_id)
|
||||
void request_pdusession(nr_ue_nas_t *nas, const pdu_session_config_t *pdu)
|
||||
{
|
||||
int t = pdu->type;
|
||||
AssertFatal(t == PDU_SESSION_TYPE_IPV4 || t == PDU_SESSION_TYPE_IPV6 || t == PDU_SESSION_TYPE_IPV4V6
|
||||
|| t == PDU_SESSION_TYPE_UNSTRUCT || t == PDU_SESSION_TYPE_ETHER,
|
||||
"illegal PDU session type %d\n",
|
||||
t);
|
||||
AssertFatal(t != PDU_SESSION_TYPE_UNSTRUCT, "unstructured PDU sessions not handled yet\n");
|
||||
MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_PDU_SESSION_REQ);
|
||||
NAS_PDU_SESSION_REQ(message_p).pdusession_id = pdusession_id;
|
||||
NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6
|
||||
NAS_PDU_SESSION_REQ(message_p).sst = nas->uicc->nssai_sst;
|
||||
NAS_PDU_SESSION_REQ(message_p).sd = nas->uicc->nssai_sd;
|
||||
nas_pdu_session_req_t *pdu_req = &NAS_PDU_SESSION_REQ(message_p);
|
||||
pdu_req->pdusession_id = pdu->id;
|
||||
// 24.501: joint PDU session type IEI (0x9-, Table 8.3.1.1.1) and type (9.11.4.11)
|
||||
pdu_req->pdusession_type = 0x90 | t;
|
||||
pdu_req->sst = pdu->nssai.sst;
|
||||
pdu_req->sd = pdu->nssai.sd;
|
||||
snprintf(pdu_req->dnn, sizeof(pdu_req->dnn), "%s", pdu->dnn);
|
||||
itti_send_msg_to_task(TASK_NAS_NRUE, nas->UE_id, message_p);
|
||||
}
|
||||
|
||||
static int get_user_nssai_idx(const nr_nas_msg_snssai_t allowed_nssai[NAS_MAX_NUMBER_SLICES], const nr_ue_nas_t *nas)
|
||||
static int get_user_nssai_idx(nssai_t ch_nssai, const nr_nas_msg_snssai_t allowed_nssai[NAS_MAX_NUMBER_SLICES])
|
||||
{
|
||||
for (int i = 0; i < NAS_MAX_NUMBER_SLICES; i++) {
|
||||
const nr_nas_msg_snssai_t *nssai = allowed_nssai + i;
|
||||
/* If it was received in Registration Accept, check the SD
|
||||
in the stored Allowed N-SSAI, else, consider the SD valid */
|
||||
bool sd_match = !nssai->sd || (nas->uicc->nssai_sd == *nssai->sd);
|
||||
if ((nas->uicc->nssai_sst == nssai->sst) && sd_match)
|
||||
bool sd_match = !nssai->sd || (ch_nssai.sd == *nssai->sd);
|
||||
if ((ch_nssai.sst == nssai->sst) && sd_match)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
@@ -1864,12 +1892,18 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff
|
||||
send_nas_uplink_data_req(nas, &initialNasMsg);
|
||||
LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n");
|
||||
}
|
||||
if (get_user_nssai_idx(msg.nas_allowed_nssai, nas) < 0) {
|
||||
LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n");
|
||||
} else {
|
||||
request_pdusession(nas, get_softmodem_params()->default_pdu_session_id);
|
||||
if (get_nrUE_params()->extra_pdu_id != -1) {
|
||||
request_pdusession(nas, get_nrUE_params()->extra_pdu_id);
|
||||
if (nas->uicc->n_pdu_sessions == 0)
|
||||
LOG_W(SIM, "no PDU sessions to request configured\n");
|
||||
for (const pdu_session_config_t *pdu = nas->uicc->pdu_sessions; pdu < nas->uicc->pdu_sessions + nas->uicc->n_pdu_sessions; ++pdu) {
|
||||
if (get_user_nssai_idx(pdu->nssai, msg.nas_allowed_nssai) < 0) {
|
||||
LOG_E(NAS,
|
||||
"PDU session ID %d NSSAI %d.%d: mismatch for allowed NSSAI. Couldn't request PDU session.\n",
|
||||
pdu->id,
|
||||
pdu->nssai.sst,
|
||||
pdu->nssai.sd);
|
||||
} else {
|
||||
LOG_I(NAS, "requested PDU session ID %d type %d NSSAI %d.%d DNN %s\n", pdu->id, pdu->type, pdu->nssai.sst, pdu->nssai.sd, pdu->dnn);
|
||||
request_pdusession(nas, pdu);
|
||||
}
|
||||
}
|
||||
// Free local message after processing
|
||||
@@ -2017,7 +2051,7 @@ void *nas_nrue(void *args_p)
|
||||
if (msg_type == FGS_REGISTRATION_ACCEPT) {
|
||||
handle_registration_accept(nas, ba.buf, ba.len);
|
||||
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
|
||||
handle_pdu_session_accept(ba.buf, ba.len, nas->UE_id);
|
||||
handle_pdu_session_accept(nas, ba.buf, ba.len, nas->UE_id);
|
||||
}
|
||||
|
||||
// Free NAS buffer memory after use (coming from RRC)
|
||||
@@ -2103,7 +2137,7 @@ void *nas_nrue(void *args_p)
|
||||
handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length);
|
||||
break;
|
||||
case FGS_DOWNLINK_NAS_TRANSPORT:
|
||||
handleDownlinkNASTransport(pdu_buffer, pdu_length, nas->UE_id);
|
||||
handleDownlinkNASTransport(nas, pdu_buffer, pdu_length, nas->UE_id);
|
||||
break;
|
||||
case FGS_REGISTRATION_ACCEPT:
|
||||
handle_registration_accept(nas, pdu_buffer, pdu_length);
|
||||
@@ -2114,7 +2148,7 @@ void *nas_nrue(void *args_p)
|
||||
nas->fiveGMM_state = FGS_DEREGISTERED;
|
||||
break;
|
||||
case FGS_PDU_SESSION_ESTABLISHMENT_ACC:
|
||||
handle_pdu_session_accept(pdu_buffer, pdu_length, nas->UE_id);
|
||||
handle_pdu_session_accept(nas, pdu_buffer, pdu_length, nas->UE_id);
|
||||
break;
|
||||
case FGS_PDU_SESSION_ESTABLISHMENT_REJ:
|
||||
LOG_E(NAS, "Received PDU Session Establishment reject\n");
|
||||
@@ -2159,10 +2193,11 @@ void *nas_nrue(void *args_p)
|
||||
} break;
|
||||
|
||||
case NAS_INIT_NOS1_IF: {
|
||||
const int pdu_session_id = get_softmodem_params()->default_pdu_session_id;
|
||||
const int pdu_session_id = DEFAULT_NOS1_PDU_ID;
|
||||
const char *ip = "10.0.1.2";
|
||||
const int qfi = 7;
|
||||
create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id);
|
||||
const bool is_default = true;
|
||||
create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id, is_default);
|
||||
set_qfi(qfi, pdu_session_id, nas->UE_id);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define __NR_NAS_MSG_SIM_H__
|
||||
|
||||
#include <common/utils/assertions.h>
|
||||
#include "common/5g_platform_types.h"
|
||||
#include <openair3/UICC/usim_interface.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -113,6 +114,6 @@ void *nas_nrue_task(void *args_p);
|
||||
void *nas_nrue(void *args_p);
|
||||
void nas_init_nrue(int num_ues);
|
||||
void nr_ue_create_ip_if(const char *ifnameprefix, const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id);
|
||||
void request_pdusession(nr_ue_nas_t *nas, int pdusession_id);
|
||||
void request_pdusession(nr_ue_nas_t *nas, const pdu_session_config_t *pdu);
|
||||
|
||||
#endif /* __NR_NAS_MSG_SIM_H__*/
|
||||
|
||||
@@ -45,7 +45,7 @@ Description Defines functions used to handle EPS bearer contexts.
|
||||
#include "esm_ebr.h"
|
||||
|
||||
#include "esm_ebr_context.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "common/utils/tuntap_if.h"
|
||||
|
||||
#include "emm_sap.h"
|
||||
#include "system.h"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
add_library(lib_uicc OBJECT usim_interface.c)
|
||||
add_library(lib_uicc OBJECT usim_interface.c pdu_session.c)
|
||||
target_include_directories(lib_uicc PRIVATE .)
|
||||
target_link_libraries(lib_uicc PRIVATE log_headers)
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include "pdu_session.h"
|
||||
// we can't include the file for PDU session type defines, as it pulls in too
|
||||
// much. However, we only use it for mapping types to integers, which are
|
||||
// standard defined, so it should be ok.
|
||||
//#include "openair3/NAS/NR_UE/5GS/5GSM/MSG/PduSessionEstablishmentAccept.h"
|
||||
#include "common/utils/utils.h"
|
||||
#include "common/config/config_paramdesc.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
|
||||
|
||||
// clang-format off
|
||||
// Note: Default PDU session ID 0 does not exist and will be replaced with PDU
|
||||
// session index if not set to a parameter > 0!
|
||||
#define PDU_SESS_PARAMS_DESC { \
|
||||
{"id", "PDU session ID\n", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
|
||||
{"type", "PDU session type\n", 0, .strptr=NULL, .defstrval="IPv4", TYPE_STRING, 0}, \
|
||||
{"nssai_sst", "NSSAI slice type\n", 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \
|
||||
{"nssai_sd", "NSSAI slice differentiator\n", 0, .uptr=NULL, .defintval=0xffffff, TYPE_UINT32, 0}, \
|
||||
{"dnn", "PDU session DNN (APN)\n", 0, .strptr=NULL, .defstrval="oai", TYPE_STRING, 0}, \
|
||||
}
|
||||
|
||||
#define PDU_SESS_PARAMS_CHECK { \
|
||||
{.s2 = {config_check_intrange, {0, 255}}}, \
|
||||
{.s3a = {config_checkstr_assign_integer, \
|
||||
{"IPv4", "IPv6", "IPv4v6", "Ethernet"}, \
|
||||
{1 /*PDU_SESSION_TYPE_IPV4*/, \
|
||||
2 /*PDU_SESSION_TYPE_IPV6*/, \
|
||||
3 /*PDU_SESSION_TYPE_IPV4V6*/, \
|
||||
5 /*PDU_SESSION_TYPE_ETHER*/}, \
|
||||
4}}, \
|
||||
{.s2 = {config_check_intrange, {1, 4}}}, \
|
||||
{.s2 = {config_check_intrange, {1, 0xffffff}}}, \
|
||||
{.s4 = {config_check_dnn}}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
static int config_check_dnn(configmodule_interface_t *cfg, paramdef_t *param)
|
||||
{
|
||||
const char *dnn = *param->strptr;
|
||||
int dnn_len = strlen(dnn);
|
||||
if (dnn_len > 102) {
|
||||
printf("DNN '%s' exceeds max len of 102 (is %d) (TS 24.501 §9.11.2.1A)\n", dnn, dnn_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check for valid characters in the APN (TS 23.003 §9.1)
|
||||
// we don't enforce all conditions
|
||||
const char *allowed = "abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789.-";
|
||||
while (*dnn) {
|
||||
if (!strchr(allowed, *dnn)) {
|
||||
printf("character '%c' in DNN '%s' is not allowed (TS 23.003 §9.1)\n", *dnn, *param->strptr);
|
||||
return -1;
|
||||
}
|
||||
dnn++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_pdu_session_configs(const char *uiccName, pdu_session_config_t *configs, int max_len)
|
||||
{
|
||||
paramdef_t pdu_sess_params[] = PDU_SESS_PARAMS_DESC;
|
||||
const int npsp = sizeofArray(pdu_sess_params);
|
||||
paramlist_def_t pdu_sess_list = {"pdu_sessions"};
|
||||
checkedparam_t pdu_sess_params_check[] = PDU_SESS_PARAMS_CHECK;
|
||||
static_assert(sizeofArray(pdu_sess_params) == sizeofArray(pdu_sess_params_check),
|
||||
"param_def_t array and corresponding checkedparam_t array should have the same size");
|
||||
for (int i = 0; i < sizeofArray(pdu_sess_params); ++i)
|
||||
pdu_sess_params[i].chkPptr = &pdu_sess_params_check[i];
|
||||
int ret = config_getlist(config_get_if(), &pdu_sess_list, pdu_sess_params, sizeofArray(pdu_sess_params), uiccName);
|
||||
if (ret < 0) {
|
||||
// couldn't load configuration from pdu_sessions, caller has to handle
|
||||
return -1;
|
||||
}
|
||||
|
||||
int num = pdu_sess_list.numelt;
|
||||
AssertFatal(num <= max_len, "cannot handle more than %d PDU sessions\n", max_len);
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
pdu_session_config_t *pdu = configs + i;
|
||||
paramdef_t *p = pdu_sess_list.paramarray[i];
|
||||
int id = *gpd(p, npsp, "id")->iptr;
|
||||
pdu->id = id > 0 ? id : i + 1; // if not user-specified ID, use PDU session index
|
||||
pdu->type = config_get_processedint(config_get_if(), (paramdef_t *)gpd(p, npsp, "type"));
|
||||
pdu->nssai.sst = *gpd(p, npsp, "nssai_sst")->iptr;
|
||||
pdu->nssai.sd = *gpd(p, npsp, "nssai_sd")->iptr;
|
||||
pdu->dnn = strdup(*gpd(p, npsp, "dnn")->strptr);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef PDU_SESSION_H_
|
||||
#define PDU_SESSION_H_
|
||||
|
||||
#include "common/5g_platform_types.h"
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
int type;
|
||||
nssai_t nssai;
|
||||
char *dnn; // [103]?
|
||||
} pdu_session_config_t;
|
||||
|
||||
int get_pdu_session_configs(const char *uiccName, pdu_session_config_t *configs, int max_len);
|
||||
|
||||
#endif /* PDU_SESSION_H_ */
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
#include <ctype.h>
|
||||
|
||||
#include "common/platform_constants.h"
|
||||
#include <openair3/UICC/usim_interface.h>
|
||||
#include <openair3/NAS/COMMON/milenage.h>
|
||||
extern uint16_t NB_UE_INST;
|
||||
@@ -76,10 +77,7 @@ uicc_t *init_uicc(char *sectionName) {
|
||||
// key, OPc, sqn, amf don't need to be read from the true USIM
|
||||
int ret = config_get(config_get_if(), uicc_params, sizeofArray(uicc_params), sectionName);
|
||||
AssertFatal(ret >= 0, "configuration couldn't be performed for uicc name: %s", sectionName);
|
||||
LOG_I(SIM,
|
||||
"UICC simulation: IMSI=%s, IMEISV=%s, Ki=%s, OPc=%s, DNN=%s, SST=0x%02x, SD=0x%06x\n",
|
||||
uicc->imsiStr, uicc->imeisvStr, uicc->keyStr, uicc->opcStr,
|
||||
uicc->dnnStr, uicc->nssai_sst, uicc->nssai_sd);
|
||||
LOG_I(SIM, "UICC simulation: IMSI=%s, IMEISV=%s, Ki=%s, OPc=%s\n", uicc->imsiStr, uicc->imeisvStr, uicc->keyStr, uicc->opcStr);
|
||||
to_hex(uicc->keyStr,uicc->key, sizeof(uicc->key) );
|
||||
to_hex(uicc->opcStr,uicc->opc, sizeof(uicc->opc) );
|
||||
to_hex(uicc->sqnStr,uicc->sqn, sizeof(uicc->sqn) );
|
||||
@@ -112,6 +110,36 @@ uicc_t * checkUicc(int Mod_id) {
|
||||
char uiccName[64];
|
||||
sprintf(uiccName,"uicc%d", Mod_id);
|
||||
uiccArray[Mod_id]=(void*)init_uicc(uiccName);
|
||||
uicc_t *uicc = uiccArray[Mod_id];
|
||||
uicc->n_pdu_sessions = get_pdu_session_configs(uiccName, uicc->pdu_sessions, sizeof(uicc->pdu_sessions));
|
||||
if (uicc->n_pdu_sessions > 0) {
|
||||
LOG_I(SIM, "overriding potential %s.dnn/nssai_sst/nssai_sd from %s.pdu_sessions\n", uiccName, uiccName);
|
||||
} else if (uicc->n_pdu_sessions < 0) {
|
||||
// we could not load from "new" pdu_sessions list, so read from "legacy"
|
||||
// config
|
||||
LOG_W(SIM,
|
||||
"loading PDU session parameters from legacy UICC configuration. Please update to use %s.pdu_sessions instead to make this warning disappear\n",
|
||||
uiccName);
|
||||
sleep(3);
|
||||
uicc->n_pdu_sessions = 1;
|
||||
pdu_session_config_t *pdu = &uicc->pdu_sessions[0];
|
||||
AssertFatal(uicc->dnnStr != NULL, "no default DNN, cannot create\n");
|
||||
pdu->id = DEFAULT_NOS1_PDU_ID; // any default would do
|
||||
pdu->dnn = strdup(uicc->dnnStr);
|
||||
pdu->nssai.sst = uicc->nssai_sst;
|
||||
pdu->nssai.sd = uicc->nssai_sd;
|
||||
pdu->type = 1; /* = PDU_SESSION_TYPE_IPV4 */
|
||||
} // else: uicc->n_pdu_sessions == 0 => don't request a PDU session
|
||||
for (int i = 0; i < uicc->n_pdu_sessions; ++i) {
|
||||
const pdu_session_config_t *pdu = &uicc->pdu_sessions[i];
|
||||
LOG_I(SIM,
|
||||
"will request PDU session ID %d, type %d, DNN %s, NSSAI %d.%6x\n",
|
||||
pdu->id,
|
||||
pdu->type,
|
||||
pdu->dnn,
|
||||
pdu->nssai.sst,
|
||||
pdu->nssai.sd);
|
||||
}
|
||||
}
|
||||
return (uicc_t*) uiccArray[Mod_id];
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <common/utils/load_module_shlib.h>
|
||||
#include <common/config/config_userapi.h>
|
||||
#include "common_lib.h"
|
||||
#include "pdu_session.h"
|
||||
|
||||
/* 3GPP glossary
|
||||
RES RESponse
|
||||
@@ -53,6 +54,8 @@ typedef struct {
|
||||
char *dnnStr;
|
||||
int nssai_sst;
|
||||
int nssai_sd;
|
||||
pdu_session_config_t pdu_sessions[256];
|
||||
int n_pdu_sessions;
|
||||
uint8_t key[16];
|
||||
uint8_t opc[16];
|
||||
uint8_t amf[2];
|
||||
|
||||
Reference in New Issue
Block a user