new NAS/RRC structure. Attaching and ping working

master
Ismael Gomez 8 years ago
parent fa05304632
commit fa9eaee498

@ -30,6 +30,7 @@
#include <ctype.h>
#include <stdint.h>
#include <string>
#include <srslte/asn1/liblte_rrc.h>
namespace srslte {
@ -112,6 +113,12 @@ inline bool mnc_to_string(uint16_t mnc, std::string *str)
*str += (mnc & 0x000F) + '0';
return true;
}
inline std::string plmn_id_to_c_str(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
std::string mcc_str, mnc_str;
mnc_to_string(plmn_id.mnc, &mnc_str);
mcc_to_string(plmn_id.mcc, &mcc_str);
return mcc_str + mnc_str;
}
} // namespace srslte

@ -623,7 +623,9 @@ int rf_uhd_recv_with_time_multi(void *h,
log_overflow(handler);
} else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) {
log_late(handler);
} else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE) {
} else if (error_code == UHD_RX_METADATA_ERROR_CODE_TIMEOUT) {
fprintf(stderr, "Error timed out while receiving asynchronoous messages from UHD.\n");
} else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE ) {
fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", error_code);
}

@ -389,8 +389,6 @@ void radio::set_tx_srate(float srate)
// Calculate TX advance in seconds from samples and sampling rate
tx_adv_sec = nsamples/cur_tx_srate;
printf("Setting TX/RX offset %d samples, %.2f us\n", nsamples, tx_adv_sec*1e6);
}
void radio::start_rx()

@ -74,7 +74,6 @@ private:
void set_ue_sync_opts(srslte_ue_sync_t *q);
void run_thread();
int sync_sfn();
bool running;
@ -91,15 +90,19 @@ private:
uint32_t nof_rx_antennas;
cf_t *sf_buffer_sfn[SRSLTE_MAX_PORTS];
cf_t *sf_buffer[SRSLTE_MAX_PORTS];
// Sync metrics
sync_metrics_t metrics;
enum {
IDLE, CELL_SEARCH, CELL_SELECT, CAMPING
IDLE, CELL_SEARCH, CELL_MEASURE, CELL_SELECT, CELL_CAMP
} phy_state;
enum {
SRATE_NONE=0, SRATE_FIND, SRATE_CAMP
} srate_mode;
srslte_cell_t cell;
bool cell_is_set;
bool is_sfn_synched;
@ -118,7 +121,16 @@ private:
const static uint32_t SYNC_SFN_TIMEOUT = 5000;
float ul_dl_factor;
int cur_earfcn_index;
bool cell_search_in_progress;
uint32_t measure_cnt;
float measure_rsrp;
srslte_ue_dl_t ue_dl_measure;
const static int RSRP_MEASURE_NOF_FRAMES = 20;
int cell_sync_sfn();
int cell_meas_rsrp();
bool cell_search(int force_N_id_2 = -1);
bool init_cell();
void free_cell();

