Merging next into guti_attach branch

master
Pedro Alvarez 7 years ago
commit c6e2f144d7

@ -371,7 +371,7 @@ if(RF_FOUND)
message(STATUS "Building with srsENB") message(STATUS "Building with srsENB")
add_subdirectory(srsenb) add_subdirectory(srsenb)
else(ENABLE_SRSENB) else(ENABLE_SRSENB)
message(STATUS "srsUE build disabled") message(STATUS "srsENB build disabled")
endif(ENABLE_SRSENB) endif(ENABLE_SRSENB)
else(RF_FOUND) else(RF_FOUND)
message(STATUS "srsUE and srsENB builds disabled due to missing RF driver") message(STATUS "srsUE and srsENB builds disabled due to missing RF driver")

@ -162,8 +162,8 @@ void usage(prog_args_t *args, char *prog) {
printf("\t-r RNTI in Hex [Default 0x%x]\n",args->rnti); printf("\t-r RNTI in Hex [Default 0x%x]\n",args->rnti);
printf("\t-l Force N_id_2 [Default best]\n"); printf("\t-l Force N_id_2 [Default best]\n");
printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo?"Disabled":"Enabled"); printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo?"Disabled":"Enabled");
printf("\t-F Enable RS-based CFO correction [Default %s]\n", args->enable_cfo_ref?"Disabled":"Enabled"); printf("\t-F Enable RS-based CFO correction [Default %s]\n", !args->enable_cfo_ref?"Disabled":"Enabled");
printf("\t-R Average channel estimates on 1 ms [Default %s]\n", args->average_subframe?"Disabled":"Enabled"); printf("\t-R Average channel estimates on 1 ms [Default %s]\n", !args->average_subframe?"Disabled":"Enabled");
printf("\t-t Add time offset [Default %d]\n", args->time_offset); printf("\t-t Add time offset [Default %d]\n", args->time_offset);
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n"); printf("\t-d disable plots [Default enabled]\n");

@ -99,7 +99,6 @@ public:
if (is_almost_empty()) { if (is_almost_empty()) {
printf("Warning buffer pool capacity is %f %%\n", (float) 100*available.size()/capacity); printf("Warning buffer pool capacity is %f %%\n", (float) 100*available.size()/capacity);
print_all_buffers();
} }
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
if (debug_name) { if (debug_name) {

@ -70,6 +70,7 @@ public:
level = LOG_LEVEL_NONE; level = LOG_LEVEL_NONE;
hex_limit = 0; hex_limit = 0;
show_layer_en = true; show_layer_en = true;
add_string_en = false;
level_text_short = true; level_text_short = true;
} }
@ -79,6 +80,7 @@ public:
level = LOG_LEVEL_NONE; level = LOG_LEVEL_NONE;
hex_limit = 0; hex_limit = 0;
show_layer_en = true; show_layer_en = true;
add_string_en = false;
level_text_short = true; level_text_short = true;
} }

@ -51,7 +51,10 @@
class thread class thread
{ {
public: public:
thread() {
_thread = 0;
}
bool start(int prio = -1) { bool start(int prio = -1) {
return threads_new_rt_prio(&_thread, thread_function_entry, this, prio); return threads_new_rt_prio(&_thread, thread_function_entry, this, prio);
} }

@ -0,0 +1,18 @@
#ifndef EPC_INTERFACE_H
#define EPC_INTERFACE_H
#include "srslte/srslte.h"
#include "srslte/common/common.h"
namespace srsepc {
class hss_interface_s1ap
{
public:
virtual bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres) = 0;
virtual bool resync_sqn(uint64_t imsi, uint8_t *auts) = 0;
};
}
#endif // ENB_METRICS_INTERFACE_H

@ -101,6 +101,7 @@ namespace srslte {
void set_tx_freq(double freq); void set_tx_freq(double freq);
void set_rx_freq(double freq); void set_rx_freq(double freq);
double get_freq_offset();
double get_tx_freq(); double get_tx_freq();
double get_rx_freq(); double get_rx_freq();

@ -55,9 +55,9 @@ public:
void init(srsue::pdcp_interface_rlc *pdcp_, void init(srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_, srsue::rrc_interface_rlc *rrc_,
srsue::ue_interface *ue_, srsue::ue_interface *ue_,
log *rlc_log_, log *rlc_log_,
mac_interface_timers *mac_timers_, mac_interface_timers *mac_timers_,
uint32_t lcid_); uint32_t lcid_);
void stop(); void stop();
void get_metrics(rlc_metrics_t &m); void get_metrics(rlc_metrics_t &m);

@ -40,7 +40,7 @@
namespace srslte { namespace srslte {
#undef RLC_AM_BUFFER_DEBUG
struct rlc_amd_rx_pdu_t{ struct rlc_amd_rx_pdu_t{
rlc_amd_pdu_header_t header; rlc_amd_pdu_header_t header;
@ -189,6 +189,7 @@ private:
bool inside_tx_window(uint16_t sn); bool inside_tx_window(uint16_t sn);
bool inside_rx_window(uint16_t sn); bool inside_rx_window(uint16_t sn);
void debug_state(); void debug_state();
void print_rx_segments();
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment); bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment);
int required_buffer_size(rlc_amd_retx_t retx); int required_buffer_size(rlc_amd_retx_t retx);

@ -36,6 +36,8 @@ namespace srslte{
logger_file::logger_file() logger_file::logger_file()
:inited(false) :inited(false)
,not_done(true) ,not_done(true)
,cur_length(0)
,max_length(0)
{} {}
logger_file::~logger_file() { logger_file::~logger_file() {
@ -48,11 +50,11 @@ logger_file::~logger_file() {
} }
} }
void logger_file::init(std::string file, int max_length) { void logger_file::init(std::string file, int max_length_) {
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&not_empty, NULL); pthread_cond_init(&not_empty, NULL);
pthread_cond_init(&not_full, NULL); pthread_cond_init(&not_full, NULL);
this->max_length = max_length*1024; max_length = max_length_*1024;
name_idx = 0; name_idx = 0;
filename = file; filename = file;
logfile = fopen(filename.c_str(), "w"); logfile = fopen(filename.c_str(), "w");

@ -282,10 +282,14 @@ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslt
/* Compute average power. Normalized for filter len 3 using matlab */ /* Compute average power. Normalized for filter len 3 using matlab */
float norm = 1; float norm = 1;
if (q->smooth_filter_len == 3) { if (q->average_subframe) {
float a = q->smooth_filter[0]; norm = 32;
float norm3 = 6.143*a*a+0.04859*a-0.002774; } else {
norm /= norm3; if (q->smooth_filter_len == 3) {
float a = q->smooth_filter[0];
float norm3 = 6.143*a*a+0.04859*a-0.002774;
norm /= norm3;
}
} }
float power = norm*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_noise, nref); float power = norm*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_noise, nref);
return power; return power;
@ -539,8 +543,7 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
/* Compute RSRP for the channel estimates in this port */ /* Compute RSRP for the channel estimates in this port */
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
float energy = cabsf(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots); q->rsrp[rxant_id][port_id] = __real__ srslte_vec_dot_prod_conj_ccc(q->pilot_estimates, q->pilot_estimates, npilots) / npilots;
q->rsrp[rxant_id][port_id] = energy*energy;
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);
} }

