diff --git a/common/utils/tun_if.c b/common/utils/tun_if.c index 79fcc6a954..87bba5a513 100644 --- a/common/utils/tun_if.c +++ b/common/utils/tun_if.c @@ -38,7 +38,7 @@ int nas_sock_fd[MAX_MOBILES_PER_ENB * 2]; // Allocated for both LTE UE and NR UE. int nas_sock_mbms_fd; -static int tun_alloc(const char *dev) +int tun_alloc(const char *dev) { struct ifreq ifr; int fd, err; @@ -157,13 +157,14 @@ static bool setInterfaceParameter(int sock_fd, const char *ifn, int af, const ch return success; } -/* - * \brief bring interface up (up != 0) or down (up == 0) - */ + typedef enum { INTERFACE_DOWN, INTERFACE_UP } if_action_t; +/* +* \brief bring interface up (up != 0) or down (up == 0) +*/ static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_action) { - const char* action = if_action == INTERFACE_DOWN ? "DOWN" : "UP"; + const char *action = if_action == INTERFACE_DOWN ? "DOWN" : "UP"; struct ifreq ifr = {0}; strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name)); @@ -189,6 +190,7 @@ fail_interface_state: return false; } + bool tun_config(const char* ifname, const char *ipv4, const char *ipv6) { AssertFatal(ipv4 != NULL || ipv6 != NULL, "need to have IP address, but none given\n"); @@ -262,3 +264,19 @@ int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id) { return snprintf(ifname, IFNAMSIZ, "%s%d", ifprefix, instance_id + 1); } + +int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id) +{ + char pdu_session_string[10]; + snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id); + return snprintf(ifname, IFNAMSIZ, "%s%d%s", "oaitun_ue", instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string); +} + +void tun_destroy(const char *dev, int fd) { + if (change_interface_state(fd, dev, INTERFACE_DOWN) == 0) { + LOG_I(UTIL, "Interface %s is now down.\n", dev); + } else { + LOG_E(UTIL, "Could not bring interface %s down.\n", dev); + } + close(fd); +} diff --git a/common/utils/tun_if.h b/common/utils/tun_if.h index eafc5b3350..e73b4be94e 100644 --- a/common/utils/tun_if.h +++ b/common/utils/tun_if.h @@ -34,6 +34,7 @@ * \param[in] instance_id unique instance number */ int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id); +int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id); /*! * \brief This function initializes the TUN interface @@ -73,4 +74,18 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6); */ void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4); +/*! + * \brief This function allocates a TUN interface + * \param[in] dev name of the interface + * \return file descriptor of the allocated interface + */ +int tun_alloc(const char *dev); + +/*! + * \brief This function destroys the TUN interface + * \param[in] dev name of the interface + * \param[in] fd file descriptor of the allocated interface + */ +void tun_destroy(const char *dev, int fd); + #endif /*TUN_IF_H_*/ diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 205da81b6b..da7f014fb7 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -329,7 +329,7 @@ To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in ## PDCP Tx flow -On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `enb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`. +On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `gnb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`. ## PDCP Rx flow diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 4f9ae49c42..f72ef0d0d1 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -85,6 +85,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "utils.h" #include "x2ap_eNB.h" #include "openair1/SCHED_NR/sched_nr.h" +#include "openair2/SDAP/nr_sdap/nr_sdap.h" pthread_cond_t nfapi_sync_cond; pthread_mutex_t nfapi_sync_mutex; @@ -497,11 +498,8 @@ static void wait_nfapi_init(char *thread_name) } void init_pdcp(void) { - uint32_t pdcp_initmask = IS_SOFTMODEM_NOS1 ? ENB_NAS_USE_TUN_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT; - if (!NODE_IS_DU(get_node_type())) { nr_pdcp_layer_init(); - nr_pdcp_module_init(pdcp_initmask, 0); } } diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 931ffc3f31..6d3efc28cd 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -301,25 +301,10 @@ void init_openair0() static void init_pdcp(int ue_id) { - uint32_t pdcp_initmask = (!IS_SOFTMODEM_NOS1) ? LINK_ENB_PDCP_TO_GTPV1U_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT; - - /*if (IS_SOFTMODEM_RFSIM || (nfapi_getmode()==NFAPI_UE_STUB_PNF)) { - pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT; - }*/ - - // previous code was: - // if (IS_SOFTMODEM_NOKRNMOD) - // pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT; - // The kernel module (KRNMOD) has been removed from the project, so the 'if' - // was removed but the flag 'pdcp_initmask' was kept, as "no kernel module" - // was always set. further refactoring could take it out - pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT; - if (get_softmodem_params()->nsa && nr_rlc_module_init(0) != 0) { LOG_I(RLC, "Problem at RLC initiation \n"); } nr_pdcp_layer_init(); - nr_pdcp_module_init(pdcp_initmask, ue_id); } // Stupid function addition because UE itti messages queues definition is common with eNB @@ -449,6 +434,11 @@ int main(int argc, char **argv) } } + if (create_tasks_nrue(1) < 0) { + printf("cannot create ITTI tasks\n"); + exit(-1); // need a softer mode + } + int mode_offset = get_softmodem_params()->nsa ? NUMBER_OF_UE_MAX : 1; uint16_t node_number = get_softmodem_params()->node_number; ue_id_g = (node_number == 0) ? 0 : node_number - 2; @@ -557,11 +547,6 @@ int main(int argc, char **argv) // wait for end of program printf("TYPE TO TERMINATE\n"); - if (create_tasks_nrue(1) < 0) { - printf("cannot create ITTI tasks\n"); - exit(-1); // need a softer mode - } - // Sleep a while before checking all parameters have been used // Some are used directly in external threads, asynchronously sleep(2); diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 348920868c..8bd3558ff1 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -144,6 +144,7 @@ extern "C" #define EMULATE_L1 softmodem_params.emulate_l1 #define CONTINUOUS_TX softmodem_params.continuous_tx #define SYNC_REF softmodem_params.sync_ref +#define DEFAULT_PDU_ID softmodem_params.default_pdu_session_id #define DEFAULT_RFCONFIG_FILE "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat"; @@ -188,6 +189,7 @@ extern int usrp_tx_thread; {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \ {"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \ {"imscope-record" , CONFIG_HLP_IMSCOPE_RECORD,PARAMFLAG_BOOL, .uptr=&enable_imscope_record, .defintval=0, TYPE_UINT, 0}, \ + {"default_pdu_id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=10, TYPE_INT, 0}, \ } // clang-format on @@ -234,6 +236,7 @@ extern int usrp_tx_thread; { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } // clang-format on @@ -343,6 +346,7 @@ typedef struct { uint32_t sync_ref; int no_itti; int threequarter_fs; + int default_pdu_session_id; } softmodem_params_t; #define IS_SA_MODE(sM_params) (!(sM_params)->phy_test && !(sM_params)->do_ra && !(sM_params)->nsa) diff --git a/openair2/COMMON/as_message.h b/openair2/COMMON/as_message.h index 31d53d12fe..1fb59c6aa9 100644 --- a/openair2/COMMON/as_message.h +++ b/openair2/COMMON/as_message.h @@ -469,6 +469,10 @@ typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t; */ typedef ul_info_transfer_ind_t dl_info_transfer_ind_t; +typedef struct nas_nos1_msg_s { + int dummy; // This dummy element is to avoid CLANG warning: empty struct has size 0 in C, size 1 in C++ +} nas_nos1_msg_t; + typedef struct nas_pdu_session_req_s { int pdusession_id; int pdusession_type; diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index 841c44d612..67aadb2869 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -79,6 +79,7 @@ MESSAGE_DEF(NR_NAS_CONN_ESTABLISH_IND, MESSAGE_PRIORITY_MED, nas_establish_ind_t MESSAGE_DEF(NR_NAS_CONN_RELEASE_IND, MESSAGE_PRIORITY_MED, NRNasConnReleaseInd, nr_nas_conn_release_ind) MESSAGE_DEF(NAS_UPLINK_DATA_CNF, MESSAGE_PRIORITY_MED, ul_info_transfer_cnf_t, nas_ul_data_cnf) MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, dl_info_transfer_ind_t, nas_dl_data_ind) +MESSAGE_DEF(NAS_INIT_NOS1_IF, MESSAGE_PRIORITY_MED, nas_nos1_msg_t, nas_init_nos1_if) // xNB: realtime -> RRC messages MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index d8b706520e..94df409113 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -390,168 +390,6 @@ bool nr_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP, /* pdcp_data_ind thread - end */ /****************************************************************************/ -/****************************************************************************/ -/* hacks to be cleaned up at some point - begin */ -/****************************************************************************/ - -#include "LAYER2/MAC/mac_extern.h" - -static void reblock_tun_socket(void) -{ - extern int nas_sock_fd[]; - int f; - - f = fcntl(nas_sock_fd[0], F_GETFL, 0); - f &= ~(O_NONBLOCK); - if (fcntl(nas_sock_fd[0], F_SETFL, f) == -1) { - LOG_E(PDCP, "fcntl(F_SETFL) failed on fd %d: errno %d, %s\n", nas_sock_fd[0], errno, strerror(errno)); - } -} - -static void *enb_tun_read_thread(void *_) -{ - extern int nas_sock_fd[]; - char rx_buf[NL_MAX_PAYLOAD]; - int len; - protocol_ctxt_t ctxt; - ue_id_t UEid; - - int rb_id = 1; - pthread_setname_np( pthread_self(),"enb_tun_read"); - - while (1) { - len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD); - if (len == -1) { - LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno)); - return NULL; - } - - LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len); - - nr_pdcp_manager_lock(nr_pdcp_ue_manager); - const bool has_ue = nr_pdcp_get_first_ue_id(nr_pdcp_ue_manager, &UEid); - nr_pdcp_manager_unlock(nr_pdcp_ue_manager); - - if (!has_ue) continue; - - ctxt.module_id = 0; - ctxt.enb_flag = 1; - ctxt.instance = 0; - ctxt.frame = 0; - ctxt.subframe = 0; - ctxt.eNB_index = 0; - ctxt.brOption = 0; - ctxt.rntiMaybeUEid = UEid; - - uint8_t qfi = 7; - bool rqi = 0; - int pdusession_id = 10; - - sdap_data_req(&ctxt, - UEid, - SRB_FLAG_NO, - rb_id, - RLC_MUI_UNDEFINED, - RLC_SDU_CONFIRM_NO, - len, - (unsigned char *)rx_buf, - PDCP_TRANSMISSION_MODE_DATA, - NULL, - NULL, - qfi, - rqi, - pdusession_id); - } - - return NULL; -} - -static void *ue_tun_read_thread(void *_) -{ - extern int nas_sock_fd[]; - char rx_buf[NL_MAX_PAYLOAD]; - int len; - protocol_ctxt_t ctxt; - ue_id_t UEid; - int has_ue; - - int rb_id = 1; - pthread_setname_np( pthread_self(),"ue_tun_read"); - while (1) { - len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD); - if (len == -1) { - LOG_E(PDCP, "error: cannot read() from fd %d: errno %d, %s\n", nas_sock_fd[0], errno, strerror(errno)); - return NULL; /* exit thread */ - } - - LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len); - - nr_pdcp_manager_lock(nr_pdcp_ue_manager); - has_ue = nr_pdcp_get_first_ue_id(nr_pdcp_ue_manager, &UEid); - nr_pdcp_manager_unlock(nr_pdcp_ue_manager); - - if (!has_ue) continue; - - ctxt.module_id = 0; - ctxt.enb_flag = 0; - ctxt.instance = 0; - ctxt.frame = 0; - ctxt.subframe = 0; - ctxt.eNB_index = 0; - ctxt.brOption = 0; - ctxt.rntiMaybeUEid = UEid; - - bool dc = SDAP_HDR_UL_DATA_PDU; - extern uint8_t nas_qfi; - extern uint8_t nas_pduid; - - sdap_data_req(&ctxt, - UEid, - SRB_FLAG_NO, - rb_id, - RLC_MUI_UNDEFINED, - RLC_SDU_CONFIRM_NO, - len, - (unsigned char *)rx_buf, - PDCP_TRANSMISSION_MODE_DATA, - NULL, - NULL, - nas_qfi, - dc, - nas_pduid); - } - - return NULL; -} - -static void start_pdcp_tun_enb(void) -{ - pthread_t t; - - reblock_tun_socket(); - - if (pthread_create(&t, NULL, enb_tun_read_thread, NULL) != 0) { - LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } -} - -static void start_pdcp_tun_ue(void) -{ - pthread_t t; - - reblock_tun_socket(); - - if (pthread_create(&t, NULL, ue_tun_read_thread, NULL) != 0) { - LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } -} - -/****************************************************************************/ -/* hacks to be cleaned up at some point - end */ -/****************************************************************************/ - int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP) { return 0; @@ -592,54 +430,7 @@ void nr_pdcp_layer_init(void) #include "nfapi/oai_integration/vendor_ext.h" #include "executables/lte-softmodem.h" #include "common/utils/tun_if.h" - -uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id) -{ - /* hack: be sure to initialize only once */ - static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; - static int initialized = 0; - if (pthread_mutex_lock(&m) != 0) abort(); - if (initialized) { - abort(); - } - initialized = 1; - if (pthread_mutex_unlock(&m) != 0) abort(); - - pdcp_optmask = pdcp_optmask | _pdcp_optmask ; - - if (UE_NAS_USE_TUN) { - char *ifprefix = get_softmodem_params()->nsa ? "oaitun_nrue" : "oaitun_ue"; - int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF) - ? MAX_MOBILES_PER_ENB - : 1; - int begx = (id == 0) ? 0 : id - 1; - int endx = (id == 0) ? num_if : id; - for (int i = begx; i < endx; i++) { - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, ifprefix, i); - tun_init(ifname, i); - } - if (IS_SOFTMODEM_NOS1) { - const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3"; - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, ifprefix, id); - tun_config(ifname, ip, NULL); - set_qfi_pduid(7, 10); - } - LOG_I(PDCP, "UE pdcp will use tun interface\n"); - start_pdcp_tun_ue(); - } else if (ENB_NAS_USE_TUN) { - char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, ifprefix, id); - tun_init(ifname, id); - tun_config(ifname, "10.0.1.1", NULL); - LOG_I(PDCP, "ENB pdcp will use tun interface\n"); - start_pdcp_tun_enb(); - } - - return pdcp_optmask ; -} +#include "openair2/SDAP/nr_sdap/nr_sdap.h" static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity, char *buf, int size, diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index a60cd869af..286d072019 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -35,7 +35,6 @@ struct NR_DRB_ToAddMod; struct NR_SRB_ToAddMod; void nr_pdcp_layer_init(void); -uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id); void du_rlc_data_req(const protocol_ctxt_t *const ctxt_pP, const srb_flag_t srb_flagP, diff --git a/openair2/RRC/NR_UE/main_ue.c b/openair2/RRC/NR_UE/main_ue.c index 0e51fe2779..e394fec299 100644 --- a/openair2/RRC/NR_UE/main_ue.c +++ b/openair2/RRC/NR_UE/main_ue.c @@ -62,6 +62,8 @@ void init_nsa_message(NR_UE_RRC_INST_t *rrc, char* reconfig_file, char* rbconfig msg_len = fread(buffer, 1, 1024, fd); fclose(fd); process_nsa_message(rrc, nr_RadioBearerConfigX_r15, buffer,msg_len); + MessageDef* ittiMsg = itti_alloc_new_message(TASK_RRC_NRUE, rrc->ue_id, NAS_INIT_NOS1_IF); + itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, ittiMsg); } else LOG_D(NR_RRC, "In NSA mode \n"); diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index d1a82310e5..1fe8e925a7 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -20,13 +20,29 @@ */ #include "nr_sdap.h" +#include "assertions.h" +#include "utils.h" #include +#include #include #include "nr_sdap_entity.h" #include "common/utils/LOG/log.h" +#include "errno.h" +#include "rlc.h" +#include "tun_if.h" +#include "system.h" + +static void reblock_tun_socket(int fd) +{ + int f; + + f = fcntl(fd, F_GETFL, 0); + f &= ~(O_NONBLOCK); + if (fcntl(fd, F_SETFL, f) == -1) { + LOG_E(PDCP, "fcntl(F_SETFL) failed on fd %d: errno %d, %s\n", fd, errno, strerror(errno)); + } +} -uint8_t nas_qfi; -uint8_t nas_pduid; bool sdap_data_req(protocol_ctxt_t *ctxt_p, const ue_id_t ue_id, @@ -91,8 +107,110 @@ void sdap_data_ind(rb_id_t pdcp_entity, size); } -void set_qfi_pduid(uint8_t qfi, uint8_t pduid){ - nas_qfi = qfi; - nas_pduid = pduid; - return; +struct thread_args { + nr_sdap_entity_t *entity; + bool is_gnb; +}; +static void *sdap_tun_read_thread(void *arg) +{ + DevAssert(arg != NULL); + struct thread_args *ta = arg; + nr_sdap_entity_t *entity = ta->entity; + bool is_gnb = ta->is_gnb; + free(ta); + + char rx_buf[NL_MAX_PAYLOAD]; + int len; + reblock_tun_socket(entity->pdusession_sock); + + int rb_id = 1; + + while (!entity->stop_thread) { + len = read(entity->pdusession_sock, &rx_buf, NL_MAX_PAYLOAD); + if (len == -1) { + LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno)); + return NULL; + } + + LOG_D(SDAP, "read data of size %d\n", len); + + protocol_ctxt_t ctxt = {.enb_flag = is_gnb, .rntiMaybeUEid = entity->ue_id}; + + bool dc = is_gnb ? false : SDAP_HDR_UL_DATA_PDU; + + DevAssert(entity != NULL); + entity->tx_entity(entity, + &ctxt, + SRB_FLAG_NO, + rb_id, + RLC_MUI_UNDEFINED, + RLC_SDU_CONFIRM_NO, + len, + (unsigned char *)rx_buf, + PDCP_TRANSMISSION_MODE_DATA, + NULL, + NULL, + entity->qfi, + dc); + } + + return NULL; +} + +void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id) +{ + nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, get_softmodem_params()->default_pdu_session_id); + DevAssert(entity != NULL); + char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, ifprefix, ue_id - 1); + entity->pdusession_sock = tun_alloc(ifname); + tun_config(ifname, "10.0.1.1", NULL); + struct thread_args *ta = calloc_or_fail(1, sizeof(*ta)); + ta->entity = entity; + ta->is_gnb = true; + + threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, "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) +{ + nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id); + DevAssert(entity != NULL); + entity->pdusession_sock = sock; + 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); + struct thread_args *ta = calloc_or_fail(1, sizeof(*ta)); + ta->entity = entity; + ta->is_gnb = false; + threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, thread_name, -1, OAI_PRIORITY_RT_LOW); +} + + +void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id) +{ + int default_pdu = get_softmodem_params()->default_pdu_session_id; + char ifname[IFNAMSIZ]; + tun_generate_ue_ifname(ifname, ue_id, pdu_session_id != default_pdu ? pdu_session_id : -1); + const int sock = tun_alloc(ifname); + tun_config(ifname, ipv4, ipv6); + if (ipv4) { + setup_ue_ipv4_route(ifname, ue_id, ipv4); + } + start_sdap_tun_ue(ue_id, pdu_session_id, sock); // interface name suffix is ue_id+1 +} + +void remove_ue_ip_if(nr_sdap_entity_t *entity) +{ + DevAssert(entity != NULL); + // Stop the read thread + entity->stop_thread = true; + int ret = pthread_join(entity->pdusession_thread, NULL); + AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno)); + // Bring down the IP interface + int default_pdu = get_softmodem_params()->default_pdu_session_id; + char ifname[IFNAMSIZ]; + tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1); + tun_destroy(ifname, entity->pdusession_sock); } diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h index ec2d7ad185..3877e58603 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.h +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -61,6 +61,8 @@ void sdap_data_ind(rb_id_t pdcp_entity, char *buf, int size); -void set_qfi_pduid(uint8_t qfi, uint8_t pduid); +void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock); +void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id); +void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id); #endif diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index aae6b81540..aa6ee95b47 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -31,6 +31,8 @@ #include "gtpv1_u_messages_types.h" #include "intertask_interface.h" #include "rlc.h" +#include "tun_if.h" +#include "nr_sdap.h" typedef struct { nr_sdap_entity_t *sdap_entity_llist; @@ -103,7 +105,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, /* The offset of the SDAP header, it might be 0 if has_sdap_tx is not true in the pdcp entity. */ int offset=0; bool ret = false; - /*Hardcode DRB ID given from upper layer (ue/enb_tun_read_thread rb_id), it will change if we have SDAP*/ + /*Hardcode DRB ID given from upper layer (ue/gnb_tun_read_thread rb_id), it will change if we have SDAP*/ rb_id_t sdap_drb_id = rb_id; int pdcp_ent_has_sdap = 0; @@ -321,8 +323,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, * 5.2.2 Downlink * deliver the retrieved SDAP SDU to the upper layer. */ - extern int nas_sock_fd[]; - int len = write(nas_sock_fd[0], &buf[offset], size-offset); + 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); LOG_D(SDAP, "RX Entity offset : %d\n", offset); @@ -513,6 +514,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del; sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map; + sdap_entity->pdusession_sock = -1; + if(is_defaultDRB) { sdap_entity->default_drb = drb_identity; LOG_I(SDAP, "Default DRB for the created SDAP entity: %ld \n", sdap_entity->default_drb); @@ -523,6 +526,12 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, sdap_entity->next_entity = sdap_info.sdap_entity_llist; sdap_info.sdap_entity_llist = sdap_entity; + + if (IS_SOFTMODEM_NOS1 && is_gnb) { + // In NOS1 mode, terminate SDAP for the first UE on the gNB. This allows injecting/receiving + // PDCP SDUs to/from the TUN interface. + start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id); + } return sdap_entity; } @@ -591,6 +600,9 @@ 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 (entityPrev->pdusession_sock != -1) { + remove_ue_ip_if(entityPrev); + } free(entityPtr); LOG_D(SDAP, "Successfully deleted Entity.\n"); ret = true; @@ -674,3 +686,11 @@ 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) +{ + nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pduid); + DevAssert(entity != NULL); + entity->qfi = qfi; + return; +} diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index bff1c49281..adfc48e663 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -81,6 +81,11 @@ typedef struct nr_sdap_entity_s { ue_id_t ue_id; rb_id_t default_drb; int pdusession_id; + int pdusession_sock; + pthread_t pdusession_thread; + bool stop_thread; + int qfi; + qfi2drb_t qfi2drb_table[SDAP_MAX_QFI]; void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx); @@ -212,4 +217,6 @@ bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config); */ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, int pdusession_id, int drb_id); +void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id); +void remove_ue_ip_if(nr_sdap_entity_t *entity); #endif diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 941e0d7cdc..61df0fe098 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -64,6 +64,7 @@ #include "secu_defs.h" #include "utils.h" #include "openair2/SDAP/nr_sdap/nr_sdap.h" +#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" #include "fgs_nas_utils.h" #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" @@ -1059,7 +1060,7 @@ static int capture_ipv6_addr(const uint8_t *addr, char *ip, size_t len) * @brief Process PDU Session Address in PDU Session Establishment Accept message * and configure the tun interface */ -static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg) +static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg, int instance_id, int pdu_session_id) { uint8_t *addr = msg->pdu_addr_ie.pdu_addr_oct; @@ -1067,18 +1068,13 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg case PDU_SESSION_TYPE_IPV4: { char ip[20]; capture_ipv4_addr(&addr[0], ip, sizeof(ip)); - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, "oaitun_ue", 0); - tun_config(ifname, ip, NULL); - setup_ue_ipv4_route(ifname, 0, ip); + create_ue_ip_if(ip, NULL, instance_id, pdu_session_id); } break; case PDU_SESSION_TYPE_IPV6: { char ipv6[40]; capture_ipv6_addr(addr, ipv6, sizeof(ipv6)); - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, "oaitun_ue", 0); - tun_config(ifname, NULL, ipv6); + create_ue_ip_if(NULL, ipv6, instance_id, pdu_session_id); } break; case PDU_SESSION_TYPE_IPV4V6: { @@ -1086,10 +1082,7 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg capture_ipv6_addr(addr, ipv6, sizeof(ipv6)); char ipv4[20]; capture_ipv4_addr(&addr[IPv6_INTERFACE_ID_LENGTH], ipv4, sizeof(ipv4)); - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, "oaitun_ue", 0); - tun_config(ifname, ipv4, ipv6); - setup_ue_ipv4_route(ifname, 0, ipv4); + create_ue_ip_if(ipv4, ipv6, instance_id, pdu_session_id); } break; default: @@ -1101,7 +1094,7 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg /** * @brief Handle PDU Session Establishment Accept and process decoded message */ -static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length) +static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length, int instance) { pdu_session_establishment_accept_msg_t msg = {0}; int size = 0; @@ -1143,24 +1136,23 @@ static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length) LOG_E(NAS, "decode_pdu_session_establishment_accept_msg failure\n"); // process PDU Session - if (msg.pdu_addr_ie.pdu_length) - process_pdu_session_addr(&msg); + 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_pduid(msg.qos_rules.rule->qfi, sm_header.pdu_session_id); + set_qfi(msg.qos_rules.rule->qfi, sm_header.pdu_session_id, instance); } /** * @brief Handle DL NAS Transport and process piggybacked 5GSM messages */ -static void handleDownlinkNASTransport(uint8_t *pdu_buffer, uint32_t msg_length) +void handleDownlinkNASTransport(uint8_t * pdu_buffer, int pdu_length, int instance) { uint8_t msg_type = *(pdu_buffer + 16); if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { LOG_A(NAS, "Received PDU Session Establishment Accept in DL NAS Transport\n"); - handle_pdu_session_accept(pdu_buffer, msg_length); + handle_pdu_session_accept(pdu_buffer, pdu_length, instance); } else { LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type); } @@ -1403,7 +1395,7 @@ static void send_nas_5gmm_ind(instance_t instance, const Guti5GSMobileIdentity_t static void request_default_pdusession(nr_ue_nas_t *nas) { 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 = 10; /* first or default pdu session */ + NAS_PDU_SESSION_REQ(message_p).pdusession_id = get_softmodem_params()->default_pdu_session_id; NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6 NAS_PDU_SESSION_REQ(message_p).sst = nas->uicc->nssai_sst; NAS_PDU_SESSION_REQ(message_p).sd = nas->uicc->nssai_sd; @@ -1634,7 +1626,7 @@ void *nas_nrue(void *args_p) if (msg_type == FGS_REGISTRATION_ACCEPT) { handle_registration_accept(nas, pdu_buffer, pdu_length); } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { - handle_pdu_session_accept(pdu_buffer, pdu_length); + handle_pdu_session_accept(pdu_buffer, pdu_length, nas->UE_id); } // Free NAS buffer memory after use (coming from RRC) @@ -1724,7 +1716,7 @@ void *nas_nrue(void *args_p) handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length); break; case FGS_DOWNLINK_NAS_TRANSPORT: - handleDownlinkNASTransport(pdu_buffer, pdu_length); + handleDownlinkNASTransport(pdu_buffer, pdu_length, nas->UE_id); break; case FGS_REGISTRATION_ACCEPT: handle_registration_accept(nas, pdu_buffer, pdu_length); @@ -1735,7 +1727,7 @@ void *nas_nrue(void *args_p) nas->fiveGMM_state = FGS_DEREGISTERED; break; case FGS_PDU_SESSION_ESTABLISHMENT_ACC: - handle_pdu_session_accept(pdu_buffer, pdu_length); + handle_pdu_session_accept(pdu_buffer, pdu_length, nas->UE_id); break; case FGS_PDU_SESSION_ESTABLISHMENT_REJ: LOG_E(NAS, "Received PDU Session Establishment reject\n"); @@ -1767,6 +1759,15 @@ void *nas_nrue(void *args_p) send_nas_uplink_data_req(nas, &initialNasMsg); } break; + case NAS_INIT_NOS1_IF: { + const int pdu_session_id = get_softmodem_params()->default_pdu_session_id; + const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3"; + const int qfi = 7; + create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id); + set_qfi(qfi, pdu_session_id, nas->UE_id); + break; + } + default: LOG_E(NAS, "[UE %ld] Received unexpected message %s\n", nas->UE_id, ITTI_MSG_NAME(msg_p)); break; diff --git a/openair3/NAS/NR_UE/nr_nas_msg.h b/openair3/NAS/NR_UE/nr_nas_msg.h index c4f1d04e28..40b4e64ac1 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.h +++ b/openair3/NAS/NR_UE/nr_nas_msg.h @@ -110,5 +110,6 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas); void *nas_nrue_task(void *args_p); void *nas_nrue(void *args_p); void nas_init_nrue(int num_ues); +void nr_ue_create_ip_if(const char *ifnameprefix, const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id); #endif /* __NR_NAS_MSG_SIM_H__*/