mirror of https://github.com/PentHertz/srsLTE.git
gw: fix race condition
GW thread was checking the default_eps_bearer variable without protection. RRC could update it when deleting DRB or receiving RRC connection release.
This commit is contained in:
parent
4d11e5552a
commit
0a16f48869
|
@ -22,6 +22,7 @@
|
||||||
#include "srsran/srslog/srslog.h"
|
#include "srsran/srslog/srslog.h"
|
||||||
#include "tft_packet_filter.h"
|
#include "tft_packet_filter.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
@ -84,6 +85,7 @@ private:
|
||||||
|
|
||||||
static const int NOT_ASSIGNED = -1;
|
static const int NOT_ASSIGNED = -1;
|
||||||
int32_t default_eps_bearer_id = NOT_ASSIGNED;
|
int32_t default_eps_bearer_id = NOT_ASSIGNED;
|
||||||
|
std::mutex gw_mutex;
|
||||||
|
|
||||||
srslog::basic_logger& logger;
|
srslog::basic_logger& logger;
|
||||||
|
|
||||||
|
|
|
@ -165,11 +165,7 @@ void gw::write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu)
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
NAS interface
|
NAS interface
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
int gw::setup_if_addr(uint32_t eps_bearer_id,
|
int gw::setup_if_addr(uint32_t eps_bearer_id, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_addr, char* err_str)
|
||||||
uint8_t pdn_type,
|
|
||||||
uint32_t ip_addr,
|
|
||||||
uint8_t* ipv6_if_addr,
|
|
||||||
char* err_str)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
if (pdn_type == LIBLTE_MME_PDN_TYPE_IPV4 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6) {
|
if (pdn_type == LIBLTE_MME_PDN_TYPE_IPV4 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6) {
|
||||||
|
@ -212,8 +208,7 @@ bool gw::is_running()
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gw::apply_traffic_flow_template(const uint8_t& erab_id,
|
int gw::apply_traffic_flow_template(const uint8_t& erab_id, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft)
|
||||||
const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft)
|
|
||||||
{
|
{
|
||||||
return tft_matcher.apply_traffic_flow_template(erab_id, tft);
|
return tft_matcher.apply_traffic_flow_template(erab_id, tft);
|
||||||
}
|
}
|
||||||
|
@ -270,86 +265,89 @@ void gw::run_thread()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if IP version makes sense and get packtet length
|
{
|
||||||
struct iphdr* ip_pkt = (struct iphdr*)pdu->msg;
|
std::unique_lock<std::mutex> lock(gw_mutex);
|
||||||
struct ipv6hdr* ip6_pkt = (struct ipv6hdr*)pdu->msg;
|
// Check if IP version makes sense and get packtet length
|
||||||
uint16_t pkt_len = 0;
|
struct iphdr* ip_pkt = (struct iphdr*)pdu->msg;
|
||||||
pdu->N_bytes = idx + N_bytes;
|
struct ipv6hdr* ip6_pkt = (struct ipv6hdr*)pdu->msg;
|
||||||
if (ip_pkt->version == 4) {
|
uint16_t pkt_len = 0;
|
||||||
pkt_len = ntohs(ip_pkt->tot_len);
|
pdu->N_bytes = idx + N_bytes;
|
||||||
} else if (ip_pkt->version == 6) {
|
if (ip_pkt->version == 4) {
|
||||||
pkt_len = ntohs(ip6_pkt->payload_len) + 40;
|
pkt_len = ntohs(ip_pkt->tot_len);
|
||||||
} else {
|
} else if (ip_pkt->version == 6) {
|
||||||
logger.error(pdu->msg, pdu->N_bytes, "Unsupported IP version. Dropping packet.");
|
pkt_len = ntohs(ip6_pkt->payload_len) + 40;
|
||||||
continue;
|
} else {
|
||||||
}
|
logger.error(pdu->msg, pdu->N_bytes, "Unsupported IP version. Dropping packet.");
|
||||||
logger.debug("IPv%d packet total length: %d Bytes", int(ip_pkt->version), pkt_len);
|
|
||||||
|
|
||||||
// Check if entire packet was received
|
|
||||||
if (pkt_len == pdu->N_bytes) {
|
|
||||||
logger.info(pdu->msg, pdu->N_bytes, "TX PDU");
|
|
||||||
|
|
||||||
// Make sure UE is attached and has default EPS bearer activated
|
|
||||||
while (run_enable && default_eps_bearer_id == NOT_ASSIGNED && register_wait < REGISTER_WAIT_TOUT) {
|
|
||||||
if (!register_wait) {
|
|
||||||
logger.info("UE is not attached, waiting for NAS attach (%d/%d)", register_wait, REGISTER_WAIT_TOUT);
|
|
||||||
}
|
|
||||||
usleep(100000);
|
|
||||||
register_wait++;
|
|
||||||
}
|
|
||||||
register_wait = 0;
|
|
||||||
|
|
||||||
// If we are still not attached by this stage, drop packet
|
|
||||||
if (run_enable && default_eps_bearer_id == NOT_ASSIGNED) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
logger.debug("IPv%d packet total length: %d Bytes", int(ip_pkt->version), pkt_len);
|
||||||
|
|
||||||
// Beyond this point we should have a activated default EPS bearer
|
// Check if entire packet was received
|
||||||
srsran_assert(default_eps_bearer_id != NOT_ASSIGNED, "Default EPS bearer not activated");
|
if (pkt_len == pdu->N_bytes) {
|
||||||
|
logger.info(pdu->msg, pdu->N_bytes, "TX PDU");
|
||||||
|
|
||||||
uint8_t eps_bearer_id = default_eps_bearer_id;
|
// Make sure UE is attached and has default EPS bearer activated
|
||||||
tft_matcher.check_tft_filter_match(pdu, eps_bearer_id);
|
while (run_enable && default_eps_bearer_id == NOT_ASSIGNED && register_wait < REGISTER_WAIT_TOUT) {
|
||||||
|
if (!register_wait) {
|
||||||
// Wait for service request if necessary
|
logger.info("UE is not attached, waiting for NAS attach (%d/%d)", register_wait, REGISTER_WAIT_TOUT);
|
||||||
while (run_enable && !stack->has_active_radio_bearer(eps_bearer_id) && service_wait < SERVICE_WAIT_TOUT) {
|
}
|
||||||
if (!service_wait) {
|
lock.unlock();
|
||||||
logger.info(
|
std::this_thread::sleep_for(std::chrono::microseconds(100));
|
||||||
"UE does not have service, waiting for NAS service request (%d/%d)", service_wait, SERVICE_WAIT_TOUT);
|
lock.lock();
|
||||||
stack->start_service_request();
|
register_wait++;
|
||||||
}
|
}
|
||||||
usleep(100000);
|
register_wait = 0;
|
||||||
service_wait++;
|
|
||||||
}
|
|
||||||
service_wait = 0;
|
|
||||||
|
|
||||||
// Quit before writing packet if necessary
|
// If we are still not attached by this stage, drop packet
|
||||||
if (!run_enable) {
|
if (run_enable && default_eps_bearer_id == NOT_ASSIGNED) {
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send PDU directly to PDCP
|
// Beyond this point we should have a activated default EPS bearer
|
||||||
pdu->set_timestamp();
|
srsran_assert(default_eps_bearer_id != NOT_ASSIGNED, "Default EPS bearer not activated");
|
||||||
ul_tput_bytes += pdu->N_bytes;
|
|
||||||
stack->write_sdu(eps_bearer_id, std::move(pdu));
|
uint8_t eps_bearer_id = default_eps_bearer_id;
|
||||||
do {
|
tft_matcher.check_tft_filter_match(pdu, eps_bearer_id);
|
||||||
pdu = srsran::make_byte_buffer();
|
|
||||||
if (!pdu) {
|
// Wait for service request if necessary
|
||||||
logger.error("Fatal Error: Couldn't allocate PDU in run_thread().");
|
while (run_enable && !stack->has_active_radio_bearer(eps_bearer_id) && service_wait < SERVICE_WAIT_TOUT) {
|
||||||
|
if (!service_wait) {
|
||||||
|
logger.info(
|
||||||
|
"UE does not have service, waiting for NAS service request (%d/%d)", service_wait, SERVICE_WAIT_TOUT);
|
||||||
|
stack->start_service_request();
|
||||||
|
}
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
|
service_wait++;
|
||||||
}
|
}
|
||||||
} while (!pdu);
|
service_wait = 0;
|
||||||
idx = 0;
|
|
||||||
} else {
|
// Quit before writing packet if necessary
|
||||||
idx += N_bytes;
|
if (!run_enable) {
|
||||||
logger.debug("Entire packet not read from socket. Total Length %d, N_Bytes %d.", ip_pkt->tot_len, pdu->N_bytes);
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send PDU directly to PDCP
|
||||||
|
pdu->set_timestamp();
|
||||||
|
ul_tput_bytes += pdu->N_bytes;
|
||||||
|
stack->write_sdu(eps_bearer_id, std::move(pdu));
|
||||||
|
do {
|
||||||
|
pdu = srsran::make_byte_buffer();
|
||||||
|
if (!pdu) {
|
||||||
|
logger.error("Fatal Error: Couldn't allocate PDU in run_thread().");
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
} while (!pdu);
|
||||||
|
idx = 0;
|
||||||
|
} else {
|
||||||
|
idx += N_bytes;
|
||||||
|
logger.debug("Entire packet not read from socket. Total Length %d, N_Bytes %d.", ip_pkt->tot_len, pdu->N_bytes);
|
||||||
|
}
|
||||||
|
} // end of holdering gw_mutex
|
||||||
}
|
}
|
||||||
running = false;
|
running = false;
|
||||||
logger.info("GW IP receiver thread exiting.");
|
logger.info("GW IP receiver thread exiting.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**************************/
|
/**************************/
|
||||||
/* TUN Interface Helpers */
|
/* TUN Interface Helpers */
|
||||||
/**************************/
|
/**************************/
|
||||||
|
|
Loading…
Reference in New Issue