@ -176,7 +176,7 @@ void print_uint8x16_t(char *s, uint8x16_t val) {
printf("\n"); printf("\n");
} }
int movemask_neon(uint8x16_t movemask_low_in) static inline int movemask_neon(uint8x16_t movemask_low_in)
{ {
uint8x8_t lo = vget_low_u8(movemask_low_in); uint8x8_t lo = vget_low_u8(movemask_low_in);
uint8x8_t hi = vget_high_u8(movemask_low_in); uint8x8_t hi = vget_high_u8(movemask_low_in);

@ -426,7 +426,8 @@ uint32_t srslte_dci_dl_info(char *info_str, uint32_t len, srslte_ra_dl_dci_t *dc
n += snprintf(&info_str[n], len - n, "%d}, ", dci_msg->ndi_1); n += snprintf(&info_str[n], len - n, "%d}, ", dci_msg->ndi_1);
} }
if (format == SRSLTE_DCI_FORMAT1 || format == SRSLTE_DCI_FORMAT1A || format == SRSLTE_DCI_FORMAT1B) { if (format == SRSLTE_DCI_FORMAT1 || format == SRSLTE_DCI_FORMAT1A || format == SRSLTE_DCI_FORMAT1B ||
format == SRSLTE_DCI_FORMAT2 || format == SRSLTE_DCI_FORMAT2A || format == SRSLTE_DCI_FORMAT2B) {
n += snprintf(&info_str[n], len-n, "tpc_pucch=%d, ", dci_msg->tpc_pucch); n += snprintf(&info_str[n], len-n, "tpc_pucch=%d, ", dci_msg->tpc_pucch);
} }
if (format == SRSLTE_DCI_FORMAT2 || format == SRSLTE_DCI_FORMAT2A || format == SRSLTE_DCI_FORMAT2B) { if (format == SRSLTE_DCI_FORMAT2 || format == SRSLTE_DCI_FORMAT2A || format == SRSLTE_DCI_FORMAT2B) {

@ -147,14 +147,16 @@ typedef struct {
int main(int argc, char **argv) { int main(int argc, char **argv) {
srslte_pdcch_t pdcch_tx, pdcch_rx; srslte_pdcch_t pdcch_tx, pdcch_rx;
testcase_dci_t testcases[10] = {0}; testcase_dci_t testcases[10] = {};
srslte_ra_dl_dci_t ra_dl; srslte_ra_dl_dci_t ra_dl;
srslte_regs_t regs; srslte_regs_t regs;
int i, j, k; int i, j, k;
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
int nof_re; int nof_re;
cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS], *rx_slot_symbols[SRSLTE_MAX_PORTS]; cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS], *rx_slot_symbols[SRSLTE_MAX_PORTS];
int nof_dcis; int nof_dcis;
bzero(&testcases, sizeof(testcase_dci_t)*10);
int ret = -1; int ret = -1;

@ -111,7 +111,7 @@ void parse_args(int argc, char **argv) {
cfi = atoi(argv[optind]); cfi = atoi(argv[optind]);
break; break;
case 'x': case 'x':
strncpy(mimo_type_str, argv[optind], sizeof(mimo_type_str)); strncpy(mimo_type_str, argv[optind], sizeof(mimo_type_str)-1);
mimo_type_str[sizeof(mimo_type_str)-1] = 0; mimo_type_str[sizeof(mimo_type_str)-1] = 0;
break; break;
case 'p': case 'p':

@ -313,6 +313,11 @@ double radio::get_rx_freq()
return rx_freq; return rx_freq;
} }
double radio::get_freq_offset()
{
return freq_offset;
}
double radio::get_tx_freq() double radio::get_tx_freq()
{ {
return tx_freq; return tx_freq;

@ -31,8 +31,8 @@
#include <sstream> #include <sstream>
#define MOD 1024 #define MOD 1024
#define RX_MOD_BASE(x) (x-vr_r)%1024 #define RX_MOD_BASE(x) ((x-vr_r)%1024)
#define TX_MOD_BASE(x) (x-vt_a)%1024 #define TX_MOD_BASE(x) ((x-vt_a)%1024)
namespace srslte { namespace srslte {
@ -312,6 +312,22 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes)
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return build_status_pdu(payload, nof_bytes); return build_status_pdu(payload, nof_bytes);
} }
// if tx_window is full and retx_queue empty, retransmit next PDU to be ack'ed
if (tx_window.size() >= RLC_AM_WINDOW_SIZE && retx_queue.size() == 0) {
if (tx_window[vt_a].buf != NULL) {
log->warning("Full Tx window, ReTx'ing first outstanding PDU\n");
rlc_amd_retx_t retx;
retx.is_segment = false;
retx.so_start = 0;
retx.so_end = tx_window[vt_a].buf->N_bytes;
retx.sn = vt_a;
retx_queue.push_back(retx);
} else {
log->error("Found invalid PDU in tx_window.\n");
}
}
// RETX if required // RETX if required
if(retx_queue.size() > 0) { if(retx_queue.size() > 0) {
int ret = build_retx_pdu(payload, nof_bytes); int ret = build_retx_pdu(payload, nof_bytes);
@ -493,6 +509,12 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes)
// Update & write header // Update & write header
rlc_amd_pdu_header_t new_header = tx_window[retx.sn].header; rlc_amd_pdu_header_t new_header = tx_window[retx.sn].header;
new_header.p = 0; new_header.p = 0;
// Set poll bit
pdu_without_poll++;
byte_without_poll += (tx_window[retx.sn].buf->N_bytes + rlc_am_packed_length(&new_header));
log->info("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll);
log->info("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll);
if(poll_required()) if(poll_required())
{ {
new_header.p = 1; new_header.p = 1;
@ -532,14 +554,28 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
rlc_amd_pdu_header_t new_header; rlc_amd_pdu_header_t new_header;
rlc_amd_pdu_header_t old_header = tx_window[retx.sn].header; rlc_amd_pdu_header_t old_header = tx_window[retx.sn].header;
pdu_without_poll++;
byte_without_poll += (tx_window[retx.sn].buf->N_bytes + rlc_am_packed_length(&new_header));
log->info("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll);
log->info("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll);
new_header.dc = RLC_DC_FIELD_DATA_PDU; new_header.dc = RLC_DC_FIELD_DATA_PDU;
new_header.rf = 1; new_header.rf = 1;
new_header.p = 0;
new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED; new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED;
new_header.sn = old_header.sn; new_header.sn = old_header.sn;
new_header.lsf = 0; new_header.lsf = 0;
new_header.so = retx.so_start; new_header.so = retx.so_start;
new_header.N_li = 0; new_header.N_li = 0;
new_header.p = 0;
if(poll_required())
{
log->debug("%s setting poll bit to request status\n", rrc->get_rb_name(lcid).c_str());
new_header.p = 1;
poll_sn = vt_s;
pdu_without_poll = 0;
byte_without_poll = 0;
poll_retx_timeout.start(cfg.t_poll_retx);
}
uint32_t head_len = 0; uint32_t head_len = 0;
uint32_t pdu_space = 0; uint32_t pdu_space = 0;
@ -636,8 +672,15 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
return 0; return 0;
} }
// do not build any more PDU if window is already full
if (!tx_sdu && tx_window.size() >= RLC_AM_WINDOW_SIZE) {
log->info("Tx window full.\n");
return 0;
}
byte_buffer_t *pdu = pool_allocate; byte_buffer_t *pdu = pool_allocate;
if (!pdu) { if (!pdu) {
#ifdef RLC_AM_BUFFER_DEBUG
log->console("Fatal Error: Could not allocate PDU in build_data_pdu()\n"); log->console("Fatal Error: Could not allocate PDU in build_data_pdu()\n");
log->console("tx_window size: %d PDUs\n", tx_window.size()); log->console("tx_window size: %d PDUs\n", tx_window.size());
log->console("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d " log->console("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d "
@ -650,6 +693,10 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
log->console("tx_window - SN: %d\n", txit->first); log->console("tx_window - SN: %d\n", txit->first);
} }
exit(-1); exit(-1);
#else
log->error("Fatal Error: Couldn't allocate PDU in build_data_pdu().\n");
return 0;
#endif
} }
rlc_amd_pdu_header_t header; rlc_amd_pdu_header_t header;
header.dc = RLC_DC_FIELD_DATA_PDU; header.dc = RLC_DC_FIELD_DATA_PDU;
@ -808,8 +855,13 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h
rlc_amd_rx_pdu_t pdu; rlc_amd_rx_pdu_t pdu;
pdu.buf = pool_allocate; pdu.buf = pool_allocate;
if (!pdu.buf) { if (!pdu.buf) {
log->console("Fatal Error: Could not allocate PDU in handle_data_pdu()\n"); #ifdef RLC_AM_BUFFER_DEBUG
log->console("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n");
exit(-1); exit(-1);
#else
log->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n");
return;
#endif
} }
memcpy(pdu.buf->msg, payload, nof_bytes); memcpy(pdu.buf->msg, payload, nof_bytes);
@ -851,12 +903,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h
// Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3) // Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3)
if(reordering_timeout.is_running()) if(reordering_timeout.is_running())
{ {
if( if(vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr))
vr_x == vr_r ||
(RX_MOD_BASE(vr_x) < RX_MOD_BASE(vr_r) ||
(RX_MOD_BASE(vr_x) > RX_MOD_BASE(vr_mr) &&
vr_x != vr_mr))
)
{ {
reordering_timeout.reset(); reordering_timeout.reset();
} }
@ -894,9 +941,15 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
rlc_amd_rx_pdu_t segment; rlc_amd_rx_pdu_t segment;
segment.buf = pool_allocate; segment.buf = pool_allocate;
if (!segment.buf) { if (!segment.buf) {
log->console("Fatal Error: Could not allocate PDU in handle_data_pdu_segment()\n"); #ifdef RLC_AM_BUFFER_DEBUG
log->console("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment().\n");
exit(-1); exit(-1);
#else
log->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment().\n");
return;
#endif
} }
memcpy(segment.buf->msg, payload, nof_bytes); memcpy(segment.buf->msg, payload, nof_bytes);
segment.buf->N_bytes = nof_bytes; segment.buf->N_bytes = nof_bytes;
memcpy(&segment.header, &header, sizeof(rlc_amd_pdu_header_t)); memcpy(&segment.header, &header, sizeof(rlc_amd_pdu_header_t));
@ -948,7 +1001,9 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a
// else delay for reordering timer // else delay for reordering timer
} }
} }
#ifdef RLC_AM_BUFFER_DEBUG
print_rx_segments();
#endif
debug_state(); debug_state();
} }
@ -963,6 +1018,11 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
poll_retx_timeout.reset(); poll_retx_timeout.reset();
// flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again
if (status.N_nack > 0) {
retx_queue.clear();
}
// Handle ACKs and NACKs // Handle ACKs and NACKs
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it; std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it;
bool update_vt_a = true; bool update_vt_a = true;
@ -986,15 +1046,26 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
retx.so_end = it->second.buf->N_bytes; retx.so_end = it->second.buf->N_bytes;
if(status.nacks[j].has_so) { if(status.nacks[j].has_so) {
// sanity check
if (status.nacks[j].so_start >= it->second.buf->N_bytes) {
// print error but try to send original PDU again
log->error("SO_start is larger than original PDU (%d >= %d)\n",
status.nacks[j].so_start,
it->second.buf->N_bytes);
status.nacks[j].so_start = 0;
}
// check for special SO_end value
if(status.nacks[j].so_end == 0x7FFF) {
status.nacks[j].so_end = it->second.buf->N_bytes;
}else{
retx.so_end = status.nacks[j].so_end + 1;
}
if(status.nacks[j].so_start < it->second.buf->N_bytes && if(status.nacks[j].so_start < it->second.buf->N_bytes &&
status.nacks[j].so_end <= it->second.buf->N_bytes) { status.nacks[j].so_end <= it->second.buf->N_bytes) {
retx.is_segment = true; retx.is_segment = true;
retx.so_start = status.nacks[j].so_start; retx.so_start = status.nacks[j].so_start;
if(status.nacks[j].so_end == 0x7FFF) {
retx.so_end = it->second.buf->N_bytes;
}else{
retx.so_end = status.nacks[j].so_end + 1;
}
} else { } else {
log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n", log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n",
rrc->get_rb_name(lcid).c_str(), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); rrc->get_rb_name(lcid).c_str(), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes);
@ -1012,17 +1083,16 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
//ACKed SNs get marked and removed from tx_window if possible //ACKed SNs get marked and removed from tx_window if possible
if(tx_window.count(i) > 0) { if(tx_window.count(i) > 0) {
it = tx_window.find(i); it = tx_window.find(i);
it->second.is_acked = true; if (it != tx_window.end()) {
if(it->second.buf) { if(update_vt_a) {
pool->deallocate(it->second.buf); tx_window.erase(it);
it->second.buf = 0; if(it->second.buf) {
log->info("SN=%d removed from tx_window\n", i); pool->deallocate(it->second.buf);
} it->second.buf = 0;
tx_window.erase(it); }
if(update_vt_a) vt_a = (vt_a + 1)%MOD;
{ vt_ms = (vt_ms + 1)%MOD;
vt_a = (vt_a + 1)%MOD; }
vt_ms = (vt_ms + 1)%MOD;
} }
} }
} }
@ -1037,8 +1107,13 @@ void rlc_am::reassemble_rx_sdus()
if(!rx_sdu) { if(!rx_sdu) {
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
if (!rx_sdu) { if (!rx_sdu) {
#ifdef RLC_AM_BUFFER_DEBUG
log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n"); log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n");
exit(-1); exit(-1);
#else
log->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n");
return;
#endif
} }
} }
// Iterate through rx_window, assembling and delivering SDUs // Iterate through rx_window, assembling and delivering SDUs
@ -1057,10 +1132,14 @@ void rlc_am::reassemble_rx_sdus()
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
if (!rx_sdu) { if (!rx_sdu) {
#ifdef RLC_AM_BUFFER_DEBUG
log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n");
exit(-1); exit(-1);
#else
log->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n");
return;
#endif
} }
} }
// Handle last segment // Handle last segment
@ -1073,8 +1152,13 @@ void rlc_am::reassemble_rx_sdus()
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
if (!rx_sdu) { if (!rx_sdu) {
#ifdef RLC_AM_BUFFER_DEBUG
log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)\n"); log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)\n");
exit(-1); exit(-1);
#else
log->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)\n");
return;
#endif
} }
} }
@ -1117,6 +1201,20 @@ void rlc_am::debug_state()
} }
void rlc_am::print_rx_segments()
{
std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it;
std::stringstream ss;
ss << "rx_segments:" << std::endl;
for(it=rx_segments.begin();it!=rx_segments.end();it++) {
std::list<rlc_amd_rx_pdu_t>::iterator segit;
for(segit = it->second.segments.begin(); segit != it->second.segments.end(); segit++) {
ss << " SN:" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes << std::endl;
}
}
log->debug("%s\n", ss.str().c_str());
}
bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment) bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment)
{ {
// Ordered insert // Ordered insert
@ -1175,8 +1273,13 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd
// Copy data // Copy data
byte_buffer_t *full_pdu = pool_allocate; byte_buffer_t *full_pdu = pool_allocate;
if (!full_pdu) { if (!full_pdu) {
#ifdef RLC_AM_BUFFER_DEBUG
log->console("Fatal Error: Could not allocate PDU in add_segment_and_check()\n"); log->console("Fatal Error: Could not allocate PDU in add_segment_and_check()\n");
exit(-1); exit(-1);
#else
log->error("Fatal Error: Could not allocate PDU in add_segment_and_check()\n");
return false;
#endif
} }
for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) { for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) {
memcpy(&full_pdu->msg[full_pdu->N_bytes], it->buf->msg, it->buf->N_bytes); memcpy(&full_pdu->msg[full_pdu->N_bytes], it->buf->msg, it->buf->N_bytes);

@ -30,6 +30,9 @@ add_executable(rlc_am_test rlc_am_test.cc)
target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common) target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common)
add_test(rlc_am_test rlc_am_test) add_test(rlc_am_test rlc_am_test)
add_executable(rlc_am_stress_test rlc_am_stress_test.cc)
target_link_libraries(rlc_am_stress_test srslte_upper srslte_phy srslte_common)
add_executable(rlc_um_data_test rlc_um_data_test.cc) add_executable(rlc_um_data_test rlc_um_data_test.cc)
target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common)
add_test(rlc_um_data_test rlc_um_data_test) add_test(rlc_um_data_test rlc_um_data_test)

