mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'next' into nas_cleanup
This commit is contained in:
commit
23836a8ab3
10
CHANGELOG
10
CHANGELOG
|
@ -1,6 +1,16 @@
|
|||
Change Log for Releases
|
||||
==============================
|
||||
|
||||
## 18.09
|
||||
* Improved Turbo Decoder performance
|
||||
* Configurable SGi interface name and M1U params
|
||||
* Support for GPTU echo mechanism
|
||||
* Added UE detach capability
|
||||
* Refactor RLC/PDCP classes
|
||||
* Various fixes for ARM-based devices
|
||||
* Added support for bladeRF 2.0 micro
|
||||
* Many bug-fixes and improved stability and performance in all parts
|
||||
|
||||
## 18.06.1
|
||||
* Fixed RLC reestablish
|
||||
* Fixed aperiodic QCI retx
|
||||
|
|
|
@ -15,8 +15,14 @@ if(NOT BLADERF_FOUND)
|
|||
)
|
||||
|
||||
if(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES)
|
||||
set(BLADERF_FOUND TRUE CACHE INTERNAL "libbladeRF found")
|
||||
message(STATUS "Found libbladeRF: ${BLADERF_INCLUDE_DIRS}, ${BLADERF_LIBRARIES}")
|
||||
CHECK_LIBRARY_EXISTS(bladeRF bladerf_get_board_name BLADERF_LIBRARIES BLADERF_VERSION_OK)
|
||||
if (BLADERF_VERSION_OK)
|
||||
set(BLADERF_FOUND TRUE CACHE INTERNAL "libbladeRF found")
|
||||
message(STATUS "Found libbladeRF: ${BLADERF_INCLUDE_DIRS}, ${BLADERF_LIBRARIES}")
|
||||
else (BLADERF_VERSION_OK)
|
||||
set(BLADERF_FOUND FALSE CACHE INTERNAL "libbladeRF found")
|
||||
message(STATUS "libbladeRF found but not compatible. Upgrade your driver or use SoapySDR.")
|
||||
endif (BLADERF_VERSION_OK)
|
||||
else(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES)
|
||||
set(BLADERF_FOUND FALSE CACHE INTERNAL "libbladeRF found")
|
||||
message(STATUS "libbladeRF not found.")
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
#
|
||||
|
||||
SET(SRSLTE_VERSION_MAJOR 18)
|
||||
SET(SRSLTE_VERSION_MINOR 6)
|
||||
SET(SRSLTE_VERSION_PATCH 1)
|
||||
SET(SRSLTE_VERSION_MINOR 9)
|
||||
SET(SRSLTE_VERSION_PATCH 0)
|
||||
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
srslte (18.09-0ubuntu1) bionic; urgency=medium
|
||||
|
||||
* Update to srsLTE 18.09
|
||||
|
||||
-- Andre Puschmann <andre@softwareradiosystems.com> Wed, 15 Oct 2018 10:05:00 +0200
|
||||
|
||||
srslte (18.06.1-0ubuntu1) bionic; urgency=medium
|
||||
|
||||
* Update to srsLTE 18.06.1
|
||||
|
|
|
@ -105,7 +105,7 @@ typedef struct{
|
|||
uint32 N_bits;
|
||||
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
|
||||
uint8 msg[LIBLTE_MAX_MSG_SIZE_BITS];
|
||||
}LIBLTE_BIT_MSG_STRUCT;
|
||||
}LIBLTE_BIT_MSG_STRUCT __attribute__ ((aligned (8)));
|
||||
|
||||
typedef struct{
|
||||
uint32 N_bytes;
|
||||
|
|
|
@ -108,8 +108,7 @@ public:
|
|||
}
|
||||
|
||||
myobj wait_pop() { // blocking pop
|
||||
myobj value;
|
||||
bzero(&value, sizeof(myobj));
|
||||
myobj value = 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);
|
||||
|
|
|
@ -204,9 +204,17 @@ public:
|
|||
b->reset();
|
||||
if (!pool->deallocate(b)) {
|
||||
if (log) {
|
||||
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
log->error("Deallocating PDU: Addr=0x%lx, name=%s not found in pool\n", (uint64_t) b, b->debug_name);
|
||||
#else
|
||||
log->error("Deallocating PDU: Addr=0x%lx\n", (uint64_t) b);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
printf("Error deallocating PDU: Addr=0x%lx, name=%s not found in pool\n", (uint64_t) b, b->debug_name);
|
||||
#else
|
||||
printf("Error deallocating PDU: Addr=0x%lx\n", (uint64_t) b);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
b = NULL;
|
||||
|
|
|
@ -59,13 +59,13 @@
|
|||
|
||||
#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
|
||||
//#define SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
|
||||
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
#define pool_allocate (pool->allocate(__PRETTY_FUNCTION__))
|
||||
|
@ -73,6 +73,7 @@
|
|||
#define SRSLTE_BUFFER_POOL_LOG_NAME_LEN 128
|
||||
#else
|
||||
#define pool_allocate (pool->allocate())
|
||||
#define pool_allocate_blocking (pool->allocate(NULL, true))
|
||||
#endif
|
||||
|
||||
#define ZERO_OBJECT(x) memset(&(x), 0x0, sizeof((x)))
|
||||
|
@ -215,13 +216,16 @@ struct bit_buffer_t{
|
|||
#endif
|
||||
}
|
||||
bit_buffer_t(const bit_buffer_t& buf){
|
||||
msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET];
|
||||
N_bits = buf.N_bits;
|
||||
memcpy(msg, buf.msg, N_bits);
|
||||
}
|
||||
bit_buffer_t & operator= (const bit_buffer_t & buf){
|
||||
// avoid self assignment
|
||||
if (&buf == this)
|
||||
if (&buf == this) {
|
||||
return *this;
|
||||
}
|
||||
msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET];
|
||||
N_bits = buf.N_bits;
|
||||
memcpy(msg, buf.msg, N_bits);
|
||||
return *this;
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
void stop() {
|
||||
stop_thread();
|
||||
// stop all listeners
|
||||
for (uint32_t i=0;i<listeners.size();i++) {
|
||||
listeners[i]->stop();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -40,57 +40,83 @@ namespace srslte {
|
|||
* | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
||||
*
|
||||
* 1 | Version |PT | * | E | S |PN |
|
||||
* 2 | Message Type |
|
||||
* 3 | Length (1st Octet) |
|
||||
* 4 | Length (2nd Octet) |
|
||||
* 5 | TEID (1st Octet) |
|
||||
* 6 | TEID (2nd Octet) |
|
||||
* 7 | TEID (3rd Octet) |
|
||||
* 8 | TEID (4th Octet) |
|
||||
* 2 | Message Type |
|
||||
* 3 | Length (1st Octet) |
|
||||
* 4 | Length (2nd Octet) |
|
||||
* 5 | TEID (1st Octet) |
|
||||
* 6 | TEID (2nd Octet) |
|
||||
* 7 | TEID (3rd Octet) |
|
||||
* 8 | TEID (4th Octet) |
|
||||
* 9 | Seq Number (1st Octet) |
|
||||
* 10 | Seq Number (2st Octet) |
|
||||
* 11 | N-PDU |
|
||||
* 12 | Next Extension Header Type |
|
||||
***************************************************************************/
|
||||
|
||||
#define GTPU_HEADER_LEN 8
|
||||
#define GTPU_BASE_HEADER_LEN 8
|
||||
#define GTPU_EXTENDED_HEADER_LEN 12
|
||||
|
||||
#define GTPU_FLAGS_VERSION_MASK 0xE0
|
||||
#define GTPU_FLAGS_VERSION_V1 0x20
|
||||
#define GTPU_FLAGS_GTP_PRIME_PROTOCOL 0x00
|
||||
#define GTPU_FLAGS_GTP_PROTOCOL 0x10
|
||||
#define GTPU_FLAGS_EXTENDED_HDR 0x04
|
||||
#define GTPU_FLAGS_SEQUENCE 0x02
|
||||
#define GTPU_FLAGS_PACKET_NUM 0x01
|
||||
|
||||
#define GTPU_MSG_ECHO_REQUEST 1
|
||||
#define GTPU_MSG_ECHO_RESPONSE 2
|
||||
#define GTPU_MSG_ERROR_INDICATION 26
|
||||
#define GTPU_MSG_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION 31
|
||||
#define GTPU_MSG_END_MARKER 254
|
||||
#define GTPU_MSG_DATA_PDU 255
|
||||
|
||||
typedef struct{
|
||||
uint8_t flags; // Only support 0x30 - v1, PT1 (GTP), no other flags
|
||||
uint8_t message_type; // Only support 0xFF - T-PDU type
|
||||
uint8_t flags;
|
||||
uint8_t message_type;
|
||||
uint16_t length;
|
||||
uint32_t teid;
|
||||
uint16_t seq_number;
|
||||
uint8_t n_pdu;
|
||||
uint8_t next_ext_hdr_type;
|
||||
}gtpu_header_t;
|
||||
|
||||
|
||||
bool gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header, srslte::log *gtpu_log);
|
||||
bool gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu, srslte::log *gtpu_log);
|
||||
|
||||
inline void uint8_to_uint32(uint8_t *buf, uint32_t *i)
|
||||
inline bool gtpu_supported_flags_check(gtpu_header_t *header, srslte::log *gtpu_log)
|
||||
{
|
||||
*i = (uint32_t)buf[0] << 24 |
|
||||
(uint32_t)buf[1] << 16 |
|
||||
(uint32_t)buf[2] << 8 |
|
||||
(uint32_t)buf[3];
|
||||
//flags
|
||||
if( (header->flags & GTPU_FLAGS_VERSION_MASK) != GTPU_FLAGS_VERSION_V1 ) {
|
||||
gtpu_log->error("gtpu_header - Unhandled GTP-U Version. Flags: 0x%x\n", header->flags);
|
||||
return false;
|
||||
}
|
||||
if( !(header->flags & GTPU_FLAGS_GTP_PROTOCOL) ) {
|
||||
gtpu_log->error("gtpu_header - Unhandled Protocol Type. Flags: 0x%x\n\n", header->flags);
|
||||
return false;
|
||||
}
|
||||
if( header->flags & GTPU_FLAGS_EXTENDED_HDR ) {
|
||||
gtpu_log->error("gtpu_header - Unhandled Header Extensions. Flags: 0x%x\n\n", header->flags);
|
||||
return false;
|
||||
}
|
||||
if( header->flags & GTPU_FLAGS_PACKET_NUM ) {
|
||||
gtpu_log->error("gtpu_header - Unhandled Packet Number. Flags: 0x%x\n\n", header->flags);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void uint32_to_uint8(uint32_t i, uint8_t *buf)
|
||||
inline bool gtpu_supported_msg_type_check(gtpu_header_t *header, srslte::log *gtpu_log)
|
||||
{
|
||||
buf[0] = (i >> 24) & 0xFF;
|
||||
buf[1] = (i >> 16) & 0xFF;
|
||||
buf[2] = (i >> 8) & 0xFF;
|
||||
buf[3] = i & 0xFF;
|
||||
//msg_tpye
|
||||
if( header->message_type != GTPU_MSG_DATA_PDU && header->message_type != GTPU_MSG_ECHO_REQUEST && header->message_type != GTPU_MSG_ECHO_RESPONSE) {
|
||||
gtpu_log->error("gtpu_header - Unhandled message type: 0x%x\n", header->message_type);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void uint8_to_uint16(uint8_t *buf, uint16_t *i)
|
||||
{
|
||||
*i = (uint32_t)buf[0] << 8 |
|
||||
(uint32_t)buf[1];
|
||||
}
|
||||
|
||||
inline void uint16_to_uint8(uint16_t i, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (i >> 8) & 0xFF;
|
||||
buf[1] = i & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
}//namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -225,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
|
||||
|
||||
|
@ -320,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);
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace srslte {
|
|||
***************************************************************************/
|
||||
|
||||
#define RLC_AM_WINDOW_SIZE 512
|
||||
|
||||
#define RLC_MAX_SDU_SIZE ((1<<11)-1) // Length of LI field is 11bits
|
||||
|
||||
|
||||
typedef enum{
|
||||
|
|
|
@ -146,6 +146,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();
|
||||
|
@ -199,7 +200,6 @@ private:
|
|||
|
||||
// helper functions
|
||||
void debug_state();
|
||||
bool reordering_timeout_running();
|
||||
const char* get_rb_name();
|
||||
};
|
||||
|
||||
|
@ -213,6 +213,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);
|
||||
};
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
|
||||
#include "srslte/upper/gtpu.h"
|
||||
|
||||
#include "srslte/common/int_helpers.h"
|
||||
|
||||
namespace srslte {
|
||||
|
||||
|
@ -37,24 +37,37 @@ namespace srslte {
|
|||
|
||||
bool gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu, srslte::log *gtpu_log)
|
||||
{
|
||||
if(header->flags != 0x30) {
|
||||
gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags);
|
||||
return false;
|
||||
}
|
||||
if(header->message_type != 0xFF) {
|
||||
gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type);
|
||||
return false;
|
||||
}
|
||||
if(pdu->get_headroom() < GTPU_HEADER_LEN) {
|
||||
gtpu_log->error("gtpu_write_header - No room in PDU for header\n");
|
||||
//flags
|
||||
if(!gtpu_supported_flags_check(header,gtpu_log)){
|
||||
gtpu_log->error("gtpu_write_header - Unhandled GTP-U Flags. Flags: 0x%x\n", header->flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
pdu->msg -= GTPU_HEADER_LEN;
|
||||
pdu->N_bytes += GTPU_HEADER_LEN;
|
||||
//msg type
|
||||
if(!gtpu_supported_msg_type_check(header,gtpu_log)){
|
||||
gtpu_log->error("gtpu_write_header - Unhandled GTP-U Message Type. Message Type: 0x%x\n", header->message_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
//If E, S or PN are set, the header is longer
|
||||
if (header->flags & (GTPU_FLAGS_EXTENDED_HDR | GTPU_FLAGS_SEQUENCE | GTPU_FLAGS_PACKET_NUM)) {
|
||||
if(pdu->get_headroom() < GTPU_EXTENDED_HEADER_LEN) {
|
||||
gtpu_log->error("gtpu_write_header - No room in PDU for header\n");
|
||||
return false;
|
||||
}
|
||||
pdu->msg -= GTPU_EXTENDED_HEADER_LEN;
|
||||
pdu->N_bytes += GTPU_EXTENDED_HEADER_LEN;
|
||||
} else {
|
||||
if(pdu->get_headroom() < GTPU_BASE_HEADER_LEN) {
|
||||
gtpu_log->error("gtpu_write_header - No room in PDU for header\n");
|
||||
return false;
|
||||
}
|
||||
pdu->msg -= GTPU_BASE_HEADER_LEN;
|
||||
pdu->N_bytes += GTPU_BASE_HEADER_LEN;
|
||||
}
|
||||
|
||||
//write mandatory fields
|
||||
uint8_t *ptr = pdu->msg;
|
||||
|
||||
*ptr = header->flags;
|
||||
ptr++;
|
||||
*ptr = header->message_type;
|
||||
|
@ -62,7 +75,30 @@ bool gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu, srslte
|
|||
uint16_to_uint8(header->length, ptr);
|
||||
ptr += 2;
|
||||
uint32_to_uint8(header->teid, ptr);
|
||||
|
||||
//write optional fields, if E, S or PN are set.
|
||||
if (header->flags & (GTPU_FLAGS_EXTENDED_HDR | GTPU_FLAGS_SEQUENCE | GTPU_FLAGS_PACKET_NUM)) {
|
||||
//S
|
||||
if (header->flags & GTPU_FLAGS_SEQUENCE ) {
|
||||
uint16_to_uint8(header->seq_number, ptr);
|
||||
} else {
|
||||
uint16_to_uint8(0, ptr);
|
||||
}
|
||||
ptr+=2;
|
||||
//PN
|
||||
if (header->flags & GTPU_FLAGS_PACKET_NUM ) {
|
||||
*ptr = header->n_pdu;
|
||||
} else {
|
||||
header->n_pdu = 0;
|
||||
}
|
||||
ptr++;
|
||||
//E
|
||||
if (header->flags & GTPU_FLAGS_EXTENDED_HDR ) {
|
||||
*ptr = header->next_ext_hdr_type;
|
||||
} else {
|
||||
*ptr = 0;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -70,26 +106,44 @@ bool gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header, srslte:
|
|||
{
|
||||
uint8_t *ptr = pdu->msg;
|
||||
|
||||
pdu->msg += GTPU_HEADER_LEN;
|
||||
pdu->N_bytes -= GTPU_HEADER_LEN;
|
||||
|
||||
header->flags = *ptr;
|
||||
header->flags = *ptr;
|
||||
ptr++;
|
||||
header->message_type = *ptr;
|
||||
header->message_type = *ptr;
|
||||
ptr++;
|
||||
uint8_to_uint16(ptr, &header->length);
|
||||
ptr += 2;
|
||||
uint8_to_uint32(ptr, &header->teid);
|
||||
|
||||
if(header->flags != 0x30) {
|
||||
gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags);
|
||||
//flags
|
||||
if(!gtpu_supported_flags_check(header,gtpu_log)){
|
||||
gtpu_log->error("gtpu_read_header - Unhandled GTP-U Flags. Flags: 0x%x\n", header->flags);
|
||||
return false;
|
||||
}
|
||||
if(header->message_type != 0xFF) {
|
||||
gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type);
|
||||
|
||||
//message_type
|
||||
if(!gtpu_supported_msg_type_check(header,gtpu_log)){
|
||||
gtpu_log->error("gtpu_read_header - Unhandled GTP-U Message Type. Flags: 0x%x\n", header->message_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
//If E, S or PN are set, header is longer
|
||||
if (header->flags & (GTPU_FLAGS_EXTENDED_HDR | GTPU_FLAGS_SEQUENCE | GTPU_FLAGS_PACKET_NUM)) {
|
||||
pdu->msg += GTPU_EXTENDED_HEADER_LEN;
|
||||
pdu->N_bytes -= GTPU_EXTENDED_HEADER_LEN;
|
||||
|
||||
uint8_to_uint16(ptr, &header->seq_number);
|
||||
ptr+=2;
|
||||
|
||||
header->n_pdu = *ptr;
|
||||
ptr++;
|
||||
|
||||
header->next_ext_hdr_type = *ptr;
|
||||
ptr++;
|
||||
} else {
|
||||
pdu->msg += GTPU_BASE_HEADER_LEN;
|
||||
pdu->N_bytes -= GTPU_BASE_HEADER_LEN;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ void pdcp_entity::write_pdu(byte_buffer_t *pdu)
|
|||
} else {
|
||||
// Handle SRB messages
|
||||
if (cfg.is_control) {
|
||||
uint32_t sn;
|
||||
uint32_t sn = 0;
|
||||
if (do_encryption) {
|
||||
cipher_decrypt(&(pdu->msg[sn_len_bytes]),
|
||||
rx_count,
|
||||
|
@ -218,7 +218,7 @@ void pdcp_entity::write_pdu(byte_buffer_t *pdu)
|
|||
rx_count,
|
||||
pdu->N_bytes - 4,
|
||||
&(pdu->msg[pdu->N_bytes - 4]))) {
|
||||
log->error_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d (Dropping PDU)", rrc->get_rb_name(lcid).c_str(), sn);
|
||||
log->error_hex(pdu->msg, pdu->N_bytes, "%s Dropping PDU", rrc->get_rb_name(lcid).c_str());
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,6 +210,13 @@ void rlc::empty_queue()
|
|||
|
||||
void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu, bool blocking)
|
||||
{
|
||||
// FIXME: rework build PDU logic to allow large SDUs (without concatenation)
|
||||
if (sdu->N_bytes > RLC_MAX_SDU_SIZE) {
|
||||
rlc_log->warning("Dropping too long SDU of size %d B (Max. size %d B).\n", sdu->N_bytes, RLC_MAX_SDU_SIZE);
|
||||
pool->deallocate(sdu);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_rwlock_rdlock(&rwlock);
|
||||
if (valid_lcid(lcid)) {
|
||||
rlc_array.at(lcid)->write_sdu(sdu, blocking);
|
||||
|
|
|
@ -322,7 +322,7 @@ 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;
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -496,8 +496,10 @@ void rlc_am::rlc_am_tx::timer_expired(uint32_t timeout_id)
|
|||
pthread_mutex_lock(&mutex);
|
||||
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, if tx_window is full and retx_queue empty, retransmit random PDU
|
||||
if ((tx_window.size() >= RLC_AM_WINDOW_SIZE && retx_queue.empty() && tx_sdu_queue.size() == 0)) {
|
||||
// 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
|
||||
|
@ -509,17 +511,18 @@ void rlc_am::rlc_am_tx::timer_expired(uint32_t timeout_id)
|
|||
|
||||
void rlc_am::rlc_am_tx::retransmit_random_pdu()
|
||||
{
|
||||
// randomly select PDU in tx window for retransmission
|
||||
std::map<uint32_t, rlc_amd_tx_pdu_t>::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);
|
||||
if (not tx_window.empty()) {
|
||||
// randomly select PDU in tx window for retransmission
|
||||
std::map<uint32_t, rlc_amd_tx_pdu_t>::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()
|
||||
|
@ -579,10 +582,11 @@ 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);
|
||||
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<uint32_t>(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();
|
||||
|
||||
|
@ -757,6 +761,10 @@ int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
|
|||
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;
|
||||
|
@ -776,19 +784,17 @@ int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
|
|||
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();
|
||||
|
@ -801,9 +807,6 @@ int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
|
|||
} 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
|
||||
|
@ -813,9 +816,6 @@ 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 > static_cast<int>(nof_bytes)) {
|
||||
|
@ -824,14 +824,17 @@ int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
|
|||
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 == NULL && 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;
|
||||
}
|
||||
|
@ -875,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)
|
||||
|
@ -906,7 +909,7 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|||
tx_sdu = NULL;
|
||||
}
|
||||
if (pdu_space > to_move) {
|
||||
pdu_space -= to_move;
|
||||
pdu_space -= SRSLTE_MIN(to_move, pdu->get_tailroom());
|
||||
} else {
|
||||
pdu_space = 0;
|
||||
}
|
||||
|
@ -917,9 +920,10 @@ 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) {
|
||||
while (pdu_space > head_len + 1 && tx_sdu_queue.size() > 0 && header.N_li < RLC_AM_WINDOW_SIZE) {
|
||||
if (last_li > 0) {
|
||||
header.li[header.N_li++] = last_li;
|
||||
header.li[header.N_li] = last_li;
|
||||
header.N_li++;
|
||||
}
|
||||
head_len = rlc_am_packed_length(&header);
|
||||
if (head_len >= pdu_space) {
|
||||
|
@ -934,8 +938,7 @@ 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);
|
||||
|
@ -992,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)
|
||||
|
@ -1007,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 != NULL) {
|
||||
poll_retx_timer->reset();
|
||||
poll_retx_timer->stop();
|
||||
}
|
||||
|
||||
// flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again
|
||||
|
@ -1304,11 +1308,11 @@ void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rl
|
|||
{
|
||||
std::map<uint32_t, rlc_amd_rx_pdu_t>::iterator it;
|
||||
|
||||
log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d (%d B), %s",
|
||||
log->info_hex(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)",
|
||||
RB_NAME,
|
||||
header.sn,
|
||||
nof_bytes,
|
||||
rlc_fi_field_text[header.fi]);
|
||||
nof_bytes);
|
||||
log->debug("%s\n", rlc_amd_pdu_header_to_string(header).c_str());
|
||||
|
||||
if(!inside_rx_window(header.sn)) {
|
||||
if(header.p) {
|
||||
|
@ -1375,9 +1379,7 @@ void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rl
|
|||
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
|
||||
|
@ -1390,7 +1392,7 @@ void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rl
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1411,8 +1413,9 @@ void rlc_am::rlc_am_rx::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_b
|
|||
{
|
||||
std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::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)) {
|
||||
|
@ -1443,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;
|
||||
}
|
||||
|
@ -1517,6 +1520,9 @@ void rlc_am::rlc_am_rx::reassemble_rx_sdus()
|
|||
for(uint32_t i=0; i<rx_window[vr_r].header.N_li; i++)
|
||||
{
|
||||
len = rx_window[vr_r].header.li[i];
|
||||
|
||||
log->debug_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;
|
||||
|
@ -1556,11 +1562,12 @@ 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);
|
||||
|
@ -1584,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<uint32_t, rlc_amd_rx_pdu_segments_t>::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<rlc_amd_rx_pdu_t>::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;
|
||||
|
@ -1669,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;
|
||||
|
@ -1678,7 +1698,8 @@ 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) && status->N_nack < RLC_AM_WINDOW_SIZE) {
|
||||
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->N_nack++;
|
||||
|
@ -1689,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<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it;
|
||||
|
@ -1757,33 +1794,46 @@ 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; i<it->header.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; i<it->header.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 == NULL) {
|
||||
|
@ -2090,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;
|
||||
|
@ -2111,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);
|
||||
|
|
|
@ -153,7 +153,7 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|||
{
|
||||
uint32_t pdu_size = ul_queue.size_tail_bytes();
|
||||
if (pdu_size > nof_bytes) {
|
||||
log->error("TX %s PDU size larger than MAC opportunity\n", rrc->get_rb_name(lcid).c_str());
|
||||
log->error("TX %s PDU size larger than MAC opportunity (%d > %d)\n", rrc->get_rb_name(lcid).c_str(), pdu_size, nof_bytes);
|
||||
return -1;
|
||||
}
|
||||
byte_buffer_t *buf;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -375,6 +376,12 @@ int rlc_um::rlc_um_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
log->debug("MAC opportunity - %d bytes\n", nof_bytes);
|
||||
|
||||
if (not tx_enabled) {
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!tx_sdu && tx_sdu_queue.size() == 0) {
|
||||
log->info("No data available to be sent\n");
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
@ -399,7 +406,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 +437,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 +481,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_hex(payload, ret, "%s Tx PDU SN=%d (%d B)\n", get_rb_name(), header.sn, pdu->N_bytes);
|
||||
pool->deallocate(pdu);
|
||||
|
||||
debug_state();
|
||||
|
@ -595,7 +602,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))
|
||||
|
@ -673,15 +680,18 @@ void rlc_um::rlc_um_rx::reassemble_rx_sdus()
|
|||
// First catch up with lower edge of reordering window
|
||||
while(!inside_reordering_window(vr_ur))
|
||||
{
|
||||
log->debug("SN=%d is not inside reordering windows\n", vr_ur);
|
||||
|
||||
if(rx_window.end() == rx_window.find(vr_ur))
|
||||
{
|
||||
log->debug("SN=%d not in rx_window. Reset received SDU\n", vr_ur);
|
||||
rx_sdu->reset();
|
||||
}else{
|
||||
// Handle any SDU segments
|
||||
for(uint32_t i=0; i<rx_window[vr_ur].header.N_li; i++)
|
||||
{
|
||||
int len = rx_window[vr_ur].header.li[i];
|
||||
|
||||
log->debug_hex(rx_window[vr_ur].buf->msg, len, "Handling segment %d/%d of length %d B of SN=%d\n", i+1, rx_window[vr_ur].header.N_li, len, vr_ur);
|
||||
// Check if we received 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("Dropping PDU %d due to lost start segment\n", vr_ur);
|
||||
|
@ -758,35 +768,34 @@ 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; i<rx_window[vr_ur].header.N_li; i++) {
|
||||
int len = rx_window[vr_ur].header.li[i];
|
||||
uint16_t len = rx_window[vr_ur].header.li[i];
|
||||
log->debug("Handling SDU segment 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);
|
||||
|
||||
if (rx_window[vr_ur].buf->N_bytes < len) {
|
||||
log->error("Dropping remaining remainder of SN %d too (N_bytes=%u < len=%d)\n", vr_ur, rx_window[vr_ur].buf->N_bytes, len);
|
||||
goto clean_up_rx_window;
|
||||
}
|
||||
|
||||
// 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 +805,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 (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 +833,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 +853,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 +892,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)
|
||||
|
@ -907,9 +939,8 @@ void rlc_um::rlc_um_rx::reset_metrics()
|
|||
|
||||
void rlc_um::rlc_um_rx::timer_expired(uint32_t timeout_id)
|
||||
{
|
||||
if (reordering_timer_id == timeout_id) {
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
if (reordering_timer != NULL && reordering_timer_id == timeout_id) {
|
||||
// 36.322 v10 Section 5.1.2.2.4
|
||||
log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n",
|
||||
get_rb_name());
|
||||
|
@ -925,7 +956,7 @@ void rlc_um::rlc_um_rx::timer_expired(uint32_t timeout_id)
|
|||
reassemble_rx_sdus();
|
||||
log->debug("Finished reassemble from timeout id=%d\n", timeout_id);
|
||||
}
|
||||
reordering_timer->stop();
|
||||
|
||||
if (RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) {
|
||||
reordering_timer->reset();
|
||||
reordering_timer->run();
|
||||
|
@ -933,13 +964,8 @@ void rlc_um::rlc_um_rx::timer_expired(uint32_t timeout_id)
|
|||
}
|
||||
|
||||
debug_state();
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
}
|
||||
|
||||
bool rlc_um::rlc_um_rx::reordering_timeout_running()
|
||||
{
|
||||
return reordering_timer->is_running();
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -34,7 +34,7 @@ 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)
|
||||
|
|
|
@ -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);
|
||||
|
@ -959,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);
|
||||
|
@ -1069,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);
|
||||
|
@ -1195,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
|
||||
|
@ -1214,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;
|
||||
|
@ -1254,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);
|
||||
|
||||
|
@ -1300,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<N_PDU_BUFS;i++) {
|
||||
|
@ -1313,17 +1323,18 @@ bool resegment_test_7()
|
|||
}
|
||||
|
||||
// Step timers until reordering timeout expires
|
||||
int cnt = 5;
|
||||
cnt = 5;
|
||||
while (cnt--) {
|
||||
timers.step_all();
|
||||
}
|
||||
|
||||
assert(12 == rlc1.get_buffer_state());
|
||||
// RLC should try to retransmit a random PDU because it needs to re-request a status PDU from the receiver
|
||||
assert(0 != rlc1.get_buffer_state());
|
||||
|
||||
// first round of retx, forcing resegmentation
|
||||
byte_buffer_t retx[4];
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
assert(rlc1.get_buffer_state());
|
||||
assert(0 != rlc1.get_buffer_state());
|
||||
retx[i].N_bytes = rlc1.read_pdu(retx[i].msg, 7);
|
||||
assert(retx[i].N_bytes);
|
||||
|
||||
|
@ -1497,7 +1508,8 @@ bool resegment_test_8()
|
|||
timers.step_all();
|
||||
}
|
||||
|
||||
assert(12 == rlc1.get_buffer_state());
|
||||
// what PDU to retransmit is random but it must not be zero
|
||||
assert(0 != rlc1.get_buffer_state());
|
||||
|
||||
// first round of retx, forcing resegmentation
|
||||
byte_buffer_t retx[4];
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <boost/program_options/parsers.hpp>
|
||||
#include <cassert>
|
||||
#include <srslte/upper/rlc_interface.h>
|
||||
#include "srslte/common/crash_handler.h"
|
||||
|
||||
#define LOG_HEX_LIMIT (-1)
|
||||
|
||||
|
@ -55,9 +56,9 @@ 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[]) {
|
||||
|
@ -75,16 +76,16 @@ void parse_args(stress_test_args_t *args, int argc, char *argv[]) {
|
|||
("mode", bpo::value<std::string>(&args->mode)->default_value("AM"), "Whether to test RLC acknowledged or unacknowledged mode (AM/UM)")
|
||||
("duration", bpo::value<uint32_t>(&args->test_duration_sec)->default_value(5), "Duration (sec)")
|
||||
("sdu_size", bpo::value<uint32_t>(&args->sdu_size)->default_value(1500), "Size of SDUs")
|
||||
("avg_opp_size", bpo::value<uint32_t>(&args->avg_opp_size)->default_value(1505), "Size of the MAC opportunity (if not random)")
|
||||
("random_opp", bpo::value<bool>(&args->random_opp)->default_value(true), "Whether to generate random MAC opportunities")
|
||||
("sdu_gen_delay", bpo::value<uint32_t>(&args->sdu_gen_delay_usec)->default_value(0), "SDU generation delay (usec)")
|
||||
("pdu_tx_delay", bpo::value<uint32_t>(&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<float>(&args->error_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped")
|
||||
("opp_sdu_ratio", bpo::value<float>(&args->opp_sdu_ratio)->default_value(0.0), "Ratio between MAC opportunity and SDU size (0==random)")
|
||||
("reestablish", bpo::value<bool>(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution")
|
||||
("loglevel", bpo::value<uint32_t>(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug)")
|
||||
("singletx", bpo::value<bool>(&args->single_tx)->default_value(false), "If set to true, only one node is generating data")
|
||||
("pcap", bpo::value<bool>(&args->write_pcap)->default_value(false), "Whether to write all RLC PDU to PCAP file")
|
||||
("zeroseed", bpo::value<bool>(&args->zero_seed)->default_value(false), "Whether to initialize random seed to zero")
|
||||
("pedantic", bpo::value<bool>(&args->pedantic)->default_value(true), "Whether to perform strict SDU size checking at receiver");
|
||||
("zeroseed", bpo::value<bool>(&args->zero_seed)->default_value(false), "Whether to initialize random seed to zero");
|
||||
|
||||
// these options are allowed on the command line
|
||||
bpo::options_description cmdline_options;
|
||||
|
@ -156,8 +157,11 @@ private:
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
float r = args.opp_sdu_ratio ? args.opp_sdu_ratio : static_cast<float>(rand())/RAND_MAX;
|
||||
int opp_size = r*args.sdu_size;
|
||||
float factor = 1.0;
|
||||
if (args.random_opp) {
|
||||
factor = 0.5 + static_cast<float>(rand())/RAND_MAX;
|
||||
}
|
||||
int opp_size = args.avg_opp_size * factor;
|
||||
uint32_t buf_state = tx_rlc->get_buffer_state(lcid);
|
||||
if (buf_state > 0) {
|
||||
int read = tx_rlc->read_pdu(lcid, pdu->msg, opp_size);
|
||||
|
@ -235,10 +239,7 @@ public:
|
|||
assert(rx_lcid == lcid);
|
||||
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);
|
||||
}
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
byte_buffer_pool::get_instance()->deallocate(sdu);
|
||||
|
@ -407,7 +408,10 @@ void stress_test(stress_test_args_t args)
|
|||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
srslte_debug_handle_crash(argc, argv);
|
||||
|
||||
stress_test_args_t args = {};
|
||||
parse_args(&args, argc, argv);
|
||||
|
||||
|
|
|
@ -150,6 +150,9 @@ nof_ctrl_symbols = 3
|
|||
# link_failure_nof_err: Number of PUSCH failures after which a radio-link failure is triggered.
|
||||
# a link failure is when SNR<0 and CRC=KO
|
||||
# max_prach_offset_us: Maximum allowed RACH offset (in us)
|
||||
# enable_mbsfn: Enable MBMS transmission in the eNB
|
||||
# m1u_multiaddr: Multicast addres the M1-U socket will register to
|
||||
# m1u_if_addr: Address of the inteferface the M1-U interface will listen for multicast packets.
|
||||
#
|
||||
#####################################################################
|
||||
[expert]
|
||||
|
@ -162,21 +165,5 @@ 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
|
||||
#m1u_multiaddr = 239.255.0.1
|
||||
#m1u_if_addr = 127.0.1.201
|
|
@ -128,13 +128,14 @@ typedef struct {
|
|||
float metrics_period_secs;
|
||||
bool enable_mbsfn;
|
||||
bool print_buffer_state;
|
||||
std::string m1u_multiaddr;
|
||||
std::string m1u_if_addr;
|
||||
}expert_args_t;
|
||||
|
||||
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 +143,7 @@ typedef struct {
|
|||
}all_args_t;
|
||||
|
||||
/*******************************************************************************
|
||||
Main UE class
|
||||
Main eNB class
|
||||
*******************************************************************************/
|
||||
|
||||
class enb
|
||||
|
@ -213,7 +214,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 +223,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
|
||||
|
|
|
@ -153,6 +153,7 @@ private:
|
|||
rrc_interface_mac *rrc;
|
||||
|
||||
pthread_rwlock_t rwlock;
|
||||
pthread_mutex_t sched_mutex;
|
||||
|
||||
cell_cfg_t cfg;
|
||||
sched_args_t sched_cfg;
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace srsenb {
|
|||
class dl_metric_rr : public sched::metric_dl
|
||||
{
|
||||
public:
|
||||
//interface
|
||||
void new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t start_rbg, uint32_t nof_rbg, uint32_t nof_ctrl_symbols, uint32_t tti);
|
||||
dl_harq_proc* get_user_allocation(sched_ue *user);
|
||||
private:
|
||||
|
@ -62,6 +63,7 @@ private:
|
|||
class ul_metric_rr : public sched::metric_ul
|
||||
{
|
||||
public:
|
||||
// interface
|
||||
void new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t nof_rb, uint32_t tti);
|
||||
ul_harq_proc* get_user_allocation(sched_ue *user);
|
||||
bool update_allocation(ul_harq_proc::ul_alloc_t alloc);
|
||||
|
@ -79,7 +81,7 @@ private:
|
|||
|
||||
bool used_rb[MAX_PRB];
|
||||
uint32_t current_tti;
|
||||
uint32_t nof_rb;
|
||||
uint32_t nof_rb;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -73,7 +73,6 @@ private:
|
|||
cf_t samples[sf_buffer_sz];
|
||||
uint32_t nof_samples;
|
||||
uint32_t tti;
|
||||
char debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN];
|
||||
};
|
||||
srslte::buffer_pool<sf_buffer> buffer_pool;
|
||||
srslte::block_queue<sf_buffer*> pending_buffers;
|
||||
|
|
|
@ -40,24 +40,6 @@
|
|||
|
||||
namespace srsenb {
|
||||
|
||||
/****************************************************************************
|
||||
* GTPU Header
|
||||
* Ref: 3GPP TS 29.281 v10.1.0 Section 5
|
||||
*
|
||||
* | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
||||
*
|
||||
* 1 | Version |PT | * | E | S |PN |
|
||||
* 2 | Message Type |
|
||||
* 3 | Length (1st Octet) |
|
||||
* 4 | Length (2nd Octet) |
|
||||
* 5 | TEID (1st Octet) |
|
||||
* 6 | TEID (2nd Octet) |
|
||||
* 7 | TEID (3rd Octet) |
|
||||
* 8 | TEID (4th Octet) |
|
||||
***************************************************************************/
|
||||
|
||||
#define GTPU_HEADER_LEN 8
|
||||
|
||||
class gtpu
|
||||
:public gtpu_interface_rrc
|
||||
,public gtpu_interface_pdcp
|
||||
|
@ -67,7 +49,7 @@ public:
|
|||
|
||||
gtpu();
|
||||
|
||||
bool init(std::string gtp_bind_addr_, std::string mme_addr_, pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_, bool enable_mbsfn = false);
|
||||
bool init(std::string gtp_bind_addr_, std::string mme_addr_, std::string m1u_multiaddr_, std::string m1u_if_addr_, pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_, bool enable_mbsfn = false);
|
||||
void stop();
|
||||
|
||||
// gtpu_interface_rrc
|
||||
|
@ -95,7 +77,7 @@ private:
|
|||
class mch_thread : public thread {
|
||||
public:
|
||||
mch_thread() : initiated(false),running(false),run_enable(false),pool(NULL) {}
|
||||
bool init(pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_);
|
||||
bool init(std::string m1u_multiaddr_, std::string m1u_if_addr_, pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_);
|
||||
void stop();
|
||||
private:
|
||||
void run_thread();
|
||||
|
@ -110,6 +92,8 @@ private:
|
|||
srslte::log *gtpu_log;
|
||||
int m1u_sd;
|
||||
int lcid_counter;
|
||||
std::string m1u_multiaddr;
|
||||
std::string m1u_if_addr;
|
||||
|
||||
srslte::byte_buffer_pool *pool;
|
||||
};
|
||||
|
@ -124,12 +108,11 @@ private:
|
|||
}bearer_map;
|
||||
std::map<uint16_t, bearer_map> rnti_bearers;
|
||||
|
||||
// Socket file descriptors
|
||||
int snk_fd;
|
||||
int src_fd;
|
||||
// Socket file descriptor
|
||||
int fd;
|
||||
|
||||
//Threading
|
||||
void run_thread();
|
||||
void echo_response(in_addr_t addr, in_port_t port, uint16_t seq);
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
|
|
|
@ -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<uint32_t, LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT> srbs;
|
||||
std::map<uint32_t, LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT> 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<uint16_t,ue> users;
|
||||
|
||||
|
||||
std::map<uint32_t, LIBLTE_S1AP_UEPAGINGID_STRUCT > 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;
|
||||
|
|
|
@ -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.
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "srsenb/hdr/enb.h"
|
||||
#include "srslte/build_info.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
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);
|
||||
|
||||
|
@ -79,6 +85,7 @@ bool enb::init(all_args_t *args_)
|
|||
} else {
|
||||
logger_file.init(args->log.filename, args->log.file_max_size);
|
||||
logger_file.log("\n\n");
|
||||
logger_file.log(get_build_string().c_str());
|
||||
logger = &logger_file;
|
||||
}
|
||||
|
||||
|
@ -159,8 +166,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);
|
||||
|
@ -212,15 +217,23 @@ bool enb::init(all_args_t *args_)
|
|||
|
||||
uint32_t prach_freq_offset = rrc_cfg.sibs[1].sib.sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset;
|
||||
|
||||
if (prach_freq_offset + 6 > cell_cfg.nof_prb) {
|
||||
fprintf(stderr, "Invalid PRACH configuration: frequency offset=%d outside bandwidth limits\n", prach_freq_offset);
|
||||
return false;
|
||||
}
|
||||
if(cell_cfg.nof_prb>10) {
|
||||
if (prach_freq_offset + 6 > cell_cfg.nof_prb - SRSLTE_MAX(rrc_cfg.cqi_cfg.nof_prb, rrc_cfg.sr_cfg.nof_prb)) {
|
||||
fprintf(stderr, "Invalid PRACH configuration: frequency offset=%d outside bandwidth limits\n", prach_freq_offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prach_freq_offset < rrc_cfg.cqi_cfg.nof_prb || prach_freq_offset < rrc_cfg.sr_cfg.nof_prb ) {
|
||||
fprintf(stderr, "Invalid PRACH configuration: frequency offset=%d lower than CQI offset: %d or SR offset: %d\n",
|
||||
prach_freq_offset, rrc_cfg.cqi_cfg.nof_prb, rrc_cfg.sr_cfg.nof_prb);
|
||||
return false;
|
||||
if (prach_freq_offset < SRSLTE_MAX(rrc_cfg.cqi_cfg.nof_prb, rrc_cfg.sr_cfg.nof_prb)) {
|
||||
fprintf(stderr, "Invalid PRACH configuration: frequency offset=%d lower than CQI offset: %d or SR offset: %d\n",
|
||||
prach_freq_offset, rrc_cfg.cqi_cfg.nof_prb, rrc_cfg.sr_cfg.nof_prb);
|
||||
return false;
|
||||
}
|
||||
} else { // 6 PRB case
|
||||
if (prach_freq_offset+6 > cell_cfg.nof_prb) {
|
||||
fprintf(stderr, "Invalid PRACH configuration: frequency interval=(%d, %d) does not fit into the eNB PRBs=(0,%d)\n",
|
||||
prach_freq_offset, prach_freq_offset+6, cell_cfg.nof_prb);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer;
|
||||
|
@ -237,8 +250,8 @@ bool enb::init(all_args_t *args_)
|
|||
pdcp.init(&rlc, &rrc, >pu, &pdcp_log);
|
||||
rrc.init(&rrc_cfg, &phy, &mac, &rlc, &pdcp, &s1ap, >pu, &rrc_log);
|
||||
s1ap.init(args->enb.s1ap, &rrc, &s1ap_log);
|
||||
gtpu.init(args->enb.s1ap.gtp_bind_addr, args->enb.s1ap.mme_addr, &pdcp, >pu_log, args->expert.enable_mbsfn);
|
||||
|
||||
gtpu.init(args->enb.s1ap.gtp_bind_addr, args->enb.s1ap.mme_addr, args->expert.m1u_multiaddr, args->expert.m1u_if_addr, &pdcp, >pu_log, args->expert.enable_mbsfn);
|
||||
|
||||
started = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -342,4 +355,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
|
||||
|
|
|
@ -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<uint32>
|
||||
|
@ -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)) {
|
||||
|
|
|
@ -64,6 +64,7 @@ sched::sched() : bc_aggr_level(0), rar_aggr_level(0), avail_rbg(0), P(0), start_
|
|||
reset();
|
||||
|
||||
pthread_rwlock_init(&rwlock, NULL);
|
||||
pthread_mutex_init(&sched_mutex, NULL);
|
||||
}
|
||||
|
||||
sched::~sched()
|
||||
|
@ -72,6 +73,7 @@ sched::~sched()
|
|||
pthread_rwlock_wrlock(&rwlock);
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
pthread_rwlock_destroy(&rwlock);
|
||||
pthread_mutex_destroy(&sched_mutex);
|
||||
}
|
||||
|
||||
void sched::init(rrc_interface_mac *rrc_, srslte::log* log)
|
||||
|
@ -677,7 +679,12 @@ int sched::dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST])
|
|||
// Schedules data to users
|
||||
int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
|
||||
{
|
||||
uint32_t nof_ctrl_symbols = (cfg.cell.nof_prb<10)?(current_cfi+1):current_cfi;
|
||||
// NOTE: In case of 6 PRBs, do not transmit if there is going to be a PRACH in the UL to avoid collisions
|
||||
if (cfg.cell.nof_prb<10 and srslte_prach_tti_opportunity_config(cfg.prach_config, current_tti+4, -1)) {
|
||||
start_rbg = avail_rbg;
|
||||
}
|
||||
|
||||
uint32_t nof_ctrl_symbols = (cfg.cell.nof_prb<10)?(current_cfi+1):current_cfi;
|
||||
dl_metric->new_tti(ue_db, start_rbg, avail_rbg, nof_ctrl_symbols, current_tti);
|
||||
|
||||
int nof_data_elems = 0;
|
||||
|
@ -768,6 +775,7 @@ int sched::dl_sched(uint32_t tti, sched_interface::dl_sched_res_t* sched_result)
|
|||
rar_aggr_level = 2;
|
||||
bzero(sched_result, sizeof(sched_interface::dl_sched_res_t));
|
||||
|
||||
pthread_mutex_lock(&sched_mutex);
|
||||
pthread_rwlock_rdlock(&rwlock);
|
||||
|
||||
/* Schedule Broadcast data */
|
||||
|
@ -780,6 +788,7 @@ int sched::dl_sched(uint32_t tti, sched_interface::dl_sched_res_t* sched_result)
|
|||
sched_result->nof_data_elems += dl_sched_data(sched_result->data);
|
||||
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
pthread_mutex_unlock(&sched_mutex);
|
||||
|
||||
/* Set CFI */
|
||||
sched_result->cfi = current_cfi;
|
||||
|
@ -796,7 +805,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (cfg.prach_freq_offset + 6 > cfg.cell.nof_prb) {
|
||||
if (cfg.prach_freq_offset + 6 > cfg.cell.nof_prb and cfg.cell.nof_prb>10) {
|
||||
fprintf(stderr, "Invalid PRACH configuration: frequency offset=%d outside bandwidth limits\n", cfg.prach_freq_offset);
|
||||
return -1;
|
||||
}
|
||||
|
@ -815,14 +824,15 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
|
|||
sf_idx = (tti+10240-HARQ_DELAY_MS)%10;
|
||||
}
|
||||
int nof_dci_elems = 0;
|
||||
int nof_phich_elems = 0;
|
||||
|
||||
// current_cfi is set in dl_sched()
|
||||
int nof_phich_elems = 0;
|
||||
|
||||
pthread_mutex_lock(&sched_mutex);
|
||||
pthread_rwlock_rdlock(&rwlock);
|
||||
|
||||
// current_cfi is set in dl_sched()
|
||||
bzero(sched_result, sizeof(sched_interface::ul_sched_res_t));
|
||||
ul_metric->reset_allocation(cfg.cell.nof_prb);
|
||||
|
||||
pthread_rwlock_rdlock(&rwlock);
|
||||
|
||||
// Get HARQ process for this TTI
|
||||
for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
||||
sched_ue *user = (sched_ue*) &iter->second;
|
||||
|
@ -840,7 +850,19 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
|
|||
}
|
||||
}
|
||||
|
||||
// reserve PRBs for PRACH
|
||||
if(srslte_prach_tti_opportunity_config(cfg.prach_config, tti, -1)) {
|
||||
ul_harq_proc::ul_alloc_t prach = {cfg.prach_freq_offset, 6};
|
||||
if(!ul_metric->update_allocation(prach)) {
|
||||
log_h->warning("SCHED: Failed to allocate PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L);
|
||||
}
|
||||
else {
|
||||
log_h->debug("SCHED: Allocated PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L);
|
||||
}
|
||||
}
|
||||
|
||||
// Update available allocation if there's a pending RAR
|
||||
// NOTE: It has priority over PUCCH.
|
||||
if (pending_msg3[tti%10].enabled) {
|
||||
ul_harq_proc::ul_alloc_t msg3 = {pending_msg3[tti%10].n_prb, pending_msg3[tti%10].L};
|
||||
if(ul_metric->update_allocation(msg3)) {
|
||||
|
@ -854,15 +876,13 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
|
|||
// Allocate PUCCH resources
|
||||
if (cfg.nrb_pucch >= 0) {
|
||||
ul_harq_proc::ul_alloc_t pucch = {0, (uint32_t) cfg.nrb_pucch};
|
||||
if(!ul_metric->update_allocation(pucch)) {
|
||||
log_h->warning("SCHED: Failed to allocate PUCCH\n");
|
||||
if (!ul_metric->update_allocation(pucch) and cfg.cell.nof_prb != 6) {
|
||||
log_h->warning("SCHED: There was a collision with the PUCCH (%d, %d)\n", pucch.RB_start, pucch.RB_start+pucch.L);
|
||||
}
|
||||
pucch.RB_start = cfg.cell.nof_prb-cfg.nrb_pucch;
|
||||
pucch.L = (uint32_t) cfg.nrb_pucch;
|
||||
if(!ul_metric->update_allocation(pucch)) {
|
||||
log_h->warning("SCHED: Failed to allocate PUCCH\n");
|
||||
} else {
|
||||
log_h->debug("Allocating PUCCH (%d,%d)\n", pucch.RB_start, pucch.RB_start+pucch.L);
|
||||
if (!ul_metric->update_allocation(pucch) and cfg.cell.nof_prb != 6) {
|
||||
log_h->warning("SCHED: There was a collision with the PUCCH (%d, %d)\n", pucch.RB_start, pucch.RB_start+pucch.L);
|
||||
}
|
||||
} else {
|
||||
for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
||||
|
@ -880,17 +900,6 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
|
|||
}
|
||||
}
|
||||
|
||||
// reserve PRBs for PRACH
|
||||
if(srslte_prach_tti_opportunity_config(cfg.prach_config, tti, -1)) {
|
||||
ul_harq_proc::ul_alloc_t prach = {cfg.prach_freq_offset, 6};
|
||||
if(!ul_metric->update_allocation(prach)) {
|
||||
log_h->warning("SCHED: Failed to allocate PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L);
|
||||
}
|
||||
else {
|
||||
log_h->debug("SCHED: Allocated PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L);
|
||||
}
|
||||
}
|
||||
|
||||
ul_metric->new_tti(ue_db, cfg.cell.nof_prb, current_tti);
|
||||
|
||||
// Now allocate PUSCH
|
||||
|
@ -994,6 +1003,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
|
|||
}
|
||||
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
pthread_mutex_unlock(&sched_mutex);
|
||||
|
||||
sched_result->nof_dci_elems = nof_dci_elems;
|
||||
sched_result->nof_phich_elems = nof_phich_elems;
|
||||
|
|
|
@ -41,9 +41,9 @@ namespace srsenb {
|
|||
*
|
||||
* Downlink Metric
|
||||
*
|
||||
*****************************************************************/
|
||||
|
||||
uint32_t dl_metric_rr::calc_rbg_mask(bool mask[MAX_RBG])
|
||||
*****************************************************************/
|
||||
|
||||
uint32_t dl_metric_rr::calc_rbg_mask(bool mask[MAX_RBG])
|
||||
{
|
||||
// Build RBG bitmask
|
||||
uint32_t rbg_bitmask = 0;
|
||||
|
@ -301,13 +301,14 @@ bool ul_metric_rr::new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t* alloc)
|
|||
|
||||
bool ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc)
|
||||
{
|
||||
bool ret = false;
|
||||
if(allocation_is_valid(alloc)) {
|
||||
for (uint32_t n=alloc.RB_start;n<alloc.RB_start+alloc.L;n++) {
|
||||
used_rb[n] = true;
|
||||
}
|
||||
return true;
|
||||
ret = true;
|
||||
}
|
||||
return false;
|
||||
for (uint32_t n=alloc.RB_start;n<alloc.RB_start+alloc.L;n++) {
|
||||
used_rb[n] = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ul_harq_proc* ul_metric_rr::allocate_user_retx_prbs(sched_ue *user)
|
||||
|
|
|
@ -87,7 +87,7 @@ void sched_ue::set_cfg(uint16_t rnti_, sched_interface::ue_cfg_t *cfg_, sched_in
|
|||
|
||||
if (cfg_) {
|
||||
memcpy(&cfg, cfg_, sizeof(sched_interface::ue_cfg_t));
|
||||
}
|
||||
}
|
||||
|
||||
Info("SCHED: Added user rnti=0x%x\n", rnti);
|
||||
// Config HARQ processes
|
||||
|
@ -102,6 +102,7 @@ void sched_ue::set_cfg(uint16_t rnti_, sched_interface::ue_cfg_t *cfg_, sched_in
|
|||
sched::generate_cce_location(regs, &dci_locations[cfi][sf_idx], cfi+1, sf_idx, rnti);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
for (int i=0;i<sched_interface::MAX_LC;i++) {
|
||||
|
@ -498,7 +499,10 @@ int sched_ue::generate_format1(dl_harq_proc *h,
|
|||
srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb);
|
||||
uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0);
|
||||
uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols);
|
||||
if (fixed_mcs_dl < 0) {
|
||||
if(need_conres_ce and cell.nof_prb<10) { // SRB0 Tx. Use a higher MCS for the PRACH to fit in 6 PRBs
|
||||
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(4), nof_prb)/8;
|
||||
mcs = 4;
|
||||
} else if (fixed_mcs_dl < 0) {
|
||||
tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs);
|
||||
} else {
|
||||
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb)/8;
|
||||
|
@ -1206,7 +1210,6 @@ int sched_ue::alloc_tbs(uint32_t nof_prb,
|
|||
uint32_t max_Qm = is_ul?4:6; // Allow 16-QAM in PUSCH Only
|
||||
|
||||
// TODO: Compute real spectral efficiency based on PUSCH-UCI configuration
|
||||
|
||||
int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, &sel_mcs)/8;
|
||||
|
||||
/* If less bytes are requested, lower the MCS */
|
||||
|
@ -1221,6 +1224,7 @@ int sched_ue::alloc_tbs(uint32_t nof_prb,
|
|||
// Avoid the unusual case n_prb=1, mcs=6 tbs=328 (used in voip)
|
||||
if (nof_prb == 1 && sel_mcs == 6) {
|
||||
sel_mcs--;
|
||||
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(sel_mcs), nof_prb)/8;
|
||||
}
|
||||
|
||||
if (mcs && tbs >= 0) {
|
||||
|
|
|
@ -145,9 +145,7 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
bpo::value<int>(&args->expert.mac.sched.nof_ctrl_symbols)->default_value(3),
|
||||
"Number of control symbols")
|
||||
|
||||
|
||||
/* Expert section */
|
||||
|
||||
("expert.metrics_period_secs",
|
||||
bpo::value<float>(&args->expert.metrics_period_secs)->default_value(1.0),
|
||||
"Periodicity for metrics in seconds")
|
||||
|
@ -191,20 +189,22 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
("expert.rrc_inactivity_timer",
|
||||
bpo::value<uint32_t>(&args->expert.rrc_inactivity_timer)->default_value(60000),
|
||||
"Inactivity timer in ms")
|
||||
|
||||
|
||||
("expert.enable_mbsfn",
|
||||
bpo::value<bool>(&args->expert.enable_mbsfn)->default_value(false),
|
||||
"enables mbms in the enodeb")
|
||||
"Enables MBMS in the eNB")
|
||||
|
||||
("expert.print_buffer_state",
|
||||
bpo::value<bool>(&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<float>(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0), "TX DC offset gain correction")
|
||||
("rf_calibration.tx_corr_dc_phase", bpo::value<float>(&args->rf_cal.tx_corr_dc_phase)->default_value(0.0), "TX DC offset phase correction")
|
||||
("rf_calibration.tx_corr_iq_i", bpo::value<float>(&args->rf_cal.tx_corr_iq_i)->default_value(0.0), "TX IQ imbalance inphase correction")
|
||||
("rf_calibration.tx_corr_iq_q", bpo::value<float>(&args->rf_cal.tx_corr_iq_q)->default_value(0.0), "TX IQ imbalance quadrature correction")
|
||||
("expert.m1u_multiaddr",
|
||||
bpo::value<string>(&args->expert.m1u_multiaddr)->default_value("239.255.0.1"),
|
||||
"M1-U Multicast address the eNB joins.")
|
||||
|
||||
("expert.m1u_if_addr",
|
||||
bpo::value<string>(&args->expert.m1u_if_addr)->default_value("127.0.1.201"),
|
||||
"IP address of the interface the eNB will listen for M1-U traffic.")
|
||||
;
|
||||
|
||||
// Positional options - config file location
|
||||
|
|
|
@ -43,44 +43,27 @@ gtpu::gtpu():mchthread()
|
|||
|
||||
}
|
||||
|
||||
bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_interface_gtpu* pdcp_, srslte::log* gtpu_log_, bool enable_mbsfn)
|
||||
bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, std::string m1u_multiaddr_, std::string m1u_if_addr_, srsenb::pdcp_interface_gtpu* pdcp_, srslte::log* gtpu_log_, bool enable_mbsfn)
|
||||
{
|
||||
pdcp = pdcp_;
|
||||
gtpu_log = gtpu_log_;
|
||||
gtp_bind_addr = gtp_bind_addr_;
|
||||
mme_addr = mme_addr_;
|
||||
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
|
||||
// Set up sink socket
|
||||
snk_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (snk_fd < 0) {
|
||||
gtpu_log->error("Failed to create sink socket\n");
|
||||
// Set up socket
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
gtpu_log->error("Failed to create socket\n");
|
||||
return false;
|
||||
}
|
||||
int enable = 1;
|
||||
#if defined (SO_REUSEADDR)
|
||||
if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
|
||||
gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n");
|
||||
#endif
|
||||
#if defined (SO_REUSEPORT)
|
||||
if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||
gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n");
|
||||
#endif
|
||||
|
||||
|
||||
// Set up source socket
|
||||
src_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (src_fd < 0) {
|
||||
gtpu_log->error("Failed to create source socket\n");
|
||||
return false;
|
||||
}
|
||||
#if defined (SO_REUSEADDR)
|
||||
if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
|
||||
gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n");
|
||||
#endif
|
||||
#if defined (SO_REUSEPORT)
|
||||
if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||
gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n");
|
||||
#endif
|
||||
|
||||
|
@ -90,7 +73,7 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
|
|||
bindaddr.sin_addr.s_addr = inet_addr(gtp_bind_addr.c_str());
|
||||
bindaddr.sin_port = htons(GTPU_PORT);
|
||||
|
||||
if (bind(src_fd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) {
|
||||
if (bind(fd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) {
|
||||
gtpu_log->error("Failed to bind on address %s, port %d\n", gtp_bind_addr.c_str(), GTPU_PORT);
|
||||
gtpu_log->console("Failed to bind on address %s, port %d\n", gtp_bind_addr.c_str(), GTPU_PORT);
|
||||
return false;
|
||||
|
@ -102,15 +85,14 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
|
|||
// Start MCH thread if enabled
|
||||
this->enable_mbsfn = enable_mbsfn;
|
||||
if(enable_mbsfn) {
|
||||
mchthread.init(pdcp, gtpu_log);
|
||||
mchthread.init(m1u_multiaddr_, m1u_if_addr_, pdcp, gtpu_log);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void gtpu::stop()
|
||||
{
|
||||
|
||||
if(enable_mbsfn){
|
||||
if(enable_mbsfn){
|
||||
mchthread.stop();
|
||||
}
|
||||
|
||||
|
@ -128,11 +110,8 @@ void gtpu::stop()
|
|||
wait_thread_finish();
|
||||
}
|
||||
|
||||
if (snk_fd) {
|
||||
close(snk_fd);
|
||||
}
|
||||
if (src_fd) {
|
||||
close(src_fd);
|
||||
if (fd) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,8 +120,8 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu)
|
|||
{
|
||||
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU, RNTI: 0x%x, LCID: %d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
|
||||
gtpu_header_t header;
|
||||
header.flags = 0x30;
|
||||
header.message_type = 0xFF;
|
||||
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL;
|
||||
header.message_type = GTPU_MSG_DATA_PDU;
|
||||
header.length = pdu->N_bytes;
|
||||
header.teid = rnti_bearers[rnti].teids_out[lcid];
|
||||
|
||||
|
@ -151,8 +130,11 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu)
|
|||
servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]);
|
||||
servaddr.sin_port = htons(GTPU_PORT);
|
||||
|
||||
gtpu_write_header(&header, pdu, gtpu_log);
|
||||
if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) {
|
||||
if(!gtpu_write_header(&header, pdu, gtpu_log)){
|
||||
gtpu_log->error("Error writing GTP-U Header. Flags 0x%x, Message Type 0x%x\n", header.flags, header.message_type);
|
||||
return;
|
||||
}
|
||||
if (sendto(fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) {
|
||||
perror("sendto");
|
||||
}
|
||||
|
||||
|
@ -223,6 +205,10 @@ void gtpu::run_thread()
|
|||
}
|
||||
run_enable = true;
|
||||
|
||||
sockaddr_in client;
|
||||
socklen_t client_len = sizeof(client);
|
||||
size_t buflen = SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET;
|
||||
|
||||
running=true;
|
||||
while(run_enable) {
|
||||
|
||||
|
@ -230,51 +216,92 @@ void gtpu::run_thread()
|
|||
gtpu_log->debug("Waiting for read...\n");
|
||||
int n = 0;
|
||||
do{
|
||||
n = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0);
|
||||
n = recvfrom(fd, pdu->msg, buflen, 0, (struct sockaddr *)&client, &client_len);
|
||||
} while (n == -1 && errno == EAGAIN);
|
||||
|
||||
if (n < 0) {
|
||||
gtpu_log->error("Failed to read from socket\n");
|
||||
}
|
||||
|
||||
gtpu_log->debug("Received %d bytes from S1-U interface\n", n);
|
||||
pdu->N_bytes = (uint32_t) n;
|
||||
|
||||
gtpu_header_t header;
|
||||
gtpu_read_header(pdu, &header,gtpu_log);
|
||||
|
||||
uint16_t rnti = 0;
|
||||
uint16_t lcid = 0;
|
||||
teidin_to_rntilcid(header.teid, &rnti, &lcid);
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
bool user_exists = (rnti_bearers.count(rnti) > 0);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
if(!user_exists) {
|
||||
gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti);
|
||||
if(!gtpu_read_header(pdu, &header,gtpu_log)){
|
||||
continue;
|
||||
}
|
||||
|
||||
if(lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) {
|
||||
gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid);
|
||||
continue;
|
||||
switch(header.message_type) {
|
||||
|
||||
case GTPU_MSG_ECHO_REQUEST:
|
||||
// Echo request - send response
|
||||
echo_response(client.sin_addr.s_addr, client.sin_port, header.seq_number);
|
||||
break;
|
||||
|
||||
case GTPU_MSG_DATA_PDU:
|
||||
|
||||
uint16_t rnti = 0;
|
||||
uint16_t lcid = 0;
|
||||
teidin_to_rntilcid(header.teid, &rnti, &lcid);
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
bool user_exists = (rnti_bearers.count(rnti) > 0);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
if(!user_exists) {
|
||||
gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) {
|
||||
gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid);
|
||||
continue;
|
||||
}
|
||||
|
||||
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
|
||||
|
||||
pdcp->write_sdu(rnti, lcid, pdu);
|
||||
|
||||
do {
|
||||
pdu = pool_allocate;
|
||||
if (!pdu) {
|
||||
gtpu_log->console("GTPU Buffer pool empty. Trying again...\n");
|
||||
usleep(10000);
|
||||
}
|
||||
} while(!pdu);
|
||||
break;
|
||||
}
|
||||
|
||||
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
|
||||
|
||||
pdcp->write_sdu(rnti, lcid, pdu);
|
||||
|
||||
do {
|
||||
pdu = pool_allocate;
|
||||
if (!pdu) {
|
||||
gtpu_log->console("GTPU Buffer pool empty. Trying again...\n");
|
||||
usleep(10000);
|
||||
}
|
||||
} while(!pdu);
|
||||
}
|
||||
running = false;
|
||||
}
|
||||
|
||||
void gtpu::echo_response(in_addr_t addr, in_port_t port, uint16_t seq)
|
||||
{
|
||||
gtpu_log->info("TX GTPU Echo Response, Seq: %d\n", seq);
|
||||
|
||||
gtpu_header_t header;
|
||||
srslte::byte_buffer_t *pdu = pool_allocate;
|
||||
|
||||
//header
|
||||
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL | GTPU_FLAGS_SEQUENCE;
|
||||
header.message_type = GTPU_MSG_ECHO_RESPONSE;
|
||||
header.teid = 0;
|
||||
header.length = 4;
|
||||
header.seq_number = seq;
|
||||
header.n_pdu = 0;
|
||||
header.next_ext_hdr_type = 0;
|
||||
|
||||
gtpu_write_header(&header,pdu,gtpu_log);
|
||||
|
||||
struct sockaddr_in servaddr;
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = addr;
|
||||
servaddr.sin_port = port;
|
||||
|
||||
sendto(fd, pdu->msg, 12, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in));
|
||||
pool->deallocate(pdu);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* TEID to RNIT/LCID helper functions
|
||||
***************************************************************************/
|
||||
|
@ -293,14 +320,16 @@ void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin)
|
|||
/****************************************************************************
|
||||
* Class to run the MCH thread
|
||||
***************************************************************************/
|
||||
bool gtpu::mch_thread::init(pdcp_interface_gtpu *pdcp, srslte::log *gtpu_log)
|
||||
bool gtpu::mch_thread::init(std::string m1u_multiaddr_, std::string m1u_if_addr_, pdcp_interface_gtpu *pdcp, srslte::log *gtpu_log)
|
||||
{
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
this->pdcp = pdcp;
|
||||
this->gtpu_log = gtpu_log;
|
||||
m1u_multiaddr = m1u_multiaddr_;
|
||||
m1u_if_addr = m1u_if_addr_;
|
||||
|
||||
struct sockaddr_in bindaddr;
|
||||
|
||||
|
||||
// Set up sink socket
|
||||
m1u_sd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (m1u_sd < 0) {
|
||||
|
@ -322,11 +351,12 @@ bool gtpu::mch_thread::init(pdcp_interface_gtpu *pdcp, srslte::log *gtpu_log)
|
|||
|
||||
/* Send an ADD MEMBERSHIP message via setsockopt */
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = inet_addr("239.255.0.1"); //Multicast address of the service
|
||||
mreq.imr_interface.s_addr = inet_addr("127.0.1.200"); //Address of the IF the socket will listen to.
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(m1u_multiaddr.c_str()); //Multicast address of the service
|
||||
mreq.imr_interface.s_addr = inet_addr(m1u_if_addr.c_str()); //Address of the IF the socket will listen to.
|
||||
if (setsockopt(m1u_sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
&mreq, sizeof(mreq)) < 0) {
|
||||
gtpu_log->error("Register musticast group for M1-U\n");
|
||||
gtpu_log->error("M1-U infterface IP: %s, M1-U Multicast Address %s\n", m1u_if_addr.c_str(),m1u_multiaddr.c_str());
|
||||
return false;
|
||||
}
|
||||
gtpu_log->info("M1-U initialized\n");
|
||||
|
@ -372,12 +402,12 @@ void gtpu::mch_thread::run_thread()
|
|||
do{
|
||||
n = recvfrom(m1u_sd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0, (struct sockaddr *) &src_addr, &addrlen);
|
||||
} while (n == -1 && errno == EAGAIN);
|
||||
gtpu_log->debug("Received %d bytes from M1-U interface\n", n);
|
||||
|
||||
pdu->N_bytes = (uint32_t) n;
|
||||
|
||||
|
||||
gtpu_header_t header;
|
||||
gtpu_read_header(pdu, &header, gtpu_log);
|
||||
|
||||
pdcp->write_sdu(SRSLTE_MRNTI, lcid, pdu);
|
||||
do {
|
||||
pdu = pool_allocate;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,13 +40,16 @@ db_file = user_db.csv
|
|||
#####################################################################
|
||||
# SP-GW configuration
|
||||
#
|
||||
# gtpu_bind_addr: GTP-U bind adress.
|
||||
# gtpu_bind_addr: GTP-U bind address.
|
||||
# sgi_if_addr: SGi TUN interface IP address.
|
||||
# sgi_if_name: SGi TUN interface name.
|
||||
#
|
||||
#####################################################################
|
||||
|
||||
[spgw]
|
||||
gtpu_bind_addr = 127.0.1.100
|
||||
sgi_if_addr = 172.16.0.1
|
||||
sgi_if_name = srs_spgw_sgi
|
||||
|
||||
####################################################################
|
||||
# PCAP configuration
|
||||
|
|
|
@ -48,9 +48,12 @@ const uint16_t GTPU_RX_PORT = 2152;
|
|||
|
||||
typedef struct {
|
||||
std::string name;
|
||||
std::string sgi_mb_if_name;
|
||||
std::string sgi_mb_if_addr;
|
||||
std::string sgi_mb_if_mask;
|
||||
std::string m1u_multi_addr;
|
||||
std::string m1u_multi_if;
|
||||
int m1u_multi_ttl;
|
||||
} mbms_gw_args_t;
|
||||
|
||||
struct pseudo_hdr
|
||||
|
|
|
@ -50,6 +50,7 @@ const uint16_t GTPU_RX_PORT = 2152;
|
|||
typedef struct {
|
||||
std::string gtpu_bind_addr;
|
||||
std::string sgi_if_addr;
|
||||
std::string sgi_if_name;
|
||||
} spgw_args_t;
|
||||
|
||||
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
#####################################################################
|
||||
# srsEPC configuration file
|
||||
# srsMBMS configuration file
|
||||
#####################################################################
|
||||
|
||||
#####################################################################
|
||||
# MBMS-GW configuration
|
||||
#
|
||||
# name: MBMS-GW name
|
||||
# sgi_mb_if_name: SGi-mb TUN interface name
|
||||
# sgi_mb_if_addr: SGi-mb interface IP address
|
||||
# m1u_addr: Multicast group for eNBs (FIXME this should be setup with M2/M3)
|
||||
# sgi_mb_if_mask: SGi-mb interface IP mask
|
||||
# m1u_multi_addr: Multicast group for eNBs (FIXME this should be setup with M2/M3)
|
||||
# m1u_multi_if: IP of local interface for multicast traffic
|
||||
# m1u_multi_ttl: TTL for M1-U multicast traffic
|
||||
#
|
||||
#####################################################################
|
||||
[mbms_gw]
|
||||
name = srsmbmsgw01
|
||||
sgi_mb_if_name = sgi_mb
|
||||
sgi_mb_if_addr = 172.16.0.254
|
||||
sgi_mb_if_mask = 255.255.255.255
|
||||
m1u_multi_addr = 239.255.0.1
|
||||
m1u_multi_if = 127.0.1.200
|
||||
m1u_multi_ttl = 1
|
||||
|
||||
####################################################################
|
||||
# Log configuration
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
@ -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"
|
||||
|
@ -87,6 +89,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
string mme_apn;
|
||||
string spgw_bind_addr;
|
||||
string sgi_if_addr;
|
||||
string sgi_if_name;
|
||||
string dns_addr;
|
||||
string hss_db_file;
|
||||
string hss_auth_algo;
|
||||
|
@ -116,6 +119,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"), "HSS uthentication algorithm.")
|
||||
("spgw.gtpu_bind_addr", bpo::value<string>(&spgw_bind_addr)->default_value("127.0.0.1"), "IP address of SP-GW for the S1-U connection")
|
||||
("spgw.sgi_if_addr", bpo::value<string>(&sgi_if_addr)->default_value("176.16.0.1"), "IP address of TUN interface for the SGi connection")
|
||||
("spgw.sgi_if_name", bpo::value<string>(&sgi_if_name)->default_value("srs_spgw_sgi"), "Name of TUN interface for the SGi connection")
|
||||
|
||||
("pcap.enable", bpo::value<bool>(&args->mme_args.s1ap_args.pcap_enable)->default_value(false), "Enable S1AP PCAP")
|
||||
("pcap.filename", bpo::value<string>(&args->mme_args.s1ap_args.pcap_filename)->default_value("/tmp/epc.pcap"), "PCAP filename")
|
||||
|
@ -221,6 +225,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
args->mme_args.s1ap_args.mme_apn = mme_apn;
|
||||
args->spgw_args.gtpu_bind_addr = spgw_bind_addr;
|
||||
args->spgw_args.sgi_if_addr = sgi_if_addr;
|
||||
args->spgw_args.sgi_if_name = sgi_if_name;
|
||||
args->hss_args.db_file = hss_db_file;
|
||||
args->hss_args.auth_algo = hss_auth_algo;
|
||||
|
||||
|
@ -290,6 +295,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[] )
|
||||
{
|
||||
|
@ -297,6 +322,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);
|
||||
|
||||
|
@ -312,6 +340,8 @@ main (int argc,char * argv[] )
|
|||
logger = &logger_stdout;
|
||||
} else {
|
||||
logger_file.init(args.log_args.filename);
|
||||
logger_file.log("\n\n");
|
||||
logger_file.log(get_build_string().c_str());
|
||||
logger_file.log("\n--- Software Radio Systems EPC log ---\n\n");
|
||||
logger = &logger_file;
|
||||
}
|
||||
|
|
|
@ -82,9 +82,11 @@ void
|
|||
parse_args(all_args_t *args, int argc, char* argv[]) {
|
||||
|
||||
string mbms_gw_name;
|
||||
string mbms_gw_sgi_mb_if_name;
|
||||
string mbms_gw_sgi_mb_if_addr;
|
||||
string mbms_gw_sgi_mb_if_mask;
|
||||
string mbms_gw_m1u_multi_addr;
|
||||
string mbms_gw_m1u_multi_if;
|
||||
|
||||
string log_filename;
|
||||
|
||||
|
@ -100,9 +102,12 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
common.add_options()
|
||||
|
||||
("mbms_gw.name", bpo::value<string>(&mbms_gw_name)->default_value("srsmbmsgw01"), "MBMS-GW Name")
|
||||
("mbms_gw.sgi_mb_if_name", bpo::value<string>(&mbms_gw_sgi_mb_if_name)->default_value("sgi_mb"), "SGi-mb TUN interface Address.")
|
||||
("mbms_gw.sgi_mb_if_addr", bpo::value<string>(&mbms_gw_sgi_mb_if_addr)->default_value("172.16.1.1"), "SGi-mb TUN interface Address.")
|
||||
("mbms_gw.sgi_mb_if_mask", bpo::value<string>(&mbms_gw_sgi_mb_if_mask)->default_value("255.255.255.255"), "SGi-mb TUN interface mask.")
|
||||
("mbms_gw.m1u_multi_addr", bpo::value<string>(&mbms_gw_m1u_multi_addr)->default_value("239.255.0.1"), "M1-u GTPu destination multicast address.")
|
||||
("mbms_gw.m1u_multi_if", bpo::value<string>(&mbms_gw_m1u_multi_if)->default_value("127.0.1.200"), "Local interface IP for M1-U multicast packets.")
|
||||
("mbms_gw.m1u_multi_ttl", bpo::value<int>(&args->mbms_gw_args.m1u_multi_ttl)->default_value(1), "TTL for M1-U multicast packets.")
|
||||
|
||||
("log.all_level", bpo::value<string>(&args->log_args.all_level)->default_value("info"), "ALL log level")
|
||||
("log.all_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit")
|
||||
|
@ -153,9 +158,11 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
bpo::notify(vm);
|
||||
|
||||
args->mbms_gw_args.name = mbms_gw_name;
|
||||
args->mbms_gw_args.sgi_mb_if_name = mbms_gw_sgi_mb_if_name;
|
||||
args->mbms_gw_args.sgi_mb_if_addr = mbms_gw_sgi_mb_if_addr;
|
||||
args->mbms_gw_args.sgi_mb_if_mask = mbms_gw_sgi_mb_if_mask;
|
||||
args->mbms_gw_args.m1u_multi_addr = mbms_gw_m1u_multi_addr;
|
||||
args->mbms_gw_args.m1u_multi_if = mbms_gw_m1u_multi_if;
|
||||
|
||||
// Apply all_level to any unset layers
|
||||
if (vm.count("log.all_level")) {
|
||||
|
|
|
@ -126,7 +126,6 @@ mbms_gw::stop()
|
|||
srslte::error_t
|
||||
mbms_gw::init_sgi_mb_if(mbms_gw_args_t *args)
|
||||
{
|
||||
char dev[IFNAMSIZ] = "sgi_mb";
|
||||
struct ifreq ifr;
|
||||
|
||||
if(m_sgi_mb_up)
|
||||
|
@ -138,22 +137,22 @@ mbms_gw::init_sgi_mb_if(mbms_gw_args_t *args)
|
|||
// Construct the TUN device
|
||||
m_sgi_mb_if = open("/dev/net/tun", O_RDWR);
|
||||
m_mbms_gw_log->info("TUN file descriptor = %d\n", m_sgi_mb_if);
|
||||
if(m_sgi_mb_if < 0)
|
||||
{
|
||||
if (m_sgi_mb_if < 0) {
|
||||
m_mbms_gw_log->error("Failed to open TUN device: %s\n", strerror(errno));
|
||||
return(srslte::ERROR_CANT_START);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ-1);
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, args->sgi_mb_if_name.c_str(), std::min(args->sgi_mb_if_name.length(), (size_t)IFNAMSIZ-1) );
|
||||
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0';
|
||||
|
||||
if(ioctl(m_sgi_mb_if, TUNSETIFF, &ifr) < 0)
|
||||
{
|
||||
m_mbms_gw_log->error("Failed to set TUN device name: %s\n", strerror(errno));
|
||||
close(m_sgi_mb_if);
|
||||
return(srslte::ERROR_CANT_START);
|
||||
if (ioctl(m_sgi_mb_if, TUNSETIFF, &ifr) < 0) {
|
||||
m_mbms_gw_log->error("Failed to set TUN device name: %s\n", strerror(errno));
|
||||
close(m_sgi_mb_if);
|
||||
return(srslte::ERROR_CANT_START);
|
||||
} else {
|
||||
m_mbms_gw_log->debug("Set TUN device name: %s\n", args->sgi_mb_if_name.c_str());
|
||||
}
|
||||
|
||||
// Bring up the interface
|
||||
|
@ -234,11 +233,18 @@ mbms_gw::init_m1_u(mbms_gw_args_t *args)
|
|||
/* Set local interface for outbound multicast packets*/
|
||||
/* The IP must be associated with a local multicast capable interface */
|
||||
struct in_addr local_if;
|
||||
local_if.s_addr = inet_addr("127.0.1.200");
|
||||
local_if.s_addr = inet_addr(args->m1u_multi_if.c_str());
|
||||
if(setsockopt(m_m1u, IPPROTO_IP, IP_MULTICAST_IF, (char*)&local_if, sizeof(struct in_addr))<0){
|
||||
perror("Error setting multicast interface.\n");
|
||||
m_mbms_gw_log->error("Error %s setting multicast interface %s.\n", strerror(errno), args->m1u_multi_if.c_str());
|
||||
return srslte::ERROR_CANT_START;
|
||||
} else {
|
||||
printf("Multicast interface specified.\n");
|
||||
printf("Multicast interface specified. Address: %s\n", args->m1u_multi_if.c_str());
|
||||
}
|
||||
|
||||
/*Set Multicast TTL*/
|
||||
if ( setsockopt(m_m1u, IPPROTO_IP,IP_MULTICAST_TTL,&args->m1u_multi_ttl,sizeof(args->m1u_multi_ttl)) <0 ) {
|
||||
perror("Error setting multicast ttl.\n");
|
||||
return srslte::ERROR_CANT_START;
|
||||
}
|
||||
|
||||
bzero(&m_m1u_multi_addr,sizeof(m_m1u_multi_addr));
|
||||
|
@ -287,29 +293,26 @@ mbms_gw::handle_sgi_md_pdu(srslte::byte_buffer_t *msg)
|
|||
srslte::gtpu_header_t header;
|
||||
|
||||
//Setup GTP-U header
|
||||
header.flags = 0x30;
|
||||
header.message_type = 0xFF;
|
||||
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL;
|
||||
header.message_type = GTPU_MSG_DATA_PDU;
|
||||
header.length = msg->N_bytes;
|
||||
header.teid = 0xAAAA; //FIXME Harcoded TEID for now
|
||||
|
||||
//Sanity Check IP packet
|
||||
if(msg->N_bytes < 20)
|
||||
{
|
||||
if (msg->N_bytes < 20) {
|
||||
m_mbms_gw_log->error("IPv4 min len: %d, drop msg len %d\n", 20, msg->N_bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
//IP Headers
|
||||
struct iphdr *iph = (struct iphdr *) msg->msg;
|
||||
if(iph->version != 4)
|
||||
{
|
||||
if(iph->version != 4) {
|
||||
m_mbms_gw_log->warning("IPv6 not supported yet.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//Write GTP-U header into packet
|
||||
if(!srslte::gtpu_write_header(&header, msg, m_mbms_gw_log))
|
||||
{
|
||||
if (!srslte::gtpu_write_header(&header, msg, m_mbms_gw_log)) {
|
||||
m_mbms_gw_log->console("Error writing GTP-U header on PDU\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -157,7 +157,6 @@ spgw::stop()
|
|||
srslte::error_t
|
||||
spgw::init_sgi_if(spgw_args_t *args)
|
||||
{
|
||||
char dev[IFNAMSIZ] = "srs_spgw_sgi";
|
||||
struct ifreq ifr;
|
||||
|
||||
if (m_sgi_up) {
|
||||
|
@ -175,7 +174,7 @@ spgw::init_sgi_if(spgw_args_t *args)
|
|||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ-1);
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, args->sgi_if_name.c_str(), std::min(args->sgi_if_name.length(), (size_t)(IFNAMSIZ-1)));
|
||||
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0';
|
||||
|
||||
if (ioctl(m_sgi_if, TUNSETIFF, &ifr) < 0) {
|
||||
|
@ -344,8 +343,8 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
|
|||
|
||||
//Setup GTP-U header
|
||||
srslte::gtpu_header_t header;
|
||||
header.flags = 0x30;
|
||||
header.message_type = 0xFF;
|
||||
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL;
|
||||
header.message_type = GTPU_MSG_DATA_PDU;
|
||||
header.length = msg->N_bytes;
|
||||
header.teid = enb_fteid.teid;
|
||||
|
||||
|
|
|
@ -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<srslte::log_filter*> log_vec;
|
||||
|
|
|
@ -111,6 +111,7 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
std::string ip_netmask;
|
||||
std::string ip_devname;
|
||||
phy_args_t phy;
|
||||
float metrics_period_secs;
|
||||
bool pregenerate_signals;
|
||||
|
@ -122,7 +123,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;
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
|
||||
void get_metrics(gw_metrics_t &m);
|
||||
void set_netmask(std::string netmask);
|
||||
void set_tundevname(const std::string & devname);
|
||||
|
||||
// PDCP interface
|
||||
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu);
|
||||
|
@ -67,6 +68,7 @@ private:
|
|||
|
||||
bool default_netmask;
|
||||
std::string netmask;
|
||||
std::string tundevname;
|
||||
|
||||
static const int GW_THREAD_PRIO = 7;
|
||||
|
||||
|
|
|
@ -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<MAX_LCID;i++) {
|
||||
lcg[i] = -1;
|
||||
priorities[i] = -1;
|
||||
last_pending_data[i] = 0;
|
||||
}
|
||||
lcg[0] = 0;
|
||||
priorities[0] = 99;
|
||||
}
|
||||
|
||||
void bsr_proc::init(rlc_interface_mac *rlc_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers *timers_db_)
|
||||
|
@ -68,15 +75,8 @@ void bsr_proc::reset()
|
|||
|
||||
reset_sr = false;
|
||||
sr_is_sent = false;
|
||||
triggered_bsr_type = NONE;
|
||||
for (int i=0;i<MAX_LCID;i++) {
|
||||
lcg[i] = -1;
|
||||
priorities[i] = -1;
|
||||
last_pending_data[i] = 0;
|
||||
}
|
||||
lcg[0] = 0;
|
||||
priorities[0] = 99;
|
||||
next_tx_tti = 0;
|
||||
triggered_bsr_type = NONE;
|
||||
next_tx_tti = 0;
|
||||
}
|
||||
|
||||
/* Process Periodic BSR */
|
||||
|
|
|
@ -90,13 +90,11 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
|
|||
("nas.pass", bpo::value<string>(&args->nas.apn_pass)->default_value(""), "Password for CHAP authentication")
|
||||
("nas.force_imsi_attach", bpo::value<bool>(&args->nas.force_imsi_attach)->default_value(false), "Whether to always perform an IMSI attach")
|
||||
|
||||
|
||||
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
|
||||
("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")
|
||||
("pcap.nas_enable", bpo::value<bool>(&args->pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark")
|
||||
("pcap.nas_filename", bpo::value<string>(&args->pcap.nas_filename)->default_value("ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)")
|
||||
|
||||
|
||||
("trace.enable", bpo::value<bool>(&args->trace.enable)->default_value(false), "Enable PHY and radio timing traces")
|
||||
("trace.phy_filename", bpo::value<string>(&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<string>(&args->log.usim_level), "USIM log level")
|
||||
("log.usim_hex_limit", bpo::value<int>(&args->log.usim_hex_limit), "USIM log hex dump limit")
|
||||
|
||||
|
||||
("log.all_level", bpo::value<string>(&args->log.all_level)->default_value("info"), "ALL log level")
|
||||
("log.all_hex_limit", bpo::value<int>(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit")
|
||||
|
||||
|
@ -145,6 +142,10 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
|
|||
bpo::value<string>(&args->expert.ip_netmask)->default_value("255.255.255.0"),
|
||||
"Netmask of the tun_srsue device")
|
||||
|
||||
("expert.ip_devname",
|
||||
bpo::value<string>(&args->expert.ip_devname)->default_value("tun_srsue"),
|
||||
"Name of the tun_srsue device")
|
||||
|
||||
("expert.mbms_service",
|
||||
bpo::value<int>(&args->expert.mbms_service)->default_value(-1),
|
||||
"automatically starts an mbms service of the number given")
|
||||
|
@ -309,16 +310,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
|
|||
|
||||
("expert.pdsch_8bit_decoder",
|
||||
bpo::value<bool>(&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<float>(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0),
|
||||
"TX DC offset gain correction")
|
||||
("rf_calibration.tx_corr_dc_phase", bpo::value<float>(&args->rf_cal.tx_corr_dc_phase)->default_value(0.0),
|
||||
"TX DC offset phase correction")
|
||||
("rf_calibration.tx_corr_iq_i", bpo::value<float>(&args->rf_cal.tx_corr_iq_i)->default_value(0.0),
|
||||
"TX IQ imbalance inphase correction")
|
||||
("rf_calibration.tx_corr_iq_q", bpo::value<float>(&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");
|
||||
|
|
|
@ -463,11 +463,6 @@ void phch_worker::work_imp()
|
|||
|
||||
tr_log_end();
|
||||
|
||||
if (next_offset > 0) {
|
||||
phy->worker_end(tx_tti, signal_ready, signal_ptr, SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
|
||||
} else {
|
||||
phy->worker_end(tx_tti, signal_ready, &signal_ptr[-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
|
||||
}
|
||||
|
||||
if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type) {
|
||||
if (!dl_action.generate_ack_callback) {
|
||||
|
@ -491,6 +486,13 @@ void phch_worker::work_imp()
|
|||
phy->set_mch_period_stop(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (next_offset > 0) {
|
||||
phy->worker_end(tx_tti, signal_ready, signal_ptr, SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
|
||||
} else {
|
||||
phy->worker_end(tx_tti, signal_ready, &signal_ptr[-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
|
||||
}
|
||||
|
||||
if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type){
|
||||
update_measurements();
|
||||
}
|
||||
|
@ -1269,6 +1271,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");
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -228,6 +225,7 @@ bool ue::init(all_args_t *args_) {
|
|||
nas.init(usim, &rrc, &gw, &nas_log, nas_cfg);
|
||||
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
|
||||
gw.set_netmask(args->expert.ip_netmask);
|
||||
gw.set_tundevname(args->expert.ip_devname);
|
||||
|
||||
// Get current band from provided EARFCN
|
||||
args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn);
|
||||
|
|
|
@ -45,6 +45,7 @@ gw::gw()
|
|||
{
|
||||
current_ip_addr = 0;
|
||||
default_netmask = true;
|
||||
tundevname = "";
|
||||
}
|
||||
|
||||
void gw::init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_log_, srslte::srslte_gw_config_t cfg_)
|
||||
|
@ -125,6 +126,11 @@ void gw::set_netmask(std::string netmask)
|
|||
this->netmask = netmask;
|
||||
}
|
||||
|
||||
void gw::set_tundevname(const std::string & devname)
|
||||
{
|
||||
tundevname = devname;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
PDCP interface
|
||||
|
@ -242,8 +248,6 @@ srslte::error_t gw::init_if(char *err_str)
|
|||
return(srslte::ERROR_ALREADY_STARTED);
|
||||
}
|
||||
|
||||
char dev[IFNAMSIZ] = "tun_srsue";
|
||||
|
||||
// Construct the TUN device
|
||||
tun_fd = open("/dev/net/tun", O_RDWR);
|
||||
gw_log->info("TUN file descriptor = %d\n", tun_fd);
|
||||
|
@ -255,7 +259,7 @@ srslte::error_t gw::init_if(char *err_str)
|
|||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ-1);
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, tundevname.c_str(), std::min(tundevname.length(), (size_t)(IFNAMSIZ-1)));
|
||||
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0;
|
||||
if(0 > ioctl(tun_fd, TUNSETIFF, &ifr))
|
||||
{
|
||||
|
@ -309,7 +313,7 @@ void gw::run_thread()
|
|||
struct iphdr *ip_pkt;
|
||||
uint32 idx = 0;
|
||||
int32 N_bytes;
|
||||
srslte::byte_buffer_t *pdu = pool_allocate;
|
||||
srslte::byte_buffer_t *pdu = pool_allocate_blocking;
|
||||
if (!pdu) {
|
||||
gw_log->error("Fatal Error: Couldn't allocate PDU in run_thread().\n");
|
||||
return;
|
||||
|
|
|
@ -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);
|
||||
|
@ -1489,7 +1490,7 @@ void nas::send_esm_information_response(const uint8 proc_transaction_id) {
|
|||
esm_info_resp.protocol_cnfg_opts_present = false;
|
||||
}
|
||||
|
||||
byte_buffer_t *pdu = pool_allocate;
|
||||
byte_buffer_t *pdu = pool_allocate_blocking;
|
||||
if (!pdu) {
|
||||
nas_log->error("Fatal Error: Couldn't allocate PDU in send_attach_request().\n");
|
||||
return;
|
||||
|
|
|
@ -1398,7 +1398,7 @@ void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) {
|
|||
void rrc::send_ul_info_transfer(byte_buffer_t *nas_msg) {
|
||||
bzero(&ul_dcch_msg, sizeof(LIBLTE_RRC_UL_DCCH_MSG_STRUCT));
|
||||
|
||||
rrc_log->debug("Preparing RX Info Transfer\n");
|
||||
rrc_log->debug("Preparing UL Info Transfer\n");
|
||||
|
||||
// Prepare RX INFO packet
|
||||
ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER;
|
||||
|
@ -1582,7 +1582,7 @@ bool rrc::con_reconfig(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig) {
|
|||
|
||||
byte_buffer_t *nas_sdu;
|
||||
for (uint32_t i = 0; i < reconfig->N_ded_info_nas; i++) {
|
||||
nas_sdu = pool_allocate;
|
||||
nas_sdu = pool_allocate_blocking;
|
||||
if (nas_sdu) {
|
||||
memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes);
|
||||
nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes;
|
||||
|
@ -1887,7 +1887,7 @@ byte_buffer_t* rrc::byte_align_and_pack()
|
|||
}
|
||||
|
||||
// Reset and reuse sdu buffer if provided
|
||||
byte_buffer_t *pdcp_buf = pool_allocate;
|
||||
byte_buffer_t *pdcp_buf = pool_allocate_blocking;
|
||||
if (pdcp_buf) {
|
||||
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
||||
pdcp_buf->N_bytes = bit_buf.N_bits / 8;
|
||||
|
@ -2051,7 +2051,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
|
||||
switch (dl_dcch_msg.msg_type) {
|
||||
case LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER:
|
||||
pdu = pool_allocate;
|
||||
pdu = pool_allocate_blocking;
|
||||
if (!pdu) {
|
||||
rrc_log->error("Fatal error: out of buffers in pool\n");
|
||||
return;
|
||||
|
|
|
@ -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
|
||||
|
@ -173,6 +175,7 @@ int security_command_test()
|
|||
nas.write_pdu(LCID, tmp);
|
||||
|
||||
// TODO: add check for authentication response
|
||||
rrc_dummy.reset();
|
||||
|
||||
// reuse buffer for security mode command
|
||||
memcpy(tmp->msg, sec_mode_command_pdu, sizeof(sec_mode_command_pdu));
|
||||
|
@ -218,6 +221,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 +231,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 +286,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
|
||||
|
|
|
@ -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.
|
||||
|
@ -137,6 +137,7 @@ enable = false
|
|||
# Expert configuration options
|
||||
#
|
||||
# ip_netmask: Netmask of the tun_srsue device. Default: 255.255.255.0
|
||||
# ip_devname: Nanme of the tun_srsue device. Default: tun_srsue
|
||||
# rssi_sensor_enabled: Enable or disable RF frontend RSSI sensor. Required for RSRP metrics but
|
||||
# can cause UHD instability for long-duration testing. Default true.
|
||||
# rx_gain_offset: RX Gain offset to add to rx_gain to calibrate RSRP readings
|
||||
|
@ -209,6 +210,7 @@ enable = false
|
|||
#####################################################################
|
||||
[expert]
|
||||
#ip_netmask = 255.255.255.0
|
||||
#ip_devname = tun_srsue
|
||||
#mbms_service = -1
|
||||
#rssi_sensor_enabled = false
|
||||
#rx_gain_offset = 62
|
||||
|
@ -249,21 +251,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
|
||||
|
|
Loading…
Reference in New Issue