@ -61,6 +61,7 @@ namespace srsue {
*******************************************************************************/
typedef struct {
uint32_t dl_earfcn;
float dl_freq;
float ul_freq;
float rx_gain;

@ -107,6 +107,9 @@ namespace srsue {
plmn_selection_state_t plmn_selection;
LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn;
LIBLTE_RRC_PLMN_IDENTITY_STRUCT home_plmn;
std::vector<LIBLTE_RRC_PLMN_IDENTITY_STRUCT > known_plmns;
// Save short MAC

@ -61,8 +61,7 @@ namespace srsue {
typedef enum {
SI_ACQUIRE_IDLE = 0,
SI_ACQUIRE_SIB1,
SI_ACQUIRE_SIB2,
SI_ACQUIRE_DONE
SI_ACQUIRE_SIB2
} si_acquire_state_t;

@ -141,7 +141,7 @@ void mac::run_thread() {
while(started) {
while (!phy_h->sync_status()) {
while (!phy_h->sync_status() && started) {
usleep(5000);
if (phy_h->sync_status()) {
Debug("Setting ttysync to %d\n", phy_h->get_current_tti());

@ -61,8 +61,9 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
// Command line or config file options
bpo::options_description common("Configuration options");
common.add_options()
("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(2680000000), "Downlink centre frequency")
("rf.ul_freq", bpo::value<float>(&args->rf.ul_freq)->default_value(2560000000), "Uplink centre frequency")
("rf.dl_earfcn", bpo::value<uint32_t>(&args->rf.dl_earfcn)->default_value(3400), "Downlink EARFCN")
("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(2680000000), "(optional) Downlink centre frequency")
("rf.ul_freq", bpo::value<float>(&args->rf.ul_freq)->default_value(2560000000), "(optional) Uplink centre frequency")
("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain")
("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain")
("rf.nof_rx_ant", bpo::value<uint32_t>(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas")

@ -25,6 +25,7 @@
*/
#include <unistd.h>
#include <srslte/srslte.h>
#include "srslte/srslte.h"
#include "srslte/common/log.h"
#include "phy/phch_worker.h"
@ -62,9 +63,11 @@ namespace srsue {
time_adv_sec = 0;
cell_is_set = false;
sync_sfn_cnt = 0;
srate_mode = SRATE_NONE;
cell_search_in_progress = false;
for (uint32_t i = 0; i < nof_rx_antennas; i++) {
sf_buffer_sfn[i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100));
sf_buffer[i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100));
}
nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers();
@ -82,8 +85,8 @@ namespace srsue {
running = false;
wait_thread_finish();
for (uint32_t i = 0; i < nof_rx_antennas; i++) {
if (sf_buffer_sfn[i]) {
free(sf_buffer_sfn[i]);
if (sf_buffer[i]) {
free(sf_buffer[i]);
}
}
}
@ -152,9 +155,14 @@ namespace srsue {
// Set options defined in expert section
set_ue_sync_opts(&ue_sync);
if (srslte_ue_dl_init_multi(&ue_dl_measure, cell, nof_rx_antennas)) {
Error("Setting cell: initiating ue_dl_measure\n");
return false;
}
for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) {
if (!((phch_worker *) workers_pool->get_worker(i))->init_cell(cell)) {
Error("Error setting cell: initiating PHCH worker\n");
Error("Setting cell: initiating PHCH worker\n");
return false;
}
}
@ -179,6 +187,10 @@ namespace srsue {
usleep(2000);
}
srslte_ue_sync_free(&ue_sync);
srslte_ue_dl_free(&ue_dl_measure);
if (cell_is_set) {
for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) {
((phch_worker *) workers_pool->get_worker(i))->free_cell();
@ -198,7 +210,6 @@ namespace srsue {
bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t));
log_h->console("Searching for cell...\n");
if (srslte_ue_cellsearch_init_multi(&cs, SRSLTE_DEFAULT_MAX_FRAMES_PSS, radio_recv_wrapper_cs, nof_rx_antennas,
radio_h)) {
Error("Initiating UE cell search\n");
@ -214,7 +225,10 @@ namespace srsue {
srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain);
}
if (srate_mode != SRATE_FIND) {
srate_mode = SRATE_FIND;
radio_h->set_rx_srate(1.92e6);
}
radio_h->start_rx();
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
@ -246,9 +260,6 @@ namespace srsue {
cell.cp = found_cells[max_peak_cell].cp;
cellsearch_cfo = found_cells[max_peak_cell].cfo;
log_h->console("Found CELL ID: %d CP: %s, CFO: %.1f KHz.\nTrying to decode MIB...\n",
cell.id, srslte_cp_string(cell.cp), cellsearch_cfo / 1000);
srslte_ue_mib_sync_t ue_mib_sync;
if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, nof_rx_antennas,
@ -281,10 +292,6 @@ namespace srsue {
if (ret == 1) {
srslte_pbch_mib_unpack(bch_payload, &cell, NULL);
worker_com->set_cell(cell);
srslte_cell_fprint(stdout, &cell, 0);
srslte_bit_pack_vector(bch_payload, bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN);
mac->bch_decoded_ok(bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN / 8);
return true;
} else {
Warning("Error decoding MIB: Error decoding PBCH\n");
@ -293,45 +300,6 @@ namespace srsue {
}
int phch_recv::sync_sfn(void) {
int ret = SRSLTE_ERROR;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer_sfn);
if (ret < 0) {
Error("Error calling ue_sync_get_buffer");
return -1;
}
if (ret == 1) {
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
int sfn_offset = 0;
Info("SYNC: Decoding MIB...\n");
int n = srslte_ue_mib_decode(&ue_mib, sf_buffer_sfn[0], bch_payload, NULL, &sfn_offset);
if (n < 0) {
Error("Error decoding MIB while synchronising SFN");
return -1;
} else if (n == SRSLTE_UE_MIB_FOUND) {
uint32_t sfn;
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
sfn = (sfn+sfn_offset)%1024;
tti = sfn * 10;
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", tti, sfn_offset);
srslte_ue_mib_reset(&ue_mib);
return 1;
}
}
} else {
Debug("SYNC: PSS/SSS not found...\n");
}
return 0;
}
void phch_recv::resync_sfn() {
sync_sfn_cnt = 0;
phy_state = CELL_SELECT;
@ -342,17 +310,17 @@ namespace srsue {
}
void phch_recv::cell_search_next() {
cell_search_in_progress = true;
cur_earfcn_index++;
if (cur_earfcn_index >= 0) {
if ((uint32_t) cur_earfcn_index >= earfcn.size() - 1) {
if (cur_earfcn_index >= (int) earfcn.size() - 1) {
cur_earfcn_index = 0;
}
// If PHY is running, stop and free resources
free_cell();
float dl_freq = srslte_band_fd(earfcn[cur_earfcn_index]);
float dl_freq = 1e6*srslte_band_fd(earfcn[cur_earfcn_index]);
if (dl_freq >= 0) {
log_h->console("Cell Search: Set DL EARFCN=%d, frequency=%.1f MHz\n", earfcn[cur_earfcn_index], dl_freq / 1e6);
log_h->info("Cell Search: Set DL EARFCN=%d, frequency=%.1f MHz, channel_index=%d\n", earfcn[cur_earfcn_index],
dl_freq / 1e6, cur_earfcn_index);
radio_h->set_rx_freq(dl_freq);
@ -366,25 +334,39 @@ namespace srsue {
}
void phch_recv::cell_search_start() {
if (earfcn.size() > 0) {
cur_earfcn_index = -1;
log_h->console("Cell Search: Starting procedure...\n");
log_h->console("Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size());
log_h->info("Cell Search: Starting procedure...\n");
cell_search_next();
} else {
log_h->info("Empty EARFCN list. Stopping cell search...\n");
log_h->console("Empty EARFCN list. Stopping cell search...\n");
}
}
bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) {
free_cell();
float dl_freq = srslte_band_fd(earfcn);
float ul_freq = srslte_band_ul_earfcn(earfcn);
int cnt=0;
while(phy_state == CELL_SEARCH && cnt<100) {
usleep(10000);
log_h->info("PHY in CELL_SEARCH. Waiting...\n");
}
if (phy_state==CELL_SEARCH) {
log_h->warning("PHY still in CELL_SEARCH, forcing CELL_SELECT...\n");
}
float dl_freq = 1e6*srslte_band_fd(earfcn);
float ul_freq = 1e6*srslte_band_fu(srslte_band_ul_earfcn(earfcn));
if (dl_freq >= 0 || ul_freq <= 0) {
log_h->console("Cell Select: Set EARFCN=%d, DL frequency=%.1f MHz, UL frequency=%.1f MHz\n", earfcn,
dl_freq / 1e6, ul_freq / 1e6);
log_h->info("Cell Select: Set EARFCN=%d, frequency=%.1f MHz, UL frequency=%.1f MHz\n", earfcn, dl_freq / 1e6,
ul_freq / 1e6);
radio_h->set_rx_freq(dl_freq);
radio_h->set_tx_freq(ul_freq);
ul_dl_factor = ul_freq/dl_freq;
cell_search_in_progress = false;
this->cell = cell;
if (init_cell()) {
phy_state = CELL_SELECT;
@ -398,6 +380,77 @@ namespace srsue {
return false;
}
int phch_recv::cell_sync_sfn(void) {
int ret = SRSLTE_ERROR;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer);
if (ret < 0) {
Error("Error calling ue_sync_get_buffer");
return -1;
}
if (ret == 1) {
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
int sfn_offset = 0;
Info("SYNC: Decoding MIB...\n");
int n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset);
if (n < 0) {
Error("SYNC: Error decoding MIB while synchronising SFN");
return -1;
} else if (n == SRSLTE_UE_MIB_FOUND) {
uint32_t sfn;
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
sfn = (sfn+sfn_offset)%1024;
tti = sfn * 10;
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", tti, sfn_offset);
srslte_ue_mib_reset(&ue_mib);
return 1;
}
}
} else {
Debug("SYNC: PSS/SSS not found...\n");
}
return 0;
}
int phch_recv::cell_meas_rsrp() {
uint32_t cfi = 0;
tti = (tti+1) % 10240;
log_h->step(tti);
uint32_t sf_idx = tti%10;
int sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer);
if (sync_res == 1) {
if (srslte_ue_dl_decode_fft_estimate_multi(&ue_dl_measure, sf_buffer, sf_idx, &cfi)) {
log_h->error("SYNC: Measuring RSRP: Estimating channel\n");
return -1;
}
float rsrp = srslte_chest_dl_get_rsrp(&ue_dl_measure.chest);
measure_rsrp = SRSLTE_VEC_CMA(rsrp, measure_rsrp, measure_cnt);
measure_cnt++;
log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm\n",
measure_cnt, RSRP_MEASURE_NOF_FRAMES, sf_idx, 10 * log10(rsrp / 1000));
if (measure_cnt >= RSRP_MEASURE_NOF_FRAMES) {
return 1;
}
} else {
log_h->error("SYNC: Measuring RSRP: Sync error\n");
return -1;
}
return 0;
}
void phch_recv::run_thread() {
int sync_res;
phch_worker *worker = NULL;
@ -406,7 +459,6 @@ namespace srsue {
switch (phy_state) {
case CELL_SEARCH:
if (cell_search()) {
log_h->console("Initializating cell configuration...\n");
init_cell();
float srate = (float) srslte_sampling_freq_hz(cell.nof_prb);
@ -416,12 +468,11 @@ namespace srsue {
radio_h->set_master_clock_rate(23.04e6);
}
log_h->console("Setting Sampling frequency %.2f MHz\n", (float) srate / 1000000);
log_h->info("Setting Sampling frequency %.2f MHz\n", (float) srate / 1000000);
srate_mode = SRATE_CAMP;
radio_h->set_rx_srate(srate);
radio_h->set_tx_srate(srate);
ul_dl_factor = radio_h->get_tx_freq() / radio_h->get_rx_freq();
Info("SYNC: Cell found. Synchronizing...\n");
phy_state = CELL_SELECT;
sync_sfn_cnt = 0;
@ -438,14 +489,21 @@ namespace srsue {
radio_is_streaming = true;
}
switch (sync_sfn()) {
switch (cell_sync_sfn()) {
default:
log_h->console("Going IDLE\n");
phy_state = IDLE;
break;
case 1:
srslte_ue_sync_set_agc_period(&ue_sync, 20);
phy_state = CAMPING;
if (!cell_search_in_progress) {
phy_state = CELL_CAMP;
log_h->console("Sync OK. Camping on cell PCI=%d...\n", cell.id);
} else {
measure_cnt = 0;
measure_rsrp = 0;
phy_state = CELL_MEASURE;
}
break;
case 0:
break;
@ -459,10 +517,21 @@ namespace srsue {
log_h->warning("Timeout while synchronizing SFN\n");
}
break;
case CAMPING:
case CELL_MEASURE:
switch(cell_meas_rsrp()) {
case 1:
rrc->cell_found(earfcn[cur_earfcn_index], cell, 10*log10(measure_rsrp/1000));
phy_state = CELL_CAMP;
case 0:
break;
default:
log_h->error("SYNC: Getting RSRP cell measurement.\n");
cell_search_next();
}
break;
case CELL_CAMP:
tti = (tti+1) % 10240;
worker = (phch_worker *) workers_pool->wait_worker(tti);
sync_res = 0;
if (worker) {
for (uint32_t i = 0; i < nof_rx_antennas; i++) {
buffer[i] = worker->get_buffer(i);
@ -535,7 +604,7 @@ namespace srsue {
}
bool phch_recv::status_is_sync() {
return phy_state == CAMPING;
return phy_state == CELL_CAMP;
}
void phch_recv::get_current_cell(srslte_cell_t *cell_) {

@ -33,6 +33,7 @@
#include <string>
#include <algorithm>
#include <iterator>
#include <ue.h>
using namespace srslte;
@ -169,6 +170,7 @@ bool ue::init(all_args_t *args_)
}
if (args->rf.tx_gain > 0) {
radio.set_tx_gain(args->rf.tx_gain);
printf("set tx gain %f\n", args->rf.tx_gain);
} else {
radio.set_tx_gain(args->rf.rx_gain);
std::cout << std::endl <<
@ -189,6 +191,14 @@ bool ue::init(all_args_t *args_)
gw.init(&pdcp, &rrc, this, &gw_log);
usim.init(&args->usim, &usim_log);
// Currently EARFCN list is set to only one frequency as indicated in ue.conf
std::vector<uint32_t> earfcn_list;
earfcn_list.push_back(args->rf.dl_earfcn);
phy.set_earfcn(earfcn_list);
printf("\n\nRequesting NAS Attach...\n");
nas.attach_request();
started = true;
return true;
}

@ -25,7 +25,9 @@
*/
#include "srslte/asn1/liblte_rrc.h"
#include "upper/nas.h"
#include "srslte/common/bcd_helpers.h"
using namespace srslte;
@ -45,11 +47,9 @@ namespace srsue {
gw = gw_;
nas_log = nas_log_;
state = EMM_STATE_DEREGISTERED;
// Manual PLMN selection procedure
current_plmn.mcc = 1;
current_plmn.mnc = 1;
plmn_selection = PLMN_SELECTED;
plmn_selection = PLMN_NOT_SELECTED;
home_plmn.mcc = 61441; // This is 001
home_plmn.mnc = 65281; // This is 01
}
void nas::stop() {}
@ -62,11 +62,14 @@ namespace srsue {
UE interface
*******************************************************************************/
void nas::attach_request() {
nas_log->info("Attach Request\n");
if (state == EMM_STATE_DEREGISTERED) {
state = EMM_STATE_REGISTERED_INITIATED;
if (plmn_selection == PLMN_NOT_SELECTED) {
nas_log->info("Starting PLMN Search...\n");
rrc->plmn_search();
} else if (plmn_selection == PLMN_SELECTED) {
nas_log->info("Selecting PLMN %s\n", plmn_id_to_c_str(current_plmn).c_str());
rrc->plmn_select(current_plmn);
}
} else {
@ -83,44 +86,57 @@ namespace srsue {
RRC interface
*******************************************************************************/
void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
// if it's the plmn we want rrc->plmn_select() and plmn_selection = PLMN_SELECTED
}
void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
void nas::cell_selected() {
// Store PLMN if not registered
for (uint32_t i=0;i<known_plmns.size();i++) {
if (plmn_id.mcc == known_plmns[i].mcc && plmn_id.mnc == known_plmns[i].mnc) {
nas_log->info("Detected known PLMN %s\n", plmn_id_to_c_str(plmn_id).c_str());
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
rrc->plmn_select(plmn_id);
}
return;
}
}
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_c_str(plmn_id).c_str(),
tracking_area_code);
nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_c_str(plmn_id).c_str(),
tracking_area_code);
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
rrc->plmn_select(plmn_id);
}
}
void nas::cell_selected() {
if (state == EMM_STATE_REGISTERED_INITIATED) {
rrc->connect();
} else {
nas_log->info("Cell selcted in invalid state = %s\n", emm_state_text[state]);
nas_log->info("Cell selected in invalid state = %s\n", emm_state_text[state]);
}
}
}
bool nas::is_attached()
{
bool nas::is_attached() {
return state == EMM_STATE_REGISTERED;
}
}
void nas::notify_connection_setup()
{
void nas::notify_connection_setup() {
nas_log->debug("State = %s\n", emm_state_text[state]);
if(EMM_STATE_REGISTERED_INITIATED == state) {
if (EMM_STATE_REGISTERED_INITIATED == state) {
send_attach_request();
} else {
send_service_request();
}
}
}
void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
{
void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
uint8 pd;
uint8 msg_type;
nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rb_id_text[lcid]);
// Parse the message
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &msg_type);
switch(msg_type)
{
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) pdu, &pd, &msg_type);
switch (msg_type) {
case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT:
parse_attach_accept(lcid, pdu);
break;
@ -149,42 +165,38 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
parse_emm_information(lcid, pdu);
break;
default:
nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n",msg_type);
nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n", msg_type);
pool->deallocate(pdu);
break;
}
}
}
uint32_t nas::get_ul_count()
{
uint32_t nas::get_ul_count() {
return count_ul;
}
}
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi)
{
if(is_guti_set) {
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
if (is_guti_set) {
s_tmsi->mmec = guti.mme_code;
s_tmsi->m_tmsi = guti.m_tmsi;
return true;
} else {
return false;
}
}
}
/*******************************************************************************
Security
*******************************************************************************/
void nas::integrity_generate(uint8_t *key_128,
void nas::integrity_generate(uint8_t *key_128,
uint32_t count,
uint8_t rb_id,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *mac)
{
switch(integ_algo)
{
uint8_t *mac) {
switch (integ_algo) {
case INTEGRITY_ALGORITHM_ID_EIA0:
break;
case INTEGRITY_ALGORITHM_ID_128_EIA1:
@ -208,31 +220,26 @@ void nas::integrity_generate(uint8_t *key_128,
default:
break;
}
}
void nas::integrity_check()
{
}
}
void nas::integrity_check() {
void nas::cipher_encrypt()
{
}
}
void nas::cipher_encrypt() {
void nas::cipher_decrypt()
{
}
}
void nas::cipher_decrypt() {
}
/*******************************************************************************
Parsers
*******************************************************************************/
void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu)
{
void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept;
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req;
LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete;
@ -241,44 +248,32 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu)
nas_log->info("Received Attach Accept\n");
count_dl++;
liblte_mme_unpack_attach_accept_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &attach_accept);
liblte_mme_unpack_attach_accept_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &attach_accept);
if(attach_accept.eps_attach_result == LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY)
{
if (attach_accept.eps_attach_result == LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY) {
//FIXME: Handle t3412.unit
//FIXME: Handle tai_list
if(attach_accept.guti_present)
{
if (attach_accept.guti_present) {
memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
is_guti_set = true;
// TODO: log message to console
}
if(attach_accept.lai_present)
{
}
if(attach_accept.ms_id_present)
{}
if(attach_accept.emm_cause_present)
{}
if(attach_accept.t3402_present)
{}
if(attach_accept.t3423_present)
{}
if(attach_accept.equivalent_plmns_present)
{}
if(attach_accept.emerg_num_list_present)
{}
if(attach_accept.eps_network_feature_support_present)
{}
if(attach_accept.additional_update_result_present)
{}
if(attach_accept.t3412_ext_present)
{}
liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req);
if(LIBLTE_MME_PDN_TYPE_IPV4 == act_def_eps_bearer_context_req.pdn_addr.pdn_type)
{
if (attach_accept.lai_present) {
}
if (attach_accept.ms_id_present) {}
if (attach_accept.emm_cause_present) {}
if (attach_accept.t3402_present) {}
if (attach_accept.t3423_present) {}
if (attach_accept.equivalent_plmns_present) {}
if (attach_accept.emerg_num_list_present) {}
if (attach_accept.eps_network_feature_support_present) {}
if (attach_accept.additional_update_result_present) {}
if (attach_accept.t3412_ext_present) {}
liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg,
&act_def_eps_bearer_context_req);
if (LIBLTE_MME_PDN_TYPE_IPV4 == act_def_eps_bearer_context_req.pdn_addr.pdn_type) {
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[0] << 24;
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[1] << 16;
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[2] << 8;
@ -298,20 +293,16 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu)
// Setup GW
char *err_str = NULL;
if(gw->setup_if_addr(ip_addr, err_str))
{
if (gw->setup_if_addr(ip_addr, err_str)) {
nas_log->error("Failed to set gateway address - %s\n", err_str);
}
}
else
{
} else {
nas_log->error("Not handling IPV6 or IPV4V6\n");
pool->deallocate(pdu);
return;
}
eps_bearer_id = act_def_eps_bearer_context_req.eps_bearer_id;
if(act_def_eps_bearer_context_req.transaction_id_present)
{
if (act_def_eps_bearer_context_req.transaction_id_present) {
transaction_id = act_def_eps_bearer_context_req.proc_transaction_id;
}
@ -337,17 +328,18 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu)
act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id;
act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id;
act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false;
liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept, &attach_complete.esm_msg);
liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept,
&attach_complete.esm_msg);
liblte_mme_pack_attach_complete_msg(&attach_complete,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
count_ul,
(LIBLTE_BYTE_MSG_STRUCT*)pdu);
(LIBLTE_BYTE_MSG_STRUCT *) pdu);
integrity_generate(&k_nas_int[16],
count_ul,
lcid-1,
lcid - 1,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[5],
pdu->N_bytes-5,
pdu->N_bytes - 5,
&pdu->msg[1]);
// Instruct RRC to enable capabilities
@ -356,34 +348,30 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu)
nas_log->info("Sending Attach Complete\n");
rrc->write_sdu(lcid, pdu);
}
else
{
} else {
nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result);
state = EMM_STATE_DEREGISTERED;
pool->deallocate(pdu);
}
}
}
void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu)
{
void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT attach_rej;
liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &attach_rej);
liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &attach_rej);
nas_log->warning("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause);
nas_log->console("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause);
state = EMM_STATE_DEREGISTERED;
pool->deallocate(pdu);
// FIXME: Command RRC to release?
}
}
void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu)
{
void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
nas_log->info("Received Authentication Request\n");;
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &auth_req);
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
// Reuse the pdu for the response message
pdu->reset();
@ -399,52 +387,45 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu)
uint8_t res[16];
usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, &net_valid, res);
if(net_valid)
{
if (net_valid) {
nas_log->info("Network authentication successful\n");
for(int i=0; i<8; i++)
{
for (int i = 0; i < 8; i++) {
auth_res.res[i] = res[i];
}
liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT*)pdu);
liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *) pdu);
nas_log->info("Sending Authentication Response\n");
rrc->write_sdu(lcid, pdu);
}
else
{
} else {
nas_log->warning("Network authentication failure\n");
nas_log->console("Warning: Network authentication failure\n");
pool->deallocate(pdu);
}
}
}
void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu)
{
void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->warning("Received Authentication Reject\n");
pool->deallocate(pdu);
state = EMM_STATE_DEREGISTERED;
// FIXME: Command RRC to release?
}
}
void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu)
{
void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_identity_request\n");
}
}
void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
{
void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) {
bool success;
LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd;
LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp;
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
nas_log->info("Received Security Mode Command\n");
liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &sec_mode_cmd);
liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd);
ksi = sec_mode_cmd.nas_ksi.nas_ksi;
cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM)sec_mode_cmd.selected_nas_sec_algs.type_of_eea;
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM)sec_mode_cmd.selected_nas_sec_algs.type_of_eia;
cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea;
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia;
// FIXME: Handle nonce_ue, nonce_mme
// FIXME: Currently only handling ciphering EEA0 (null) and integrity EIA1,EIA2
// FIXME: Use selected_nas_sec_algs to choose correct algos
@ -453,17 +434,14 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]);
if(CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo ||
if (CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo ||
(INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo &&
INTEGRITY_ALGORITHM_ID_128_EIA1 != integ_algo) ||
sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE)
{
sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) {
sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH;
nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n");
success = false;
}
else
{
} else {
// Generate NAS encryption key and integrity protection key
usim->generate_nas_keys(k_nas_enc, k_nas_int, cipher_algo, integ_algo);
nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc");
@ -474,37 +452,34 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
uint8_t genMAC[4];
integrity_generate(&k_nas_int[16],
count_dl,
lcid-1,
lcid - 1,
SECURITY_DIRECTION_DOWNLINK,
&pdu->msg[5],
pdu->N_bytes-5,
pdu->N_bytes - 5,
genMAC);
nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:");
nas_log->info_hex(genMAC, 4, "Generated PDU MAC:");
bool match=true;
for(int i=0;i<4;i++) {
if(inMAC[i] != genMAC[i]) {
bool match = true;
for (int i = 0; i < 4; i++) {
if (inMAC[i] != genMAC[i]) {
match = false;
}
}
if(!match) {
if (!match) {
sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED;
nas_log->warning("Sending Security Mode Reject due to integrity check failure\n");
success = false;
} else {
if(sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req)
{
if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) {
sec_mode_comp.imeisv_present = true;
sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV;
usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15);
sec_mode_comp.imeisv.imeisv[14] = 5;
sec_mode_comp.imeisv.imeisv[15] = 3;
}
else
{
} else {
sec_mode_comp.imeisv_present = false;
}
@ -513,13 +488,13 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
count_ul,
(LIBLTE_BYTE_MSG_STRUCT*)pdu);
(LIBLTE_BYTE_MSG_STRUCT *) pdu);
integrity_generate(&k_nas_int[16],
count_ul,
lcid-1,
lcid - 1,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[5],
pdu->N_bytes-5,
pdu->N_bytes - 5,
&pdu->msg[1]);
nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n",
count_ul,
@ -528,42 +503,39 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
}
}
if(!success) {
if (!success) {
// Reuse pdu for response
pdu->reset();
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT*)pdu);
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) pdu);
}
rrc->write_sdu(lcid, pdu);
}
}
void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu)
{
void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_service_reject\n");
}
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu)
{
}
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_esm_information_request\n");
}
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu)
{
}
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_emm_information\n");
}
}
/*******************************************************************************
Senders
*******************************************************************************/
void nas::send_attach_request()
{
void nas::send_attach_request() {
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
byte_buffer_t *msg = pool_allocate;
u_int32_t i;
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
for(i=0; i<8; i++)
{
for (i = 0; i < 8; i++) {
attach_req.ue_network_cap.eea[i] = false;
attach_req.ue_network_cap.eia[i] = false;
}
@ -599,14 +571,13 @@ void nas::send_attach_request()
attach_req.old_guti_type_present = false;
// Pack the message
liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT*)msg);
liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg);
nas_log->info("Sending attach request\n");
rrc->write_sdu(RB_ID_SRB1, msg);
}
}
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg)
{
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req;
nas_log->info("Generating PDN Connectivity Request\n");
@ -625,12 +596,11 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg)
// Pack the message
liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg);
}
}
void nas::send_identity_response(){}
void nas::send_identity_response() {}
void nas::send_service_request()
{
void nas::send_service_request() {
byte_buffer_t *msg = pool_allocate;
count_ul++;
@ -644,7 +614,7 @@ void nas::send_service_request()
uint8_t mac[4];
integrity_generate(&k_nas_int[16],
count_ul,
RB_ID_SRB1-1,
RB_ID_SRB1 - 1,
SECURITY_DIRECTION_UPLINK,
&msg->msg[0],
2,
@ -656,8 +626,8 @@ void nas::send_service_request()
msg->N_bytes++;
nas_log->info("Sending service request\n");
rrc->write_sdu(RB_ID_SRB1, msg);
}
}
void nas::send_esm_information_response(){}
void nas::send_esm_information_response() {}
} // namespace srsue

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save