@ -0,0 +1,251 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include <stdlib.h>
#include <pthread.h>
#include "srslte/common/log_filter.h"
#include "srslte/common/logger_stdout.h"
#include "srslte/common/threads.h"
#include "srslte/upper/rlc.h"
#include <assert.h>
#define NBUFS 5
using namespace srsue;
using namespace srslte;
class mac_reader
:public thread
{
public:
mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_)
{
rlc1 = rlc1_;
rlc2 = rlc2_;
fail_rate = fail_rate_;
run_enable = true;
}
void stop()
{
run_enable = false;
int cnt=0;
while(running && cnt<100) {
usleep(10000);
cnt++;
}
if(running) {
thread_cancel();
}
wait_thread_finish();
}
private:
void run_thread()
{
running = true;
byte_buffer_t *pdu = byte_buffer_pool::get_instance()->allocate("mac_reader::run_thread");
if (!pdu) {
printf("Fatal Error: Could not allocate PDU in mac_reader::run_thread\n");
exit(-1);
}
while(run_enable) {
float r = (float)rand()/RAND_MAX;
int opp_size = r*1500;
rlc1->get_buffer_state(1);
int read = rlc1->read_pdu(1, pdu->msg, opp_size);
if(((float)rand()/RAND_MAX > fail_rate) && read>0) {
rlc2->write_pdu(1, pdu->msg, opp_size);
}
usleep(1000);
}
running = false;
}
rlc_interface_mac *rlc1;
rlc_interface_mac *rlc2;
float fail_rate;
bool run_enable;
bool running;
};
class mac_dummy
:public srslte::mac_interface_timers
{
public:
mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_)
:r1(rlc1_, rlc2_, fail_rate_)
,r2(rlc2_, rlc1_, fail_rate_)
{
}
void start()
{
r1.start(7);
r2.start(7);
}
void stop()
{
r1.stop();
r2.stop();
}
srslte::timers::timer* timer_get(uint32_t timer_id)
{
return &t;
}
uint32_t timer_get_unique_id(){return 0;}
void timer_release_id(uint32_t id){}
private:
srslte::timers::timer t;
mac_reader r1;
mac_reader r2;
};
class rlc_am_tester
:public pdcp_interface_rlc
,public rrc_interface_rlc
,public thread
{
public:
rlc_am_tester(rlc_interface_pdcp *rlc_){
rlc = rlc_;
run_enable = true;
running = false;
}
void stop()
{
run_enable = false;
int cnt=0;
while(running && cnt<100) {
usleep(10000);
cnt++;
}
if(running) {
thread_cancel();
}
wait_thread_finish();
}
// PDCP interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu)
{
assert(lcid == 1);
byte_buffer_pool::get_instance()->deallocate(sdu);
}
void write_pdu_bcch_bch(byte_buffer_t *sdu) {}
void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {}
void write_pdu_pcch(byte_buffer_t *sdu) {}
// RRC interface
void max_retx_attempted(){}
std::string get_rb_name(uint32_t lcid) { return std::string(""); }
private:
void run_thread()
{
uint8_t sn = 0;
running = true;
while(run_enable) {
byte_buffer_t *pdu = byte_buffer_pool::get_instance()->allocate("rlc_am_tester::run_thread");
if (!pdu) {
printf("Fatal Error: Could not allocate PDU in rlc_am_tester::run_thread\n");
exit(-1);
}
pdu->N_bytes = 1500;
pdu->msg[0] = sn++;
rlc->write_sdu(1, pdu);
usleep(1000);
}
running = false;
}
bool run_enable;
bool running;
rlc_interface_pdcp *rlc;
};
void stress_test()
{
srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2");
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log2.set_level(srslte::LOG_LEVEL_DEBUG);
log1.set_hex_limit(-1);
log2.set_hex_limit(-1);
float fail_rate = 0.1;
rlc rlc1;
rlc rlc2;
rlc_am_tester tester1(&rlc1);
rlc_am_tester tester2(&rlc2);
mac_dummy mac(&rlc1, &rlc2, fail_rate);
ue_interface ue;
rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0);
rlc2.init(&tester1, &tester1, &ue, &log2, &mac, 0);
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM;
cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5;
cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5;
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
srslte_rlc_config_t cnfg_(&cnfg);
rlc1.add_bearer(1, cnfg_);
rlc2.add_bearer(1, cnfg_);
tester1.start(7);
//tester2.start(7);
mac.start();
usleep(100e6);
tester1.stop();
tester2.stop();
mac.stop();
}
int main(int argc, char **argv) {
stress_test();
byte_buffer_pool::get_instance()->cleanup();
}

