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:
@@ -12,8 +12,7 @@ uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
|
||||
MACRLCs = (
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
pdu_sessions = (
|
||||
{ id = 1; dnn = "oai"; nssai_sst = 1; },
|
||||
{ id = 2; dnn = "oai"; nssai_sst = 1; }
|
||||
)
|
||||
}
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
@@ -2,8 +2,7 @@ uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
|
||||
position0 = {
|
||||
|
||||
@@ -2,8 +2,7 @@ uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
|
||||
position0 = {
|
||||
|
||||
@@ -2,8 +2,9 @@ uicc0:
|
||||
imsi: 208990100001100
|
||||
key: fec86ba6eb707ed08905757b1bb44b8f
|
||||
opc: C42449363BBAD02B66D16BC975D77CC1
|
||||
dnn: oai
|
||||
nssai_sst: 1
|
||||
pdu_sessions:
|
||||
- dnn: oai
|
||||
nssai_sst: 1
|
||||
|
||||
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@ uicc0:
|
||||
imsi: 208990100001100
|
||||
key: fec86ba6eb707ed08905757b1bb44b8f
|
||||
opc: C42449363BBAD02B66D16BC975D77CC1
|
||||
dnn: oai
|
||||
nssai_sst: 1
|
||||
pdu_sessions:
|
||||
- dnn: oai
|
||||
nssai_sst: 1
|
||||
|
||||
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@ uicc0 = {
|
||||
imsi = "208970100001127";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "c42449363bbad02b66d16bc975d77cc1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
@@ -12,9 +12,7 @@ uicc0 = {
|
||||
imsi = "208950000000031";
|
||||
key = "0c0a34601d4f07677303652c0462535b";
|
||||
opc= "63bfa50ee6523365ff14c1f45f88737d";
|
||||
dnn= "oai";
|
||||
nssai_sst=222;
|
||||
nssai_sd=123;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 222; nssai_sd = 123; });
|
||||
}
|
||||
|
||||
MACRLCs = (
|
||||
|
||||
@@ -12,9 +12,7 @@ uicc0 = {
|
||||
imsi = "2089900007487";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
nssai_sd=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; nssai_sd = 1; });
|
||||
}
|
||||
|
||||
MACRLCs = (
|
||||
|
||||
@@ -518,8 +518,7 @@ uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -338,7 +338,7 @@ services:
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time
|
||||
-r 106 --numerology 1 -C 3619200000
|
||||
--uicc0.imsi 208990100001101 --uicc0.nssai_sst 2
|
||||
--uicc0.imsi 208990100001101 --uicc0.pdu_sessions.[0].nssai_sst 2
|
||||
--rfsimulator.[0].serveraddr 192.168.78.3
|
||||
depends_on:
|
||||
- oai-du2
|
||||
@@ -368,7 +368,7 @@ services:
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time
|
||||
-r 106 --numerology 1 -C 3619200000
|
||||
--uicc0.imsi 208990100001102 --uicc0.nssai_sst 3
|
||||
--uicc0.imsi 208990100001102 --uicc0.pdu_sessions.[0].nssai_sst 3
|
||||
--rfsimulator.[0].serveraddr 192.168.78.4
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
depends_on:
|
||||
|
||||
@@ -2,71 +2,61 @@ uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc1 = {
|
||||
imsi = "208990100001101";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc2 = {
|
||||
imsi = "208990100001102";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc3 = {
|
||||
imsi = "208990100001103";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc4 = {
|
||||
imsi = "208990100001104";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc5 = {
|
||||
imsi = "208990100001105";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc6 = {
|
||||
imsi = "208990100001106";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc7 = {
|
||||
imsi = "208990100001107";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc8 = {
|
||||
imsi = "208990100001108";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
uicc9 = {
|
||||
imsi = "208990100001109";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
|
||||
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
@@ -149,7 +149,7 @@ services:
|
||||
- NET_RAW # for ping
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim -r 25 --numerology 0 --uicc0.imsi 208990100001100 --band 66 -C 2152680000 --CO -400000000 --ssb 48
|
||||
--rfsimulator.[0].serveraddr 192.168.71.141 --extra-pdu-id 2 --log_config.global_log_options level,nocolor,time
|
||||
--rfsimulator.[0].serveraddr 192.168.71.141 --log_config.global_log_options level,nocolor,time
|
||||
--telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.150 --telnetsrv.listenport 8091
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0
|
||||
depends_on:
|
||||
@@ -160,7 +160,7 @@ services:
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
- ../../conf_files/nrue.uicc.2pdu.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-uesoftmodem"
|
||||
start_period: 10s
|
||||
|
||||
@@ -144,7 +144,7 @@ int config_cmdlineonly_getlist(configmodule_interface_t *cfg,
|
||||
paramlist_def_t *ParamList,
|
||||
paramdef_t *params,
|
||||
int numparams,
|
||||
char *prefix)
|
||||
const char *prefix)
|
||||
{
|
||||
ParamList->numelt = 0;
|
||||
return 0;
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
struct configmodule_interface;
|
||||
typedef int (*configmodule_getfunc_t)(struct configmodule_interface *, paramdef_t *, int numparams, const char *prefix);
|
||||
typedef int (
|
||||
*configmodule_getlistfunc_t)(struct configmodule_interface *, paramlist_def_t *, paramdef_t *, int numparams, char *prefix);
|
||||
*configmodule_getlistfunc_t)(struct configmodule_interface *, paramlist_def_t *, paramdef_t *, int numparams, const char *prefix);
|
||||
typedef int (*configmodule_setfunc_t)(paramdef_t *cfgoptions, int numoptions, const char *prefix);
|
||||
typedef void (*configmodule_endfunc_t)(struct configmodule_interface *cfg);
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ int config_get(configmodule_interface_t *cfgif, paramdef_t *params, int numparam
|
||||
return ret;
|
||||
}
|
||||
|
||||
int config_getlist(configmodule_interface_t *cfg, paramlist_def_t *ParamList, paramdef_t *params, int numparams, char *prefix)
|
||||
int config_getlist(configmodule_interface_t *cfg, paramlist_def_t *ParamList, paramdef_t *params, int numparams, const char *prefix)
|
||||
{
|
||||
if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
|
||||
fprintf(stderr,"[CONFIG] config_get skipped, config module not properly initialized\n");
|
||||
|
||||
@@ -62,7 +62,7 @@ int config_assign_ipv4addr(configmodule_interface_t *cfg, paramdef_t *cfgoptions
|
||||
#define CONFIG_CHECKALLSECTIONS "ALLSECTIONS"
|
||||
int config_check_unknown_cmdlineopt(configmodule_interface_t *cfg, char *prefix);
|
||||
int config_get(configmodule_interface_t *cfg, paramdef_t *params, int numparams, const char *prefix);
|
||||
int config_getlist(configmodule_interface_t *cfg, paramlist_def_t *ParamList, paramdef_t *params, int numparams, char *prefix);
|
||||
int config_getlist(configmodule_interface_t *cfg, paramlist_def_t *ParamList, paramdef_t *params, int numparams, const char *prefix);
|
||||
|
||||
/* apis to set some of the paramdef_t fields before using the get/getlist api's */
|
||||
void config_set_checkfunctions(paramdef_t *params, checkedparam_t *checkfunctions, int numparams);
|
||||
|
||||
@@ -100,5 +100,8 @@
|
||||
// SDAP
|
||||
#define MAX_QOS_FLOWS 64
|
||||
|
||||
// SDAP/5G NAS NOS1
|
||||
#define DEFAULT_NOS1_PDU_ID 10
|
||||
|
||||
#define SPEED_OF_LIGHT 299792458 // in m/s
|
||||
#endif /* __PLATFORM_CONSTANTS_H__ */
|
||||
|
||||
@@ -14,7 +14,7 @@ add_subdirectory(nr)
|
||||
add_subdirectory(LOG)
|
||||
add_subdirectory(threadPool)
|
||||
add_subdirectory(time_manager)
|
||||
add_library(utils utils.c system.c time_meas.c time_stat.c tun_if.c)
|
||||
add_library(utils utils.c system.c time_meas.c time_stat.c tuntap_if.c)
|
||||
target_include_directories(utils PUBLIC .)
|
||||
target_link_libraries(utils PRIVATE ${T_LIB})
|
||||
if (ENABLE_TESTS)
|
||||
|
||||
@@ -172,7 +172,11 @@ static int add_pdu_session(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
if (!nas)
|
||||
ERROR_MSG_RET("No NAS context found for UE_ID %d\n", ue_id);
|
||||
|
||||
request_pdusession(nas, pdusession_id);
|
||||
DevAssert(nas->uicc);
|
||||
nssai_t nssai = {nas->uicc->nssai_sst, nas->uicc->nssai_sd};
|
||||
pdu_session_config_t c = {pdusession_id, 1 /* = PDU_SESSION_TYPE_IPV4 */, nssai, nas->uicc->dnnStr};
|
||||
nas->uicc->pdu_sessions[nas->uicc->n_pdu_sessions++] = c;
|
||||
request_pdusession(nas, &c);
|
||||
prnt("Triggered PDU session request for UE %d with ID %d\n", ue_id, pdusession_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "tun_if.h"
|
||||
#include "tuntap_if.h"
|
||||
#include "common/platform_constants.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/system.h"
|
||||
@@ -38,7 +37,7 @@
|
||||
int nas_sock_fd[MAX_MOBILES_PER_ENB * 2]; // Allocated for both LTE UE and NR UE.
|
||||
int nas_sock_mbms_fd;
|
||||
|
||||
int tun_alloc(const char *dev)
|
||||
int tuntap_alloc(int flag, const char *dev)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd, err;
|
||||
@@ -54,7 +53,8 @@ int tun_alloc(const char *dev)
|
||||
*
|
||||
* IFF_NO_PI - Do not provide packet information
|
||||
*/
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
DevAssert(flag == IFF_TUN || flag == IFF_TAP);
|
||||
ifr.ifr_flags = flag | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
|
||||
if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
|
||||
close(fd);
|
||||
@@ -76,7 +76,7 @@ int tun_alloc(const char *dev)
|
||||
|
||||
int tun_init_mbms(char *ifname)
|
||||
{
|
||||
nas_sock_mbms_fd = tun_alloc(ifname);
|
||||
nas_sock_mbms_fd = tuntap_alloc(IFF_TUN, ifname);
|
||||
|
||||
if (nas_sock_mbms_fd == -1) {
|
||||
LOG_E(UTIL, "Error opening mbms socket %s (%d:%s)\n", ifname, errno, strerror(errno));
|
||||
@@ -96,7 +96,7 @@ int tun_init_mbms(char *ifname)
|
||||
|
||||
int tun_init(const char *ifname, int instance_id)
|
||||
{
|
||||
nas_sock_fd[instance_id] = tun_alloc(ifname);
|
||||
nas_sock_fd[instance_id] = tuntap_alloc(IFF_TUN, ifname);
|
||||
|
||||
if (nas_sock_fd[instance_id] == -1) {
|
||||
LOG_E(UTIL, "Error opening socket %s (%d:%s)\n", ifname, errno, strerror(errno));
|
||||
@@ -158,42 +158,47 @@ static bool setInterfaceParameter(int sock_fd, const char *ifn, int af, const ch
|
||||
}
|
||||
|
||||
|
||||
typedef enum { INTERFACE_DOWN, INTERFACE_UP } if_action_t;
|
||||
/*
|
||||
* \brief bring interface up (up != 0) or down (up == 0)
|
||||
* \brief Get an interface's flags.
|
||||
* \param[in] sock_fd socket to use for getting the flags
|
||||
* \param[in] ifn the interface name for which to get flags
|
||||
* \param[out] flags the flags of the interface
|
||||
* \return true on success, false otherwise
|
||||
*/
|
||||
static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_action)
|
||||
static bool get_if_flags(int sock_fd, const char *ifn, short *flags)
|
||||
{
|
||||
const char *action = if_action == INTERFACE_DOWN ? "DOWN" : "UP";
|
||||
|
||||
struct ifreq ifr = {0};
|
||||
strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
/* get flags of this interface: see netdevice(7) */
|
||||
bool success = ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t)&ifr) == 0;
|
||||
if (!success && if_action == INTERFACE_DOWN && errno == ENODEV) {
|
||||
LOG_W(OIP, "trying to remove non-existant device %s\n", ifn);
|
||||
return true;
|
||||
int success = ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t)&ifr) == 0;
|
||||
if (!success) {
|
||||
LOG_W(OIP, "On interface %s: ioctl() failed: %d, %s\n", ifn, errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
LOG_D(OIP, "Got flags for %s: 0x%x (action: %s)\n", ifn, ifr.ifr_flags, action);
|
||||
|
||||
if (if_action == INTERFACE_UP) {
|
||||
ifr.ifr_flags |= IFF_UP | IFF_NOARP | IFF_POINTOPOINT;
|
||||
ifr.ifr_flags &= ~IFF_MULTICAST;
|
||||
} else {
|
||||
ifr.ifr_flags &= ~IFF_UP;
|
||||
}
|
||||
|
||||
success = ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t)&ifr) == 0;
|
||||
if (!success)
|
||||
goto fail_interface_state;
|
||||
LOG_D(OIP, "Interface %s successfully set %s\n", ifn, action);
|
||||
|
||||
*flags = ifr.ifr_flags;
|
||||
return true;
|
||||
}
|
||||
|
||||
fail_interface_state:
|
||||
LOG_E(OIP, "Bringing interface %s for %s: ioctl call failed: %d, %s\n", action, ifn, errno, strerror(errno));
|
||||
return false;
|
||||
/*
|
||||
* \brief Set an interface's flags.
|
||||
* \param[in] sock_fd socket to use for setting the flags
|
||||
* \param[in] ifn the interface name for which to set flags
|
||||
* \param[in] flags the flags to set for the interface
|
||||
* \return true on success, false otherwise
|
||||
*/
|
||||
static bool set_if_flags(int sock_fd, const char *ifn, short flags)
|
||||
{
|
||||
struct ifreq ifr = {0};
|
||||
strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name) - 1);
|
||||
ifr.ifr_flags = flags;
|
||||
|
||||
int success = ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t)&ifr) == 0;
|
||||
if (!success) {
|
||||
LOG_W(OIP, "On interface %s: ioctl() failed: %d, %s\n", ifn, errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,11 +232,13 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6)
|
||||
close(sock_fd);
|
||||
}
|
||||
|
||||
// if successfully set IP addresses: set iterface up, disable ARP, no
|
||||
// multicast, point-to-point
|
||||
if (success)
|
||||
success = change_interface_state(sock_fd, ifname, INTERFACE_UP);
|
||||
success = set_if_flags(sock_fd, ifname, (IFF_UP | IFF_NOARP | IFF_POINTOPOINT) & ~IFF_MULTICAST);
|
||||
|
||||
if (success)
|
||||
LOG_I(OIP, "Interface %s successfully configured, IPv4 %s, IPv6 %s\n", ifname, ipv4, ipv6);
|
||||
LOG_A(OIP, "TUN Interface %s successfully configured, IPv4 %s, IPv6 %s\n", ifname, ipv4, ipv6);
|
||||
else
|
||||
LOG_E(OIP, "Interface %s couldn't be configured (IPv4 %s, IPv6 %s)\n", ifname, ipv4, ipv6);
|
||||
|
||||
@@ -239,6 +246,25 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool tap_config(const char* ifname)
|
||||
{
|
||||
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
LOG_E(UTIL, "Failed creating socket for interface management: %d, %s\n", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = set_if_flags(sock_fd, ifname, IFF_UP);
|
||||
|
||||
if (success)
|
||||
LOG_A(OIP, "TAP interface %s successfully configured\n", ifname);
|
||||
else
|
||||
LOG_E(OIP, "Tap interface %s couldn't be configured\n", ifname);
|
||||
|
||||
close(sock_fd);
|
||||
return success;
|
||||
}
|
||||
|
||||
void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4)
|
||||
{
|
||||
int table_id = instance_id - 1 + 10000;
|
||||
@@ -267,14 +293,16 @@ int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id)
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d", ifprefix, instance_id + 1);
|
||||
}
|
||||
|
||||
int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id)
|
||||
int tuntap_generate_ue_ifname(char *ifname, int flag, int instance_id, int pdu_session_id)
|
||||
{
|
||||
DevAssert(flag == IFF_TUN || flag == IFF_TAP);
|
||||
char pdu_session_string[10];
|
||||
snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id);
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d%s", "oaitun_ue", instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
|
||||
const char *basename = flag == IFF_TUN ? "oaitun_ue" : "oaitap_ue";
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d%s", basename, instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
|
||||
}
|
||||
|
||||
void tun_destroy(const char *dev)
|
||||
void tuntap_destroy(const char *dev)
|
||||
{
|
||||
// Use a new socket for ioctl operations
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
@@ -283,11 +311,12 @@ void tun_destroy(const char *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = change_interface_state(fd, dev, INTERFACE_DOWN);
|
||||
// interface not up => down
|
||||
short flags;
|
||||
bool success = get_if_flags(fd, dev, &flags);
|
||||
success = success && set_if_flags(fd, dev, flags & ~IFF_UP);
|
||||
if (success) {
|
||||
LOG_I(UTIL, "Interface %s is now down.\n", dev);
|
||||
} else {
|
||||
LOG_E(UTIL, "Could not bring interface %s down.\n", dev);
|
||||
}
|
||||
} // no else: get_if_flags()/set_if_flags() should have printed error
|
||||
close(fd);
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
/*!
|
||||
* \brief This function generates the name of the interface based on the prefix and
|
||||
@@ -34,7 +35,17 @@
|
||||
* \param[in] instance_id unique instance number
|
||||
*/
|
||||
int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id);
|
||||
int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id);
|
||||
|
||||
/*!
|
||||
* \brief This function generates the name of the interface based on the prefix and
|
||||
* the instance id for a UE.
|
||||
*
|
||||
* \param[in,out] ifname name of the interface
|
||||
* \param[in] flag IFF_TUN (for TUN device) or IFF_TAP (for TAP device)
|
||||
* \param[in] ifprefix prefix of the interface
|
||||
* \param[in] instance_id unique instance number
|
||||
*/
|
||||
int tuntap_generate_ue_ifname(char *ifname, int flag, int instance_id, int pdu_session_id);
|
||||
|
||||
/*!
|
||||
* \brief This function initializes the TUN interface
|
||||
@@ -50,9 +61,8 @@ int tun_init(const char *ifname, int instance_id);
|
||||
int tun_init_mbms(char *ifname);
|
||||
|
||||
/*!
|
||||
* \brief This function initializes the nasmesh interface using the basic values,
|
||||
* basic address, network mask and broadcast address, as the default configured
|
||||
* ones
|
||||
* \brief Initializes the TUN interface with an IPv4 or IPv6 address and
|
||||
* activates the interface.
|
||||
* \param[in] ifname name of the interface
|
||||
* \param[in] ipv4 IPv4 address of this interface as a string
|
||||
* \param[in] ipv6 IPv6 address of this interface as a string
|
||||
@@ -62,6 +72,15 @@ int tun_init_mbms(char *ifname);
|
||||
*/
|
||||
bool tun_config(const char* ifname, const char *ipv4, const char *ipv6);
|
||||
|
||||
/*!
|
||||
* \brief Initializes and activates the TAP interface.
|
||||
* \param[in] ifname name of the interface
|
||||
* \return true on success, otherwise false
|
||||
* \note
|
||||
* @ingroup _nas
|
||||
*/
|
||||
bool tap_config(const char* ifname);
|
||||
|
||||
/*!
|
||||
* \brief Setup a IPv4 rule in table (interface_id - 1 + 10000) and route to
|
||||
* force packets coming into interface back through it, and workaround
|
||||
@@ -75,16 +94,17 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6);
|
||||
void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4);
|
||||
|
||||
/*!
|
||||
* \brief This function allocates a TUN interface
|
||||
* \brief This function allocates a TUN or TAP interface
|
||||
* \param[in] flag IFF_TUN (for TUN device) or IFF_TAP (for TAP device)
|
||||
* \param[in] dev name of the interface
|
||||
* \return file descriptor of the allocated interface
|
||||
*/
|
||||
int tun_alloc(const char *dev);
|
||||
int tuntap_alloc(int flag, const char *dev);
|
||||
|
||||
/*!
|
||||
* \brief This function destroys the TUN interface
|
||||
* \brief This function destroys the TUN or TAP interface
|
||||
* \param[in] dev name of the interface
|
||||
*/
|
||||
void tun_destroy(const char *dev);
|
||||
void tuntap_destroy(const char *dev);
|
||||
|
||||
#endif /*TUN_IF_H_*/
|
||||
+2
-2
@@ -866,8 +866,8 @@ INPUT = \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/config/config_cmdline.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/time_meas.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/time_meas.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/tun_if.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/tun_if.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/tuntap_if.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/tuntap_if.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/utils.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/oai_asn1.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/system.h \
|
||||
|
||||
@@ -173,8 +173,7 @@ uicc0 = {
|
||||
imsi = "001010000000001";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc = "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn = "oai";
|
||||
nssai_sst = 1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
|
||||
}
|
||||
```
|
||||
|
||||
@@ -183,8 +182,23 @@ uicc0 = {
|
||||
| **IMSI** | Unique identifier for the UE within the mobile network. Used by the network to identify the UE during authentication. It ensures that the UE is correctly identified by the network. | 001010000000001 |
|
||||
| **key** | Cryptographic key shared between the UE and the network, used for encryption during the authentication process. | `fec86ba6eb707ed08905757b1bb44b8f` |
|
||||
| **OPC** | Operator key for the Milenage Authentication and Key Agreement algorithm used for encryption during the authentication process. | Ensures secure communication between the UE and the network by matching the encryption keys. | `C42449363BBAD02B66D16BC975D77CC1` |
|
||||
| **DNN** | Specifies the name of the data network the UE wishes to connect to, similar to an APN in 4G networks. | `oai` |
|
||||
| **NSSAI** | Allows the UE to select the appropriate network slice, which provides different QoS. | `1` |
|
||||
| **DNN** | _Deprecated_: Specifies the name of the data network the UE wishes to connect to, similar to an APN in 4G networks. | `oai` |
|
||||
| **NSSAI** | _Deprecated_: Allows the UE to select the appropriate network slice, which provides different QoS. | `1` |
|
||||
| **pdu_sessions** | list of PDU sessions to request | empty array (no PDU session) |
|
||||
|
||||
Note that DNN and NSSAI parameters are deprecated, and `pdu_sessions` should be
|
||||
used. If the `pdu_sessions` array is present, DNN and NSSAI are ignored.
|
||||
|
||||
Each element within the `pdu_sessions` array takes the following parameters.
|
||||
Multiple PDU sessions can be requested.
|
||||
|
||||
| **Parameter** | **Description** | **Default Value** |
|
||||
|---------------|-----------------|-------------------|
|
||||
| `id` | ID of the PDU session to request | index of the current element (1..16) |
|
||||
| `type` | Type of the PDU session to request (allowed: `IPv4`, `IPv6`, `IPv4v6`, `Ethernet` | `IPv4` |
|
||||
| `dnn` | Specifies the name of the data network the UE wishes to connect to | `oai` |
|
||||
| `nssai_sst` | Slice Service Type to request (1=eMBB, 2=URLLC, 3=mMTC) | `1` |
|
||||
| `nssai_sd` | Slice Differentiator to request | `0xffffff` (meaning "no SD") |
|
||||
|
||||
The UE configuration must match the one of the network's AMF. The nrUE can connect by default to OAI CN5G with no need to provide the configuration file.
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ ENV TZ=Europe/Paris
|
||||
RUN apt-get update && \
|
||||
apt-get upgrade --yes && \
|
||||
apt-get install --yes \
|
||||
arping \
|
||||
software-properties-common \
|
||||
procps \
|
||||
libsctp1 \
|
||||
|
||||
@@ -168,10 +168,8 @@ static void get_options(configmodule_interface_t *cfg)
|
||||
config_get(cfg, cmdline_params, numparams, NULL);
|
||||
if (nrUE_params.vcdflag > 0)
|
||||
ouput_vcd = 1;
|
||||
AssertFatal(nrUE_params.extra_pdu_id != get_softmodem_params()->default_pdu_session_id,
|
||||
"Default PDU ID (%d) and Extra PDU ID (%d) must be different!\n",
|
||||
get_softmodem_params()->default_pdu_session_id,
|
||||
nrUE_params.extra_pdu_id);
|
||||
AssertFatal(nrUE_params.extra_pdu_id == -1,
|
||||
"Add additional PDU sessions in uicc.pdu_sessions array instead\n");
|
||||
}
|
||||
|
||||
// set PHY vars from command line
|
||||
|
||||
@@ -156,6 +156,10 @@ void get_common_options(configmodule_interface_t *cfg)
|
||||
nfapi_setmode(nfapi_mode);
|
||||
if (stats_disabled)
|
||||
IS_SOFTMODEM_NOSTATS = true;
|
||||
|
||||
// To be removed in a future release (after 1 month)
|
||||
AssertFatal(get_softmodem_params()->default_pdu_session_id == -1,
|
||||
"Use uicc0.pdu_sessions.[0].id to change the requested PDU session ID (is %d)\n", get_softmodem_params()->default_pdu_session_id);
|
||||
}
|
||||
|
||||
void softmodem_verify_mode(const softmodem_params_t *p)
|
||||
|
||||
@@ -180,7 +180,7 @@ extern int usrp_tx_thread;
|
||||
{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \
|
||||
{"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \
|
||||
{"imscope-record" , CONFIG_HLP_IMSCOPE_RECORD,PARAMFLAG_BOOL, .uptr=&enable_imscope_record, .defintval=0, TYPE_UINT, 0}, \
|
||||
{"default-pdu-id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=10, TYPE_INT, 0}, \
|
||||
{"default-pdu-id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=-1, TYPE_INT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -474,6 +474,7 @@ typedef struct nas_pdu_session_req_s {
|
||||
int pdusession_type;
|
||||
int sst;
|
||||
int sd;
|
||||
char dnn[103]; /* 24.501 §9.11.2.1A: max length 102 + 0-byte */
|
||||
} nas_pdu_session_req_t;
|
||||
|
||||
/*
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#include "common/ngran_types.h"
|
||||
#include "common/openairinterface5g_limits.h"
|
||||
#include "executables/lte-softmodem.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "common/utils/tuntap_if.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "openair3/S1AP/s1ap_eNB.h"
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
#include "common/platform_constants.h"
|
||||
#include "common/ran_context.h"
|
||||
#include "common/utils/T/T.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "common/utils/tuntap_if.h"
|
||||
#include "cuup_cucp_if.h"
|
||||
#include "executables/lte-softmodem.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
@@ -405,7 +405,7 @@ void nr_pdcp_layer_init(void)
|
||||
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "executables/lte-softmodem.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "common/utils/tuntap_if.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
|
||||
|
||||
static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
#include "LTE_UECapabilityEnquiry.h"
|
||||
#include "LTE_UE-CapabilityRequest.h"
|
||||
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "common/utils/tuntap_if.h"
|
||||
#if ENABLE_RAL
|
||||
#include "rrc_UE_ral.h"
|
||||
#endif
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
#include "T.h"
|
||||
#include "LTE_MeasResults.h"
|
||||
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "common/utils/tuntap_if.h"
|
||||
|
||||
#include "rrc_eNB_S1AP.h"
|
||||
#include "rrc_eNB_GTPV1U.h"
|
||||
|
||||
@@ -201,7 +201,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_
|
||||
byte_array_t cgci = {0};
|
||||
if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) {
|
||||
DevAssert(m == NULL);
|
||||
UE->rb_config = get_default_rbconfig(10 /* EPS bearer ID */, 1 /* drb ID */, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master, &rrc->pdcp_config);
|
||||
UE->rb_config = get_default_rbconfig(DEFAULT_NOS1_PDU_ID, 1 /* drb ID */, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master, &rrc->pdcp_config);
|
||||
int len = cg_config_info_from_ue_cap_file(sizeof tmp, tmp);
|
||||
DevAssert(len > 0);
|
||||
cgci = create_byte_array(len, tmp);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "errno.h"
|
||||
#include "rlc.h"
|
||||
#include "tun_if.h"
|
||||
#include "tuntap_if.h"
|
||||
#include "system.h"
|
||||
|
||||
static void reblock_tun_socket(int fd)
|
||||
@@ -157,25 +157,27 @@ static void *sdap_tun_read_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id)
|
||||
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_session_id)
|
||||
{
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, get_softmodem_params()->default_pdu_session_id);
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
|
||||
DevAssert(entity != NULL);
|
||||
DevAssert(entity->is_gnb);
|
||||
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ifname(ifname, ifprefix, ue_id - 1);
|
||||
entity->pdusession_sock = tun_alloc(ifname);
|
||||
entity->pdusession_sock = tuntap_alloc(IFF_TUN, ifname);
|
||||
entity->pdusession_if_name = strdup(ifname);
|
||||
tun_config(ifname, "10.0.1.1", NULL);
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW);
|
||||
}
|
||||
|
||||
void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock)
|
||||
static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const char *ifname)
|
||||
{
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
|
||||
DevAssert(entity != NULL);
|
||||
DevAssert(!entity->is_gnb);
|
||||
entity->pdusession_sock = sock;
|
||||
entity->pdusession_if_name = strdup(ifname);
|
||||
entity->stop_thread = false;
|
||||
char thread_name[64];
|
||||
snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id);
|
||||
@@ -183,22 +185,32 @@ void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock)
|
||||
}
|
||||
|
||||
|
||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id)
|
||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default)
|
||||
{
|
||||
int default_pdu = get_softmodem_params()->default_pdu_session_id;
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ue_ifname(ifname, ue_id, pdu_session_id != default_pdu ? pdu_session_id : -1);
|
||||
const int sock = tun_alloc(ifname);
|
||||
tuntap_generate_ue_ifname(ifname, IFF_TUN, ue_id, is_default ? -1 : pdu_session_id);
|
||||
const int sock = tuntap_alloc(IFF_TUN, ifname);
|
||||
tun_config(ifname, ipv4, ipv6);
|
||||
if (ipv4) {
|
||||
setup_ue_ipv4_route(ifname, ue_id, ipv4);
|
||||
}
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock); // interface name suffix is ue_id+1
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname); // interface name suffix is ue_id+1
|
||||
}
|
||||
|
||||
void create_ue_eth_if(int ue_id, int pdu_session_id, bool is_default)
|
||||
{
|
||||
char ifname[IFNAMSIZ];
|
||||
tuntap_generate_ue_ifname(ifname, IFF_TAP, ue_id, is_default ? -1 : pdu_session_id);
|
||||
const int sock = tuntap_alloc(IFF_TAP, ifname);
|
||||
tap_config(ifname); // brings the interface up
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname);
|
||||
}
|
||||
|
||||
void remove_ip_if(nr_sdap_entity_t *entity)
|
||||
{
|
||||
DevAssert(entity != NULL);
|
||||
DevAssert(entity->pdusession_if_name != NULL);
|
||||
|
||||
// Stop the read thread
|
||||
entity->stop_thread = true;
|
||||
|
||||
@@ -208,13 +220,7 @@ void remove_ip_if(nr_sdap_entity_t *entity)
|
||||
int ret = pthread_join(entity->pdusession_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno));
|
||||
// Bring down the IP interface
|
||||
int default_pdu = get_softmodem_params()->default_pdu_session_id;
|
||||
char ifname[IFNAMSIZ];
|
||||
if (entity->is_gnb) {
|
||||
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
|
||||
tun_generate_ifname(ifname, ifprefix, entity->ue_id - 1);
|
||||
} else {
|
||||
tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1);
|
||||
}
|
||||
tun_destroy(ifname);
|
||||
tuntap_destroy(entity->pdusession_if_name);
|
||||
free(entity->pdusession_if_name);
|
||||
entity->pdusession_if_name = NULL;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ void sdap_data_ind(int pdcp_entity,
|
||||
char *buf,
|
||||
int size);
|
||||
|
||||
void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock);
|
||||
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id);
|
||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id);
|
||||
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_session_id);
|
||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default);
|
||||
void create_ue_eth_if(int ue_id, int pdu_session_id, bool is_default);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "gtpv1_u_messages_types.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "rlc.h"
|
||||
#include "tun_if.h"
|
||||
#include "tuntap_if.h"
|
||||
#include "nr_sdap.h"
|
||||
|
||||
#define NO_SDAP_HEADER 0
|
||||
@@ -534,7 +534,7 @@ static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap
|
||||
if (IS_SOFTMODEM_NOS1 && is_gnb) {
|
||||
// In NOS1 mode, terminate SDAP for the first UE on the gNB. This allows injecting/receiving
|
||||
// PDCP SDUs to/from the TUN interface.
|
||||
start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id);
|
||||
start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id, sdap_entity->pdusession_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,7 @@ typedef struct nr_sdap_entity_s {
|
||||
bool enable_sdap;
|
||||
int pdusession_id;
|
||||
int pdusession_sock;
|
||||
char *pdusession_if_name;
|
||||
pthread_t pdusession_thread;
|
||||
bool stop_thread;
|
||||
int qfi;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -2,9 +2,7 @@ uicc0 = {
|
||||
imsi = "2089900007487";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
nssai_sd=1;
|
||||
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; nssai_sd = 1; });
|
||||
}
|
||||
|
||||
position0 = {
|
||||
|
||||
Reference in New Issue
Block a user