mirror of https://github.com/PentHertz/srsLTE.git
Merging next into guti_attach branch
This commit is contained in:
commit
c6e2f144d7
|
@ -371,7 +371,7 @@ if(RF_FOUND)
|
|||
message(STATUS "Building with srsENB")
|
||||
add_subdirectory(srsenb)
|
||||
else(ENABLE_SRSENB)
|
||||
message(STATUS "srsUE build disabled")
|
||||
message(STATUS "srsENB build disabled")
|
||||
endif(ENABLE_SRSENB)
|
||||
else(RF_FOUND)
|
||||
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-l Force N_id_2 [Default best]\n");
|
||||
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-R Average channel estimates on 1 ms [Default %s]\n", args->average_subframe?"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-t Add time offset [Default %d]\n", args->time_offset);
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
printf("\t-d disable plots [Default enabled]\n");
|
||||
|
|
|
@ -99,7 +99,6 @@ public:
|
|||
|
||||
if (is_almost_empty()) {
|
||||
printf("Warning buffer pool capacity is %f %%\n", (float) 100*available.size()/capacity);
|
||||
print_all_buffers();
|
||||
}
|
||||
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
if (debug_name) {
|
||||
|
|
|
@ -70,6 +70,7 @@ public:
|
|||
level = LOG_LEVEL_NONE;
|
||||
hex_limit = 0;
|
||||
show_layer_en = true;
|
||||
add_string_en = false;
|
||||
level_text_short = true;
|
||||
}
|
||||
|
||||
|
@ -79,6 +80,7 @@ public:
|
|||
level = LOG_LEVEL_NONE;
|
||||
hex_limit = 0;
|
||||
show_layer_en = true;
|
||||
add_string_en = false;
|
||||
level_text_short = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,10 @@
|
|||
|
||||
class thread
|
||||
{
|
||||
public:
|
||||
public:
|
||||
thread() {
|
||||
_thread = 0;
|
||||
}
|
||||
bool start(int prio = -1) {
|
||||
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_rx_freq(double freq);
|
||||
|
||||
double get_freq_offset();
|
||||
double get_tx_freq();
|
||||
double get_rx_freq();
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ public:
|
|||
void init(srsue::pdcp_interface_rlc *pdcp_,
|
||||
srsue::rrc_interface_rlc *rrc_,
|
||||
srsue::ue_interface *ue_,
|
||||
log *rlc_log_,
|
||||
mac_interface_timers *mac_timers_,
|
||||
uint32_t lcid_);
|
||||
log *rlc_log_,
|
||||
mac_interface_timers *mac_timers_,
|
||||
uint32_t lcid_);
|
||||
void stop();
|
||||
|
||||
void get_metrics(rlc_metrics_t &m);
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
namespace srslte {
|
||||
|
||||
|
||||
#undef RLC_AM_BUFFER_DEBUG
|
||||
|
||||
struct rlc_amd_rx_pdu_t{
|
||||
rlc_amd_pdu_header_t header;
|
||||
|
@ -189,6 +189,7 @@ private:
|
|||
bool inside_tx_window(uint16_t sn);
|
||||
bool inside_rx_window(uint16_t sn);
|
||||
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);
|
||||
int required_buffer_size(rlc_amd_retx_t retx);
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace srslte{
|
|||
logger_file::logger_file()
|
||||
:inited(false)
|
||||
,not_done(true)
|
||||
,cur_length(0)
|
||||
,max_length(0)
|
||||
{}
|
||||
|
||||
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_cond_init(¬_empty, NULL);
|
||||
pthread_cond_init(¬_full, NULL);
|
||||
this->max_length = max_length*1024;
|
||||
max_length = max_length_*1024;
|
||||
name_idx = 0;
|
||||
filename = file;
|
||||
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 */
|
||||
float norm = 1;
|
||||
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;
|
||||
if (q->average_subframe) {
|
||||
norm = 32;
|
||||
} else {
|
||||
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);
|
||||
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 */
|
||||
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] = energy*energy;
|
||||
q->rsrp[rxant_id][port_id] = __real__ srslte_vec_dot_prod_conj_ccc(q->pilot_estimates, q->pilot_estimates, npilots) / npilots;
|
||||
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");
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
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_regs_t regs;
|
||||
int i, j, k;
|
||||
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
|
||||
int nof_re;
|
||||
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;
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ void parse_args(int argc, char **argv) {
|
|||
cfi = atoi(argv[optind]);
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
case 'p':
|
||||
|
|
|
@ -313,6 +313,11 @@ double radio::get_rx_freq()
|
|||
return rx_freq;
|
||||
}
|
||||
|
||||
double radio::get_freq_offset()
|
||||
{
|
||||
return freq_offset;
|
||||
}
|
||||
|
||||
double radio::get_tx_freq()
|
||||
{
|
||||
return tx_freq;
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
#include <sstream>
|
||||
|
||||
#define MOD 1024
|
||||
#define RX_MOD_BASE(x) (x-vr_r)%1024
|
||||
#define TX_MOD_BASE(x) (x-vt_a)%1024
|
||||
#define RX_MOD_BASE(x) ((x-vr_r)%1024)
|
||||
#define TX_MOD_BASE(x) ((x-vt_a)%1024)
|
||||
|
||||
namespace srslte {
|
||||
|
||||
|
@ -312,6 +312,22 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|||
pthread_mutex_unlock(&mutex);
|
||||
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
|
||||
if(retx_queue.size() > 0) {
|
||||
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
|
||||
rlc_amd_pdu_header_t new_header = tx_window[retx.sn].header;
|
||||
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())
|
||||
{
|
||||
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 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.rf = 1;
|
||||
new_header.p = 0;
|
||||
new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED;
|
||||
new_header.sn = old_header.sn;
|
||||
new_header.lsf = 0;
|
||||
new_header.so = retx.so_start;
|
||||
new_header.N_li = 0;
|
||||
new_header.p = 0;
|
||||
if(poll_required())
|
||||
{
|
||||
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 pdu_space = 0;
|
||||
|
@ -636,8 +672,15 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|||
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;
|
||||
if (!pdu) {
|
||||
#ifdef RLC_AM_BUFFER_DEBUG
|
||||
log->console("Fatal Error: Could not allocate PDU in build_data_pdu()\n");
|
||||
log->console("tx_window size: %d PDUs\n", tx_window.size());
|
||||
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);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
pdu.buf = pool_allocate;
|
||||
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);
|
||||
#else
|
||||
log->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
if(reordering_timeout.is_running())
|
||||
{
|
||||
if(
|
||||
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))
|
||||
)
|
||||
if(vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr))
|
||||
{
|
||||
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;
|
||||
segment.buf = pool_allocate;
|
||||
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);
|
||||
#else
|
||||
log->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment().\n");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(segment.buf->msg, payload, nof_bytes);
|
||||
segment.buf->N_bytes = nof_bytes;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RLC_AM_BUFFER_DEBUG
|
||||
print_rx_segments();
|
||||
#endif
|
||||
debug_state();
|
||||
}
|
||||
|
||||
|
@ -963,6 +1018,11 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|||
|
||||
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
|
||||
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it;
|
||||
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;
|
||||
|
||||
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 &&
|
||||
status.nacks[j].so_end <= it->second.buf->N_bytes) {
|
||||
retx.is_segment = true;
|
||||
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 {
|
||||
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);
|
||||
|
@ -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
|
||||
if(tx_window.count(i) > 0) {
|
||||
it = tx_window.find(i);
|
||||
it->second.is_acked = true;
|
||||
if(it->second.buf) {
|
||||
pool->deallocate(it->second.buf);
|
||||
it->second.buf = 0;
|
||||
log->info("SN=%d removed from tx_window\n", i);
|
||||
}
|
||||
tx_window.erase(it);
|
||||
if(update_vt_a)
|
||||
{
|
||||
vt_a = (vt_a + 1)%MOD;
|
||||
vt_ms = (vt_ms + 1)%MOD;
|
||||
if (it != tx_window.end()) {
|
||||
if(update_vt_a) {
|
||||
tx_window.erase(it);
|
||||
if(it->second.buf) {
|
||||
pool->deallocate(it->second.buf);
|
||||
it->second.buf = 0;
|
||||
}
|
||||
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) {
|
||||
rx_sdu = pool_allocate;
|
||||
if (!rx_sdu) {
|
||||
#ifdef RLC_AM_BUFFER_DEBUG
|
||||
log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n");
|
||||
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
|
||||
|
@ -1057,10 +1132,14 @@ void rlc_am::reassemble_rx_sdus()
|
|||
pdcp->write_pdu(lcid, rx_sdu);
|
||||
rx_sdu = pool_allocate;
|
||||
if (!rx_sdu) {
|
||||
#ifdef RLC_AM_BUFFER_DEBUG
|
||||
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
|
||||
|
@ -1073,8 +1152,13 @@ void rlc_am::reassemble_rx_sdus()
|
|||
pdcp->write_pdu(lcid, rx_sdu);
|
||||
rx_sdu = pool_allocate;
|
||||
if (!rx_sdu) {
|
||||
#ifdef RLC_AM_BUFFER_DEBUG
|
||||
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)
|
||||
{
|
||||
// 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
|
||||
byte_buffer_t *full_pdu = pool_allocate;
|
||||
if (!full_pdu) {
|
||||
#ifdef RLC_AM_BUFFER_DEBUG
|
||||
log->console("Fatal Error: Could not allocate PDU in add_segment_and_check()\n");
|
||||
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++) {
|
||||
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)
|
||||
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)
|
||||
target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common)
|
||||
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)) {
|
||||
data->hnb_name_present = true;
|
||||
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_size = strnlen(hnb_name.c_str(), 48);
|
||||
} else if (hex_enabled) {
|
||||
|
|
|
@ -630,7 +630,7 @@ int sched::dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST])
|
|||
}
|
||||
|
||||
} 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 {
|
||||
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))
|
||||
{
|
||||
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);
|
||||
|
||||
sched_result->pusch[nof_dci_elems].needs_pdcch = false;
|
||||
|
|
|
@ -24,6 +24,7 @@ mme_bind_addr = 127.0.1.100
|
|||
#####################################################################
|
||||
# HSS configuration
|
||||
#
|
||||
# algo: Authentication algorithm (xor/milenage)
|
||||
# db_file: Location of .csv file that stores UEs information.
|
||||
#
|
||||
#####################################################################
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "srslte/common/logger_file.h"
|
||||
#include "srslte/common/log_filter.h"
|
||||
#include "srslte/common/buffer_pool.h"
|
||||
#include "srslte/interfaces/epc_interfaces.h"
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
|
@ -56,6 +57,8 @@ typedef struct{
|
|||
uint8_t key[16];
|
||||
uint8_t op[16];
|
||||
uint8_t amf[2];
|
||||
uint8_t sqn[6];
|
||||
uint8_t last_rand[16];
|
||||
}hss_ue_ctx_t;
|
||||
|
||||
enum hss_auth_algo {
|
||||
|
@ -63,7 +66,7 @@ enum hss_auth_algo {
|
|||
HSS_ALGO_MILENAGE
|
||||
};
|
||||
|
||||
class hss
|
||||
class hss : public hss_interface_s1ap
|
||||
{
|
||||
public:
|
||||
static hss* get_instance(void);
|
||||
|
@ -71,18 +74,8 @@ public:
|
|||
int init(hss_args_t *hss_args, srslte::log_filter* hss_log);
|
||||
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_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);
|
||||
|
||||
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);
|
||||
bool resync_sqn(uint64_t imsi, uint8_t *auts);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -90,14 +83,38 @@ private:
|
|||
virtual ~hss();
|
||||
static hss *m_instance;
|
||||
|
||||
uint64_t m_sqn; //48 bits
|
||||
srslte::byte_buffer_pool *m_pool;
|
||||
std::ifstream m_db_file;
|
||||
|
||||
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*/
|
||||
srslte::log_filter *m_hss_log;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ class mme:
|
|||
public:
|
||||
static mme* get_instance(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();
|
||||
int get_s1_mme();
|
||||
void run_thread();
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
static void cleanup();
|
||||
|
||||
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();
|
||||
|
||||
int get_s1_mme();
|
||||
|
@ -114,7 +114,7 @@ private:
|
|||
uint32_t m_plmn;
|
||||
srslte::byte_buffer_pool *m_pool;
|
||||
|
||||
hss *m_hss;
|
||||
hss_interface_s1ap *m_hss;
|
||||
int m_s1mme;
|
||||
std::map<uint16_t, enb_ctx_t*> m_active_enbs;
|
||||
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* get_instance(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_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,
|
||||
bool* reply_flag,
|
||||
struct sctp_sndrcvinfo *enb_sri);
|
||||
|
||||
bool handle_nas_service_request(uint32_t m_tmsi,
|
||||
uint32_t enb_ue_s1ap_id,
|
||||
srslte::byte_buffer_t *nas_msg,
|
||||
|
@ -106,7 +107,7 @@ private:
|
|||
srslte::byte_buffer_pool *m_pool;
|
||||
|
||||
s1ap* m_s1ap;
|
||||
hss* m_hss;
|
||||
hss_interface_s1ap* m_hss;
|
||||
mme_gtpc* m_mme_gtpc;
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <time.h> /* time */
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "hss/hss.h"
|
||||
#include "srslte/common/security.h"
|
||||
|
@ -39,8 +40,6 @@ hss* hss::m_instance = NULL;
|
|||
boost::mutex hss_instance_mutex;
|
||||
|
||||
hss::hss()
|
||||
// :m_sqn(0x112233445566)
|
||||
:m_sqn(0)
|
||||
{
|
||||
m_pool = srslte::byte_buffer_pool::get_instance();
|
||||
return;
|
||||
|
@ -92,27 +91,26 @@ hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
|
|||
|
||||
mcc = hss_args->mcc;
|
||||
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->console("HSS Initialized\n");
|
||||
m_hss_log->console("HSS Initialized.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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();
|
||||
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->console("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: %015lu\n", it->second->imsi);
|
||||
delete it->second;
|
||||
m_imsi_to_ue_ctx.erase(it++);
|
||||
}
|
||||
if(m_db_file.is_open())
|
||||
{
|
||||
m_db_file.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -139,6 +137,8 @@ hss::set_auth_algo(std::string auth_algo)
|
|||
bool
|
||||
hss::read_db_file(std::string db_filename)
|
||||
{
|
||||
std::ifstream m_db_file;
|
||||
|
||||
m_db_file.open(db_filename.c_str(), std::ifstream::in);
|
||||
if(!m_db_file.is_open())
|
||||
{
|
||||
|
@ -152,7 +152,7 @@ hss::read_db_file(std::string db_filename)
|
|||
if(line[0] != '#')
|
||||
{
|
||||
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");
|
||||
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[3],ue_ctx->op,16);
|
||||
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_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->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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -189,10 +238,101 @@ 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);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
|
||||
{
|
||||
|
@ -207,13 +347,12 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
|
|||
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;
|
||||
}
|
||||
gen_rand(rand);
|
||||
get_sqn(sqn);
|
||||
|
||||
|
||||
security_milenage_f2345( k,
|
||||
op,
|
||||
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: ");
|
||||
|
||||
set_last_rand(imsi, rand);
|
||||
|
||||
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;
|
||||
|
||||
if(!get_k_amf_op(imsi,k,amf,op))
|
||||
if(!get_k_amf_op_sqn(imsi, k, amf, op, sqn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
gen_rand(rand);
|
||||
get_sqn(sqn);
|
||||
|
||||
// Use RAND and K to compute RES, CK, IK and AK
|
||||
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: ");
|
||||
|
||||
set_last_rand(imsi, rand);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
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;
|
||||
m_hss_log->info("Found User %015lu\n",imsi);
|
||||
memcpy(k,ue_ctx->key,16);
|
||||
memcpy(amf,ue_ctx->amf,2);
|
||||
memcpy(op,ue_ctx->op,16);
|
||||
memcpy(k, ue_ctx->key, 16);
|
||||
memcpy(amf, ue_ctx->amf, 2);
|
||||
memcpy(op, ue_ctx->op, 16);
|
||||
memcpy(sqn, ue_ctx->sqn, 6);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
hss::get_sqn(uint8_t sqn[6])
|
||||
void
|
||||
hss::increment_sqn(uint64_t imsi)
|
||||
{
|
||||
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++;
|
||||
return; //TODO See TS 33.102, Annex C
|
||||
|
||||
// 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
|
||||
hss::get_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(rand, ue_ctx->last_rand, 16);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -426,6 +617,19 @@ hss::gen_rand(uint8_t rand_[16])
|
|||
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*/
|
||||
std::vector<std::string>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
string_to_imsi()
|
||||
|
|
|
@ -306,19 +306,20 @@ main (int argc,char * argv[] )
|
|||
spgw_log.init("SPGW",logger);
|
||||
spgw_log.set_level(level(args.log_args.spgw_level));
|
||||
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();
|
||||
if (hss->init(&args.hss_args,&hss_log)) {
|
||||
cout << "Error initializing HSS" << endl;
|
||||
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();
|
||||
if (spgw->init(&args.spgw_args,&spgw_log)) {
|
||||
cout << "Error initializing SP-GW" << endl;
|
||||
|
|
|
@ -70,7 +70,7 @@ mme::cleanup(void)
|
|||
}
|
||||
|
||||
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*/
|
||||
|
@ -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;
|
||||
/*Init S1AP*/
|
||||
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");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ s1ap::cleanup(void)
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
|
@ -78,17 +78,17 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log)
|
|||
//Init log
|
||||
m_s1ap_log = s1ap_log;
|
||||
|
||||
//Get pointer to the HSS
|
||||
m_hss = hss_;
|
||||
|
||||
//Init message handlers
|
||||
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures
|
||||
m_s1ap_mngmt_proc->init();
|
||||
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->init();
|
||||
|
||||
|
||||
//Get pointer to the HSS
|
||||
m_hss = hss::get_instance();
|
||||
//Get pointer to GTP-C class
|
||||
m_mme_gtpc = mme_gtpc::get_instance();
|
||||
//Initialize S1-MME
|
||||
|
|
|
@ -65,13 +65,13 @@ s1ap_nas_transport::cleanup(void)
|
|||
}
|
||||
|
||||
void
|
||||
s1ap_nas_transport::init(void)
|
||||
s1ap_nas_transport::init(hss_interface_s1ap * hss_)
|
||||
{
|
||||
m_s1ap = s1ap::get_instance();
|
||||
m_s1ap_log = m_s1ap->m_s1ap_log;
|
||||
m_pool = srslte::byte_buffer_pool::get_instance();
|
||||
|
||||
m_hss = hss::get_instance();
|
||||
m_hss = hss_;
|
||||
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");
|
||||
handle_tracking_area_update_request(nas_msg, ue_ecm_ctx, reply_buffer, reply_flag);
|
||||
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:
|
||||
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 );
|
||||
|
@ -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_ERROR_ENUM err = liblte_mme_unpack_identity_response_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &id_resp);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -884,8 +889,8 @@ s1ap_nas_transport::handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_
|
|||
|
||||
//Send reply to eNB
|
||||
*reply_flag = true;
|
||||
m_s1ap_log->info("Downlink NAS: Sent Athentication Request\n");
|
||||
m_s1ap_log->console("Downlink NAS: Sent Athentication Request\n");
|
||||
m_s1ap_log->info("Downlink NAS: Sent Authentication Request\n");
|
||||
m_s1ap_log->console("Downlink NAS: Sent Authentication Request\n");
|
||||
//TODO Start T3460 Timer!
|
||||
|
||||
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->HandoverRestrictionList_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;
|
||||
|
||||
|
||||
|
@ -942,7 +947,7 @@ s1ap_nas_transport::handle_tracking_area_update_request(srslte::byte_buffer_t *n
|
|||
bool eps_network_feature_support_present;
|
||||
bool additional_update_result_present;
|
||||
bool t3412_ext_present;
|
||||
|
||||
*/
|
||||
//Get decimal MCC and MNC
|
||||
uint32_t mcc = 0;
|
||||
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*/
|
||||
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)
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
# IMSI: UE's IMSI value
|
||||
# Key: UE's key, where other keys are derived from. Stored 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
|
||||
ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001
|
||||
ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000
|
||||
ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001,000000001234
|
||||
ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,8000,000000001235
|
||||
|
|
|
@ -70,6 +70,8 @@ public:
|
|||
void start_plot();
|
||||
|
||||
float get_ref_cfo();
|
||||
float get_cfo();
|
||||
float get_ul_cfo();
|
||||
|
||||
private:
|
||||
/* 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.")
|
||||
|
||||
("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.")
|
||||
|
||||
("expert.time_correct_period",
|
||||
|
|
|
@ -203,6 +203,25 @@ float phch_worker::get_ref_cfo()
|
|||
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()
|
||||
{
|
||||
if (!cell_initiated) {
|
||||
|
@ -324,7 +343,7 @@ void phch_worker::work_imp()
|
|||
}
|
||||
|
||||
/* 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 */
|
||||
bool signal_ready = false;
|
||||
|
@ -367,7 +386,7 @@ void phch_worker::work_imp()
|
|||
update_measurements();
|
||||
|
||||
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",
|
||||
10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), phy->avg_rsrp_dbm);
|
||||
chest_loop->in_sync();
|
||||
|
@ -1476,6 +1495,13 @@ plot_scatter_t pconst;
|
|||
float tmp_plot[SCATTER_PDSCH_BUFFER_LEN];
|
||||
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) {
|
||||
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());
|
||||
|
||||
#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 readed_pdsch_re=0;
|
||||
|
@ -1527,7 +1557,14 @@ void *plot_thread_run(void *arg) {
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -201,7 +201,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);
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ-1);
|
||||
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0;
|
||||
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();
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ enable = false
|
|||
#sfo_correct_disable = false
|
||||
#sss_algorithm = full
|
||||
#estimator_fil_w = 0.1
|
||||
#average_subframe_enabled = false
|
||||
#average_subframe_enabled = true
|
||||
#sic_pss_enabled = true
|
||||
#pregenerate_signals = false
|
||||
#metrics_csv_enable = false
|
||||
|
|
Loading…
Reference in New Issue