@ -715,7 +715,7 @@ int enb::parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUC
if (!parser::parse_section(filename, &sib9)) { if (!parser::parse_section(filename, &sib9)) {
data->hnb_name_present = true; data->hnb_name_present = true;
if (name_enabled) { if (name_enabled) {
strncpy((char*) data->hnb_name, hnb_name.c_str(), 48); strncpy((char*) data->hnb_name, hnb_name.c_str(), 47);
data->hnb_name[47] = 0; data->hnb_name[47] = 0;
data->hnb_name_size = strnlen(hnb_name.c_str(), 48); data->hnb_name_size = strnlen(hnb_name.c_str(), 48);
} else if (hex_enabled) { } else if (hex_enabled) {

@ -630,7 +630,7 @@ int sched::dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST])
} }
} else { } else {
log_h->console("SCHED: Could not schedule DCI for RAR tti=%d, L=%d\n", pending_rar[i].rar_tti, rar_aggr_level); log_h->warning("SCHED: Could not schedule DCI for RAR tti=%d, L=%d\n", pending_rar[i].rar_tti, rar_aggr_level);
} }
} else { } else {
log_h->console("SCHED: Could not transmit RAR within the window (RA TTI=%d, Window=%d, Now=%d)\n", log_h->console("SCHED: Could not transmit RAR within the window (RA TTI=%d, Window=%d, Now=%d)\n",
@ -861,7 +861,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
aggr_level)) aggr_level))
{ {
h->reset(0); h->reset(0);
printf("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d, sf_idx=%d\n", log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d, sf_idx=%d\n",
rnti, h->get_id(), aggr_level, sf_idx); rnti, h->get_id(), aggr_level, sf_idx);
sched_result->pusch[nof_dci_elems].needs_pdcch = false; sched_result->pusch[nof_dci_elems].needs_pdcch = false;

@ -24,6 +24,7 @@ mme_bind_addr = 127.0.1.100
##################################################################### #####################################################################
# HSS configuration # HSS configuration
# #
# algo: Authentication algorithm (xor/milenage)
# db_file: Location of .csv file that stores UEs information. # db_file: Location of .csv file that stores UEs information.
# #
##################################################################### #####################################################################

@ -38,6 +38,7 @@
#include "srslte/common/logger_file.h" #include "srslte/common/logger_file.h"
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/interfaces/epc_interfaces.h"
#include <fstream> #include <fstream>
#include <map> #include <map>
@ -56,6 +57,8 @@ typedef struct{
uint8_t key[16]; uint8_t key[16];
uint8_t op[16]; uint8_t op[16];
uint8_t amf[2]; uint8_t amf[2];
uint8_t sqn[6];
uint8_t last_rand[16];
}hss_ue_ctx_t; }hss_ue_ctx_t;
enum hss_auth_algo { enum hss_auth_algo {
@ -63,7 +66,7 @@ enum hss_auth_algo {
HSS_ALGO_MILENAGE HSS_ALGO_MILENAGE
}; };
class hss class hss : public hss_interface_s1ap
{ {
public: public:
static hss* get_instance(void); static hss* get_instance(void);
@ -71,18 +74,8 @@ public:
int init(hss_args_t *hss_args, srslte::log_filter* hss_log); int init(hss_args_t *hss_args, srslte::log_filter* hss_log);
void stop(void); void stop(void);
bool set_auth_algo(std::string auth_algo);
bool read_db_file(std::string db_file);
void get_sqn(uint8_t sqn[6]);
void gen_rand(uint8_t rand_[16]);
bool get_k_amf_op(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op);
bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres); bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
bool gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres); bool resync_sqn(uint64_t imsi, uint8_t *auts);
bool gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
std::vector<std::string> split_string(const std::string &str, char delimiter);
void get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len);
private: private:
@ -90,14 +83,38 @@ private:
virtual ~hss(); virtual ~hss();
static hss *m_instance; static hss *m_instance;
uint64_t m_sqn; //48 bits
srslte::byte_buffer_pool *m_pool; srslte::byte_buffer_pool *m_pool;
std::ifstream m_db_file;
std::map<uint64_t,hss_ue_ctx_t*> m_imsi_to_ue_ctx; std::map<uint64_t,hss_ue_ctx_t*> m_imsi_to_ue_ctx;
enum hss_auth_algo m_auth_algo;
void gen_rand(uint8_t rand_[16]);
bool get_k_amf_op_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op, uint8_t *sqn);
bool gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
bool gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
bool resync_sqn_milenage(uint64_t imsi, uint8_t *auts);
bool resync_sqn_xor(uint64_t imsi, uint8_t *auts);
std::vector<std::string> split_string(const std::string &str, char delimiter);
void get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len);
void increment_sqn(uint64_t imsi);
void set_sqn(uint64_t imsi, uint8_t *sqn);
void set_last_rand(uint64_t imsi, uint8_t *rand);
void get_last_rand(uint64_t imsi, uint8_t *rand);
bool set_auth_algo(std::string auth_algo);
bool read_db_file(std::string db_file);
bool write_db_file(std::string db_file);
bool get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx);
std::string hex_string(uint8_t *hex, int size);
enum hss_auth_algo m_auth_algo;
std::string db_file;
/*Logs*/ /*Logs*/
srslte::log_filter *m_hss_log; srslte::log_filter *m_hss_log;

