diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index ed2478896..9c85814f8 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -244,7 +244,7 @@ public: class gtpu_interface_rrc { public: - virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) = 0; + virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in) = 0; virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; virtual void rem_user(uint16_t rnti) = 0; }; diff --git a/srsenb/hdr/upper/gtpu.h b/srsenb/hdr/upper/gtpu.h index 9ad9441fa..6ec371655 100644 --- a/srsenb/hdr/upper/gtpu.h +++ b/srsenb/hdr/upper/gtpu.h @@ -75,7 +75,7 @@ public: void stop(); // gtpu_interface_rrc - void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in); + void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in); void rem_bearer(uint16_t rnti, uint32_t lcid); void rem_user(uint16_t rnti); @@ -86,7 +86,7 @@ public: private: static const int THREAD_PRIO = 7; static const int GTPU_PORT = 2152; - srslte::byte_buffer_pool *pool; + srslte::byte_buffer_pool *pool; bool running; bool run_enable; @@ -98,11 +98,13 @@ private: typedef struct{ uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; uint32_t teids_out[SRSENB_N_RADIO_BEARERS]; + uint32_t spgw_addrs[SRSENB_N_RADIO_BEARERS]; }bearer_map; std::map rnti_bearers; - srslte_netsink_t snk; - srslte_netsource_t src; + // Socket file descriptors + int snk_fd; + int src_fd; void run_thread(); diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index 49a02d0b9..e0b9dd158 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -195,6 +195,9 @@ public: bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e); bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); + void setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out, + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu); bool release_erabs(); void notify_s1ap_ue_ctxt_setup_complete(); diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc index 83f7a1b75..ddd695ffe 100644 --- a/srsenb/src/upper/gtpu.cc +++ b/srsenb/src/upper/gtpu.cc @@ -26,6 +26,9 @@ #include "upper/gtpu.h" #include +#include +#include +#include using namespace srslte; @@ -42,16 +45,51 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ pool = byte_buffer_pool::get_instance(); - if(0 != srslte_netsource_init(&src, gtp_bind_addr.c_str(), GTPU_PORT, SRSLTE_NETSOURCE_UDP)) { - gtpu_log->error("Failed to create source socket on %s:%d", gtp_bind_addr.c_str(), GTPU_PORT); + // Set up sink socket + snk_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (snk_fd < 0) { + gtpu_log->error("Failed to create sink socket\n"); return false; } - if(0 != srslte_netsink_init(&snk, mme_addr.c_str(), GTPU_PORT, SRSLTE_NETSINK_UDP)) { - gtpu_log->error("Failed to create sink socket on %s:%d", mme_addr.c_str(), GTPU_PORT); + if (fcntl(snk_fd, F_SETFL, O_NONBLOCK)) { + gtpu_log->error("Failed to set non-blocking sink socket\n"); + return false; + } + int enable = 1; +#if defined (SO_REUSEADDR) + if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n"); +#endif +#if defined (SO_REUSEPORT) + if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n"); +#endif + + + // Set up source socket + src_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (src_fd < 0) { + gtpu_log->error("Failed to create source socket\n"); + return false; + } +#if defined (SO_REUSEADDR) + if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n"); +#endif +#if defined (SO_REUSEPORT) + if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n"); +#endif + + struct sockaddr_in bindaddr; + bindaddr.sin_family = AF_INET; + bindaddr.sin_addr.s_addr = inet_addr(gtp_bind_addr.c_str()); + bindaddr.sin_port = htons(GTPU_PORT); + + if (bind(src_fd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) { + gtpu_log->error("Failed to bind on address %s, port %d\n", gtp_bind_addr, GTPU_PORT); return false; } - - srslte_netsink_set_nonblocking(&snk); // Setup a thread to receive packets from the src socket start(THREAD_PRIO); @@ -61,7 +99,7 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ void gtpu::stop() { - if(run_enable) { + if (run_enable) { run_enable = false; // Wait thread to exit gracefully otherwise might leave a mutex locked int cnt=0; @@ -75,8 +113,12 @@ void gtpu::stop() wait_thread_finish(); } - srslte_netsink_free(&snk); - srslte_netsource_free(&src); + if (snk_fd) { + close(snk_fd); + } + if (src_fd) { + close(src_fd); + } } // gtpu_interface_pdcp @@ -89,28 +131,35 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu) header.length = pdu->N_bytes; header.teid = rnti_bearers[rnti].teids_out[lcid]; + struct sockaddr_in servaddr; + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]); + servaddr.sin_port = htons(GTPU_PORT); + gtpu_write_header(&header, pdu); - srslte_netsink_write(&snk, pdu->msg, pdu->N_bytes); + sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in)); pool->deallocate(pdu); } // gtpu_interface_rrc -void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) +void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in) { // Allocate a TEID for the incoming tunnel rntilcid_to_teidin(rnti, lcid, teid_in); - gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, teid_out, *teid_in); + gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, *teid_in); // Initialize maps if it's a new RNTI if(rnti_bearers.count(rnti) == 0) { for(int i=0;ireset(); gtpu_log->debug("Waiting for read...\n"); - pdu->N_bytes = srslte_netsource_read(&src, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET); + do{ + pdu->N_bytes = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0); + }while (pdu->N_bytes == -1 && errno == EAGAIN); + if (pdu->N_bytes == -1) { + gtpu_log->error("Failed to read from socket\n"); + } gtpu_header_t header; gtpu_read_header(pdu, &header); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 89b38dd36..b1280cf55 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -946,20 +946,16 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e) if(erab->iE_Extensions_present) { parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); } - - uint8_t id = erab->e_RAB_ID.E_RAB_ID; - erabs[id].id = id; - memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); - memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); - uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out); - - uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) - parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in)); - - if(erab->nAS_PDU_present) { - memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets); - parent->erab_info.N_bytes = erab->nAS_PDU.n_octets; + if(erab->transportLayerAddress.n_bits > 32) { + parent->rrc_log->error("IPv6 addresses not currently supported\n"); + return false; } + + uint32_t teid_out; + uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out); + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu = erab->nAS_PDU_present ? &erab->nAS_PDU : NULL; + setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters, + &erab->transportLayerAddress, teid_out, nas_pdu); } return true; } @@ -974,25 +970,43 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e) if(erab->iE_Extensions_present) { parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); } + if(erab->transportLayerAddress.n_bits > 32) { + parent->rrc_log->error("IPv6 addresses not currently supported\n"); + return false; + } - uint8_t id = erab->e_RAB_ID.E_RAB_ID; - erabs[id].id = id; - memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); - memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); - uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out); - - uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) - parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in)); - - memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets); - parent->erab_info.N_bytes = erab->nAS_PDU.n_octets; + uint32_t teid_out; + uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out); + setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters, + &erab->transportLayerAddress, teid_out, &erab->nAS_PDU); } + // Work in progress notify_s1ap_ue_erab_setup_response(e); send_connection_reconf_new_bearer(e); return true; } +void rrc::ue::setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out, + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu) +{ + erabs[id].id = id; + memcpy(&erabs[id].qos_params, qos, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); + memcpy(&erabs[id].address, addr, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); + erabs[id].teid_out = teid_out; + + uint8_t* bit_ptr = addr->buffer; + uint32_t addr_ = liblte_bits_2_value(&bit_ptr, addr->n_bits); + uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) + parent->gtpu->add_bearer(rnti, lcid, addr_, erabs[id].teid_out, &(erabs[id].teid_in)); + + if(nas_pdu) { + memcpy(parent->erab_info.msg, nas_pdu->buffer, nas_pdu->n_octets); + parent->erab_info.N_bytes = nas_pdu->n_octets; + } +} + bool rrc::ue::release_erabs() { typedef std::map::iterator it_t;