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:
Robert Schmidt
2026-01-29 07:52:48 +01:00
49 changed files with 483 additions and 190 deletions
@@ -12,8 +12,7 @@ uicc0 = {
imsi = "208990100001100"; imsi = "208990100001100";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
MACRLCs = ( MACRLCs = (
+11
View File
@@ -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"
+1 -2
View File
@@ -2,8 +2,7 @@ uicc0 = {
imsi = "208990100001100"; imsi = "208990100001100";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
position0 = { position0 = {
+1 -2
View File
@@ -2,8 +2,7 @@ uicc0 = {
imsi = "208990100001100"; imsi = "208990100001100";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
position0 = { position0 = {
+3 -2
View File
@@ -2,8 +2,9 @@ uicc0:
imsi: 208990100001100 imsi: 208990100001100
key: fec86ba6eb707ed08905757b1bb44b8f key: fec86ba6eb707ed08905757b1bb44b8f
opc: C42449363BBAD02B66D16BC975D77CC1 opc: C42449363BBAD02B66D16BC975D77CC1
dnn: oai pdu_sessions:
nssai_sst: 1 - dnn: oai
nssai_sst: 1
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
@@ -2,8 +2,9 @@ uicc0:
imsi: 208990100001100 imsi: 208990100001100
key: fec86ba6eb707ed08905757b1bb44b8f key: fec86ba6eb707ed08905757b1bb44b8f
opc: C42449363BBAD02B66D16BC975D77CC1 opc: C42449363BBAD02B66D16BC975D77CC1
dnn: oai pdu_sessions:
nssai_sst: 1 - dnn: oai
nssai_sst: 1
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
+1 -2
View File
@@ -2,8 +2,7 @@ uicc0 = {
imsi = "208970100001127"; imsi = "208970100001127";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "c42449363bbad02b66d16bc975d77cc1"; opc= "c42449363bbad02b66d16bc975d77cc1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
@@ -12,9 +12,7 @@ uicc0 = {
imsi = "208950000000031"; imsi = "208950000000031";
key = "0c0a34601d4f07677303652c0462535b"; key = "0c0a34601d4f07677303652c0462535b";
opc= "63bfa50ee6523365ff14c1f45f88737d"; opc= "63bfa50ee6523365ff14c1f45f88737d";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 222; nssai_sd = 123; });
nssai_sst=222;
nssai_sd=123;
} }
MACRLCs = ( MACRLCs = (
@@ -12,9 +12,7 @@ uicc0 = {
imsi = "2089900007487"; imsi = "2089900007487";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; nssai_sd = 1; });
nssai_sst=1;
nssai_sd=1;
} }
MACRLCs = ( MACRLCs = (
@@ -518,8 +518,7 @@ uicc0 = {
imsi = "208990100001100"; imsi = "208990100001100";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
``` ```
@@ -338,7 +338,7 @@ services:
environment: environment:
USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time
-r 106 --numerology 1 -C 3619200000 -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 --rfsimulator.[0].serveraddr 192.168.78.3
depends_on: depends_on:
- oai-du2 - oai-du2
@@ -368,7 +368,7 @@ services:
environment: environment:
USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time
-r 106 --numerology 1 -C 3619200000 -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 --rfsimulator.[0].serveraddr 192.168.78.4
ASAN_OPTIONS: detect_leaks=0 ASAN_OPTIONS: detect_leaks=0
depends_on: depends_on:
@@ -2,71 +2,61 @@ uicc0 = {
imsi = "208990100001100"; imsi = "208990100001100";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc1 = { uicc1 = {
imsi = "208990100001101"; imsi = "208990100001101";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc2 = { uicc2 = {
imsi = "208990100001102"; imsi = "208990100001102";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc3 = { uicc3 = {
imsi = "208990100001103"; imsi = "208990100001103";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc4 = { uicc4 = {
imsi = "208990100001104"; imsi = "208990100001104";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc5 = { uicc5 = {
imsi = "208990100001105"; imsi = "208990100001105";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc6 = { uicc6 = {
imsi = "208990100001106"; imsi = "208990100001106";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc7 = { uicc7 = {
imsi = "208990100001107"; imsi = "208990100001107";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc8 = { uicc8 = {
imsi = "208990100001108"; imsi = "208990100001108";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
uicc9 = { uicc9 = {
imsi = "208990100001109"; imsi = "208990100001109";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
nssai_sst=1;
} }
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
@@ -149,7 +149,7 @@ services:
- NET_RAW # for ping - NET_RAW # for ping
environment: environment:
USE_ADDITIONAL_OPTIONS: --rfsim -r 25 --numerology 0 --uicc0.imsi 208990100001100 --band 66 -C 2152680000 --CO -400000000 --ssb 48 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 --telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.150 --telnetsrv.listenport 8091
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0
depends_on: depends_on:
@@ -160,7 +160,7 @@ services:
devices: devices:
- /dev/net/tun:/dev/net/tun - /dev/net/tun:/dev/net/tun
volumes: 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: healthcheck:
test: /bin/bash -c "pgrep nr-uesoftmodem" test: /bin/bash -c "pgrep nr-uesoftmodem"
start_period: 10s start_period: 10s
+1 -1
View File
@@ -144,7 +144,7 @@ int config_cmdlineonly_getlist(configmodule_interface_t *cfg,
paramlist_def_t *ParamList, paramlist_def_t *ParamList,
paramdef_t *params, paramdef_t *params,
int numparams, int numparams,
char *prefix) const char *prefix)
{ {
ParamList->numelt = 0; ParamList->numelt = 0;
return 0; return 0;
+1 -1
View File
@@ -61,7 +61,7 @@
struct configmodule_interface; struct configmodule_interface;
typedef int (*configmodule_getfunc_t)(struct configmodule_interface *, paramdef_t *, int numparams, const char *prefix); typedef int (*configmodule_getfunc_t)(struct configmodule_interface *, paramdef_t *, int numparams, const char *prefix);
typedef int ( 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 int (*configmodule_setfunc_t)(paramdef_t *cfgoptions, int numoptions, const char *prefix);
typedef void (*configmodule_endfunc_t)(struct configmodule_interface *cfg); typedef void (*configmodule_endfunc_t)(struct configmodule_interface *cfg);
+1 -1
View File
@@ -142,7 +142,7 @@ int config_get(configmodule_interface_t *cfgif, paramdef_t *params, int numparam
return ret; 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)) { if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
fprintf(stderr,"[CONFIG] config_get skipped, config module not properly initialized\n"); fprintf(stderr,"[CONFIG] config_get skipped, config module not properly initialized\n");
+1 -1
View File
@@ -62,7 +62,7 @@ int config_assign_ipv4addr(configmodule_interface_t *cfg, paramdef_t *cfgoptions
#define CONFIG_CHECKALLSECTIONS "ALLSECTIONS" #define CONFIG_CHECKALLSECTIONS "ALLSECTIONS"
int config_check_unknown_cmdlineopt(configmodule_interface_t *cfg, char *prefix); 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_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 */ /* 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); void config_set_checkfunctions(paramdef_t *params, checkedparam_t *checkfunctions, int numparams);
+3
View File
@@ -100,5 +100,8 @@
// SDAP // SDAP
#define MAX_QOS_FLOWS 64 #define MAX_QOS_FLOWS 64
// SDAP/5G NAS NOS1
#define DEFAULT_NOS1_PDU_ID 10
#define SPEED_OF_LIGHT 299792458 // in m/s #define SPEED_OF_LIGHT 299792458 // in m/s
#endif /* __PLATFORM_CONSTANTS_H__ */ #endif /* __PLATFORM_CONSTANTS_H__ */
+1 -1
View File
@@ -14,7 +14,7 @@ add_subdirectory(nr)
add_subdirectory(LOG) add_subdirectory(LOG)
add_subdirectory(threadPool) add_subdirectory(threadPool)
add_subdirectory(time_manager) 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_include_directories(utils PUBLIC .)
target_link_libraries(utils PRIVATE ${T_LIB}) target_link_libraries(utils PRIVATE ${T_LIB})
if (ENABLE_TESTS) if (ENABLE_TESTS)
+5 -1
View File
@@ -172,7 +172,11 @@ static int add_pdu_session(char *buf, int debug, telnet_printfunc_t prnt)
if (!nas) if (!nas)
ERROR_MSG_RET("No NAS context found for UE_ID %d\n", ue_id); 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); prnt("Triggered PDU session request for UE %d with ID %d\n", ue_id, pdusession_id);
return 0; return 0;
} }
@@ -27,10 +27,9 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/if_tun.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include "tun_if.h" #include "tuntap_if.h"
#include "common/platform_constants.h" #include "common/platform_constants.h"
#include "common/utils/LOG/log.h" #include "common/utils/LOG/log.h"
#include "common/utils/system.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_fd[MAX_MOBILES_PER_ENB * 2]; // Allocated for both LTE UE and NR UE.
int nas_sock_mbms_fd; int nas_sock_mbms_fd;
int tun_alloc(const char *dev) int tuntap_alloc(int flag, const char *dev)
{ {
struct ifreq ifr; struct ifreq ifr;
int fd, err; int fd, err;
@@ -54,7 +53,8 @@ int tun_alloc(const char *dev)
* *
* IFF_NO_PI - Do not provide packet information * 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); strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) { if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
close(fd); close(fd);
@@ -76,7 +76,7 @@ int tun_alloc(const char *dev)
int tun_init_mbms(char *ifname) 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) { if (nas_sock_mbms_fd == -1) {
LOG_E(UTIL, "Error opening mbms socket %s (%d:%s)\n", ifname, errno, strerror(errno)); 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) 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) { if (nas_sock_fd[instance_id] == -1) {
LOG_E(UTIL, "Error opening socket %s (%d:%s)\n", ifname, errno, strerror(errno)); 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}; struct ifreq ifr = {0};
strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name) - 1); strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name) - 1);
/* get flags of this interface: see netdevice(7) */ /* get flags of this interface: see netdevice(7) */
bool success = ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t)&ifr) == 0; int success = ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t)&ifr) == 0;
if (!success && if_action == INTERFACE_DOWN && errno == ENODEV) { if (!success) {
LOG_W(OIP, "trying to remove non-existant device %s\n", ifn); LOG_W(OIP, "On interface %s: ioctl() failed: %d, %s\n", ifn, errno, strerror(errno));
return true; return false;
} }
LOG_D(OIP, "Got flags for %s: 0x%x (action: %s)\n", ifn, ifr.ifr_flags, action); *flags = ifr.ifr_flags;
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);
return true; return true;
}
fail_interface_state: /*
LOG_E(OIP, "Bringing interface %s for %s: ioctl call failed: %d, %s\n", action, ifn, errno, strerror(errno)); * \brief Set an interface's flags.
return false; * \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); close(sock_fd);
} }
// if successfully set IP addresses: set iterface up, disable ARP, no
// multicast, point-to-point
if (success) 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) 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 else
LOG_E(OIP, "Interface %s couldn't be configured (IPv4 %s, IPv6 %s)\n", ifname, ipv4, ipv6); 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; 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) void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4)
{ {
int table_id = instance_id - 1 + 10000; 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); 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]; char pdu_session_string[10];
snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id); 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 // Use a new socket for ioctl operations
int fd = socket(AF_INET, SOCK_DGRAM, 0); int fd = socket(AF_INET, SOCK_DGRAM, 0);
@@ -283,11 +311,12 @@ void tun_destroy(const char *dev)
return; 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) { if (success) {
LOG_I(UTIL, "Interface %s is now down.\n", dev); LOG_I(UTIL, "Interface %s is now down.\n", dev);
} else { } // no else: get_if_flags()/set_if_flags() should have printed error
LOG_E(UTIL, "Could not bring interface %s down.\n", dev);
}
close(fd); close(fd);
} }
@@ -24,6 +24,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <net/if.h> #include <net/if.h>
#include <linux/if_tun.h>
/*! /*!
* \brief This function generates the name of the interface based on the prefix and * \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 * \param[in] instance_id unique instance number
*/ */
int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id); 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 * \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); int tun_init_mbms(char *ifname);
/*! /*!
* \brief This function initializes the nasmesh interface using the basic values, * \brief Initializes the TUN interface with an IPv4 or IPv6 address and
* basic address, network mask and broadcast address, as the default configured * activates the interface.
* ones
* \param[in] ifname name of the interface * \param[in] ifname name of the interface
* \param[in] ipv4 IPv4 address of this interface as a string * \param[in] ipv4 IPv4 address of this interface as a string
* \param[in] ipv6 IPv6 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); 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 * \brief Setup a IPv4 rule in table (interface_id - 1 + 10000) and route to
* force packets coming into interface back through it, and workaround * 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); 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 * \param[in] dev name of the interface
* \return file descriptor of the allocated 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 * \param[in] dev name of the interface
*/ */
void tun_destroy(const char *dev); void tuntap_destroy(const char *dev);
#endif /*TUN_IF_H_*/ #endif /*TUN_IF_H_*/
+2 -2
View File
@@ -866,8 +866,8 @@ INPUT = \
@CMAKE_CURRENT_SOURCE_DIR@/../common/config/config_cmdline.c \ @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.c \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/time_meas.h \ @CMAKE_CURRENT_SOURCE_DIR@/../common/utils/time_meas.h \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/tun_if.h \ @CMAKE_CURRENT_SOURCE_DIR@/../common/utils/tuntap_if.h \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/tun_if.c \ @CMAKE_CURRENT_SOURCE_DIR@/../common/utils/tuntap_if.c \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/utils.c \ @CMAKE_CURRENT_SOURCE_DIR@/../common/utils/utils.c \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/oai_asn1.h \ @CMAKE_CURRENT_SOURCE_DIR@/../common/utils/oai_asn1.h \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/system.h \ @CMAKE_CURRENT_SOURCE_DIR@/../common/utils/system.h \
+18 -4
View File
@@ -173,8 +173,7 @@ uicc0 = {
imsi = "001010000000001"; imsi = "001010000000001";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc = "C42449363BBAD02B66D16BC975D77CC1"; opc = "C42449363BBAD02B66D16BC975D77CC1";
dnn = "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
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 | | **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` | | **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` | | **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` | | **DNN** | _Deprecated_: 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` | | **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. 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.
+1
View File
@@ -39,6 +39,7 @@ ENV TZ=Europe/Paris
RUN apt-get update && \ RUN apt-get update && \
apt-get upgrade --yes && \ apt-get upgrade --yes && \
apt-get install --yes \ apt-get install --yes \
arping \
software-properties-common \ software-properties-common \
procps \ procps \
libsctp1 \ libsctp1 \
+2 -4
View File
@@ -168,10 +168,8 @@ static void get_options(configmodule_interface_t *cfg)
config_get(cfg, cmdline_params, numparams, NULL); config_get(cfg, cmdline_params, numparams, NULL);
if (nrUE_params.vcdflag > 0) if (nrUE_params.vcdflag > 0)
ouput_vcd = 1; ouput_vcd = 1;
AssertFatal(nrUE_params.extra_pdu_id != get_softmodem_params()->default_pdu_session_id, AssertFatal(nrUE_params.extra_pdu_id == -1,
"Default PDU ID (%d) and Extra PDU ID (%d) must be different!\n", "Add additional PDU sessions in uicc.pdu_sessions array instead\n");
get_softmodem_params()->default_pdu_session_id,
nrUE_params.extra_pdu_id);
} }
// set PHY vars from command line // set PHY vars from command line
+4
View File
@@ -156,6 +156,10 @@ void get_common_options(configmodule_interface_t *cfg)
nfapi_setmode(nfapi_mode); nfapi_setmode(nfapi_mode);
if (stats_disabled) if (stats_disabled)
IS_SOFTMODEM_NOSTATS = true; 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) void softmodem_verify_mode(const softmodem_params_t *p)
+1 -1
View File
@@ -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}, \ {"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" , 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}, \ {"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 // clang-format on
+1
View File
@@ -474,6 +474,7 @@ typedef struct nas_pdu_session_req_s {
int pdusession_type; int pdusession_type;
int sst; int sst;
int sd; int sd;
char dnn[103]; /* 24.501 §9.11.2.1A: max length 102 + 0-byte */
} nas_pdu_session_req_t; } nas_pdu_session_req_t;
/* /*
+1 -1
View File
@@ -49,7 +49,7 @@
#include "common/ngran_types.h" #include "common/ngran_types.h"
#include "common/openairinterface5g_limits.h" #include "common/openairinterface5g_limits.h"
#include "executables/lte-softmodem.h" #include "executables/lte-softmodem.h"
#include "common/utils/tun_if.h" #include "common/utils/tuntap_if.h"
#include "intertask_interface.h" #include "intertask_interface.h"
#include "openair3/S1AP/s1ap_eNB.h" #include "openair3/S1AP/s1ap_eNB.h"
#include <pthread.h> #include <pthread.h>
+2 -2
View File
@@ -46,7 +46,7 @@
#include "common/platform_constants.h" #include "common/platform_constants.h"
#include "common/ran_context.h" #include "common/ran_context.h"
#include "common/utils/T/T.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 "cuup_cucp_if.h"
#include "executables/lte-softmodem.h" #include "executables/lte-softmodem.h"
#include "executables/softmodem-common.h" #include "executables/softmodem-common.h"
@@ -405,7 +405,7 @@ void nr_pdcp_layer_init(void)
#include "nfapi/oai_integration/vendor_ext.h" #include "nfapi/oai_integration/vendor_ext.h"
#include "executables/lte-softmodem.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" #include "openair2/SDAP/nr_sdap/nr_sdap.h"
static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity, static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
+1 -1
View File
@@ -64,7 +64,7 @@
#include "LTE_UECapabilityEnquiry.h" #include "LTE_UECapabilityEnquiry.h"
#include "LTE_UE-CapabilityRequest.h" #include "LTE_UE-CapabilityRequest.h"
#include "common/utils/tun_if.h" #include "common/utils/tuntap_if.h"
#if ENABLE_RAL #if ENABLE_RAL
#include "rrc_UE_ral.h" #include "rrc_UE_ral.h"
#endif #endif
+1 -1
View File
@@ -79,7 +79,7 @@
#include "T.h" #include "T.h"
#include "LTE_MeasResults.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_S1AP.h"
#include "rrc_eNB_GTPV1U.h" #include "rrc_eNB_GTPV1U.h"
+1 -1
View File
@@ -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}; byte_array_t cgci = {0};
if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) { if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) {
DevAssert(m == NULL); 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); int len = cg_config_info_from_ue_cap_file(sizeof tmp, tmp);
DevAssert(len > 0); DevAssert(len > 0);
cgci = create_byte_array(len, tmp); cgci = create_byte_array(len, tmp);
+25 -19
View File
@@ -29,7 +29,7 @@
#include "common/utils/LOG/log.h" #include "common/utils/LOG/log.h"
#include "errno.h" #include "errno.h"
#include "rlc.h" #include "rlc.h"
#include "tun_if.h" #include "tuntap_if.h"
#include "system.h" #include "system.h"
static void reblock_tun_socket(int fd) static void reblock_tun_socket(int fd)
@@ -157,25 +157,27 @@ static void *sdap_tun_read_thread(void *arg)
return NULL; 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 != NULL);
DevAssert(entity->is_gnb); DevAssert(entity->is_gnb);
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
tun_generate_ifname(ifname, ifprefix, ue_id - 1); 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); 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); 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); nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
DevAssert(entity != NULL); DevAssert(entity != NULL);
DevAssert(!entity->is_gnb); DevAssert(!entity->is_gnb);
entity->pdusession_sock = sock; entity->pdusession_sock = sock;
entity->pdusession_if_name = strdup(ifname);
entity->stop_thread = false; entity->stop_thread = false;
char thread_name[64]; char thread_name[64];
snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id); 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]; char ifname[IFNAMSIZ];
tun_generate_ue_ifname(ifname, ue_id, pdu_session_id != default_pdu ? pdu_session_id : -1); tuntap_generate_ue_ifname(ifname, IFF_TUN, ue_id, is_default ? -1 : pdu_session_id);
const int sock = tun_alloc(ifname); const int sock = tuntap_alloc(IFF_TUN, ifname);
tun_config(ifname, ipv4, ipv6); tun_config(ifname, ipv4, ipv6);
if (ipv4) { if (ipv4) {
setup_ue_ipv4_route(ifname, ue_id, 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) void remove_ip_if(nr_sdap_entity_t *entity)
{ {
DevAssert(entity != NULL); DevAssert(entity != NULL);
DevAssert(entity->pdusession_if_name != NULL);
// Stop the read thread // Stop the read thread
entity->stop_thread = true; 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); int ret = pthread_join(entity->pdusession_thread, NULL);
AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno)); AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno));
// Bring down the IP interface // Bring down the IP interface
int default_pdu = get_softmodem_params()->default_pdu_session_id; tuntap_destroy(entity->pdusession_if_name);
char ifname[IFNAMSIZ]; free(entity->pdusession_if_name);
if (entity->is_gnb) { entity->pdusession_if_name = NULL;
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);
} }
+3 -3
View File
@@ -60,8 +60,8 @@ void sdap_data_ind(int pdcp_entity,
char *buf, char *buf,
int size); 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, int pdu_session_id);
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, bool is_default);
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id); void create_ue_eth_if(int ue_id, int pdu_session_id, bool is_default);
#endif #endif
+2 -2
View File
@@ -31,7 +31,7 @@
#include "gtpv1_u_messages_types.h" #include "gtpv1_u_messages_types.h"
#include "intertask_interface.h" #include "intertask_interface.h"
#include "rlc.h" #include "rlc.h"
#include "tun_if.h" #include "tuntap_if.h"
#include "nr_sdap.h" #include "nr_sdap.h"
#define NO_SDAP_HEADER 0 #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) { if (IS_SOFTMODEM_NOS1 && is_gnb) {
// In NOS1 mode, terminate SDAP for the first UE on the gNB. This allows injecting/receiving // In NOS1 mode, terminate SDAP for the first UE on the gNB. This allows injecting/receiving
// PDCP SDUs to/from the TUN interface. // 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);
} }
} }
+1
View File
@@ -102,6 +102,7 @@ typedef struct nr_sdap_entity_s {
bool enable_sdap; bool enable_sdap;
int pdusession_id; int pdusession_id;
int pdusession_sock; int pdusession_sock;
char *pdusession_if_name;
pthread_t pdusession_thread; pthread_t pdusession_thread;
bool stop_thread; bool stop_thread;
int qfi; int qfi;
@@ -23,7 +23,6 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "PduSessionEstablishmentAccept.h" #include "PduSessionEstablishmentAccept.h"
#include "common/utils/LOG/log.h" #include "common/utils/LOG/log.h"
#include "common/utils/tun_if.h"
#include "fgs_nas_utils.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_IPV4 0b001
#define PDU_SESSION_TYPE_IPV6 0b010 #define PDU_SESSION_TYPE_IPV6 0b010
#define PDU_SESSION_TYPE_IPV4V6 0b011 #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 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 IPv6_INTERFACE_ID_LENGTH 8 // interface identifier for the IPv6 link local address
#define SMF_IPv6_LLA_LENGTH 16 #define SMF_IPv6_LLA_LENGTH 16
+74 -39
View File
@@ -56,7 +56,6 @@
#include "aka_functions.h" #include "aka_functions.h"
#include "assertions.h" #include "assertions.h"
#include "common/utils/ds/byte_array.h" #include "common/utils/ds/byte_array.h"
#include "common/utils/tun_if.h"
#include "commonDef.h" #include "commonDef.h"
#include "intertask_interface.h" #include "intertask_interface.h"
#include "kdf.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 * @brief Process PDU Session Address in PDU Session Establishment Accept message
* and configure the tun interface * 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; 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: { case PDU_SESSION_TYPE_IPV4: {
char ip[20]; char ip[20];
capture_ipv4_addr(&addr[0], ip, sizeof(ip)); 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; } break;
case PDU_SESSION_TYPE_IPV6: { case PDU_SESSION_TYPE_IPV6: {
char ipv6[40]; char ipv6[40];
capture_ipv6_addr(addr, ipv6, sizeof(ipv6)); 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; } break;
case PDU_SESSION_TYPE_IPV4V6: { 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)); capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
char ipv4[20]; char ipv4[20];
capture_ipv4_addr(&addr[IPv6_INTERFACE_ID_LENGTH], ipv4, sizeof(ipv4)); 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; } break;
default: 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 * @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}; pdu_session_establishment_accept_msg_t msg = {0};
int size = 0; int size = 0;
@@ -1545,22 +1547,42 @@ static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length,
size += decoded; size += decoded;
// decode PDU Session Establishment Accept // 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"); 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); set_qfi(msg.qos_rules.rule->qfi, sm_header.pdu_session_id, instance);
} }
/** /**
* @brief Handle DL NAS Transport and process piggybacked 5GSM messages * @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) { if (pdu_length < 17) {
LOG_E(NAS, "Received DL NAS Transport message too short (%d)\n", pdu_length); 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); uint8_t msg_type = *(pdu_buffer + 16);
if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
LOG_A(NAS, "Received PDU Session Establishment Accept in DL NAS Transport\n"); 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 { } else {
LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type); 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 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; const size_t nssai_len = has_nssai_sd ? 4 : 1;
mm_msg->snssai.length = nssai_len; mm_msg->snssai.length = nssai_len;
// Fixme: it seems there are a lot of memory errors in this: this value was on the stack,
// but pushed in a itti message to another thread
// this kind of error seems in many places in 5G NAS
mm_msg->snssai.value = calloc(1, nssai_len); mm_msg->snssai.value = calloc(1, nssai_len);
mm_msg->snssai.value[0] = pdu_req->sst; mm_msg->snssai.value[0] = pdu_req->sst;
if (has_nssai_sd) if (has_nssai_sd)
INT24_TO_BUFFER(pdu_req->sd, &mm_msg->snssai.value[1]); INT24_TO_BUFFER(pdu_req->sd, &mm_msg->snssai.value[1]);
size += 1 + 1 + nssai_len; 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.value = calloc(1, dnnSize + 1);
mm_msg->dnn.length = dnnSize + 1; mm_msg->dnn.length = dnnSize + 1;
mm_msg->dnn.value[0] = dnnSize; 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); size += (1 + 1 + dnnSize + 1);
// encode the message // 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); 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); 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_t *pdu_req = &NAS_PDU_SESSION_REQ(message_p);
NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6 pdu_req->pdusession_id = pdu->id;
NAS_PDU_SESSION_REQ(message_p).sst = nas->uicc->nssai_sst; // 24.501: joint PDU session type IEI (0x9-, Table 8.3.1.1.1) and type (9.11.4.11)
NAS_PDU_SESSION_REQ(message_p).sd = nas->uicc->nssai_sd; 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); 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++) { for (int i = 0; i < NAS_MAX_NUMBER_SLICES; i++) {
const nr_nas_msg_snssai_t *nssai = allowed_nssai + i; const nr_nas_msg_snssai_t *nssai = allowed_nssai + i;
/* If it was received in Registration Accept, check the SD /* If it was received in Registration Accept, check the SD
in the stored Allowed N-SSAI, else, consider the SD valid */ in the stored Allowed N-SSAI, else, consider the SD valid */
bool sd_match = !nssai->sd || (nas->uicc->nssai_sd == *nssai->sd); bool sd_match = !nssai->sd || (ch_nssai.sd == *nssai->sd);
if ((nas->uicc->nssai_sst == nssai->sst) && sd_match) if ((ch_nssai.sst == nssai->sst) && sd_match)
return i; return i;
} }
return -1; 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); send_nas_uplink_data_req(nas, &initialNasMsg);
LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n"); LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n");
} }
if (get_user_nssai_idx(msg.nas_allowed_nssai, nas) < 0) { if (nas->uicc->n_pdu_sessions == 0)
LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n"); LOG_W(SIM, "no PDU sessions to request configured\n");
} else { for (const pdu_session_config_t *pdu = nas->uicc->pdu_sessions; pdu < nas->uicc->pdu_sessions + nas->uicc->n_pdu_sessions; ++pdu) {
request_pdusession(nas, get_softmodem_params()->default_pdu_session_id); if (get_user_nssai_idx(pdu->nssai, msg.nas_allowed_nssai) < 0) {
if (get_nrUE_params()->extra_pdu_id != -1) { LOG_E(NAS,
request_pdusession(nas, get_nrUE_params()->extra_pdu_id); "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 // Free local message after processing
@@ -2017,7 +2051,7 @@ void *nas_nrue(void *args_p)
if (msg_type == FGS_REGISTRATION_ACCEPT) { if (msg_type == FGS_REGISTRATION_ACCEPT) {
handle_registration_accept(nas, ba.buf, ba.len); handle_registration_accept(nas, ba.buf, ba.len);
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { } 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) // 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); handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length);
break; break;
case FGS_DOWNLINK_NAS_TRANSPORT: case FGS_DOWNLINK_NAS_TRANSPORT:
handleDownlinkNASTransport(pdu_buffer, pdu_length, nas->UE_id); handleDownlinkNASTransport(nas, pdu_buffer, pdu_length, nas->UE_id);
break; break;
case FGS_REGISTRATION_ACCEPT: case FGS_REGISTRATION_ACCEPT:
handle_registration_accept(nas, pdu_buffer, pdu_length); handle_registration_accept(nas, pdu_buffer, pdu_length);
@@ -2114,7 +2148,7 @@ void *nas_nrue(void *args_p)
nas->fiveGMM_state = FGS_DEREGISTERED; nas->fiveGMM_state = FGS_DEREGISTERED;
break; break;
case FGS_PDU_SESSION_ESTABLISHMENT_ACC: 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; break;
case FGS_PDU_SESSION_ESTABLISHMENT_REJ: case FGS_PDU_SESSION_ESTABLISHMENT_REJ:
LOG_E(NAS, "Received PDU Session Establishment reject\n"); LOG_E(NAS, "Received PDU Session Establishment reject\n");
@@ -2159,10 +2193,11 @@ void *nas_nrue(void *args_p)
} break; } break;
case NAS_INIT_NOS1_IF: { 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 char *ip = "10.0.1.2";
const int qfi = 7; 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); set_qfi(qfi, pdu_session_id, nas->UE_id);
break; break;
} }
+2 -1
View File
@@ -32,6 +32,7 @@
#define __NR_NAS_MSG_SIM_H__ #define __NR_NAS_MSG_SIM_H__
#include <common/utils/assertions.h> #include <common/utils/assertions.h>
#include "common/5g_platform_types.h"
#include <openair3/UICC/usim_interface.h> #include <openair3/UICC/usim_interface.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@@ -113,6 +114,6 @@ void *nas_nrue_task(void *args_p);
void *nas_nrue(void *args_p); void *nas_nrue(void *args_p);
void nas_init_nrue(int num_ues); 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 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__*/ #endif /* __NR_NAS_MSG_SIM_H__*/
+1 -1
View File
@@ -45,7 +45,7 @@ Description Defines functions used to handle EPS bearer contexts.
#include "esm_ebr.h" #include "esm_ebr.h"
#include "esm_ebr_context.h" #include "esm_ebr_context.h"
#include "common/utils/tun_if.h" #include "common/utils/tuntap_if.h"
#include "emm_sap.h" #include "emm_sap.h"
#include "system.h" #include "system.h"
+1 -1
View File
@@ -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_include_directories(lib_uicc PRIVATE .)
target_link_libraries(lib_uicc PRIVATE log_headers) target_link_libraries(lib_uicc PRIVATE log_headers)
+116
View File
@@ -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;
}
+36
View File
@@ -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_ */
+32 -4
View File
@@ -22,6 +22,7 @@
*/ */
#include <ctype.h> #include <ctype.h>
#include "common/platform_constants.h"
#include <openair3/UICC/usim_interface.h> #include <openair3/UICC/usim_interface.h>
#include <openair3/NAS/COMMON/milenage.h> #include <openair3/NAS/COMMON/milenage.h>
extern uint16_t NB_UE_INST; 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 // 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); 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); AssertFatal(ret >= 0, "configuration couldn't be performed for uicc name: %s", sectionName);
LOG_I(SIM, LOG_I(SIM, "UICC simulation: IMSI=%s, IMEISV=%s, Ki=%s, OPc=%s\n", uicc->imsiStr, uicc->imeisvStr, uicc->keyStr, uicc->opcStr);
"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);
to_hex(uicc->keyStr,uicc->key, sizeof(uicc->key) ); to_hex(uicc->keyStr,uicc->key, sizeof(uicc->key) );
to_hex(uicc->opcStr,uicc->opc, sizeof(uicc->opc) ); to_hex(uicc->opcStr,uicc->opc, sizeof(uicc->opc) );
to_hex(uicc->sqnStr,uicc->sqn, sizeof(uicc->sqn) ); to_hex(uicc->sqnStr,uicc->sqn, sizeof(uicc->sqn) );
@@ -112,6 +110,36 @@ uicc_t * checkUicc(int Mod_id) {
char uiccName[64]; char uiccName[64];
sprintf(uiccName,"uicc%d", Mod_id); sprintf(uiccName,"uicc%d", Mod_id);
uiccArray[Mod_id]=(void*)init_uicc(uiccName); 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]; return (uicc_t*) uiccArray[Mod_id];
} }
+3
View File
@@ -34,6 +34,7 @@
#include <common/utils/load_module_shlib.h> #include <common/utils/load_module_shlib.h>
#include <common/config/config_userapi.h> #include <common/config/config_userapi.h>
#include "common_lib.h" #include "common_lib.h"
#include "pdu_session.h"
/* 3GPP glossary /* 3GPP glossary
RES RESponse RES RESponse
@@ -53,6 +54,8 @@ typedef struct {
char *dnnStr; char *dnnStr;
int nssai_sst; int nssai_sst;
int nssai_sd; int nssai_sd;
pdu_session_config_t pdu_sessions[256];
int n_pdu_sessions;
uint8_t key[16]; uint8_t key[16];
uint8_t opc[16]; uint8_t opc[16];
uint8_t amf[2]; uint8_t amf[2];
+1 -3
View File
@@ -2,9 +2,7 @@ uicc0 = {
imsi = "2089900007487"; imsi = "2089900007487";
key = "fec86ba6eb707ed08905757b1bb44b8f"; key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1"; opc= "C42449363BBAD02B66D16BC975D77CC1";
dnn= "oai"; pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; nssai_sd = 1; });
nssai_sst=1;
nssai_sd=1;
} }
position0 = { position0 = {