@ -66,7 +66,7 @@ class mme:
public: public:
static mme* get_instance(void); static mme* get_instance(void);
static void cleanup(void); static void cleanup(void);
int init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log); int init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log, hss_interface_s1ap * hss_);
void stop(); void stop();
int get_s1_mme(); int get_s1_mme();
void run_thread(); void run_thread();

@ -59,7 +59,7 @@ public:
static void cleanup(); static void cleanup();
int enb_listen(); int enb_listen();
int init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log); int init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1ap * hss_);
void stop(); void stop();
int get_s1_mme(); int get_s1_mme();
@ -114,7 +114,7 @@ private:
uint32_t m_plmn; uint32_t m_plmn;
srslte::byte_buffer_pool *m_pool; srslte::byte_buffer_pool *m_pool;
hss *m_hss; hss_interface_s1ap *m_hss;
int m_s1mme; int m_s1mme;
std::map<uint16_t, enb_ctx_t*> m_active_enbs; std::map<uint16_t, enb_ctx_t*> m_active_enbs;
std::map<int32_t, uint16_t> m_sctp_to_enb_id; std::map<int32_t, uint16_t> m_sctp_to_enb_id;

@ -42,7 +42,7 @@ public:
static s1ap_nas_transport* m_instance; static s1ap_nas_transport* m_instance;
static s1ap_nas_transport* get_instance(void); static s1ap_nas_transport* get_instance(void);
static void cleanup(void); static void cleanup(void);
void init(void); void init(hss_interface_s1ap * hss_);
bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag); bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag); bool handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
@ -65,6 +65,7 @@ public:
srslte::byte_buffer_t *reply_buffer, srslte::byte_buffer_t *reply_buffer,
bool* reply_flag, bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri); struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_service_request(uint32_t m_tmsi, bool handle_nas_service_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id, uint32_t enb_ue_s1ap_id,
srslte::byte_buffer_t *nas_msg, srslte::byte_buffer_t *nas_msg,
@ -106,7 +107,7 @@ private:
srslte::byte_buffer_pool *m_pool; srslte::byte_buffer_pool *m_pool;
s1ap* m_s1ap; s1ap* m_s1ap;
hss* m_hss; hss_interface_s1ap* m_hss;
mme_gtpc* m_mme_gtpc; mme_gtpc* m_mme_gtpc;
}; };

