diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c8f5a021..ccc1ce54d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,8 @@ option(ENABLE_HARDSIM "Enable support for SIM cards" ON) option(BUILD_STATIC "Attempt to statically link external deps" OFF) option(RPATH "Enable RPATH" OFF) -option(ENABLE_ASAN "Enable gcc address sanitizer" OFF) +option(ENABLE_ASAN "Enable gcc/clang address sanitizer" OFF) +option(ENABLE_MSAN "Enable clang memory sanitizer" OFF) option(USE_LTE_RATES "Use standard LTE sampling rates" OFF) @@ -315,7 +316,6 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif(HAVE_SSE) endif(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") - if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon -march=native -DIS_ARM -DHAVE_NEON") message(STATUS "have ARM") @@ -332,10 +332,21 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") if(NOT WIN32) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) endif(NOT WIN32) - if (ENABLE_ASAN) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") - endif (ENABLE_ASAN) + + if (ENABLE_ASAN AND ENABLE_MSAN) + message(FATAL_ERROR "ASAN and MSAN cannot be enabled at the same time.") + endif (ENABLE_ASAN AND ENABLE_MSAN) + + if (ENABLE_ASAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + endif (ENABLE_ASAN) + + if (ENABLE_MSAN AND CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fPIE -pie") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fPIE -pie") + endif (ENABLE_MSAN AND CMAKE_C_COMPILER_ID MATCHES "Clang") + endif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") @@ -359,7 +370,7 @@ if(NOT CLANG_TIDY_BIN) message(STATUS "clang-tidy not found.") else() message(STATUS "clang-tidy found: ${CLANG_TIDY_BIN}") - set(DO_CLANG_TIDY "${CLANG_TIDY_BIN}" "-checks=*,-clang-analyzer-alpha.*") + set(DO_CLANG_TIDY "${CLANG_TIDY_BIN}" "-checks=*,-clang-analyzer-alpha.*,-modernize-*,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-constant-array-index") endif() diff --git a/lib/include/srslte/common/bcd_helpers.h b/lib/include/srslte/common/bcd_helpers.h index b145a2d5a..abd596860 100644 --- a/lib/include/srslte/common/bcd_helpers.h +++ b/lib/include/srslte/common/bcd_helpers.h @@ -150,9 +150,9 @@ inline void s1ap_plmn_to_mccmnc(uint32_t plmn, uint16_t *mcc, uint16_t *mnc) *mnc |= nibbles[4]; // MNC digit 3 } else { // 3-digit MNC - *mnc |= nibbles[5] << 8; // MNC digit 1 - *mnc |= nibbles[4] << 4; // MNC digit 2 - *mnc |= nibbles[2] ; // MNC digit 3 + *mnc |= nibbles[2] << 8; // MNC digit 1 + *mnc |= nibbles[5] << 4; // MNC digit 2 + *mnc |= nibbles[4] ; // MNC digit 3 } } @@ -177,9 +177,9 @@ inline void s1ap_mccmnc_to_plmn(uint16_t mcc, uint16_t mnc, uint32_t *plmn) nibbles[4] = (mnc & 0x000F); // MNC digit 3 } else { // 3-digit MNC - nibbles[5] = (mnc & 0x0F00) >> 8; // MNC digit 1 - nibbles[4] = (mnc & 0x00F0) >> 4; // MNC digit 2 - nibbles[2] = (mnc & 0x000F); // MNC digit 3 + nibbles[2] = (mnc & 0x0F00) >> 8; // MNC digit 1 + nibbles[5] = (mnc & 0x00F0) >> 4; // MNC digit 2 + nibbles[4] = (mnc & 0x000F); // MNC digit 3 } *plmn = 0x000000; diff --git a/lib/include/srslte/common/block_queue.h b/lib/include/srslte/common/block_queue.h index 2e476dd65..1098e3db5 100644 --- a/lib/include/srslte/common/block_queue.h +++ b/lib/include/srslte/common/block_queue.h @@ -109,7 +109,6 @@ public: myobj wait_pop() { // blocking pop myobj value; - bzero(&value, sizeof(myobj)); pop_(&value, true); return value; } @@ -154,8 +153,8 @@ private: } if (value) { *value = q.front(); - q.pop(); } + q.pop(); ret = true; if (mutexed_callback) { mutexed_callback->popping(*value); diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 549e992bf..27e8bf2a9 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -59,10 +59,10 @@ #define ASYNC_DL_SCHED (HARQ_DELAY_MS <= 4) -// Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI +// Cat 4 UE - Max number of DL-SCH transport block bits received within a TTI // 3GPP 36.306 Table 4.1.1 -#define SRSLTE_MAX_BUFFER_SIZE_BITS 102048 -#define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756 +#define SRSLTE_MAX_BUFFER_SIZE_BITS 150752 +#define SRSLTE_MAX_BUFFER_SIZE_BYTES (SRSLTE_MAX_BUFFER_SIZE_BITS/8) #define SRSLTE_BUFFER_HEADER_OFFSET 1020 #define SRSLTE_BUFFER_POOL_LOG_ENABLED @@ -125,7 +125,7 @@ public: #ifdef ENABLE_TIMESTAMP timestamp_is_set = false; #endif - msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; + msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; next = NULL; #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED bzero(debug_name, SRSLTE_BUFFER_POOL_LOG_NAME_LEN); @@ -134,6 +134,9 @@ public: byte_buffer_t(const byte_buffer_t& buf) { bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES); + msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; + next = NULL; + // copy actual contents N_bytes = buf.N_bytes; memcpy(msg, buf.msg, N_bytes); } @@ -143,6 +146,8 @@ public: if (&buf == this) return *this; bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES); + msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; + next = NULL; N_bytes = buf.N_bytes; memcpy(msg, buf.msg, N_bytes); return *this; diff --git a/lib/include/srslte/common/log_filter.h b/lib/include/srslte/common/log_filter.h index 1296fbbbd..e0dbf4b5b 100644 --- a/lib/include/srslte/common/log_filter.h +++ b/lib/include/srslte/common/log_filter.h @@ -54,6 +54,7 @@ public: log_filter(); log_filter(std::string layer); log_filter(std::string layer, logger *logger_, bool tti=false); + ~log_filter(); void init(std::string layer, logger *logger_, bool tti=false); diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index f093d1d55..9adea96b8 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -48,14 +48,6 @@ typedef struct { float tx_rx_gain_offset; } srslte_rf_t; -typedef struct { - float dc_gain; - float dc_phase; - float iq_i; - float iq_q; -} srslte_rf_cal_t; - - typedef struct { double min_tx_gain; double max_tx_gain; @@ -96,10 +88,6 @@ SRSLTE_API int srslte_rf_start_gain_thread(srslte_rf_t *rf, SRSLTE_API int srslte_rf_close(srslte_rf_t *h); -SRSLTE_API void srslte_rf_set_tx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); - -SRSLTE_API void srslte_rf_set_rx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); - SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h, bool now); SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h); diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 2b14b30cd..e9ff3a4a2 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -33,17 +33,6 @@ #ifndef SRSLTE_RADIO_H #define SRSLTE_RADIO_H -typedef struct { - float tx_corr_dc_gain; - float tx_corr_dc_phase; - float tx_corr_iq_i; - float tx_corr_iq_q; - float rx_corr_dc_gain; - float rx_corr_dc_phase; - float rx_corr_iq_i; - float rx_corr_iq_q; -} rf_cal_t; - namespace srslte { /* Interface to the RF frontend. @@ -85,8 +74,6 @@ class radio { void set_tx_adv(int nsamples); void set_tx_adv_neg(bool tx_adv_is_neg); - void set_manual_calibration(rf_cal_t *calibration); - bool is_continuous_tx(); void set_continuous_tx(bool enable); diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 0bea0394e..f211edf72 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -56,7 +56,7 @@ public: log *rlc_log_, mac_interface_timers *mac_timers_, uint32_t lcid_, - int buffer_size = -1); // -1 to use default buffer sizes + int buffer_size_ = -1); // -1 to use default buffer sizes void stop(); void get_metrics(rlc_metrics_t &m); @@ -88,6 +88,7 @@ public: void add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg); void add_bearer_mrb(uint32_t lcid); void del_bearer(uint32_t lcid); + void del_bearer_mrb(uint32_t lcid); void change_lcid(uint32_t old_lcid, uint32_t new_lcid); private: diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index f771ef607..0e18a7e7f 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -69,14 +69,14 @@ struct rlc_amd_retx_t{ class rlc_am : public rlc_common { public: - rlc_am(uint32_t queue_len = 16); + rlc_am(uint32_t queue_len = 128); ~rlc_am(); - void init(log *rlc_entity_log_, + void init(log *log_, uint32_t lcid_, srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, - mac_interface_timers *mac_timers); - bool configure(srslte_rlc_config_t cnfg); + mac_interface_timers *mac_timers_); + bool configure(srslte_rlc_config_t cfg_); void reestablish(); void stop(); @@ -104,7 +104,7 @@ private: class rlc_am_tx : public timer_callback { public: - rlc_am_tx(rlc_am *parent_, uint32_t queue_len); + rlc_am_tx(rlc_am *parent_, uint32_t queue_len_); ~rlc_am_tx(); void init(); @@ -139,6 +139,7 @@ private: bool retx_queue_has_sn(uint32_t sn); int required_buffer_size(rlc_amd_retx_t retx); + void retransmit_random_pdu(); // Timer checks bool status_prohibited; @@ -224,7 +225,8 @@ private: void timer_expired(uint32_t timeout_id); // Functions needed by Tx subclass to query rx state - int get_status(rlc_status_pdu_t* status); + int get_status_pdu_length(); + int get_status_pdu(rlc_status_pdu_t* status, const uint32_t nof_bytes); bool get_do_status(); void reset_status(); // called when status PDU has been sent @@ -319,7 +321,8 @@ uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); bool rlc_am_is_control_pdu(byte_buffer_t *pdu); bool rlc_am_is_control_pdu(uint8_t *payload); bool rlc_am_is_pdu_segment(uint8_t *payload); -std::string rlc_am_to_string(rlc_status_pdu_t *status); +std::string rlc_am_status_pdu_to_string(rlc_status_pdu_t *status); +std::string rlc_amd_pdu_header_to_string(const rlc_amd_pdu_header_t &header); bool rlc_am_start_aligned(const uint8_t fi); bool rlc_am_end_aligned(const uint8_t fi); bool rlc_am_is_unaligned(const uint8_t fi); diff --git a/lib/include/srslte/upper/rlc_um.h b/lib/include/srslte/upper/rlc_um.h index f866417d2..92a7822d5 100644 --- a/lib/include/srslte/upper/rlc_um.h +++ b/lib/include/srslte/upper/rlc_um.h @@ -39,6 +39,8 @@ namespace srslte { +#define RLC_UM_MAX_SDU_SIZE (2048-1) // Length of LI field is 11bits + struct rlc_umd_pdu_t{ rlc_umd_pdu_header_t header; byte_buffer_t *buf; @@ -48,7 +50,7 @@ class rlc_um :public rlc_common { public: - rlc_um(uint32_t queue_len = 32); + rlc_um(uint32_t queue_len = 128); ~rlc_um(); void init(log *rlc_entity_log_, uint32_t lcid_, @@ -146,6 +148,7 @@ private: bool configure(srslte_rlc_config_t cfg, std::string rb_name); void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes); void reassemble_rx_sdus(); + bool pdu_belongs_to_rx_sdu(); bool inside_reordering_window(uint16_t sn); uint32_t get_num_rx_bytes(); void reset_metrics(); @@ -213,6 +216,7 @@ private: uint32_t lcid; srslte_rlc_um_config_t cfg; std::string rb_name; + byte_buffer_pool *pool; std::string get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb); }; diff --git a/lib/src/common/log_filter.cc b/lib/src/common/log_filter.cc index 9602e202a..f496c1895 100644 --- a/lib/src/common/log_filter.cc +++ b/lib/src/common/log_filter.cc @@ -59,6 +59,10 @@ log_filter::log_filter(std::string layer, logger *logger_, bool tti) init(layer, logger_, tti); } +log_filter::~log_filter() +{ +} + void log_filter::init(std::string layer, logger *logger_, bool tti) { service_name = layer; diff --git a/lib/src/common/threads.c b/lib/src/common/threads.c index 024faa64a..1d35d91aa 100644 --- a/lib/src/common/threads.c +++ b/lib/src/common/threads.c @@ -86,7 +86,7 @@ bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void #else // All threads have normal priority except prio_offset=0,1,2,3,4 if (prio_offset >= 0 && prio_offset < 5) { - param.sched_priority = 50; + param.sched_priority = 50-prio_offset; pthread_attr_init(&attr); if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) { perror("pthread_attr_setinheritsched"); diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index 3f6a082f8..0f06ef1bb 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -524,7 +524,6 @@ int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softb cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), rnti, cfg->grant.mcs.tbs, cfg->nbits.nof_re, cfg->nbits.nof_symb, cfg->nbits.nof_bits, cfg->rv); - bzero(q->q, cfg->nbits.nof_bits); if (srslte_ulsch_uci_encode(&q->ul_sch, cfg, softbuffer, data, uci_data, q->g, q->q)) { fprintf(stderr, "Error encoding TB\n"); return SRSLTE_ERROR; @@ -534,6 +533,10 @@ int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softb srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); // Run scrambling + if (!seq) { + fprintf(stderr, "Error getting scrambling sequence\n"); + return SRSLTE_ERROR; + } srslte_scrambling_bytes(seq, (uint8_t*) q->q, cfg->nbits.nof_bits); // Correct UCI placeholder/repetition bits diff --git a/lib/src/phy/rf/rf_blade_imp.c b/lib/src/phy/rf/rf_blade_imp.c index 71e5025b5..061c5aa92 100644 --- a/lib/src/phy/rf/rf_blade_imp.c +++ b/lib/src/phy/rf/rf_blade_imp.c @@ -402,23 +402,6 @@ double rf_blade_set_tx_freq(void *h, double freq) return freq; } -void rf_blade_set_tx_cal(void *h, srslte_rf_cal_t *cal) { - rf_blade_handler_t *handler = (rf_blade_handler_t*) h; - bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_FPGA_PHASE, cal->dc_phase); - bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_FPGA_GAIN, cal->dc_gain); - bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_LMS_DCOFF_I, cal->iq_i); - bladerf_set_correction(handler->dev, BLADERF_MODULE_TX, BLADERF_CORR_LMS_DCOFF_Q, cal->iq_q); -} - -void rf_blade_set_rx_cal(void *h, srslte_rf_cal_t *cal) { - rf_blade_handler_t *handler = (rf_blade_handler_t*) h; - bladerf_set_correction(handler->dev, BLADERF_MODULE_RX, BLADERF_CORR_FPGA_PHASE, cal->dc_phase); - bladerf_set_correction(handler->dev, BLADERF_MODULE_RX, BLADERF_CORR_FPGA_GAIN, cal->dc_gain); - bladerf_set_correction(handler->dev, BLADERF_MODULE_RX, BLADERF_CORR_LMS_DCOFF_I, cal->iq_i); - bladerf_set_correction(handler->dev, BLADERF_MODULE_RX, BLADERF_CORR_LMS_DCOFF_Q, cal->iq_q); -} - - static void timestamp_to_secs(uint32_t rate, uint64_t timestamp, time_t *secs, double *frac_secs) { double totalsecs = (double) timestamp/rate; time_t secs_i = (time_t) totalsecs; diff --git a/lib/src/phy/rf/rf_blade_imp.h b/lib/src/phy/rf/rf_blade_imp.h index 6c8c04c43..3809a149f 100644 --- a/lib/src/phy/rf/rf_blade_imp.h +++ b/lib/src/phy/rf/rf_blade_imp.h @@ -40,10 +40,6 @@ SRSLTE_API char* rf_blade_devname(void *h); SRSLTE_API int rf_blade_close(void *h); -SRSLTE_API void rf_blade_set_tx_cal(void *h, srslte_rf_cal_t *cal); - -SRSLTE_API void rf_blade_set_rx_cal(void *h, srslte_rf_cal_t *cal); - SRSLTE_API int rf_blade_start_rx_stream(void *h, bool now); SRSLTE_API int rf_blade_start_rx_stream_nsamples(void *h, diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index 80b5125e4..0d2e11592 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -62,10 +62,6 @@ typedef struct { int (*srslte_rf_send_timed_multi)(void *h, void *data[4], int nsamples, time_t secs, double frac_secs, bool has_time_spec, bool blocking, bool is_start_of_burst, bool is_end_of_burst); - void (*srslte_rf_set_tx_cal)(void *h, srslte_rf_cal_t *cal); - - void (*srslte_rf_set_rx_cal)(void *h, srslte_rf_cal_t *cal); - } rf_dev_t; /* Define implementation for UHD */ @@ -102,9 +98,7 @@ static rf_dev_t dev_uhd = { rf_uhd_recv_with_time, rf_uhd_recv_with_time_multi, rf_uhd_send_timed, - .srslte_rf_send_timed_multi = rf_uhd_send_timed_multi, - rf_uhd_set_tx_cal, - rf_uhd_set_rx_cal + .srslte_rf_send_timed_multi = rf_uhd_send_timed_multi }; #endif @@ -142,9 +136,7 @@ static rf_dev_t dev_blade = { rf_blade_recv_with_time, rf_blade_recv_with_time_multi, rf_blade_send_timed, - .srslte_rf_send_timed_multi = rf_blade_send_timed_multi, - rf_blade_set_tx_cal, - rf_blade_set_rx_cal + .srslte_rf_send_timed_multi = rf_blade_send_timed_multi }; #endif @@ -181,9 +173,7 @@ static rf_dev_t dev_soapy = { rf_soapy_recv_with_time, rf_soapy_recv_with_time_multi, rf_soapy_send_timed, - .srslte_rf_send_timed_multi = rf_soapy_send_timed_multi, - rf_soapy_set_tx_cal, - rf_soapy_set_rx_cal + .srslte_rf_send_timed_multi = rf_soapy_send_timed_multi }; #endif diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index eec44ef30..bc7ac59d6 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -129,15 +129,6 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args, uint32_t return -1; } -void srslte_rf_set_tx_cal(srslte_rf_t *rf, srslte_rf_cal_t *cal) { - return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_cal(rf->handler, cal); -} - -void srslte_rf_set_rx_cal(srslte_rf_t *rf, srslte_rf_cal_t *cal) { - return ((rf_dev_t*) rf->dev)->srslte_rf_set_rx_cal(rf->handler, cal); -} - - const char* srslte_rf_name(srslte_rf_t *rf) { return ((rf_dev_t*) rf->dev)->srslte_rf_devname(rf->handler); } diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 26ad5bac0..5d77a0a0d 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -205,25 +205,18 @@ bool rf_soapy_rx_wait_lo_locked(void *h) return true; } - -void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal) +void rf_soapy_calibrate_tx(void *h) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; double actual_bw = SoapySDRDevice_getBandwidth(handler->device, SOAPY_SDR_TX, 0); char str_buf[25]; snprintf(str_buf, sizeof(str_buf), "%f", actual_bw); + str_buf[24] = 0; if (SoapySDRDevice_writeSetting(handler->device, "CALIBRATE_TX", str_buf)) { printf("Error calibrating Rx\n"); } } - -void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal) -{ - // not supported -} - - int rf_soapy_start_rx_stream(void *h, bool now) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 5b1787304..da4143e76 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -43,14 +43,12 @@ SRSLTE_API char* rf_soapy_devname(void *h); SRSLTE_API int rf_soapy_close(void *h); -SRSLTE_API void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal); - -SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal); - SRSLTE_API int rf_soapy_start_rx_stream(void *h, bool now); SRSLTE_API int rf_soapy_stop_rx_stream(void *h); +SRSLTE_API void rf_soapy_calibrate_tx(void *h); + SRSLTE_API void rf_soapy_flush_buffer(void *h); SRSLTE_API bool rf_soapy_has_rssi(void *h); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 5439db828..993118675 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -230,17 +230,6 @@ bool rf_uhd_rx_wait_lo_locked(void *h) return val; } -void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal) -{ - -} - -void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal) -{ - -} - - int rf_uhd_start_rx_stream(void *h, bool now) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index e0ad09bba..2da9f4efb 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -47,10 +47,6 @@ SRSLTE_API char* rf_uhd_devname(void *h); SRSLTE_API int rf_uhd_close(void *h); -SRSLTE_API void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal); - -SRSLTE_API void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal); - SRSLTE_API int rf_uhd_start_rx_stream(void *h, bool now); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 558f8b5fe..8571825bf 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -450,9 +450,9 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 } } else { if (grant->pinfo == 2) { - ERROR("Not implemented codebook index (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); + /* Not implemented */ } else if (grant->pinfo > 2) { - ERROR("Reserved codebook index (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); + /* Reserved */ } pmi = grant->pinfo % 2; } diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index 349048838..ffae700ee 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -97,16 +97,6 @@ void radio::reset() usleep(100000); } -void radio::set_manual_calibration(rf_cal_t* calibration) -{ - srslte_rf_cal_t tx_cal; - tx_cal.dc_gain = calibration->tx_corr_dc_gain; - tx_cal.dc_phase = calibration->tx_corr_dc_phase; - tx_cal.iq_i = calibration->tx_corr_iq_i; - tx_cal.iq_q = calibration->tx_corr_iq_q; - srslte_rf_set_tx_cal(&rf_device, &tx_cal); -} - void radio::set_tx_rx_gain_offset(float offset) { srslte_rf_set_tx_rx_gain_offset(&rf_device, offset); } diff --git a/lib/src/upper/CMakeLists.txt b/lib/src/upper/CMakeLists.txt index 725d6de60..4ba2ff951 100644 --- a/lib/src/upper/CMakeLists.txt +++ b/lib/src/upper/CMakeLists.txt @@ -22,3 +22,8 @@ file(GLOB SOURCES "*.cc") add_library(srslte_upper STATIC ${SOURCES}) target_link_libraries(srslte_upper srslte_common srslte_asn1) install(TARGETS srslte_upper DESTINATION ${LIBRARY_DIR}) + +# Run clang-tidy if available +if(CLANG_TIDY_BIN) + set_target_properties(srslte_upper PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}") +endif() \ No newline at end of file diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index e32e64bc7..5cf561415 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -42,6 +42,7 @@ rlc::rlc() mac_timers = NULL; ue = NULL; default_lcid = 0; + buffer_size = 0; bzero(metrics_time, sizeof(metrics_time)); pthread_rwlock_init(&rwlock, NULL); } @@ -123,8 +124,8 @@ void rlc::get_metrics(rlc_metrics_t &m) m.ul_tput_mbps[it->first] = (it->second->get_num_tx_bytes()*8/static_cast(1e6))/secs; rlc_log->info("LCID=%d, RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", it->first, - (it->second->get_num_rx_bytes()*8/(double)1e6)/secs, - (it->second->get_num_tx_bytes()*8/(double)1e6)/secs); + (it->second->get_num_rx_bytes()*8/static_cast(1e6))/secs, + (it->second->get_num_tx_bytes()*8/static_cast(1e6))/secs); } // Add multicast metrics @@ -279,7 +280,7 @@ uint32_t rlc::get_total_mch_buffer_state(uint32_t lcid) uint32_t ret = 0; pthread_rwlock_rdlock(&rwlock); - if (valid_lcid(lcid)) { + if (valid_lcid_mrb(lcid)) { ret = rlc_array_mrb.at(lcid)->get_total_buffer_state(); } pthread_rwlock_unlock(&rwlock); @@ -305,7 +306,7 @@ int rlc::read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) uint32_t ret = 0; pthread_rwlock_rdlock(&rwlock); - if (valid_lcid(lcid)) { + if (valid_lcid_mrb(lcid)) { ret = rlc_array_mrb.at(lcid)->read_pdu(payload, nof_bytes); } pthread_rwlock_unlock(&rwlock); @@ -327,7 +328,7 @@ void rlc::write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) { rlc_log->info_hex(payload, nof_bytes, "BCCH BCH message received."); byte_buffer_t *buf = pool_allocate; - if (buf) { + if (buf != NULL) { memcpy(buf->msg, payload, nof_bytes); buf->N_bytes = nof_bytes; buf->set_timestamp(); @@ -342,7 +343,7 @@ void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) { rlc_log->info_hex(payload, nof_bytes, "BCCH TXSCH message received."); byte_buffer_t *buf = pool_allocate; - if (buf) { + if (buf != NULL) { memcpy(buf->msg, payload, nof_bytes); buf->N_bytes = nof_bytes; buf->set_timestamp(); @@ -357,7 +358,7 @@ void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) { rlc_log->info_hex(payload, nof_bytes, "PCCH message received."); byte_buffer_t *buf = pool_allocate; - if (buf) { + if (buf != NULL) { memcpy(buf->msg, payload, nof_bytes); buf->N_bytes = nof_bytes; buf->set_timestamp(); @@ -394,7 +395,7 @@ void rlc::add_bearer(uint32_t lcid) add_bearer(lcid, srslte_rlc_config_t()); } else { // SRB1 and SRB2 are AM - LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg = {}; cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS45; cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_INFINITY; @@ -472,10 +473,10 @@ void rlc::add_bearer_mrb(uint32_t lcid) if (not valid_lcid_mrb(lcid)) { rlc_entity = new rlc_um(); - if (rlc_entity) { + if (rlc_entity != NULL) { // configure and add to array rlc_entity->init(rlc_log, lcid, pdcp, rrc, mac_timers); - if (rlc_entity->configure(srslte_rlc_config_t::mch_config()) == false) { + if (not rlc_entity->configure(srslte_rlc_config_t::mch_config())) { rlc_log->error("Error configuring RLC entity\n."); goto delete_and_exit; } @@ -494,7 +495,7 @@ void rlc::add_bearer_mrb(uint32_t lcid) } delete_and_exit: - if (rlc_entity) { + if (rlc_entity != NULL) { delete(rlc_entity); } @@ -507,7 +508,7 @@ void rlc::del_bearer(uint32_t lcid) { pthread_rwlock_wrlock(&rwlock); - if (valid_lcid_mrb(lcid)) { + if (valid_lcid(lcid)) { rlc_map_t::iterator it = rlc_array.find(lcid); it->second->stop(); delete(it->second); @@ -521,6 +522,24 @@ void rlc::del_bearer(uint32_t lcid) } +void rlc::del_bearer_mrb(uint32_t lcid) +{ + pthread_rwlock_wrlock(&rwlock); + + if (valid_lcid_mrb(lcid)) { + rlc_map_t::iterator it = rlc_array_mrb.find(lcid); + it->second->stop(); + delete(it->second); + rlc_array_mrb.erase(it); + rlc_log->warning("Deleted RLC MRB bearer %s\n", rrc->get_rb_name(lcid).c_str()); + } else { + rlc_log->error("Can't delete bearer %s. Bearer doesn't exist.\n", rrc->get_rb_name(lcid).c_str()); + } + + pthread_rwlock_unlock(&rwlock); +} + + void rlc::change_lcid(uint32_t old_lcid, uint32_t new_lcid) { pthread_rwlock_wrlock(&rwlock); @@ -577,4 +596,4 @@ bool rlc::valid_lcid_mrb(uint32_t lcid) return true; } -} // namespace srsue +} // namespace srslte diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 5c5964288..7c2e18b0f 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -31,8 +31,8 @@ #include #define MOD 1024 -#define RX_MOD_BASE(x) ((x-vr_r)%1024) -#define TX_MOD_BASE(x) ((x-vt_a)%1024) +#define RX_MOD_BASE(x) (((x)-vr_r)%1024) +#define TX_MOD_BASE(x) (((x)-vt_a)%1024) #define LCID (parent->lcid) #define RB_NAME (parent->rb_name.c_str()) @@ -198,6 +198,7 @@ rlc_am::rlc_am_tx::rlc_am_tx(rlc_am* parent_, uint32_t queue_len_) ,tx_enabled(false) { pthread_mutex_init(&mutex, NULL); + ZERO_OBJECT(tx_status); } rlc_am::rlc_am_tx::~rlc_am_tx() @@ -209,7 +210,7 @@ void rlc_am::rlc_am_tx::init() { log = parent->log; - if (parent->mac_timers) { + if (parent->mac_timers != NULL) { poll_retx_timer_id = parent->mac_timers->timer_get_unique_id(); poll_retx_timer = parent->mac_timers->timer_get(poll_retx_timer_id); @@ -224,10 +225,19 @@ bool rlc_am::rlc_am_tx::configure(srslte_rlc_am_config_t cfg_) cfg = cfg_; // check timers - if (not poll_retx_timer or not status_prohibit_timer) { + if (poll_retx_timer == NULL or status_prohibit_timer == NULL) { return false; } + // configure timers + if (cfg.t_status_prohibit > 0) { + status_prohibit_timer->set(this, static_cast(cfg.t_status_prohibit)); + } + + if (cfg.t_poll_retx > 0) { + poll_retx_timer->set(this, static_cast(cfg.t_poll_retx)); + } + tx_enabled = true; return true; @@ -239,13 +249,15 @@ void rlc_am::rlc_am_tx::stop() pthread_mutex_lock(&mutex); - if (parent->mac_timers && poll_retx_timer) { + tx_enabled = false; + + if (parent->mac_timers != NULL && poll_retx_timer != NULL) { poll_retx_timer->stop(); parent->mac_timers->timer_release_id(poll_retx_timer_id); poll_retx_timer = NULL; } - if (parent->mac_timers && status_prohibit_timer) { + if (parent->mac_timers != NULL && status_prohibit_timer != NULL) { status_prohibit_timer->stop(); parent->mac_timers->timer_release_id(status_prohibit_timer_id); status_prohibit_timer = NULL; @@ -283,7 +295,7 @@ void rlc_am::rlc_am_tx::empty_queue() } // deallocate SDU that is currently processed - if(tx_sdu) { + if (tx_sdu != NULL) { pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -310,13 +322,13 @@ uint32_t rlc_am::rlc_am_tx::get_buffer_state() // Bytes needed for status report if (do_status() && not status_prohibited) { - n_bytes = parent->rx.get_status(&tx_status); + n_bytes = parent->rx.get_status_pdu_length(); log->debug("%s Buffer state - status report: %d bytes\n", RB_NAME, n_bytes); goto unlock_and_return; } // Bytes needed for retx - if (retx_queue.size() > 0) { + if (not retx_queue.empty()) { rlc_amd_retx_t retx = retx_queue.front(); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); if(tx_window.end() != tx_window.find(retx.sn)) { @@ -326,7 +338,7 @@ uint32_t rlc_am::rlc_am_tx::get_buffer_state() retx_queue.pop_front(); goto unlock_and_return; } - n_bytes = (uint32_t) req_bytes; + n_bytes = static_cast(req_bytes); log->debug("Buffer state - retx: %d bytes\n", n_bytes); goto unlock_and_return; } @@ -336,7 +348,7 @@ uint32_t rlc_am::rlc_am_tx::get_buffer_state() if (tx_window.size() < 1024) { n_sdus = tx_sdu_queue.size(); n_bytes = tx_sdu_queue.size_bytes(); - if (tx_sdu) { + if (tx_sdu != NULL) { n_sdus++; n_bytes += tx_sdu->N_bytes; } @@ -366,12 +378,12 @@ uint32_t rlc_am::rlc_am_tx::get_total_buffer_state() // Bytes needed for status report if(do_status() && not status_prohibited) { - n_bytes += parent->rx.get_status(&tx_status); + n_bytes += parent->rx.get_status_pdu_length(); log->debug("%s Buffer state - total status report: %d bytes\n", RB_NAME, n_bytes); } // Bytes needed for retx - if(retx_queue.size() > 0) { + if(not retx_queue.empty()) { rlc_amd_retx_t retx = retx_queue.front(); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); if(tx_window.end() != tx_window.find(retx.sn)) { @@ -390,19 +402,19 @@ uint32_t rlc_am::rlc_am_tx::get_total_buffer_state() if(tx_window.size() < 1024) { n_sdus = tx_sdu_queue.size(); n_bytes += tx_sdu_queue.size_bytes(); - if(tx_sdu) - { + if (tx_sdu != NULL) { n_sdus++; n_bytes += tx_sdu->N_bytes; } } // Room needed for header extensions? (integer rounding) - if(n_sdus > 1) + if (n_sdus > 1) { n_bytes += ((n_sdus-1)*1.5)+0.5; + } // Room needed for fixed header? - if(n_bytes > 0) { + if (n_bytes > 0) { n_bytes += 3; log->debug("Buffer state - tx SDUs: %d bytes\n", n_bytes); } @@ -417,7 +429,8 @@ void rlc_am::rlc_am_tx::write_sdu(byte_buffer_t *sdu, bool blocking) byte_buffer_pool::get_instance()->deallocate(sdu); return; } - if (sdu) { + + if (sdu != NULL) { if (blocking) { // block on write to queue tx_sdu_queue.write(sdu); @@ -427,7 +440,7 @@ void rlc_am::rlc_am_tx::write_sdu(byte_buffer_t *sdu, bool blocking) if (tx_sdu_queue.try_write(sdu)) { log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", RB_NAME, sdu->N_bytes, tx_sdu_queue.size()); } else { - log->info_hex(sdu->msg, sdu->N_bytes, "[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)", RB_NAME, sdu->N_bytes, tx_sdu_queue.size()); + log->debug_hex(sdu->msg, sdu->N_bytes, "[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)", RB_NAME, sdu->N_bytes, tx_sdu_queue.size()); pool->deallocate(sdu); } } @@ -439,34 +452,30 @@ void rlc_am::rlc_am_tx::write_sdu(byte_buffer_t *sdu, bool blocking) int rlc_am::rlc_am_tx::read_pdu(uint8_t *payload, uint32_t nof_bytes) { pthread_mutex_lock(&mutex); + int pdu_size = 0; log->debug("MAC opportunity - %d bytes\n", nof_bytes); log->debug("tx_window size - %zu PDUs\n", tx_window.size()); + if (not tx_enabled) { + log->debug("RLC entity not active. Not generating PDU.\n"); + goto unlock_and_exit; + } + // Tx STATUS if requested if(do_status() && not status_prohibited) { pdu_size = build_status_pdu(payload, nof_bytes); goto unlock_and_exit; } - // if tx_window is full and retx_queue empty, retransmit next PDU to be ack'ed - if (tx_window.size() >= RLC_AM_WINDOW_SIZE && retx_queue.size() == 0) { - if (tx_window[vt_a].buf != NULL) { - log->warning("Full Tx window, ReTx'ing first outstanding PDU\n"); - rlc_amd_retx_t retx; - retx.is_segment = false; - retx.so_start = 0; - retx.so_end = tx_window[vt_a].buf->N_bytes; - retx.sn = vt_a; - retx_queue.push_back(retx); - } else { - log->error("Found invalid PDU in tx_window.\n"); - } + // Section 5.2.2.3 in TS 36.311, if tx_window is full and retx_queue empty, retransmit random PDU + if (tx_window.size() >= RLC_AM_WINDOW_SIZE && retx_queue.empty()) { + retransmit_random_pdu(); } // RETX if required - if(retx_queue.size() > 0) { + if (not retx_queue.empty()) { pdu_size = build_retx_pdu(payload, nof_bytes); if (pdu_size > 0) { goto unlock_and_exit; @@ -485,31 +494,37 @@ unlock_and_exit: void rlc_am::rlc_am_tx::timer_expired(uint32_t timeout_id) { pthread_mutex_lock(&mutex); - if (poll_retx_timer && poll_retx_timer_id == timeout_id) { - // if both tx and retx buffer are empty, retransmit next PDU to be ack'ed (Section 5.2.2.3 in TS 36.322) - log->debug("Poll reTx timer expired (lcid=%d)\n", parent->lcid); - if ((tx_window.size() > 0 && retx_queue.size() == 0 && tx_sdu_queue.size() == 0)) { - std::map::iterator it = tx_window.find(vt_s - 1); - if (it != tx_window.end()) { - log->info("Schedule last PDU (SN=%d) for reTx.\n", vt_s - 1); - rlc_amd_retx_t retx; - retx.is_segment = false; - retx.so_start = 0; - retx.so_end = tx_window[vt_s - 1].buf->N_bytes; - retx.sn = vt_s - 1; - retx_queue.push_back(retx); - } else { - log->error("Found invalid PDU in tx_window.\n"); - } + if (poll_retx_timer != NULL && poll_retx_timer_id == timeout_id) { + log->debug("Poll reTx timer expired for LCID=%d after %d ms\n", parent->lcid, poll_retx_timer->get_timeout()); + // Section 5.2.2.3 in TS 36.311, schedule random PDU for retransmission if + // (a) both tx and retx buffer are empty, or + // (b) no new data PDU can be transmitted (tx window is full) + if ((retx_queue.empty() && tx_sdu_queue.size() == 0) || tx_window.size() >= RLC_AM_WINDOW_SIZE) { + retransmit_random_pdu(); } } else - if (status_prohibit_timer && status_prohibit_timer_id == timeout_id) { - status_prohibited = true; - status_prohibit_timer->reset(); + if (status_prohibit_timer != NULL && status_prohibit_timer_id == timeout_id) { + status_prohibited = false; } pthread_mutex_unlock(&mutex); } +void rlc_am::rlc_am_tx::retransmit_random_pdu() +{ + if (not tx_window.empty()) { + // randomly select PDU in tx window for retransmission + std::map::iterator it = tx_window.begin(); + std::advance(it, rand() % tx_window.size()); + log->info("Schedule SN=%d for reTx.\n", it->first); + rlc_amd_retx_t retx = {}; + retx.is_segment = false; + retx.so_start = 0; + retx.so_end = it->second.buf->N_bytes; + retx.sn = it->first; + retx_queue.push_back(retx); + } +} + uint32_t rlc_am::rlc_am_tx::get_num_tx_bytes() { return num_tx_bytes; @@ -528,25 +543,28 @@ void rlc_am::rlc_am_tx::reset_metrics() bool rlc_am::rlc_am_tx::poll_required() { - if (cfg.poll_pdu > 0 && pdu_without_poll > (uint32_t)cfg.poll_pdu) { + if (cfg.poll_pdu > 0 && pdu_without_poll > static_cast(cfg.poll_pdu)) { return true; } - if (cfg.poll_byte > 0 && byte_without_poll > (uint32_t)cfg.poll_byte) { + if (cfg.poll_byte > 0 && byte_without_poll > static_cast(cfg.poll_byte)) { return true; } - if (poll_retx_timer) { + if (poll_retx_timer != NULL) { if (poll_retx_timer->is_expired()) { - // re-arm timer + // re-arm timer (will be stopped when status PDU is received) poll_retx_timer->reset(); - poll_retx_timer->set(this, cfg.t_poll_retx); poll_retx_timer->run(); return true; } } - if (tx_sdu_queue.size() == 0 && retx_queue.size() == 0) { + if (tx_window.size() >= RLC_AM_WINDOW_SIZE) { + return true; + } + + if (tx_sdu_queue.size() == 0 && retx_queue.empty()) { return true; } @@ -564,26 +582,30 @@ bool rlc_am::rlc_am_tx::poll_required() int rlc_am::rlc_am_tx::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) { - int pdu_len = parent->rx.get_status(&tx_status); - if (pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) - { + int pdu_len = parent->rx.get_status_pdu(&tx_status, nof_bytes); + log->debug("%s\n", rlc_am_status_pdu_to_string(&tx_status).c_str()); + if (pdu_len > 0 && nof_bytes >= static_cast(pdu_len)) { log->info("%s Tx status PDU - %s\n", - RB_NAME, rlc_am_to_string(&tx_status).c_str()); + RB_NAME, rlc_am_status_pdu_to_string(&tx_status).c_str()); parent->rx.reset_status(); - if(cfg.t_status_prohibit > 0 && status_prohibit_timer) { - status_prohibited = false; - status_prohibit_timer->set(this, cfg.t_status_prohibit); + if (cfg.t_status_prohibit > 0 && status_prohibit_timer != NULL) { + status_prohibited = true; + + // re-arm timer + status_prohibit_timer->reset(); status_prohibit_timer->run(); } debug_state(); - return rlc_am_write_status_pdu(&tx_status, payload); - }else{ + pdu_len = rlc_am_write_status_pdu(&tx_status, payload); + } else{ log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n", RB_NAME, nof_bytes, pdu_len); - return 0; + pdu_len = 0; } + + return pdu_len; } int rlc_am::rlc_am_tx::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) @@ -614,7 +636,8 @@ int rlc_am::rlc_am_tx::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) retx_queue.pop_front(); return -1; } - if(retx.is_segment || req_size > (int)nof_bytes) { + + if (retx.is_segment || req_size > static_cast(nof_bytes)) { log->debug("%s build_retx_pdu - resegmentation required\n", RB_NAME); return build_segment(payload, nof_bytes, retx); } @@ -633,8 +656,8 @@ int rlc_am::rlc_am_tx::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) poll_sn = vt_s; pdu_without_poll = 0; byte_without_poll = 0; - if (poll_retx_timer) { - poll_retx_timer->set(this, cfg.t_poll_retx); + if (poll_retx_timer != NULL) { + poll_retx_timer->reset(); poll_retx_timer->run(); } } @@ -646,6 +669,8 @@ int rlc_am::rlc_am_tx::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) retx_queue.pop_front(); tx_window[retx.sn].retx_count++; if (tx_window[retx.sn].retx_count >= cfg.max_retx_thresh) { + log->warning("%s Signaling max number of reTx=%d for for PDU %d\n", + RB_NAME, tx_window[retx.sn].retx_count, retx.sn); parent->rrc->max_retx_attempted(); } @@ -656,15 +681,14 @@ int rlc_am::rlc_am_tx::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) return (ptr-payload) + tx_window[retx.sn].buf->N_bytes; } -int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx) -{ - if (!tx_window[retx.sn].buf) { +int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx) { + if (tx_window[retx.sn].buf == NULL) { log->error("In build_segment: retx.sn=%d has null buffer\n", retx.sn); return 0; } - if(!retx.is_segment){ + if (!retx.is_segment) { retx.so_start = 0; - retx.so_end = tx_window[retx.sn].buf->N_bytes; + retx.so_end = tx_window[retx.sn].buf->N_bytes; } // Construct new header @@ -676,28 +700,27 @@ int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a log->info("%s pdu_without_poll: %d\n", RB_NAME, pdu_without_poll); log->info("%s byte_without_poll: %d\n", RB_NAME, byte_without_poll); - new_header.dc = RLC_DC_FIELD_DATA_PDU; - new_header.rf = 1; - new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED; - new_header.sn = old_header.sn; - new_header.lsf = 0; - new_header.so = retx.so_start; + new_header.dc = RLC_DC_FIELD_DATA_PDU; + new_header.rf = 1; + new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED; + new_header.sn = old_header.sn; + new_header.lsf = 0; + new_header.so = retx.so_start; new_header.N_li = 0; - new_header.p = 0; - if(poll_required()) - { + new_header.p = 0; + if (poll_required()) { log->debug("%s setting poll bit to request status\n", RB_NAME); - new_header.p = 1; - poll_sn = vt_s; - pdu_without_poll = 0; + new_header.p = 1; + poll_sn = vt_s; + pdu_without_poll = 0; byte_without_poll = 0; - if (poll_retx_timer) { - poll_retx_timer->set(this, cfg.t_poll_retx); + if (poll_retx_timer != NULL) { + poll_retx_timer->reset(); poll_retx_timer->run(); } } - uint32_t head_len = 0; + uint32_t head_len = 0; uint32_t pdu_space = 0; head_len = rlc_am_packed_length(&new_header); @@ -706,76 +729,84 @@ int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a head_len += 2; } - if(nof_bytes <= head_len) - { + if (nof_bytes <= head_len) { log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", RB_NAME, nof_bytes, head_len); return 0; } - pdu_space = nof_bytes-head_len; - if(pdu_space < (retx.so_end-retx.so_start)) - retx.so_end = retx.so_start+pdu_space; + pdu_space = nof_bytes - head_len; + if (pdu_space < (retx.so_end - retx.so_start)) { + retx.so_end = retx.so_start + pdu_space; + } // Need to rebuild the li table & update fi based on so_start and so_end - if(retx.so_start == 0 && rlc_am_start_aligned(old_header.fi)) + if (retx.so_start == 0 && rlc_am_start_aligned(old_header.fi)) { new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment is start aligned + } uint32_t lower = 0; uint32_t upper = 0; uint32_t li = 0; for(uint32_t i=0; i= retx.so_end) + if (lower >= retx.so_end) { break; + } - if(pdu_space <= 2) + if (pdu_space <= 2) { break; + } upper += old_header.li[i]; head_len = rlc_am_packed_length(&new_header); + + // Accomodate some extra space for for LIs if old header contained segments too + head_len += old_header.N_li; + pdu_space = nof_bytes-head_len; - if(pdu_space < (retx.so_end-retx.so_start)) - retx.so_end = retx.so_start+pdu_space; + if(pdu_space < (retx.so_end-retx.so_start)) { + retx.so_end = retx.so_start + pdu_space; + } if(upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed li = upper - lower; - if(upper > retx.so_end) + if (upper > retx.so_end) { li -= upper - retx.so_end; - if(lower < retx.so_start) + } + if (lower < retx.so_start) { li -= retx.so_start - lower; - if(lower > 0 && lower == retx.so_start) + } + if (lower > 0 && lower == retx.so_start) { new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment start is aligned with this SDU - if(upper == retx.so_end) { + } + if (upper == retx.so_end) { new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU } - new_header.li[new_header.N_li++] = li; + new_header.li[new_header.N_li] = li; + + // only increment N_li if more SDU (segments) are being added + if (retx.so_end > upper) { + new_header.N_li++; + } } lower += old_header.li[i]; } - // Make sure LI is not deleted in case the SDU boundary is crossed - // FIXME: fix if N_li > 1 - if (new_header.N_li == 1 && retx.so_start + new_header.li[0] < retx.so_end && retx.so_end <= retx.so_start + pdu_space) { - // This segment crosses a SDU boundary - new_header.N_li++; - } - // Update retx_queue if(tx_window[retx.sn].buf->N_bytes == retx.so_end) { retx_queue.pop_front(); new_header.lsf = 1; - if(rlc_am_end_aligned(old_header.fi)) + if(rlc_am_end_aligned(old_header.fi)) { new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment is end aligned + } } else if(retx_queue.front().so_end == retx.so_end) { retx_queue.pop_front(); } else { retx_queue.front().is_segment = true; retx_queue.front().so_start = retx.so_end; - if(new_header.N_li > 0) - new_header.N_li--; } // Write header and pdu @@ -785,37 +816,37 @@ int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a uint32_t len = retx.so_end - retx.so_start; memcpy(ptr, data, len); - log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n", - RB_NAME, retx.sn, retx.so_start); - debug_state(); int pdu_len = (ptr-payload) + len; - if(pdu_len > (int)nof_bytes) { + if (pdu_len > static_cast(nof_bytes)) { log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n", RB_NAME, nof_bytes, pdu_len); log->debug("%s Retx PDU segment length error. Header len: %ld, Payload len: %d, N_li: %d\n", RB_NAME, (ptr-payload), len, new_header.N_li); } + + log->info_hex(payload, pdu_len, "%s Retx PDU segment of SN=%d (%d B), SO: %d, N_li: %d\n", + RB_NAME, retx.sn, pdu_len, retx.so_start, new_header.N_li); + return pdu_len; } int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { - if(!tx_sdu && tx_sdu_queue.size() == 0) - { + if (tx_sdu == NULL && tx_sdu_queue.size() == 0) { log->info("No data available to be sent\n"); return 0; } // do not build any more PDU if window is already full - if (!tx_sdu && tx_window.size() >= RLC_AM_WINDOW_SIZE) { + if (tx_sdu == NULL && tx_window.size() >= RLC_AM_WINDOW_SIZE) { log->info("Tx window full.\n"); return 0; } byte_buffer_t *pdu = pool_allocate_blocking; - if (!pdu) { + if (pdu == NULL) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in build_data_pdu()\n"); log->console("tx_window size: %d PDUs\n", tx_window.size()); @@ -847,7 +878,7 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t head_len = rlc_am_packed_length(&header); uint32_t to_move = 0; uint32_t last_li = 0; - uint32_t pdu_space = nof_bytes; + uint32_t pdu_space = SRSLTE_MIN(nof_bytes, pdu->get_tailroom()); uint8_t *pdu_ptr = pdu->msg; if(pdu_space <= head_len + 1) @@ -862,8 +893,7 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) RB_NAME, pdu_space, head_len); // Check for SDU segment - if(tx_sdu) - { + if (tx_sdu != NULL) { to_move = ((pdu_space-head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space-head_len; memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; @@ -878,10 +908,11 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pool->deallocate(tx_sdu); tx_sdu = NULL; } - if(pdu_space > to_move) - pdu_space -= to_move; - else + if (pdu_space > to_move) { + pdu_space -= SRSLTE_MIN(to_move, pdu->get_tailroom()); + } else { pdu_space = 0; + } header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", @@ -889,12 +920,13 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) } // Pull SDUs from queue - while(pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) - { - if(last_li > 0) - header.li[header.N_li++] = last_li; + while (pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) { + if (last_li > 0) { + header.li[header.N_li] = last_li; + header.N_li++; + } head_len = rlc_am_packed_length(&header); - if(head_len >= pdu_space) { + if (head_len >= pdu_space) { header.N_li--; break; } @@ -906,17 +938,17 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pdu->N_bytes += to_move; tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; - if(tx_sdu->N_bytes == 0) - { + if (tx_sdu->N_bytes == 0) { log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", RB_NAME, tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } - if(pdu_space > to_move) + if(pdu_space > to_move) { pdu_space -= to_move; - else + } else { pdu_space = 0; + } log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", RB_NAME, to_move, pdu_space, head_len); @@ -928,8 +960,9 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) return 0; } - if(tx_sdu) + if (tx_sdu != NULL) { header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU + } // Set Poll bit pdu_without_poll++; @@ -943,8 +976,8 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) poll_sn = vt_s; pdu_without_poll = 0; byte_without_poll = 0; - if (poll_retx_timer) { - poll_retx_timer->set(this, cfg.t_poll_retx); + if (poll_retx_timer != NULL) { + poll_retx_timer->reset(); poll_retx_timer->run(); } } @@ -962,10 +995,11 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint8_t *ptr = payload; rlc_am_write_data_pdu_header(&header, &ptr); memcpy(ptr, pdu->msg, pdu->N_bytes); - log->info_hex(payload, pdu->N_bytes, "%s PDU scheduled for tx. SN: %d (%d B)\n", RB_NAME, header.sn, pdu->N_bytes); - + int total_len = (ptr-payload) + pdu->N_bytes; + log->info_hex(payload, total_len, "%s Tx PDU SN=%d (%d B)\n", RB_NAME, header.sn, total_len); + log->debug("%s\n", rlc_amd_pdu_header_to_string(header).c_str()); debug_state(); - return (ptr-payload) + pdu->N_bytes; + return total_len; } void rlc_am::rlc_am_tx::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) @@ -977,10 +1011,10 @@ void rlc_am::rlc_am_tx::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) rlc_status_pdu_t status; rlc_am_read_status_pdu(payload, nof_bytes, &status); - log->info("%s Rx Status PDU: %s\n", RB_NAME, rlc_am_to_string(&status).c_str()); + log->info("%s Rx Status PDU: %s\n", RB_NAME, rlc_am_status_pdu_to_string(&status).c_str()); - if (poll_retx_timer) { - poll_retx_timer->reset(); + if (poll_retx_timer != NULL) { + poll_retx_timer->stop(); } // flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again @@ -1005,7 +1039,8 @@ void rlc_am::rlc_am_tx::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_window.end() != it) { if(!retx_queue_has_sn(i)) { - rlc_amd_retx_t retx; + rlc_amd_retx_t retx = {}; + retx.sn = i; retx.is_segment = false; retx.so_start = 0; retx.so_end = it->second.buf->N_bytes; @@ -1036,8 +1071,6 @@ void rlc_am::rlc_am_tx::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) RB_NAME, i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); } } - - retx.sn = i; retx_queue.push_back(retx); } } @@ -1050,7 +1083,7 @@ void rlc_am::rlc_am_tx::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) it = tx_window.find(i); if (it != tx_window.end()) { if(update_vt_a) { - if(it->second.buf) { + if (it->second.buf != NULL) { pool->deallocate(it->second.buf); it->second.buf = 0; } @@ -1080,7 +1113,7 @@ void rlc_am::rlc_am_tx::debug_state() int rlc_am::rlc_am_tx::required_buffer_size(rlc_amd_retx_t retx) { if (!retx.is_segment) { - if (tx_window.count(retx.sn)) { + if (tx_window.count(retx.sn) == 1) { if (tx_window[retx.sn].buf) { return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; } else { @@ -1106,33 +1139,34 @@ int rlc_am::rlc_am_tx::required_buffer_size(rlc_amd_retx_t retx) new_header.so = retx.so_start; new_header.N_li = 0; - uint32_t head_len = 0; - // Need to rebuild the li table & update fi based on so_start and so_end - if(retx.so_start != 0 && rlc_am_start_aligned(old_header.fi)) + if(retx.so_start != 0 && rlc_am_start_aligned(old_header.fi)) { new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment is start aligned + } uint32_t lower = 0; uint32_t upper = 0; uint32_t li = 0; for(uint32_t i=0; i= retx.so_end) + if(lower >= retx.so_end) { break; + } upper += old_header.li[i]; - head_len = rlc_am_packed_length(&new_header); - - if(upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed + if (upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed li = upper - lower; - if(upper > retx.so_end) + if (upper > retx.so_end) { li -= upper - retx.so_end; - if(lower < retx.so_start) + } + if (lower < retx.so_start) { li -= retx.so_start - lower; - if(lower > 0 && lower == retx.so_start) + } + if (lower > 0 && lower == retx.so_start) { new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment start is aligned with this SDU - if(upper == retx.so_end) { + } + if (upper == retx.so_end) { new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU } new_header.li[new_header.N_li++] = li; @@ -1152,9 +1186,10 @@ int rlc_am::rlc_am_tx::required_buffer_size(rlc_amd_retx_t retx) bool rlc_am::rlc_am_tx::retx_queue_has_sn(uint32_t sn) { std::deque::iterator q_it; - for(q_it = retx_queue.begin(); q_it != retx_queue.end(); q_it++) { - if(q_it->sn == sn) + for (q_it = retx_queue.begin(); q_it != retx_queue.end(); ++q_it) { + if (q_it->sn == sn) { return true; + } } return false; } @@ -1192,8 +1227,8 @@ rlc_am::rlc_am_rx::~rlc_am_rx() void rlc_am::rlc_am_rx::init() { - log = parent->log; - if (parent->mac_timers) { + log = parent->log; + if (parent->mac_timers != NULL) { reordering_timer_id = parent->mac_timers->timer_get_unique_id(); reordering_timer = parent->mac_timers->timer_get(reordering_timer_id); } @@ -1205,10 +1240,15 @@ bool rlc_am::rlc_am_rx::configure(srslte_rlc_am_config_t cfg_) cfg = cfg_; // check timers - if (not reordering_timer) { + if (reordering_timer == NULL) { return false; } + // configure timer + if (cfg.t_reordering > 0) { + reordering_timer->set(this, static_cast(cfg.t_reordering)); + } + return true; } @@ -1221,13 +1261,13 @@ void rlc_am::rlc_am_rx::stop() { pthread_mutex_lock(&mutex); - if (parent->mac_timers && reordering_timer) { + if (parent->mac_timers != NULL && reordering_timer != NULL) { reordering_timer->stop(); parent->mac_timers->timer_release_id(reordering_timer_id); reordering_timer = NULL; } - if (rx_sdu) { + if (rx_sdu != NULL) { pool->deallocate(rx_sdu); rx_sdu = NULL; } @@ -1268,8 +1308,11 @@ void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rl { std::map::iterator it; - log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d (%d B), %s", - RB_NAME, header.sn, nof_bytes, rlc_fi_field_text[header.fi]); + log->info_hex(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", + RB_NAME, + header.sn, + nof_bytes); + log->debug("%s\n", rlc_amd_pdu_header_to_string(header).c_str()); if(!inside_rx_window(header.sn)) { if(header.p) { @@ -1295,7 +1338,7 @@ void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rl // Write to rx window rlc_amd_rx_pdu_t pdu; pdu.buf = pool_allocate_blocking; - if (!pdu.buf) { + if (pdu.buf == NULL) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n"); exit(-1); @@ -1331,14 +1374,12 @@ void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rl } // Check poll bit - if(header.p) { + if (header.p) { log->info("%s Status packet requested through polling bit\n", RB_NAME); poll_received = true; // 36.322 v10 Section 5.2.3 - if(RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ms) || - RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_mr)) - { + if (RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ms) || RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_mr)) { do_status = true; } // else delay for reordering timer @@ -1348,16 +1389,16 @@ void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rl reassemble_rx_sdus(); // Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3) - if (reordering_timer) { + if (reordering_timer != NULL) { if (reordering_timer->is_running()) { if(vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr)) { - reordering_timer->reset(); + reordering_timer->stop(); } } if (not reordering_timer->is_running()) { if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) { - reordering_timer->set(this, cfg.t_reordering); + reordering_timer->reset(); reordering_timer->run(); vr_x = vr_h; } @@ -1372,8 +1413,9 @@ void rlc_am::rlc_am_rx::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_b { std::map::iterator it; - log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d", - RB_NAME, header.sn, header.so); + log->info_hex(payload, nof_bytes, "%s Rx data PDU segment of SN=%d (%d B), SO=%d, N_li=%d", + RB_NAME, header.sn, nof_bytes, header.so, header.N_li); + log->debug("%s\n", rlc_amd_pdu_header_to_string(header).c_str()); // Check inside rx window if(!inside_rx_window(header.sn)) { @@ -1388,7 +1430,7 @@ void rlc_am::rlc_am_rx::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_b rlc_amd_rx_pdu_t segment; segment.buf = pool_allocate_blocking; - if (!segment.buf) { + if (segment.buf == NULL) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment().\n"); exit(-1); @@ -1404,9 +1446,9 @@ void rlc_am::rlc_am_rx::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_b // Check if we already have a segment from the same PDU it = rx_segments.find(header.sn); - if(rx_segments.end() != it) { + if (rx_segments.end() != it) { - if(header.p) { + if (header.p) { log->info("%s Status packet requested through polling bit\n", RB_NAME); do_status = true; } @@ -1429,14 +1471,13 @@ void rlc_am::rlc_am_rx::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_b pdu.segments.push_back(segment); rx_segments[header.sn] = pdu; - // Update vr_h - if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) - vr_h = (header.sn + 1)%MOD; + if (RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) { + vr_h = (header.sn + 1) % MOD; + } // Check poll bit - if(header.p) - { + if (header.p) { log->info("%s Status packet requested through polling bit\n", RB_NAME); poll_received = true; @@ -1459,9 +1500,9 @@ void rlc_am::rlc_am_rx::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_b void rlc_am::rlc_am_rx::reassemble_rx_sdus() { uint32_t len = 0; - if(!rx_sdu) { + if (rx_sdu == NULL) { rx_sdu = pool_allocate_blocking; - if (!rx_sdu) { + if (rx_sdu == NULL) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n"); exit(-1); @@ -1479,6 +1520,9 @@ void rlc_am::rlc_am_rx::reassemble_rx_sdus() for(uint32_t i=0; idebug_hex(rx_window[vr_r].buf->msg, len, "Handling segment %d/%d of length %d B of SN=%d\n", i+1, rx_window[vr_r].header.N_li, len, vr_r); + // sanity check to avoid zero-size SDUs if (len == 0) { break; @@ -1495,7 +1539,7 @@ void rlc_am::rlc_am_rx::reassemble_rx_sdus() parent->pdcp->write_pdu(parent->lcid, rx_sdu); rx_sdu = pool_allocate_blocking; - if (!rx_sdu) { + if (rx_sdu == NULL) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); exit(-1); @@ -1518,22 +1562,23 @@ void rlc_am::rlc_am_rx::reassemble_rx_sdus() // Handle last segment len = rx_window[vr_r].buf->N_bytes; + log->debug_hex(rx_window[vr_r].buf->msg, len, "Handling last segment of length %d B of SN=%d\n", len, vr_r); if (rx_sdu->get_tailroom() >= len) { memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len); rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; } else { - log->error("Cannot fit RLC PDU in SDU buffer, dropping both.\n"); + log->error("Cannot fit RLC PDU in SDU buffer, dropping both. Erasing SN=%d.\n", vr_r); pool->deallocate(rx_sdu); pool->deallocate(rx_window[vr_r].buf); rx_window.erase(vr_r); } - if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) { + if (rlc_am_end_aligned(rx_window[vr_r].header.fi)) { log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes); rx_sdu->set_timestamp(); parent->pdcp->write_pdu(parent->lcid, rx_sdu); rx_sdu = pool_allocate_blocking; - if (!rx_sdu) { + if (rx_sdu == NULL) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)\n"); exit(-1); @@ -1546,6 +1591,19 @@ void rlc_am::rlc_am_rx::reassemble_rx_sdus() exit: // Move the rx_window + log->debug("Erasing SN=%d.\n", vr_r); + // also erase any segments of this SN + std::map::iterator it; + it = rx_segments.find(vr_r); + if(rx_segments.end() != it) { + log->debug("Erasing segments of SN=%d\n", vr_r); + std::list::iterator segit; + for(segit = it->second.segments.begin(); segit != it->second.segments.end(); ++segit) { + log->debug(" Erasing segment of SN=%d SO=%d Len=%d N_li=%d\n", segit->header.sn, segit->header.so, segit->buf->N_bytes, segit->header.N_li); + pool->deallocate(segit->buf); + } + it->second.segments.clear(); + } pool->deallocate(rx_window[vr_r].buf); rx_window.erase(vr_r); vr_r = (vr_r + 1)%MOD; @@ -1604,7 +1662,7 @@ void rlc_am::rlc_am_rx::write_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_am::rlc_am_rx::timer_expired(uint32_t timeout_id) { pthread_mutex_lock(&mutex); - if (reordering_timer && reordering_timer_id == timeout_id) { + if (reordering_timer != NULL && reordering_timer_id == timeout_id) { reordering_timer->reset(); log->debug("%s reordering timeout expiry - updating vr_ms\n", RB_NAME); @@ -1621,7 +1679,7 @@ void rlc_am::rlc_am_rx::timer_expired(uint32_t timeout_id) } if (RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_ms)) { - reordering_timer->set(this, cfg.t_reordering); + reordering_timer->reset(); reordering_timer->run(); vr_x = vr_h; } @@ -1631,8 +1689,8 @@ void rlc_am::rlc_am_rx::timer_expired(uint32_t timeout_id) pthread_mutex_unlock(&mutex); } -// Called from Tx object (packs status PDU and returns length of it) -int rlc_am::rlc_am_rx::get_status(rlc_status_pdu_t* status) +// Called from Tx object to pack status PDU that doesn't exceed a given size +int rlc_am::rlc_am_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_pdu_size) { pthread_mutex_lock(&mutex); status->N_nack = 0; @@ -1640,9 +1698,11 @@ int rlc_am::rlc_am_rx::get_status(rlc_status_pdu_t* status) // We don't use segment NACKs - just NACK the full PDU uint32_t i = vr_r; - while(RX_MOD_BASE(i) < RX_MOD_BASE(vr_ms)) { + while (RX_MOD_BASE(i) < RX_MOD_BASE(vr_ms) && status->N_nack < RLC_AM_WINDOW_SIZE && rlc_am_packed_length(status) <= max_pdu_size-2) { + status->ack_sn = i; if(rx_window.find(i) == rx_window.end()) { - status->nacks[status->N_nack++].nack_sn = i; + status->nacks[status->N_nack].nack_sn = i; + status->N_nack++; } i = (i + 1)%MOD; } @@ -1650,6 +1710,22 @@ int rlc_am::rlc_am_rx::get_status(rlc_status_pdu_t* status) return rlc_am_packed_length(status); } +// Called from Tx object to obtain length of the full status PDU +int rlc_am::rlc_am_rx::get_status_pdu_length() +{ + pthread_mutex_lock(&mutex); + rlc_status_pdu_t status; + uint32_t i = vr_r; + while (RX_MOD_BASE(i) < RX_MOD_BASE(vr_ms) && status.N_nack < RLC_AM_WINDOW_SIZE) { + if(rx_window.find(i) == rx_window.end()) { + status.N_nack++; + } + i = (i + 1)%MOD; + } + pthread_mutex_unlock(&mutex); + return rlc_am_packed_length(&status); +} + void rlc_am::rlc_am_rx::print_rx_segments() { std::map::iterator it; @@ -1694,12 +1770,14 @@ bool rlc_am::rlc_am_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rl uint32_t so = 0; std::list::iterator it, tmpit; for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) { - if(so != it->header.so) + if (so != it->header.so) { return false; + } so += it->buf->N_bytes; } - if(!pdu->segments.back().header.lsf) + if (!pdu->segments.back().header.lsf) { return false; + } // We have all segments of the PDU - reconstruct and handle rlc_amd_pdu_header_t header; @@ -1716,36 +1794,49 @@ bool rlc_am::rlc_am_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rl header.fi |= (pdu->segments.front().header.fi & RLC_FI_FIELD_NOT_START_ALIGNED); header.fi |= (pdu->segments.back().header.fi & RLC_FI_FIELD_NOT_END_ALIGNED); + log->debug("Starting header reconstruction of %zd segments\n", pdu->segments.size()); + // Reconstruct li fields uint16_t count = 0; uint16_t carryover = 0; for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) { - if(it->header.N_li > 0) { - header.li[header.N_li++] = it->header.li[0] + carryover; - count += it->header.li[0]; - for(uint32_t i=1; iheader.N_li; i++) { - header.li[header.N_li++] = it->header.li[i]; - count += it->header.li[i]; + log->debug(" Handling %d PDU segments\n", it->header.N_li); + for(uint32_t i=0; iheader.N_li; i++) { + header.li[header.N_li] = it->header.li[i]; + if (i == 0) { + header.li[header.N_li] += carryover; } + log->debug(" - adding segment %d/%d (%d B, SO=%d, carryover=%d, count=%d)\n", i+1, it->header.N_li, header.li[header.N_li], header.so, carryover, count); + header.N_li++; + count += it->header.li[i]; + carryover = 0; } - // accumulate segment sizes until end aligned PDU is received - if (rlc_am_not_start_aligned(it->header.fi)) { + if (count <= it->buf->N_bytes) { carryover += it->buf->N_bytes - count; + log->debug("Incremented carryover (it->buf->N_bytes=%d, count=%d). New carryover=%d\n", it->buf->N_bytes, count, carryover); } else { - carryover = it->buf->N_bytes - count; + // Next segment would be too long, recalculate carryover + header.N_li--; + carryover = it->buf->N_bytes - (count - header.li[header.N_li]); + log->debug("Recalculated carryover=%d (it->buf->N_bytes=%d, count=%d, header.li[header.N_li]=%d)\n", carryover, it->buf->N_bytes, count, header.li[header.N_li]); } + tmpit = it; if(rlc_am_end_aligned(it->header.fi) && ++tmpit != pdu->segments.end()) { - header.li[header.N_li++] = carryover; + log->debug("Header is end-aligned, overwrite header.li[%d]=%d\n", header.N_li, carryover); + header.li[header.N_li] = carryover; + header.N_li++; carryover = 0; } count = 0; } + log->debug("Finished header reconstruction of %zd segments\n", pdu->segments.size()); + // Copy data byte_buffer_t *full_pdu = pool_allocate_blocking; - if (!full_pdu) { + if (full_pdu == NULL) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in add_segment_and_check()\n"); exit(-1); @@ -1801,14 +1892,14 @@ void rlc_am_read_data_pdu_header(uint8_t **payload, uint32_t *nof_bytes, rlc_amd uint8_t ext; uint8_t *ptr = *payload; - header->dc = (rlc_dc_field_t)((*ptr >> 7) & 0x01); + header->dc = static_cast((*ptr >> 7) & 0x01); if(RLC_DC_FIELD_DATA_PDU == header->dc) { // Fixed part header->rf = ((*ptr >> 6) & 0x01); header->p = ((*ptr >> 5) & 0x01); - header->fi = (rlc_fi_field_t)((*ptr >> 3) & 0x03); + header->fi = static_cast((*ptr >> 3) & 0x03); ext = ((*ptr >> 2) & 0x01); header->sn = (*ptr & 0x03) << 8; // 2 bits SN ptr++; @@ -1848,8 +1939,9 @@ void rlc_am_read_data_pdu_header(uint8_t **payload, uint32_t *nof_bytes, rlc_amd } // Account for padding if N_li is odd - if(header->N_li%2 == 1) + if (header->N_li%2 == 1) { ptr++; + } *nof_bytes -= ptr-*payload; *payload = ptr; @@ -1885,7 +1977,7 @@ void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t *header, uint8_t **payloa ptr++; // Segment part - if(header->rf) + if (header->rf) { *ptr = (header->lsf & 0x01) << 7; *ptr |= (header->so & 0x7F00) >> 8; // 7 bits of SO @@ -1916,8 +2008,9 @@ void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t *header, uint8_t **payloa } } // Pad if N_li is odd - if(header->N_li%2 == 1) + if (header->N_li%2 == 1) { ptr++; + } *payload = ptr; } @@ -1937,7 +2030,7 @@ void rlc_am_read_status_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_status_pdu srslte_bit_unpack_vector(payload, tmp.msg, nof_bytes*8); tmp.N_bits = nof_bytes*8; - rlc_dc_field_t dc = (rlc_dc_field_t)srslte_bit_pack(&ptr, 1); + rlc_dc_field_t dc = static_cast(srslte_bit_pack(&ptr, 1)); if(RLC_DC_FIELD_CONTROL_PDU == dc) { @@ -2009,7 +2102,9 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t *status, uint8_t *payload) uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header) { uint32_t len = 2; // Fixed part is 2 bytes - if(header->rf) len += 2; // Segment header is 2 bytes + if (header->rf) { + len += 2; // Segment header is 2 bytes + } len += header->N_li * 1.5 + 0.5; // Extension part - integer rounding up return len; } @@ -2045,7 +2140,7 @@ bool rlc_am_is_pdu_segment(uint8_t *payload) return ((*(payload) >> 6) & 0x01) == 1; } -std::string rlc_am_to_string(rlc_status_pdu_t *status) +std::string rlc_am_status_pdu_to_string(rlc_status_pdu_t *status) { std::stringstream ss; ss << "ACK_SN = " << status->ack_sn; @@ -2066,6 +2161,28 @@ std::string rlc_am_to_string(rlc_status_pdu_t *status) return ss.str(); } +std::string rlc_amd_pdu_header_to_string(const rlc_amd_pdu_header_t &header) +{ + std::stringstream ss; + ss << "[" << rlc_dc_field_text[header.dc]; + ss << ", RF=" << (header.rf ? "1":"0"); + ss << ", P=" << (header.p ? "1":"0"); + ss << ", FI=" << (header.fi ? "1":"0"); + ss << ", SN=" << header.sn; + ss << ", LSF=" << (header.lsf ? "1":"0"); + ss << ", SO=" << header.so; + ss << ", N_li=" << header.N_li; + if (header.N_li > 0) { + ss << " ("; + for (uint32_t i = 0; i < header.N_li; i++) { + ss << header.li[i] << ", "; + } + ss << ")"; + } + ss << "]"; + return ss.str(); +} + bool rlc_am_start_aligned(const uint8_t fi) { return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_END_ALIGNED); @@ -2086,4 +2203,4 @@ bool rlc_am_not_start_aligned(const uint8_t fi) return (fi == RLC_FI_FIELD_NOT_START_ALIGNED || fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED); } -} // namespace srsue +} // namespace srslte diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 5a13b55f6..7145a8b66 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -37,6 +37,7 @@ namespace srslte { rlc_um::rlc_um(uint32_t queue_len) :lcid(0) ,tx(queue_len) + ,pool(byte_buffer_pool::get_instance()) ,rrc(NULL) ,log(NULL) { @@ -150,6 +151,11 @@ uint32_t rlc_um::get_bearer() ***************************************************************************/ void rlc_um::write_sdu(byte_buffer_t *sdu, bool blocking) { + if (sdu->N_bytes > RLC_UM_MAX_SDU_SIZE) { + log->warning("Dropping too long SDU of size %d B (Max. size %d B).", sdu->N_bytes, RLC_UM_MAX_SDU_SIZE); + pool->deallocate(sdu); + } + if (blocking) { tx.write_sdu(sdu); } else { @@ -399,7 +405,7 @@ int rlc_um::rlc_um_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint8_t *pdu_ptr = pdu->msg; int head_len = rlc_um_packed_length(&header); - int pdu_space = nof_bytes; + int pdu_space = SRSLTE_MIN(nof_bytes, pdu->get_tailroom());; if(pdu_space <= head_len + 1) { @@ -430,7 +436,7 @@ int rlc_um::rlc_um_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pool->deallocate(tx_sdu); tx_sdu = NULL; } - pdu_space -= to_move; + pdu_space -= SRSLTE_MIN(to_move, pdu->get_tailroom()); header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU } @@ -474,7 +480,7 @@ int rlc_um::rlc_um_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) memcpy(payload, pdu->msg, pdu->N_bytes); uint32_t ret = pdu->N_bytes; - log->info("%s Transmitting PDU SN=%d (%d B)\n", get_rb_name(), header.sn, pdu->N_bytes); + log->info("%s Tx PDU SN=%d (%d B)\n", get_rb_name(), header.sn, pdu->N_bytes); pool->deallocate(pdu); debug_state(); @@ -595,7 +601,7 @@ void rlc_um::rlc_um_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header); - log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", get_rb_name(), header.sn); + log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d (%d B)", get_rb_name(), header.sn, nof_bytes); if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) && RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) @@ -758,35 +764,29 @@ void rlc_um::rlc_um_rx::reassemble_rx_sdus() // Now update vr_ur until we reach an SN we haven't yet received while(rx_window.end() != rx_window.find(vr_ur)) { log->debug("Reassemble loop for vr_ur=%d\n", vr_ur); - if ((vr_ur_in_rx_sdu+1)%cfg.rx_mod != vr_ur) { - log->warning("PDU SN=%d lost, dropping remainder of %d\n", vr_ur_in_rx_sdu+1, vr_ur); + + if (not pdu_belongs_to_rx_sdu()) { + log->warning("PDU SN=%d lost, stop reassambling SDU (vr_ur_in_rx_sdu=%d)\n", vr_ur_in_rx_sdu+1, vr_ur_in_rx_sdu); + pdu_lost = false; // Reset flag to not prevent reassembling of further segments rx_sdu->reset(); } // Handle any SDU segments for(uint32_t i=0; idebug("Handling SDU egment i=%d with len=%d of vr_ur=%d N_li=%d [%s]\n", i, len, vr_ur, rx_window[vr_ur].header.N_li, rlc_fi_field_text[rx_window[vr_ur].header.fi]); // Check if the first part of the PDU is a middle or end segment if (rx_sdu->N_bytes == 0 && i == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { - log->warning_hex(rx_window[vr_ur].buf->msg, len, "Dropping first part of SN %d due to lost start segment\n", vr_ur); + log->warning_hex(rx_window[vr_ur].buf->msg, len, "Dropping first %d B of SN %d due to lost start segment\n", len, vr_ur); // Advance data pointers and continue with next segment rx_window[vr_ur].buf->msg += len; rx_window[vr_ur].buf->N_bytes -= len; rx_sdu->reset(); - // beginning of next SDU? - if (rx_window[vr_ur].header.fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED) { - len = rx_window[vr_ur].buf->N_bytes; - log->info_hex(rx_window[vr_ur].buf->msg, len, "Copying first %d bytes of new SDU\n", len); - memcpy(rx_sdu->msg, rx_window[vr_ur].buf->msg, len); - rx_sdu->N_bytes = len; - rx_window[vr_ur].buf->msg += len; - rx_window[vr_ur].buf->N_bytes -= len; - log->info("Updating vr_ur_in_rx_sdu. old=%d, new=%d\n", vr_ur_in_rx_sdu, vr_ur); - vr_ur_in_rx_sdu = vr_ur; - goto clean_up_rx_window; - } + // Reset flag, it is safe to process all remaining segments of this PDU + pdu_lost = false; + continue; } // Check available space in SDU @@ -796,16 +796,22 @@ void rlc_um::rlc_um_rx::reassemble_rx_sdus() goto clean_up_rx_window; } - log->info_hex(rx_window[vr_ur].buf->msg, len, "Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d\n", - len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, cfg.rx_mod, (vr_ur_in_rx_sdu+1)%cfg.rx_mod); + if (not pdu_belongs_to_rx_sdu()) { + log->info_hex(rx_window[vr_ur].buf->msg, len, "Copying first %d bytes of new SDU\n", len); + log->info("Updating vr_ur_in_rx_sdu. old=%d, new=%d\n", vr_ur_in_rx_sdu, vr_ur); + vr_ur_in_rx_sdu = vr_ur; + } else { + log->info_hex(rx_window[vr_ur].buf->msg, len, "Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d\n", + len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, cfg.rx_mod, (vr_ur_in_rx_sdu+1)%cfg.rx_mod); + } + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); rx_sdu->N_bytes += len; rx_window[vr_ur].buf->msg += len; rx_window[vr_ur].buf->N_bytes -= len; - if((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || (vr_ur != ((vr_ur_in_rx_sdu+1)%cfg.rx_mod))) { - log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); - rx_sdu->reset(); - } else { + vr_ur_in_rx_sdu = vr_ur; + + if (not pdu_lost && pdu_belongs_to_rx_sdu()) { log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", get_rb_name(), vr_ur, i); rx_sdu->set_timestamp(); if(cfg.is_mrb){ @@ -818,6 +824,11 @@ void rlc_um::rlc_um_rx::reassemble_rx_sdus() log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n"); return; } + } else { + log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); + // Advance data pointers and continue with next segment + rx_window[vr_ur].buf->msg += len; + rx_window[vr_ur].buf->N_bytes -= len; } pdu_lost = false; } @@ -833,8 +844,8 @@ void rlc_um::rlc_um_rx::reassemble_rx_sdus() rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES && rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES) { - log->info_hex(rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes, "Writing last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", - vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); + log->info_hex(rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes, "Writing last segment in SDU buffer. Updating vr_ur=%d, vr_ur_in_rx_sdu=%d, Buffer size=%d, segment size=%d\n", + vr_ur, vr_ur_in_rx_sdu, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; } else { @@ -872,6 +883,18 @@ clean_up_rx_window: } } + +// Only called when lock is hold +bool rlc_um::rlc_um_rx::pdu_belongs_to_rx_sdu() +{ + // return true if the currently received SDU + if (((vr_ur_in_rx_sdu + 1)%cfg.rx_mod == vr_ur) || (vr_ur == vr_ur_in_rx_sdu)) { + return true; + } + return false; +} + + // Only called when lock is hold // 36.322 Section 5.1.2.2.1 bool rlc_um::rlc_um_rx::inside_reordering_window(uint16_t sn) diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index e3fcd4f4b..7a5a49898 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -34,7 +34,12 @@ add_executable(rlc_stress_test rlc_stress_test.cc) target_link_libraries(rlc_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES}) add_test(rlc_am_stress_test rlc_stress_test --mode=AM --loglevel 1 --sdu_gen_delay 250) add_test(rlc_um_stress_test rlc_stress_test --mode=UM --loglevel 1) -add_test(rlc_tm_stress_test rlc_stress_test --mode=TM --loglevel 1 --opp_sdu_ratio=1.0) +add_test(rlc_tm_stress_test rlc_stress_test --mode=TM --loglevel 1 --random_opp=false) + +# Run clang-tidy if available +if(CLANG_TIDY_BIN) + set_target_properties(rlc_stress_test PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}") +endif() add_executable(rlc_um_data_test rlc_um_data_test.cc) target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index bd5e7e2c0..bb6628279 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -732,11 +732,11 @@ bool resegment_test_2() // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); - assert(16 == rlc1.get_buffer_state()); + assert(18 == rlc1.get_buffer_state()); // Read the remaining segment byte_buffer_t retx2; - retx2.N_bytes = rlc1.read_pdu(retx2.msg, 16); // 6 byte header + 10 data + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 18); // 6 byte header + 12 data // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); @@ -867,7 +867,6 @@ bool resegment_test_3() bool resegment_test_4() { - // SDUs: | 10 | 10 | 10 | 10 | 10 | // PDUs: | 5 | 5| 30 | 5 | 5| // Retx PDU segments: | 15 | 15 | @@ -960,9 +959,11 @@ bool resegment_test_4() // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); + assert(23 == rlc1.get_buffer_state()); + // Read the remaining segment byte_buffer_t retx2; - retx2.N_bytes = rlc1.read_pdu(retx2.msg, 21); // 6 byte header + 15 data + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 23); // 6 byte header + 18 data // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); @@ -980,7 +981,6 @@ bool resegment_test_4() bool resegment_test_5() { - // SDUs: | 10 | 10 | 10 | 10 | 10 | // PDUs: |2|3| 40 |3|2| // Retx PDU segments: | 20 | 20 | @@ -1071,9 +1071,11 @@ bool resegment_test_5() // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); + assert(31 == rlc1.get_buffer_state()); + // Read the remaining segment byte_buffer_t retx2; - retx2.N_bytes = rlc1.read_pdu(retx2.msg, 27); // 7 byte header + 20 data + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 34); // 7 byte header + 24 data // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); @@ -1197,11 +1199,11 @@ bool resegment_test_6() // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); - assert(155 == rlc1.get_buffer_state()); + assert(159 == rlc1.get_buffer_state()); // Read the remaining segment byte_buffer_t retx2; - len = rlc1.read_pdu(retx2.msg, 157); + len = rlc1.read_pdu(retx2.msg, 162); retx2.N_bytes = len; // Write the retx PDU to RLC2 @@ -1216,6 +1218,7 @@ bool resegment_test_6() } for(int i=3;i<9;i++) { + if (i >= tester.n_sdus) return -1; if(tester.sdus[i]->N_bytes != 54) return -1; for(int j=0;j<54;j++) { if (tester.sdus[i]->msg[j] != j) return -1; @@ -1256,8 +1259,6 @@ bool resegment_test_7() rlc_am rlc1; rlc_am rlc2; - int len; - log1.set_level(srslte::LOG_LEVEL_DEBUG); log2.set_level(srslte::LOG_LEVEL_DEBUG); @@ -1302,7 +1303,14 @@ bool resegment_test_7() assert(pdu_bufs[i].N_bytes); } - assert(0 == rlc1.get_buffer_state()); + // Step timers until poll_retx timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } + + // RLC should try to retx a random PDU because it needs to request a status from the receiver + assert(0 != rlc1.get_buffer_state()); // Skip PDU with SN 2 for(uint32_t i=0;i -#include +#include #include #include "srslte/common/log_filter.h" #include "srslte/common/logger_stdout.h" @@ -34,10 +34,9 @@ #include "srslte/upper/rlc.h" #include #include -#include +#include #include -#define SDU_SIZE (1500) #define LOG_HEX_LIMIT (-1) using namespace std; @@ -47,6 +46,7 @@ namespace bpo = boost::program_options; typedef struct { std::string mode; + uint32_t sdu_size; uint32_t test_duration_sec; float error_rate; uint32_t sdu_gen_delay_usec; @@ -55,8 +55,10 @@ typedef struct { uint32_t log_level; bool single_tx; bool write_pcap; - float opp_sdu_ratio; + uint32_t avg_opp_size; + bool random_opp; bool zero_seed; + bool pedantic; } stress_test_args_t; void parse_args(stress_test_args_t *args, int argc, char *argv[]) { @@ -73,15 +75,18 @@ void parse_args(stress_test_args_t *args, int argc, char *argv[]) { common.add_options() ("mode", bpo::value(&args->mode)->default_value("AM"), "Whether to test RLC acknowledged or unacknowledged mode (AM/UM)") ("duration", bpo::value(&args->test_duration_sec)->default_value(5), "Duration (sec)") + ("sdu_size", bpo::value(&args->sdu_size)->default_value(1500), "Size of SDUs") + ("avg_opp_size", bpo::value(&args->avg_opp_size)->default_value(1505), "Size of the MAC opportunity (if not random)") + ("random_opp", bpo::value(&args->random_opp)->default_value(true), "Whether to generate random MAC opportunities") ("sdu_gen_delay", bpo::value(&args->sdu_gen_delay_usec)->default_value(0), "SDU generation delay (usec)") ("pdu_tx_delay", bpo::value(&args->pdu_tx_delay_usec)->default_value(0), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)") ("error_rate", bpo::value(&args->error_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped") - ("opp_sdu_ratio", bpo::value(&args->opp_sdu_ratio)->default_value(0.0), "Ratio between MAC opportunity and SDU size (0==random)") ("reestablish", bpo::value(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution") ("loglevel", bpo::value(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug)") ("singletx", bpo::value(&args->single_tx)->default_value(false), "If set to true, only one node is generating data") ("pcap", bpo::value(&args->write_pcap)->default_value(false), "Whether to write all RLC PDU to PCAP file") - ("zeroseed", bpo::value(&args->zero_seed)->default_value(false), "Whether to initialize random seed to zero"); + ("zeroseed", bpo::value(&args->zero_seed)->default_value(false), "Whether to initialize random seed to zero") + ("pedantic", bpo::value(&args->pedantic)->default_value(true), "Whether to perform strict SDU size checking at receiver"); // these options are allowed on the command line bpo::options_description cmdline_options; @@ -93,7 +98,7 @@ void parse_args(stress_test_args_t *args, int argc, char *argv[]) { bpo::notify(vm); // help option was given - print usage and exit - if (vm.count("help")) { + if (vm.count("help") > 0) { cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl; cout << common << endl << general << endl; exit(0); @@ -110,19 +115,17 @@ class mac_dummy ,public thread { public: - mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, float opp_sdu_ratio_, int32_t pdu_tx_delay_usec_, uint32_t lcid_, rlc_pcap* pcap_ = NULL) + mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, stress_test_args_t args_, uint32_t lcid_, rlc_pcap* pcap_ = NULL) :timers(8) ,run_enable(true) ,rlc1(rlc1_) ,rlc2(rlc2_) - ,fail_rate(fail_rate_) - ,opp_sdu_ratio(opp_sdu_ratio_) - ,pdu_tx_delay_usec(pdu_tx_delay_usec_) + ,args(args_) ,pcap(pcap_) ,lcid(lcid_) ,log("MAC ") { - log.set_level(srslte::LOG_LEVEL_ERROR); + log.set_level(static_cast(args.log_level)); log.set_hex_limit(LOG_HEX_LIMIT); } @@ -155,14 +158,19 @@ private: exit(-1); } - float r = opp_sdu_ratio ? opp_sdu_ratio : (float)rand()/RAND_MAX; - int opp_size = r*SDU_SIZE; + float factor = 1.0; + if (args.random_opp) { + factor = 0.5 + static_cast(rand())/RAND_MAX; + } + int opp_size = args.avg_opp_size * factor; uint32_t buf_state = tx_rlc->get_buffer_state(lcid); - if (buf_state) { + if (buf_state > 0) { int read = tx_rlc->read_pdu(lcid, pdu->msg, opp_size); pdu->N_bytes = read; - if (pdu_tx_delay_usec) usleep(pdu_tx_delay_usec); - if(((float)rand()/RAND_MAX > fail_rate) && read>0) { + if (args.pdu_tx_delay_usec > 0) { + usleep(args.pdu_tx_delay_usec); + } + if(((float)rand()/RAND_MAX > args.error_rate) && read>0) { rx_rlc->write_pdu(lcid, pdu->msg, pdu->N_bytes); if (is_dl) { pcap->write_dl_am_ccch(pdu->msg, pdu->N_bytes); @@ -170,7 +178,7 @@ private: pcap->write_ul_am_ccch(pdu->msg, pdu->N_bytes); } } else { - log.info_hex(pdu->msg, pdu->N_bytes, "Dropping RLC PDU (%d B)\n", pdu->N_bytes); + log.warning_hex(pdu->msg, pdu->N_bytes, "Dropping RLC PDU (%d B)\n", pdu->N_bytes); } } byte_buffer_pool::get_instance()->deallocate(pdu); @@ -194,9 +202,7 @@ private: rlc_interface_mac *rlc2; srslte::timers timers; bool run_enable; - float fail_rate; - float opp_sdu_ratio; - uint32_t pdu_tx_delay_usec; + stress_test_args_t args; rlc_pcap *pcap; uint32_t lcid; srslte::log_filter log; @@ -209,13 +215,17 @@ class rlc_tester ,public thread { public: - rlc_tester(rlc_interface_pdcp *rlc_, std::string name_, uint32_t sdu_gen_delay_usec_, uint32_t lcid_){ - rlc = rlc_; - run_enable = true; - rx_pdus = 0; - name = name_; - sdu_gen_delay_usec = sdu_gen_delay_usec_; - lcid = lcid_; + rlc_tester(rlc_interface_pdcp *rlc_, std::string name_, stress_test_args_t args_, uint32_t lcid_) + :log("Testr") + ,rlc(rlc_) + ,run_enable(true) + ,rx_pdus() + ,name(name_) + ,args(args_) + ,lcid(lcid_) + { + log.set_level(srslte::LOG_LEVEL_ERROR); + log.set_hex_limit(LOG_HEX_LIMIT); } void stop() @@ -228,13 +238,14 @@ public: void write_pdu(uint32_t rx_lcid, byte_buffer_t *sdu) { assert(rx_lcid == lcid); - if (sdu->N_bytes != SDU_SIZE) { - srslte::log_filter log1("Testr");; - log1.set_level(srslte::LOG_LEVEL_ERROR); - log1.set_hex_limit(sdu->N_bytes); - log1.error_hex(sdu->msg, sdu->N_bytes, "Received PDU with size %d, expected %d. Exiting.\n", sdu->N_bytes, SDU_SIZE); - exit(-1); + if (sdu->N_bytes != args.sdu_size) { + log.error_hex(sdu->msg, sdu->N_bytes, "Received SDU with size %d, expected %d.\n", sdu->N_bytes, args.sdu_size); + // exit if in pedantic mode or SDU is not a multiple of the expected size + if (args.pedantic || sdu->N_bytes % args.sdu_size != 0) { + exit(-1); + } } + byte_buffer_pool::get_instance()->deallocate(sdu); rx_pdus++; } @@ -254,29 +265,32 @@ private: uint8_t sn = 0; while(run_enable) { byte_buffer_t *pdu = byte_buffer_pool::get_instance()->allocate("rlc_tester::run_thread"); - if (!pdu) { + if (pdu == NULL) { printf("Error: Could not allocate PDU in rlc_tester::run_thread\n\n\n"); // backoff for a bit usleep(1000); continue; } - for (uint32_t i = 0; i < SDU_SIZE; i++) { + for (uint32_t i = 0; i < args.sdu_size; i++) { pdu->msg[i] = sn; } sn++; - pdu->N_bytes = SDU_SIZE; + pdu->N_bytes = args.sdu_size; rlc->write_sdu(lcid, pdu); - if (sdu_gen_delay_usec) usleep(sdu_gen_delay_usec); + if (args.sdu_gen_delay_usec > 0) { + usleep(args.sdu_gen_delay_usec); + } } } bool run_enable; - long rx_pdus; + uint64_t rx_pdus; uint32_t lcid; + srslte::log_filter log; std::string name; - uint32_t sdu_gen_delay_usec; + stress_test_args_t args; rlc_interface_pdcp *rlc; }; @@ -285,8 +299,8 @@ void stress_test(stress_test_args_t args) { srslte::log_filter log1("RLC_1"); srslte::log_filter log2("RLC_2"); - log1.set_level((LOG_LEVEL_ENUM)args.log_level); - log2.set_level((LOG_LEVEL_ENUM)args.log_level); + log1.set_level(static_cast(args.log_level)); + log2.set_level(static_cast(args.log_level)); log1.set_hex_limit(LOG_HEX_LIMIT); log2.set_hex_limit(LOG_HEX_LIMIT); rlc_pcap pcap; @@ -326,9 +340,9 @@ void stress_test(stress_test_args_t args) rlc rlc1; rlc rlc2; - rlc_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec, lcid); - rlc_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec, lcid); - mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.opp_sdu_ratio, args.pdu_tx_delay_usec, lcid, &pcap); + rlc_tester tester1(&rlc1, "tester1", args, lcid); + rlc_tester tester2(&rlc2, "tester2", args, lcid); + mac_dummy mac(&rlc1, &rlc2, args, lcid, &pcap); ue_interface ue; rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0); @@ -346,6 +360,10 @@ void stress_test(stress_test_args_t args) } mac.start(); + if (args.test_duration_sec < 1) { + args.test_duration_sec = 1; + } + for (uint32_t i = 0; i < args.test_duration_sec; i++) { // if enabled, mimic reestablishment every second if (args.reestablish) { @@ -355,39 +373,47 @@ void stress_test(stress_test_args_t args) usleep(1e6); } + printf("Test finished, tearing down ..\n"); + // Stop RLC instances first to release blocking writers rlc1.stop(); rlc2.stop(); + printf("RLC entities stopped.\n"); + + // Stop upper layer writers tester1.stop(); tester2.stop(); + + printf("Writers stopped.\n"); + mac.stop(); if (args.write_pcap) { pcap.close(); } - rlc_metrics_t metrics; + rlc_metrics_t metrics = {}; rlc1.get_metrics(metrics); - printf("RLC1 received %d SDUs in %ds (%.2f PDU/s), Throughput: DL=%4.2f Mbps, UL=%4.2f Mbps\n", + printf("RLC1 received %d SDUs in %ds (%.2f/s), Throughput: DL=%4.2f Mbps, UL=%4.2f Mbps\n", tester1.get_nof_rx_pdus(), args.test_duration_sec, - (float)tester1.get_nof_rx_pdus()/args.test_duration_sec, + static_cast(tester1.get_nof_rx_pdus()/args.test_duration_sec), metrics.dl_tput_mbps[lcid], metrics.ul_tput_mbps[lcid]); rlc2.get_metrics(metrics); - printf("RLC2 received %d SDUs in %ds (%.2f PDU/s), Throughput: DL=%4.2f Mbps, UL=%4.2f Mbps\n", + printf("RLC2 received %d SDUs in %ds (%.2f/s), Throughput: DL=%4.2f Mbps, UL=%4.2f Mbps\n", tester2.get_nof_rx_pdus(), args.test_duration_sec, - (float)tester2.get_nof_rx_pdus()/args.test_duration_sec, + static_cast(tester2.get_nof_rx_pdus()/args.test_duration_sec), metrics.dl_tput_mbps[lcid], metrics.ul_tput_mbps[lcid]); } int main(int argc, char **argv) { - stress_test_args_t args; + stress_test_args_t args = {}; parse_args(&args, argc, argv); if (args.zero_seed) { diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 53e43e799..67b83afb5 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -162,21 +162,3 @@ nof_ctrl_symbols = 3 #rrc_inactivity_timer = 60000 #max_prach_offset_us = 30 #enable_mbsfn = false - -##################################################################### -# Manual RF calibration -# -# Applies DC offset and IQ imbalance to TX and RX modules. -# Currently this configuration is only used if the detected device is a bladeRF -# -# tx_corr_dc_gain: TX DC offset gain correction -# tx_corr_dc_phase: TX DC offset phase correction -# tx_corr_iq_i: TX IQ imbalance inphase correction -# tx_corr_iq_q: TX IQ imbalance quadrature correction -# same can be configured for rx_* -##################################################################### -[rf_calibration] -tx_corr_dc_gain = 20 -tx_corr_dc_phase = 184 -tx_corr_iq_i = 19 -tx_corr_iq_q = 97 diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index 08f75bc1e..2f00f5f62 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -134,7 +134,6 @@ typedef struct { enb_args_t enb; enb_files_t enb_files; rf_args_t rf; - rf_cal_t rf_cal; pcap_args_t pcap; log_args_t log; gui_args_t gui; @@ -142,7 +141,7 @@ typedef struct { }all_args_t; /******************************************************************************* - Main UE class + Main eNB class *******************************************************************************/ class enb @@ -213,7 +212,7 @@ private: bool check_srslte_version(); int parse_sib1(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *data); - int parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *data); + int parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *data, bool *mbsfn_section_present); int parse_sib3(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *data); int parse_sib4(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data); int parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *data); @@ -222,7 +221,11 @@ private: int parse_rr(all_args_t *args, rrc_cfg_t *rrc_cfg); int parse_drb(all_args_t *args, rrc_cfg_t *rrc_cfg); bool sib_is_present(LIBLTE_RRC_SCHEDULING_INFO_STRUCT *sched_info, uint32_t nof_sched_info, LIBLTE_RRC_SIB_TYPE_ENUM sib_num); - int parse_cell_cfg(all_args_t *args, srslte_cell_t *cell); + int parse_cell_cfg(all_args_t *args, srslte_cell_t *cell); + + std::string get_build_mode(); + std::string get_build_info(); + std::string get_build_string(); }; } // namespace srsenb diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index d20079135..c1221b2ae 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -83,9 +83,9 @@ private: const static int MAX_WORKERS = 4; const static int DEFAULT_WORKERS = 2; - const static int PRACH_WORKER_THREAD_PRIO = 80; + const static int PRACH_WORKER_THREAD_PRIO = 3; const static int SF_RECV_THREAD_PRIO = 1; - const static int WORKERS_THREAD_PRIO = 0; + const static int WORKERS_THREAD_PRIO = 2; srslte::radio *radio_handler; srslte::log *log_h; diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index c640df197..8a57f6e09 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -182,39 +182,39 @@ public: bool running; void run_thread(); }; - + class ue { - public: - ue(); + public: + ue(); bool is_connected(); - bool is_idle(); + bool is_idle(); bool is_timeout(); void set_activity(); uint32_t rl_failure(); rrc_state_t get_state(); - + void send_connection_setup(bool is_setup = true); - void send_connection_reest(); + void send_connection_reest(); void send_connection_release(); - void send_connection_reest_rej(); + void send_connection_reest_rej(); void send_connection_reconf(srslte::byte_buffer_t *sdu); void send_connection_reconf_new_bearer(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); - void send_connection_reconf_upd(srslte::byte_buffer_t *pdu); + void send_connection_reconf_upd(srslte::byte_buffer_t *pdu); void send_security_mode_command(); void send_ue_cap_enquiry(); void parse_ul_dcch(uint32_t lcid, srslte::byte_buffer_t* pdu); void handle_rrc_con_req(LIBLTE_RRC_CONNECTION_REQUEST_STRUCT *msg); - void handle_rrc_con_reest_req(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *msg); + void handle_rrc_con_reest_req(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_REQUEST_STRUCT *msg); void handle_rrc_con_setup_complete(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE_STRUCT *msg, srslte::byte_buffer_t *pdu); void handle_rrc_reconf_complete(LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *msg, srslte::byte_buffer_t *pdu); void handle_security_mode_complete(LIBLTE_RRC_SECURITY_MODE_COMPLETE_STRUCT *msg); void handle_security_mode_failure(LIBLTE_RRC_SECURITY_MODE_FAILURE_STRUCT *msg); void handle_ue_cap_info(LIBLTE_RRC_UE_CAPABILITY_INFORMATION_STRUCT *msg); - + void set_bitrates(LIBLTE_S1AP_UEAGGREGATEMAXIMUMBITRATE_STRUCT *rates); void set_security_capabilities(LIBLTE_S1AP_UESECURITYCAPABILITIES_STRUCT *caps); void set_security_key(uint8_t* key, uint32_t length); @@ -229,26 +229,26 @@ public: void notify_s1ap_ue_ctxt_setup_complete(); void notify_s1ap_ue_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); - int sr_allocate(uint32_t period, uint32_t *I_sr, uint32_t *N_pucch_sr); - void sr_get(uint32_t *I_sr, uint32_t *N_pucch_sr); + int sr_allocate(uint32_t period, uint32_t *I_sr, uint32_t *N_pucch_sr); + void sr_get(uint32_t *I_sr, uint32_t *N_pucch_sr); int sr_free(); - int cqi_allocate(uint32_t period, uint32_t *pmi_idx, uint32_t *n_pucch); - void cqi_get(uint32_t *pmi_idx, uint32_t *n_pucch); - int cqi_free(); - + int cqi_allocate(uint32_t period, uint32_t *pmi_idx, uint32_t *n_pucch); + void cqi_get(uint32_t *pmi_idx, uint32_t *n_pucch); + int cqi_free(); + void send_dl_ccch(LIBLTE_RRC_DL_CCCH_MSG_STRUCT *dl_ccch_msg); void send_dl_dcch(LIBLTE_RRC_DL_DCCH_MSG_STRUCT *dl_dcch_msg, srslte::byte_buffer_t *pdu = NULL); - - uint16_t rnti; - rrc *parent; - - bool connect_notified; - + + uint16_t rnti; + rrc *parent; + + bool connect_notified; + private: srslte::byte_buffer_pool *pool; - struct timeval t_last_activity; + struct timeval t_last_activity; LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM establishment_cause; @@ -260,10 +260,10 @@ public: uint32_t rlf_cnt; uint8_t transaction_id; rrc_state_t state; - + std::map srbs; std::map drbs; - + uint8_t k_enb[32]; // Provided by MME uint8_t k_rrc_enc[32]; uint8_t k_rrc_int[32]; @@ -290,20 +290,21 @@ public: bool sr_allocated; uint32_t sr_N_pucch; uint32_t sr_I; - uint32_t cqi_pucch; - uint32_t cqi_idx; - bool cqi_allocated; - int cqi_sched_sf_idx; + uint32_t cqi_pucch; + uint32_t cqi_idx; + bool cqi_allocated; + int cqi_sched_sf_idx; int cqi_sched_prb_idx; int get_drbid_config(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb, int drbid); + bool nas_pending; srslte::byte_buffer_t erab_info; - }; - - -private: - + }; + + +private: + std::map users; - + std::map pending_paging; activity_monitor act_monitor; @@ -362,7 +363,8 @@ private: typedef struct { uint32_t nof_users[100][80]; } sr_sched_t; - + + sr_sched_t sr_sched; sr_sched_t cqi_sched; LIBLTE_RRC_MCCH_MSG_STRUCT mcch; diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index dded32c7c..80b2894f6 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -111,17 +111,6 @@ sib2 = additional_spectrum_emission = 1; }; - mbsfnSubframeConfigList = - { - radioframeAllocationPeriod = "1"; - subframeAllocationNumFrames = "1"; - radioframeAllocationOffset = 0; - subframeAllocation = 63; - - }; - - mbsfnSubframeConfigListLength = 0; - time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc. }; diff --git a/srsenb/sib.conf.mbsfn.example b/srsenb/sib.conf.mbsfn.example index 3fe2ddc11..588ba71d1 100644 --- a/srsenb/sib.conf.mbsfn.example +++ b/srsenb/sib.conf.mbsfn.example @@ -46,8 +46,8 @@ sib2 = { high_speed_flag = false; prach_config_index = 3; - prach_freq_offset = 0; - zero_correlation_zone_config = 11; + prach_freq_offset = 2; + zero_correlation_zone_config = 5; }; }; pdsch_cnfg = @@ -111,8 +111,6 @@ sib2 = additional_spectrum_emission = 1; }; - - mbsfnSubframeConfigList = { radioframeAllocationPeriod = "1"; @@ -122,8 +120,6 @@ sib2 = }; - mbsfnSubframeConfigListLength = 1; - time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc. }; diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 911fb1d48..23cd63882 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -26,6 +26,9 @@ #include #include "srsenb/hdr/enb.h" +#include "srslte/build_info.h" +#include +#include namespace srsenb { @@ -54,6 +57,9 @@ void enb::cleanup(void) } enb::enb() : started(false) { + // print build info + std::cout << std::endl << get_build_string() << std::endl; + srslte_dft_load(); pool = srslte::byte_buffer_pool::get_instance(ENB_POOL_SIZE); @@ -159,8 +165,6 @@ bool enb::init(all_args_t *args_) if (args->rf.burst_preamble.compare("auto")) { radio.set_burst_preamble(atof(args->rf.burst_preamble.c_str())); } - - radio.set_manual_calibration(&args->rf_cal); radio.set_rx_gain(args->rf.rx_gain); radio.set_tx_gain(args->rf.tx_gain); @@ -342,4 +346,24 @@ srslte::LOG_LEVEL_ENUM enb::level(std::string l) } } +std::string enb::get_build_mode() +{ + return std::string(srslte_get_build_mode()); +} + +std::string enb::get_build_info() +{ + if (std::string(srslte_get_build_info()) == "") { + return std::string(srslte_get_version()); + } + return std::string(srslte_get_build_info()); +} + +std::string enb::get_build_string() +{ + std::stringstream ss; + ss << "Built in " << get_build_mode() << " mode using " << get_build_info() << "." << std::endl; + return ss.str(); +} + } // namespace srsenb diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 0e4771e9f..3ddb3d9f7 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -201,7 +201,7 @@ int enb::parse_sib1(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUC return parser::parse_section(filename, &sib1); } -int enb::parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *data) +int enb::parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *data, bool *mbsfn_section_present) { parser::section sib2("sib2"); @@ -214,12 +214,7 @@ int enb::parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUC parser::section mbsfnSubframeConfigList("mbsfnSubframeConfigList"); sib2.add_subsection(&mbsfnSubframeConfigList); - bool mbsfn_present=false; - mbsfnSubframeConfigList.set_optional(&mbsfn_present); - - if (mbsfn_present) { - data->mbsfn_subfr_cnfg_list_size = 1; - } + mbsfnSubframeConfigList.set_optional(mbsfn_section_present); mbsfnSubframeConfigList.add_field( new parser::field @@ -876,11 +871,12 @@ int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_ // Generate SIB2 bzero(sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); - if (parse_sib2(args->enb_files.sib_config, sib2)) { + bool mbsfn_section_present = false; + if (parse_sib2(args->enb_files.sib_config, sib2, &mbsfn_section_present)) { return -1; } - // SRS not yet supported + // SRS not yet supported sib2->rr_config_common_sib.srs_ul_cnfg.present = false; if (sib2->ul_bw.present) { switch(args->enb.n_prb) { @@ -907,8 +903,13 @@ int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_ if (sib2->arfcn_value_eutra.present) { sib2->arfcn_value_eutra.value = args->rf.ul_earfcn; } - - // Generate SIB3 if defined in mapping info + + // Update MBSFN list counter. Only 1 supported + if (mbsfn_section_present && args->expert.enable_mbsfn) { + sib2->mbsfn_subfr_cnfg_list_size = 1; + } + + // Generate SIB3 if defined in mapping info if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_3)) { bzero(sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT)); if (parse_sib3(args->enb_files.sib_config, sib3)) { diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 941a6fff9..d36cf7ef8 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -199,12 +199,6 @@ void parse_args(all_args_t *args, int argc, char* argv[]) { ("expert.print_buffer_state", bpo::value(&args->expert.print_buffer_state)->default_value(false), "Prints on the console the buffer state every 10 seconds") - - ("rf_calibration.tx_corr_dc_gain", bpo::value(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0), "TX DC offset gain correction") - ("rf_calibration.tx_corr_dc_phase", bpo::value(&args->rf_cal.tx_corr_dc_phase)->default_value(0.0), "TX DC offset phase correction") - ("rf_calibration.tx_corr_iq_i", bpo::value(&args->rf_cal.tx_corr_iq_i)->default_value(0.0), "TX IQ imbalance inphase correction") - ("rf_calibration.tx_corr_iq_q", bpo::value(&args->rf_cal.tx_corr_iq_q)->default_value(0.0), "TX IQ imbalance quadrature correction") - ; // Positional options - config file location diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 269e5dcaf..eae78d4bd 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -885,24 +885,25 @@ void rrc::activity_monitor::run_thread() *******************************************************************************/ rrc::ue::ue() { - parent = NULL; + parent = NULL; set_activity(); - has_tmsi = false; - connect_notified = false; - transaction_id = 0; - sr_allocated = false; - sr_sched_sf_idx = 0; - sr_sched_prb_idx = 0; - sr_N_pucch = 0; - sr_I = 0; - cqi_allocated = false; - cqi_pucch = 0; - cqi_idx = 0; - cqi_sched_sf_idx = 0; + has_tmsi = false; + connect_notified = false; + transaction_id = 0; + sr_allocated = false; + sr_sched_sf_idx = 0; + sr_sched_prb_idx = 0; + sr_N_pucch = 0; + sr_I = 0; + cqi_allocated = false; + cqi_pucch = 0; + cqi_idx = 0; + cqi_sched_sf_idx = 0; cqi_sched_prb_idx = 0; - rlf_cnt = 0; - state = RRC_STATE_IDLE; - pool = srslte::byte_buffer_pool::get_instance(); + rlf_cnt = 0; + nas_pending = false; + state = RRC_STATE_IDLE; + pool = srslte::byte_buffer_pool::get_instance(); } rrc_state_t rrc::ue::get_state() @@ -1227,9 +1228,12 @@ void rrc::ue::setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT parent->gtpu->add_bearer(rnti, lcid, addr_, erabs[id].teid_out, &(erabs[id].teid_in)); if(nas_pdu) { + nas_pending = true; memcpy(erab_info.buffer, nas_pdu->buffer, nas_pdu->n_octets); erab_info.N_bytes = nas_pdu->n_octets; parent->rrc_log->info_hex(erab_info.buffer, erab_info.N_bytes, "setup_erab nas_pdu -> erab_info rnti 0x%x", rnti); + } else { + nas_pending = false; } } @@ -1666,18 +1670,23 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu) // DRB1 has already been configured in GTPU through bearer setup - // Add NAS Attach accept - conn_reconf->N_ded_info_nas = 1; + // Add NAS Attach accept + if(nas_pending){ + parent->rrc_log->debug("Adding NAS message to connection reconfiguration\n"); + conn_reconf->N_ded_info_nas = 1; - parent->rrc_log->info_hex(erab_info.buffer, erab_info.N_bytes, "connection_reconf erab_info -> nas_info rnti 0x%x\n", rnti); - conn_reconf->ded_info_nas_list[0].N_bytes = erab_info.N_bytes; - memcpy(conn_reconf->ded_info_nas_list[0].msg, erab_info.buffer, erab_info.N_bytes); - + parent->rrc_log->info_hex(erab_info.buffer, erab_info.N_bytes, "connection_reconf erab_info -> nas_info rnti 0x%x\n", rnti); + conn_reconf->ded_info_nas_list[0].N_bytes = erab_info.N_bytes; + memcpy(conn_reconf->ded_info_nas_list[0].msg, erab_info.buffer, erab_info.N_bytes); + } else { + parent->rrc_log->debug("Not adding NAS message to connection reconfiguration\n"); + conn_reconf->N_ded_info_nas = 0; + } // Reuse same PDU pdu->reset(); - + send_dl_dcch(&dl_dcch_msg, pdu); - + state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; } diff --git a/srsenb/test/upper/plmn_test.cc b/srsenb/test/upper/plmn_test.cc index 2f27febc3..448931129 100644 --- a/srsenb/test/upper/plmn_test.cc +++ b/srsenb/test/upper/plmn_test.cc @@ -65,7 +65,7 @@ void s1ap_plmn_test() // 3-digit MNC test mnc = 0xF456; srslte::s1ap_mccmnc_to_plmn(mcc, mnc, &plmn); - assert(plmn == 0x216354); + assert(plmn == 0x214365); srslte::s1ap_plmn_to_mccmnc(plmn, &mcc, &mnc); assert(mcc == 0xF123); assert(mnc == 0xF456); diff --git a/srsepc/src/main.cc b/srsepc/src/main.cc index 95883cd44..984f81dd6 100644 --- a/srsepc/src/main.cc +++ b/srsepc/src/main.cc @@ -22,6 +22,7 @@ * */ #include +#include #include #include #include @@ -30,6 +31,7 @@ #include "srslte/common/crash_handler.h" #include "srslte/common/bcd_helpers.h" #include "srslte/common/config_file.h" +#include "srslte/build_info.h" #include "srsepc/hdr/mme/mme.h" #include "srsepc/hdr/hss/hss.h" #include "srsepc/hdr/spgw/spgw.h" @@ -280,6 +282,26 @@ level(std::string l) } } +std::string get_build_mode() +{ + return std::string(srslte_get_build_mode()); +} + +std::string get_build_info() +{ + if (std::string(srslte_get_build_info()) == "") { + return std::string(srslte_get_version()); + } + return std::string(srslte_get_build_info()); +} + +std::string get_build_string() +{ + std::stringstream ss; + ss << "Built in " << get_build_mode() << " mode using " << get_build_info() << "." << std::endl; + return ss.str(); +} + int main (int argc,char * argv[] ) { @@ -287,6 +309,9 @@ main (int argc,char * argv[] ) signal(SIGTERM, sig_int_handler); signal(SIGKILL, sig_int_handler); + // print build info + cout << endl << get_build_string() << endl; + cout << endl <<"--- Software Radio Systems EPC ---" << endl << endl; srslte_debug_handle_crash(argc, argv); diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index fa3ed2fee..04599c11a 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -159,7 +159,7 @@ private: const static int DEFAULT_WORKERS = 2; const static int SF_RECV_THREAD_PRIO = 1; - const static int WORKERS_THREAD_PRIO = 0; + const static int WORKERS_THREAD_PRIO = 2; srslte::radio_multi *radio_handler; std::vector log_vec; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index 6e4853dfd..0f362160a 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -122,7 +122,6 @@ typedef struct { typedef struct { rf_args_t rf; - rf_cal_t rf_cal; pcap_args_t pcap; trace_args_t trace; log_args_t log; diff --git a/srsue/src/mac/proc_bsr.cc b/srsue/src/mac/proc_bsr.cc index bd49671df..1026bf2f1 100644 --- a/srsue/src/mac/proc_bsr.cc +++ b/srsue/src/mac/proc_bsr.cc @@ -41,8 +41,15 @@ bsr_proc::bsr_proc() initiated = false; last_print = 0; next_tx_tti = 0; - triggered_bsr_type=NONE; - + triggered_bsr_type=NONE; + + for (int i=0;i(&args->nas.apn_pass)->default_value(""), "Password for CHAP authentication") ("nas.force_imsi_attach", bpo::value(&args->nas.force_imsi_attach)->default_value(false), "Whether to always perform an IMSI attach") - ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") ("pcap.nas_enable", bpo::value(&args->pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark") ("pcap.nas_filename", bpo::value(&args->pcap.nas_filename)->default_value("ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)") - ("trace.enable", bpo::value(&args->trace.enable)->default_value(false), "Enable PHY and radio timing traces") ("trace.phy_filename", bpo::value(&args->trace.phy_filename)->default_value("ue.phy_trace"), "PHY timing traces filename") @@ -123,7 +121,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("log.usim_level", bpo::value(&args->log.usim_level), "USIM log level") ("log.usim_hex_limit", bpo::value(&args->log.usim_hex_limit), "USIM log hex dump limit") - ("log.all_level", bpo::value(&args->log.all_level)->default_value("info"), "ALL log level") ("log.all_hex_limit", bpo::value(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit") @@ -309,16 +306,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("expert.pdsch_8bit_decoder", bpo::value(&args->expert.phy.pdsch_8bit_decoder)->default_value(false), - "Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)") - - ("rf_calibration.tx_corr_dc_gain", bpo::value(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0), - "TX DC offset gain correction") - ("rf_calibration.tx_corr_dc_phase", bpo::value(&args->rf_cal.tx_corr_dc_phase)->default_value(0.0), - "TX DC offset phase correction") - ("rf_calibration.tx_corr_iq_i", bpo::value(&args->rf_cal.tx_corr_iq_i)->default_value(0.0), - "TX IQ imbalance inphase correction") - ("rf_calibration.tx_corr_iq_q", bpo::value(&args->rf_cal.tx_corr_iq_q)->default_value(0.0), - "TX IQ imbalance quadrature correction"); + "Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)"); // Positional options - config file location bpo::options_description position("Positional options"); diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 0fbd9e221..3cac3509c 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -53,6 +53,7 @@ phch_recv::phch_recv() { ul_freq = -1; bzero(&cell, sizeof(srslte_cell_t)); bzero(&metrics, sizeof(sync_metrics_t)); + cellsearch_earfcn_index = 0; running = false; worker_com = NULL; } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 178a803ae..53ca93273 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -61,6 +61,7 @@ phch_worker::phch_worker() : tr_exec(10240) chest_loop = NULL; bzero(signal_buffer, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + ZERO_OBJECT(cell); mem_initiated = false; cell_initiated = false; @@ -1268,6 +1269,22 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui char timestr[64]; timestr[0]='\0'; + /* Check input values ranges */ + if (rnti == 0) { + Warning("Encode PUSCH: Invalid RNTI (= 0)\n"); + return; + } else if (rv > 3) { + Warning("Encode PUSCH: Invalid RV (= %ud)\n", rv); + return; + } else if (payload == NULL) { + Warning("Encode PUSCH: NULL payload\n"); + return; + } else if (softbuffer == NULL) { + Warning("Encode PUSCH: NULL softbuffer\n"); + return; + } + + /* Configure and encode */ if (srslte_ue_ul_cfg_grant(&ue_ul, grant, TTI_TX(tti), rv, current_tx_nb)) { Error("Configuring UL grant\n"); } diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index daccfca8b..2a6b05425 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -193,10 +193,7 @@ bool ue::init(all_args_t *args_) { radio.set_continuous_tx(args->rf.continuous_tx.compare("yes")?false:true); } - radio.set_manual_calibration(&args->rf_cal); - // Set PHY options - if (args->rf.tx_gain > 0) { args->expert.phy.ul_pwr_ctrl_en = false; } else { diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 197dd4367..b7fb0caaf 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -308,30 +308,31 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { uint8 pd = 0; uint8 msg_type = 0; uint8 sec_hdr_type = 0; - bool mac_valid = false; nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rrc->get_rb_name(lcid).c_str()); // Parse the message security header liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &sec_hdr_type); - switch(sec_hdr_type) + switch (sec_hdr_type) { case LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS: case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT: case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST: + break; case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY: - break; case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED: - if((mac_valid = integrity_check(pdu))) { + if((integrity_check(pdu))) { + if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED) { cipher_decrypt(pdu); - break; - } else { - nas_log->error("Not handling NAS message with integrity check error\n"); - pool->deallocate(pdu); - return; } - case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT: break; + } else { + nas_log->error("Not handling NAS message with integrity check error\n"); + pool->deallocate(pdu); + return; + } + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT: + break; default: nas_log->error("Not handling NAS message with SEC_HDR_TYPE=%02X\n", sec_hdr_type); pool->deallocate(pdu); diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index 38a7f6ca3..101d403fc 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -51,7 +51,7 @@ uint8_t auth_request_pdu[] = { 0x07, 0x52, 0x01, 0x0c, 0x63, 0xa8, 0x54, 0x13, 0 uint8_t sec_mode_command_pdu[] = { 0x37, 0x37, 0xc7, 0x67, 0xae, 0x00, 0x07, 0x5d, 0x02, 0x01, 0x02, 0xe0, 0x60, 0xc1 }; -uint8_t attach_accept_pdu[] = { 0x27, 0x0f, 0x4f, 0xb3, 0xef, 0x01, 0x07, 0x42, 0x01, 0x3e, +uint8_t attach_accept_pdu[] = { 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x42, 0x01, 0x3e, 0x06, 0x00, 0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x2a, 0x52, 0x01, 0xc1, 0x01, 0x04, 0x1b, 0x07, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33, 0x06, 0x6d, 0x6e, 0x63, 0x30, 0x30, 0x31, @@ -60,7 +60,7 @@ uint8_t attach_accept_pdu[] = { 0x27, 0x0f, 0x4f, 0xb3, 0xef, 0x01, 0x07, 0x42, 0x80, 0x50, 0x0b, 0xf6, 0x00, 0xf1, 0x10, 0x80, 0x01, 0x01, 0x35, 0x16, 0x6d, 0xbc, 0x64, 0x01, 0x00 }; -uint8_t esm_info_req_pdu[] = { 0x27, 0x1d, 0xbf, 0x7e, 0x05, 0x01, 0x02, 0x5a, 0xd9 }; +uint8_t esm_info_req_pdu[] = { 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x5a, 0xd9 }; uint16 mcc = 61441; uint16 mnc = 65281; @@ -98,6 +98,7 @@ public: } std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); } uint32_t get_last_sdu_len() { return last_sdu_len; } + void reset() { last_sdu_len = 0; } int plmn_search(srsue::rrc_interface_nas::found_plmn_t* found) { memcpy(found, &plmns, sizeof(found_plmn_t)); @@ -164,6 +165,7 @@ int security_command_test() srsue::nas nas; srslte_nas_config_t cfg; + ZERO_OBJECT(cfg); nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg); // push auth request PDU to NAS to generate security context @@ -218,6 +220,8 @@ int mme_attach_request_test() usim.init(&args, &usim_log); srslte_nas_config_t nas_cfg; + ZERO_OBJECT(nas_cfg); + nas_cfg.force_imsi_attach = true; nas_cfg.apn = "test123"; srsue::nas nas; nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg); @@ -226,6 +230,9 @@ int mme_attach_request_test() // this will time out in the first place + // reset length of last received NAS PDU + rrc_dummy.reset(); + // finally push attach accept byte_buffer_t* tmp = byte_buffer_pool::get_instance()->allocate(); memcpy(tmp->msg, attach_accept_pdu, sizeof(attach_accept_pdu)); @@ -278,9 +285,11 @@ int esm_info_request_test() srsue::nas nas; srslte_nas_config_t cfg; + ZERO_OBJECT(cfg); cfg.apn = "srslte"; cfg.user = "srsuser"; cfg.pass = "srspass"; + cfg.force_imsi_attach = true; nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg); // push ESM info request PDU to NAS to generate response diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 4073ad96f..d2bc4bb12 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -16,7 +16,7 @@ # device_args: Arguments for the device driver. Options are "auto" or any string. # Default for UHD: "recv_frame_size=9232,send_frame_size=9232" # Default for bladeRF: "" -# #time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay +# time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay # from antenna to timestamp insertion. # Default "auto". B210 USRP: 100 samples, bladeRF: 27. # burst_preamble_us: Preamble length to transmit before start of burst. @@ -249,21 +249,3 @@ enable = false #cfo_loop_pss_tol = 400 #cfo_loop_ref_min = 0 #cfo_loop_pss_conv = 20 - -##################################################################### -# Manual RF calibration -# -# Applies DC offset and IQ imbalance to TX and RX modules. -# Currently this configuration is only used if the detected device is a bladeRF -# -# tx_corr_dc_gain: TX DC offset gain correction -# tx_corr_dc_phase: TX DC offset phase correction -# tx_corr_iq_i: TX IQ imbalance inphase correction -# tx_corr_iq_q: TX IQ imbalance quadrature correction -# same can be configured for rx_* -##################################################################### -[rf_calibration] -tx_corr_dc_gain = 20 -tx_corr_dc_phase = 184 -tx_corr_iq_i = 19 -tx_corr_iq_q = 97