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")
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(&not_empty, NULL);
pthread_cond_init(&not_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,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);
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
@ -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::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
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++;
return; //TODO See TS 33.102, Annex C
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…
Cancel
Save