@ -27,6 +27,7 @@
#include <time.h> /* time */ #include <time.h> /* time */
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <iomanip>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include "hss/hss.h" #include "hss/hss.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
@ -39,8 +40,6 @@ hss* hss::m_instance = NULL;
boost::mutex hss_instance_mutex; boost::mutex hss_instance_mutex;
hss::hss() hss::hss()
// :m_sqn(0x112233445566)
:m_sqn(0)
{ {
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
return; return;
@ -92,27 +91,26 @@ hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
mcc = hss_args->mcc; mcc = hss_args->mcc;
mnc = hss_args->mnc; mnc = hss_args->mnc;
db_file = hss_args->db_file;
m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s, MCC: %d, MNC: %d\n", hss_args->db_file.c_str(),hss_args->auth_algo.c_str(), mcc, mnc); m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s, MCC: %d, MNC: %d\n", hss_args->db_file.c_str(),hss_args->auth_algo.c_str(), mcc, mnc);
m_hss_log->console("HSS Initialized\n"); m_hss_log->console("HSS Initialized.\n");
return 0; return 0;
} }
void void
hss::stop(void) hss::stop(void)
{ {
write_db_file(db_file);
std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin(); std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end()) while(it!=m_imsi_to_ue_ctx.end())
{ {
m_hss_log->info("Deleting UE context in HSS. IMSI: %lu\n", it->second->imsi); m_hss_log->info("Deleting UE context in HSS. IMSI: %015lu\n", it->second->imsi);
m_hss_log->console("Deleting UE context in HSS. IMSI: %lu\n", it->second->imsi); m_hss_log->console("Deleting UE context in HSS. IMSI: %015lu\n", it->second->imsi);
delete it->second; delete it->second;
m_imsi_to_ue_ctx.erase(it++); m_imsi_to_ue_ctx.erase(it++);
} }
if(m_db_file.is_open())
{
m_db_file.close();
}
return; return;
} }
@ -139,6 +137,8 @@ hss::set_auth_algo(std::string auth_algo)
bool bool
hss::read_db_file(std::string db_filename) hss::read_db_file(std::string db_filename)
{ {
std::ifstream m_db_file;
m_db_file.open(db_filename.c_str(), std::ifstream::in); m_db_file.open(db_filename.c_str(), std::ifstream::in);
if(!m_db_file.is_open()) if(!m_db_file.is_open())
{ {
@ -152,7 +152,7 @@ hss::read_db_file(std::string db_filename)
if(line[0] != '#') if(line[0] != '#')
{ {
std::vector<std::string> split = split_string(line,','); std::vector<std::string> split = split_string(line,',');
if(split.size()!=5) if(split.size()!=6)
{ {
m_hss_log->error("Error parsing UE database\n"); m_hss_log->error("Error parsing UE database\n");
return false; return false;
@ -163,16 +163,65 @@ hss::read_db_file(std::string db_filename)
get_uint_vec_from_hex_str(split[2],ue_ctx->key,16); get_uint_vec_from_hex_str(split[2],ue_ctx->key,16);
get_uint_vec_from_hex_str(split[3],ue_ctx->op,16); get_uint_vec_from_hex_str(split[3],ue_ctx->op,16);
get_uint_vec_from_hex_str(split[4],ue_ctx->amf,2); get_uint_vec_from_hex_str(split[4],ue_ctx->amf,2);
get_uint_vec_from_hex_str(split[5],ue_ctx->sqn,6);
m_hss_log->debug("Added user from DB, IMSI: %015lu\n", ue_ctx->imsi); m_hss_log->debug("Added user from DB, IMSI: %015lu\n", ue_ctx->imsi);
m_hss_log->debug_hex(ue_ctx->key, 16, "User Key : "); m_hss_log->debug_hex(ue_ctx->key, 16, "User Key : ");
m_hss_log->debug_hex(ue_ctx->op, 16, "User OP : "); m_hss_log->debug_hex(ue_ctx->op, 16, "User OP : ");
m_hss_log->debug_hex(ue_ctx->amf, 2, "AMF : "); m_hss_log->debug_hex(ue_ctx->amf, 2, "AMF : ");
m_hss_log->debug_hex(ue_ctx->sqn, 6, "SQN : ");
m_imsi_to_ue_ctx.insert(std::pair<uint64_t,hss_ue_ctx_t*>(ue_ctx->imsi,ue_ctx)); m_imsi_to_ue_ctx.insert(std::pair<uint64_t,hss_ue_ctx_t*>(ue_ctx->imsi,ue_ctx));
} }
} }
if(m_db_file.is_open())
{
m_db_file.close();
}
return true;
}
bool hss::write_db_file(std::string db_filename)
{
std::string line;
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t sqn[6];
std::ofstream m_db_file;
m_db_file.open(db_filename.c_str(), std::ofstream::out);
if(!m_db_file.is_open())
{
return false;
}
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str() );
std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end())
{
m_db_file << it->second->name;
m_db_file << ",";
m_db_file << std::setfill('0') << std::setw(15) << it->second->imsi;
m_db_file << ",";
m_db_file << hex_string(it->second->key, 16);
m_db_file << ",";
m_db_file << hex_string(it->second->op, 16);
m_db_file << ",";
m_db_file << hex_string(it->second->amf, 2);
m_db_file << ",";
m_db_file << hex_string(it->second->sqn, 6);
m_db_file << std::endl;
it++;
}
if(m_db_file.is_open())
{
m_db_file.close();
}
return true; return true;
} }
@ -189,8 +238,99 @@ hss::gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t
ret = gen_auth_info_answer_milenage(imsi, k_asme, autn, rand, xres); ret = gen_auth_info_answer_milenage(imsi, k_asme, autn, rand, xres);
break; break;
} }
increment_sqn(imsi);
return ret;
}
bool
hss::resync_sqn(uint64_t imsi, uint8_t *auts)
{
bool ret = false;
switch (m_auth_algo)
{
case HSS_ALGO_XOR:
ret = resync_sqn_xor(imsi, auts);
break;
case HSS_ALGO_MILENAGE:
ret = resync_sqn_milenage(imsi, auts);
break;
}
increment_sqn(imsi);
return ret; return ret;
}
bool
hss::resync_sqn_xor(uint64_t imsi, uint8_t *auts)
{
m_hss_log->error("XOR SQN synchronization not supported yet\n");
m_hss_log->console("XOR SQNs synchronization not supported yet\n");
return false;
}
bool
hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
{
uint8_t last_rand[16];
uint8_t ak[6];
uint8_t mac_s[8];
uint8_t sqn_ms_xor_ak[6];
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t sqn[6];
if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
{
return false;
}
get_last_rand(imsi, last_rand);
for(int i=0; i<6; i++){
sqn_ms_xor_ak[i] = auts[i];
}
for(int i=0; i<8; i++){
mac_s[i] = auts[i+6];
}
m_hss_log->debug_hex(k, 16, "User Key : ");
m_hss_log->debug_hex(op, 16, "User OP : ");
m_hss_log->debug_hex(last_rand, 16, "User Last Rand : ");
m_hss_log->debug_hex(auts, 16, "AUTS : ");
m_hss_log->debug_hex(sqn_ms_xor_ak, 6, "SQN xor AK : ");
m_hss_log->debug_hex(mac_s, 8, "MAC : ");
security_milenage_f5_star(k, op, last_rand, ak);
m_hss_log->debug_hex(ak, 6, "Resynch AK : ");
uint8_t sqn_ms[6];
for(int i=0; i<6; i++){
sqn_ms[i] = sqn_ms_xor_ak[i] ^ ak[i];
}
m_hss_log->debug_hex(sqn_ms, 6, "SQN MS : ");
m_hss_log->debug_hex(amf, 2, "AMF : ");
uint8_t mac_s_tmp[8];
security_milenage_f1_star(k, op, last_rand, sqn_ms, amf, mac_s_tmp);
m_hss_log->debug_hex(mac_s_tmp, 8, "MAC calc : ");
/*
for(int i=0; i<8; i++){
if(!(mac_s_tmp[i] == mac_s[i])){
m_hss_log->error("Calculated MAC does not match sent MAC\n");
return false;
}
}
*/
set_sqn(imsi, sqn_ms);
return true;
} }
bool bool
@ -207,13 +347,12 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
uint8_t mac[8]; uint8_t mac[8];
if(!get_k_amf_op(imsi,k,amf,op)) if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
{ {
return false; return false;
} }
gen_rand(rand); gen_rand(rand);
get_sqn(sqn);
security_milenage_f2345( k, security_milenage_f2345( k,
op, op,
rand, rand,
@ -268,6 +407,8 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
m_hss_log->debug_hex(autn, 16, "User AUTN: "); m_hss_log->debug_hex(autn, 16, "User AUTN: ");
set_last_rand(imsi, rand);
return true; return true;
} }
@ -289,12 +430,11 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
int i = 0; int i = 0;
if(!get_k_amf_op(imsi,k,amf,op)) if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
{ {
return false; return false;
} }
gen_rand(rand); gen_rand(rand);
get_sqn(sqn);
// Use RAND and K to compute RES, CK, IK and AK // Use RAND and K to compute RES, CK, IK and AK
for(i=0; i<16; i++) { for(i=0; i<16; i++) {
@ -376,19 +516,16 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
m_hss_log->debug_hex(autn, 8, "User AUTN: "); m_hss_log->debug_hex(autn, 8, "User AUTN: ");
set_last_rand(imsi, rand);
return true; return true;
} }
bool bool
hss::get_k_amf_op(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op ) hss::get_k_amf_op_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op, uint8_t *sqn)
{ {
/*
uint8_t k_tmp[16] ={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
uint8_t amf_tmp[2]={0x80,0x00};
uint8_t op_tmp[16]={0x63,0xbf,0xA5,0x0E,0xE6,0x52,0x33,0x65,0xFF,0x14,0xC1,0xF4,0x5F,0x88,0x73,0x7D};
*/
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi); std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end()) if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{ {
@ -398,22 +535,76 @@ hss::get_k_amf_op(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op )
} }
hss_ue_ctx_t *ue_ctx = ue_ctx_it->second; hss_ue_ctx_t *ue_ctx = ue_ctx_it->second;
m_hss_log->info("Found User %015lu\n",imsi); m_hss_log->info("Found User %015lu\n",imsi);
memcpy(k,ue_ctx->key,16); memcpy(k, ue_ctx->key, 16);
memcpy(amf,ue_ctx->amf,2); memcpy(amf, ue_ctx->amf, 2);
memcpy(op,ue_ctx->op,16); memcpy(op, ue_ctx->op, 16);
memcpy(sqn, ue_ctx->sqn, 6);
return true; return true;
} }
void
hss::increment_sqn(uint64_t imsi)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
return;
}
// Awkward 48 bit sqn and doing arithmetic
uint64_t sqn = 0;
uint8_t *p = (uint8_t *)&sqn;
for(int i = 0; i < 6; i++) {
p[5-i] = (uint8_t) ((ue_ctx->sqn[i]));
}
sqn++;
m_hss_log->debug("Incremented SQN (IMSI: %015lu) SQN: %d\n", imsi, sqn);
for(int i = 0; i < 6; i++){
ue_ctx->sqn[i] = p[5-i];
}
}
void
hss::set_sqn(uint64_t imsi, uint8_t *sqn)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
return;
}
memcpy(ue_ctx->sqn, sqn, 6);
}
void
hss::set_last_rand(uint64_t imsi, uint8_t *rand)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
return;
}
memcpy(ue_ctx->last_rand, rand, 16);
}
void void
hss::get_sqn(uint8_t sqn[6]) hss::get_last_rand(uint64_t imsi, uint8_t *rand)
{ {
for (int i=0; i<6; i++) hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{ {
sqn[i] = ((uint8_t *)&m_sqn)[i]; return;
} }
m_sqn++; memcpy(rand, ue_ctx->last_rand, 16);
return; //TODO See TS 33.102, Annex C
} }
void void
@ -426,6 +617,19 @@ hss::gen_rand(uint8_t rand_[16])
return; return;
} }
bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx)
{
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
m_hss_log->info("User not found. IMSI: %015lu\n",imsi);
return false;
}
*ue_ctx = ue_ctx_it->second;
return true;
}
/* Helper functions*/ /* Helper functions*/
std::vector<std::string> std::vector<std::string>
hss::split_string(const std::string &str, char delimiter) hss::split_string(const std::string &str, char delimiter)
@ -454,6 +658,18 @@ hss::get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint le
return; return;
} }
std::string
hss::hex_string(uint8_t *hex, int size)
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
for(int i=0;i<size;i++) {
ss << std::setw(2) << static_cast<unsigned>(hex[i]);
}
return ss.str();
}
/* /*
uint64_t uint64_t
string_to_imsi() string_to_imsi()

@ -306,19 +306,20 @@ main (int argc,char * argv[] )
spgw_log.init("SPGW",logger); spgw_log.init("SPGW",logger);
spgw_log.set_level(level(args.log_args.spgw_level)); spgw_log.set_level(level(args.log_args.spgw_level));
spgw_log.set_hex_limit(args.log_args.spgw_hex_limit); spgw_log.set_hex_limit(args.log_args.spgw_hex_limit);
mme *mme = mme::get_instance();
if (mme->init(&args.mme_args, &s1ap_log, &mme_gtpc_log)) {
cout << "Error initializing MME" << endl;
exit(1);
}
hss *hss = hss::get_instance(); hss *hss = hss::get_instance();
if (hss->init(&args.hss_args,&hss_log)) { if (hss->init(&args.hss_args,&hss_log)) {
cout << "Error initializing HSS" << endl; cout << "Error initializing HSS" << endl;
exit(1); exit(1);
} }
mme *mme = mme::get_instance();
if (mme->init(&args.mme_args, &s1ap_log, &mme_gtpc_log, hss)) {
cout << "Error initializing MME" << endl;
exit(1);
}
spgw *spgw = spgw::get_instance(); spgw *spgw = spgw::get_instance();
if (spgw->init(&args.spgw_args,&spgw_log)) { if (spgw->init(&args.spgw_args,&spgw_log)) {
cout << "Error initializing SP-GW" << endl; cout << "Error initializing SP-GW" << endl;

@ -70,7 +70,7 @@ mme::cleanup(void)
} }
int int
mme::init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log) mme::init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log, hss_interface_s1ap * hss_)
{ {
/*Init logger*/ /*Init logger*/
@ -78,7 +78,7 @@ mme::init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mm
m_mme_gtpc_log = mme_gtpc_log; m_mme_gtpc_log = mme_gtpc_log;
/*Init S1AP*/ /*Init S1AP*/
m_s1ap = s1ap::get_instance(); m_s1ap = s1ap::get_instance();
if(m_s1ap->init(args->s1ap_args, s1ap_log)){ if(m_s1ap->init(args->s1ap_args, s1ap_log, hss_)){
m_s1ap_log->error("Error initializing MME S1APP\n"); m_s1ap_log->error("Error initializing MME S1APP\n");
exit(-1); exit(-1);
} }

