mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Paging UE (SDAP): reattach TUN after idle reset
UE paging can recreate the AS-side SDAP entity while NAS still keeps the PDU session established. Per TS 38.304 clause 7.1 and TS 24.501 clauses 5.6.2.2.1,5.6.1.2 paging/service request restores user-plane resources for an established PDU session, it does not imply deleting the UE IP/TUN interface. Deleting the UE TUN with SDAP entity teardown breaks user-plane continuity after re-attach. We need SDAP entity lifetime and UE TUN lifetime to be decoupled. This commit keeps a UE/PDU-session TUN registry outside the SDAP entity lifetime. When a UE SDAP entity is recreated, reattach it to the preserved TUN socket and restart the reader thread. On first PDU session setup, NAS registers the TUN before attaching the reader. The sequence is the following: (1) NAS register the iface (2) sdap entity attaches to the iface (3) UE goes IDLE, SDAP entity is destroyed, iface is deatched and brought down (4) UE Service Request, SDAP entity is created (5) iface reattaches to the SDAP entity and is brought up UE reattach assumes the PDU session TUN interface was registered before the SDAP entity is recreated. DL/UL data is intentionally dropped when SDAP is not yet attached or QFI is unavailable, rather than queued in this layer. Changes: - `nr_sdap.c`: keep a UE/PDU-session TUN registry, duplicate the stored socket into each SDAP entity, and add attach/detach/destroy helpers. - `nr_sdap_entity.c`: detach SDAP entities from their TUN reader on deletion, preserve UE TUN interfaces across idle cleanup, and destroy gNB TUN interfaces when the gNB entity is removed. Drop downlink SDUs if the UE SDAP entity is not attached to a TUN socket yet. - `openair3/NAS/NR_UE/nr_nas_msg.c`: set QFI before UE TUN creation so first attach can pick up cached QFI. - `common/utils/tuntap_if.c`: add `tuntap_set_up`/`tuntap_set_down` helpers for UE interface state reflection and initialize `flags` in `tuntap_destroy` to avoid maybe-uninitialized build failures. Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
This commit is contained in:
@@ -184,6 +184,18 @@ static bool set_if_flags(int sock_fd, const char *ifn, short flags)
|
||||
return true;
|
||||
}
|
||||
|
||||
short tuntap_set_up(const char *ifname, int sock_fd)
|
||||
{
|
||||
short flags = 0;
|
||||
if (!get_if_flags(sock_fd, ifname, &flags))
|
||||
return -1;
|
||||
|
||||
flags |= IFF_UP;
|
||||
if (!set_if_flags(sock_fd, ifname, flags))
|
||||
return -1;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool tun_config(const char* ifname, const char *ipv4, const char *ipv6)
|
||||
{
|
||||
@@ -215,10 +227,10 @@ 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 = set_if_flags(sock_fd, ifname, (IFF_UP | IFF_NOARP | IFF_POINTOPOINT) & ~IFF_MULTICAST);
|
||||
if (success) {
|
||||
const short flags = tuntap_set_up(ifname, sock_fd);
|
||||
success = flags >= 0 && set_if_flags(sock_fd, ifname, (flags | IFF_NOARP | IFF_POINTOPOINT) & ~IFF_MULTICAST);
|
||||
}
|
||||
|
||||
if (success)
|
||||
LOG_A(OIP, "TUN Interface %s successfully configured, IPv4 %s, IPv6 %s\n", ifname, ipv4, ipv6);
|
||||
@@ -233,11 +245,11 @@ 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));
|
||||
LOG_E(UTIL, "tap_config: failed creating socket %d, %s\n", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = set_if_flags(sock_fd, ifname, IFF_UP);
|
||||
const bool success = tuntap_set_up(ifname, sock_fd) >= 0;
|
||||
|
||||
if (success)
|
||||
LOG_A(OIP, "TAP interface %s successfully configured\n", ifname);
|
||||
@@ -282,6 +294,7 @@ int tuntap_generate_ue_ifname(char *ifname, int flag, int instance_id, int pdu_s
|
||||
char pdu_session_string[10];
|
||||
snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id);
|
||||
const char *basename = flag == IFF_TUN ? "oaitun_ue" : "oaitap_ue";
|
||||
// ifname: oaitun_ue<ue_id+1>[p<pdu_session_id>] when not default
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d%s", basename, instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
|
||||
}
|
||||
|
||||
@@ -295,7 +308,7 @@ void tuntap_destroy(const char *dev)
|
||||
}
|
||||
|
||||
// interface not up => down
|
||||
short flags;
|
||||
short flags = 0;
|
||||
bool success = get_if_flags(fd, dev, &flags);
|
||||
success = success && set_if_flags(fd, dev, flags & ~IFF_UP);
|
||||
if (success) {
|
||||
|
||||
@@ -90,4 +90,12 @@ int tuntap_alloc(int flag, const char *dev);
|
||||
*/
|
||||
void tuntap_destroy(const char *dev);
|
||||
|
||||
/*!
|
||||
* \brief Bring a TUN/TAP interface administratively up (IOCTL SIOCSIFFLAGS, set IFF_UP).
|
||||
* \param[in] ifname name of the interface
|
||||
* \param[in] sock_fd IPv4 SOCK_DGRAM fd for ioctl (opened by the caller)
|
||||
* \return interface flags with IFF_UP set, or -1 on failure
|
||||
*/
|
||||
short tuntap_set_up(const char *ifname, int sock_fd);
|
||||
|
||||
#endif /*TUN_IF_H_*/
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "SIMULATION/TOOLS/sim.h" // for taus
|
||||
|
||||
#include "nr_nas_msg.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h"
|
||||
|
||||
static NR_UE_RRC_INST_t *NR_UE_rrc_inst[MAX_NUM_NR_UE_INST] = {0};
|
||||
|
||||
@@ -5,16 +5,30 @@
|
||||
#include "nr_sdap.h"
|
||||
#include "assertions.h"
|
||||
#include "utils.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "nr_sdap_entity.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "errno.h"
|
||||
#include "rlc.h"
|
||||
#include "tuntap_if.h"
|
||||
#include "system.h"
|
||||
|
||||
typedef struct sdap_tun_iface_s {
|
||||
ue_id_t ue_id;
|
||||
int pdusession_id;
|
||||
int sock;
|
||||
char *ifname;
|
||||
int qfi;
|
||||
struct sdap_tun_iface_s *next;
|
||||
} sdap_tun_iface_t;
|
||||
|
||||
static sdap_tun_iface_t *sdap_tun_iface_list = NULL;
|
||||
|
||||
static void reblock_tun_socket(int fd)
|
||||
{
|
||||
int f;
|
||||
@@ -26,6 +40,88 @@ static void reblock_tun_socket(int fd)
|
||||
}
|
||||
}
|
||||
|
||||
static void *sdap_tun_read_thread(void *arg);
|
||||
|
||||
static sdap_tun_iface_t *sdap_tun_iface_lookup(ue_id_t ue_id, int pdusession_id)
|
||||
{
|
||||
for (sdap_tun_iface_t *it = sdap_tun_iface_list; it != NULL; it = it->next) {
|
||||
if (it->ue_id == ue_id && it->pdusession_id == pdusession_id)
|
||||
return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nr_sdap_tun_store_qfi(ue_id_t ue_id, int pdusession_id, uint8_t qfi)
|
||||
{
|
||||
DevAssert(qfi < SDAP_MAX_QFI);
|
||||
sdap_tun_iface_t *iface = sdap_tun_iface_lookup(ue_id, pdusession_id);
|
||||
if (iface == NULL)
|
||||
return;
|
||||
|
||||
iface->qfi = qfi;
|
||||
}
|
||||
|
||||
void nr_sdap_tun_attach(nr_sdap_entity_t *entity)
|
||||
{
|
||||
DevAssert(entity);
|
||||
if (entity->pdusession_sock >= 0)
|
||||
return;
|
||||
|
||||
sdap_tun_iface_t *iface = sdap_tun_iface_lookup(entity->ue_id, entity->pdusession_id);
|
||||
if (iface == NULL)
|
||||
return;
|
||||
|
||||
if (!entity->is_gnb && iface->qfi >= 0 && iface->qfi < SDAP_MAX_QFI) {
|
||||
entity->qfi = iface->qfi;
|
||||
LOG_I(SDAP, "UE %ld PDU session %d: cached QFI %d\n", entity->ue_id, entity->pdusession_id, entity->qfi);
|
||||
}
|
||||
|
||||
/* For UE, reflect UP suspend/resume to the OS by toggling IFF_UP. */
|
||||
if (!entity->is_gnb) {
|
||||
LOG_I(SDAP, "UE %ld PDU session %d: bringing TUN %s up\n", entity->ue_id, entity->pdusession_id, iface->ifname);
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd >= 0) {
|
||||
tuntap_set_up(iface->ifname, fd);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
int d = dup(iface->sock);
|
||||
AssertFatal(d >= 0, "dup(tun sock) failed: errno %d %s\n", errno, strerror(errno));
|
||||
reblock_tun_socket(d);
|
||||
entity->pdusession_sock = d;
|
||||
entity->stop_thread = false;
|
||||
|
||||
char thread_name[64];
|
||||
if (entity->is_gnb) {
|
||||
snprintf(thread_name, sizeof(thread_name), "gnb_tun_read_thread");
|
||||
} else {
|
||||
snprintf(thread_name,
|
||||
sizeof(thread_name),
|
||||
"ue_tun_read_%ld_p%d",
|
||||
entity->ue_id,
|
||||
entity->pdusession_id);
|
||||
}
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, thread_name, -1, OAI_PRIORITY_RT_LOW);
|
||||
}
|
||||
|
||||
static sdap_tun_iface_t *sdap_tun_iface_register(ue_id_t ue_id, int pdusession_id, int sock, const char *ifname)
|
||||
{
|
||||
DevAssert(sdap_tun_iface_lookup(ue_id, pdusession_id) == NULL);
|
||||
sdap_tun_iface_t *iface = calloc_or_fail(1, sizeof(*iface));
|
||||
iface->ue_id = ue_id;
|
||||
iface->pdusession_id = pdusession_id;
|
||||
iface->sock = sock;
|
||||
iface->qfi = -1;
|
||||
iface->ifname = strdup(ifname);
|
||||
AssertFatal(iface->ifname != NULL, "strdup(ifname) failed\n");
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdusession_id);
|
||||
if (entity != NULL && !entity->is_gnb && entity->qfi >= 0 && entity->qfi < SDAP_MAX_QFI)
|
||||
iface->qfi = entity->qfi;
|
||||
iface->next = sdap_tun_iface_list;
|
||||
sdap_tun_iface_list = iface;
|
||||
return iface;
|
||||
}
|
||||
|
||||
bool sdap_data_req(protocol_ctxt_t *ctxt_p,
|
||||
const ue_id_t ue_id,
|
||||
@@ -88,6 +184,7 @@ static void *sdap_tun_read_thread(void *arg)
|
||||
|
||||
char rx_buf[NL_MAX_PAYLOAD];
|
||||
int len;
|
||||
DevAssert(entity->pdusession_sock >= 0);
|
||||
reblock_tun_socket(entity->pdusession_sock);
|
||||
|
||||
while (!entity->stop_thread) {
|
||||
@@ -112,11 +209,18 @@ static void *sdap_tun_read_thread(void *arg)
|
||||
|
||||
LOG_D(SDAP, "read data of size %d\n", len);
|
||||
|
||||
if (!entity->is_gnb && entity->enable_sdap && (entity->qfi < 0 || entity->qfi >= SDAP_MAX_QFI)) {
|
||||
LOG_W(SDAP,
|
||||
"Dropping UL SDU for UE %ld PDU session %d: no QoS rule QFI available for SDAP header\n",
|
||||
entity->ue_id,
|
||||
entity->pdusession_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
protocol_ctxt_t ctxt = {.enb_flag = entity->is_gnb, .rntiMaybeUEid = entity->ue_id};
|
||||
|
||||
bool dc = entity->is_gnb ? false : SDAP_HDR_UL_DATA_PDU;
|
||||
|
||||
DevAssert(entity != NULL);
|
||||
entity->tx_entity(entity,
|
||||
&ctxt,
|
||||
SRB_FLAG_NO,
|
||||
@@ -134,6 +238,56 @@ static void *sdap_tun_read_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nr_sdap_tun_detach(nr_sdap_entity_t *entity)
|
||||
{
|
||||
DevAssert(entity != NULL);
|
||||
sdap_tun_iface_t *iface = NULL;
|
||||
if (!entity->is_gnb) {
|
||||
iface = sdap_tun_iface_lookup(entity->ue_id, entity->pdusession_id);
|
||||
if (iface != NULL && entity->qfi >= 0 && entity->qfi < SDAP_MAX_QFI)
|
||||
iface->qfi = entity->qfi; // store the QFI for the next attach
|
||||
}
|
||||
if (entity->pdusession_sock < 0)
|
||||
return;
|
||||
|
||||
entity->stop_thread = true;
|
||||
close(entity->pdusession_sock);
|
||||
entity->pdusession_sock = -1;
|
||||
|
||||
/* For UE, bring interface down so the OS reflects UP suspension. */
|
||||
if (!entity->is_gnb && iface != NULL) {
|
||||
LOG_I(SDAP, "UE %ld PDU session %d: bringing TUN %s down\n", entity->ue_id, entity->pdusession_id, iface->ifname);
|
||||
tuntap_destroy(iface->ifname);
|
||||
}
|
||||
|
||||
int cancel_ret = pthread_cancel(entity->pdusession_thread);
|
||||
AssertFatal(cancel_ret == 0, "pthread_cancel() failed: %d (%s)\n", cancel_ret, strerror(cancel_ret));
|
||||
int ret = pthread_join(entity->pdusession_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join() failed: %d (%s)\n", ret, strerror(ret));
|
||||
}
|
||||
|
||||
void nr_sdap_tun_destroy(ue_id_t ue_id, int pdusession_id)
|
||||
{
|
||||
sdap_tun_iface_t *iface = NULL;
|
||||
for (sdap_tun_iface_t **pp = &sdap_tun_iface_list; *pp != NULL; pp = &(*pp)->next) {
|
||||
if ((*pp)->ue_id == ue_id && (*pp)->pdusession_id == pdusession_id) {
|
||||
iface = *pp;
|
||||
*pp = iface->next;
|
||||
iface->next = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iface == NULL) {
|
||||
LOG_D(SDAP, "nr_sdap_tun_destroy: no iface (ue=%ld, pdu=%d)\n", ue_id, pdusession_id);
|
||||
return;
|
||||
}
|
||||
close(iface->sock);
|
||||
tuntap_destroy(iface->ifname);
|
||||
LOG_I(SDAP, "Destroyed TUN dataplane for UE %ld PDU session %d (%s)\n", iface->ue_id, iface->pdusession_id, iface->ifname);
|
||||
free(iface->ifname);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
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, pdu_session_id);
|
||||
@@ -142,10 +296,10 @@ void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_sess
|
||||
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ifname(ifname, ifprefix, ue_id - 1);
|
||||
entity->pdusession_sock = tuntap_alloc(IFF_TUN, ifname);
|
||||
entity->pdusession_if_name = strdup(ifname);
|
||||
const int sock = tuntap_alloc(IFF_TUN, 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);
|
||||
sdap_tun_iface_register(entity->ue_id, entity->pdusession_id, sock, ifname);
|
||||
nr_sdap_tun_attach(entity);
|
||||
}
|
||||
|
||||
static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const char *ifname)
|
||||
@@ -153,51 +307,44 @@ static void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock, const
|
||||
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);
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, thread_name, -1, OAI_PRIORITY_RT_LOW);
|
||||
// First PDU session setup: register UE TUN and attach the reader thread
|
||||
sdap_tun_iface_register(ue_id, pdu_session_id, sock, ifname);
|
||||
nr_sdap_tun_attach(entity);
|
||||
}
|
||||
|
||||
|
||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default)
|
||||
{
|
||||
char ifname[IFNAMSIZ];
|
||||
tuntap_generate_ue_ifname(ifname, IFF_TUN, ue_id, is_default ? -1 : pdu_session_id);
|
||||
const int sock = tuntap_alloc(IFF_TUN, ifname);
|
||||
|
||||
if (sdap_tun_iface_lookup(ue_id, pdu_session_id) == NULL) {
|
||||
const int sock = tuntap_alloc(IFF_TUN, ifname);
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname);
|
||||
} else {
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
|
||||
if (entity != NULL)
|
||||
nr_sdap_tun_attach(entity);
|
||||
}
|
||||
|
||||
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, 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;
|
||||
|
||||
// Close the socket: read() will get EBADF and exit
|
||||
close(entity->pdusession_sock);
|
||||
|
||||
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
|
||||
tuntap_destroy(entity->pdusession_if_name);
|
||||
free(entity->pdusession_if_name);
|
||||
entity->pdusession_if_name = NULL;
|
||||
|
||||
if (sdap_tun_iface_lookup(ue_id, pdu_session_id) == NULL) {
|
||||
const int sock = tuntap_alloc(IFF_TAP, ifname);
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock, ifname);
|
||||
} else {
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
|
||||
if (entity != NULL)
|
||||
nr_sdap_tun_attach(entity);
|
||||
}
|
||||
|
||||
tap_config(ifname);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <stdint.h>
|
||||
#include "common/platform_types.h"
|
||||
|
||||
struct nr_sdap_entity_s;
|
||||
|
||||
/*
|
||||
* TS 37.324 4.4 Functions
|
||||
* Transfer of user plane data
|
||||
@@ -40,5 +42,9 @@ void sdap_data_ind(int pdcp_entity, int is_gnb, int pdusession_id, ue_id_t ue_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);
|
||||
void nr_sdap_tun_attach(struct nr_sdap_entity_s *entity);
|
||||
void nr_sdap_tun_detach(struct nr_sdap_entity_s *entity);
|
||||
void nr_sdap_tun_destroy(ue_id_t ue_id, int pdusession_id);
|
||||
void nr_sdap_tun_store_qfi(ue_id_t ue_id, int pdusession_id, uint8_t qfi);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <openair3/ocp-gtpu/gtp_itf.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "T.h"
|
||||
#include "assertions.h"
|
||||
@@ -14,7 +15,6 @@
|
||||
#include "gtpv1_u_messages_types.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "rlc.h"
|
||||
#include "tuntap_if.h"
|
||||
#include "nr_sdap.h"
|
||||
|
||||
#define NO_SDAP_HEADER 0
|
||||
@@ -27,6 +27,15 @@ static nr_sdap_entity_info sdap_info;
|
||||
|
||||
instance_t *N3GTPUInst = NULL;
|
||||
|
||||
static void remove_ip_if(nr_sdap_entity_t *entity)
|
||||
{
|
||||
DevAssert(entity != NULL);
|
||||
nr_sdap_tun_detach(entity);
|
||||
if (!entity->is_gnb)
|
||||
return;
|
||||
nr_sdap_tun_destroy(entity->ue_id, entity->pdusession_id);
|
||||
}
|
||||
|
||||
/** @brief Returns a bitmap indicating the SDAP entity role,
|
||||
* i.e. for UL transmission, header for UL data is present in RX/TX
|
||||
* for DL transmission, header for DL data is present in RX/TX */
|
||||
@@ -338,6 +347,10 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
|
||||
* 5.2.2 Downlink
|
||||
* deliver the retrieved SDAP SDU to the upper layer.
|
||||
*/
|
||||
if (entity->pdusession_sock < 0) {
|
||||
LOG_D(SDAP, "[UE %ld] PDU session %d: TUN not attached, drop DL SDU (%d B)\n", ue_id, pdusession_id, size - offset);
|
||||
return;
|
||||
}
|
||||
int len = write(entity->pdusession_sock, &buf[offset], size - offset);
|
||||
LOG_D(SDAP, "RX Entity len : %d\n", len);
|
||||
LOG_D(SDAP, "RX Entity size : %d\n", size);
|
||||
@@ -568,6 +581,13 @@ static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap
|
||||
// PDCP SDUs to/from the TUN interface.
|
||||
start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id, sdap_entity->pdusession_id);
|
||||
}
|
||||
|
||||
if (!is_gnb) {
|
||||
/* No-op on first setup until NAS registers the TUN. After paging/service request,
|
||||
* re-attach the preserved UE TUN for the established PDU session (TS 38.304 clause 7.1,
|
||||
* TS 24.501 clauses 5.6.2.2.1/5.6.1.1 restore UP resources for an established PDU session). */
|
||||
nr_sdap_tun_attach(sdap_entity);
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Add or modify an SDAP entity if it already exists */
|
||||
@@ -692,8 +712,7 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
||||
|
||||
if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) {
|
||||
sdap_info.sdap_entity_llist = sdap_info.sdap_entity_llist->next_entity;
|
||||
if (entityPtr->pdusession_sock != -1)
|
||||
remove_ip_if(entityPtr);
|
||||
remove_ip_if(entityPtr);
|
||||
free(entityPtr);
|
||||
LOG_D(SDAP, "Successfully deleted SDAP entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id);
|
||||
return true;
|
||||
@@ -707,9 +726,7 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
||||
|
||||
if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) {
|
||||
entityPrev->next_entity = entityPtr->next_entity;
|
||||
if (entityPtr->pdusession_sock != -1) {
|
||||
remove_ip_if(entityPtr);
|
||||
}
|
||||
remove_ip_if(entityPtr);
|
||||
free(entityPtr);
|
||||
LOG_D(SDAP, "Successfully deleted Entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id);
|
||||
return true;
|
||||
@@ -734,8 +751,7 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
|
||||
/* Handle scenario where ue_id matches the head of the list */
|
||||
while (entityPtr != NULL && entityPtr->ue_id == ue_id && upperBound < MAX_DRBS_PER_UE) {
|
||||
sdap_info.sdap_entity_llist = entityPtr->next_entity;
|
||||
if (entityPtr->pdusession_sock != -1)
|
||||
remove_ip_if(entityPtr);
|
||||
remove_ip_if(entityPtr);
|
||||
free(entityPtr);
|
||||
entityPtr = sdap_info.sdap_entity_llist;
|
||||
ret = true;
|
||||
@@ -747,8 +763,7 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
|
||||
entityPtr = entityPtr->next_entity;
|
||||
} else {
|
||||
entityPrev->next_entity = entityPtr->next_entity;
|
||||
if (entityPtr->pdusession_sock != -1)
|
||||
remove_ip_if(entityPtr);
|
||||
remove_ip_if(entityPtr);
|
||||
free(entityPtr);
|
||||
entityPtr = entityPrev->next_entity;
|
||||
LOG_I(SDAP, "Successfully deleted SDAP entity for UE %ld\n", ue_id);
|
||||
@@ -815,8 +830,9 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in
|
||||
|
||||
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id)
|
||||
{
|
||||
DevAssert(qfi < SDAP_MAX_QFI);
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pduid);
|
||||
DevAssert(entity != NULL);
|
||||
entity->qfi = qfi;
|
||||
return;
|
||||
nr_sdap_tun_store_qfi(ue_id, pduid, qfi);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ 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;
|
||||
@@ -186,5 +185,4 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in
|
||||
void nr_sdap_entity_update_qos_flows(ue_id_t ue_id, int pdusession_id, int drb_id, const uint8_t *qfis, int n_qfis);
|
||||
|
||||
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id);
|
||||
void remove_ip_if(nr_sdap_entity_t *entity);
|
||||
#endif
|
||||
|
||||
@@ -2428,8 +2428,8 @@ void *nas_nrue(void *args_p)
|
||||
const char *ip = "10.0.1.2";
|
||||
const int qfi = 7;
|
||||
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);
|
||||
create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id, is_default);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user