@ -68,7 +68,7 @@ s1ap::cleanup(void)
} }
int int
s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log) s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1ap * hss_)
{ {
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
@ -78,17 +78,17 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log)
//Init log //Init log
m_s1ap_log = s1ap_log; m_s1ap_log = s1ap_log;
//Get pointer to the HSS
m_hss = hss_;
//Init message handlers //Init message handlers
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures
m_s1ap_mngmt_proc->init(); m_s1ap_mngmt_proc->init();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures
m_s1ap_nas_transport->init(); m_s1ap_nas_transport->init(m_hss);
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures
m_s1ap_ctx_mngmt_proc->init(); m_s1ap_ctx_mngmt_proc->init();
//Get pointer to the HSS
m_hss = hss::get_instance();
//Get pointer to GTP-C class //Get pointer to GTP-C class
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
//Initialize S1-MME //Initialize S1-MME

@ -65,13 +65,13 @@ s1ap_nas_transport::cleanup(void)
} }
void void
s1ap_nas_transport::init(void) s1ap_nas_transport::init(hss_interface_s1ap * hss_)
{ {
m_s1ap = s1ap::get_instance(); m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log; m_s1ap_log = m_s1ap->m_s1ap_log;
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
m_hss = hss::get_instance(); m_hss = hss_;
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
} }
@ -257,6 +257,11 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA
m_s1ap_log->info("UL NAS: Tracking Area Update Request\n"); m_s1ap_log->info("UL NAS: Tracking Area Update Request\n");
handle_tracking_area_update_request(nas_msg, ue_ecm_ctx, reply_buffer, reply_flag); handle_tracking_area_update_request(nas_msg, ue_ecm_ctx, reply_buffer, reply_flag);
break; break;
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
m_s1ap_log->info("Uplink NAS: Authentication Failure\n");
handle_authentication_failure(nas_msg, ue_ctx, reply_buffer, reply_flag);
ue_ctx->security_ctxt.ul_nas_count++;
break;
default: default:
m_s1ap_log->warning("Unhandled NAS integrity protected message 0x%x\n", msg_type ); m_s1ap_log->warning("Unhandled NAS integrity protected message 0x%x\n", msg_type );
m_s1ap_log->console("Unhandled NAS integrity protected message 0x%x\n", msg_type ); m_s1ap_log->console("Unhandled NAS integrity protected message 0x%x\n", msg_type );
@ -838,7 +843,7 @@ s1ap_nas_transport::handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp; LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp;
LIBLTE_ERROR_ENUM err = liblte_mme_unpack_identity_response_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &id_resp); LIBLTE_ERROR_ENUM err = liblte_mme_unpack_identity_response_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &id_resp);
if(err != LIBLTE_SUCCESS){ if(err != LIBLTE_SUCCESS){
m_s1ap_log->error("Error unpacking NAS authentication response. Error: %s\n", liblte_error_text[err]); m_s1ap_log->error("Error unpacking NAS identity response. Error: %s\n", liblte_error_text[err]);
return false; return false;
} }
@ -884,8 +889,8 @@ s1ap_nas_transport::handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_
//Send reply to eNB //Send reply to eNB
*reply_flag = true; *reply_flag = true;
m_s1ap_log->info("Downlink NAS: Sent Athentication Request\n"); m_s1ap_log->info("Downlink NAS: Sent Authentication Request\n");
m_s1ap_log->console("Downlink NAS: Sent Athentication Request\n"); m_s1ap_log->console("Downlink NAS: Sent Authentication Request\n");
//TODO Start T3460 Timer! //TODO Start T3460 Timer!
return true; return true;
@ -923,8 +928,8 @@ s1ap_nas_transport::handle_tracking_area_update_request(srslte::byte_buffer_t *n
dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ecm_ctx->enb_ue_s1ap_id; dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ecm_ctx->enb_ue_s1ap_id;
dw_nas->HandoverRestrictionList_present=false; dw_nas->HandoverRestrictionList_present=false;
dw_nas->SubscriberProfileIDforRFP_present=false; dw_nas->SubscriberProfileIDforRFP_present=false;
m_s1ap_log->console("Tracking area accept to MME-UE S1AP Id %d\n", ue_ecm_ctx->mme_ue_s1ap_id); //m_s1ap_log->console("Tracking area accept to MME-UE S1AP Id %d\n", ue_ctx->mme_ue_s1ap_id);
/*
LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT tau_acc; LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT tau_acc;
@ -942,7 +947,7 @@ s1ap_nas_transport::handle_tracking_area_update_request(srslte::byte_buffer_t *n
bool eps_network_feature_support_present; bool eps_network_feature_support_present;
bool additional_update_result_present; bool additional_update_result_present;
bool t3412_ext_present; bool t3412_ext_present;
*/
//Get decimal MCC and MNC //Get decimal MCC and MNC
uint32_t mcc = 0; uint32_t mcc = 0;
mcc += 0x000F & m_s1ap->m_s1ap_args.mcc; mcc += 0x000F & m_s1ap->m_s1ap_args.mcc;
@ -1098,6 +1103,66 @@ s1ap_nas_transport::integrity_check(ue_emm_ctx_t *emm_ctx, srslte::byte_buffer_t
} }
bool
s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag)
{
uint8_t autn[16];
uint8_t rand[16];
uint8_t xres[8];
LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT auth_fail;
LIBLTE_ERROR_ENUM err = liblte_mme_unpack_authentication_failure_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &auth_fail);
if(err != LIBLTE_SUCCESS){
m_s1ap_log->error("Error unpacking NAS authentication failure. Error: %s\n", liblte_error_text[err]);
return false;
}
switch(auth_fail.emm_cause){
case 20:
m_s1ap_log->console("MAC code failure\n");
m_s1ap_log->info("MAC code failure\n");
break;
case 26:
m_s1ap_log->console("Non-EPS authentication unacceptable\n");
m_s1ap_log->info("Non-EPS authentication unacceptable\n");
break;
case 21:
m_s1ap_log->console("Sequence number synch failure\n");
m_s1ap_log->info("Sequence number synch failure\n");
if(auth_fail.auth_fail_param_present == false){
m_s1ap_log->error("Missing fail parameter\n");
return false;
}
if(!m_hss->resync_sqn(ue_ctx->imsi, auth_fail.auth_fail_param))
{
m_s1ap_log->console("Resynchronization failed. IMSI %015lu\n", ue_ctx->imsi);
m_s1ap_log->info("Resynchronization failed. IMSI %015lu\n", ue_ctx->imsi);
return false;
}
//Get Authentication Vectors from HSS
if(!m_hss->gen_auth_info_answer(ue_ctx->imsi, ue_ctx->security_ctxt.k_asme, autn, rand, ue_ctx->security_ctxt.xres))
{
m_s1ap_log->console("User not found. IMSI %015lu\n", ue_ctx->imsi);
m_s1ap_log->info("User not found. IMSI %015lu\n", ue_ctx->imsi);
return false;
}
//Pack NAS Authentication Request in Downlink NAS Transport msg
pack_authentication_request(reply_msg, ue_ctx->enb_ue_s1ap_id, ue_ctx->mme_ue_s1ap_id, autn, rand);
//Send reply to eNB
*reply_flag = true;
m_s1ap_log->info("Downlink NAS: Sent Authentication Request\n");
m_s1ap_log->console("Downlink NAS: Sent Authentication Request\n");
//TODO Start T3460 Timer!
break;
}
return true;
}
/*Packing/Unpacking helper functions*/ /*Packing/Unpacking helper functions*/
bool bool
s1ap_nas_transport::pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t *autn, uint8_t *rand) s1ap_nas_transport::pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t *autn, uint8_t *rand)

@ -6,8 +6,9 @@
# IMSI: UE's IMSI value # IMSI: UE's IMSI value
# Key: UE's key, where other keys are derived from. Stored in hexadecimal # Key: UE's key, where other keys are derived from. Stored in hexadecimal
# OP: Operator's code, sotred in hexadecimal # OP: Operator's code, sotred in hexadecimal
# AMF: Authentication management feild, stored in hexadecimal # AMF: Authentication management field, stored in hexadecimal
# SQN: UE's Sequence number for freshness of the authentication
# #
# Note: Lines starting by '#' are ignored # Note: Lines starting by '#' are ignored
ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001 ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001,000000001234
ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000 ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000,000000001235

@ -70,6 +70,8 @@ public:
void start_plot(); void start_plot();
float get_ref_cfo(); float get_ref_cfo();
float get_cfo();
float get_ul_cfo();
private: private:
/* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */

@ -246,7 +246,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. Must be disabled if cells have identical channel and timing.") "Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. Must be disabled if cells have identical channel and timing.")
("expert.average_subframe_enabled", ("expert.average_subframe_enabled",
bpo::value<bool>(&args->expert.phy.average_subframe_enabled)->default_value(false), bpo::value<bool>(&args->expert.phy.average_subframe_enabled)->default_value(true),
"Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.")
("expert.time_correct_period", ("expert.time_correct_period",

@ -203,6 +203,25 @@ float phch_worker::get_ref_cfo()
return srslte_chest_dl_get_cfo(&ue_dl.chest); return srslte_chest_dl_get_cfo(&ue_dl.chest);
} }
float phch_worker::get_cfo()
{
return cfo;
}
float phch_worker::get_ul_cfo() {
srslte::radio *radio = phy->get_radio();
if (radio->get_freq_offset() != 0.0f) {
/* Compensates the radio frequency offset applied equally to DL and UL */
const float ul_dl_ratio = (float) radio->get_tx_freq() / (float) radio->get_rx_freq();
const float offset_hz = (float) radio->get_freq_offset() * (1.0f - ul_dl_ratio);
return cfo - offset_hz / (15000);
} else {
return cfo;
}
}
void phch_worker::work_imp() void phch_worker::work_imp()
{ {
if (!cell_initiated) { if (!cell_initiated) {
@ -324,7 +343,7 @@ void phch_worker::work_imp()
} }
/* Set UL CFO before transmission */ /* Set UL CFO before transmission */
srslte_ue_ul_set_cfo(&ue_ul, cfo); srslte_ue_ul_set_cfo(&ue_ul, get_ul_cfo());
/* Transmit PUSCH, PUCCH or SRS */ /* Transmit PUSCH, PUCCH or SRS */
bool signal_ready = false; bool signal_ready = false;
@ -367,7 +386,7 @@ void phch_worker::work_imp()
update_measurements(); update_measurements();
if (chest_ok) { if (chest_ok) {
if (phy->avg_rsrp_dbm > -130.0 && 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)) > -30.0) { if (phy->avg_rsrp_dbm > -130.0 && phy->avg_snr_db > -30.0) {
log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n", log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n",
10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), phy->avg_rsrp_dbm); 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), phy->avg_rsrp_dbm);
chest_loop->in_sync(); chest_loop->in_sync();
@ -1476,6 +1495,13 @@ plot_scatter_t pconst;
float tmp_plot[SCATTER_PDSCH_BUFFER_LEN]; float tmp_plot[SCATTER_PDSCH_BUFFER_LEN];
cf_t tmp_plot2[SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)]; cf_t tmp_plot2[SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)];
#define CFO_PLOT_LEN 0 /* Set to non zero for enabling CFO plot */
#if CFO_PLOT_LEN > 0
static plot_real_t pcfo;
static uint32_t icfo = 0;
static float cfo_buffer[CFO_PLOT_LEN];
#endif /* CFO_PLOT_LEN > 0 */
void *plot_thread_run(void *arg) { void *plot_thread_run(void *arg) {
srsue::phch_worker *worker = (srsue::phch_worker*) arg; srsue::phch_worker *worker = (srsue::phch_worker*) arg;
@ -1500,10 +1526,14 @@ void *plot_thread_run(void *arg) {
plot_scatter_addToWindowGrid(&pconst, (char*)"srsue", 0, worker->get_rx_nof_antennas()); plot_scatter_addToWindowGrid(&pconst, (char*)"srsue", 0, worker->get_rx_nof_antennas());
#if CFO_PLOT_LEN > 0
plot_real_init(&pcfo);
plot_real_setTitle(&pcfo, (char*) "CFO (Hz)");
plot_real_setLabels(&pcfo, (char *) "Time", (char *) "Hz");
plot_real_setYAxisScale(&pcfo, -4000, 4000);
plot_scatter_addToWindowGrid(&pcfo, (char*)"srsue", 1, worker->get_rx_nof_antennas());
#endif /* CFO_PLOT_LEN > 0 */
int n; int n;
int readed_pdsch_re=0; int readed_pdsch_re=0;
@ -1527,7 +1557,14 @@ void *plot_thread_run(void *arg) {
} }
readed_pdsch_re = 0; readed_pdsch_re = 0;
} }
}
#if CFO_PLOT_LEN > 0
cfo_buffer[icfo] = worker->get_cfo() * 15000.0f;
icfo = (icfo + 1)%CFO_PLOT_LEN;
plot_real_setNewData(&pcfo, cfo_buffer, CFO_PLOT_LEN);
#endif /* CFO_PLOT_LEN > 0 */
}
return NULL; return NULL;
} }

@ -201,7 +201,7 @@ srslte::error_t gw::init_if(char *err_str)
} }
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ-1);
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0; ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0;
if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) if(0 > ioctl(tun_fd, TUNSETIFF, &ifr))
{ {

@ -665,6 +665,11 @@ void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) {
pdu->reset(); pdu->reset();
liblte_mme_pack_identity_response_msg(&id_resp, (LIBLTE_BYTE_MSG_STRUCT *) pdu); liblte_mme_pack_identity_response_msg(&id_resp, (LIBLTE_BYTE_MSG_STRUCT *) pdu);
if(pcap != NULL) {
pcap->write_nas(pdu->msg, pdu->N_bytes);
}
rrc->write_sdu(lcid, pdu); rrc->write_sdu(lcid, pdu);
} }

@ -197,7 +197,7 @@ enable = false
#sfo_correct_disable = false #sfo_correct_disable = false
#sss_algorithm = full #sss_algorithm = full
#estimator_fil_w = 0.1 #estimator_fil_w = 0.1
#average_subframe_enabled = false #average_subframe_enabled = true
#sic_pss_enabled = true #sic_pss_enabled = true
#pregenerate_signals = false #pregenerate_signals = false
#metrics_csv_enable = false #metrics_csv_enable = false

Loading…
Cancel
Save