diff --git a/CMakeLists.txt b/CMakeLists.txt index 855df3a04..fe2d99690 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,6 @@ configure_file( option(ENABLE_SRSUE "Build srsUE application" ON) option(ENABLE_SRSENB "Build srsENB application" ON) -option(ENABLE_VOLK "Enable use of VOLK SIMD library" OFF) option(ENABLE_GUI "Enable GUI (using srsGUI)" ON) option(ENABLE_BLADERF "Enable BladeRF" ON) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 573cab255..71c0864c8 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -295,7 +295,7 @@ int main(int argc, char **argv) { return -1; } - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); float rx_gain_offset = 0; @@ -329,7 +329,7 @@ int main(int argc, char **argv) { case DECODE_SIB: /* We are looking for SI Blocks, search only in appropiate places */ if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); + n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); if (n < 0) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); return -1; @@ -366,7 +366,7 @@ int main(int argc, char **argv) { if ((nframes%100) == 0 || rx_gain_offset == 0) { if (srslte_rf_has_rssi(&rf)) { - rx_gain_offset = 10*log10(rssi*1000)-srslte_rf_get_rssi(&rf); + rx_gain_offset = 30+10*log10(rssi*1000)-srslte_rf_get_rssi(&rf); } else { rx_gain_offset = srslte_rf_get_rx_gain(&rf); } diff --git a/lib/examples/cell_search.c b/lib/examples/cell_search.c index 9ecc79c72..17e75369f 100644 --- a/lib/examples/cell_search.c +++ b/lib/examples/cell_search.c @@ -221,7 +221,7 @@ int main(int argc, char **argv) { INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000); srslte_rf_set_rx_srate(&rf, SRSLTE_CS_SAMP_FREQ); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); n = srslte_ue_cellsearch_scan(&cs, found_cells, NULL); if (n < 0) { diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index b62ae263e..6293d0e70 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -570,7 +570,7 @@ int main(int argc, char **argv) { #ifndef DISABLE_RF if (!prog_args.input_file_name) { - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); } #endif @@ -676,19 +676,19 @@ int main(int argc, char **argv) { if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe if (cell.nof_ports == 1) { /* Transmission mode 1 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); + n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); } else { if (prog_args.rf_nof_rx_ant == 1) { /* Transmission mode 2 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + n = srslte_ue_dl_decode(&ue_dl, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); } else { /* Transmission mode 3 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + n = srslte_ue_dl_decode(&ue_dl, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); if (n < 1) { /* Transmission mode 4 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + n = srslte_ue_dl_decode(&ue_dl, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); } } @@ -701,7 +701,6 @@ int main(int argc, char **argv) { }else{ // MBSFN subframe n = srslte_ue_dl_decode_mbsfn(&ue_dl, - sf_buffer, data[0], sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); if(n>0){ @@ -959,7 +958,7 @@ void *plot_thread_run(void *arg) { plot_real_init(&pce); plot_real_setTitle(&pce, "Channel Response - Magnitude"); plot_real_setLabels(&pce, "Index", "dB"); - plot_real_setYAxisScale(&pce, -M_PI, M_PI); + plot_real_setYAxisScale(&pce, -40, 40); plot_real_init(&p_sync); plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value"); @@ -995,15 +994,11 @@ void *plot_thread_run(void *arg) { tmp_plot2[g+i] = -80; } } - uint32_t nrefs = 2*ue_dl.cell.nof_prb; - for (i=0;iconv_output_avg, pss_obj->frame_size+pss_obj->fft_size-1); srslte_vec_sc_prod_fff(pss_obj->conv_output_avg, 1/pss_obj->conv_output_avg[max], diff --git a/lib/examples/synch_file.c b/lib/examples/synch_file.c index 178e56e99..4d553bd38 100644 --- a/lib/examples/synch_file.c +++ b/lib/examples/synch_file.c @@ -102,8 +102,8 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { srslte_filesource_t fsrc; srslte_filesink_t fsink; - srslte_pss_synch_t pss[3]; // One for each N_id_2 - srslte_sss_synch_t sss[3]; // One for each N_id_2 + srslte_pss_t pss[3]; // One for each N_id_2 + srslte_sss_t sss[3]; // One for each N_id_2 srslte_cfo_t cfocorr; int peak_pos[3]; float *cfo; @@ -163,19 +163,19 @@ int main(int argc, char **argv) { * a) requries more memory but has less latency and is paralellizable. */ for (N_id_2=0;N_id_2<3;N_id_2++) { - if (srslte_pss_synch_init(&pss[N_id_2], frame_length)) { + if (srslte_pss_init(&pss[N_id_2], frame_length)) { fprintf(stderr, "Error initializing PSS object\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss[N_id_2], N_id_2)) { + if (srslte_pss_set_N_id_2(&pss[N_id_2], N_id_2)) { fprintf(stderr, "Error initializing N_id_2\n"); exit(-1); } - if (srslte_sss_synch_init(&sss[N_id_2], 128)) { + if (srslte_sss_init(&sss[N_id_2], 128)) { fprintf(stderr, "Error initializing SSS object\n"); exit(-1); } - if (srslte_sss_synch_set_N_id_2(&sss[N_id_2], N_id_2)) { + if (srslte_sss_set_N_id_2(&sss[N_id_2], N_id_2)) { fprintf(stderr, "Error initializing N_id_2\n"); exit(-1); } @@ -199,10 +199,10 @@ int main(int argc, char **argv) { if (force_N_id_2 != -1) { N_id_2 = force_N_id_2; - peak_pos[N_id_2] = srslte_pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); + peak_pos[N_id_2] = srslte_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); } else { for (N_id_2=0;N_id_2<3;N_id_2++) { - peak_pos[N_id_2] = srslte_pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); + peak_pos[N_id_2] = srslte_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); } float max_value=-99999; N_id_2=-1; @@ -220,13 +220,13 @@ int main(int argc, char **argv) { sss_idx = peak_pos[N_id_2]-2*(symbol_sz+SRSLTE_CP_LEN(symbol_sz,SRSLTE_CP_NORM_LEN)); if (sss_idx >= 0) { - srslte_sss_synch_m0m1_diff(&sss[N_id_2], &input[sss_idx], + srslte_sss_m0m1_diff(&sss[N_id_2], &input[sss_idx], &m0, &m0_value, &m1, &m1_value); - cfo[frame_cnt] = srslte_pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); + cfo[frame_cnt] = srslte_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n", - frame_cnt,N_id_2, srslte_sss_synch_N_id_1(&sss[N_id_2], m0, m1), - srslte_sss_synch_subframe(m0, m1), peak_value[N_id_2], + frame_cnt,N_id_2, srslte_sss_N_id_1(&sss[N_id_2], m0, m1), + srslte_sss_subframe(m0, m1), peak_value[N_id_2], peak_pos[N_id_2], m0, m1, cfo[frame_cnt]); } @@ -254,8 +254,8 @@ int main(int argc, char **argv) { printf("Average CFO: %.3f\n", cfo_mean); for (N_id_2=0;N_id_2<3;N_id_2++) { - srslte_pss_synch_free(&pss[N_id_2]); - srslte_sss_synch_free(&sss[N_id_2]); + srslte_pss_free(&pss[N_id_2]); + srslte_sss_free(&sss[N_id_2]); } srslte_filesource_free(&fsrc); diff --git a/lib/examples/usrp_capture.c b/lib/examples/usrp_capture.c index 02b543c0e..a0136e913 100644 --- a/lib/examples/usrp_capture.c +++ b/lib/examples/usrp_capture.c @@ -153,7 +153,7 @@ int main(int argc, char **argv) { printf("Correctly RX rate: %.2f MHz\n", srate*1e-6); srslte_rf_rx_wait_lo_locked(&rf); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); while((sample_count < nof_samples || nof_samples == -1) diff --git a/lib/examples/usrp_capture_sync.c b/lib/examples/usrp_capture_sync.c index bac17698a..613f26d84 100644 --- a/lib/examples/usrp_capture_sync.c +++ b/lib/examples/usrp_capture_sync.c @@ -158,7 +158,7 @@ int main(int argc, char **argv) { exit(-1); } srslte_rf_rx_wait_lo_locked(&rf); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); cell.cp = SRSLTE_CP_NORM; cell.id = N_id_2; diff --git a/lib/examples/usrp_txrx.c b/lib/examples/usrp_txrx.c index 508b4b397..42f610d65 100644 --- a/lib/examples/usrp_txrx.c +++ b/lib/examples/usrp_txrx.c @@ -175,7 +175,7 @@ int main(int argc, char **argv) { srslte_timestamp_t tstamp; - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); uint32_t nframe=0; diff --git a/lib/include/srslte/asn1/liblte_mme.h b/lib/include/srslte/asn1/liblte_mme.h index 977f309ce..842fd2e17 100644 --- a/lib/include/srslte/asn1/liblte_mme.h +++ b/lib/include/srslte/asn1/liblte_mme.h @@ -2545,6 +2545,9 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8 // Enums // Structs // Functions +LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 *pd, + uint8 *sec_hdr_type); LIBLTE_ERROR_ENUM liblte_mme_parse_msg_header(LIBLTE_BYTE_MSG_STRUCT *msg, uint8 *pd, uint8 *msg_type); diff --git a/lib/include/srslte/asn1/liblte_rrc.h b/lib/include/srslte/asn1/liblte_rrc.h index d508f3697..e0fb43aef 100644 --- a/lib/include/srslte/asn1/liblte_rrc.h +++ b/lib/include/srslte/asn1/liblte_rrc.h @@ -1218,6 +1218,9 @@ typedef enum{ }LIBLTE_RRC_REPORT_AMOUNT_ENUM; static const char liblte_rrc_report_amount_text[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS][20] = { "r1", "r2", "r4", "r8", "r16", "r32", "r64", "INFINITY"}; + +static const int8 liblte_rrc_report_amount_num[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS] = {1, 2, 4, 8, 16, 32, 64, -1}; + typedef enum{ LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP = 0, LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ECNO, @@ -2681,6 +2684,7 @@ typedef enum{ }LIBLTE_RRC_T304_ENUM; static const char liblte_rrc_t304_text[LIBLTE_RRC_T304_N_ITEMS][20] = { "50", "100", "150", "200", "500", "1000", "2000", "SPARE"}; +static const int32 liblte_rrc_t304_num[LIBLTE_RRC_T304_N_ITEMS] = {50, 100, 150, 200, 500, 1000, 2000, -1}; // Structs typedef struct{ uint8 p_b; diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 41a89fb36..3fd71422b 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -96,6 +96,35 @@ static const char error_text[ERROR_N_ITEMS][20] = { "None", "Can't start", "Already started"}; +// Radio bearers +typedef enum{ + RB_ID_SRB0 = 0, + RB_ID_SRB1, + RB_ID_SRB2, + RB_ID_DRB1, + RB_ID_DRB2, + RB_ID_DRB3, + RB_ID_DRB4, + RB_ID_DRB5, + RB_ID_DRB6, + RB_ID_DRB7, + RB_ID_DRB8, + RB_ID_MAX +} rb_id_t; + +static const char rb_id_str[RB_ID_MAX][8] = {"SRB0", "SRB1", "SRB2", + "DRB1", "DRB2", "DRB3", + "DRB4", "DRB5", "DRB6", + "DRB7", "DRB8"}; + +inline const char* get_rb_name(uint32_t lcid) { + if (lcid < RB_ID_MAX) { + return rb_id_str[lcid]; + } else { + return "INVALID_RB"; + } +} + /****************************************************************************** * Byte and Bit buffers * diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h index a027b6230..5fe26bc13 100644 --- a/lib/include/srslte/common/interfaces_common.h +++ b/lib/include/srslte/common/interfaces_common.h @@ -52,14 +52,12 @@ public: :direction(direction_) ,is_control(is_control_) ,is_data(is_data_) - ,do_security(false) ,sn_len(12) {} - uint8_t direction; - bool is_control; - bool is_data; - bool do_security; - uint8_t sn_len; + uint8_t direction; + bool is_control; + bool is_data; + uint8_t sn_len; // TODO: Support the following configurations // bool do_rohc; diff --git a/lib/include/srslte/common/liblte_security.h b/lib/include/srslte/common/liblte_security.h index b49f7211b..02cc42ca8 100644 --- a/lib/include/srslte/common/liblte_security.h +++ b/lib/include/srslte/common/liblte_security.h @@ -86,6 +86,15 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme, uint32 nas_count, uint8 *k_enb); +LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb, + uint32 pci, + uint32_t earfcn, + uint8 *k_enb_star); + +LIBLTE_ERROR_ENUM liblte_security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh); + /********************************************************************* Name: liblte_security_generate_k_nas @@ -121,6 +130,8 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_nas(uint8 uint8 *k_nas_enc, uint8 *k_nas_int); + + /********************************************************************* Name: liblte_security_generate_k_rrc @@ -185,6 +196,73 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(uint8 *key, LIBLTE_BIT_MSG_STRUCT *msg, uint8 *mac); +/********************************************************************* + Name: liblte_security_encryption_eea1 + + Description: 128-bit encryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_decryption_eea1 + + Description: 128-bit decryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_encryption_eea2 + + Description: 128-bit encryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_decryption_eea2 + + Description: 128-bit decryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out); + + /********************************************************************* Name: liblte_security_milenage_f1 diff --git a/lib/include/srslte/common/liblte_ssl.h b/lib/include/srslte/common/liblte_ssl.h index 886d557b1..d96c728ab 100644 --- a/lib/include/srslte/common/liblte_ssl.h +++ b/lib/include/srslte/common/liblte_ssl.h @@ -38,6 +38,18 @@ int aes_crypt_ecb( aes_context *ctx, return mbedtls_aes_crypt_ecb(ctx, mode, input, output); } +int aes_crypt_ctr(aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + return mbedtls_aes_crypt_ctr(ctx, length, nc_off, nonce_counter, + stream_block, input, output); +} + void sha256(const unsigned char *key, size_t keylen, const unsigned char *input, size_t ilen, unsigned char output[32], int is224 ) diff --git a/lib/include/srslte/common/mac_pcap.h b/lib/include/srslte/common/mac_pcap.h index f441e1aed..26a8f20bb 100644 --- a/lib/include/srslte/common/mac_pcap.h +++ b/lib/include/srslte/common/mac_pcap.h @@ -35,10 +35,13 @@ namespace srslte { class mac_pcap { public: - mac_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; + mac_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; void enable(bool en); void open(const char *filename, uint32_t ue_id = 0); - void close(); + void close(); + + void set_ue_id(uint16_t ue_id); + void write_ul_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti); void write_dl_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti); void write_dl_ranti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti); @@ -51,8 +54,8 @@ public: private: bool enable_write; FILE *pcap_file; - uint32_t ue_id; - void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, uint16_t crnti_, uint8_t direction, uint8_t rnti_type); }; diff --git a/lib/include/srslte/common/nas_pcap.h b/lib/include/srslte/common/nas_pcap.h new file mode 100644 index 000000000..68fcabb73 --- /dev/null +++ b/lib/include/srslte/common/nas_pcap.h @@ -0,0 +1,25 @@ +#ifndef NAS_PCAP_H +#define NAS_PCAP_H + +#include "srslte/common/pcap.h" + +namespace srslte { + +class nas_pcap +{ +public: + nas_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; } + void enable(); + void open(const char *filename, uint32_t ue_id=0); + void close(); + void write_nas(uint8_t *pdu, uint32_t pdu_len_bytes); +private: + bool enable_write; + FILE *pcap_file; + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes); +}; + +} //namespace srsue + +#endif // NAS_PCAP_H diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h index db1dc17d0..ce4fcf541 100644 --- a/lib/include/srslte/common/pcap.h +++ b/lib/include/srslte/common/pcap.h @@ -32,7 +32,8 @@ #include #include -#define MAC_LTE_DLT 147 +#define MAC_LTE_DLT 147 +#define NAS_LTE_DLT 148 /* This structure gets written to the start of the file */ @@ -72,30 +73,15 @@ typedef struct pcaprec_hdr_s { #define SPS_RNTI 5 #define M_RNTI 6 -#define MAC_LTE_START_STRING "mac-lte" - +#define MAC_LTE_START_STRING "mac-lte" +#define MAC_LTE_PAYLOAD_TAG 0x01 #define MAC_LTE_RNTI_TAG 0x02 -/* 2 bytes, network order */ - #define MAC_LTE_UEID_TAG 0x03 -/* 2 bytes, network order */ - #define MAC_LTE_FRAME_SUBFRAME_TAG 0x04 -/* 2 bytes, network order */ -/* SFN is stored in 12 MSB and SF in 4 LSB */ - #define MAC_LTE_PREDFINED_DATA_TAG 0x05 -/* 1 byte */ - #define MAC_LTE_RETX_TAG 0x06 -/* 1 byte */ - #define MAC_LTE_CRC_STATUS_TAG 0x07 -/* 1 byte */ -/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU - continues until the end of the frame) */ -#define MAC_LTE_PAYLOAD_TAG 0x01 /* Context information for every MAC PDU that will be logged */ @@ -110,17 +96,20 @@ typedef struct MAC_Context_Info_t { unsigned short sysFrameNumber; unsigned short subFrameNumber; - } MAC_Context_Info_t; +/* Context information for every NAS PDU that will be logged */ +typedef struct NAS_Context_Info_s { + // No Context yet +} NAS_Context_Info_t; - -/**************************************************************************/ -/* API functions for opening/writing/closing MAC-LTE PCAP files */ +/************************************************************************** + * API functions for opening/closing LTE PCAP files * + **************************************************************************/ /* Open the file and write file header */ -inline FILE *MAC_LTE_PCAP_Open(const char *fileName) +inline FILE *LTE_PCAP_Open(uint32_t DLT, const char *fileName) { pcap_hdr_t file_header = { @@ -129,7 +118,7 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName) 0, /* timezone */ 0, /* sigfigs - apparently all tools do this */ 65535, /* snaplen - this should be long enough */ - MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */ + DLT /* Data Link Type (DLT). Set as unused value 147 for now */ }; FILE *fd = fopen(fileName, "w"); @@ -144,9 +133,21 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName) return fd; } +/* Close the PCAP file */ +inline void LTE_PCAP_Close(FILE *fd) +{ + if(fd) + fclose(fd); +} + + +/************************************************************************** + * API functions for writing MAC-LTE PCAP files * + **************************************************************************/ + /* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ -inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, - const unsigned char *PDU, unsigned int length) +inline int LTE_PCAP_MAC_WritePDU(FILE *fd, MAC_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) { pcaprec_hdr_t packet_header; char context_header[256]; @@ -211,11 +212,39 @@ inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, return 1; } -/* Close the PCAP file */ -inline void MAC_LTE_PCAP_Close(FILE *fd) + + +/************************************************************************** + * API functions for writing NAS-EPS PCAP files * + **************************************************************************/ + +/* Write an individual PDU (PCAP packet header + nas-context + nas-pdu) */ +inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) { - if(fd) - fclose(fd); + pcaprec_hdr_t packet_header; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + + /****************************************************************/ + /* PCAP Header */ + struct timeval t; + gettimeofday(&t, NULL); + packet_header.ts_sec = t.tv_sec; + packet_header.ts_usec = t.tv_usec; + packet_header.incl_len = length; + packet_header.orig_len = length; + + /***************************************************************/ + /* Now write everything to the file */ + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(PDU, 1, length, fd); + + return 1; } #endif /* UEPCAP_H */ diff --git a/lib/include/srslte/common/security.h b/lib/include/srslte/common/security.h index 080f1848f..9ba2616d1 100644 --- a/lib/include/srslte/common/security.h +++ b/lib/include/srslte/common/security.h @@ -76,6 +76,15 @@ uint8_t security_generate_k_enb( uint8_t *k_asme, uint32_t nas_count, uint8_t *k_enb); +uint8_t security_generate_k_enb_star( uint8_t *k_enb, + uint32_t pci, + uint32_t earfcn, + uint8_t *k_enb_star); + +uint8_t security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh); + uint8_t security_generate_k_nas( uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, @@ -114,6 +123,26 @@ uint8_t security_128_eia2( uint8_t *key, uint32_t msg_len, uint8_t *mac); +/****************************************************************************** + * Encryption / Decryption + *****************************************************************************/ + +uint8_t security_128_eea1( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out); + +uint8_t security_128_eea2(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out); + /****************************************************************************** * Authentication *****************************************************************************/ diff --git a/lib/include/srslte/common/threads.h b/lib/include/srslte/common/threads.h index a8807ba9b..077dda72b 100644 --- a/lib/include/srslte/common/threads.h +++ b/lib/include/srslte/common/threads.h @@ -78,22 +78,30 @@ class periodic_thread : public thread { public: void start_periodic(int period_us_, int priority = -1) { + run_enable = true; period_us = period_us_; start(priority); } + void stop() { + run_enable = false; + wait_thread_finish(); + } protected: virtual void run_period() = 0; private: int wakeups_missed; int timer_fd; - int period_us; + int period_us; + bool run_enable; void run_thread() { if (make_periodic()) { return; } - while(1) { + while(run_enable) { run_period(); - wait_period(); + if (run_enable) { + wait_period(); + } } } int make_periodic() { diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index a8563af37..d77692d5a 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -64,7 +64,7 @@ public: return (counter < timeout) && running; } bool is_expired() { - return callback && (counter >= timeout || !running); + return (timeout > 0) && (counter >= timeout || !running); } uint32_t get_timeout() { return timeout; @@ -72,6 +72,9 @@ public: void reset() { counter = 0; } + uint32_t value() { + return counter; + } void step() { if (running) { counter++; diff --git a/lib/include/srslte/common/tti_sync.h b/lib/include/srslte/common/tti_sync.h index 23061ea2d..fd62f442b 100644 --- a/lib/include/srslte/common/tti_sync.h +++ b/lib/include/srslte/common/tti_sync.h @@ -50,6 +50,7 @@ class tti_sync init_counters(0); } virtual void increase() = 0; + virtual void increase(uint32_t cnt) = 0; virtual void resync() = 0; virtual uint32_t wait() = 0; virtual void set_producer_cntr(uint32_t) = 0; @@ -60,6 +61,7 @@ class tti_sync } protected: void increase_producer() { producer_cntr = (producer_cntr + increment)%modulus; } + void increase_producer(uint32_t cnt) { producer_cntr = cnt%modulus; } void increase_consumer() { consumer_cntr = (consumer_cntr + increment)%modulus; } bool wait_condition() { return producer_cntr == consumer_cntr; } void init_counters(uint32_t val) diff --git a/lib/include/srslte/common/tti_sync_cv.h b/lib/include/srslte/common/tti_sync_cv.h index c04fa71f0..887ac4f04 100644 --- a/lib/include/srslte/common/tti_sync_cv.h +++ b/lib/include/srslte/common/tti_sync_cv.h @@ -44,7 +44,8 @@ class tti_sync_cv : public tti_sync tti_sync_cv(uint32_t modulus = 10240); ~tti_sync_cv(); void increase(); - uint32_t wait(); + void increase(uint32_t cnt); + uint32_t wait(); void resync(); void set_producer_cntr(uint32_t producer_cntr); diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 175f99f59..cd7d10020 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -151,6 +151,7 @@ public: /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls * RLC PDUs according to TB size. */ virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual bool rb_is_um(uint16_t rnti, uint32_t lcid) = 0; }; // RLC interface for RRC diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index d382c01e6..e8a33c207 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -83,6 +83,15 @@ public: uint8_t *k_up_int, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; + virtual void generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + int ncc, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; }; // GW interface for NAS @@ -118,15 +127,15 @@ public: class nas_interface_ue { public: - virtual void attach_request() = 0; - virtual void deattach_request() = 0; + virtual void attach_request() = 0; + virtual void deattach_request() = 0; }; // NAS interface for UE class nas_interface_gw { public: - virtual void attach_request() = 0; + virtual void attach_request() = 0; }; // RRC interface for MAC @@ -139,7 +148,9 @@ public: class rrc_interface_mac : public rrc_interface_mac_common { public: + virtual void ho_ra_completed(bool ra_successful) = 0; virtual void release_pucch_srs() = 0; + virtual void run_tti(uint32_t tti) = 0; }; // RRC interface for PHY @@ -150,6 +161,7 @@ public: virtual void out_of_sync() = 0; virtual void earfcn_end() = 0; virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0; + virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn = 0, uint32_t pci = 0) = 0; }; // RRC interface for NAS @@ -162,7 +174,6 @@ public: virtual void enable_capabilities() = 0; virtual void plmn_search() = 0; virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // RRC interface for PDCP @@ -173,7 +184,6 @@ public: virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // RRC interface for RLC @@ -181,7 +191,6 @@ class rrc_interface_rlc { public: virtual void max_retx_attempted() = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // PDCP interface for GW @@ -196,14 +205,21 @@ public: class pdcp_interface_rrc { public: + virtual void reestablish() = 0; virtual void reset() = 0; virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0; virtual void config_security(uint32_t lcid, - uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, + uint8_t *k_enc_, + uint8_t *k_int_, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void config_security_all(uint8_t *k_enc_, + uint8_t *k_int_, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void enable_integrity(uint32_t lcid) = 0; + virtual void enable_encryption(uint32_t lcid) = 0; }; // PDCP interface for RLC @@ -222,6 +238,7 @@ class rlc_interface_rrc { public: virtual void reset() = 0; + virtual void reestablish() = 0; virtual void add_bearer(uint32_t lcid) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0; }; @@ -233,6 +250,7 @@ public: /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls * RLC PDUs according to TB size. */ virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual bool rb_is_um(uint32_t lcid) = 0; }; //RLC interface for MAC @@ -396,8 +414,8 @@ public: LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach; LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr; ul_harq_params_t ul_harq_params; - uint32_t prach_config_index; - } mac_cfg_t; + uint32_t prach_config_index; + } mac_cfg_t; /* Instructs the MAC to start receiving BCCH */ virtual void bcch_start_rx() = 0; @@ -412,7 +430,7 @@ public: virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; virtual uint32_t get_current_tti() = 0; - + virtual void set_config(mac_cfg_t *mac_cfg) = 0; virtual void set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *main_cfg) = 0; virtual void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index) = 0; @@ -421,10 +439,14 @@ public: virtual void get_rntis(ue_rnti_t *rntis) = 0; virtual void set_contention_id(uint64_t uecri) = 0; + virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0; + + virtual void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask) = 0; + virtual void start_cont_ho() = 0; - virtual void reconfiguration() = 0; virtual void reset() = 0; + virtual void wait_uplink() = 0; }; @@ -466,6 +488,7 @@ typedef struct { std::string sss_algorithm; float estimator_fil_w; bool rssi_sensor_enabled; + bool sic_pss_enabled; } phy_args_t; @@ -535,19 +558,28 @@ public: bool enable_64qam; } phy_cfg_t; - virtual void get_current_cell(srslte_cell_t *cell) = 0; - virtual void get_config(phy_cfg_t *phy_cfg) = 0; + virtual void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL) = 0; + virtual uint32_t get_current_earfcn() = 0; + virtual uint32_t get_current_pci() = 0; + + virtual void get_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated) = 0; virtual void set_config_common(phy_cfg_common_t *common) = 0; virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0; virtual void set_config_64qam_en(bool enable) = 0; + /* Measurements interface */ + virtual void meas_reset() = 0; + virtual int meas_start(uint32_t earfcn, int pci = -1) = 0; + virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0; + /* Cell search and selection procedures */ virtual void cell_search_start() = 0; virtual void cell_search_stop() = 0; virtual void cell_search_next() = 0; virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; + virtual bool cell_handover(srslte_cell_t cell) = 0; /* Is the PHY downlink synchronized? */ virtual bool sync_status() = 0; diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 4a1eeb27d..c55713cfc 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -301,7 +301,8 @@ SRSLTE_API int srslte_str2mimotype(char *mimo_type_str, SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type); -SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, +/* Returns the interval tti1-tti2 mod 10240 */ +SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2); #endif diff --git a/lib/include/srslte/phy/dft/ofdm.h b/lib/include/srslte/phy/dft/ofdm.h index cba963ca4..e48c240b9 100644 --- a/lib/include/srslte/phy/dft/ofdm.h +++ b/lib/include/srslte/phy/dft/ofdm.h @@ -113,8 +113,16 @@ SRSLTE_API void srslte_ofdm_rx_free(srslte_ofdm_t *q); SRSLTE_API void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf); +SRSLTE_API void srslte_ofdm_rx_slot_ng(srslte_ofdm_t *q, + cf_t *input, + cf_t *output); + SRSLTE_API void srslte_ofdm_rx_sf(srslte_ofdm_t *q); +SRSLTE_API void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q, + cf_t *input, + cf_t *output); + SRSLTE_API int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp_type, cf_t *in_buffer, diff --git a/lib/include/srslte/phy/fec/rm_turbo.h b/lib/include/srslte/phy/fec/rm_turbo.h index df0720b95..182b49fb8 100644 --- a/lib/include/srslte/phy/fec/rm_turbo.h +++ b/lib/include/srslte/phy/fec/rm_turbo.h @@ -58,6 +58,8 @@ SRSLTE_API int srslte_rm_turbo_tx(uint8_t *w_buff, SRSLTE_API void srslte_rm_turbo_gentables(); +SRSLTE_API void srslte_rm_turbo_free_tables(); + SRSLTE_API int srslte_rm_turbo_tx_lut(uint8_t *w_buff, uint8_t *systematic, uint8_t *parity, diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index c171e69d1..44bde9943 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -91,7 +91,7 @@ SRSLTE_API void srslte_rf_set_tx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); SRSLTE_API void srslte_rf_set_rx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); -SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h); +SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h, bool now); SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h); diff --git a/lib/include/srslte/phy/sync/pss.h b/lib/include/srslte/phy/sync/pss.h index aba84f5cd..922bc0286 100644 --- a/lib/include/srslte/phy/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -29,9 +29,9 @@ * * Description: Primary synchronization signal (PSS) generation and detection. * - * The srslte_pss_synch_t object provides functions for fast + * The srslte_pss_t object provides functions for fast * computation of the crosscorrelation between the PSS and received - * signal and CFO estimation. Also, the function srslte_pss_synch_tperiodic() + * signal and CFO estimation. Also, the function srslte_pss_tperiodic() * is designed to be called periodically every subframe, taking * care of the correct data alignment with respect to the PSS sequence. * @@ -61,7 +61,7 @@ /* PSS processing options */ -#define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_synch_find_pss +#define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_find_pss #define SRSLTE_PSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value @@ -85,6 +85,7 @@ typedef struct SRSLTE_API { cf_t *pss_signal_freq_full[3]; cf_t *pss_signal_time[3]; + cf_t *pss_signal_time_scale[3]; cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2 cf_t *tmp_input; @@ -100,41 +101,48 @@ typedef struct SRSLTE_API { cf_t tmp_fft[SRSLTE_SYMBOL_SZ_MAX]; cf_t tmp_fft2[SRSLTE_SYMBOL_SZ_MAX]; -}srslte_pss_synch_t; + cf_t tmp_ce[SRSLTE_PSS_LEN]; + + bool chest_on_filter; + +}srslte_pss_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; /* Basic functionality */ -SRSLTE_API int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size); -SRSLTE_API int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft_offset(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int cfo_i); -SRSLTE_API int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int cfo_i, int decimate); -SRSLTE_API int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, +SRSLTE_API int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset); -SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init(srslte_pss_t *q, uint32_t frame_size); -SRSLTE_API void srslte_pss_synch_free(srslte_pss_synch_t *q); +SRSLTE_API void srslte_pss_free(srslte_pss_t *q); -SRSLTE_API void srslte_pss_synch_reset(srslte_pss_synch_t *q); +SRSLTE_API void srslte_pss_reset(srslte_pss_t *q); -SRSLTE_API void srslte_pss_synch_filter_enable(srslte_pss_synch_t *q, +SRSLTE_API void srslte_pss_filter_enable(srslte_pss_t *q, bool enable); -SRSLTE_API void srslte_pss_synch_filter(srslte_pss_synch_t *q, +SRSLTE_API void srslte_pss_sic(srslte_pss_t *q, + cf_t *input); + +SRSLTE_API void srslte_pss_filter(srslte_pss_t *q, const cf_t *input, cf_t *output); @@ -151,21 +159,21 @@ SRSLTE_API void srslte_pss_put_slot(cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp); -SRSLTE_API void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, +SRSLTE_API void srslte_pss_set_ema_alpha(srslte_pss_t *q, float alpha); -SRSLTE_API int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_set_N_id_2(srslte_pss_t *q, uint32_t N_id_2); -SRSLTE_API int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_find_pss(srslte_pss_t *q, const cf_t *input, float *corr_peak_value); -SRSLTE_API int srslte_pss_synch_chest(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_chest(srslte_pss_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]); -SRSLTE_API float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, +SRSLTE_API float srslte_pss_cfo_compute(srslte_pss_t* q, const cf_t *pss_recv); #endif // PSS_ diff --git a/lib/include/srslte/phy/sync/sss.h b/lib/include/srslte/phy/sync/sss.h index 4a0942d61..9f77d1ce6 100644 --- a/lib/include/srslte/phy/sync/sss.h +++ b/lib/include/srslte/phy/sync/sss.h @@ -83,17 +83,17 @@ typedef struct SRSLTE_API { float corr_output_m0[SRSLTE_SSS_N]; float corr_output_m1[SRSLTE_SSS_N]; -}srslte_sss_synch_t; +}srslte_sss_t; /* Basic functionality */ -SRSLTE_API int srslte_sss_synch_init(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_init(srslte_sss_t *q, uint32_t fft_size); -SRSLTE_API int srslte_sss_synch_resize(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_resize(srslte_sss_t *q, uint32_t fft_size); -SRSLTE_API void srslte_sss_synch_free(srslte_sss_synch_t *q); +SRSLTE_API void srslte_sss_free(srslte_sss_t *q); SRSLTE_API void srslte_sss_generate(float *signal0, float *signal5, @@ -104,10 +104,10 @@ SRSLTE_API void srslte_sss_put_slot(float *sss, uint32_t nof_prb, srslte_cp_t cp); -SRSLTE_API int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_set_N_id_2(srslte_sss_t *q, uint32_t N_id_2); -SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_m0m1_partial(srslte_sss_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], @@ -116,7 +116,7 @@ SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, uint32_t *m1, float *m1_value); -SRSLTE_API int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_m0m1_diff_coh(srslte_sss_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, @@ -124,7 +124,7 @@ SRSLTE_API int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, uint32_t *m1, float *m1_value); -SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_m0m1_diff(srslte_sss_t *q, const cf_t *input, uint32_t *m0, float *m0_value, @@ -132,25 +132,25 @@ SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, float *m1_value); -SRSLTE_API uint32_t srslte_sss_synch_subframe(uint32_t m0, +SRSLTE_API uint32_t srslte_sss_subframe(uint32_t m0, uint32_t m1); -SRSLTE_API int srslte_sss_synch_N_id_1(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t *q, uint32_t m0, uint32_t m1); -SRSLTE_API int srslte_sss_synch_frame(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_frame(srslte_sss_t *q, cf_t *input, uint32_t *subframe_idx, uint32_t *N_id_1); -SRSLTE_API void srslte_sss_synch_set_threshold(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_threshold(srslte_sss_t *q, float threshold); -SRSLTE_API void srslte_sss_synch_set_symbol_sz(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_symbol_sz(srslte_sss_t *q, uint32_t symbol_sz); -SRSLTE_API void srslte_sss_synch_set_subframe_sz(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_subframe_sz(srslte_sss_t *q, uint32_t subframe_sz); #endif // SSS_ diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index 151c530b1..3146761ce 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -60,9 +60,9 @@ typedef enum {SSS_DIFF=0, SSS_PARTIAL_3=2, SSS_FULL=1} sss_alg_t; typedef struct SRSLTE_API { - srslte_pss_synch_t pss; - srslte_pss_synch_t pss_i[2]; - srslte_sss_synch_t sss; + srslte_pss_t pss; + srslte_pss_t pss_i[2]; + srslte_sss_t sss; srslte_cp_synch_t cp_synch; cf_t *cfo_i_corr[2]; int decimate; @@ -110,7 +110,7 @@ typedef struct SRSLTE_API { srslte_cfo_t cfo_corr_frame; srslte_cfo_t cfo_corr_symbol; - bool sss_filtering_enabled; + bool sss_channel_equalize; bool pss_filtering_enabled; cf_t sss_filt[SRSLTE_SYMBOL_SZ_MAX]; cf_t pss_filt[SRSLTE_SYMBOL_SZ_MAX]; @@ -186,8 +186,8 @@ SRSLTE_API int srslte_sync_get_cell_id(srslte_sync_t *q); SRSLTE_API void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, bool enable); -SRSLTE_API void srslte_sync_set_sss_filt_enable(srslte_sync_t *q, - bool enable); +SRSLTE_API void srslte_sync_set_sss_eq_enable(srslte_sync_t *q, + bool enable); /* Gets the CFO estimation from the last call to synch_run() */ SRSLTE_API float srslte_sync_get_cfo(srslte_sync_t *q); @@ -227,7 +227,7 @@ SRSLTE_API void srslte_sync_set_cp(srslte_sync_t *q, SRSLTE_API void srslte_sync_sss_en(srslte_sync_t *q, bool enabled); -SRSLTE_API srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); +SRSLTE_API srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index a60761a37..02341c08d 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -131,7 +131,7 @@ typedef struct SRSLTE_API { /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, - cf_t *in_buffer[SRSLTE_MAX_PORTS], + cf_t *input[SRSLTE_MAX_PORTS], uint32_t max_prb, uint32_t nof_rx_antennas); @@ -141,20 +141,22 @@ SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell); int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - uint32_t sf_idx, + uint32_t sf_idx, uint32_t *cfi); SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - uint32_t sf_idx, + uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type); +SRSLTE_API int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t *cfi); -int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, - uint32_t sf_idx, - uint32_t *cfi); +SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, + uint32_t sf_idx, + uint32_t *cfi); SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, @@ -195,14 +197,12 @@ SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset); SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, @@ -216,7 +216,6 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, * srslte_pmch_decode_multi */ SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti); diff --git a/lib/include/srslte/phy/utils/bit.h b/lib/include/srslte/phy/utils/bit.h index c02ecd6bb..e4289b790 100644 --- a/lib/include/srslte/phy/utils/bit.h +++ b/lib/include/srslte/phy/utils/bit.h @@ -40,6 +40,25 @@ #include "srslte/config.h" +typedef struct { + uint32_t nof_bits; + uint16_t *interleaver; + uint16_t *byte_idx; + uint8_t *bit_mask; + uint8_t n_128; +} srslte_bit_interleaver_t; + +SRSLTE_API void srslte_bit_interleaver_init(srslte_bit_interleaver_t *q, + uint16_t *interleaver, + uint32_t nof_bits); + +SRSLTE_API void srslte_bit_interleaver_free(srslte_bit_interleaver_t *q); + +SRSLTE_API void srslte_bit_interleaver_run(srslte_bit_interleaver_t *q, + uint8_t *input, + uint8_t *output, + uint16_t w_offset); + SRSLTE_API void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, diff --git a/lib/include/srslte/phy/utils/ringbuffer.h b/lib/include/srslte/phy/utils/ringbuffer.h index 9cbe0ddd6..e590131ff 100644 --- a/lib/include/srslte/phy/utils/ringbuffer.h +++ b/lib/include/srslte/phy/utils/ringbuffer.h @@ -17,18 +17,21 @@ typedef struct { } srslte_ringbuffer_t; -SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, +SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity); -SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q, - int capacity); +SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q); + +SRSLTE_API void srslte_ringbuffer_reset(srslte_ringbuffer_t *q); + +SRSLTE_API int srslte_ringbuffer_status(srslte_ringbuffer_t *q); -SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, - uint8_t *ptr, +SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, + void *ptr, int nof_bytes); -SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, - uint8_t *ptr, +SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, + void *ptr, int nof_bytes); diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 2a34bd9a9..6ff0c5100 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -118,7 +118,7 @@ namespace srslte { void start_trace(); void write_trace(std::string filename); - void start_rx(); + void start_rx(bool now = false); void stop_rx(); void set_tti(uint32_t tti); diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h index f44f5325d..f4806b36d 100644 --- a/lib/include/srslte/srslte.h +++ b/lib/include/srslte/srslte.h @@ -39,6 +39,7 @@ #include "srslte/version.h" #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/ringbuffer.h" #include "srslte/phy/utils/convolution.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/cexptab.h" diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index ce6ece151..584b231a3 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -54,14 +54,21 @@ public: bool is_drb_enabled(uint32_t lcid); // RRC interface + void reestablish(); void reset(); void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void config_security(uint32_t lcid, - uint8_t *k_rrc_enc, - uint8_t *k_rrc_int, + uint8_t *k_enc, + uint8_t *k_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void config_security_all(uint8_t *k_enc, + uint8_t *k_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void enable_integrity(uint32_t lcid); + void enable_encryption(uint32_t lcid); // RLC interface void write_pdu(uint32_t lcid, byte_buffer_t *sdu); diff --git a/lib/include/srslte/upper/pdcp_entity.h b/lib/include/srslte/upper/pdcp_entity.h index 0ff005d07..186da3767 100644 --- a/lib/include/srslte/upper/pdcp_entity.h +++ b/lib/include/srslte/upper/pdcp_entity.h @@ -32,6 +32,8 @@ #include "srslte/common/common.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" +#include "srslte/common/msg_queue.h" +#include "srslte/common/threads.h" namespace srslte { @@ -59,6 +61,7 @@ static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU", * Common interface for all PDCP entities ***************************************************************************/ class pdcp_entity + :public thread { public: pdcp_entity(); @@ -68,16 +71,20 @@ public: srslte::log *log_, uint32_t lcid_, srslte_pdcp_config_t cfg_); + void stop(); void reset(); + void reestablish(); bool is_active(); // RRC interface void write_sdu(byte_buffer_t *sdu); - void config_security(uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, + void config_security(uint8_t *k_enc_, + uint8_t *k_int_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_); + void enable_integrity(); + void enable_encryption(); // RLC interface void write_pdu(byte_buffer_t *pdu); @@ -90,26 +97,46 @@ private: srsue::rrc_interface_pdcp *rrc; srsue::gw_interface_pdcp *gw; + static const int PDCP_THREAD_PRIO = 7; + srslte::msg_queue rx_pdu_queue; + bool running; + bool active; uint32_t lcid; srslte_pdcp_config_t cfg; + uint8_t sn_len_bytes; + bool do_integrity; + bool do_encryption; uint32_t rx_count; uint32_t tx_count; - uint8_t k_rrc_enc[32]; - uint8_t k_rrc_int[32]; + uint8_t k_enc[32]; + uint8_t k_int[32]; CIPHERING_ALGORITHM_ID_ENUM cipher_algo; INTEGRITY_ALGORITHM_ID_ENUM integ_algo; - void integrity_generate(uint8_t *key_128, - uint32_t count, - uint8_t rb_id, - uint8_t direction, - uint8_t *msg, + void integrity_generate(uint8_t *msg, uint32_t msg_len, uint8_t *mac); + bool integrity_verify(uint8_t *msg, + uint32_t count, + uint32_t msg_len, + uint8_t *mac); + + void cipher_encrypt(uint8_t *msg, + uint32_t msg_len, + uint8_t *ct); + + void cipher_decrypt(uint8_t *ct, + uint32_t count, + uint32_t ct_len, + uint8_t *msg); + + void run_thread(); + + uint8_t get_bearer_id(uint8_t lcid); }; /**************************************************************************** diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 349a7952d..17f6bd82c 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -64,7 +64,8 @@ public: // PDCP interface void write_sdu(uint32_t lcid, byte_buffer_t *sdu); - std::string get_rb_name(uint32_t lcid); + + bool rb_is_um(uint32_t lcid); // MAC interface uint32_t get_buffer_state(uint32_t lcid); @@ -76,6 +77,7 @@ public: void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes); // RRC interface + void reestablish(); void reset(); void empty_queue(); void add_bearer(uint32_t lcid); diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index cee0d5959..c0289956c 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -78,6 +78,7 @@ public: mac_interface_timers *mac_timers); void configure(srslte_rlc_config_t cnfg); void reset(); + void reestablish(); void stop(); void empty_queue(); diff --git a/lib/include/srslte/upper/rlc_entity.h b/lib/include/srslte/upper/rlc_entity.h index e9c41fa30..de4a396fe 100644 --- a/lib/include/srslte/upper/rlc_entity.h +++ b/lib/include/srslte/upper/rlc_entity.h @@ -56,6 +56,7 @@ public: void configure(srslte_rlc_config_t cnfg); void reset(); + void reestablish(); void stop(); void empty_queue(); bool active(); diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc index 215ffd838..ce3c08987 100644 --- a/lib/src/asn1/liblte_mme.cc +++ b/lib/src/asn1/liblte_mme.cc @@ -4922,6 +4922,32 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8 MESSAGE FUNCTIONS *******************************************************************************/ +/********************************************************************* + Message Name: Security Message Header (Plain NAS Message) + + Description: Security header for NAS messages. + + Document Reference: 24.301 v10.2.0 Section 9.1 +*********************************************************************/ + +LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 *pd, + uint8 *sec_hdr_type) +{ + + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if (msg != NULL && + pd != NULL && + sec_hdr_type != NULL) + { + *sec_hdr_type = (uint8) ((msg->msg[0] & 0xF0) >> 4); + err = LIBLTE_SUCCESS; + } + return(err); +} + + /********************************************************************* Message Name: Message Header (Plain NAS Message) diff --git a/lib/src/common/liblte_security.cc b/lib/src/common/liblte_security.cc index 95f9617cd..1cf83e5b3 100644 --- a/lib/src/common/liblte_security.cc +++ b/lib/src/common/liblte_security.cc @@ -55,6 +55,11 @@ typedef struct{ uint8 state[4][4]; }STATE_STRUCT; +typedef struct{ + uint32 * lfsr; + uint32 * fsm; +}S3G_STATE; + /******************************************************************************* GLOBAL VARIABLES *******************************************************************************/ @@ -76,6 +81,35 @@ static const uint8 S[256] = { 99,124,119,123,242,107,111,197, 48, 1,103, 43,254 225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223, 140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22}; +/* S-box SQ */ +static const uint8 SQ[256] = { 0x25, 0x24, 0x73, 0x67, 0xD7, 0xAE, + 0x5C, 0x30, 0xA4, 0xEE, 0x6E, 0xCB, 0x7D, 0xB5, 0x82, 0xDB, + 0xE4, 0x8E, 0x48, 0x49, 0x4F, 0x5D, 0x6A, 0x78, 0x70, 0x88, + 0xE8, 0x5F, 0x5E, 0x84, 0x65, 0xE2, 0xD8, 0xE9, 0xCC, 0xED, + 0x40, 0x2F, 0x11, 0x28, 0x57, 0xD2, 0xAC, 0xE3, 0x4A, 0x15, + 0x1B, 0xB9, 0xB2, 0x80, 0x85, 0xA6, 0x2E, 0x02, 0x47, 0x29, + 0x07, 0x4B, 0x0E, 0xC1, 0x51, 0xAA, 0x89, 0xD4, 0xCA, 0x01, + 0x46, 0xB3, 0xEF, 0xDD, 0x44, 0x7B, 0xC2, 0x7F, 0xBE, 0xC3, + 0x9F, 0x20, 0x4C, 0x64, 0x83, 0xA2, 0x68, 0x42, 0x13, 0xB4, + 0x41, 0xCD, 0xBA, 0xC6, 0xBB, 0x6D, 0x4D, 0x71, 0x21, 0xF4, + 0x8D, 0xB0, 0xE5, 0x93, 0xFE, 0x8F, 0xE6, 0xCF, 0x43, 0x45, + 0x31, 0x22, 0x37, 0x36, 0x96, 0xFA, 0xBC, 0x0F, 0x08, 0x52, + 0x1D, 0x55, 0x1A, 0xC5, 0x4E, 0x23, 0x69, 0x7A, 0x92, 0xFF, + 0x5B, 0x5A, 0xEB, 0x9A, 0x1C, 0xA9, 0xD1, 0x7E, 0x0D, 0xFC, + 0x50, 0x8A, 0xB6, 0x62, 0xF5, 0x0A, 0xF8, 0xDC, 0x03, 0x3C, + 0x0C, 0x39, 0xF1, 0xB8, 0xF3, 0x3D, 0xF2, 0xD5, 0x97, 0x66, + 0x81, 0x32, 0xA0, 0x00, 0x06, 0xCE, 0xF6, 0xEA, 0xB7, 0x17, + 0xF7, 0x8C, 0x79, 0xD6, 0xA7, 0xBF, 0x8B, 0x3F, 0x1F, 0x53, + 0x63, 0x75, 0x35, 0x2C, 0x60, 0xFD, 0x27, 0xD3, 0x94, 0xA5, + 0x7C, 0xA1, 0x05, 0x58, 0x2D, 0xBD, 0xD9, 0xC7, 0xAF, 0x6B, + 0x54, 0x0B, 0xE0, 0x38, 0x04, 0xC8, 0x9D, 0xE7, 0x14, 0xB1, + 0x87, 0x9C, 0xDF, 0x6F, 0xF9, 0xDA, 0x2A, 0xC4, 0x59, 0x16, + 0x74, 0x91, 0xAB, 0x26, 0x61, 0x76, 0x34, 0x2B, 0xAD, 0x99, + 0xFB, 0x72, 0xEC, 0x33, 0x12, 0xDE, 0x98, 0x3B, 0xC0, 0x9B, + 0x3E, 0x18, 0x10, 0x3A, 0x56, 0xE1, 0x77, 0xC9, 0x1E, 0x9E, + 0x95, 0xA3, 0x90, 0x19, 0xA8, 0x6C, 0x09, 0xD0, 0xF0, 0x86 }; + + static const uint8 X_TIME[256] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, @@ -195,6 +229,136 @@ void shift_row(STATE_STRUCT *state); // Functions void mix_column(STATE_STRUCT *state); +/********************************************************************* + Name: zero_tailing_bits + + Description: Fill tailing bits with zeros. + + Document Reference: - +*********************************************************************/ +void zero_tailing_bits(uint8 * data, uint32 length_bits); + +/********************************************************************* + Name: s3g_mul_x + + Description: Multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.1 +*********************************************************************/ +uint8 s3g_mul_x(uint8 v, uint8 c); + +/********************************************************************* + Name: s3g_mul_x_pow + + Description: Recursive multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.2 +*********************************************************************/ +uint8 s3g_mul_x_pow(uint8 v, uint8 i, uint8 c); + +/********************************************************************* + Name: s3g_mul_alpha + + Description: Multiplication with alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.2 +*********************************************************************/ +uint32 s3g_mul_alpha(uint8 c); + +/********************************************************************* + Name: s3g_div_alpha + + Description: Division by alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.3 +*********************************************************************/ +uint32 s3g_div_alpha(uint8 c); + +/********************************************************************* + Name: s3g_s1 + + Description: S-Box S1. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.1 +*********************************************************************/ +uint32 s3g_s1(uint32 w); + +/********************************************************************* + Name: s3g_s2 + + Description: S-Box S2. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.2 +*********************************************************************/ +uint32 s3g_s2(uint32 w); + +/********************************************************************* + Name: s3g_clock_lfsr + + Description: Clocking LFSR. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.4 and Section 3.4.5 +*********************************************************************/ +void s3g_clock_lfsr(S3G_STATE * state, uint32 f); + +/********************************************************************* + Name: s3g_clock_fsm + + Description: Clocking FSM. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.6 +*********************************************************************/ +uint32 s3g_clock_fsm(S3G_STATE * state); + +/********************************************************************* + Name: s3g_initialize + + Description: Initialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.1 +*********************************************************************/ +void s3g_initialize(S3G_STATE * state, uint32 k[4], uint32 iv[4]); + +/********************************************************************* + Name: s3g_deinitialize + + Description: Deinitialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 +*********************************************************************/ +void s3g_deinitialize(S3G_STATE * state); + +/********************************************************************* + Name: s3g_generate_keystream + + Description: Generation of Keystream. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.2 +*********************************************************************/ +void s3g_generate_keystream(S3G_STATE * state, uint32 n, uint32 *ks); + + /******************************************************************************* FUNCTIONS *******************************************************************************/ @@ -298,6 +462,71 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme, return(err); } +/********************************************************************* + Name: liblte_security_generate_k_enb_star + + Description: Generate the security key Kenb*. + + Document Reference: 33.401 v10.0.0 Annex A.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb, + uint32 pci, + uint32_t earfcn, + uint8 *k_enb_star) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[9]; + + if (k_enb_star != NULL && + k_enb != NULL) { + // Construct S + s[0] = 0x13; // FC + s[1] = (pci >> 8) & 0xFF; // First byte of P0 + s[2] = pci & 0xFF; // Second byte of P0 + s[3] = 0x00; // First byte of L0 + s[4] = 0x02; // Second byte of L0 + s[5] = (earfcn >> 8) & 0xFF; // First byte of P0 + s[6] = earfcn & 0xFF; // Second byte of P0 + s[7] = 0x00; // First byte of L0 + s[8] = 0x02; // Second byte of L0 + + // Derive Kenb + sha256(k_enb, 32, s, 9, k_enb_star, 0); + + err = LIBLTE_SUCCESS; + } + + return (err); +} + +LIBLTE_ERROR_ENUM liblte_security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[35]; + + if (k_asme != NULL && + sync != NULL && + nh != NULL) + { + // Construct S + s[0] = 0x12; // FC + for (int i=0;i<32;i++) { + s[1+i] = sync[i]; + } + s[33] = 0x00; // First byte of L0 + s[34] = 0x20, // Second byte of L0 + + // Derive NH + sha256(k_asme, 32, s, 35, nh, 0); + + err = LIBLTE_SUCCESS; + } + + return (err); +} + /********************************************************************* Name: liblte_security_generate_k_nas @@ -682,6 +911,183 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(uint8 *key, return(err); } +/********************************************************************* + Name: liblte_security_encryption_eea1 + + Description: 128-bit encryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + S3G_STATE state, *state_ptr; + uint32 k[] = {0,0,0,0}; + uint32 iv[] = {0,0,0,0}; + uint32 *ks; + int32 i; + uint32 msg_len_block_8, msg_len_block_32, m; + + if (key != NULL && + msg != NULL && + out != NULL) + { + state_ptr = &state; + msg_len_block_8 = (msg_len + 7) / 8; + msg_len_block_32 = (msg_len + 31) / 32; + + // Transform key + for (i = 3; i >= 0; i--) { + k[i] = (key[4 * (3 - i) + 0] << 24) | + (key[4 * (3 - i) + 1] << 16) | + (key[4 * (3 - i) + 2] << 8) | + (key[4 * (3 - i) + 3]); + } + + // Construct iv + iv[3] = count; + iv[2] = ((bearer & 0x1F) << 27) | ((direction & 0x01) << 26); + iv[1] = iv[3]; + iv[0] = iv[2]; + + // Initialize keystream + s3g_initialize(state_ptr, k, iv); + + // Generate keystream + + ks = (uint32 *) calloc(msg_len_block_32, sizeof(uint32)); + s3g_generate_keystream(state_ptr, msg_len_block_32, ks); + + // Generate output except last block + for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) { + out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF); + out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF); + out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF); + out[4 * i + 3] = msg[4 * i + 3] ^ ((ks[i] & 0xFF)); + } + + // Process last bytes + for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) { + out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF); + } + + // Zero tailing bits + zero_tailing_bits(out, msg_len); + + // Clean up + free(ks); + s3g_deinitialize(state_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_decryption_eea1 + + Description: 128-bit decryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out) { + return liblte_security_encryption_eea1(key, count, bearer, + direction, ct, ct_len, out); +} + +/********************************************************************* + Name: liblte_security_encryption_eea2 + + Description: 128-bit encryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + aes_context ctx; + unsigned char stream_blk[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char nonce_cnt[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int32 i; + int ret; + size_t nc_off = 0; + + if(key != NULL && + msg != NULL && + out != NULL) + { + ret = aes_setkey_enc(&ctx, key, 128); + + if (ret == 0) { + // Construct nonce + nonce_cnt[0] = (count >> 24) & 0xFF; + nonce_cnt[1] = (count >> 16) & 0xFF; + nonce_cnt[2] = (count >> 8) & 0xFF; + nonce_cnt[3] = (count) & 0xFF; + nonce_cnt[4] = ((bearer & 0x1F) << 3) | + ((direction & 0x01) << 2); + + // Encryption + ret = aes_crypt_ctr(&ctx, (msg_len + 7) / 8, &nc_off, nonce_cnt, + stream_blk, msg, out); + } + + if (ret == 0) { + // Zero tailing bits + zero_tailing_bits(out, msg_len); + err = LIBLTE_SUCCESS; + } + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_decryption_eea2 + + Description: 128-bit decryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out) +{ + return liblte_security_encryption_eea2(key, count, bearer, + direction, ct, ct_len, out); +} + + + /********************************************************************* Name: liblte_security_milenage_f1 @@ -1243,3 +1649,293 @@ void mix_column(STATE_STRUCT *state) state->state[3][i] ^= temp ^ tmp; } } + +/********************************************************************* + Name: zero_tailing_bits + + Description: Fill tailing bits with zeros. + + Document Reference: - +*********************************************************************/ +void zero_tailing_bits(uint8 * data, uint32 length_bits) { + uint8 bits = (8 - (length_bits & 0x07)) & 0x07; + data[(length_bits + 7) / 8 - 1] &= (uint8) (0xFF << bits); +} + +/********************************************************************* + Name: s3g_mul_x + + Description: Multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.1 +*********************************************************************/ +uint8 s3g_mul_x(uint8 v, uint8 c) { + if (v & 0x80) + return ((v << 1) ^ c); + else + return (v << 1); +} + +/********************************************************************* + Name: s3g_mul_x_pow + + Description: Recursive multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.2 +*********************************************************************/ +uint8 s3g_mul_x_pow(uint8 v, uint8 i, uint8 c) { + if (i == 0) + return v; + else + return s3g_mul_x(s3g_mul_x_pow(v, i - 1, c), c); +} + +/********************************************************************* + Name: s3g_mul_alpha + + Description: Multiplication with alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.2 +*********************************************************************/ +uint32 s3g_mul_alpha(uint8 c) { + return ((((uint32) s3g_mul_x_pow(c, 23, 0xa9)) << 24) | + (((uint32) s3g_mul_x_pow(c, 245, 0xa9)) << 16) | + (((uint32) s3g_mul_x_pow(c, 48, 0xa9)) << 8) | + (((uint32) s3g_mul_x_pow(c, 239, 0xa9)))); +} + +/********************************************************************* + Name: s3g_div_alpha + + Description: Division by alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.3 +*********************************************************************/ +uint32 s3g_div_alpha(uint8 c) { + return ((((uint32) s3g_mul_x_pow(c, 16, 0xa9)) << 24) | + (((uint32) s3g_mul_x_pow(c, 39, 0xa9)) << 16) | + (((uint32) s3g_mul_x_pow(c, 6, 0xa9)) << 8) | + (((uint32) s3g_mul_x_pow(c, 64, 0xa9)))); +} + +/********************************************************************* + Name: s3g_s1 + + Description: S-Box S1. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.1 +*********************************************************************/ +uint32 s3g_s1(uint32 w) { + uint8 r0 = 0, r1 = 0, r2 = 0, r3 = 0; + uint8 srw0 = S[(uint8) ((w >> 24) & 0xff)]; + uint8 srw1 = S[(uint8) ((w >> 16) & 0xff)]; + uint8 srw2 = S[(uint8) ((w >> 8) & 0xff)]; + uint8 srw3 = S[(uint8) ((w) & 0xff)]; + + r0 = ((s3g_mul_x(srw0, 0x1b)) ^ + (srw1) ^ + (srw2) ^ + ((s3g_mul_x(srw3, 0x1b)) ^ srw3)); + + r1 = (((s3g_mul_x(srw0, 0x1b)) ^ srw0) ^ + (s3g_mul_x(srw1, 0x1b)) ^ + (srw2) ^ + (srw3)); + + r2 = ((srw0) ^ + ((s3g_mul_x(srw1, 0x1b)) ^ srw1) ^ + (s3g_mul_x(srw2, 0x1b)) ^ + (srw3)); + + r3 = ((srw0) ^ + (srw1) ^ + ((s3g_mul_x(srw2, 0x1b)) ^ srw2) ^ + (s3g_mul_x(srw3, 0x1b))); + + return ((((uint32) r0) << 24) | + (((uint32) r1) << 16) | + (((uint32) r2) << 8) | + (((uint32) r3))); +} + +/********************************************************************* + Name: s3g_s2 + + Description: S-Box S2. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.2 +*********************************************************************/ +uint32 s3g_s2(uint32 w) { + uint8 r0 = 0, r1 = 0, r2 = 0, r3 = 0; + uint8 sqw0 = SQ[(uint8) ((w >> 24) & 0xff)]; + uint8 sqw1 = SQ[(uint8) ((w >> 16) & 0xff)]; + uint8 sqw2 = SQ[(uint8) ((w >> 8) & 0xff)]; + uint8 sqw3 = SQ[(uint8) ((w) & 0xff)]; + + r0 = ((s3g_mul_x(sqw0, 0x69)) ^ + (sqw1) ^ + (sqw2) ^ + ((s3g_mul_x(sqw3, 0x69)) ^ sqw3)); + + r1 = (((s3g_mul_x(sqw0, 0x69)) ^ sqw0) ^ + (s3g_mul_x(sqw1, 0x69)) ^ + (sqw2) ^ + (sqw3)); + + r2 = ((sqw0) ^ + ((s3g_mul_x(sqw1, 0x69)) ^ sqw1) ^ + (s3g_mul_x(sqw2, 0x69)) ^ + (sqw3)); + + r3 = ((sqw0) ^ + (sqw1) ^ + ((s3g_mul_x(sqw2, 0x69)) ^ sqw2) ^ + (s3g_mul_x(sqw3, 0x69))); + + return ((((uint32) r0) << 24) | + (((uint32) r1) << 16) | + (((uint32) r2) << 8) | + (((uint32) r3))); +} + +/********************************************************************* + Name: s3g_clock_lfsr + + Description: Clocking LFSR. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.4 and Section 3.4.5 +*********************************************************************/ +void s3g_clock_lfsr(S3G_STATE * state, uint32 f) { + uint32 v = ( + ((state->lfsr[0] << 8) & 0xffffff00) ^ + (s3g_mul_alpha((uint8) ((state->lfsr[0] >> 24) & 0xff))) ^ + (state->lfsr[2]) ^ + ((state->lfsr[11] >> 8) & 0x00ffffff) ^ + (s3g_div_alpha((uint8) ((state->lfsr[11]) & 0xff))) ^ + (f) + ); + uint8 i; + + for (i = 0; i < 15; i++) { + state->lfsr[i] = state->lfsr[i + 1]; + } + state->lfsr[15] = v; +} + +/********************************************************************* + Name: s3g_clock_fsm + + Description: Clocking FSM. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.6 +*********************************************************************/ +uint32 s3g_clock_fsm(S3G_STATE * state) { + uint32 f = ((state->lfsr[15] + state->fsm[0]) & 0xffffffff) ^ + state->fsm[1]; + uint32 r = (state->fsm[1] + (state->fsm[2] ^ state->lfsr[5])) & + 0xffffffff; + + state->fsm[2] = s3g_s2(state->fsm[1]); + state->fsm[1] = s3g_s1(state->fsm[0]); + state->fsm[0] = r; + + return f; +} + +/********************************************************************* + Name: s3g_initialize + + Description: Initialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.1 +*********************************************************************/ +void s3g_initialize(S3G_STATE * state, uint32 k[4], uint32 iv[4]) { + uint8 i = 0; + uint32 f = 0x0; + + state->lfsr = (uint32 *) calloc(16, sizeof(uint32)); + state->fsm = (uint32 *) calloc( 3, sizeof(uint32)); + + state->lfsr[15] = k[3] ^ iv[0]; + state->lfsr[14] = k[2]; + state->lfsr[13] = k[1]; + state->lfsr[12] = k[0] ^ iv[1]; + + state->lfsr[11] = k[3] ^ 0xffffffff; + state->lfsr[10] = k[2] ^ 0xffffffff ^ iv[2]; + state->lfsr[ 9] = k[1] ^ 0xffffffff ^ iv[3]; + state->lfsr[ 8] = k[0] ^ 0xffffffff; + state->lfsr[ 7] = k[3]; + state->lfsr[ 6] = k[2]; + state->lfsr[ 5] = k[1]; + state->lfsr[ 4] = k[0]; + state->lfsr[ 3] = k[3] ^ 0xffffffff; + state->lfsr[ 2] = k[2] ^ 0xffffffff; + state->lfsr[ 1] = k[1] ^ 0xffffffff; + state->lfsr[ 0] = k[0] ^ 0xffffffff; + + state->fsm[0] = 0x0; + state->fsm[1] = 0x0; + state->fsm[2] = 0x0; + for (i = 0; i < 32; i++) { + f = s3g_clock_fsm(state); + s3g_clock_lfsr(state, f); + } +} + +/********************************************************************* + Name: s3g_deinitialize + + Description: Deinitialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 +*********************************************************************/ +void s3g_deinitialize(S3G_STATE * state) { + free(state->lfsr); + free(state->fsm); +} + +/********************************************************************* + Name: s3g_generate_keystream + + Description: Generation of Keystream. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.2 +*********************************************************************/ +void s3g_generate_keystream(S3G_STATE * state, uint32 n, uint32 *ks) { + uint32 t = 0; + uint32 f = 0x0; + + // Clock FSM once. Discard the output. + s3g_clock_fsm(state); + // Clock LFSR in keystream mode once. + s3g_clock_lfsr(state, 0x0); + + for (t = 0; t < n; t++) { + f = s3g_clock_fsm(state); + // Note that ks[t] corresponds to z_{t+1} in section 4.2 + ks[t] = f ^ state->lfsr[0]; + s3g_clock_lfsr(state, 0x0); + } +} diff --git a/lib/src/common/mac_pcap.cc b/lib/src/common/mac_pcap.cc index ff30670ed..caca254a3 100644 --- a/lib/src/common/mac_pcap.cc +++ b/lib/src/common/mac_pcap.cc @@ -40,14 +40,18 @@ void mac_pcap::enable(bool en) } void mac_pcap::open(const char* filename, uint32_t ue_id) { - pcap_file = MAC_LTE_PCAP_Open(filename); - ue_id = ue_id; - enable_write = true; + pcap_file = LTE_PCAP_Open(MAC_LTE_DLT, filename); + this->ue_id = ue_id; + enable_write = true; } void mac_pcap::close() { - fprintf(stdout, "Saving PCAP file\n"); - MAC_LTE_PCAP_Close(pcap_file); + fprintf(stdout, "Saving MAC PCAP file\n"); + LTE_PCAP_Close(pcap_file); +} + +void mac_pcap::set_ue_id(uint16_t ue_id) { + this->ue_id = ue_id; } void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, @@ -65,7 +69,7 @@ void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reT (uint16_t)(tti%10) /* Subframe number */ }; if (pdu) { - MAC_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + LTE_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); } } } diff --git a/lib/src/common/nas_pcap.cc b/lib/src/common/nas_pcap.cc new file mode 100644 index 000000000..94e2cd9b0 --- /dev/null +++ b/lib/src/common/nas_pcap.cc @@ -0,0 +1,35 @@ +#include +#include "srslte/srslte.h" +#include "srslte/common/pcap.h" +#include "srslte/common/nas_pcap.h" + + +namespace srslte { + +void nas_pcap::enable() +{ + enable_write = true; +} +void nas_pcap::open(const char* filename, uint32_t ue_id) +{ + pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename); + ue_id = ue_id; + enable_write = true; +} +void nas_pcap::close() +{ + fprintf(stdout, "Saving NAS PCAP file\n"); + LTE_PCAP_Close(pcap_file); +} + +void nas_pcap::write_nas(uint8_t *pdu, uint32_t pdu_len_bytes) +{ + if (enable_write) { + NAS_Context_Info_t context; + if (pdu) { + LTE_PCAP_NAS_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } + } +} + +} diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc index f0ad1ce7e..fba1b37d9 100644 --- a/lib/src/common/security.cc +++ b/lib/src/common/security.cc @@ -61,6 +61,26 @@ uint8_t security_generate_k_enb( uint8_t *k_asme, k_enb); } +uint8_t security_generate_k_enb_star( uint8_t *k_enb, + uint32_t pci, + uint32_t earfcn, + uint8_t *k_enb_star) +{ + return liblte_security_generate_k_enb_star(k_enb, + pci, + earfcn, + k_enb_star); +} + +uint8_t security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh) +{ + return liblte_security_generate_nh( k_asme, + sync, + nh); +} + uint8_t security_generate_k_nas( uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, @@ -146,6 +166,46 @@ uint8_t security_128_eia2( uint8_t *key, mac); } +/****************************************************************************** + * Encryption / Decryption + *****************************************************************************/ + +uint8_t security_128_eea1(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out){ + + return liblte_security_encryption_eea1(key, + count, + bearer, + direction, + msg, + msg_len * 8, + msg_out); + +} + + +uint8_t security_128_eea2(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out){ + + return liblte_security_encryption_eea2(key, + count, + bearer, + direction, + msg, + msg_len * 8, + msg_out); +} + /****************************************************************************** * Authentication *****************************************************************************/ diff --git a/lib/src/common/tti_sync_cv.cc b/lib/src/common/tti_sync_cv.cc index a3fc7ce4b..c48f0772a 100644 --- a/lib/src/common/tti_sync_cv.cc +++ b/lib/src/common/tti_sync_cv.cc @@ -75,4 +75,11 @@ namespace srslte { pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); } + void tti_sync_cv::increase(uint32_t tti) + { + pthread_mutex_lock(&mutex); + increase_producer(tti); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } } diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index e04d30e69..35122958d 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -434,10 +434,10 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) uint32_t l; float rssi = 0; - uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); for (l=0;lcell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE]; - rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE); + rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE); } return rssi/nsymbols; } @@ -495,7 +495,9 @@ 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 */ - q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + float energy = cabsf(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots); + q->rsrp[rxant_id][port_id] = energy*energy; if (port_id == 0) { /* compute rssi only for port 0 */ q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); diff --git a/lib/src/phy/dft/ofdm.c b/lib/src/phy/dft/ofdm.c index 8ea690bb5..e266023bb 100644 --- a/lib/src/phy/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -380,15 +380,8 @@ void srslte_ofdm_tx_free(srslte_ofdm_t *q) { srslte_ofdm_free_(q); } -/* Transforms input samples into output OFDM symbols. - * Performs FFT on a each symbol and removes CP. - */ -void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) { - cf_t *output = q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols; - -#ifdef AVOID_GURU +void srslte_ofdm_rx_slot_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) { uint32_t i; - cf_t *input = q->in_buffer + slot_in_sf * q->slot_sz; for (i=0;inof_symbols;i++) { input += SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(i, q->symbol_sz):SRSLTE_CP_LEN_EXT(q->symbol_sz); srslte_dft_run_c(&q->fft_plan, input, q->tmp); @@ -396,6 +389,16 @@ void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) { input += q->symbol_sz; output += q->nof_re; } +} + +/* Transforms input samples into output OFDM symbols. + * Performs FFT on a each symbol and removes CP. + */ +void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) { + cf_t *output = q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols; + +#ifdef AVOID_GURU + srslte_ofdm_rx_slot_ng(q, q->in_buffer + slot_in_sf * q->slot_sz, q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols); #else float norm = 1.0f/sqrtf(q->fft_plan.size); cf_t *tmp = q->tmp + slot_in_sf * q->symbol_sz * q->nof_symbols; @@ -462,6 +465,22 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q) { } } +void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) { + uint32_t n; + if (q->freq_shift) { + srslte_vec_prod_ccc(q->in_buffer, q->shift_buffer, q->in_buffer, 2*q->slot_sz); + } + if(!q->mbsfn_subframe){ + for (n=0;n<2;n++) { + srslte_ofdm_rx_slot_ng(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + } + } + else{ + srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0*q->slot_sz], &q->out_buffer[0*q->nof_re*q->nof_symbols]); + srslte_ofdm_rx_slot(q, 1); + } +} + /* Transforms input OFDM symbols into output samples. * Performs FFT on a each symbol and adds CP. */ diff --git a/lib/src/phy/fec/rm_turbo.c b/lib/src/phy/fec/rm_turbo.c index cdc8ac88d..b1cc95a8c 100644 --- a/lib/src/phy/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -61,7 +61,9 @@ static uint8_t RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, /* Align tables to 16-byte boundary */ static uint16_t interleaver_systematic_bits[192][6160]; // 4 tail bits +static srslte_bit_interleaver_t bit_interleavers_systematic_bits[192]; static uint16_t interleaver_parity_bits[192][2*6160]; +static srslte_bit_interleaver_t bit_interleavers_parity_bits[192]; static uint16_t deinterleaver[192][4][18448]; static int k0_vec[SRSLTE_NOF_TC_CB_SIZES][4][2]; static bool rm_turbo_tables_generated = false; @@ -235,7 +237,12 @@ void srslte_rm_turbo_gentables() { k0_vec[cb_idx][i][1] = -1; } srslte_rm_turbo_gentable_systematic(interleaver_systematic_bits[cb_idx], k0_vec[cb_idx], nrows, ndummy); + srslte_bit_interleaver_init(&bit_interleavers_systematic_bits[cb_idx], interleaver_systematic_bits[cb_idx], + (uint32_t) srslte_cbsegm_cbsize(cb_idx)+4); + srslte_rm_turbo_gentable_parity(interleaver_parity_bits[cb_idx], k0_vec[cb_idx], in_len/3, nrows, ndummy); + srslte_bit_interleaver_init(&bit_interleavers_parity_bits[cb_idx], interleaver_parity_bits[cb_idx], + (uint32_t) (srslte_cbsegm_cbsize(cb_idx)+4)*2); for (int i=0;i<4;i++) { srslte_rm_turbo_gentable_receive(deinterleaver[cb_idx][i], in_len, i); @@ -244,6 +251,12 @@ void srslte_rm_turbo_gentables() { } } +void srslte_rm_turbo_free_tables () { + for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) { + srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]); + srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]); + } +} /** * Rate matching for LTE Turbo Coder @@ -274,11 +287,13 @@ int srslte_rm_turbo_tx_lut(uint8_t *w_buff, uint8_t *systematic, uint8_t *parity if (rv_idx == 0) { // Systematic bits - srslte_bit_interleave(systematic, w_buff, interleaver_systematic_bits[cb_idx], in_len/3); + //srslte_bit_interleave(systematic, w_buff, interleaver_systematic_bits[cb_idx], in_len/3); + srslte_bit_interleaver_run(&bit_interleavers_systematic_bits[cb_idx], systematic, w_buff, 0); // Parity bits - srslte_bit_interleave_w_offset(parity, &w_buff[in_len/24], interleaver_parity_bits[cb_idx], 2*in_len/3, 4); + //srslte_bit_interleave_w_offset(parity, &w_buff[in_len/24], interleaver_parity_bits[cb_idx], 2*in_len/3, 4); + srslte_bit_interleaver_run(&bit_interleavers_parity_bits[cb_idx], parity, &w_buff[in_len/24], 4); } /* Bit selection and transmission 5.1.4.1.2 */ diff --git a/lib/src/phy/fec/test/rm_turbo_test.c b/lib/src/phy/fec/test/rm_turbo_test.c index 6943c72d1..1c5b2abf5 100644 --- a/lib/src/phy/fec/test/rm_turbo_test.c +++ b/lib/src/phy/fec/test/rm_turbo_test.c @@ -197,6 +197,7 @@ int main(int argc, char **argv) { } } + srslte_rm_turbo_free_tables(); free(rm_bits); free(rm_bits2); free(rm_bits2_bytes); diff --git a/lib/src/phy/fec/turbocoder.c b/lib/src/phy/fec/turbocoder.c index b7785980c..64f05b5e8 100644 --- a/lib/src/phy/fec/turbocoder.c +++ b/lib/src/phy/fec/turbocoder.c @@ -43,6 +43,7 @@ uint8_t tcod_lut_next_state[188][8][256]; uint8_t tcod_lut_output[188][8][256]; uint16_t tcod_per_fw[188][6144]; +static srslte_bit_interleaver_t tcod_interleavers[188]; static bool table_initiated = false; @@ -63,6 +64,9 @@ void srslte_tcod_free(srslte_tcod_t *h) { if (h->temp) { free(h->temp); } + for (int i = 0; i < 188; i++) { + srslte_bit_interleaver_free(&tcod_interleavers[i]); + } } /* Expects bits (1 byte = 1 bit) and produces bits. The systematic and parity bits are interlaced in the output */ @@ -198,8 +202,9 @@ int srslte_tcod_encode_lut(srslte_tcod_t *h, uint8_t *input, uint8_t *parity, ui } parity[long_cb/8] = 0; // will put tail here later - /* Interleave input */ - srslte_bit_interleave(input, h->temp, tcod_per_fw[cblen_idx], long_cb); + /* Interleave input */ + srslte_bit_interleaver_run(&tcod_interleavers[cblen_idx], input, h->temp, 0); + //srslte_bit_interleave(input, h->temp, tcod_per_fw[cblen_idx], long_cb); /* Parity bits for the 2nd constituent encoders */ uint8_t state1 = 0; @@ -297,6 +302,7 @@ void srslte_tcod_gentable() { for (uint32_t i=0;icb_in) { free(q->cb_in); } diff --git a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c index 0faf7eca1..ba662bc49 100644 --- a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c @@ -182,7 +182,7 @@ int main(int argc, char **argv) { srslte_filesource_read(&fsrc, input_buffer[0], flen); INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); - ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, 0, sf_idx, acks); + ret = srslte_ue_dl_decode(&ue_dl, data, 0, sf_idx, acks); if(ret > 0) { printf("PDSCH Decoded OK!\n"); } else if (ret == 0) { diff --git a/lib/src/phy/phch/test/pmch_file_test.c b/lib/src/phy/phch/test/pmch_file_test.c index 6586b2ee9..1d0715caa 100644 --- a/lib/src/phy/phch/test/pmch_file_test.c +++ b/lib/src/phy/phch/test/pmch_file_test.c @@ -187,7 +187,7 @@ int main(int argc, char **argv) { srslte_filesource_read(&fsrc, input_buffer[0], flen); INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); - ret = srslte_ue_dl_decode_mbsfn(&ue_dl, input_buffer, data[0], sf_idx); + ret = srslte_ue_dl_decode_mbsfn(&ue_dl, data[0], sf_idx); if(ret > 0) { printf("PMCH Decoded OK!\n"); } else if (ret < 0) { diff --git a/lib/src/phy/phch/test/prach_test_usrp.c b/lib/src/phy/phch/test/prach_test_usrp.c index c0fae365c..c4edc343d 100644 --- a/lib/src/phy/phch/test/prach_test_usrp.c +++ b/lib/src/phy/phch/test/prach_test_usrp.c @@ -199,7 +199,7 @@ int main(int argc, char **argv) { srslte_timestamp_t tstamp; - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); uint32_t nframe=0; while(nframedev)->srslte_rf_rx_wait_lo_locked(rf->handler); } -int srslte_rf_start_rx_stream(srslte_rf_t *rf) +int srslte_rf_start_rx_stream(srslte_rf_t *rf, bool now) { - return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler); + return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler, now); } int srslte_rf_stop_rx_stream(srslte_rf_t *rf) diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 90ede26e9..83f5c3a23 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -115,7 +115,7 @@ void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal) } -int rf_soapy_start_rx_stream(void *h) +int rf_soapy_start_rx_stream(void *h, bool now) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; if(handler->rx_stream_active == false){ diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 5dd1c6c44..4974157d1 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -45,7 +45,7 @@ SRSLTE_API void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal); -SRSLTE_API int rf_soapy_start_rx_stream(void *h); +SRSLTE_API int rf_soapy_start_rx_stream(void *h, bool now); SRSLTE_API int rf_soapy_stop_rx_stream(void *h); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 9ed9e5501..75482eaa1 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -219,21 +219,23 @@ void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal) } -int rf_uhd_start_rx_stream(void *h) +int rf_uhd_start_rx_stream(void *h, bool now) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; uhd_stream_cmd_t stream_cmd = { .stream_mode = UHD_STREAM_MODE_START_CONTINUOUS, - .stream_now = false + .stream_now = now }; - uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); - stream_cmd.time_spec_frac_secs += 0.1; - if (stream_cmd.time_spec_frac_secs > 1) { - stream_cmd.time_spec_frac_secs -= 1; - stream_cmd.time_spec_full_secs += 1; + if (!now) { + uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); + stream_cmd.time_spec_frac_secs += 0.1; + if (stream_cmd.time_spec_frac_secs > 1) { + stream_cmd.time_spec_frac_secs -= 1; + stream_cmd.time_spec_full_secs += 1; + } } - uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); + uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); return 0; } @@ -788,7 +790,7 @@ int rf_uhd_send_timed_multi(void *h, int n = 0; cf_t *data_c[4]; for (int i = 0; i < 4; i++) { - data_c[i] = data[i]; + data_c[i] = data[i] ? data[i] : zero_mem; } do { size_t tx_samples = handler->tx_nof_samples; diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index 2be799333..e3555fab3 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -49,7 +49,8 @@ SRSLTE_API void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal); -SRSLTE_API int rf_uhd_start_rx_stream(void *h); +SRSLTE_API int rf_uhd_start_rx_stream(void *h, + bool now); SRSLTE_API int rf_uhd_start_rx_stream_nsamples(void *h, uint32_t nsamples); diff --git a/lib/src/phy/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c index f97784305..892ad817e 100644 --- a/lib/src/phy/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -60,7 +60,7 @@ int rf_rssi_scan(srslte_rf_t *rf, float *freqs, float *rssi, int nof_bands, doub srslte_rf_set_rx_freq(rf, f); srslte_rf_rx_wait_lo_locked(rf); usleep(10000); - srslte_rf_start_rx_stream(rf); + srslte_rf_start_rx_stream(rf, false); /* discard first samples */ for (j=0;j<2;j++) { @@ -122,7 +122,7 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * srslte_rf_set_rx_srate(rf, (float) srate); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(rf); + srslte_rf_start_rx_stream(rf, false); /* Find and decody MIB */ ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pbch, bch_payload, &cell->nof_ports, NULL); @@ -179,7 +179,7 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, srslte_rf_set_rx_srate(rf, SRSLTE_CS_SAMP_FREQ); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(rf); + srslte_rf_start_rx_stream(rf, false); /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ uint32_t max_peak_cell = 0; diff --git a/lib/src/phy/sync/find_sss.c b/lib/src/phy/sync/find_sss.c index 70b300bd3..6695d70c2 100644 --- a/lib/src/phy/sync/find_sss.c +++ b/lib/src/phy/sync/find_sss.c @@ -68,7 +68,7 @@ static void corr_all_sz_partial(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSL } } -static void extract_pair_sss(srslte_sss_synch_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { +static void extract_pair_sss(srslte_sss_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; srslte_dft_run_c(&q->dftp_input, input, input_fft); @@ -88,10 +88,10 @@ static void extract_pair_sss(srslte_sss_synch_t *q, const cf_t *input, cf_t *ce, } -int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, const cf_t *input, uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_diff(srslte_sss_t *q, const cf_t *input, uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { - return srslte_sss_synch_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value); + return srslte_sss_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value); } /* Differential SSS estimation. @@ -102,7 +102,7 @@ int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, const cf_t *input, uint32_ * */ -int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_diff_coh(srslte_sss_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { @@ -145,7 +145,7 @@ int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, const cf_t *input, cf_ * Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi */ -int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_partial(srslte_sss_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index d93fe0896..1f56dfda9 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -35,7 +35,7 @@ #include "srslte/phy/utils/debug.h" -int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, +int srslte_pss_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, uint32_t N_id_2, uint32_t fft_size, int cfo_i) { srslte_dft_plan_t plan; cf_t pss_signal_pad[2048]; @@ -73,16 +73,16 @@ int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, /* Initializes the PSS synchronization object with fft_size=128 */ -int srslte_pss_synch_init(srslte_pss_synch_t *q, uint32_t frame_size) { - return srslte_pss_synch_init_fft(q, frame_size, 128); +int srslte_pss_init(srslte_pss_t *q, uint32_t frame_size) { + return srslte_pss_init_fft(q, frame_size, 128); } -int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { - return srslte_pss_synch_init_fft_offset(q, frame_size, fft_size, 0); +int srslte_pss_init_fft(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size) { + return srslte_pss_init_fft_offset(q, frame_size, fft_size, 0); } -int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { - return srslte_pss_synch_init_fft_offset_decim(q, frame_size, fft_size, offset, 1); +int srslte_pss_init_fft_offset(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { + return srslte_pss_init_fft_offset_decim(q, frame_size, fft_size, offset, 1); } /* Initializes the PSS synchronization object. @@ -90,7 +90,7 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, +int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, uint32_t max_frame_size, uint32_t max_fft_size, int offset, int decimate) { @@ -102,7 +102,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, uint32_t N_id_2; uint32_t buffer_size; - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_t)); q->N_id_2 = 10; q->ema_alpha = 0.2; @@ -143,7 +143,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } srslte_dft_plan_set_mirror(&q->idftp_input, true); srslte_dft_plan_set_dc(&q->idftp_input, true); - srslte_dft_plan_set_norm(&q->idftp_input, true); + srslte_dft_plan_set_norm(&q->idftp_input, false); bzero(q->tmp_fft2, sizeof(cf_t)*SRSLTE_SYMBOL_SZ_MAX); @@ -183,7 +183,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, goto clean_and_exit; } /* The PSS is translated into the time domain for each N_id_2 */ - if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { + if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); goto clean_and_exit; } @@ -192,27 +192,25 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, #ifdef CONVOLUTION_FFT - for(N_id_2=0; N_id_2<3; N_id_2++) - q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); - if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { fprintf(stderr, "Error initiating convolution FFT\n"); goto clean_and_exit; } - for(int i=0; i<3; i++) { - srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); + for(N_id_2=0; N_id_2<3; N_id_2++) { + q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); + srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[N_id_2], q->pss_signal_freq_full[N_id_2]); } #endif - srslte_pss_synch_reset(q); + srslte_pss_reset(q); ret = SRSLTE_SUCCESS; } clean_and_exit: if (ret == SRSLTE_ERROR) { - srslte_pss_synch_free(q); + srslte_pss_free(q); } return ret; @@ -224,7 +222,7 @@ clean_and_exit: * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { +int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -233,7 +231,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t ret = SRSLTE_ERROR; if (fft_size > q->max_fft_size || frame_size > q->max_frame_size) { - fprintf(stderr, "Error in pss_synch_config(): fft_size and frame_size must be lower than initialized\n"); + fprintf(stderr, "Error in pss_config(): fft_size and frame_size must be lower than initialized\n"); return SRSLTE_ERROR; } @@ -273,7 +271,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t // Generate PSS sequences for this FFT size for (N_id_2=0;N_id_2<3;N_id_2++) { - if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { + if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); return SRSLTE_ERROR; } @@ -291,7 +289,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t #endif - srslte_pss_synch_reset(q); + srslte_pss_reset(q); ret = SRSLTE_SUCCESS; } @@ -299,7 +297,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t } -void srslte_pss_synch_free(srslte_pss_synch_t *q) { +void srslte_pss_free(srslte_pss_t *q) { uint32_t i; if (q) { @@ -339,11 +337,11 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_t)); } } -void srslte_pss_synch_reset(srslte_pss_synch_t *q) { +void srslte_pss_reset(srslte_pss_t *q) { uint32_t buffer_size = q->fft_size + q->frame_size + 1; bzero(q->conv_output_avg, sizeof(float) * buffer_size); } @@ -401,7 +399,7 @@ void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_ /** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise */ -int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { +int srslte_pss_set_N_id_2(srslte_pss_t *q, uint32_t N_id_2) { if (!srslte_N_id_2_isvalid((N_id_2))) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; @@ -413,11 +411,11 @@ int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { /* Sets the weight factor alpha for the exponential moving average of the PSS correlation output */ -void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { +void srslte_pss_set_ema_alpha(srslte_pss_t *q, float alpha) { q->ema_alpha = alpha; } -float compute_peak_sidelobe(srslte_pss_synch_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len) +float compute_peak_sidelobe(srslte_pss_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len) { // Find end of peak lobe to the right int pl_ub = corr_peak_pos+1; @@ -455,7 +453,7 @@ float compute_peak_sidelobe(srslte_pss_synch_t *q, uint32_t corr_peak_pos, uint3 * * Input buffer must be subframe_size long. */ -int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *corr_peak_value) +int srslte_pss_find_pss(srslte_pss_t *q, const cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -474,7 +472,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *c /* Correlate input with PSS sequence * * We do not reverse time-domain PSS signal because it's conjugate is symmetric. - * The conjugate operation on pss_signal_time has been done in srslte_pss_synch_init_N_id_2 + * The conjugate operation on pss_signal_time has been done in srslte_pss_init_N_id_2 * This is why we can use FFT-based convolution */ if (q->frame_size >= q->fft_size) { @@ -545,9 +543,8 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *c * input signal is in the time-domain. * ce is the returned frequency-domain channel estimates. */ -int srslte_pss_synch_chest(srslte_pss_synch_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { +int srslte_pss_chest(srslte_pss_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; if (q != NULL && input != NULL) @@ -559,18 +556,41 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, const cf_t *input, cf_t ce[SRS } /* Transform to frequency-domain */ - srslte_dft_run_c(&q->dftp_input, input, input_fft); + srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); /* Compute channel estimate taking the PSS sequence as reference */ - srslte_vec_prod_conj_ccc(&input_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); + srslte_vec_prod_conj_ccc(&q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); ret = SRSLTE_SUCCESS; } return ret; } +/* input points to beginning of last OFDM symbol of slot 0 of subframe 0 or 5 + * It must be called after calling srslte_pss_cfo_compute() with filter enabled + */ +void srslte_pss_sic(srslte_pss_t *q, cf_t *input) { + if (q->chest_on_filter) { + + bzero(q->tmp_fft, sizeof(cf_t)*q->fft_size); + + // Pass transmitted PSS sequence through the channel + srslte_vec_prod_ccc(q->pss_signal_freq[q->N_id_2], q->tmp_ce, &q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], SRSLTE_PSS_LEN); + + // Get time-domain version of the received PSS + srslte_dft_run_c(&q->idftp_input, q->tmp_fft, q->tmp_fft2); + + // Substract received PSS from this N_id_2 from the input signal + srslte_vec_sc_prod_cfc(q->tmp_fft2, 1.0/q->fft_size, q->tmp_fft2, q->fft_size); + srslte_vec_sub_ccc(input, q->tmp_fft2, input, q->fft_size); + + } else { + fprintf(stderr, "Error calling srslte_pss_sic(): need to enable channel estimation on filtering\n"); + } +} + // Frequency-domain filtering of the central 64 sub-carriers -void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *output) +void srslte_pss_filter(srslte_pss_t *q, const cf_t *input, cf_t *output) { srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); @@ -578,6 +598,10 @@ void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *out &q->tmp_fft[q->fft_size/2-SRSLTE_PSS_LEN/2], sizeof(cf_t)*SRSLTE_PSS_LEN); + if (q->chest_on_filter) { + srslte_vec_prod_conj_ccc(&q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], q->tmp_ce, SRSLTE_PSS_LEN); + } + srslte_dft_run_c(&q->idftp_input, q->tmp_fft2, output); } @@ -586,13 +610,13 @@ void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *out * Source: An Efficient CFO Estimation Algorithm for the Downlink of 3GPP-LTE * Feng Wang and Yu Zhu */ -float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, const cf_t *pss_recv) { +float srslte_pss_cfo_compute(srslte_pss_t* q, const cf_t *pss_recv) { cf_t y0, y1; const cf_t *pss_ptr = pss_recv; if (q->filter_pss_enable) { - srslte_pss_synch_filter(q, pss_recv, q->tmp_fft); + srslte_pss_filter(q, pss_recv, q->tmp_fft); pss_ptr = (const cf_t*) q->tmp_fft; } diff --git a/lib/src/phy/sync/sss.c b/lib/src/phy/sync/sss.c index 4ed7b1d6c..31091bdb3 100644 --- a/lib/src/phy/sync/sss.c +++ b/lib/src/phy/sync/sss.c @@ -40,7 +40,7 @@ void generate_sss_all_tables(srslte_sss_tables_t *tables, uint32_t N_id_2); void convert_tables(srslte_sss_fc_tables_t *fc_tables, srslte_sss_tables_t *in); void generate_N_id_1_table(uint32_t table[30][30]); -int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { +int srslte_sss_init(srslte_sss_t *q, uint32_t fft_size) { if (q != NULL && fft_size <= 2048) @@ -48,10 +48,10 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { uint32_t N_id_2; srslte_sss_tables_t sss_tables; - bzero(q, sizeof(srslte_sss_synch_t)); + bzero(q, sizeof(srslte_sss_t)); if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { - srslte_sss_synch_free(q); + srslte_sss_free(q); return SRSLTE_ERROR; } srslte_dft_plan_set_mirror(&q->dftp_input, true); @@ -72,7 +72,7 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR_INVALID_INPUTS; } -int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { +int srslte_sss_resize(srslte_sss_t *q, uint32_t fft_size) { if (q != NULL && fft_size <= 2048) { @@ -81,7 +81,7 @@ int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR; } if (srslte_dft_replan(&q->dftp_input, fft_size)) { - srslte_sss_synch_free(q); + srslte_sss_free(q); return SRSLTE_ERROR; } q->fft_size = fft_size; @@ -90,13 +90,13 @@ int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR_INVALID_INPUTS; } -void srslte_sss_synch_free(srslte_sss_synch_t *q) { +void srslte_sss_free(srslte_sss_t *q) { srslte_dft_plan_free(&q->dftp_input); - bzero(q, sizeof(srslte_sss_synch_t)); + bzero(q, sizeof(srslte_sss_t)); } /** Sets the N_id_2 to search for */ -int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, uint32_t N_id_2) { +int srslte_sss_set_N_id_2(srslte_sss_t *q, uint32_t N_id_2) { if (!srslte_N_id_2_isvalid(N_id_2)) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return SRSLTE_ERROR; @@ -124,12 +124,12 @@ void srslte_sss_put_slot(float *sss, cf_t *slot, uint32_t nof_prb, srslte_cp_t c } /** Sets the SSS correlation peak detection threshold */ -void srslte_sss_synch_set_threshold(srslte_sss_synch_t *q, float threshold) { +void srslte_sss_set_threshold(srslte_sss_t *q, float threshold) { q->corr_peak_threshold = threshold; } /** Returns the subframe index based on the m0 and m1 values */ -uint32_t srslte_sss_synch_subframe(uint32_t m0, uint32_t m1) { +uint32_t srslte_sss_subframe(uint32_t m0, uint32_t m1) { if (m1 > m0) { return 0; } else { @@ -138,7 +138,7 @@ uint32_t srslte_sss_synch_subframe(uint32_t m0, uint32_t m1) { } /** Returns the N_id_1 value based on the m0 and m1 values */ -int srslte_sss_synch_N_id_1(srslte_sss_synch_t *q, uint32_t m0, uint32_t m1) { +int srslte_sss_N_id_1(srslte_sss_t *q, uint32_t m0, uint32_t m1) { int N_id_1 = -1; if (m1 > m0) { if (m0 < 30 && m1 - 1 < 30) { diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index bc9d27c19..8b7bbd69c 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -42,6 +42,8 @@ #define DEFAULT_CFO_TOL 0.0 // Hz +#define MAX_CFO_PSS_OFFSET 7000 + static bool fft_size_isvalid(uint32_t fft_size) { if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) { return true; @@ -60,7 +62,6 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && - frame_size <= 307200 && fft_size_isvalid(fft_size)) { ret = SRSLTE_ERROR; @@ -78,7 +79,6 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o q->cfo_cp_enable = false; q->cfo_i_initiated = false; q->pss_filtering_enabled = false; - q->sss_filtering_enabled = false; q->fft_size = fft_size; q->frame_size = frame_size; @@ -120,11 +120,11 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o decimate = 1; } - if (srslte_pss_synch_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { + if (srslte_pss_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { fprintf(stderr, "Error initializing PSS object\n"); goto clean_exit; } - if (srslte_sss_synch_init(&q->sss, fft_size)) { + if (srslte_sss_init(&q->sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); goto clean_exit; } @@ -152,8 +152,8 @@ void srslte_sync_free(srslte_sync_t *q) { if (q) { - srslte_pss_synch_free(&q->pss); - srslte_sss_synch_free(&q->sss); + srslte_pss_free(&q->pss); + srslte_sss_free(&q->sss); srslte_cfo_free(&q->cfo_corr_frame); srslte_cfo_free(&q->cfo_corr_symbol); srslte_cp_synch_free(&q->cp_synch); @@ -163,7 +163,7 @@ void srslte_sync_free(srslte_sync_t *q) if (q->cfo_i_corr[i]) { free(q->cfo_i_corr[i]); } - srslte_pss_synch_free(&q->pss_i[i]); + srslte_pss_free(&q->pss_i[i]); } } if (q->temp) { @@ -189,11 +189,11 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse q->frame_size = frame_size; q->max_offset = max_offset; - if (srslte_pss_synch_resize(&q->pss, q->max_offset, q->fft_size, 0)) { + if (srslte_pss_resize(&q->pss, q->max_offset, q->fft_size, 0)) { fprintf(stderr, "Error resizing PSS object\n"); return SRSLTE_ERROR; } - if (srslte_sss_synch_resize(&q->sss, q->fft_size)) { + if (srslte_sss_resize(&q->sss, q->fft_size)) { fprintf(stderr, "Error resizing SSS object\n"); return SRSLTE_ERROR; } @@ -216,7 +216,7 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse if (q->cfo_i_initiated) { for (int i=0;i<2;i++) { int offset=(i==0)?-1:1; - if (srslte_pss_synch_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + if (srslte_pss_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { fprintf(stderr, "Error initializing PSS object\n"); } for (int t=0;tframe_size;t++) { @@ -303,7 +303,7 @@ void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) { if (q->cfo_i_enable && !q->cfo_i_initiated) { for (int i=0;i<2;i++) { int offset=(i==0)?-1:1; - if (srslte_pss_synch_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + if (srslte_pss_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { fprintf(stderr, "Error initializing PSS object\n"); } for (int t=0;tframe_size;t++) { @@ -314,8 +314,12 @@ void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) { } } -void srslte_sync_set_sss_filt_enable(srslte_sync_t *q, bool enable) { - q->sss_filtering_enabled = enable; +void srslte_sync_set_sss_eq_enable(srslte_sync_t *q, bool enable) { + q->sss_channel_equalize = enable; + if (enable) { + q->pss_filtering_enabled = true; + q->pss.chest_on_filter = true; + } } void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, bool enable) { @@ -344,7 +348,7 @@ void srslte_sync_cp_en(srslte_sync_t *q, bool enabled) { void srslte_sync_set_em_alpha(srslte_sync_t *q, float alpha) { - srslte_pss_synch_set_ema_alpha(&q->pss, alpha); + srslte_pss_set_ema_alpha(&q->pss, alpha); } srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q) @@ -435,22 +439,22 @@ int sync_sss_symbol(srslte_sync_t *q, const cf_t *input) { int ret; - srslte_sss_synch_set_N_id_2(&q->sss, q->N_id_2); + srslte_sss_set_N_id_2(&q->sss, q->N_id_2); switch(q->sss_alg) { case SSS_DIFF: - srslte_sss_synch_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; case SSS_PARTIAL_3: - srslte_sss_synch_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; case SSS_FULL: - srslte_sss_synch_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; } - q->sf_idx = srslte_sss_synch_subframe(q->m0, q->m1); - ret = srslte_sss_synch_N_id_1(&q->sss, q->m0, q->m1); + q->sf_idx = srslte_sss_subframe(q->m0, q->m1); + ret = srslte_sss_N_id_1(&q->sss, q->m0, q->m1); if (ret >= 0) { q->N_id_1 = (uint32_t) ret; DEBUG("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n", @@ -462,9 +466,9 @@ int sync_sss_symbol(srslte_sync_t *q, const cf_t *input) } } -srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) +srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) { - srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; + srslte_pss_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; return pss_obj[q->cfo_i_value+1]; } @@ -482,10 +486,10 @@ static int cfo_i_estimate(srslte_sync_t *q, const cf_t *input, int find_offset, float peak_value; float max_peak_value = -99; int max_cfo_i = 0; - srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; + srslte_pss_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; for (int cfo_i=0;cfo_i<3;cfo_i++) { - srslte_pss_synch_set_N_id_2(pss_obj[cfo_i], q->N_id_2); - int p = srslte_pss_synch_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); + srslte_pss_set_N_id_2(pss_obj[cfo_i], q->N_id_2); + int p = srslte_pss_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); if (p < 0) { return -1; } @@ -575,8 +579,8 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin /* Find maximum of PSS correlation. If Integer CFO is enabled, correlation is already done */ if (!q->cfo_i_enable) { - srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); - peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL); + srslte_pss_set_N_id_2(&q->pss, q->N_id_2); + peak_pos = srslte_pss_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL); if (peak_pos < 0) { fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); return SRSLTE_ERROR; @@ -603,16 +607,16 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin // Filter central bands before PSS-based CFO estimation const cf_t *pss_ptr = &input_ptr[find_offset + peak_pos - q->fft_size]; if (q->pss_filtering_enabled) { - srslte_pss_synch_filter(&q->pss, pss_ptr, q->pss_filt); + srslte_pss_filter(&q->pss, pss_ptr, q->pss_filt); pss_ptr = q->pss_filt; } // PSS-based CFO estimation - float cfo_pss = srslte_pss_synch_cfo_compute(&q->pss, pss_ptr); + float cfo_pss = srslte_pss_cfo_compute(&q->pss, pss_ptr); if (!q->cfo_pss_is_set) { q->cfo_pss_mean = cfo_pss; q->cfo_pss_is_set = true; - } else { + } else if (15000*fabsf(cfo_pss) < MAX_CFO_PSS_OFFSET) { q->cfo_pss_mean = SRSLTE_VEC_EMA(cfo_pss, q->cfo_pss_mean, q->cfo_ema_alpha); } @@ -621,7 +625,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin } - // If there is enough space for CP and PSS-based CFO estimation + // If there is enough space for CP and SSS estimation if (peak_pos + find_offset >= 2 * (q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { // If SSS search is enabled, correlate SSS sequence @@ -638,12 +642,11 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin // Correct CFO if detected in PSS if (q->cfo_pss_enable) { srslte_cfo_correct(&q->cfo_corr_symbol, sss_ptr, q->sss_filt, -q->cfo_pss_mean / q->fft_size); - sss_ptr = q->sss_filt; - } - - // Filter central bands before SSS estimation - if (q->sss_filtering_enabled) { - srslte_pss_synch_filter(&q->pss, sss_ptr, q->sss_filt); + // Equalize channel if estimated in PSS + if (q->sss_channel_equalize && q->pss.chest_on_filter && q->pss_filtering_enabled) { + srslte_vec_prod_ccc(&q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], q->pss.tmp_ce, + &q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], SRSLTE_PSS_LEN); + } sss_ptr = q->sss_filt; } @@ -682,5 +685,5 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin void srslte_sync_reset(srslte_sync_t *q) { q->M_ext_avg = 0; q->M_norm_avg = 0; - srslte_pss_synch_reset(&q->pss); + srslte_pss_reset(&q->pss); } diff --git a/lib/src/phy/sync/test/pss_file.c b/lib/src/phy/sync/test/pss_file.c index 7f70ad8ff..4087366ec 100644 --- a/lib/src/phy/sync/test/pss_file.c +++ b/lib/src/phy/sync/test/pss_file.c @@ -121,9 +121,9 @@ int main(int argc, char **argv) { srslte_filesource_t fsrc; cf_t *buffer; int frame_cnt, n; - srslte_pss_synch_t pss; + srslte_pss_t pss; srslte_cfo_t cfocorr, cfocorr64; - srslte_sss_synch_t sss; + srslte_sss_t sss; int32_t flen; int peak_idx, last_peak; float peak_value; @@ -152,12 +152,12 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { + if (srslte_pss_init_fft(&pss, flen, fft_size)) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { + if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) { fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); exit(-1); } @@ -165,12 +165,12 @@ int main(int argc, char **argv) { srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr64, flen); - if (srslte_sss_synch_init(&sss, fft_size)) { + if (srslte_sss_init(&sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); return SRSLTE_ERROR; } - srslte_sss_synch_set_N_id_2(&sss, N_id_2); + srslte_sss_set_N_id_2(&sss, N_id_2); printf("Opening file...\n"); if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { @@ -210,7 +210,7 @@ int main(int argc, char **argv) { break; } - peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); + peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value); if (peak_idx < 0) { fprintf(stderr, "Error finding PSS peak\n"); exit(-1); @@ -224,14 +224,14 @@ int main(int argc, char **argv) { if (peak_idx >= fft_size) { // Estimate CFO - cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); + cfo = srslte_pss_cfo_compute(&pss, &buffer[peak_idx-fft_size]); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); // Correct CFO srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); // Estimate channel - if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { + if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) { fprintf(stderr, "Error computing channel estimation\n"); exit(-1); } @@ -239,22 +239,22 @@ int main(int argc, char **argv) { // Find SSS int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); if (sss_idx >= 0 && sss_idx < flen-fft_size) { - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error2++; } - INFO("sf_idx = %d\n", srslte_sss_synch_subframe(m0, m1)); - INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("sf_idx = %d\n", srslte_sss_subframe(m0, m1)); + INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error3++; } - INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error1++; } - INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); + INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); } // Estimate CP @@ -269,7 +269,7 @@ int main(int argc, char **argv) { INFO("No space for CFO computation. Frame starts at \n",peak_idx); } - if(srslte_sss_synch_subframe(m0,m1) == 0) + if(srslte_sss_subframe(m0,m1) == 0) { #ifndef DISABLE_GRAPHICS if (!disable_plots) @@ -317,7 +317,7 @@ int main(int argc, char **argv) { } - srslte_pss_synch_free(&pss); + srslte_pss_free(&pss); free(buffer); srslte_filesource_free(&fsrc); #ifndef DISABLE_GRAPHICS diff --git a/lib/src/phy/sync/test/pss_mex.c b/lib/src/phy/sync/test/pss_mex.c index 77922a020..59cc0a897 100644 --- a/lib/src/phy/sync/test/pss_mex.c +++ b/lib/src/phy/sync/test/pss_mex.c @@ -47,7 +47,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { srslte_cell_t cell; - srslte_pss_synch_t pss; + srslte_pss_t pss; cf_t *input_symbols; int frame_len; @@ -74,17 +74,17 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) frame_len = (int) mxGetScalar(prhs[NOF_INPUTS]); } - if (srslte_pss_synch_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) { + if (srslte_pss_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, cell.id%3)) { + if (srslte_pss_set_N_id_2(&pss, cell.id%3)) { fprintf(stderr, "Error setting N_id_2=%d\n",cell.id%3); exit(-1); } - srslte_pss_synch_set_ema_alpha(&pss, 1.0); + srslte_pss_set_ema_alpha(&pss, 1.0); - int peak_idx = srslte_pss_synch_find_pss(&pss, input_symbols, NULL); + int peak_idx = srslte_pss_find_pss(&pss, input_symbols, NULL); if (nlhs >= 1) { plhs[0] = mxCreateDoubleScalar(peak_idx); @@ -93,7 +93,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexutils_write_cf(pss.conv_output, &plhs[1], frame_len, 1); } - srslte_pss_synch_free(&pss); + srslte_pss_free(&pss); free(input_symbols); return; diff --git a/lib/src/phy/sync/test/pss_usrp.c b/lib/src/phy/sync/test/pss_usrp.c index 7c22652f7..70881f15b 100644 --- a/lib/src/phy/sync/test/pss_usrp.c +++ b/lib/src/phy/sync/test/pss_usrp.c @@ -125,9 +125,9 @@ int main(int argc, char **argv) { cf_t *buffer; int frame_cnt, n; srslte_rf_t rf; - srslte_pss_synch_t pss; + srslte_pss_t pss; srslte_cfo_t cfocorr, cfocorr64; - srslte_sss_synch_t sss; + srslte_sss_t sss; int32_t flen; int peak_idx, last_peak; float peak_value; @@ -176,12 +176,12 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { + if (srslte_pss_init_fft(&pss, flen, fft_size)) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { + if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) { fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); exit(-1); } @@ -189,16 +189,16 @@ int main(int argc, char **argv) { srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr64, flen); - if (srslte_sss_synch_init(&sss, fft_size)) { + if (srslte_sss_init(&sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); exit(-1); } - srslte_sss_synch_set_N_id_2(&sss, N_id_2); + srslte_sss_set_N_id_2(&sss, N_id_2); printf("N_id_2: %d\n", N_id_2); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); printf("Frame length %d samples\n", flen); printf("PSS detection threshold: %.2f\n", threshold); @@ -232,7 +232,7 @@ int main(int argc, char **argv) { exit(-1); } - peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); + peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value); if (peak_idx < 0) { fprintf(stderr, "Error finding PSS peak\n"); exit(-1); @@ -246,14 +246,14 @@ int main(int argc, char **argv) { if (peak_idx >= fft_size) { // Estimate CFO - cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); + cfo = srslte_pss_cfo_compute(&pss, &buffer[peak_idx-fft_size]); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); // Correct CFO srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); // Estimate channel - if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { + if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) { fprintf(stderr, "Error computing channel estimation\n"); exit(-1); } @@ -263,22 +263,22 @@ int main(int argc, char **argv) { if (sss_idx >= 0 && sss_idx < flen-fft_size) { // Filter SSS - srslte_pss_synch_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]); + srslte_pss_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]); - INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error2++; } - INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error3++; } - INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); + INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); } - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error1++; } @@ -294,7 +294,7 @@ int main(int argc, char **argv) { INFO("No space for CFO computation. Frame starts at \n",peak_idx); } - if(srslte_sss_synch_subframe(m0,m1) == 0) + if(srslte_sss_subframe(m0,m1) == 0) { #ifndef DISABLE_GRAPHICS if (!disable_plots) @@ -358,8 +358,8 @@ int main(int argc, char **argv) { } - srslte_sss_synch_free(&sss); - srslte_pss_synch_free(&pss); + srslte_sss_free(&sss); + srslte_pss_free(&pss); free(buffer); srslte_rf_close(&rf); diff --git a/lib/src/phy/sync/test/sss_mex.c b/lib/src/phy/sync/test/sss_mex.c index 4c92d81ec..56165fe3d 100644 --- a/lib/src/phy/sync/test/sss_mex.c +++ b/lib/src/phy/sync/test/sss_mex.c @@ -50,7 +50,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { srslte_cell_t cell; - srslte_sss_synch_t sss; + srslte_sss_t sss; cf_t *input_symbols; int frame_len; uint32_t m0, m1; @@ -80,12 +80,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } - if (srslte_sss_synch_init(&sss, srslte_symbol_sz(cell.nof_prb))) { + if (srslte_sss_init(&sss, srslte_symbol_sz(cell.nof_prb))) { mexErrMsgTxt("Error initializing SSS object\n"); return; } - srslte_sss_synch_set_N_id_2(&sss, cell.id%3); + srslte_sss_set_N_id_2(&sss, cell.id%3); // Find SSS uint32_t sss_idx = SRSLTE_SLOT_IDX_CPNORM(5,srslte_symbol_sz(cell.nof_prb)); @@ -95,23 +95,23 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } //mexPrintf("SSS begins at %d/%d. Running algorithm %s\n", sss_idx, frame_len, alg); if (!strcmp(alg, "partial")) { - srslte_sss_synch_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); } else if (!strcmp(alg, "diff")) { - srslte_sss_synch_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value); } else if (!strcmp(alg, "full")) { - srslte_sss_synch_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); } else { mexErrMsgTxt("Unsupported algorithm type\n"); return; } - //mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_synch_N_id_1(&sss, m0, m1)); + //mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_N_id_1(&sss, m0, m1)); if (nlhs >= 1) { - plhs[0] = mxCreateDoubleScalar(srslte_sss_synch_N_id_1(&sss, m0, m1)); + plhs[0] = mxCreateDoubleScalar(srslte_sss_N_id_1(&sss, m0, m1)); } if (nlhs >= 2) { - plhs[1] = mxCreateDoubleScalar(srslte_sss_synch_subframe(m0, m1)); + plhs[1] = mxCreateDoubleScalar(srslte_sss_subframe(m0, m1)); } if (nlhs >= 3) { mexutils_write_f(sss.corr_output_m0, &plhs[2], SRSLTE_SSS_N, 1); @@ -119,7 +119,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) if (nlhs >= 4) { mexutils_write_f(sss.corr_output_m1, &plhs[3], SRSLTE_SSS_N, 1); } - srslte_sss_synch_free(&sss); + srslte_sss_free(&sss); free(input_symbols); return; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 5782ff8bf..4183016e0 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -257,7 +257,7 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell) } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + fprintf(stderr, "Invalid cell properties ue_dl: Id=%d, Ports=%d, PRBs=%d\n", cell.id, cell.nof_ports, cell.nof_prb); } return ret; @@ -359,20 +359,20 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { * - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti() * - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti() */ -int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], +int srslte_ue_dl_decode(srslte_ue_dl_t *q, uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { - return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); + return srslte_ue_dl_decode_rnti(q, data, tm, tti, q->current_rnti, acks); } -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){ +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi){ - return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM); + return srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); } -int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) +int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) { - if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { + if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ for (int j=0;jnof_rx_antennas;j++) { @@ -398,6 +398,32 @@ int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE return SRSLTE_ERROR_INVALID_INPUTS; } } + +int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) +{ + if (input && q && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { + + /* Run FFT for all subframe data */ + for (int j=0;jnof_rx_antennas;j++) { + srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]); + + /* Correct SFO multiplying by complex exponential in the time domain */ + if (q->sample_offset) { + int nsym = SRSLTE_CP_NSYMB(q->cell.cp); + for (int i=0;i<2*nsym;i++) { + srslte_cfo_correct(&q->sfo_correct, + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + q->sample_offset / q->fft[j].symbol_sz); + } + } + } + return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) { return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); @@ -468,7 +494,7 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 } } -int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], +int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti, bool acks[SRSLTE_MAX_CODEWORDS]) { srslte_mimo_type_t mimo_type; @@ -479,7 +505,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { return ret; } @@ -621,16 +647,15 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, - cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data, - uint32_t tti) + uint8_t *data, + uint32_t tti) { srslte_ra_dl_grant_t grant; int ret = SRSLTE_ERROR; uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { return ret; } diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index b5d89743f..511cdde2f 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -272,14 +272,14 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, srslte_sync_set_cfo_cp_enable(&q->sfind, true); srslte_sync_set_cfo_pss_enable(&q->sfind, true); srslte_sync_set_pss_filt_enable(&q->sfind, true); - srslte_sync_set_sss_filt_enable(&q->sfind, true); + srslte_sync_set_sss_eq_enable(&q->sfind, false); // During track, we do CFO correction outside the sync object srslte_sync_set_cfo_i_enable(&q->strack, false); srslte_sync_set_cfo_cp_enable(&q->strack, false); srslte_sync_set_cfo_pss_enable(&q->strack, true); srslte_sync_set_pss_filt_enable(&q->strack, true); - srslte_sync_set_sss_filt_enable(&q->strack, false); + srslte_sync_set_sss_eq_enable(&q->strack, false); // FIXME: CP detection not working very well. Not supporting Extended CP right now srslte_sync_cp_en(&q->strack, false); diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 6bf70741e..736fc3470 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -178,7 +178,7 @@ int srslte_ue_ul_set_cell(srslte_ue_ul_t *q, } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + fprintf(stderr, "Invalid cell properties ue_ul: Id=%d, Ports=%d, PRBs=%d\n", cell.id, cell.nof_ports, cell.nof_prb); } return ret; diff --git a/lib/src/phy/utils/bit.c b/lib/src/phy/utils/bit.c index b1ae383a6..809d4c392 100644 --- a/lib/src/phy/utils/bit.c +++ b/lib/src/phy/utils/bit.c @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef LV_HAVE_SSE @@ -38,6 +39,172 @@ #endif /* LV_HAVE_SSE */ #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" + +void srslte_bit_interleaver_init(srslte_bit_interleaver_t *q, + uint16_t *interleaver, + uint32_t nof_bits) { + static const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; + + bzero(q, sizeof(srslte_bit_interleaver_t)); + + q->interleaver = srslte_vec_malloc(sizeof(uint16_t)*nof_bits); + q->byte_idx = srslte_vec_malloc(sizeof(uint16_t)*nof_bits); + q->bit_mask = srslte_vec_malloc(sizeof(uint8_t)*nof_bits); + q->nof_bits = nof_bits; + + for (int i = 0; i < nof_bits; i++) { + uint16_t i_px = interleaver[i]; + q->interleaver[i] = i_px; + q->byte_idx[i] = (uint16_t) (interleaver[i] / 8); + q->bit_mask[i] = (uint8_t) (mask[i_px%8]); + } +} + +void srslte_bit_interleaver_free(srslte_bit_interleaver_t *q) { + if (q->interleaver) { + free(q->interleaver); + } + + if (q->byte_idx) { + free(q->byte_idx); + } + + if (q->bit_mask) { + free(q->bit_mask); + } + + bzero(q, sizeof(srslte_bit_interleaver_t)); +} + +void srslte_bit_interleaver_run(srslte_bit_interleaver_t *q, uint8_t *input, uint8_t *output, uint16_t w_offset) { + static const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; + uint16_t *byte_idx = q->byte_idx; + uint8_t *bit_mask = q->bit_mask; + uint8_t *output_ptr = output; + + uint32_t st=0, w_offset_p=0; + + if (w_offset < 8 && w_offset > 0) { + st=1; + for (uint32_t j=0;j<8-w_offset;j++) { + uint16_t i_p = q->interleaver[j]; + if (input[i_p/8] & mask[i_p%8]) { + output[0] |= mask[j+w_offset]; + } else { + output[0] &= ~(mask[j+w_offset]); + } + } + w_offset_p=8-w_offset; + } + + uint32_t i = st * 8; + + byte_idx += i - w_offset_p; + bit_mask += i - w_offset_p; + output_ptr += st; + +#ifdef LV_HAVE_SSE + for(; i < q->nof_bits - 15; i += 16) { + __m128i in128; + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x7); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x6); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x5); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x4); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x3); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x2); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x1); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x0); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xF); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xE); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xD); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xC); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xB); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xA); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x9); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x8); + + __m128i mask128 = _mm_loadu_si128((__m128i *) bit_mask); + mask128 = _mm_shuffle_epi8(mask128, _mm_set_epi8(0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7)); + + __m128i cmp128 = _mm_cmpeq_epi8(_mm_and_si128(in128, mask128), mask128); + *((uint16_t *) (output_ptr)) = (uint16_t) _mm_movemask_epi8(cmp128); + + bit_mask += 16; + output_ptr += 2; + } + +#endif /* LV_HAVE_SSE */ + + for(; i < q->nof_bits; i += 8) { + uint8_t out0 = (input[*(byte_idx++)] & *(bit_mask++))?mask[0]:(uint8_t)0; + uint8_t out1 = (input[*(byte_idx++)] & *(bit_mask++))?mask[1]:(uint8_t)0; + uint8_t out2 = (input[*(byte_idx++)] & *(bit_mask++))?mask[2]:(uint8_t)0; + uint8_t out3 = (input[*(byte_idx++)] & *(bit_mask++))?mask[3]:(uint8_t)0; + uint8_t out4 = (input[*(byte_idx++)] & *(bit_mask++))?mask[4]:(uint8_t)0; + uint8_t out5 = (input[*(byte_idx++)] & *(bit_mask++))?mask[5]:(uint8_t)0; + uint8_t out6 = (input[*(byte_idx++)] & *(bit_mask++))?mask[6]:(uint8_t)0; + uint8_t out7 = (input[*(byte_idx++)] & *(bit_mask++))?mask[7]:(uint8_t)0; + + *output_ptr = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7; + output_ptr++; + } + + for (uint32_t j=0;jnof_bits%8;j++) { + uint16_t i_p = q->interleaver[(q->nof_bits/8)*8+j-w_offset]; + if (input[i_p/8] & mask[i_p%8]) { + output[q->nof_bits/8] |= mask[j]; + } else { + output[q->nof_bits/8] &= ~(mask[j]); + } + } + for (uint32_t j=0;jinterleaver[(q->nof_bits/8)*8+j-w_offset]; + if (input[i_p/8] & (1<<(7-i_p%8))) { + output[q->nof_bits/8] |= mask[j]; + } else { + output[q->nof_bits/8] &= ~(mask[j]); + } + } + +#if 0 + /* THIS PIECE OF CODE IS FOR CHECKING SIMD BEHAVIOUR. DO NOT ENABLE. */ + uint8_t *output2 = malloc(q->nof_bits/8); + for (i=st;inof_bits/8;i++) { + + uint16_t i_p0 = q->interleaver[i*8+0-w_offset_p]; + uint16_t i_p1 = q->interleaver[i*8+1-w_offset_p]; + uint16_t i_p2 = q->interleaver[i*8+2-w_offset_p]; + uint16_t i_p3 = q->interleaver[i*8+3-w_offset_p]; + uint16_t i_p4 = q->interleaver[i*8+4-w_offset_p]; + uint16_t i_p5 = q->interleaver[i*8+5-w_offset_p]; + uint16_t i_p6 = q->interleaver[i*8+6-w_offset_p]; + uint16_t i_p7 = q->interleaver[i*8+7-w_offset_p]; + + uint8_t out0 = (input[i_p0/8] & mask[i_p0%8])?mask[0]:(uint8_t)0; + uint8_t out1 = (input[i_p1/8] & mask[i_p1%8])?mask[1]:(uint8_t)0; + uint8_t out2 = (input[i_p2/8] & mask[i_p2%8])?mask[2]:(uint8_t)0; + uint8_t out3 = (input[i_p3/8] & mask[i_p3%8])?mask[3]:(uint8_t)0; + uint8_t out4 = (input[i_p4/8] & mask[i_p4%8])?mask[4]:(uint8_t)0; + uint8_t out5 = (input[i_p5/8] & mask[i_p5%8])?mask[5]:(uint8_t)0; + uint8_t out6 = (input[i_p6/8] & mask[i_p6%8])?mask[6]:(uint8_t)0; + uint8_t out7 = (input[i_p7/8] & mask[i_p7%8])?mask[7]:(uint8_t)0; + + output2[i] = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7; + } + + for(i = st; i < q->nof_bits/8; i++) { + if (true || output[i] != output2[i]) { + printf("%05d/%05d %02X %02X\n", i, q->nof_bits/8, output[i], output2[i]); + } + //output[i] = output2[i]; + } + free(output2); +#endif +} + + void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, uint32_t nof_bits) { srslte_bit_interleave_w_offset(input, output, interleaver, nof_bits, 0); @@ -90,7 +257,11 @@ void srslte_bit_interleave_w_offset(uint8_t *input, uint8_t *output, uint16_t *i epx2.m128 = _mm_shuffle_epi8(ipx2.m128, _mm_set_epi8(0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E)); - epx.m64.reg_b = epx2.m64.reg_a; + epx.m128 = _mm_blendv_epi8(epx.m128, epx2.m128, _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF)); b128.m128 = _mm_and_si128(epx.m128, _mm_set1_epi8(0x7)); b128.m128 = _mm_shuffle_epi8(m128mask, b128.m128); diff --git a/lib/src/phy/utils/ringbuffer.c b/lib/src/phy/utils/ringbuffer.c index 86578b3ea..400f80360 100644 --- a/lib/src/phy/utils/ringbuffer.c +++ b/lib/src/phy/utils/ringbuffer.c @@ -11,10 +11,9 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity) if (!q->buffer) { return -1; } - q->capacity = capacity; - q->count = 0; - q->wpm = 0; - q->rpm = 0; + + q->capacity = capacity; + srslte_ringbuffer_reset(q); pthread_mutex_init(&q->mutex, NULL); pthread_cond_init(&q->cvar, NULL); @@ -22,7 +21,7 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity) return 0; } -void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) +void srslte_ringbuffer_free(srslte_ringbuffer_t *q) { if (q) { if (q->buffer) { @@ -34,11 +33,26 @@ void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) } } -int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) -{ +void srslte_ringbuffer_reset(srslte_ringbuffer_t *q) +{ + pthread_mutex_lock(&q->mutex); + q->count = 0; + q->wpm = 0; + q->rpm = 0; + pthread_mutex_unlock(&q->mutex); +} + +int srslte_ringbuffer_status(srslte_ringbuffer_t *q) +{ + return q->count; +} + +int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes) +{ + uint8_t *ptr = (uint8_t*) p; int w_bytes = nof_bytes; pthread_mutex_lock(&q->mutex); - if (q->count + w_bytes >= q->capacity) { + if (q->count + w_bytes > q->capacity) { w_bytes = q->capacity - q->count; fprintf(stderr, "Buffer overrun: lost %d bytes\n", nof_bytes - w_bytes); } @@ -59,8 +73,9 @@ int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) return w_bytes; } -int srslte_ringbuffer_read(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) +int srslte_ringbuffer_read(srslte_ringbuffer_t *q, void *p, int nof_bytes) { + uint8_t *ptr = (uint8_t*) p; pthread_mutex_lock(&q->mutex); while(q->count < nof_bytes) { pthread_cond_wait(&q->cvar, &q->mutex); diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index f01e60154..f592db71f 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -441,9 +441,9 @@ void radio::set_tx_srate(double srate) tx_adv_sec = nsamples/cur_tx_srate; } -void radio::start_rx() +void radio::start_rx(bool now) { - srslte_rf_start_rx_stream(&rf_device); + srslte_rf_start_rx_stream(&rf_device, now); } void radio::stop_rx() diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 0acc7f6bd..5d3b4d061 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -51,7 +51,19 @@ void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_ } void pdcp::stop() -{} +{ + for(uint32_t i=0;iinfo("Added bearer %s\n", rrc->get_rb_name(lcid).c_str()); + pdcp_log->info("Added bearer %s\n", get_rb_name(lcid)); } else { - pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str()); + pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid)); } } void pdcp::config_security(uint32_t lcid, - uint8_t *k_rrc_enc, - uint8_t *k_rrc_int, + uint8_t *k_enc, + uint8_t *k_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { if(valid_lcid(lcid)) - pdcp_array[lcid].config_security(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp_array[lcid].config_security(k_enc, k_int, cipher_algo, integ_algo); +} + +void pdcp::config_security_all(uint8_t *k_enc, + uint8_t *k_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + for(uint32_t i=0;idebug("Init %s\n", get_rb_name(lcid)); +} - log->debug("Init %s\n", rrc->get_rb_name(lcid).c_str()); +void pdcp_entity::stop() +{ + if(running) { + running = false; + thread_cancel(); + wait_thread_finish(); + } +} + +// Reestablishment procedure: 36.323 5.2 +void pdcp_entity::reestablish() { + // For SRBs + if (cfg.is_control) { + tx_count = 0; + rx_count = 0; + } else { + if (rlc->rb_is_um(lcid)) { + tx_count = 0; + rx_count = 0; + } + } } void pdcp_entity::reset() { active = false; if(log) - log->debug("Reset %s\n", rrc->get_rb_name(lcid).c_str()); + log->debug("Reset %s\n", get_rb_name(lcid)); } bool pdcp_entity::is_active() @@ -74,116 +105,309 @@ bool pdcp_entity::is_active() // RRC interface void pdcp_entity::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU, do_security = %s", rrc->get_rb_name(lcid).c_str(), (cfg.do_security)?"true":"false"); + log->info_hex(sdu->msg, sdu->N_bytes, + "TX %s SDU, SN: %d, do_integrity = %s, do_encryption = %s", + get_rb_name(lcid), tx_count, + (do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false"); if (cfg.is_control) { pdcp_pack_control_pdu(tx_count, sdu); - if(cfg.do_security) - { - integrity_generate(&k_rrc_int[16], - tx_count, - lcid-1, - cfg.direction, - sdu->msg, + if(do_integrity) { + integrity_generate(sdu->msg, sdu->N_bytes-4, &sdu->msg[sdu->N_bytes-4]); } - tx_count++; } if (cfg.is_data) { if(12 == cfg.sn_len) { - pdcp_pack_data_pdu_long_sn(tx_count++, sdu); + pdcp_pack_data_pdu_long_sn(tx_count, sdu); } else { - pdcp_pack_data_pdu_short_sn(tx_count++, sdu); + pdcp_pack_data_pdu_short_sn(tx_count, sdu); } } + if(do_encryption) { + cipher_encrypt(&sdu->msg[sn_len_bytes], + sdu->N_bytes-sn_len_bytes, + &sdu->msg[sn_len_bytes]); + log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU (encrypted)", get_rb_name(lcid)); + } + tx_count++; + rlc->write_sdu(lcid, sdu); } -void pdcp_entity::config_security(uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, +void pdcp_entity::config_security(uint8_t *k_enc_, + uint8_t *k_int_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) { - cfg.do_security = true; for(int i=0; i<32; i++) { - k_rrc_enc[i] = k_rrc_enc_[i]; - k_rrc_int[i] = k_rrc_int_[i]; + k_enc[i] = k_enc_[i]; + k_int[i] = k_int_[i]; } cipher_algo = cipher_algo_; integ_algo = integ_algo_; } -// RLC interface -void pdcp_entity::write_pdu(byte_buffer_t *pdu) +void pdcp_entity::enable_integrity() { + do_integrity = true; +} +void pdcp_entity::enable_encryption() +{ + do_encryption = true; +} +// RLC interface +void pdcp_entity::write_pdu(byte_buffer_t *pdu) +{ + rx_pdu_queue.write(pdu); +} +void pdcp_entity::integrity_generate( uint8_t *msg, + uint32_t msg_len, + uint8_t *mac) +{ + uint8_t bearer; - - if (cfg.is_data) { - uint32_t sn; - if(12 == cfg.sn_len) - { - pdcp_unpack_data_pdu_long_sn(pdu, &sn); - } else { - pdcp_unpack_data_pdu_short_sn(pdu, &sn); - } - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", rrc->get_rb_name(lcid).c_str(), sn); - gw->write_pdu(lcid, pdu); - } else { - if (cfg.is_control) { - uint32_t sn; - pdcp_unpack_control_pdu(pdu, &sn); - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d", - rrc->get_rb_name(lcid).c_str(), sn); - } else { - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rrc->get_rb_name(lcid).c_str()); - } - // pass to RRC - rrc->write_pdu(lcid, pdu); + switch(integ_algo) + { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(&k_int[16], + tx_count, + get_bearer_id(lcid), + cfg.direction, + msg, + msg_len, + mac); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(&k_int[16], + tx_count, + get_bearer_id(lcid), + cfg.direction, + msg, + msg_len, + mac); + break; + default: + break; } } -void pdcp_entity::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) +bool pdcp_entity::integrity_verify(uint8_t *msg, + uint32_t count, + uint32_t msg_len, + uint8_t *mac) { + uint8_t mac_exp[4] = {0x00}; + uint8_t i = 0; + bool isValid = true; + switch(integ_algo) { case INTEGRITY_ALGORITHM_ID_EIA0: break; case INTEGRITY_ALGORITHM_ID_128_EIA1: - security_128_eia1(key_128, + security_128_eia1(&k_int[16], count, - rb_id, - direction, + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), msg, msg_len, - mac); + mac_exp); break; case INTEGRITY_ALGORITHM_ID_128_EIA2: - security_128_eia2(key_128, + security_128_eia2(&k_int[16], count, - rb_id, - direction, + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), msg, msg_len, - mac); + mac_exp); + break; + default: + break; + } + + switch(integ_algo) + { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: // Intentional fall-through + case INTEGRITY_ALGORITHM_ID_128_EIA2: + for(i=0; i<4; i++){ + if(mac[i] != mac_exp[i]){ + log->error_hex(mac_exp, 4, "MAC mismatch (expected)"); + log->error_hex(mac, 4, "MAC mismatch (found)"); + isValid = false; + break; + } + } + if (isValid){ + log->info_hex(mac_exp, 4, "MAC match (expected)"); + log->info_hex(mac, 4, "MAC match (found)"); + } + break; + default: + break; + } + + return isValid; +} + +void pdcp_entity::cipher_encrypt(uint8_t *msg, + uint32_t msg_len, + uint8_t *ct) +{ + byte_buffer_t ct_tmp; + switch(cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&(k_enc[16]), + tx_count, + get_bearer_id(lcid), + cfg.direction, + msg, + msg_len, + ct_tmp.msg); + memcpy(ct, ct_tmp.msg, msg_len); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&(k_enc[16]), + tx_count, + get_bearer_id(lcid), + cfg.direction, + msg, + msg_len, + ct_tmp.msg); + memcpy(ct, ct_tmp.msg, msg_len); + break; + default: + break; + } +} + +void pdcp_entity::cipher_decrypt(uint8_t *ct, + uint32_t count, + uint32_t ct_len, + uint8_t *msg) +{ + byte_buffer_t msg_tmp; + switch(cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&(k_enc[16]), + count, + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + ct, + ct_len, + msg_tmp.msg); + memcpy(msg, msg_tmp.msg, ct_len); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&(k_enc[16]), + count, + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + ct, + ct_len, + msg_tmp.msg); + memcpy(msg, msg_tmp.msg, ct_len); break; default: break; } } + +void pdcp_entity::run_thread() +{ + byte_buffer_t *pdu; + running = true; + + while(running) { + rx_pdu_queue.read(&pdu); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU, do_integrity = %s, do_encryption = %s", + get_rb_name(lcid), (do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false"); + + // Handle SRB messages + switch(lcid) + { + case RB_ID_SRB0: + // Simply pass on to RRC + rrc->write_pdu(RB_ID_SRB0, pdu); + break; + case RB_ID_SRB1: // Intentional fall-through + case RB_ID_SRB2: + uint32_t sn; + if (do_encryption) { + cipher_decrypt(&(pdu->msg[sn_len_bytes]), + rx_count, + pdu->N_bytes - sn_len_bytes, + &(pdu->msg[sn_len_bytes])); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid)); + } + + if (do_integrity) { + integrity_verify(pdu->msg, + rx_count, + pdu->N_bytes - 4, + &(pdu->msg[pdu->N_bytes - 4])); + } + + pdcp_unpack_control_pdu(pdu, &sn); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn); + rrc->write_pdu(lcid, pdu); + break; + } + + // Handle DRB messages + if(lcid >= RB_ID_DRB1) + { + uint32_t sn; + if (do_encryption) { + cipher_decrypt(&(pdu->msg[sn_len_bytes]), + rx_count, + pdu->N_bytes - sn_len_bytes, + &(pdu->msg[sn_len_bytes])); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid)); + } + if(12 == cfg.sn_len) + { + pdcp_unpack_data_pdu_long_sn(pdu, &sn); + } else { + pdcp_unpack_data_pdu_short_sn(pdu, &sn); + } + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn); + gw->write_pdu(lcid, pdu); + } + + rx_count++; + } +} + +uint8_t pdcp_entity::get_bearer_id(uint8_t lcid) +{ + if(lcid <= RB_ID_SRB2) { + return lcid - 1; + } else { + return lcid - RB_ID_SRB2 - 1; + } +} + + /**************************************************************************** * Pack/Unpack helper functions * Ref: 3GPP TS 36.323 v10.1.0 diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index f506ebc63..16319c268 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -95,6 +95,14 @@ void rlc::get_metrics(rlc_metrics_t &m) reset_metrics(); } +void rlc::reestablish() { + for(uint32_t i=0; iget_rb_name(lcid); +bool rlc::rb_is_um(uint32_t lcid) { + return rlc_array[lcid].get_mode()==RLC_MODE_UM; } /******************************************************************************* @@ -217,11 +224,10 @@ void rlc::add_bearer(uint32_t lcid) cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0; add_bearer(lcid, srslte_rlc_config_t(&cnfg)); } else { - rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid).c_str()); + rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid)); } }else{ - rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", - get_rb_name(lcid).c_str()); + rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", get_rb_name(lcid)); } } @@ -234,7 +240,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) if (!rlc_array[lcid].active()) { rlc_log->info("Adding radio bearer %s with mode %s\n", - get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); switch(cnfg.rlc_mode) { case LIBLTE_RRC_RLC_MODE_AM: @@ -254,7 +260,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) return; } } else { - rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid).c_str()); + rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid)); } rlc_array[lcid].configure(cnfg); diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index f8abc0aef..c048133d6 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -79,7 +79,7 @@ void rlc_am::configure(srslte_rlc_config_t cfg_) cfg = cfg_.am; log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " "t_reordering=%d, t_status_prohibit=%d\n", - rrc->get_rb_name(lcid).c_str(), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, + get_rb_name(lcid), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, cfg.t_reordering, cfg.t_status_prohibit); } @@ -175,7 +175,7 @@ uint32_t rlc_am::get_bearer() void rlc_am::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); tx_sdu_queue.write(sdu); } @@ -359,7 +359,7 @@ void rlc_am::check_reordering_timeout() if(reordering_timeout.is_running() && reordering_timeout.expired()) { reordering_timeout.reset(); - log->debug("%s reordering timeout expiry - updating vr_ms\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s reordering timeout expiry - updating vr_ms\n", get_rb_name(lcid)); // 36.322 v10 Section 5.1.3.2.4 vr_ms = vr_x; @@ -433,7 +433,7 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) { log->info("%s Tx status PDU - %s\n", - rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); + get_rb_name(lcid), rlc_am_to_string(&status).c_str()); do_status = false; poll_received = false; @@ -444,7 +444,7 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) return rlc_am_write_status_pdu(&status, payload); }else{ log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); + get_rb_name(lcid), nof_bytes, pdu_len); return 0; } } @@ -478,7 +478,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) return -1; } if(retx.is_segment || req_size > (int)nof_bytes) { - log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s build_retx_pdu - resegmentation required\n", get_rb_name(lcid)); return build_segment(payload, nof_bytes, retx); } @@ -503,7 +503,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_window[retx.sn].retx_count >= cfg.max_retx_thresh) rrc->max_retx_attempted(); log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n", - rrc->get_rb_name(lcid).c_str(), retx.sn, tx_window[retx.sn].retx_count); + get_rb_name(lcid), retx.sn, tx_window[retx.sn].retx_count); debug_state(); return (ptr-payload) + tx_window[retx.sn].buf->N_bytes; @@ -540,7 +540,7 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r if(nof_bytes <= head_len) { log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); return 0; } pdu_space = nof_bytes-head_len; @@ -606,15 +606,15 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r memcpy(ptr, data, len); log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n", - rrc->get_rb_name(lcid).c_str(), retx.sn, retx.so_start); + get_rb_name(lcid), retx.sn, retx.so_start); debug_state(); int pdu_len = (ptr-payload) + len; if(pdu_len > (int)nof_bytes) { log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); + get_rb_name(lcid), nof_bytes, pdu_len); log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n", - rrc->get_rb_name(lcid).c_str(), (ptr-payload), len, new_header.N_li); + get_rb_name(lcid), (ptr-payload), len, new_header.N_li); } return pdu_len; @@ -662,13 +662,13 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(pdu_space <= head_len + 1) { log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); pool->deallocate(pdu); return 0; } log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), pdu_space, head_len); + get_rb_name(lcid), pdu_space, head_len); // Check for SDU segment if(tx_sdu) @@ -683,7 +683,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -694,7 +694,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); + get_rb_name(lcid), to_move, pdu_space, head_len); } // Pull SDUs from queue @@ -718,7 +718,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -728,7 +728,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pdu_space = 0; log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); + get_rb_name(lcid), to_move, pdu_space, head_len); } if(tx_sdu) @@ -737,11 +737,11 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) // Set Poll bit pdu_without_poll++; byte_without_poll += (pdu->N_bytes + head_len); - log->debug("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll); - log->debug("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll); + log->debug("%s pdu_without_poll: %d\n", get_rb_name(lcid), pdu_without_poll); + log->debug("%s byte_without_poll: %d\n", get_rb_name(lcid), byte_without_poll); if(poll_required()) { - log->debug("%s setting poll bit to request status\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s setting poll bit to request status\n", get_rb_name(lcid)); header.p = 1; poll_sn = vt_s; pdu_without_poll = 0; @@ -752,7 +752,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) // Set SN header.sn = vt_s; vt_s = (vt_s + 1)%MOD; - log->info("%s PDU scheduled for tx. SN: %d\n", rrc->get_rb_name(lcid).c_str(), header.sn); + log->info("%s PDU scheduled for tx. SN: %d\n", get_rb_name(lcid), header.sn); // Place PDU in tx_window, write header and TX tx_window[header.sn].buf = pdu; @@ -773,26 +773,26 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h std::map::iterator it; log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); if(!inside_rx_window(header.sn)) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); + get_rb_name(lcid), header.sn, vr_r, vr_mr); return; } it = rx_window.find(header.sn); if(rx_window.end() != it) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s Discarding duplicate SN: %d\n", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); return; } @@ -825,7 +825,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h // Check poll bit if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -870,16 +870,16 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a std::map::iterator it; log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d", - rrc->get_rb_name(lcid).c_str(), header.sn, header.so); + get_rb_name(lcid), header.sn, header.so); // Check inside rx window if(!inside_rx_window(header.sn)) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); + get_rb_name(lcid), header.sn, vr_r, vr_mr); return; } @@ -898,7 +898,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a if(rx_segments.end() != it) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } @@ -928,7 +928,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a // Check poll bit if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -946,12 +946,12 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) { - log->info_hex(payload, nof_bytes, "%s Rx control PDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(payload, nof_bytes, "%s Rx control PDU", get_rb_name(lcid)); rlc_status_pdu_t status; rlc_am_read_status_pdu(payload, nof_bytes, &status); - log->info("%s Rx Status PDU: %s\n", rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); + log->info("%s Rx Status PDU: %s\n", get_rb_name(lcid), rlc_am_to_string(&status).c_str()); poll_retx_timeout.reset(); @@ -989,7 +989,7 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) } } 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); + get_rb_name(lcid), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); } } @@ -1043,7 +1043,7 @@ void rlc_am::reassemble_rx_sdus() rx_sdu->N_bytes += len; rx_window[vr_r].buf->msg += len; rx_window[vr_r].buf->N_bytes -= len; - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", get_rb_name(lcid)); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -1059,7 +1059,7 @@ void rlc_am::reassemble_rx_sdus() rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", get_rb_name(lcid)); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -1103,7 +1103,7 @@ void rlc_am::debug_state() { log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d " "vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n", - rrc->get_rb_name(lcid).c_str(), vt_a, vt_ms, vt_s, poll_sn, + get_rb_name(lcid), vt_a, vt_ms, vt_s, poll_sn, vr_r, vr_mr, vr_x, vr_ms, vr_h); } diff --git a/lib/src/upper/rlc_entity.cc b/lib/src/upper/rlc_entity.cc index 5a351162a..81692889c 100644 --- a/lib/src/upper/rlc_entity.cc +++ b/lib/src/upper/rlc_entity.cc @@ -70,6 +70,10 @@ void rlc_entity::configure(srslte_rlc_config_t cnfg) rlc->configure(cnfg); } +void rlc_entity::reestablish() { + rlc->reset(); +} + void rlc_entity::reset() { rlc->reset(); diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index 627752494..4559dd07b 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -84,7 +84,7 @@ uint32_t rlc_tm::get_bearer() // PDCP interface void rlc_tm::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); ul_queue.write(sdu); } @@ -104,7 +104,7 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t pdu_size = ul_queue.size_tail_bytes(); if(pdu_size > nof_bytes) { - log->error("TX %s PDU size larger than MAC opportunity\n", rrc->get_rb_name(lcid).c_str()); + log->error("TX %s PDU size larger than MAC opportunity\n", get_rb_name(lcid)); return 0; } byte_buffer_t *buf; @@ -112,9 +112,9 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) pdu_size = buf->N_bytes; memcpy(payload, buf->msg, buf->N_bytes); log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), buf->get_latency_us()); + get_rb_name(lcid), buf->get_latency_us()); pool->deallocate(buf); - log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]); + log->info_hex(payload, pdu_size, "TX %s, %s PDU", get_rb_name(lcid), rlc_mode_text[RLC_MODE_TM]); return pdu_size; } diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 4756e2f7c..5b395228f 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -75,18 +75,18 @@ void rlc_um::configure(srslte_rlc_config_t cnfg_) case LIBLTE_RRC_RLC_MODE_UM_BI: log->info("%s configured in %s mode: " "t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: log->info("%s configured in %s mode: " "t_reordering=%d ms, rx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; default: @@ -153,7 +153,7 @@ uint32_t rlc_um::get_bearer() void rlc_um::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); tx_sdu_queue.write(sdu); } @@ -216,7 +216,7 @@ void rlc_um::timer_expired(uint32_t timeout_id) // 36.322 v10 Section 5.1.2.2.4 log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", - rrc->get_rb_name(lcid).c_str()); + get_rb_name(lcid)); log->warning("Lost PDU SN: %d\n", vr_ur); pdu_lost = true; @@ -281,7 +281,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { pool->deallocate(pdu); log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); return 0; } @@ -291,7 +291,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", - rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); + get_rb_name(lcid), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -301,7 +301,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -320,7 +320,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", - rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); + get_rb_name(lcid), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -330,7 +330,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -345,11 +345,11 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) vt_us = (vt_us + 1)%cfg.tx_mod; // Add header and TX - log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + log->debug("%s packing PDU with length %d\n", get_rb_name(lcid), pdu->N_bytes); rlc_um_write_data_pdu_header(&header, pdu); memcpy(payload, pdu->msg, pdu->N_bytes); uint32_t ret = pdu->N_bytes; - log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + log->debug("%s returning length %d\n", get_rb_name(lcid), pdu->N_bytes); pool->deallocate(pdu); debug_state(); @@ -363,20 +363,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header); log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) && RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) { log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh); + get_rb_name(lcid), header.sn, vr_ur, vr_uh); return; } it = rx_window.find(header.sn); if(rx_window.end() != it) { log->info("%s Discarding duplicate SN: %d\n", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); return; } @@ -451,7 +451,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", get_rb_name(lcid), vr_ur, i); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -471,7 +471,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", get_rb_name(lcid), vr_ur); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -505,7 +505,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", get_rb_name(lcid), vr_ur, i); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -534,7 +534,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", get_rb_name(lcid), vr_ur); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -564,7 +564,7 @@ bool rlc_um::inside_reordering_window(uint16_t sn) void rlc_um::debug_state() { log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n", - rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh); + get_rb_name(lcid), vt_us, vr_ur, vr_ux, vr_uh); } diff --git a/lib/test/common/CMakeLists.txt b/lib/test/common/CMakeLists.txt index 3faa2ff59..bbdc74613 100644 --- a/lib/test/common/CMakeLists.txt +++ b/lib/test/common/CMakeLists.txt @@ -29,6 +29,14 @@ add_executable(msg_queue_test msg_queue_test.cc) target_link_libraries(msg_queue_test srslte_phy srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) add_test(msg_queue_test msg_queue_test) +add_executable(test_eea1 test_eea1.cc) +target_link_libraries(test_eea1 srslte_common ${CMAKE_THREAD_LIBS_INIT}) +add_test(test_eea1 test_eea1) + +add_executable(test_eea2 test_eea2.cc) +target_link_libraries(test_eea2 srslte_common ${CMAKE_THREAD_LIBS_INIT}) +add_test(test_eea2 test_eea2) + add_executable(log_filter_test log_filter_test.cc) target_link_libraries(log_filter_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/lib/test/common/test_eea1.cc b/lib/test/common/test_eea1.cc new file mode 100644 index 000000000..b3c57caa6 --- /dev/null +++ b/lib/test/common/test_eea1.cc @@ -0,0 +1,569 @@ +/* + * Includes + */ + +#include +#include +#include + +#include "srslte/common/liblte_security.h" + +/* + * Prototypes + */ + +int32 arrcmp(uint8_t const * const a, uint8_t const * const b, uint32 len) { + uint32 i = 0; + + for (i = 0; i < len; i++) { + if (a[i] != b[i]) { + return a[i] - b[i]; + } + } + return 0; +} + +/* + * Tests + * + * Document Reference: 33.401 V13.1.0 Annex C.3 + * Specification of the 3GPP Confidentiality and + * Integrity Algorithms UEA2 & UIA2 D4 v1.0 + */ + +void test_set_1() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_2() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x2b, 0xd6, 0x45, 0x9f, 0x82, 0xc4, 0x40, + 0xe0, 0x95, 0x2c, 0x49, 0x10, 0x48, 0x05, 0xff, 0x48 }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 798, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x7e, 0xc6, 0x12, 0x72, 0x74, 0x3b, 0xf1, + 0x61, 0x47, 0x26, 0x44, 0x6a, 0x6c, 0x38, 0xce, 0xd1, + 0x66, 0xf6, 0xca, 0x76, 0xeb, 0x54, 0x30, 0x04, 0x42, + 0x86, 0x34, 0x6c, 0xef, 0x13, 0x0f, 0x92, 0x92, 0x2b, + 0x03, 0x45, 0x0d, 0x3a, 0x99, 0x75, 0xe5, 0xbd, 0x2e, + 0xa0, 0xeb, 0x55, 0xad, 0x8e, 0x1b, 0x19, 0x9e, 0x3e, + 0xc4, 0x31, 0x60, 0x20, 0xe9, 0xa1, 0xb2, 0x85, 0xe7, + 0x62, 0x79, 0x53, 0x59, 0xb7, 0xbd, 0xfd, 0x39, 0xbe, + 0xf4, 0xb2, 0x48, 0x45, 0x83, 0xd5, 0xaf, 0xe0, 0x82, + 0xae, 0xe6, 0x38, 0xbf, 0x5f, 0xd5, 0xa6, 0x06, 0x19, + 0x39, 0x01, 0xa0, 0x8f, 0x4a, 0xb4, 0x1a, 0xab, 0x9b, + 0x13, 0x48, 0x80 }; + uint8_t ct[] = { 0x3f, 0x67, 0x85, 0x07, 0x14, 0xb8, 0xda, + 0x69, 0xef, 0xb7, 0x27, 0xed, 0x7a, 0x6c, 0x0c, 0x50, + 0x71, 0x4a, 0xd7, 0x36, 0xc4, 0xf5, 0x60, 0x00, 0x06, + 0xe3, 0x52, 0x5b, 0xe8, 0x07, 0xc4, 0x67, 0xc6, 0x77, + 0xff, 0x86, 0x4a, 0xf4, 0x5f, 0xba, 0x09, 0xc2, 0x7c, + 0xde, 0x38, 0xf8, 0x7a, 0x1f, 0x84, 0xd5, 0x9a, 0xb2, + 0x55, 0x40, 0x8f, 0x2c, 0x7b, 0x82, 0xf9, 0xea, 0xd4, + 0x1a, 0x1f, 0xe6, 0x5e, 0xab, 0xeb, 0xfb, 0xc1, 0xf3, + 0xa4, 0xc5, 0x6c, 0x9a, 0x26, 0xfc, 0xf7, 0xb3, 0xd6, + 0x6d, 0x02, 0x20, 0xee, 0x47, 0x75, 0xbc, 0x58, 0x17, + 0x0a, 0x2b, 0x12, 0xf3, 0x43, 0x1d, 0x11, 0xb3, 0x44, + 0xd6, 0xe3, 0x6c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_3() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, 0x8b, + 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, 0xfb }; + uint32_t count = 0x544d49cd; + uint8_t bearer = 0x04; + uint8_t direction = 0; + uint32_t len_bits = 310, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfd, 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, + 0x65, 0x74, 0x50, 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, + 0x36, 0xd2, 0x34, 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, + 0x8e, 0xa9, 0xc4, 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, + 0xf2, 0x64, 0xd0, 0xf2, 0x48, 0x00 }; + uint8_t ct[] = { 0x48, 0x14, 0x8e, 0x54, 0x52, 0xa2, 0x10, + 0xc0, 0x5f, 0x46, 0xbc, 0x80, 0xdc, 0x6f, 0x73, 0x49, + 0x5b, 0x02, 0x04, 0x8c, 0x1b, 0x95, 0x8b, 0x02, 0x61, + 0x02, 0xca, 0x97, 0x28, 0x02, 0x79, 0xa4, 0xc1, 0x8d, + 0x2e, 0xe3, 0x08, 0x92, 0x1c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_4() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xaa, 0x1f, 0x95, 0xae, 0xa5, 0x33, 0xbc, + 0xb3, 0x2e, 0xb6, 0x3b, 0xf5, 0x2d, 0x8f, 0x83, 0x1a }; + uint32_t count = 0x72d8c671; + uint8_t bearer = 0x10; + uint8_t direction = 1; + uint32_t len_bits = 1022, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfb, 0x1b, 0x96, 0xc5, 0xc8, 0xba, 0xdf, + 0xb2, 0xe8, 0xe8, 0xed, 0xfd, 0xe7, 0x8e, 0x57, 0xf2, + 0xad, 0x81, 0xe7, 0x41, 0x03, 0xfc, 0x43, 0x0a, 0x53, + 0x4d, 0xcc, 0x37, 0xaf, 0xce, 0xc7, 0x0e, 0x15, 0x17, + 0xbb, 0x06, 0xf2, 0x72, 0x19, 0xda, 0xe4, 0x90, 0x22, + 0xdd, 0xc4, 0x7a, 0x06, 0x8d, 0xe4, 0xc9, 0x49, 0x6a, + 0x95, 0x1a, 0x6b, 0x09, 0xed, 0xbd, 0xc8, 0x64, 0xc7, + 0xad, 0xbd, 0x74, 0x0a, 0xc5, 0x0c, 0x02, 0x2f, 0x30, + 0x82, 0xba, 0xfd, 0x22, 0xd7, 0x81, 0x97, 0xc5, 0xd5, + 0x08, 0xb9, 0x77, 0xbc, 0xa1, 0x3f, 0x32, 0xe6, 0x52, + 0xe7, 0x4b, 0xa7, 0x28, 0x57, 0x60, 0x77, 0xce, 0x62, + 0x8c, 0x53, 0x5e, 0x87, 0xdc, 0x60, 0x77, 0xba, 0x07, + 0xd2, 0x90, 0x68, 0x59, 0x0c, 0x8c, 0xb5, 0xf1, 0x08, + 0x8e, 0x08, 0x2c, 0xfa, 0x0e, 0xc9, 0x61, 0x30, 0x2d, + 0x69, 0xcf, 0x3d, 0x44 }; + uint8_t ct[] = { 0xff, 0xcf, 0xc2, 0xfe, 0xad, 0x6c, 0x09, + 0x4e, 0x96, 0xc5, 0x89, 0xd0, 0xf6, 0x77, 0x9b, 0x67, + 0x84, 0x24, 0x6c, 0x3c, 0x4d, 0x1c, 0xea, 0x20, 0x3d, + 0xb3, 0x90, 0x1f, 0x40, 0xad, 0x4f, 0xd7, 0x13, 0x8b, + 0xc6, 0xd7, 0x7e, 0x83, 0x20, 0xcb, 0x10, 0x2f, 0x49, + 0x7f, 0xdd, 0x44, 0xa2, 0x69, 0xa9, 0x6e, 0xcb, 0x28, + 0x61, 0x77, 0x00, 0xe3, 0x32, 0xeb, 0x2f, 0x73, 0x6b, + 0x34, 0xf4, 0xf2, 0x69, 0x30, 0x94, 0xe2, 0x2f, 0xf9, + 0x4f, 0x9b, 0xe4, 0x72, 0x3d, 0xa4, 0x0c, 0x40, 0xdf, + 0xd3, 0x93, 0x1c, 0xc1, 0xac, 0x97, 0x23, 0xf6, 0xb4, + 0xa9, 0x91, 0x3e, 0x96, 0xb6, 0xdb, 0x7a, 0xbc, 0xac, + 0xe4, 0x15, 0x17, 0x7c, 0x1d, 0x01, 0x15, 0xc5, 0xf0, + 0x9b, 0x5f, 0xde, 0xa0, 0xb3, 0xad, 0xb8, 0xf9, 0xda, + 0x6e, 0x9f, 0x9a, 0x04, 0xc5, 0x43, 0x39, 0x7b, 0x9d, + 0x43, 0xf8, 0x73, 0x30 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_5() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x96, 0x18, 0xae, 0x46, 0x89, 0x1f, 0x86, + 0x57, 0x8e, 0xeb, 0xe9, 0x0e, 0xf7, 0xa1, 0x20, 0x2e }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 1245, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x8d, 0xaa, 0x17, 0xb1, 0xae, 0x05, 0x05, + 0x29, 0xc6, 0x82, 0x7f, 0x28, 0xc0, 0xef, 0x6a, 0x12, + 0x42, 0xe9, 0x3f, 0x8b, 0x31, 0x4f, 0xb1, 0x8a, 0x77, + 0xf7, 0x90, 0xae, 0x04, 0x9f, 0xed, 0xd6, 0x12, 0x26, + 0x7f, 0xec, 0xae, 0xfc, 0x45, 0x01, 0x74, 0xd7, 0x6d, + 0x9f, 0x9a, 0xa7, 0x75, 0x5a, 0x30, 0xcd, 0x90, 0xa9, + 0xa5, 0x87, 0x4b, 0xf4, 0x8e, 0xaf, 0x70, 0xee, 0xa3, + 0xa6, 0x2a, 0x25, 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, + 0x8b, 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, + 0xfb, 0x54, 0x4d, 0x49, 0xcd, 0x49, 0x72, 0x0e, 0x21, + 0x9d, 0xbf, 0x8b, 0xbe, 0xd3, 0x39, 0x04, 0xe1, 0xfd, + 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, 0x65, 0x74, 0x50, + 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, 0x36, 0xd2, 0x34, + 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, 0x8e, 0xa9, 0xc4, + 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, 0xf2, 0x64, 0xd0, + 0xf2, 0x48, 0x41, 0xd6, 0x46, 0x5f, 0x09, 0x96, 0xff, + 0x84, 0xe6, 0x5f, 0xc5, 0x17, 0xc5, 0x3e, 0xfc, 0x33, + 0x63, 0xc3, 0x84, 0x92, 0xa8 }; + uint8_t ct[] = { 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, 0x18, + 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, 0x37, + 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, 0x81, + 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, 0x7c, + 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, 0xfe, + 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, 0x17, + 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, 0xd9, + 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, 0x25, + 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, 0x92, + 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, 0xaa, + 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, 0xff, + 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, 0x36, + 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, 0x8e, + 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, 0x05, + 0x4b, 0xe1, 0xfa, 0x72, 0x72, 0xb5, 0xff, 0xb2, 0xb2, + 0x57, 0x0f, 0x4f, 0x7c, 0xea, 0xf3, 0x83, 0xa8, 0xa9, + 0xd9, 0x35, 0x72, 0xf0, 0x4d, 0x6e, 0x3a, 0x6e, 0x29, + 0x37, 0x26, 0xec, 0x62, 0xc8 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_6() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x54, 0xf4, 0xe2, 0xe0, 0x4c, 0x83, 0x78, + 0x6e, 0xec, 0x8f, 0xb5, 0xab, 0xe8, 0xe3, 0x65, 0x66 }; + uint32_t count = 0xaca4f50f; + uint8_t bearer = 0x0b; + uint8_t direction = 0; + uint32_t len_bits = 3861, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x40, 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, + 0xfb, 0x42, 0x86, 0xb2, 0x99, 0x78, 0x3d, 0xaf, 0x44, + 0x2c, 0x09, 0x9f, 0x7a, 0xb0, 0xf5, 0x8d, 0x5c, 0x8e, + 0x46, 0xb1, 0x04, 0xf0, 0x8f, 0x01, 0xb4, 0x1a, 0xb4, + 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x36, 0xbd, 0x1a, + 0x3d, 0x90, 0xdc, 0x3a, 0x41, 0xb4, 0x6d, 0x51, 0x67, + 0x2a, 0xc4, 0xc9, 0x66, 0x3a, 0x2b, 0xe0, 0x63, 0xda, + 0x4b, 0xc8, 0xd2, 0x80, 0x8c, 0xe3, 0x3e, 0x2c, 0xcc, + 0xbf, 0xc6, 0x34, 0xe1, 0xb2, 0x59, 0x06, 0x08, 0x76, + 0xa0, 0xfb, 0xb5, 0xa4, 0x37, 0xeb, 0xcc, 0x8d, 0x31, + 0xc1, 0x9e, 0x44, 0x54, 0x31, 0x87, 0x45, 0xe3, 0xfa, + 0x16, 0xbb, 0x11, 0xad, 0xae, 0x24, 0x88, 0x79, 0xfe, + 0x52, 0xdb, 0x25, 0x43, 0xe5, 0x3c, 0xf4, 0x45, 0xd3, + 0xd8, 0x28, 0xce, 0x0b, 0xf5, 0xc5, 0x60, 0x59, 0x3d, + 0x97, 0x27, 0x8a, 0x59, 0x76, 0x2d, 0xd0, 0xc2, 0xc9, + 0xcd, 0x68, 0xd4, 0x49, 0x6a, 0x79, 0x25, 0x08, 0x61, + 0x40, 0x14, 0xb1, 0x3b, 0x6a, 0xa5, 0x11, 0x28, 0xc1, + 0x8c, 0xd6, 0xa9, 0x0b, 0x87, 0x97, 0x8c, 0x2f, 0xf1, + 0xca, 0xbe, 0x7d, 0x9f, 0x89, 0x8a, 0x41, 0x1b, 0xfd, + 0xb8, 0x4f, 0x68, 0xf6, 0x72, 0x7b, 0x14, 0x99, 0xcd, + 0xd3, 0x0d, 0xf0, 0x44, 0x3a, 0xb4, 0xa6, 0x66, 0x53, + 0x33, 0x0b, 0xcb, 0xa1, 0x10, 0x5e, 0x4c, 0xec, 0x03, + 0x4c, 0x73, 0xe6, 0x05, 0xb4, 0x31, 0x0e, 0xaa, 0xad, + 0xcf, 0xd5, 0xb0, 0xca, 0x27, 0xff, 0xd8, 0x9d, 0x14, + 0x4d, 0xf4, 0x79, 0x27, 0x59, 0x42, 0x7c, 0x9c, 0xc1, + 0xf8, 0xcd, 0x8c, 0x87, 0x20, 0x23, 0x64, 0xb8, 0xa6, + 0x87, 0x95, 0x4c, 0xb0, 0x5a, 0x8d, 0x4e, 0x2d, 0x99, + 0xe7, 0x3d, 0xb1, 0x60, 0xde, 0xb1, 0x80, 0xad, 0x08, + 0x41, 0xe9, 0x67, 0x41, 0xa5, 0xd5, 0x9f, 0xe4, 0x18, + 0x9f, 0x15, 0x42, 0x00, 0x26, 0xfe, 0x4c, 0xd1, 0x21, + 0x04, 0x93, 0x2f, 0xb3, 0x8f, 0x73, 0x53, 0x40, 0x43, + 0x8a, 0xaf, 0x7e, 0xca, 0x6f, 0xd5, 0xcf, 0xd3, 0xa1, + 0x95, 0xce, 0x5a, 0xbe, 0x65, 0x27, 0x2a, 0xf6, 0x07, + 0xad, 0xa1, 0xbe, 0x65, 0xa6, 0xb4, 0xc9, 0xc0, 0x69, + 0x32, 0x34, 0x09, 0x2c, 0x4d, 0x01, 0x8f, 0x17, 0x56, + 0xc6, 0xdb, 0x9d, 0xc8, 0xa6, 0xd8, 0x0b, 0x88, 0x81, + 0x38, 0x61, 0x6b, 0x68, 0x12, 0x62, 0xf9, 0x54, 0xd0, + 0xe7, 0x71, 0x17, 0x48, 0x78, 0x0d, 0x92, 0x29, 0x1d, + 0x86, 0x29, 0x99, 0x72, 0xdb, 0x74, 0x1c, 0xfa, 0x4f, + 0x37, 0xb8, 0xb5, 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, + 0x18, 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, + 0x37, 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, + 0x81, 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, + 0x7c, 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, + 0xfe, 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, + 0x17, 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, + 0xd9, 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, + 0x25, 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, + 0x92, 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, + 0xaa, 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, + 0xff, 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, + 0x36, 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, + 0x8e, 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, + 0x05, 0x4b, 0xe1, 0xfa, 0x72, 0xb0, 0x95, 0x50 }; + uint8_t ct[] = { 0x35, 0x1e, 0x30, 0xd4, 0xd9, 0x10, 0xc5, + 0xdd, 0x5a, 0xd7, 0x83, 0x4c, 0x42, 0x6e, 0x6c, 0x0c, + 0xab, 0x64, 0x86, 0xda, 0x7b, 0x0f, 0xda, 0x4c, 0xd8, + 0x3a, 0xf1, 0xb9, 0x64, 0x71, 0x37, 0xf1, 0xac, 0x43, + 0xb4, 0x34, 0x22, 0x3b, 0x19, 0xbe, 0x07, 0xbd, 0x89, + 0xd1, 0xcc, 0x30, 0x69, 0x44, 0xd3, 0x36, 0x1e, 0xa1, + 0xa2, 0xf8, 0xcd, 0xbd, 0x32, 0x16, 0x55, 0x97, 0x63, + 0x50, 0xd0, 0x0b, 0x80, 0xdd, 0x83, 0x81, 0x20, 0xa7, + 0x75, 0x5c, 0x6d, 0xea, 0x2a, 0xb2, 0xb0, 0xc9, 0x9a, + 0x91, 0x3f, 0x47, 0xda, 0xe2, 0xb8, 0xde, 0xb9, 0xa8, + 0x29, 0xe5, 0x46, 0x9f, 0xf2, 0xe1, 0x87, 0x77, 0x6f, + 0x6f, 0xd0, 0x81, 0xe3, 0x87, 0x1d, 0x11, 0x9a, 0x76, + 0xe2, 0x4c, 0x91, 0x7e, 0xa6, 0x26, 0x48, 0xe0, 0x2e, + 0x90, 0x36, 0x75, 0x64, 0xde, 0x72, 0xae, 0x7e, 0x4f, + 0x0a, 0x42, 0x49, 0xa9, 0xa5, 0xb0, 0xe4, 0x65, 0xa2, + 0xd6, 0xd9, 0xdc, 0x87, 0x84, 0x3b, 0x1b, 0x87, 0x5c, + 0xc9, 0xa3, 0xbe, 0x93, 0xd8, 0xda, 0x8f, 0x56, 0xec, + 0xaf, 0x59, 0x81, 0xfe, 0x93, 0xc2, 0x84, 0x31, 0x8b, + 0x0d, 0xec, 0x7a, 0x3b, 0xa1, 0x08, 0xe2, 0xcb, 0x1a, + 0x61, 0xe9, 0x66, 0xfa, 0x7a, 0xfa, 0x7a, 0xc7, 0xf6, + 0x7f, 0x65, 0xbc, 0x4a, 0x2d, 0xf0, 0x70, 0xd4, 0xe4, + 0x34, 0x84, 0x5f, 0x10, 0x9a, 0xb2, 0xb6, 0x8a, 0xde, + 0x3d, 0xc3, 0x16, 0xca, 0x63, 0x32, 0xa6, 0x28, 0x93, + 0xe0, 0xa7, 0xec, 0x0b, 0x4f, 0xc2, 0x51, 0x91, 0xbf, + 0x2f, 0xf1, 0xb9, 0xf9, 0x81, 0x5e, 0x4b, 0xa8, 0xa9, + 0x9c, 0x64, 0x3b, 0x52, 0x18, 0x04, 0xf7, 0xd5, 0x85, + 0x0d, 0xde, 0x39, 0x52, 0x20, 0x6e, 0xc6, 0xcc, 0xf3, + 0x40, 0xf9, 0xb3, 0x22, 0x0b, 0x30, 0x23, 0xbd, 0xd0, + 0x63, 0x95, 0x6e, 0xa8, 0x33, 0x39, 0x20, 0xfd, 0xe9, + 0x9e, 0x06, 0x75, 0x41, 0x0e, 0x49, 0xef, 0x3b, 0x4d, + 0x3f, 0xb3, 0xdf, 0x51, 0x92, 0xf9, 0x9c, 0xa8, 0x3d, + 0x3b, 0x00, 0x32, 0xde, 0x08, 0xc2, 0x20, 0x77, 0x6a, + 0x58, 0x65, 0xb0, 0xe4, 0xb3, 0xb0, 0xc7, 0x5d, 0xef, + 0xe7, 0x76, 0x2d, 0xff, 0x01, 0x8e, 0xa7, 0xf5, 0xbe, + 0x2b, 0x2f, 0x97, 0x2b, 0x2a, 0x8b, 0xa5, 0x97, 0x0e, + 0x43, 0xbd, 0x6f, 0xdd, 0x63, 0xda, 0xe6, 0x29, 0x78, + 0x4e, 0xc4, 0x8d, 0x61, 0x00, 0x54, 0xee, 0x4e, 0x4b, + 0x5d, 0xbb, 0xf1, 0xfc, 0x2f, 0xa0, 0xb8, 0x30, 0xe9, + 0x4d, 0xcb, 0xb7, 0x01, 0x4e, 0x8a, 0xb4, 0x29, 0xab, + 0x10, 0x0f, 0xc4, 0x8f, 0x83, 0x17, 0x1d, 0x99, 0xfc, + 0x25, 0x8b, 0x7c, 0x2b, 0xa7, 0xc1, 0x76, 0xea, 0xea, + 0xad, 0x37, 0xf8, 0x60, 0xd5, 0x97, 0xa3, 0x1c, 0xe7, + 0x9b, 0x59, 0x47, 0x33, 0xc7, 0x14, 0x1d, 0xf7, 0x91, + 0x51, 0xfc, 0xa9, 0x0c, 0x08, 0x47, 0x8a, 0x5c, 0x6c, + 0x2c, 0xc4, 0x81, 0xd5, 0x1f, 0xfe, 0xce, 0x3c, 0xd7, + 0xd2, 0x58, 0x13, 0x48, 0x82, 0x7a, 0x71, 0xf0, 0x91, + 0x42, 0x8e, 0xbe, 0x38, 0xc9, 0x5a, 0x3f, 0x5c, 0x63, + 0xe0, 0x56, 0xdf, 0xb7, 0xcc, 0x45, 0xa9, 0xb7, 0xc0, + 0x7d, 0x83, 0x4e, 0x7b, 0x20, 0xb9, 0x9e, 0xd2, 0x02, + 0x42, 0x9c, 0x14, 0xbb, 0x85, 0xff, 0xa4, 0x3b, 0x7c, + 0xb6, 0x84, 0x95, 0xcd, 0x75, 0xab, 0x66, 0xd9, 0x64, + 0xd4, 0xca, 0xfe, 0x64, 0xdd, 0x94, 0x04, 0xda, 0xe2, + 0xdc, 0x51, 0x10, 0x61, 0x7f, 0x19, 0x4f, 0xc3, 0xc1, + 0x84, 0xf5, 0x83, 0xcd, 0x0d, 0xef, 0x6d, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// set len_bitsgth to multiple of 8 respectively 128 +void test_set_1_block_size() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 256, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x7c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// inserted bit flip in msg[0] +void test_set_1_invalid() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x99, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp != 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp != 0); + + free(out); +} + +/* + * Functions + */ + +int main(int argc, char * argv[]) { + test_set_1(); + test_set_2(); + test_set_3(); + test_set_4(); + test_set_5(); + test_set_6(); + test_set_1_block_size(); + test_set_1_invalid(); +} diff --git a/lib/test/common/test_eea2.cc b/lib/test/common/test_eea2.cc new file mode 100644 index 000000000..fccaefe70 --- /dev/null +++ b/lib/test/common/test_eea2.cc @@ -0,0 +1,567 @@ +/* + * Includes + */ + +#include +#include +#include + +#include "srslte/common/liblte_security.h" + +/* + * Prototypes + */ + +int32 arrcmp(uint8_t const * const a, uint8_t const * const b, uint32 len) { + uint32 i = 0; + + for (i = 0; i < len; i++) { + if (a[i] != b[i]) { + return a[i] - b[i]; + } + } + return 0; +} + +/* + * Tests + * + * Document Reference: 33.401 V13.1.0 Annex C.1 + */ + +void test_set_1() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_2() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x2b, 0xd6, 0x45, 0x9f, 0x82, 0xc4, 0x40, + 0xe0, 0x95, 0x2c, 0x49, 0x10, 0x48, 0x05, 0xff, 0x48 }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 798, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x7e, 0xc6, 0x12, 0x72, 0x74, 0x3b, 0xf1, + 0x61, 0x47, 0x26, 0x44, 0x6a, 0x6c, 0x38, 0xce, 0xd1, + 0x66, 0xf6, 0xca, 0x76, 0xeb, 0x54, 0x30, 0x04, 0x42, + 0x86, 0x34, 0x6c, 0xef, 0x13, 0x0f, 0x92, 0x92, 0x2b, + 0x03, 0x45, 0x0d, 0x3a, 0x99, 0x75, 0xe5, 0xbd, 0x2e, + 0xa0, 0xeb, 0x55, 0xad, 0x8e, 0x1b, 0x19, 0x9e, 0x3e, + 0xc4, 0x31, 0x60, 0x20, 0xe9, 0xa1, 0xb2, 0x85, 0xe7, + 0x62, 0x79, 0x53, 0x59, 0xb7, 0xbd, 0xfd, 0x39, 0xbe, + 0xf4, 0xb2, 0x48, 0x45, 0x83, 0xd5, 0xaf, 0xe0, 0x82, + 0xae, 0xe6, 0x38, 0xbf, 0x5f, 0xd5, 0xa6, 0x06, 0x19, + 0x39, 0x01, 0xa0, 0x8f, 0x4a, 0xb4, 0x1a, 0xab, 0x9b, + 0x13, 0x48, 0x80 }; + uint8_t ct[] = { 0x59, 0x61, 0x60, 0x53, 0x53, 0xc6, 0x4b, + 0xdc, 0xa1, 0x5b, 0x19, 0x5e, 0x28, 0x85, 0x53, 0xa9, + 0x10, 0x63, 0x25, 0x06, 0xd6, 0x20, 0x0a, 0xa7, 0x90, + 0xc4, 0xc8, 0x06, 0xc9, 0x99, 0x04, 0xcf, 0x24, 0x45, + 0xcc, 0x50, 0xbb, 0x1c, 0xf1, 0x68, 0xa4, 0x96, 0x73, + 0x73, 0x4e, 0x08, 0x1b, 0x57, 0xe3, 0x24, 0xce, 0x52, + 0x59, 0xc0, 0xe7, 0x8d, 0x4c, 0xd9, 0x7b, 0x87, 0x09, + 0x76, 0x50, 0x3c, 0x09, 0x43, 0xf2, 0xcb, 0x5a, 0xe8, + 0xf0, 0x52, 0xc7, 0xb7, 0xd3, 0x92, 0x23, 0x95, 0x87, + 0xb8, 0x95, 0x60, 0x86, 0xbc, 0xab, 0x18, 0x83, 0x60, + 0x42, 0xe2, 0xe6, 0xce, 0x42, 0x43, 0x2a, 0x17, 0x10, + 0x5c, 0x53, 0xd0 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_3() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, 0x8b, + 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, 0xfb }; + uint32_t count = 0x544d49cd; + uint8_t bearer = 0x04; + uint8_t direction = 0; + uint32_t len_bits = 310, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfd, 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, + 0x65, 0x74, 0x50, 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, + 0x36, 0xd2, 0x34, 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, + 0x8e, 0xa9, 0xc4, 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, + 0xf2, 0x64, 0xd0, 0xf2, 0x48, 0x00 }; + uint8_t ct[] = { 0x75, 0x75, 0x0d, 0x37, 0xb4, 0xbb, 0xa2, + 0xa4, 0xde, 0xdb, 0x34, 0x23, 0x5b, 0xd6, 0x8c, 0x66, + 0x45, 0xac, 0xda, 0xac, 0xa4, 0x81, 0x38, 0xa3, 0xb0, + 0xc4, 0x71, 0xe2, 0xa7, 0x04, 0x1a, 0x57, 0x64, 0x23, + 0xd2, 0x92, 0x72, 0x87, 0xf0, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_4() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xaa, 0x1f, 0x95, 0xae, 0xa5, 0x33, 0xbc, + 0xb3, 0x2e, 0xb6, 0x3b, 0xf5, 0x2d, 0x8f, 0x83, 0x1a }; + uint32_t count = 0x72d8c671; + uint8_t bearer = 0x10; + uint8_t direction = 1; + uint32_t len_bits = 1022, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfb, 0x1b, 0x96, 0xc5, 0xc8, 0xba, 0xdf, + 0xb2, 0xe8, 0xe8, 0xed, 0xfd, 0xe7, 0x8e, 0x57, 0xf2, + 0xad, 0x81, 0xe7, 0x41, 0x03, 0xfc, 0x43, 0x0a, 0x53, + 0x4d, 0xcc, 0x37, 0xaf, 0xce, 0xc7, 0x0e, 0x15, 0x17, + 0xbb, 0x06, 0xf2, 0x72, 0x19, 0xda, 0xe4, 0x90, 0x22, + 0xdd, 0xc4, 0x7a, 0x06, 0x8d, 0xe4, 0xc9, 0x49, 0x6a, + 0x95, 0x1a, 0x6b, 0x09, 0xed, 0xbd, 0xc8, 0x64, 0xc7, + 0xad, 0xbd, 0x74, 0x0a, 0xc5, 0x0c, 0x02, 0x2f, 0x30, + 0x82, 0xba, 0xfd, 0x22, 0xd7, 0x81, 0x97, 0xc5, 0xd5, + 0x08, 0xb9, 0x77, 0xbc, 0xa1, 0x3f, 0x32, 0xe6, 0x52, + 0xe7, 0x4b, 0xa7, 0x28, 0x57, 0x60, 0x77, 0xce, 0x62, + 0x8c, 0x53, 0x5e, 0x87, 0xdc, 0x60, 0x77, 0xba, 0x07, + 0xd2, 0x90, 0x68, 0x59, 0x0c, 0x8c, 0xb5, 0xf1, 0x08, + 0x8e, 0x08, 0x2c, 0xfa, 0x0e, 0xc9, 0x61, 0x30, 0x2d, + 0x69, 0xcf, 0x3d, 0x44 }; + uint8_t ct[] = { 0xdf, 0xb4, 0x40, 0xac, 0xb3, 0x77, 0x35, + 0x49, 0xef, 0xc0, 0x46, 0x28, 0xae, 0xb8, 0xd8, 0x15, + 0x62, 0x75, 0x23, 0x0b, 0xdc, 0x69, 0x0d, 0x94, 0xb0, + 0x0d, 0x8d, 0x95, 0xf2, 0x8c, 0x4b, 0x56, 0x30, 0x7f, + 0x60, 0xf4, 0xca, 0x55, 0xeb, 0xa6, 0x61, 0xeb, 0xba, + 0x72, 0xac, 0x80, 0x8f, 0xa8, 0xc4, 0x9e, 0x26, 0x78, + 0x8e, 0xd0, 0x4a, 0x5d, 0x60, 0x6c, 0xb4, 0x18, 0xde, + 0x74, 0x87, 0x8b, 0x9a, 0x22, 0xf8, 0xef, 0x29, 0x59, + 0x0b, 0xc4, 0xeb, 0x57, 0xc9, 0xfa, 0xf7, 0xc4, 0x15, + 0x24, 0xa8, 0x85, 0xb8, 0x97, 0x9c, 0x42, 0x3f, 0x2f, + 0x8f, 0x8e, 0x05, 0x92, 0xa9, 0x87, 0x92, 0x01, 0xbe, + 0x7f, 0xf9, 0x77, 0x7a, 0x16, 0x2a, 0xb8, 0x10, 0xfe, + 0xb3, 0x24, 0xba, 0x74, 0xc4, 0xc1, 0x56, 0xe0, 0x4d, + 0x39, 0x09, 0x72, 0x09, 0x65, 0x3a, 0xc3, 0x3e, 0x5a, + 0x5f, 0x2d, 0x88, 0x64 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_5() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x96, 0x18, 0xae, 0x46, 0x89, 0x1f, 0x86, + 0x57, 0x8e, 0xeb, 0xe9, 0x0e, 0xf7, 0xa1, 0x20, 0x2e }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 1245, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x8d, 0xaa, 0x17, 0xb1, 0xae, 0x05, 0x05, + 0x29, 0xc6, 0x82, 0x7f, 0x28, 0xc0, 0xef, 0x6a, 0x12, + 0x42, 0xe9, 0x3f, 0x8b, 0x31, 0x4f, 0xb1, 0x8a, 0x77, + 0xf7, 0x90, 0xae, 0x04, 0x9f, 0xed, 0xd6, 0x12, 0x26, + 0x7f, 0xec, 0xae, 0xfc, 0x45, 0x01, 0x74, 0xd7, 0x6d, + 0x9f, 0x9a, 0xa7, 0x75, 0x5a, 0x30, 0xcd, 0x90, 0xa9, + 0xa5, 0x87, 0x4b, 0xf4, 0x8e, 0xaf, 0x70, 0xee, 0xa3, + 0xa6, 0x2a, 0x25, 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, + 0x8b, 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, + 0xfb, 0x54, 0x4d, 0x49, 0xcd, 0x49, 0x72, 0x0e, 0x21, + 0x9d, 0xbf, 0x8b, 0xbe, 0xd3, 0x39, 0x04, 0xe1, 0xfd, + 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, 0x65, 0x74, 0x50, + 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, 0x36, 0xd2, 0x34, + 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, 0x8e, 0xa9, 0xc4, + 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, 0xf2, 0x64, 0xd0, + 0xf2, 0x48, 0x41, 0xd6, 0x46, 0x5f, 0x09, 0x96, 0xff, + 0x84, 0xe6, 0x5f, 0xc5, 0x17, 0xc5, 0x3e, 0xfc, 0x33, + 0x63, 0xc3, 0x84, 0x92, 0xa8 }; + uint8_t ct[] = { 0x91, 0x9c, 0x8c, 0x33, 0xd6, 0x67, 0x89, + 0x70, 0x3d, 0x05, 0xa0, 0xd7, 0xce, 0x82, 0xa2, 0xae, + 0xac, 0x4e, 0xe7, 0x6c, 0x0f, 0x4d, 0xa0, 0x50, 0x33, + 0x5e, 0x8a, 0x84, 0xe7, 0x89, 0x7b, 0xa5, 0xdf, 0x2f, + 0x36, 0xbd, 0x51, 0x3e, 0x3d, 0x0c, 0x85, 0x78, 0xc7, + 0xa0, 0xfc, 0xf0, 0x43, 0xe0, 0x3a, 0xa3, 0xa3, 0x9f, + 0xba, 0xad, 0x7d, 0x15, 0xbe, 0x07, 0x4f, 0xaa, 0x5d, + 0x90, 0x29, 0xf7, 0x1f, 0xb4, 0x57, 0xb6, 0x47, 0x83, + 0x47, 0x14, 0xb0, 0xe1, 0x8f, 0x11, 0x7f, 0xca, 0x10, + 0x67, 0x79, 0x45, 0x09, 0x6c, 0x8c, 0x5f, 0x32, 0x6b, + 0xa8, 0xd6, 0x09, 0x5e, 0xb2, 0x9c, 0x3e, 0x36, 0xcf, + 0x24, 0x5d, 0x16, 0x22, 0xaa, 0xfe, 0x92, 0x1f, 0x75, + 0x66, 0xc4, 0xf5, 0xd6, 0x44, 0xf2, 0xf1, 0xfc, 0x0e, + 0xc6, 0x84, 0xdd, 0xb2, 0x13, 0x49, 0x74, 0x76, 0x22, + 0xe2, 0x09, 0x29, 0x5d, 0x27, 0xff, 0x3f, 0x95, 0x62, + 0x33, 0x71, 0xd4, 0x9b, 0x14, 0x7c, 0x0a, 0xf4, 0x86, + 0x17, 0x1f, 0x22, 0xcd, 0x04, 0xb1, 0xcb, 0xeb, 0x26, + 0x58, 0x22, 0x3e, 0x69, 0x38 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_6() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x54, 0xf4, 0xe2, 0xe0, 0x4c, 0x83, 0x78, + 0x6e, 0xec, 0x8f, 0xb5, 0xab, 0xe8, 0xe3, 0x65, 0x66 }; + uint32_t count = 0xaca4f50f; + uint8_t bearer = 0x0b; + uint8_t direction = 0; + uint32_t len_bits = 3861, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x40, 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, + 0xfb, 0x42, 0x86, 0xb2, 0x99, 0x78, 0x3d, 0xaf, 0x44, + 0x2c, 0x09, 0x9f, 0x7a, 0xb0, 0xf5, 0x8d, 0x5c, 0x8e, + 0x46, 0xb1, 0x04, 0xf0, 0x8f, 0x01, 0xb4, 0x1a, 0xb4, + 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x36, 0xbd, 0x1a, + 0x3d, 0x90, 0xdc, 0x3a, 0x41, 0xb4, 0x6d, 0x51, 0x67, + 0x2a, 0xc4, 0xc9, 0x66, 0x3a, 0x2b, 0xe0, 0x63, 0xda, + 0x4b, 0xc8, 0xd2, 0x80, 0x8c, 0xe3, 0x3e, 0x2c, 0xcc, + 0xbf, 0xc6, 0x34, 0xe1, 0xb2, 0x59, 0x06, 0x08, 0x76, + 0xa0, 0xfb, 0xb5, 0xa4, 0x37, 0xeb, 0xcc, 0x8d, 0x31, + 0xc1, 0x9e, 0x44, 0x54, 0x31, 0x87, 0x45, 0xe3, 0xfa, + 0x16, 0xbb, 0x11, 0xad, 0xae, 0x24, 0x88, 0x79, 0xfe, + 0x52, 0xdb, 0x25, 0x43, 0xe5, 0x3c, 0xf4, 0x45, 0xd3, + 0xd8, 0x28, 0xce, 0x0b, 0xf5, 0xc5, 0x60, 0x59, 0x3d, + 0x97, 0x27, 0x8a, 0x59, 0x76, 0x2d, 0xd0, 0xc2, 0xc9, + 0xcd, 0x68, 0xd4, 0x49, 0x6a, 0x79, 0x25, 0x08, 0x61, + 0x40, 0x14, 0xb1, 0x3b, 0x6a, 0xa5, 0x11, 0x28, 0xc1, + 0x8c, 0xd6, 0xa9, 0x0b, 0x87, 0x97, 0x8c, 0x2f, 0xf1, + 0xca, 0xbe, 0x7d, 0x9f, 0x89, 0x8a, 0x41, 0x1b, 0xfd, + 0xb8, 0x4f, 0x68, 0xf6, 0x72, 0x7b, 0x14, 0x99, 0xcd, + 0xd3, 0x0d, 0xf0, 0x44, 0x3a, 0xb4, 0xa6, 0x66, 0x53, + 0x33, 0x0b, 0xcb, 0xa1, 0x10, 0x5e, 0x4c, 0xec, 0x03, + 0x4c, 0x73, 0xe6, 0x05, 0xb4, 0x31, 0x0e, 0xaa, 0xad, + 0xcf, 0xd5, 0xb0, 0xca, 0x27, 0xff, 0xd8, 0x9d, 0x14, + 0x4d, 0xf4, 0x79, 0x27, 0x59, 0x42, 0x7c, 0x9c, 0xc1, + 0xf8, 0xcd, 0x8c, 0x87, 0x20, 0x23, 0x64, 0xb8, 0xa6, + 0x87, 0x95, 0x4c, 0xb0, 0x5a, 0x8d, 0x4e, 0x2d, 0x99, + 0xe7, 0x3d, 0xb1, 0x60, 0xde, 0xb1, 0x80, 0xad, 0x08, + 0x41, 0xe9, 0x67, 0x41, 0xa5, 0xd5, 0x9f, 0xe4, 0x18, + 0x9f, 0x15, 0x42, 0x00, 0x26, 0xfe, 0x4c, 0xd1, 0x21, + 0x04, 0x93, 0x2f, 0xb3, 0x8f, 0x73, 0x53, 0x40, 0x43, + 0x8a, 0xaf, 0x7e, 0xca, 0x6f, 0xd5, 0xcf, 0xd3, 0xa1, + 0x95, 0xce, 0x5a, 0xbe, 0x65, 0x27, 0x2a, 0xf6, 0x07, + 0xad, 0xa1, 0xbe, 0x65, 0xa6, 0xb4, 0xc9, 0xc0, 0x69, + 0x32, 0x34, 0x09, 0x2c, 0x4d, 0x01, 0x8f, 0x17, 0x56, + 0xc6, 0xdb, 0x9d, 0xc8, 0xa6, 0xd8, 0x0b, 0x88, 0x81, + 0x38, 0x61, 0x6b, 0x68, 0x12, 0x62, 0xf9, 0x54, 0xd0, + 0xe7, 0x71, 0x17, 0x48, 0x78, 0x0d, 0x92, 0x29, 0x1d, + 0x86, 0x29, 0x99, 0x72, 0xdb, 0x74, 0x1c, 0xfa, 0x4f, + 0x37, 0xb8, 0xb5, 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, + 0x18, 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, + 0x37, 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, + 0x81, 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, + 0x7c, 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, + 0xfe, 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, + 0x17, 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, + 0xd9, 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, + 0x25, 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, + 0x92, 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, + 0xaa, 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, + 0xff, 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, + 0x36, 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, + 0x8e, 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, + 0x05, 0x4b, 0xe1, 0xfa, 0x72, 0x00, 0xb0, 0x90, 0x00 }; + uint8_t ct[] = { 0x5c, 0xb7, 0x2c, 0x6e, 0xdc, 0x87, 0x8f, + 0x15, 0x66, 0xe1, 0x02, 0x53, 0xaf, 0xc3, 0x64, 0xc9, + 0xfa, 0x54, 0x0d, 0x91, 0x4d, 0xb9, 0x4c, 0xbe, 0xe2, + 0x75, 0xd0, 0x91, 0x7c, 0xa6, 0xaf, 0x0d, 0x77, 0xac, + 0xb4, 0xef, 0x3b, 0xbe, 0x1a, 0x72, 0x2b, 0x2e, 0xf5, + 0xbd, 0x1d, 0x4b, 0x8e, 0x2a, 0xa5, 0x02, 0x4e, 0xc1, + 0x38, 0x8a, 0x20, 0x1e, 0x7b, 0xce, 0x79, 0x20, 0xae, + 0xc6, 0x15, 0x89, 0x5f, 0x76, 0x3a, 0x55, 0x64, 0xdc, + 0xc4, 0xc4, 0x82, 0xa2, 0xee, 0x1d, 0x8b, 0xfe, 0xcc, + 0x44, 0x98, 0xec, 0xa8, 0x3f, 0xbb, 0x75, 0xf9, 0xab, + 0x53, 0x0e, 0x0d, 0xaf, 0xbe, 0xde, 0x2f, 0xa5, 0x89, + 0x5b, 0x82, 0x99, 0x1b, 0x62, 0x77, 0xc5, 0x29, 0xe0, + 0xf2, 0x52, 0x9d, 0x7f, 0x79, 0x60, 0x6b, 0xe9, 0x67, + 0x06, 0x29, 0x6d, 0xed, 0xfa, 0x9d, 0x74, 0x12, 0xb6, + 0x16, 0x95, 0x8c, 0xb5, 0x63, 0xc6, 0x78, 0xc0, 0x28, + 0x25, 0xc3, 0x0d, 0x0a, 0xee, 0x77, 0xc4, 0xc1, 0x46, + 0xd2, 0x76, 0x54, 0x12, 0x42, 0x1a, 0x80, 0x8d, 0x13, + 0xce, 0xc8, 0x19, 0x69, 0x4c, 0x75, 0xad, 0x57, 0x2e, + 0x9b, 0x97, 0x3d, 0x94, 0x8b, 0x81, 0xa9, 0x33, 0x7c, + 0x3b, 0x2a, 0x17, 0x19, 0x2e, 0x22, 0xc2, 0x06, 0x9f, + 0x7e, 0xd1, 0x16, 0x2a, 0xf4, 0x4c, 0xde, 0xa8, 0x17, + 0x60, 0x36, 0x65, 0xe8, 0x07, 0xce, 0x40, 0xc8, 0xe0, + 0xdd, 0x9d, 0x63, 0x94, 0xdc, 0x6e, 0x31, 0x15, 0x3f, + 0xe1, 0x95, 0x5c, 0x47, 0xaf, 0xb5, 0x1f, 0x26, 0x17, + 0xee, 0x0c, 0x5e, 0x3b, 0x8e, 0xf1, 0xad, 0x75, 0x74, + 0xed, 0x34, 0x3e, 0xdc, 0x27, 0x43, 0xcc, 0x94, 0xc9, + 0x90, 0xe1, 0xf1, 0xfd, 0x26, 0x42, 0x53, 0xc1, 0x78, + 0xde, 0xa7, 0x39, 0xc0, 0xbe, 0xfe, 0xeb, 0xcd, 0x9f, + 0x9b, 0x76, 0xd4, 0x9c, 0x10, 0x15, 0xc9, 0xfe, 0xcf, + 0x50, 0xe5, 0x3b, 0x8b, 0x52, 0x04, 0xdb, 0xcd, 0x3e, + 0xed, 0x86, 0x38, 0x55, 0xda, 0xbc, 0xdc, 0xc9, 0x4b, + 0x31, 0xe3, 0x18, 0x02, 0x15, 0x68, 0x85, 0x5c, 0x8b, + 0x9e, 0x52, 0xa9, 0x81, 0x95, 0x7a, 0x11, 0x28, 0x27, + 0xf9, 0x78, 0xba, 0x96, 0x0f, 0x14, 0x47, 0x91, 0x1b, + 0x31, 0x7b, 0x55, 0x11, 0xfb, 0xcc, 0x7f, 0xb1, 0x3a, + 0xc1, 0x53, 0xdb, 0x74, 0x25, 0x11, 0x17, 0xe4, 0x86, + 0x1e, 0xb9, 0xe8, 0x3b, 0xff, 0xff, 0xc4, 0xeb, 0x77, + 0x55, 0x57, 0x90, 0x38, 0xe5, 0x79, 0x24, 0xb1, 0xf7, + 0x8b, 0x3e, 0x1a, 0xd9, 0x0b, 0xab, 0x2a, 0x07, 0x87, + 0x1b, 0x72, 0xdb, 0x5e, 0xef, 0x96, 0xc3, 0x34, 0x04, + 0x49, 0x66, 0xdb, 0x0c, 0x37, 0xca, 0xfd, 0x1a, 0x89, + 0xe5, 0x64, 0x6a, 0x35, 0x80, 0xeb, 0x64, 0x65, 0xf1, + 0x21, 0xdc, 0xe9, 0xcb, 0x88, 0xd8, 0x5b, 0x96, 0xcf, + 0x23, 0xcc, 0xcc, 0xd4, 0x28, 0x07, 0x67, 0xbe, 0xe8, + 0xee, 0xb2, 0x3d, 0x86, 0x52, 0x46, 0x1d, 0xb6, 0x49, + 0x31, 0x03, 0x00, 0x3b, 0xaf, 0x89, 0xf5, 0xe1, 0x82, + 0x61, 0xea, 0x43, 0xc8, 0x4a, 0x92, 0xeb, 0xff, 0xff, + 0xe4, 0x90, 0x9d, 0xc4, 0x6c, 0x51, 0x92, 0xf8, 0x25, + 0xf7, 0x70, 0x60, 0x0b, 0x96, 0x02, 0xc5, 0x57, 0xb5, + 0xf8, 0xb4, 0x31, 0xa7, 0x9d, 0x45, 0x97, 0x7d, 0xd9, + 0xc4, 0x1b, 0x86, 0x3d, 0xa9, 0xe1, 0x42, 0xe9, 0x00, + 0x20, 0xcf, 0xd0, 0x74, 0xd6, 0x92, 0x7b, 0x7a, 0xb3, + 0xb6, 0x72, 0x5d, 0x1a, 0x6f, 0x3f, 0x98, 0xb9, 0xc9, + 0xda, 0xa8, 0x98, 0x2a, 0xff, 0x06, 0x78, 0x28, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// set len_bitsgth to multiple of 8 respectively 128 +void test_set_1_block_size() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 256, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// inserted bit flip in msg[0] +void test_set_1_invalid() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x99, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp != 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp != 0); + + free(out); +} + +/* + * Functions + */ + +int main(int argc, char * argv[]) { + test_set_1(); + test_set_2(); + test_set_3(); + test_set_4(); + test_set_5(); + test_set_6(); + test_set_1_block_size(); + test_set_1_invalid(); +} diff --git a/srsenb/hdr/upper/pdcp.h b/srsenb/hdr/upper/pdcp.h index 228490312..8c5b05275 100644 --- a/srsenb/hdr/upper/pdcp.h +++ b/srsenb/hdr/upper/pdcp.h @@ -67,8 +67,9 @@ private: uint16_t rnti; srsenb::rlc_interface_pdcp *rlc; // rlc_interface_pdcp - void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu); - }; + void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu); + bool rb_is_um(uint32_t lcid); + }; class user_interface_gtpu : public srsue::gw_interface_pdcp { diff --git a/srsenb/hdr/upper/rlc.h b/srsenb/hdr/upper/rlc.h index abbf99516..b937cd216 100644 --- a/srsenb/hdr/upper/rlc.h +++ b/srsenb/hdr/upper/rlc.h @@ -54,6 +54,7 @@ public: // rlc_interface_pdcp void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); + bool rb_is_um(uint16_t rnti, uint32_t lcid); std::string get_rb_name(uint32_t lcid); // rlc_interface_mac diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index dc2c0f742..97741a670 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -267,7 +267,7 @@ public: uint32_t cqi_idx; bool cqi_allocated; int cqi_sched_sf_idx; - bool cqi_sched_prb_idx; + int cqi_sched_prb_idx; int get_drbid_config(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb, int drbid); }; diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index ea24b8908..73c217a74 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -680,8 +680,7 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]) for(uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { h->reset(tb); } - Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d, L=%d, nof_candidates=%d\n", - rnti, h->get_id(), aggr_level, user->get_locations(current_cfi, sf_idx)->nof_loc[aggr_level] ); + Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id()); } } } @@ -826,7 +825,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched { ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); bool is_newtx = h->is_empty(0); - bool needs_pdcch = h->is_adaptive_retx() && !is_rar; + bool needs_pdcch = !h->is_adaptive_retx() && !is_rar; // Set number of retx if (is_newtx) { diff --git a/srsenb/src/mac/scheduler_harq.cc b/srsenb/src/mac/scheduler_harq.cc index cbeb0d550..6e1596850 100644 --- a/srsenb/src/mac/scheduler_harq.cc +++ b/srsenb/src/mac/scheduler_harq.cc @@ -200,13 +200,13 @@ ul_harq_proc::ul_alloc_t ul_harq_proc::get_alloc() void ul_harq_proc::set_alloc(ul_harq_proc::ul_alloc_t alloc) { - is_adaptive = true; + is_adaptive = false; memcpy(&allocation, &alloc, sizeof(ul_alloc_t)); } void ul_harq_proc::same_alloc() { - is_adaptive = false; + is_adaptive = true; } bool ul_harq_proc::is_adaptive_retx() diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 5ced3631a..ab3fc10b9 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -334,8 +334,8 @@ void sched_ue::set_dl_pmi(uint32_t tti, uint32_t pmi) void sched_ue::set_dl_cqi(uint32_t tti, uint32_t cqi) { - dl_cqi = cqi; - dl_cqi_tti = tti; + dl_cqi = cqi; + dl_cqi_tti = tti; } void sched_ue::set_dl_ant_info(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *d) @@ -371,10 +371,10 @@ void sched_ue::tpc_dec() { // Generates a Format1 grant -int sched_ue::generate_format1(dl_harq_proc *h, - sched_interface::dl_sched_data_t *data, - uint32_t tti, - uint32_t cfi) +int sched_ue::generate_format1(dl_harq_proc *h, + sched_interface::dl_sched_data_t *data, + uint32_t tti, + uint32_t cfi) { srslte_ra_dl_dci_t *dci = &data->dci; bzero(dci, sizeof(srslte_ra_dl_dci_t)); @@ -586,7 +586,7 @@ int sched_ue::generate_format0(ul_harq_proc *h, int tbs = 0; ul_harq_proc::ul_alloc_t allocation = h->get_alloc(); - + bool is_newtx = true; if (h->get_rar_mcs(&mcs)) { tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; @@ -606,9 +606,9 @@ int sched_ue::generate_format0(ul_harq_proc *h, h->new_tx(tti, mcs, tbs); - } else { - is_newtx = false; + } else { h->new_retx(0, tti, &mcs, NULL); + is_newtx = false; tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; } diff --git a/srsenb/src/upper/pdcp.cc b/srsenb/src/upper/pdcp.cc index 027f04909..afd41976f 100644 --- a/srsenb/src/upper/pdcp.cc +++ b/srsenb/src/upper/pdcp.cc @@ -124,6 +124,10 @@ void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* s rlc->write_sdu(rnti, lcid, sdu); } +bool pdcp::user_interface_rlc::rb_is_um(uint32_t lcid) { + return rlc->rb_is_um(rnti, lcid); +} + void pdcp::user_interface_rrc::write_pdu(uint32_t lcid, srslte::byte_buffer_t* pdu) { rrc->write_pdu(rnti, lcid, pdu); diff --git a/srsenb/src/upper/rlc.cc b/srsenb/src/upper/rlc.cc index 6147597e3..fff674112 100644 --- a/srsenb/src/upper/rlc.cc +++ b/srsenb/src/upper/rlc.cc @@ -160,6 +160,14 @@ void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) } } +bool rlc::rb_is_um(uint16_t rnti, uint32_t lcid) { + if (users.count(rnti)) { + return users[rnti].rlc->rb_is_um(lcid); + } else { + return false; + } +} + void rlc::user_interface::max_retx_attempted() { rrc->max_retx_attempted(rnti); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 843c3e350..8d8d9773e 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -699,10 +699,19 @@ rrc::ue::ue() { parent = NULL; set_activity(); - sr_allocated = false; has_tmsi = false; connect_notified = false; transaction_id = 0; + sr_allocated = false; + sr_sched_sf_idx = 0; + sr_sched_prb_idx = 0; + sr_N_pucch = 0; + sr_I = 0; + cqi_allocated = false; + cqi_pucch = 0; + cqi_idx = 0; + cqi_sched_sf_idx = 0; + cqi_sched_prb_idx = 0; state = RRC_STATE_IDLE; } diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index 521018d73..46c3fb0d0 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -259,7 +259,7 @@ private: memcpy(&cur_grant, &grant, sizeof(Tgrant)); // If data has not yet been successfully decoded - if (!ack || (grant.rv[tid]==0 && grant.phy_grant.dl.mcs[tid].idx < 29)) { + if (!ack) { // Instruct the PHY To combine the received data and attempt to decode it if (pid == HARQ_BCCH_PID) { diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h index d19f668bf..b1b649de7 100644 --- a/srsue/hdr/mac/mac.h +++ b/srsue/hdr/mac/mac.h @@ -79,7 +79,8 @@ public: void pcch_stop_rx(); void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); void reconfiguration(); - void reset(); + void reset(); + void wait_uplink(); /******** set/get MAC configuration ****************/ void set_config(mac_cfg_t *mac_cfg); @@ -88,8 +89,12 @@ public: void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index); void set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sr_cfg); void set_contention_id(uint64_t uecri); - + + void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask); + void start_cont_ho(); + void get_rntis(ue_rnti_t *rntis); + void set_ho_rnti(uint16_t crnti, uint16_t target_pci); void start_pcap(srslte::mac_pcap* pcap); diff --git a/srsue/hdr/mac/proc_ra.h b/srsue/hdr/mac/proc_ra.h index 2bd2dd807..de8a0671d 100644 --- a/srsue/hdr/mac/proc_ra.h +++ b/srsue/hdr/mac/proc_ra.h @@ -43,164 +43,175 @@ namespace srsue { class ra_proc : public srslte::timer_callback { - public: - ra_proc() : rar_pdu_msg(20) { - bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t)); - pcap = NULL; - backoff_interval_start = 0; - backoff_inteval = 0; - received_target_power_dbm = 0; - ra_rnti = 0; - current_ta = 0; - state = IDLE; - last_msg3_group = RA_GROUP_A; - msg3_transmitted = false; - first_rar_received = false; - phy_h = NULL; - log_h = NULL; - mac_cfg = NULL; - mux_unit = NULL; - demux_unit = NULL; - rrc = NULL; - transmitted_contention_id = 0; - transmitted_crnti = 0; - pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; - started_by_pdcch = false; - rar_grant_nbytes = 0; - rar_grant_tti = 0; - msg3_flushed = false; - - time_alignment_timer = NULL; - contention_resolution_timer = NULL; - }; - - ~ra_proc(); - - void init(phy_interface_mac *phy_h, - rrc_interface_mac *rrc_, - srslte::log *log_h, - mac_interface_rrc::ue_rnti_t *rntis, - mac_interface_rrc::mac_cfg_t *mac_cfg, - srslte::timers::timer* time_alignment_timer_, - srslte::timers::timer* contention_resolution_timer_, - mux *mux_unit, - demux *demux_unit); - void reset(); - void start_pdcch_order(); - void start_mac_order(uint32_t msg_len_bits = 56); - void step(uint32_t tti); - bool is_successful(); - bool is_response_error(); - bool is_contention_resolution(); - void harq_retx(); - bool is_error(); - bool in_progress(); - void pdcch_to_crnti(bool contains_uplink_grant); - void timer_expired(uint32_t timer_id); - - void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action); - void tb_decoded_ok(); - - void start_pcap(srslte::mac_pcap* pcap); +public: + ra_proc() : rar_pdu_msg(20) { + bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t)); + pcap = NULL; + backoff_interval_start = 0; + backoff_inteval = 0; + received_target_power_dbm = 0; + ra_rnti = 0; + current_ta = 0; + state = IDLE; + last_msg3_group = RA_GROUP_A; + msg3_transmitted = false; + first_rar_received = false; + phy_h = NULL; + log_h = NULL; + mac_cfg = NULL; + mux_unit = NULL; + demux_unit = NULL; + rrc = NULL; + transmitted_contention_id = 0; + transmitted_crnti = 0; + pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; + started_by_pdcch = false; + rar_grant_nbytes = 0; + rar_grant_tti = 0; + msg3_flushed = false; + + noncontention_enabled = false; + next_preamble_idx = 0; + next_prach_mask = 0; + + time_alignment_timer = NULL; + contention_resolution_timer = NULL; + }; + + ~ra_proc(); + + void init(phy_interface_mac *phy_h, + rrc_interface_mac *rrc_, + srslte::log *log_h, + mac_interface_rrc::ue_rnti_t *rntis, + mac_interface_rrc::mac_cfg_t *mac_cfg, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, + mux *mux_unit, + demux *demux_unit); + void reset(); + void start_pdcch_order(); + void start_mac_order(uint32_t msg_len_bits = 56, bool is_ho = false); + void step(uint32_t tti); + bool is_successful(); + bool is_response_error(); + bool is_contention_resolution(); + void harq_retx(); + bool is_error(); + bool in_progress(); + void pdcch_to_crnti(bool contains_uplink_grant); + void timer_expired(uint32_t timer_id); + + void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action); + void tb_decoded_ok(); + + void start_noncont(uint32_t preamble_index, uint32_t prach_mask); + + void start_pcap(srslte::mac_pcap* pcap); private: - static bool uecrid_callback(void *arg, uint64_t uecri); - - bool contention_resolution_id_received(uint64_t uecri); - void process_timeadv_cmd(uint32_t ta_cmd); - void step_initialization(); - void step_resource_selection(); - void step_preamble_transmission(); - void step_pdcch_setup(); - void step_response_reception(); - void step_response_error(); - void step_backoff_wait(); - void step_contention_resolution(); - void step_completition(); - - // Buffer to receive RAR PDU - static const uint32_t MAX_RAR_PDU_LEN = 2048; - uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; - srslte::rar_pdu rar_pdu_msg; - - // Random Access parameters provided by higher layers defined in 5.1.1 - uint32_t configIndex; - uint32_t nof_preambles; - uint32_t nof_groupA_preambles; - uint32_t nof_groupB_preambles; - uint32_t messagePowerOffsetGroupB; - uint32_t messageSizeGroupA; - uint32_t responseWindowSize; - uint32_t powerRampingStep; - uint32_t preambleTransMax; - uint32_t iniReceivedTargetPower; - int delta_preamble_db; - uint32_t contentionResolutionTimer; - uint32_t maskIndex; - int preambleIndex; - uint32_t new_ra_msg_len; - - // Internal variables - uint32_t preambleTransmissionCounter; - uint32_t backoff_param_ms; - uint32_t sel_maskIndex; - uint32_t sel_preamble; - uint32_t backoff_interval_start; - uint32_t backoff_inteval; - int received_target_power_dbm; - uint32_t ra_rnti; - uint32_t current_ta; - - srslte_softbuffer_rx_t softbuffer_rar; - - enum { - IDLE = 0, - INITIALIZATION, // Section 5.1.1 - RESOURCE_SELECTION, // Section 5.1.2 - PREAMBLE_TRANSMISSION, // Section 5.1.3 - PDCCH_SETUP, - RESPONSE_RECEPTION, // Section 5.1.4 - RESPONSE_ERROR, - BACKOFF_WAIT, - CONTENTION_RESOLUTION, // Section 5.1.5 - COMPLETION, // Section 5.1.6 - COMPLETION_DONE, - RA_PROBLEM // Section 5.1.5 last part - } state; - - typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; - - ra_group_t last_msg3_group; - bool msg3_transmitted; - bool first_rar_received; - void read_params(); - - phy_interface_mac *phy_h; - srslte::log *log_h; - mux *mux_unit; - demux *demux_unit; - srslte::mac_pcap *pcap; - rrc_interface_mac *rrc; - - srslte::timers::timer *time_alignment_timer; - srslte::timers::timer *contention_resolution_timer; - - mac_interface_rrc::ue_rnti_t *rntis; - mac_interface_rrc::mac_cfg_t *mac_cfg; - - uint64_t transmitted_contention_id; - uint16_t transmitted_crnti; - - enum { - PDCCH_CRNTI_NOT_RECEIVED = 0, - PDCCH_CRNTI_UL_GRANT, - PDCCH_CRNTI_DL_GRANT - } pdcch_to_crnti_received; - - bool started_by_pdcch; - uint32_t rar_grant_nbytes; - uint32_t rar_grant_tti; - bool msg3_flushed; - bool rar_received; + static bool uecrid_callback(void *arg, uint64_t uecri); + + bool contention_resolution_id_received(uint64_t uecri); + void process_timeadv_cmd(uint32_t ta_cmd); + void step_initialization(); + void step_resource_selection(); + void step_preamble_transmission(); + void step_pdcch_setup(); + void step_response_reception(); + void step_response_error(); + void step_backoff_wait(); + void step_contention_resolution(); + void step_completition(); + + // Buffer to receive RAR PDU + static const uint32_t MAX_RAR_PDU_LEN = 2048; + uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; + srslte::rar_pdu rar_pdu_msg; + + // Random Access parameters provided by higher layers defined in 5.1.1 + uint32_t configIndex; + uint32_t nof_preambles; + uint32_t nof_groupA_preambles; + uint32_t nof_groupB_preambles; + uint32_t messagePowerOffsetGroupB; + uint32_t messageSizeGroupA; + uint32_t responseWindowSize; + uint32_t powerRampingStep; + uint32_t preambleTransMax; + uint32_t iniReceivedTargetPower; + int delta_preamble_db; + uint32_t contentionResolutionTimer; + uint32_t maskIndex; + int preambleIndex; + uint32_t new_ra_msg_len; + + bool noncontention_enabled; + uint32_t next_preamble_idx; + uint32_t next_prach_mask; + + // Internal variables + uint32_t preambleTransmissionCounter; + uint32_t backoff_param_ms; + uint32_t sel_maskIndex; + uint32_t sel_preamble; + uint32_t backoff_interval_start; + uint32_t backoff_inteval; + int received_target_power_dbm; + uint32_t ra_rnti; + uint32_t current_ta; + + srslte_softbuffer_rx_t softbuffer_rar; + + enum { + IDLE = 0, + INITIALIZATION, // Section 5.1.1 + RESOURCE_SELECTION, // Section 5.1.2 + PREAMBLE_TRANSMISSION, // Section 5.1.3 + PDCCH_SETUP, + RESPONSE_RECEPTION, // Section 5.1.4 + RESPONSE_ERROR, + BACKOFF_WAIT, + CONTENTION_RESOLUTION, // Section 5.1.5 + COMPLETION, // Section 5.1.6 + COMPLETION_DONE, + RA_PROBLEM // Section 5.1.5 last part + } state; + + typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; + + ra_group_t last_msg3_group; + bool msg3_transmitted; + bool first_rar_received; + void read_params(); + + phy_interface_mac *phy_h; + srslte::log *log_h; + mux *mux_unit; + demux *demux_unit; + srslte::mac_pcap *pcap; + rrc_interface_mac *rrc; + + srslte::timers::timer *time_alignment_timer; + srslte::timers::timer *contention_resolution_timer; + + mac_interface_rrc::ue_rnti_t *rntis; + mac_interface_rrc::mac_cfg_t *mac_cfg; + + uint64_t transmitted_contention_id; + uint16_t transmitted_crnti; + + enum { + PDCCH_CRNTI_NOT_RECEIVED = 0, + PDCCH_CRNTI_UL_GRANT, + PDCCH_CRNTI_DL_GRANT + } pdcch_to_crnti_received; + + bool ra_is_ho; + bool started_by_pdcch; + uint32_t rar_grant_nbytes; + uint32_t rar_grant_tti; + bool msg3_flushed; + bool rar_received; }; } // namespace srsue diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index 72b691c00..bd38fca97 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -205,23 +205,26 @@ private: *ack = false; } } - set_harq_feedback(*ack); + harq_feedback = *ack; } - uint32_t max_retx; - if (is_msg3) { - max_retx = harq_entity->params->max_harq_msg3_tx; - } else { - max_retx = harq_entity->params->max_harq_tx; + // Reset HARQ process if TB has changed + if (harq_feedback && has_grant() && grant) { + if (grant->n_bytes[0] != cur_grant.n_bytes[0] && cur_grant.n_bytes[0] > 0) { + Debug("UL %d: Reset due to change of grant size last_grant=%d, new_grant=%d\n", + pid, cur_grant.n_bytes[0], grant->n_bytes[0]); + reset(); + } } // Receive and route HARQ feedbacks if (grant) { - if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && ack) || + if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && harq_feedback) || (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || grant->is_from_rar) { // New transmission + reset(); // Uplink grant in a RAR if (grant->is_from_rar) { @@ -245,25 +248,13 @@ private: } } else if (has_grant()) { // Adaptive Re-TX - if (current_tx_nb >= max_retx) { - Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); - reset(); - action->expect_ack = false; - } else { - generate_retx(tti_tx, grant, action); - } + generate_retx(tti_tx, grant, action); } else { Warning("UL %d: Received retransmission but no previous grant available for this PID.\n", pid); } } else if (has_grant()) { // Non-Adaptive Re-Tx - if (current_tx_nb >= max_retx) { - Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); - reset(); - action->expect_ack = false; - } else { - generate_retx(tti_tx, action); - } + generate_retx(tti_tx, action); } if (harq_entity->pcap && grant) { if (grant->is_from_rar) { @@ -273,18 +264,6 @@ private: } } - void set_harq_feedback(bool ack) - { - harq_feedback = ack; - // UL packet successfully delivered - if (ack) { - Info("UL %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid); - reset(); - } else { - Info("UL %d: HARQ = NACK for UL transmission\n", pid); - } - } - uint32_t get_rv() { int rv_of_irv[4] = {0, 2, 3, 1}; @@ -326,24 +305,43 @@ private: void generate_retx(uint32_t tti_tx, Tgrant *grant, Taction *action) { + uint32_t max_retx; + if (is_msg3) { + max_retx = harq_entity->params->max_harq_msg3_tx; + } else { + max_retx = harq_entity->params->max_harq_tx; + } + + if (current_tx_nb >= max_retx) { + Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); + reset(); + action->expect_ack = false; + return; + } + int irv_of_rv[4] = {0, 3, 1, 2}; + + // HARQ entity requests an adaptive transmission if (grant) { - // HARQ entity requests an adaptive transmission if (grant->rv) { current_irv = irv_of_rv[grant->rv[0]%4]; } + + Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d, HI=%s, ndi=%d, prev_ndi=%d\n", + pid, current_tx_nb, get_rv(), grant->n_bytes[0], harq_feedback?"ACK":"NACK", grant->ndi[0], cur_grant.ndi[0]); + memcpy(&cur_grant, grant, sizeof(Tgrant)); harq_feedback = false; - Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n", - pid, current_tx_nb, get_rv(), grant->n_bytes[0]); + + generate_tx(tti_tx, action); + + // HARQ entity requests a non-adaptive transmission + } else if (!harq_feedback) { + // Non-adaptive retx are only sent if HI=NACK. If HI=ACK but no grant was received do not reset PID + Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d, HI=%s\n", + pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0], harq_feedback?"ACK":"NACK"); + generate_tx(tti_tx, action); - } else { - Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n", - pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0]); - // HARQ entity requests a non-adaptive transmission - if (!harq_feedback) { - generate_tx(tti_tx, action); - } } // On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5 diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index 963f146dc..fd73d9421 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -46,6 +46,7 @@ namespace srsue { class chest_feedback_itf { public: + virtual void out_of_sync() = 0; virtual void set_cfo(float cfo) = 0; }; @@ -58,7 +59,6 @@ public: phy_args_t *args; rrc_interface_phy *rrc; mac_interface_phy *mac; - srslte_ue_ul_t ue_ul; /* Power control variables */ float pathloss; @@ -66,12 +66,15 @@ public: float p0_preamble; float cur_radio_power; float cur_pusch_power; - float avg_rsrp_db; + float avg_rsrp; + float avg_rsrp_dbm; float avg_rsrq_db; float rx_gain_offset; float avg_snr_db; float avg_noise; - float avg_rsrp; + + bool pcell_meas_enabled; + uint32_t pcell_report_period; // Save last TBS for mcs>28 cases int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; @@ -105,6 +108,7 @@ public: void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); bool get_pending_ack(uint32_t tti); bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); + bool is_any_pending_ack(); void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); @@ -125,6 +129,7 @@ public: void get_sync_metrics(sync_metrics_t &m); void reset_ul(); + void reset(); private: @@ -173,7 +178,7 @@ private: uint32_t sync_metrics_count; bool sync_metrics_read; }; - + } // namespace srsue #endif // UEPHYWORKERCOMMON_H diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index a5f290887..6c7ff7717 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -27,10 +27,13 @@ #ifndef UEPHYRECV_H #define UEPHYRECV_H +#include + #include "srslte/srslte.h" #include "srslte/common/log.h" #include "srslte/common/threads.h" #include "srslte/common/thread_pool.h" +#include "srslte/common/tti_sync_cv.h" #include "srslte/radio/radio_multi.h" #include "phy/prach.h" #include "phy/phch_worker.h" @@ -39,7 +42,8 @@ namespace srsue { -typedef _Complex float cf_t; +typedef _Complex float cf_t; + class phch_recv : public thread, public chest_feedback_itf { @@ -60,24 +64,29 @@ public: void cell_search_stop(); void cell_search_next(bool reset = false); bool cell_select(uint32_t earfcn, srslte_cell_t cell); + bool cell_handover(srslte_cell_t cell); + + void meas_reset(); + int meas_start(uint32_t earfcn, int pci); + int meas_stop(uint32_t earfcn, int pci); uint32_t get_current_tti(); bool status_is_sync(); // from chest_feedback_itf + void out_of_sync(); void set_cfo(float cfo); void set_time_adv_sec(float time_adv_sec); - void get_current_cell(srslte_cell_t *cell); - - const static int MUTEX_X_WORKER = 4; + void get_current_cell(srslte_cell_t *cell, uint32_t *earfcn = NULL); - // public variables needed by callback function - uint32_t current_sflen; - srslte::radio_multi *radio_h; - int next_offset; + const static int MUTEX_X_WORKER = 4; + + double set_rx_gain(double gain); + int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); + int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); private: @@ -86,49 +95,201 @@ private: void reset(); void radio_error(); bool wait_radio_reset(); - void set_ue_sync_opts(srslte_ue_sync_t *q); + void set_ue_sync_opts(srslte_ue_sync_t *q); void run_thread(); void set_sampling_rate(); bool set_frequency(); - void resync_sfn(bool is_connected = false); - bool stop_sync(); + bool set_cell(); void cell_search_inc(); - - bool init_cell(); - void free_cell(); + void resync_sfn(bool is_connected = false, bool rx_now = false); + bool stop_sync(); void stop_rx(); - void start_rx(); + void start_rx(bool now = false); bool radio_is_rx; bool radio_is_resetting; + bool running; + + // Class to run cell search + class search { + public: + typedef enum {CELL_NOT_FOUND, CELL_FOUND, ERROR, TIMEOUT} ret_code; + + ~search(); + void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent); + void reset(); + float get_last_gain(); + float get_last_cfo(); + void set_N_id_2(int N_id_2); + ret_code run(srslte_cell_t *cell); + + private: + phch_recv *p; + srslte::log *log_h; + cf_t *buffer[SRSLTE_MAX_PORTS]; + srslte_ue_cellsearch_t cs; + srslte_ue_mib_sync_t ue_mib_sync; + int force_N_id_2; + }; + + // Class to synchronize system frame number + class sfn_sync { + public: + typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, ERROR, TIMEOUT} ret_code; + + ~sfn_sync(); + void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout = SYNC_SFN_TIMEOUT); + void reset(); + bool set_cell(srslte_cell_t cell); + ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false); + + private: + srslte::log *log_h; + srslte_ue_sync_t *ue_sync; + cf_t *buffer[SRSLTE_MAX_PORTS]; + srslte_ue_mib_t ue_mib; + uint32_t cnt; + uint32_t timeout; + const static uint32_t SYNC_SFN_TIMEOUT = 200; + }; + + // Class to perform cell measurements + class measure { + + // TODO: This class could early stop once the variance between the last N measurements is below 3GPP requirements + + public: + typedef enum {IDLE, MEASURE_OK, ERROR} ret_code; + + ~measure(); + void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, + uint32_t nof_rx_antennas, uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); + void reset(); + void set_cell(srslte_cell_t cell); + ret_code run_subframe(uint32_t sf_idx); + ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx); + ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf); + float rsrp(); + float rsrq(); + float snr(); + uint32_t frame_st_idx(); + void set_rx_gain_offset(float rx_gain_offset); + private: + srslte::log *log_h; + srslte_ue_dl_t ue_dl; + cf_t *buffer[SRSLTE_MAX_PORTS]; + uint32_t cnt; + uint32_t nof_subframes; + uint32_t current_prb; + float rx_gain_offset; + float mean_rsrp, mean_rsrq, mean_snr; + uint32_t final_offset; + const static int RSRP_MEASURE_NOF_FRAMES = 5; + }; + + // Class to receive secondary cell + class scell_recv { + public: + const static int MAX_CELLS = 8; + typedef struct { + uint32_t pci; + float rsrp; + float rsrq; + uint32_t offset; + } cell_info_t; + void init(srslte::log *log_h, bool sic_pss_enabled); + void reset(); + int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); + private: + + const static int DEFAULT_MEASUREMENT_LEN = 10; + + cf_t *input_cfo_corrected; + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + srslte::log *log_h; + srslte_sync_t sync_find; + + bool sic_pss_enabled; + uint32_t current_fft_sz; + measure measure_p; + }; + + /* TODO: Intra-freq measurements can be improved by capturing 200 ms length signal and run cell search + + * measurements offline using sync object and finding multiple cells for each N_id_2 + */ + + // Class to perform intra-frequency measurements + class intra_measure : public thread { + public: + void init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h); + void stop(); + void add_cell(int pci); + void rem_cell(int pci); + void set_primay_cell(uint32_t earfcn, srslte_cell_t cell); + void clear_cells(); + int get_offset(uint32_t pci); + void write(uint32_t tti, cf_t *data, uint32_t nsamples); + private: + void run_thread(); + const static int CAPTURE_LEN_SF = 15; + const static int INTRA_FREQ_MEAS_PERIOD_MS = 200; + scell_recv scell; + rrc_interface_phy *rrc; + srslte::log *log_h; + phch_common *common; + uint32_t current_earfcn; + uint32_t current_sflen; + srslte_cell_t primary_cell; + std::vector active_pci; + + srslte::tti_sync_cv tti_sync; + + cf_t *search_buffer; + + scell_recv::cell_info_t info[scell_recv::MAX_CELLS]; + + bool running; + bool receive_enabled; + bool receiving; + uint32_t measure_tti; + uint32_t receive_cnt; + srslte_ringbuffer_t ring_buffer; + }; + + + + // Objects for internal use + measure measure_p; + search search_p; + sfn_sync sfn_p; + intra_measure intra_freq_meas; - bool running; - + uint32_t current_sflen; + int next_offset; + uint32_t nof_rx_antennas; + + // Pointers to other classes mac_interface_phy *mac; rrc_interface_phy *rrc; srslte::log *log_h; srslte::thread_pool *workers_pool; + srslte::radio_multi *radio_h; phch_common *worker_com; prach *prach_buffer; - // Structures for Cell Camp - srslte_ue_sync_t ue_sync; - srslte_ue_mib_t ue_mib; - - // Structures for Cell Search - srslte_ue_cellsearch_t cs; - srslte_ue_mib_sync_t ue_mib_sync; - - uint32_t nof_rx_antennas; + // Object for synchronization of the primary cell + srslte_ue_sync_t ue_sync; - cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + // Buffer for primary cell samples + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; // Sync metrics - sync_metrics_t metrics; + sync_metrics_t metrics; + // State for primary cell enum { IDLE = 0, CELL_SEARCH, @@ -140,44 +301,33 @@ private: bool is_in_idle; + // Sampling rate mode (find is 1.96 MHz, camp is the full cell BW) enum { SRATE_NONE=0, SRATE_FIND, SRATE_CAMP } srate_mode; float current_srate; + // This is the primary cell srslte_cell_t cell; bool cell_is_set; - bool is_sfn_synched; - bool started; + bool started; float time_adv_sec; uint32_t tti; bool do_agc; - float last_gain; - float cellsearch_cfo; uint32_t nof_tx_mutex; uint32_t tx_mutex_cnt; + float ul_dl_factor; uint32_t current_earfcn; + int cur_earfcn_index; + bool cell_search_in_progress; - uint32_t sync_sfn_cnt; - const static uint32_t SYNC_SFN_TIMEOUT = 1000; - 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 = 10; - - int cell_sync_sfn(); - int cell_meas_rsrp(); - int cell_search(int force_N_id_2 = -1); - bool set_cell(); + uint32_t out_of_sync_cnt; + uint32_t out_of_sync2_cnt; - float dl_freq; - float ul_freq; + float dl_freq; + float ul_freq; }; diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 9540b278d..f711ade09 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -67,9 +67,7 @@ public: int read_pdsch_d(cf_t *pdsch_d); void start_plot(); - float get_ref_cfo(); - -private: +private: /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ void work_imp(); @@ -150,7 +148,8 @@ private: srslte_uci_cfg_t uci_cfg; srslte_cqi_periodic_cfg_t period_cqi; srslte_ue_ul_powerctrl_t power_ctrl; - uint32_t I_sr; + uint32_t I_sr; + bool sr_configured; float cfo; bool rar_cqi_request; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 07a2713fa..adc2abdca 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -40,8 +40,8 @@ #include "srslte/interfaces/ue_interfaces.h" namespace srsue { - -typedef _Complex float cf_t; + +typedef _Complex float cf_t; class phy : public phy_interface_mac @@ -78,6 +78,7 @@ public: void set_earfcn(std::vector earfcns); void force_freq(float dl_freq, float ul_freq); + /********** RRC INTERFACE ********************/ void reset(); void sync_reset(); @@ -86,6 +87,11 @@ public: void cell_search_stop(); void cell_search_next(); bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell); + bool cell_handover(srslte_cell_t cell); + + void meas_reset(); + int meas_start(uint32_t earfcn, int pci); + int meas_stop(uint32_t earfcn, int pci); /********** MAC INTERFACE ********************/ /* Functions to synchronize with a cell */ @@ -131,7 +137,10 @@ public: float get_pathloss_db(); uint32_t get_current_tti(); - void get_current_cell(srslte_cell_t *cell); + + void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL); + uint32_t get_current_earfcn(); + uint32_t get_current_pci(); void start_plot(); diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h index 2872c374c..8218ca644 100644 --- a/srsue/hdr/phy/prach.h +++ b/srsue/hdr/phy/prach.h @@ -49,7 +49,7 @@ namespace srsue { target_power_dbm = 0; mem_initiated = false; cell_initiated = false; - bzero(signal_buffer, sizeof(signal_buffer)); + signal_buffer = NULL; } ~prach(); void init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config, uint32_t max_prb, phy_args_t *args, srslte::log *log_h); @@ -78,7 +78,7 @@ namespace srsue { srslte_prach_t prach_obj; int transmitted_tti; srslte_cell_t cell; - cf_t *signal_buffer[SRSLTE_MAX_PORTS]; + cf_t *signal_buffer; srslte_cfo_t cfo_h; float target_power_dbm; diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 4e48f6b6d..b008b2fd5 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -80,7 +80,6 @@ public: void pregenerate_signals(bool enable); - private: virtual ~ue(); @@ -88,6 +87,7 @@ private: srsue::phy phy; srsue::mac mac; srslte::mac_pcap mac_pcap; + srslte::nas_pcap nas_pcap; srslte::rlc rlc; srslte::pdcp pdcp; srsue::rrc rrc; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index e23adf3d2..8e5ce22a9 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -69,6 +69,8 @@ typedef struct { typedef struct { bool enable; std::string filename; + bool nas_enable; + std::string nas_filename; }pcap_args_t; typedef struct { diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 2e795098e..6038993e0 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -33,6 +33,7 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" #include "srslte/asn1/liblte_mme.h" +#include "srslte/common/nas_pcap.h" using srslte::byte_buffer_t; @@ -57,8 +58,8 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED INITIATED", "TRACKING AREA UPDATE INITIATED"}; -static const bool eia_caps[8] = {false, true, true, false, false, false, false, false}; -static const bool eea_caps[8] = {true, false, false, false, false, false, false, false}; +static const bool eia_caps[8] = {false, true, true, false, false, false, false, false}; +static const bool eea_caps[8] = {true, true, true, false, false, false, false, false}; typedef enum { PLMN_NOT_SELECTED = 0, @@ -96,6 +97,9 @@ public: void attach_request(); void deattach_request(); + // PCAP + void start_pcap(srslte::nas_pcap *pcap_); + private: srslte::byte_buffer_pool *pool; srslte::log *nas_log; @@ -140,17 +144,19 @@ private: uint8_t k_nas_enc[32]; uint8_t k_nas_int[32]; - void integrity_generate(uint8_t integ_algo, - uint8_t *key_128, + // PCAP + srslte::nas_pcap *pcap = NULL; + + void 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); - void integrity_check(); - void cipher_encrypt(); - void cipher_decrypt(); + bool integrity_check(byte_buffer_t *pdu); + void cipher_encrypt(byte_buffer_t *pdu); + void cipher_decrypt(byte_buffer_t *pdu); + bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps); // Parsers diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index d561b0f1c..b5df0900a 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -38,6 +38,7 @@ #include "srslte/common/threads.h" #include +#include typedef struct { uint32_t ue_category; @@ -48,12 +49,14 @@ typedef struct { using srslte::byte_buffer_t; -namespace srsue { static std::string rb_id_str[] = {"SRB0", "SRB1", "SRB2", - "DRB1","DRB2","DRB3", - "DRB4","DRB5","DRB6", - "DRB7","DRB8"}; + "DRB1","DRB2","DRB3", + "DRB4","DRB5","DRB6", + "DRB7","DRB8"}; + + +namespace srsue { class rrc :public rrc_interface_nas @@ -87,6 +90,47 @@ public: void liblte_rrc_log(char *str); + + // NAS interface + void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + + uint16_t get_mcc(); + + uint16_t get_mnc(); + + void enable_capabilities(); + void plmn_search(); + void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); + + // PHY interface + void in_sync(); + void out_of_sync(); + void earfcn_end(); + void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); + void new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci); + + // MAC interface + void ho_ra_completed(bool ra_successful); + void release_pucch_srs(); + void run_tti(uint32_t tti); + + void ra_problem(); + + // GW interface + bool is_connected(); + + bool have_drb(); + + // PDCP interface + void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + + void write_pdu_bcch_bch(byte_buffer_t *pdu); + + void write_pdu_bcch_dlsch(byte_buffer_t *pdu); + + void write_pdu_pcch(byte_buffer_t *pdu); + + private: srslte::byte_buffer_pool *pool; srslte::log *rrc_log; @@ -97,7 +141,15 @@ private: nas_interface_rrc *nas; usim_interface_rrc *usim; - srslte::bit_buffer_t bit_buf; + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + + byte_buffer_t* byte_align_and_pack(byte_buffer_t *pdu = NULL); + void send_ul_ccch_msg(byte_buffer_t *pdu = NULL); + void send_ul_dcch_msg(byte_buffer_t *pdu = NULL); + srslte::bit_buffer_t bit_buf; pthread_mutex_t mutex; @@ -108,7 +160,12 @@ private: rrc_args_t args; bool first_stimsi_attempt; - bool reestablishment_in_progress; + uint16_t ho_src_rnti; + int ho_src_cell_idx; + phy_interface_rrc::phy_cfg_t ho_src_phy_cfg; + mac_interface_rrc::mac_cfg_t ho_src_mac_cfg; + bool pending_mob_reconf; + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT mob_reconf; // timeouts in ms @@ -132,16 +189,11 @@ private: std::map srbs; std::map drbs; - LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; - LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; - // RRC constants and timers srslte::mac_interface_timers *mac_timers; - uint32_t sync_reset_cnt; - const static uint32_t SYNC_RESET_TIMEOUT = 10; uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; - uint32_t t301, t310, t311; + uint32_t t301, t310, t311, t304; typedef struct { uint32_t earfcn; @@ -149,14 +201,22 @@ private: float rsrp; bool has_valid_sib1; bool has_valid_sib2; + bool has_valid_sib3; + bool has_valid_sib13; bool in_sync; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13; } cell_t; - std::vector known_cells; + const static int MAX_KNOWN_CELLS = 64; + cell_t known_cells[MAX_KNOWN_CELLS]; cell_t *current_cell; + int find_cell_idx(uint32_t earfcn, uint32_t pci); + cell_t* add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); + uint32_t find_best_cell(uint32_t earfcn, srslte_cell_t *cell); typedef enum { SI_ACQUIRE_IDLE = 0, @@ -166,8 +226,9 @@ private: si_acquire_state_t si_acquire_state; void run_si_acquisition_procedure(); - uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x); + uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf); uint32_t nof_sib1_trials; + uint16_t sysinfo_index; uint32_t last_win_start; void select_next_cell_in_plmn(); @@ -177,73 +238,134 @@ private: bool thread_running; void run_thread(); - // NAS interface - void write_sdu(uint32_t lcid, byte_buffer_t *sdu); - - uint16_t get_mcc(); - - uint16_t get_mnc(); - - void enable_capabilities(); - void plmn_search(); - void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); - - // PHY interface - void in_sync(); - void out_of_sync(); - void earfcn_end(); - void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); + // Measurements sub-class + class rrc_meas { + public: + void init(rrc *parent); + void reset(); + void parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_config); + void new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti); + void run_tti(uint32_t tti); + bool timer_expired(uint32_t timer_id); + void ho_finish(); + private: + + const static int NOF_MEASUREMENTS = 3; + + typedef enum {RSRP = 0, RSRQ = 1, BOTH = 2} quantity_t; + + typedef struct { + uint32_t pci; + float q_offset; + } meas_cell_t; + + typedef struct { + uint32_t earfcn; + float q_offset; + std::map cells; + } meas_obj_t; + + typedef struct { + uint32_t interval; + uint32_t max_cell; + uint32_t amount; + quantity_t trigger_quantity; + quantity_t report_quantity; + LIBLTE_RRC_EVENT_EUTRA_STRUCT event; + enum {EVENT, PERIODIC} trigger_type; + } report_cfg_t; + + typedef struct { + float ms[NOF_MEASUREMENTS]; + bool triggered; + bool timer_enter_triggered; + bool timer_exit_triggered; + uint32_t enter_tti; + uint32_t exit_tti; + } meas_value_t; + + typedef struct { + uint32_t nof_reports_sent; + uint32_t report_id; + uint32_t object_id; + bool triggered; + uint32_t periodic_timer; + std::map cell_values; // Value for each PCI in this object + } meas_t; + + std::map objects; + std::map reports_cfg; + std::map active; + + rrc *parent; + srslte::log *log_h; + phy_interface_rrc *phy; + srslte::mac_interface_timers *mac_timers; + + uint32_t filter_k_rsrp, filter_k_rsrq; + float filter_a[NOF_MEASUREMENTS]; + + meas_value_t pcell_measurement; + + bool s_measure_enabled; + float s_measure_value; + + void stop_reports(meas_t *m); + void stop_reports_object(uint32_t object_id); + void remove_meas_object(uint32_t object_id); + void remove_meas_report(uint32_t report_id); + void remove_meas_id(uint32_t measId); + void remove_meas_id(std::map::iterator it); + void calculate_triggers(uint32_t tti); + void update_phy(); + void L3_filter(meas_value_t *value, float rsrp[NOF_MEASUREMENTS]); + bool find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t **object, int *cell_idx); + float range_to_value(quantity_t quant, uint8_t range); + uint8_t value_to_range(quantity_t quant, float value); + bool process_event(LIBLTE_RRC_EVENT_EUTRA_STRUCT *event, uint32_t tti, + bool enter_condition, bool exit_condition, + meas_t *m, meas_value_t *cell); + + void generate_report(uint32_t meas_id); + }; + + rrc_meas measurements; + + + // Cell selection/reselection functions/variables + typedef struct { + float Qrxlevmin; + float Qrxlevminoffset; + float Qqualmin; + float Qqualminoffset; + float s_intrasearchP; + float q_hyst; + float threshservinglow; - // MAC interface - void release_pucch_srs(); - void ra_problem(); + } cell_resel_cfg_t; - // GW interface - bool is_connected(); - bool have_drb(); + cell_resel_cfg_t cell_resel_cfg; - // PDCP interface - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); - void write_pdu_bcch_bch(byte_buffer_t *pdu); - void write_pdu_bcch_dlsch(byte_buffer_t *pdu); - void write_pdu_pcch(byte_buffer_t *pdu); + float get_srxlev(float Qrxlevmeas); + float get_squal(float Qqualmeas); + void cell_reselection_eval(float rsrp, float rsrq); + bool cell_selection_eval(float rsrp, float rsrq = 0); - // Radio bearers - typedef enum{ - RB_ID_SRB0 = 0, - RB_ID_SRB1, - RB_ID_SRB2, - RB_ID_DRB1, - RB_ID_DRB2, - RB_ID_DRB3, - RB_ID_DRB4, - RB_ID_DRB5, - RB_ID_DRB6, - RB_ID_DRB7, - RB_ID_DRB8, - RB_ID_MAX - } rb_id_t; - - std::string get_rb_name(uint32_t lcid) { - if (lcid < RB_ID_MAX) { - return rb_id_str[lcid]; - } else { - return std::string("INVALID_RB"); - } - } + bool connection_requested; + void plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); // RLC interface void max_retx_attempted(); // Senders void send_con_request(); - void send_con_restablish_request(); + void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti); void send_con_restablish_complete(); void send_con_setup_complete(byte_buffer_t *nas_msg); void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu); void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu); - void send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu); - void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu); + void send_rrc_con_reconfig_complete(byte_buffer_t *pdu); + void send_rrc_ue_cap_info(byte_buffer_t *pdu); // Parsers void parse_dl_ccch(byte_buffer_t *pdu); @@ -251,11 +373,22 @@ private: void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); // Helpers + void ho_failed(); + bool ho_prepare(); + void add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp); void rrc_connection_release(); void con_restablish_cell_reselected(); void radio_link_failure(); + static void* start_sib_thread(void *rrc_); void sib_search(); + void apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); + void apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); + void handle_sib1(); + void handle_sib2(); + void handle_sib3(); + void handle_sib13(); + void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); diff --git a/srsue/hdr/upper/rrc_common.h b/srsue/hdr/upper/rrc_common.h index 95b909620..6d1186812 100644 --- a/srsue/hdr/upper/rrc_common.h +++ b/srsue/hdr/upper/rrc_common.h @@ -38,6 +38,8 @@ typedef enum { RRC_STATE_CELL_SELECTED, RRC_STATE_CONNECTING, RRC_STATE_CONNECTED, + RRC_STATE_HO_PREPARE, + RRC_STATE_HO_PROCESS, RRC_STATE_LEAVE_CONNECTED, RRC_STATE_N_ITEMS, } rrc_state_t; diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h index 73acd5594..cf5a4c820 100644 --- a/srsue/hdr/upper/usim.h +++ b/srsue/hdr/upper/usim.h @@ -90,6 +90,16 @@ public: srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + int ncc, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + private: void gen_auth_res_milenage( uint8_t *rand, @@ -128,7 +138,12 @@ private: uint8_t ak[6]; uint8_t mac[8]; uint8_t autn[16]; + uint8_t k_asme[32]; + uint8_t nh[32]; uint8_t k_enb[32]; + uint8_t k_enb_star[32]; + + uint32_t current_ncc; bool initiated; diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 3d1f60f56..86b644b8d 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -110,6 +110,15 @@ void mac::reconfiguration() } +void mac::wait_uplink() { + int cnt=0; + Info("Waiting to uplink...\n"); + while(mux_unit.is_pending_any_sdu() && cnt<20) { + usleep(1000); + cnt++; + } +} + // Implement Section 5.9 void mac::reset() { @@ -153,8 +162,7 @@ void mac::run_thread() { while(started) { /* Warning: Here order of invocation of procedures is important!! */ - ttisync.wait(); - tti = phy_h->get_current_tti(); + tti = ttisync.wait(); log_h->step(tti); timers.step_all(); @@ -180,6 +188,8 @@ void mac::run_thread() { ra_procedure.start_mac_order(); } ra_procedure.step(tti); + + rrc_h->run_tti(tti); } } @@ -218,7 +228,7 @@ void mac::pcch_stop_rx() void mac::tti_clock(uint32_t tti) { - ttisync.increase(); + ttisync.increase(tti); } void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) @@ -268,6 +278,7 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); action->generate_ack = false; action->decode_enabled[0] = true; + action->decode_enabled[1] = false; srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); action->payload_ptr[0] = pch_payload_buffer; action->softbuffers[0] = &pch_softbuffer; @@ -369,11 +380,30 @@ void mac::get_rntis(ue_rnti_t* rntis) memcpy(rntis, &uernti, sizeof(ue_rnti_t)); } +void mac::set_ho_rnti(uint16_t crnti, uint16_t target_pci) { + phy_h->pdcch_dl_search_reset(); + phy_h->pdcch_ul_search_reset(); + uernti.crnti = crnti; + if (pcap) { + pcap->set_ue_id(target_pci); + } +} + void mac::set_contention_id(uint64_t uecri) { uernti.contention_id = uecri; } +void mac::start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask) +{ + ra_procedure.start_noncont(preamble_index, prach_mask); +} + +void mac::start_cont_ho() +{ + ra_procedure.start_mac_order(56, true); +} + void mac::get_config(mac_cfg_t* mac_cfg) { memcpy(mac_cfg, &config, sizeof(mac_cfg_t)); diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc index 4e1a3b870..e6e136d2e 100644 --- a/srsue/src/mac/mux.cc +++ b/srsue/src/mac/mux.cc @@ -62,7 +62,9 @@ void mux::init(rlc_interface_mac *rlc_, srslte::log *log_h_, bsr_interface_mux * void mux::reset() { - lch.clear(); + for (uint32_t i=0;iset_c_rnti(pending_crnti_ce)) { Warning("Pending C-RNTI CE could not be inserted in MAC PDU\n"); } } } + } else { + is_rar = true; } pending_crnti_ce = 0; @@ -200,43 +207,44 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 } } - // Update buffer states for all logical channels - int sdu_space = pdu_msg.get_sdu_space(); - for (uint32_t i=0;iget_buffer_state(lch[i].id); - lch[i].sched_len = 0; - } - - // data from any Logical Channel, except data from UL-CCCH; - // first only those with positive Bj - for (uint32_t i=0;i= 0) { - lch[i].Bj -= lch[i].sched_len; + if (!is_rar) { + // Update buffer states for all logical channels + int sdu_space = pdu_msg.get_sdu_space(); + for (uint32_t i=0;iget_buffer_state(lch[i].id); + lch[i].sched_len = 0; + } + + // data from any Logical Channel, except data from UL-CCCH; + // first only those with positive Bj + for (uint32_t i=0;i= 0) { + lch[i].Bj -= lch[i].sched_len; + } } } - } - // If resources remain, allocate regardless of their Bj value - for (uint32_t i=0;i 0) { - for (int i=(int)lch.size()-1;i>=0;i--) { - if (lch[i].sched_len > 0) { - lch[i].sched_len = -1; - break; + + // Maximize the grant utilization + if (lch.size() > 0) { + for (int i=(int)lch.size()-1;i>=0;i--) { + if (lch[i].sched_len > 0) { + lch[i].sched_len = -1; + break; + } } } - } - // Now allocate the SDUs from the RLC - for (uint32_t i=0;iprach_config_index; - preambleIndex = 0; // pass when called from higher layers for non-contention based RA - maskIndex = 0; // same - nof_preambles = liblte_rrc_number_of_ra_preambles_num[mac_cfg->rach.num_ra_preambles]; + if (noncontention_enabled) { + preambleIndex = next_preamble_idx; + maskIndex = next_prach_mask; + noncontention_enabled = false; + } else { + preambleIndex = 0; // pass when called from higher layers for non-contention based RA + maskIndex = 0; // same + } + nof_preambles = liblte_rrc_number_of_ra_preambles_num[mac_cfg->rach.num_ra_preambles]; if (mac_cfg->rach.preambles_group_a_cnfg.present) { nof_groupA_preambles = liblte_rrc_size_of_ra_preambles_group_a_num[mac_cfg->rach.preambles_group_a_cnfg.size_of_ra]; } else { @@ -386,13 +392,16 @@ void ra_proc::step_response_reception() { } } -void ra_proc::step_response_error() { - +void ra_proc::step_response_error() +{ preambleTransmissionCounter++; if (preambleTransmissionCounter >= preambleTransMax + 1) { rError("Maximum number of transmissions reached (%d)\n", preambleTransMax); rrc->ra_problem(); state = RA_PROBLEM; + if (ra_is_ho) { + rrc->ho_ra_completed(false); + } } else { backoff_interval_start = phy_h->get_current_tti(); if (backoff_param_ms) { @@ -495,8 +504,11 @@ void ra_proc::step_completition() { phy_h->set_crnti(rntis->crnti); - msg3_transmitted = false; + msg3_transmitted = false; state = COMPLETION_DONE; + if (ra_is_ho) { + rrc->ho_ra_completed(true); + } } void ra_proc::step(uint32_t tti_) @@ -536,9 +548,17 @@ void ra_proc::step(uint32_t tti_) } } -void ra_proc::start_mac_order(uint32_t msg_len_bits) +void ra_proc::start_noncont(uint32_t preamble_index, uint32_t prach_mask) { + next_preamble_idx = preamble_index; + next_prach_mask = prach_mask; + noncontention_enabled = true; + start_mac_order(56, true); +} + +void ra_proc::start_mac_order(uint32_t msg_len_bits, bool is_ho) { if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) { + ra_is_ho = is_ho; started_by_pdcch = false; new_ra_msg_len = msg_len_bits; state = INITIALIZATION; diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 201af1b14..6df1cac99 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -82,9 +82,11 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") - ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), - "Enable MAC packet captures for wireshark") + ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") + ("pcap.nas_enable", bpo::value(&args->pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark") + ("pcap.nas_filename", bpo::value(&args->pcap.nas_filename)->default_value("ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)") + ("trace.enable", bpo::value(&args->trace.enable)->default_value(false), "Enable PHY and radio timing traces") ("trace.phy_filename", bpo::value(&args->trace.phy_filename)->default_value("ue.phy_trace"), @@ -203,7 +205,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { "Tolerance (in Hz) for digital CFO compensation (needs to be low if average_subframe_enabled=true.") ("expert.cfo_pss_ema", - bpo::value(&args->expert.phy.cfo_pss_ema)->default_value(0.1), + bpo::value(&args->expert.phy.cfo_pss_ema)->default_value(0.01), "CFO Exponential Moving Average coefficient for PSS estimation during TRACK.") ("expert.cfo_ref_ema", @@ -231,13 +233,16 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.phy.cfo_loop_ref_min)->default_value(0), "Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop") - ("expert.cfo_loop_pss_conv", - bpo::value(&args->expert.phy.cfo_loop_pss_conv)->default_value(50), + bpo::value(&args->expert.phy.cfo_loop_pss_conv)->default_value(20), "After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.") + ("expert.sic_pss_enabled", + bpo::value(&args->expert.phy.sic_pss_enabled)->default_value(true), + "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(&args->expert.phy.average_subframe_enabled)->default_value(true), + bpo::value(&args->expert.phy.average_subframe_enabled)->default_value(false), "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") ("expert.time_correct_period", @@ -436,6 +441,7 @@ int main(int argc, char *argv[]) bool plot_started = false; bool signals_pregenerated = false; + while (running) { if (ue->is_attached()) { if (!signals_pregenerated && args.expert.pregenerate_signals) { diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index be06b8e9c..59db2f546 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -47,24 +47,7 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) mac = NULL; max_mutex = max_mutex_; nof_mutex = 0; - sr_enabled = false; - is_first_of_burst = true; - is_first_tx = true; - rar_grant_pending = false; - pathloss = 0; - cur_pathloss = 0; - cur_pusch_power = 0; - p0_preamble = 0; - cur_radio_power = 0; - rx_gain_offset = 0; - sr_last_tx_tti = -1; - cur_pusch_power = 0; - bzero(zeros, 50000*sizeof(cf_t)); - // FIXME: This is an ungly fix to avoid the TX filters to empty - for (int i=0;i<50000;i++) { - zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); - } bzero(&dl_metrics, sizeof(dl_metrics_t)); dl_metrics_read = true; dl_metrics_count = 0; @@ -74,6 +57,16 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) bzero(&sync_metrics, sizeof(sync_metrics_t)); sync_metrics_read = true; sync_metrics_count = 0; + + bzero(zeros, 50000*sizeof(cf_t)); + + // FIXME: This is an ugly fix to avoid the TX filters to empty + for (int i=0;i<50000;i++) { + zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); + } + + reset(); + } void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac) @@ -221,6 +214,15 @@ bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_ return pending_ack[TTIMOD(tti)].enabled; } +bool phch_common::is_any_pending_ack() { + for (int i=0;itti_clock(tti); - } @@ -328,9 +326,30 @@ void phch_common::get_sync_metrics(sync_metrics_t &m) { sync_metrics_read = true; } +void phch_common::reset() { + sr_enabled = false; + is_first_of_burst = true; + is_first_tx = true; + rar_grant_pending = false; + pathloss = 0; + cur_pathloss = 0; + cur_pusch_power = 0; + p0_preamble = 0; + cur_radio_power = 0; + rx_gain_offset = 0; + sr_last_tx_tti = -1; + cur_pusch_power = 0; + + pcell_meas_enabled = false; + pcell_report_period = 20; + + bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ); + +} + void phch_common::reset_ul() { - is_first_tx = true; + is_first_tx = true; is_first_of_burst = true; for (uint32_t i=0;i -#include +#include #include "srslte/srslte.h" #include "srslte/common/log.h" #include "phy/phch_worker.h" -#include "phy/phch_common.h" #include "phy/phch_recv.h" #define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) @@ -39,27 +38,12 @@ namespace srsue { -int radio_recv_wrapper_cs(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { - phch_recv *h = (phch_recv*) obj; - srslte::radio_multi *radio_h = h->radio_h; - - if (radio_h->rx_now(data, nsamples, rx_time)) { - int offset = nsamples - h->current_sflen; - if (abs(offset) < 10 && offset != 0) { - h->next_offset = offset; - } else if (nsamples < 10) { - h->next_offset = nsamples; - } - return nsamples; - } else { - return -1; - } +int radio_recv_callback(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { + return ((phch_recv*) obj)->radio_recv_fnc(data, nsamples, rx_time); } double callback_set_rx_gain(void *h, double gain) { - phch_recv *obj = (phch_recv*) h; - srslte::radio_multi *radio_h = obj->radio_h; - return radio_h->set_rx_gain_th(gain); + return ((phch_recv*) h)->set_rx_gain(gain); } @@ -68,63 +52,50 @@ phch_recv::phch_recv() { ul_freq = -1; bzero(&cell, sizeof(srslte_cell_t)); running = false; + worker_com = NULL; } -void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, +void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, prach *_prach_buffer, srslte::thread_pool *_workers_pool, phch_common *_worker_com, srslte::log *_log_h, uint32_t nof_rx_antennas_, uint32_t prio, - int sync_cpu_affinity) { + int sync_cpu_affinity) +{ radio_h = _radio_handler; - log_h = _log_h; - mac = _mac; - rrc = _rrc; - workers_pool = _workers_pool; - worker_com = _worker_com; - prach_buffer = _prach_buffer; + log_h = _log_h; + mac = _mac; + rrc = _rrc; + workers_pool = _workers_pool; + worker_com = _worker_com; + prach_buffer = _prach_buffer; nof_rx_antennas = nof_rx_antennas_; - reset(); - for (uint32_t i = 0; i < nof_rx_antennas; i++) { sf_buffer[i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100)); } - - if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_wrapper_cs, nof_rx_antennas, - this)) { - Error("SYNC: Initiating UE cell search\n"); + if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rx_antennas, this)) { + Error("SYNC: Initiating ue_sync\n"); return; } - srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); + nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers(); + worker_com->set_nof_mutex(nof_tx_mutex); - last_gain = 40; - if (do_agc) { - srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain); - } - - if (srslte_ue_dl_init(&ue_dl_measure, sf_buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) { - Error("SYNC: Initiating ue_dl_measure\n"); - return; - } + // Initialize cell searcher + search_p.init(sf_buffer, log_h, nof_rx_antennas, this); - if (srslte_ue_mib_init(&ue_mib, sf_buffer, SRSLTE_MAX_PRB)) { - Error("SYNC: Initiating UE MIB decoder\n"); - return; - } + // Initialize SFN synchronizer + sfn_p.init(&ue_sync, sf_buffer, log_h); - if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_wrapper_cs, nof_rx_antennas, this)) { - Error("SYNC: Initiating ue_sync\n"); - return; - } + // Initialize measurement class for the primary cell + measure_p.init(sf_buffer, log_h, nof_rx_antennas); - if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_wrapper_cs, nof_rx_antennas, this)) { - Error("SYNC: Initiating UE MIB synchronization\n"); - return; - } + // Start intra-frequency measurement + intra_freq_meas.init(worker_com, rrc, log_h); - nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers(); - worker_com->set_nof_mutex(nof_tx_mutex); + reset(); + + // Start main thread if (sync_cpu_affinity < 0) { start(prio); } else { @@ -139,33 +110,35 @@ phch_recv::~phch_recv() { } } srslte_ue_sync_free(&ue_sync); - srslte_ue_dl_free(&ue_dl_measure); - srslte_ue_mib_free(&ue_mib); - srslte_ue_mib_sync_free(&ue_mib_sync); - srslte_ue_cellsearch_free(&cs); } -void phch_recv::stop() { - +void phch_recv::stop() +{ + intra_freq_meas.stop(); running = false; wait_thread_finish(); } -void phch_recv::reset() { +void phch_recv::reset() +{ tx_mutex_cnt = 0; running = true; phy_state = IDLE; time_adv_sec = 0; next_offset = 0; cell_is_set = false; - sync_sfn_cnt = 0; srate_mode = SRATE_NONE; cell_search_in_progress = false; current_earfcn = 0; radio_is_resetting = false; + sfn_p.reset(); + measure_p.reset(); + search_p.reset(); + } -void phch_recv::radio_error() { +void phch_recv::radio_error() +{ log_h->error("SYNC: Receiving from radio.\n"); phy_state = IDLE; radio_is_resetting=true; @@ -182,7 +155,6 @@ void phch_recv::radio_error() { } void phch_recv::set_cfo(float cfo) { - Debug("set_ref_cfo=%f\n",cfo*15000); srslte_ue_sync_set_cfo_ref(&ue_sync, cfo); } @@ -195,11 +167,13 @@ bool phch_recv::wait_radio_reset() { return radio_is_resetting; } -void phch_recv::set_agc_enable(bool enable) { +void phch_recv::set_agc_enable(bool enable) +{ do_agc = enable; } -void phch_recv::set_time_adv_sec(float _time_adv_sec) { +void phch_recv::set_time_adv_sec(float _time_adv_sec) +{ if (TX_MODE_CONTINUOUS && !radio_h->is_first_of_burst()) { int nsamples = ceil(current_srate*_time_adv_sec); next_offset = -nsamples; @@ -208,7 +182,8 @@ void phch_recv::set_time_adv_sec(float _time_adv_sec) { } } -void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { +void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) +{ if (worker_com->args->cfo_integer_enabled) { srslte_ue_sync_set_cfo_i_enable(q, true); } @@ -221,6 +196,8 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { worker_com->args->cfo_loop_pss_tol, worker_com->args->cfo_loop_pss_conv); + q->strack.pss.chest_on_filter = worker_com->args->sic_pss_enabled; + int time_correct_period = worker_com->args->time_correct_period; if (time_correct_period > 0) { srslte_ue_sync_set_sample_offset_correct_period(q, time_correct_period); @@ -242,24 +219,16 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { bool phch_recv::set_cell() { cell_is_set = false; - if (srslte_ue_mib_set_cell(&ue_mib, cell)) { - Error("SYNC: Setting cell: initiating ue_mib\n"); - return false; - } + + // Set cell in all objects if (srslte_ue_sync_set_cell(&ue_sync, cell)) { Error("SYNC: Setting cell: initiating ue_sync"); return false; } - - // Set options defined in expert section - set_ue_sync_opts(&ue_sync); - - if (srslte_ue_dl_set_cell(&ue_dl_measure, cell)) { - Error("SYNC: Setting cell: initiating ue_dl_measure\n"); - return false; - } - + measure_p.set_cell(cell); + sfn_p.set_cell(cell); worker_com->set_cell(cell); + intra_freq_meas.set_primay_cell(current_earfcn, cell); for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) { if (!((phch_worker *) workers_pool->get_worker(i))->set_cell(cell)) { @@ -267,188 +236,28 @@ bool phch_recv::set_cell() { return false; } } - if (do_agc) { - srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain); - } - cell_is_set = true; - - return cell_is_set; -} - -int phch_recv::cell_search(int force_N_id_2) { - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - - srslte_ue_cellsearch_result_t found_cells[3]; - - bzero(&cell, sizeof(srslte_cell_t)); - bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t)); - - if (srate_mode != SRATE_FIND) { - srate_mode = SRATE_FIND; - radio_h->set_rx_srate(1.92e6); - } - start_rx(); - - /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ - uint32_t max_peak_cell = 0; - int ret = SRSLTE_ERROR; - - Info("SYNC: Searching for cell...\n"); - printf("."); fflush(stdout); - - if (force_N_id_2 >= 0 && force_N_id_2 < 3) { - ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); - max_peak_cell = force_N_id_2; - } else { - ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); - } - - last_gain = srslte_agc_get_gain(&cs.ue_sync.agc); - - if (ret < 0) { - Error("SYNC: Error decoding MIB: Error searching PSS\n"); - return -1; - } else if (ret == 0) { - stop_rx(); - Info("SYNC: Could not find any cell in this frequency\n"); - return 0; - } - // Save result - cell.id = found_cells[max_peak_cell].cell_id; - cell.cp = found_cells[max_peak_cell].cp; - cellsearch_cfo = found_cells[max_peak_cell].cfo; - - printf("\n"); - Info("SYNC: PSS/SSS detected: PCI=%d, CFO=%.1f KHz, CP=%s\n", - cell.id, cellsearch_cfo/1000, srslte_cp_string(cell.cp)); - - if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, cell.id, cell.cp)) { - Error("SYNC: Setting UE MIB cell\n"); - return false; - } - - if (do_agc) { - srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain); - } - - srslte_ue_sync_reset(&ue_mib_sync.ue_sync); - srslte_ue_sync_copy_cfo(&ue_mib_sync.ue_sync, &cs.ue_sync); - Info("Copied cfo=%f Hz from cs_sync to ue_mib\n", srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync)); - /* Find and decode MIB */ - int sfn_offset; - ret = srslte_ue_mib_sync_decode(&ue_mib_sync, - 40, - bch_payload, &cell.nof_ports, &sfn_offset); - stop_rx(); - last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); - cellsearch_cfo = srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); + // Set options defined in expert section + set_ue_sync_opts(&ue_sync); + // Reset ue_sync and set CFO/gain from search procedure srslte_ue_sync_reset(&ue_sync); - srslte_ue_sync_copy_cfo(&ue_sync, &ue_mib_sync.ue_sync); - Info("Copied cfo=%f Hz from ue_mib_sync to ue_sync\n", srslte_ue_sync_get_cfo(&ue_sync)); - - if (ret == 1) { - srslte_pbch_mib_unpack(bch_payload, &cell, NULL); - - fprintf(stdout, "Found Cell: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", - cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); - - Info("SYNC: MIB Decoded: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", - cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); - - return true; - } else if (ret == 0) { - Warning("SYNC: Found PSS but could not decode PBCH\n"); - return 0; - } else { - Error("SYNC: Receiving MIB\n"); - return -1; - } -} - - -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("SYNC: 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: Trying to decode MIB... SNR=%.1f dB\n", - 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest))); - int n = srslte_ue_mib_decode(&ue_mib, 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; + cell_is_set = true; - 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; + return cell_is_set; } -int phch_recv::cell_meas_rsrp() { +void phch_recv::resync_sfn(bool is_connected, bool now) { - 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(&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); - float snr = srslte_chest_dl_get_snr(&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, SNR=%.1f dB\n", - measure_cnt, RSRP_MEASURE_NOF_FRAMES, sf_idx, 10 * log10(rsrp / 1000), 10*log10(snr)); - if (measure_cnt >= RSRP_MEASURE_NOF_FRAMES) { - return 1; - } - } else { - log_h->error("SYNC: Measuring RSRP: Sync error\n"); - return -1; + if (!now) { + wait_radio_reset(); + stop_rx(); } - - return 0; -} - -void phch_recv::resync_sfn(bool is_connected) { - - wait_radio_reset(); - - stop_rx(); - start_rx(); - srslte_ue_mib_reset(&ue_mib); + start_rx(now); + sfn_p.reset(); Info("SYNC: Starting SFN synchronization\n"); - sync_sfn_cnt = 0; + phy_state = is_connected?CELL_RESELECT:CELL_SELECT; } @@ -484,25 +293,26 @@ void phch_recv::reset_sync() { wait_radio_reset(); Warning("SYNC: Resetting sync, cell_search_in_progress=%s\n", cell_search_in_progress?"yes":"no"); - srslte_ue_sync_reset(&ue_mib_sync.ue_sync); + search_p.reset(); srslte_ue_sync_reset(&ue_sync); - resync_sfn(true); + resync_sfn(true, true); } void phch_recv::cell_search_inc() { cur_earfcn_index++; if (cur_earfcn_index >= 0) { - if (cur_earfcn_index >= (int) earfcn.size() - 1) { + if (cur_earfcn_index >= (int) earfcn.size()) { cur_earfcn_index = 0; rrc->earfcn_end(); + } else { + Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); + if (current_earfcn != earfcn[cur_earfcn_index]) { + current_earfcn = earfcn[cur_earfcn_index]; + set_frequency(); + } } } - Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); - if (current_earfcn != earfcn[cur_earfcn_index]) { - current_earfcn = earfcn[cur_earfcn_index]; - set_frequency(); - } } void phch_recv::cell_search_next(bool reset) { @@ -521,12 +331,16 @@ void phch_recv::cell_search_next(bool reset) { } void phch_recv::cell_search_start() { - if (earfcn.size() > 0) { - Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); - cell_search_next(true); + if (phy_state == CELL_CAMP) { + Warning("SYNC: Can't start cell search procedure while camping on cell\n"); } else { - Info("SYNC: Empty EARFCN list. Stopping cell search...\n"); - log_h->console("Empty EARFCN list. Stopping cell search...\n"); + if (earfcn.size() > 0) { + Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); + cell_search_next(true); + } else { + Info("SYNC: Empty EARFCN list. Stopping cell search...\n"); + log_h->console("Empty EARFCN list. Stopping cell search...\n"); + } } } @@ -538,6 +352,32 @@ void phch_recv::cell_search_stop() { cell_search_in_progress = false; } +bool phch_recv::cell_handover(srslte_cell_t cell) +{ + int cnt = 0; + while(worker_com->is_any_pending_ack() && cnt < 10) { + usleep(1000); + cnt++; + log_h->info("Cell HO: Waiting pending PHICH\n"); + } + + bool ret; + this->cell = cell; + Info("Cell HO: Stopping sync with current cell\n"); + worker_com->reset_ul(); + stop_sync(); + Info("Cell HO: Reconfiguring cell\n"); + if (set_cell()) { + Info("Cell HO: Synchronizing with new cell\n"); + resync_sfn(true, true); + ret = true; + } else { + log_h->error("Cell HO: Configuring cell PCI=%d\n", cell.id); + ret = false; + } + return ret; +} + bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { // Check if we are already camping in this cell @@ -559,22 +399,24 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { log_h->warning("Still not in idle\n"); } - current_earfcn = earfcn; + if (earfcn != current_earfcn) { + if (set_frequency()) { + log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id); + return false; + } + current_earfcn = earfcn; + } - if (set_frequency()) { - this->cell = cell; - log_h->info("Cell Select: Configuring cell...\n"); + this->cell = cell; + log_h->info("Cell Select: Configuring cell...\n"); - if (set_cell()) { - log_h->info("Cell Select: Synchronizing on cell...\n"); + if (set_cell()) { + log_h->info("Cell Select: Synchronizing on cell...\n"); - resync_sfn(); + resync_sfn(); - usleep(500000); // Time offset we set start_rx to start receveing samples - return true; - } else { - log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id); - } + usleep(500000); // Time offset we set start_rx to start receiving samples + return true; } return false; } @@ -632,22 +474,93 @@ void phch_recv::set_sampling_rate() } } -void phch_recv::run_thread() { +void phch_recv::stop_rx() { + if (radio_is_rx) { + Info("SYNC: Stopping RX streaming\n"); + radio_h->stop_rx(); + } + radio_is_rx = false; +} + +void phch_recv::start_rx(bool now) { + if (!radio_is_rx) { + Info("SYNC: Starting RX streaming\n"); + radio_h->start_rx(now); + } + radio_is_rx = true; +} + +uint32_t phch_recv::get_current_tti() { + return tti; +} + +bool phch_recv::status_is_sync() { + return phy_state == CELL_CAMP; +} + +void phch_recv::get_current_cell(srslte_cell_t *cell_, uint32_t *earfcn) { + if (cell_) { + memcpy(cell_, &cell, sizeof(srslte_cell_t)); + } + if (earfcn) { + *earfcn = current_earfcn; + } +} + +int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) +{ + if (radio_h->rx_now(data, nsamples, rx_time)) { + int offset = nsamples - current_sflen; + if (abs(offset) < 10 && offset != 0) { + next_offset = offset; + } else if (nsamples < 10) { + next_offset = nsamples; + } + + log_h->debug("SYNC: received %d samples from radio\n", nsamples); + + return nsamples; + } else { + return -1; + } +} + +double phch_recv::set_rx_gain(double gain) { + return radio_h->set_rx_gain_th(gain); +} + + + + +/** + * MAIN THREAD + */ + +void phch_recv::run_thread() +{ phch_worker *worker = NULL; - cf_t *buffer[SRSLTE_MAX_PORTS]; + cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL}; + uint32_t sf_idx = 0; phy_state = IDLE; is_in_idle = true; - while (running) { + while (running) + { if (phy_state != IDLE) { is_in_idle = false; Debug("SYNC: state=%d\n", phy_state); } + + log_h->step(tti); + sf_idx = tti%10; + switch (phy_state) { case CELL_SEARCH: - if (cell_search_in_progress) { - switch(cell_search()) { - case 1: + if (cell_search_in_progress) + { + switch(search_p.run(&cell)) + { + case search::CELL_FOUND: if (!srslte_cell_isvalid(&cell)) { Error("SYNC: Detected invalid cell\n"); phy_state = IDLE; @@ -658,7 +571,7 @@ void phch_recv::run_thread() { resync_sfn(); } break; - case 0: + case search::CELL_NOT_FOUND: if (cell_search_in_progress) { cell_search_inc(); } @@ -671,46 +584,42 @@ void phch_recv::run_thread() { break; case CELL_RESELECT: case CELL_SELECT: - - srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - - switch (cell_sync_sfn()) { - case 1: - srslte_ue_sync_set_agc_period(&ue_sync, 4); + switch (sfn_p.run_subframe(&cell, &tti)) + { + case sfn_sync::SFN_FOUND: if (!cell_search_in_progress) { - phy_state = CELL_CAMP; log_h->info("Sync OK. Camping on cell PCI=%d...\n", cell.id); + phy_state = CELL_CAMP; } else { - measure_cnt = 0; - measure_rsrp = 0; - phy_state = CELL_MEASURE; + measure_p.reset(); + phy_state = CELL_MEASURE; } break; - case 0: + case sfn_sync::TIMEOUT: + if (cell_search_in_progress) { + log_h->warning("SYNC: Timeout while synchronizing SFN. Going back to cell search\n"); + phy_state = CELL_SEARCH; + } else { + log_h->warning("SYNC: Timeout while synchronizing SFN. Reselecting cell\n"); + resync_sfn(true, true); + } + break; + case sfn_sync::IDLE: break; default: radio_error(); break; } - sync_sfn_cnt++; - if (sync_sfn_cnt >= SYNC_SFN_TIMEOUT) { - sync_sfn_cnt = 0; - log_h->warning("SYNC: Timeout while synchronizing SFN\n"); - if (phy_state == CELL_SELECT) { - phy_state = CELL_SEARCH; - } else { - phy_state = IDLE; - } - } break; case CELL_MEASURE: - switch(cell_meas_rsrp()) { - case 1: + switch(measure_p.run_subframe_sync(&ue_sync, sf_idx)) + { + case measure::MEASURE_OK: log_h->info("SYNC: Measured OK. Camping on cell PCI=%d...\n", cell.id); phy_state = CELL_CAMP; - rrc->cell_found(earfcn[cur_earfcn_index], cell, 10*log10(measure_rsrp/1000)); + rrc->cell_found(earfcn[cur_earfcn_index], cell, measure_p.rsrp()); break; - case 0: + case measure::IDLE: break; default: radio_error(); @@ -718,18 +627,16 @@ void phch_recv::run_thread() { } break; case CELL_CAMP: - tti = (tti+1) % 10240; + worker = (phch_worker *) workers_pool->wait_worker(tti); if (worker) { - for (uint32_t i = 0; i < nof_rx_antennas; i++) { + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { buffer[i] = worker->get_buffer(i); } switch(srslte_ue_sync_zerocopy_multi(&ue_sync, buffer)) { case 1: - log_h->step(tti); - Debug("SYNC: Worker %d synchronized\n", worker->get_id()); metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); @@ -737,9 +644,6 @@ void phch_recv::run_thread() { worker->set_cfo(ul_dl_factor * metrics.cfo / 15000); worker_com->set_sync_metrics(metrics); - Debug("current_cfo=%f, pss_stable_cnt=%d, cfo_pss=%f Hz\n", - metrics.cfo, ue_sync.pss_stable_cnt, srslte_sync_get_cfo(&ue_sync.strack)*15000); - worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000); /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ @@ -763,15 +667,28 @@ void phch_recv::run_thread() { worker_com->p0_preamble = prach_buffer->get_p0_preamble(); worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); } + workers_pool->start_worker(worker); + + if ((tti%5) == 0 && worker_com->args->sic_pss_enabled) { + srslte_pss_sic(&ue_sync.strack.pss, &buffer[0][SRSLTE_SF_LEN_PRB(cell.nof_prb)/2-ue_sync.strack.fft_size]); + } + intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); + out_of_sync_cnt = 0; break; case 0: - log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); - // Notify RRC of out-of-sync frame - rrc->out_of_sync(); + // Signal every 5 errors only (PSS is every 5) + if (out_of_sync_cnt == 0) { + // Notify RRC of out-of-sync frame + log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); + rrc->out_of_sync(); + } worker->release(); worker_com->reset_ul(); - mac->tti_clock(tti); + out_of_sync_cnt++; + if (out_of_sync_cnt >= 5) { + out_of_sync_cnt = 0; + } break; default: radio_error(); @@ -788,41 +705,782 @@ void phch_recv::run_thread() { } is_in_idle = true; usleep(1000); - // Keep running MAC timer from system clock - tti = (tti+1) % 10240; - mac->tti_clock(tti); break; } + + // Increase TTI counter and trigger MAC clock (lower priority) + mac->tti_clock(tti); + tti = (tti+1) % 10240; } } -void phch_recv::stop_rx() { - if (radio_is_rx) { - Info("SYNC: Stopping RX streaming\n"); - radio_h->stop_rx(); +void phch_recv::out_of_sync() { + out_of_sync2_cnt++; + Info("SYNC: Received out_of_sync from channel estimator (%d)\n", out_of_sync2_cnt); + if (out_of_sync2_cnt >= 2) { + out_of_sync2_cnt = 0; + Info("SYNC: Trying to resync signal\n"); + resync_sfn(true, true); } - radio_is_rx = false; } -void phch_recv::start_rx() { - if (!radio_is_rx) { - Info("SYNC: Starting RX streaming\n"); - radio_h->start_rx(); + + + + + + + + + + + +/********* + * Cell search class + */ +phch_recv::search::~search() +{ + srslte_ue_mib_sync_free(&ue_mib_sync); + srslte_ue_cellsearch_free(&cs); +} + +void phch_recv::search::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent) +{ + this->log_h = log_h; + this->p = parent; + + for (int i=0;ibuffer[i] = buffer[i]; } - radio_is_rx = true; + + if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_callback, nof_rx_antennas, parent)) { + Error("SYNC: Initiating UE cell search\n"); + } + + if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_callback, nof_rx_antennas, parent)) { + Error("SYNC: Initiating UE MIB synchronization\n"); + } + + srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); + + // Set options defined in expert section + p->set_ue_sync_opts(&cs.ue_sync); + + if (p->do_agc) { + srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, 40); + } + + force_N_id_2 = -1; } -uint32_t phch_recv::get_current_tti() { - return tti; +void phch_recv::search::set_N_id_2(int N_id_2) { + force_N_id_2 = N_id_2; } -bool phch_recv::status_is_sync() { - return phy_state == CELL_CAMP; +void phch_recv::search::reset() +{ + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); } -void phch_recv::get_current_cell(srslte_cell_t *cell_) { - if (cell_) { - memcpy(cell_, &cell, sizeof(srslte_cell_t)); +float phch_recv::search::get_last_gain() +{ + return srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); +} + +float phch_recv::search::get_last_cfo() +{ + return srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); +} + +phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) +{ + + if (!cell) { + return ERROR; } + + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + srslte_ue_cellsearch_result_t found_cells[3]; + + bzero(cell, sizeof(srslte_cell_t)); + bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t)); + + if (p->srate_mode != SRATE_FIND) { + p->srate_mode = SRATE_FIND; + p->radio_h->set_rx_srate(1.92e6); + } + p->start_rx(); + + /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ + uint32_t max_peak_cell = 0; + int ret = SRSLTE_ERROR; + + Info("SYNC: Searching for cell...\n"); + printf("."); fflush(stdout); + + if (force_N_id_2 >= 0 && force_N_id_2 < 3) { + ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); + max_peak_cell = force_N_id_2; + } else { + ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); + } + + if (ret < 0) { + Error("SYNC: Error decoding MIB: Error searching PSS\n"); + return ERROR; + } else if (ret == 0) { + p->stop_rx(); + Info("SYNC: Could not find any cell in this frequency\n"); + return CELL_NOT_FOUND; + } + // Save result + cell->id = found_cells[max_peak_cell].cell_id; + cell->cp = found_cells[max_peak_cell].cp; + float cfo = found_cells[max_peak_cell].cfo; + + printf("\n"); + Info("SYNC: PSS/SSS detected: PCI=%d, CFO=%.1f KHz, CP=%s\n", + cell->id, cfo/1000, srslte_cp_string(cell->cp)); + + if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, cell->id, cell->cp)) { + Error("SYNC: Setting UE MIB cell\n"); + return ERROR; + } + + // Set options defined in expert section + p->set_ue_sync_opts(&ue_mib_sync.ue_sync); + + if (p->do_agc) { + srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, srslte_agc_get_gain(&cs.ue_sync.agc)); + } + + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); + + /* Find and decode MIB */ + int sfn_offset; + ret = srslte_ue_mib_sync_decode(&ue_mib_sync, + 40, + bch_payload, &cell->nof_ports, &sfn_offset); + p->stop_rx(); + + if (ret == 1) { + srslte_pbch_mib_unpack(bch_payload, cell, NULL); + + fprintf(stdout, "Found Cell: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell->id, cell->nof_prb, cell->nof_ports, cfo/1000); + + Info("SYNC: MIB Decoded: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell->id, cell->nof_prb, cell->nof_ports, cfo/1000); + + return CELL_FOUND; + } else if (ret == 0) { + Warning("SYNC: Found PSS but could not decode PBCH\n"); + return CELL_NOT_FOUND; + } else { + Error("SYNC: Receiving MIB\n"); + return ERROR; + } +} + + + + + + + + +/********* + * SFN synchronizer class + */ + +phch_recv::sfn_sync::~sfn_sync() +{ + srslte_ue_mib_free(&ue_mib); } + +void phch_recv::sfn_sync::init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout) +{ + this->log_h = log_h; + this->ue_sync = ue_sync; + this->timeout = timeout; + + for (int i=0;ibuffer[i] = buffer[i]; + } + + if (srslte_ue_mib_init(&ue_mib, this->buffer, SRSLTE_MAX_PRB)) { + Error("SYNC: Initiating UE MIB decoder\n"); + } +} + +bool phch_recv::sfn_sync::set_cell(srslte_cell_t cell) +{ + if (srslte_ue_mib_set_cell(&ue_mib, cell)) { + Error("SYNC: Setting cell: initiating ue_mib\n"); + return false; + } + reset(); + return true; +} + +void phch_recv::sfn_sync::reset() +{ + srslte_ue_mib_reset(&ue_mib); + cnt = 0; +} + +phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only) +{ + + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + srslte_ue_sync_decode_sss_on_track(ue_sync, true); + int ret = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); + if (ret < 0) { + Error("SYNC: Error calling ue_sync_get_buffer"); + return ERROR; + } + + if (ret == 1) { + if (srslte_ue_sync_get_sfidx(ue_sync) == 0) { + + // Skip MIB decoding if we are only interested in subframe 0 + if (sfidx_only) { + if (tti_cnt) { + *tti_cnt = 0; + } + return SFX0_FOUND; + } + + int sfn_offset = 0; + Info("SYNC: Trying to decode MIB... SNR=%.1f dB\n", 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest))); + + int n = srslte_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); + if (n < 0) { + Error("SYNC: Error decoding MIB while synchronising SFN"); + return ERROR; + } else if (n == SRSLTE_UE_MIB_FOUND) { + uint32_t sfn; + srslte_pbch_mib_unpack(bch_payload, cell, &sfn); + + sfn = (sfn+sfn_offset)%1024; + if (tti_cnt) { + *tti_cnt = 10*sfn; + Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", *tti_cnt, sfn_offset); + } + + srslte_ue_sync_set_agc_period(ue_sync, 20); + srslte_ue_sync_decode_sss_on_track(ue_sync, true); + reset(); + return SFN_FOUND; + } + } + } else { + Debug("SYNC: PSS/SSS not found...\n"); + } + + cnt++; + if (cnt >= timeout) { + cnt = 0; + return TIMEOUT; + } + + return IDLE; +} + + + + + + +/********* + * Measurement class + */ +void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subframes) +{ + this->log_h = log_h; + this->nof_subframes = nof_subframes; + for (int i=0;ibuffer[i] = buffer[i]; + } + + if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) { + Error("SYNC: Initiating ue_dl_measure\n"); + return; + } + reset(); +} + +phch_recv::measure::~measure() { + srslte_ue_dl_free(&ue_dl); +} + +void phch_recv::measure::reset() { + cnt = 0; + mean_rsrp = 0; + mean_rsrq = 0; + mean_snr = 0; +} + +void phch_recv::measure::set_cell(srslte_cell_t cell) +{ + current_prb = cell.nof_prb; + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + Error("SYNC: Setting cell: initiating ue_dl_measure\n"); + } + reset(); +} + +float phch_recv::measure::rsrp() { + return mean_rsrp; +} + +float phch_recv::measure::rsrq() { + return mean_rsrq; +} + +float phch_recv::measure::snr() { + return mean_snr; +} + +uint32_t phch_recv::measure::frame_st_idx() { + return final_offset; +} + +void phch_recv::measure::set_rx_gain_offset(float rx_gain_offset) { + this->rx_gain_offset = rx_gain_offset; +} + +phch_recv::measure::ret_code phch_recv::measure::run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx) +{ + int sync_res = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); + if (sync_res == 1) { + log_h->info("SYNC: CFO=%.1f KHz\n", srslte_ue_sync_get_cfo(ue_sync)); + return run_subframe(sf_idx); + } else { + log_h->error("SYNC: Measuring RSRP: Sync error\n"); + return ERROR; + } + + return IDLE; +} + +phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *input_buffer, + uint32_t offset, + uint32_t sf_idx, + uint32_t max_sf) +{ + uint32_t sf_len = SRSLTE_SF_LEN_PRB(current_prb); + + ret_code ret = IDLE; + + offset = offset-sf_len/2; + if (offset < 0) { + offset += sf_len; + sf_idx ++; + } + + float max_rsrp = -99; + int best_test_offset = 0; + int test_offset = 0; + bool found_best = false; + + // Fine-tune offset using RS + for (uint32_t n=0;n<5;n++) { + + test_offset = offset-2+n; + if (test_offset >= 0) { + + cf_t *buf_m[SRSLTE_MAX_PORTS]; + buf_m[0] = &input_buffer[test_offset]; + + uint32_t cfi; + if (srslte_ue_dl_decode_fft_estimate_noguru(&ue_dl, buf_m, sf_idx, &cfi)) { + Error("MEAS: Measuring RSRP: Estimating channel\n"); + return ERROR; + } + + float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); + if (rsrp > max_rsrp) { + max_rsrp = rsrp; + best_test_offset = test_offset; + found_best = true; + } + } + } + + offset = found_best?best_test_offset:offset; + if (offset >= 0 && offset < sf_len*max_sf) { + uint32_t nof_sf = (sf_len*max_sf - offset)/sf_len; + + Debug("INTRA: fine-tuning offset: %d, found_best=%d, rem_sf=%d\n", offset, found_best, nof_sf); + + final_offset = offset; + + for (uint32_t i=0;ierror("SYNC: Measuring RSRP: Estimating channel\n"); + return ERROR; + } + + float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - rx_gain_offset; + float rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); + float snr = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)); + + if (cnt == 0) { + mean_rsrp = rsrp; + mean_rsrq = rsrq; + mean_snr = snr; + } else { + mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt); + mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt); + mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt); + + } + cnt++; + + log_h->debug("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", + cnt, nof_subframes, sf_idx, rsrp, snr); + + if (cnt >= nof_subframes) { + return MEASURE_OK; + } else { + return IDLE; + } +} + + + + + + +/********** + * Secondary cell receiver + */ + +void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled) +{ + this->log_h = log_h; + this->sic_pss_enabled = sic_pss_enabled; + + // and a separate ue_sync instance + + uint32_t max_fft_sz = srslte_symbol_sz(100); + uint32_t max_sf_size = SRSLTE_SF_LEN(max_fft_sz); + + sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size); + input_cfo_corrected = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*15*max_sf_size); + + measure_p.init(sf_buffer, log_h, 1, DEFAULT_MEASUREMENT_LEN); + + //do this different we don't need all this search window. + if(srslte_sync_init(&sync_find, 50*max_sf_size, 5*max_sf_size, max_fft_sz)) { + fprintf(stderr, "Error initiating sync_find\n"); + return; + } + srslte_sync_cp_en(&sync_find, false); + srslte_sync_set_threshold(&sync_find, 1.2); + srslte_sync_set_em_alpha(&sync_find, 0.0); + + // Configure FIND object behaviour (this configuration is always the same) + srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0); + srslte_sync_set_cfo_i_enable(&sync_find, false); + srslte_sync_set_cfo_cp_enable(&sync_find, false); + srslte_sync_set_cfo_pss_enable(&sync_find, true); + srslte_sync_set_pss_filt_enable(&sync_find, true); + srslte_sync_set_sss_eq_enable(&sync_find, true); + + sync_find.pss.chest_on_filter = true; + + if (!sic_pss_enabled) { + sync_find.sss_channel_equalize = false; + } + + reset(); +} + +void phch_recv::scell_recv::reset() +{ + current_fft_sz = 0; + measure_p.reset(); +} + +int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) +{ + uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb); + uint32_t sf_len = SRSLTE_SF_LEN(fft_sz); + + if (fft_sz != current_fft_sz) { + if (srslte_sync_resize(&sync_find, nof_sf*sf_len, 5*sf_len, fft_sz)) { + fprintf(stderr, "Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz); + return SRSLTE_ERROR; + } + current_fft_sz = fft_sz; + } + + int nof_cells = 0; + uint32_t peak_idx = 0; + uint32_t sf_idx = 0; + int cell_id = 0; + + srslte_cell_t found_cell; + memcpy(&found_cell, &cell, sizeof(srslte_cell_t)); + found_cell.id = 10000; + + measure_p.set_rx_gain_offset(rx_gain_offset); + + for (uint32_t n_id_2=0;n_id_2<3;n_id_2++) { + + if (n_id_2 != (cell.id%3) || sic_pss_enabled) { + srslte_sync_set_N_id_2(&sync_find, n_id_2); + + srslte_sync_find_ret_t sync_res; + + do { + srslte_sync_reset(&sync_find); + srslte_sync_cfo_reset(&sync_find); + + uint32_t sf5_cnt=0; + do { + sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx); + } while(sync_res != SRSLTE_SYNC_FOUND && sf5_cnt < nof_sf/5); + + switch(sync_res) { + case SRSLTE_SYNC_ERROR: + return SRSLTE_ERROR; + fprintf(stderr, "Error finding correlation peak\n"); + return SRSLTE_ERROR; + case SRSLTE_SYNC_FOUND: + sf_idx = srslte_sync_get_sf_idx(&sync_find); + cell_id = srslte_sync_get_cell_id(&sync_find); + + if (cell_id >= 0) { + // We found the same cell as before, look another N_id_2 + if ((uint32_t) cell_id == found_cell.id || (uint32_t) cell_id == cell.id) { + sync_res = SRSLTE_SYNC_NOFOUND; + } else { + // We found a new cell ID + found_cell.id = cell_id; + found_cell.nof_ports = 1; // Use port 0 only for measurement + measure_p.set_cell(found_cell); + + // Correct CFO + srslte_cfo_correct(&sync_find.cfo_corr_frame, + input_buffer, + input_cfo_corrected, + -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); + + + switch(measure_p.run_multiple_subframes(input_cfo_corrected, peak_idx, sf_idx, nof_sf)) { + case measure::MEASURE_OK: + cells[nof_cells].pci = found_cell.id; + cells[nof_cells].rsrp = measure_p.rsrp(); + cells[nof_cells].rsrq = measure_p.rsrq(); + cells[nof_cells].offset = measure_p.frame_st_idx(); + + Info("INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f n_id_2=%d, CFO=%6.1f Hz\n", + nof_cells, cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value, n_id_2, 15000*srslte_sync_get_cfo(&sync_find)); + + nof_cells++; + + if (sic_pss_enabled) { + srslte_pss_sic(&sync_find.pss, &input_buffer[sf_len/2-fft_sz]); + } + + break; + case measure::ERROR: + Error("Measuring neighbour cell\n"); + return SRSLTE_ERROR; + default: + break; + } + } + } else { + sync_res = SRSLTE_SYNC_NOFOUND; + } + break; + case SRSLTE_SYNC_FOUND_NOSPACE: + /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ + break; + default: + break; + } + } while (sync_res == SRSLTE_SYNC_FOUND && sic_pss_enabled); + } + } + return nof_cells; +} + + + +/********** + * PHY measurements + * + */ + +void phch_recv::meas_reset() { + // Stop all measurements + intra_freq_meas.clear_cells(); + if (worker_com) { + worker_com->pcell_meas_enabled = false; + } +} + +int phch_recv::meas_start(uint32_t earfcn, int pci) { + if (earfcn == current_earfcn) { + worker_com->pcell_meas_enabled = true; + if (pci != (int) cell.id) { + intra_freq_meas.add_cell(pci); + } + return 0; + } else { + Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested measurement for %d)\n", + current_earfcn, earfcn); + return -1; + } +} + +int phch_recv::meas_stop(uint32_t earfcn, int pci) { + if (earfcn == current_earfcn) { + intra_freq_meas.rem_cell(pci); + return 0; + } else { + Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested stop measurement for %d)\n", + current_earfcn, earfcn); + } + return -1; +} + +void phch_recv::intra_measure::init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h) { + this->rrc = rrc; + this->log_h = log_h; + this->common = common; + receive_enabled = false; + + // Start scell + scell.init(log_h, common->args->sic_pss_enabled); + + search_buffer = (cf_t*) srslte_vec_malloc(CAPTURE_LEN_SF*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t)); + + if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*100*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) { + return; + } + + running = true; + start(); +} + +void phch_recv::intra_measure::stop() { + running = false; + tti_sync.increase(); + wait_thread_finish(); +} + +void phch_recv::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) { + this->current_earfcn = earfcn; + current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); + memcpy(&this->primary_cell, &cell, sizeof(srslte_cell_t)); +} + +void phch_recv::intra_measure::clear_cells() { + active_pci.clear(); + receive_enabled = false; + receiving = false; + receive_cnt = 0; + srslte_ringbuffer_reset(&ring_buffer); +} + +void phch_recv::intra_measure::add_cell(int pci) { + if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) { + active_pci.push_back(pci); + receive_enabled = true; + Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci); + } else { + Debug("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); + } +} + +int phch_recv::intra_measure::get_offset(uint32_t pci) { + for (int i=0;i::iterator newEnd = std::remove(active_pci.begin(), active_pci.end(), pci); + + if (newEnd != active_pci.end()) { + active_pci.erase(newEnd, active_pci.end()); + if (active_pci.size() == 0) { + receive_enabled = false; + } + Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %d\n", pci, active_pci.size()); + } else { + Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci); + } +} + +void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples) { + if (receive_enabled) { + if ((tti%INTRA_FREQ_MEAS_PERIOD_MS) == 0) { + receiving = true; + receive_cnt = 0; + measure_tti = tti; + srslte_ringbuffer_reset(&ring_buffer); + } + if (receiving == true) { + if (srslte_ringbuffer_write(&ring_buffer, data, nsamples*sizeof(cf_t)) < (int) (nsamples*sizeof(cf_t))) { + Warning("Error writing to ringbuffer\n"); + receiving = false; + } else { + receive_cnt++; + if (receive_cnt == CAPTURE_LEN_SF) { + tti_sync.increase(); + } + } + } + + } +} + +void phch_recv::intra_measure::run_thread() +{ + while(running) { + if (running) { + tti_sync.wait(); + } + + if (running) { + // Read 15 ms data from buffer + srslte_ringbuffer_read(&ring_buffer, search_buffer, CAPTURE_LEN_SF*current_sflen*sizeof(cf_t)); + int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, CAPTURE_LEN_SF, info); + receiving = false; + + for (int i=0;inew_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci); + } + // Look for other cells not found automatically + } + } +} + } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index fd6e959db..934be8aa7 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -95,10 +95,11 @@ void phch_worker::reset() bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); bzero(&period_cqi, sizeof(srslte_cqi_periodic_cfg_t)); - I_sr = 0; + sr_configured = false; rnti_is_set = false; rar_cqi_request = false; - cfi = 0; + I_sr = 0; + cfi = 0; } void phch_worker::set_common(phch_common* phy_) @@ -140,10 +141,6 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, chest_feedback_itf return true; } -float phch_worker::get_ref_cfo() { - return srslte_chest_dl_get_cfo(&ue_dl.chest); -} - bool phch_worker::set_cell(srslte_cell_t cell_) { if (cell.id != cell_.id || !cell_initiated) { @@ -229,14 +226,15 @@ void phch_worker::work_imp() /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ bool chest_ok = extract_fft_and_pdcch_llr(); - bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0; + bool snr_th_err = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))<-20.0; + bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>-15.0; // Call feedback loop for chest if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) { chest_loop->set_cfo(srslte_chest_dl_get_cfo(&ue_dl.chest)); } - if (chest_ok && snr_th_ok) { + if (chest_ok && !snr_th_err) { /***** Downlink Processing *******/ @@ -359,9 +357,10 @@ void phch_worker::work_imp() if (snr_th_ok) { phy->rrc->in_sync(); log_h->debug("SYNC: Sending in-sync to RRC\n"); - } else { + } else if (snr_th_err) { + chest_loop->out_of_sync(); phy->rrc->out_of_sync(); - log_h->debug("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", + log_h->info("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))); } } @@ -433,7 +432,7 @@ bool phch_worker::extract_fft_and_pdcch_llr() { srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); } - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { Error("Getting PDCCH FFT estimate\n"); return false; } @@ -843,7 +842,7 @@ void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_ void phch_worker::set_uci_sr() { uci_data.scheduling_request = false; - if (phy->sr_enabled) { + if (phy->sr_enabled && sr_configured) { uint32_t sr_tx_tti = TTI_TX(tti); // Get I_sr parameter if (srslte_ue_ul_sr_send_tti(I_sr, sr_tx_tti)) { @@ -1046,7 +1045,8 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec); #endif - Info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", + uint8_t dummy[2] = {0,0}; + log_h->info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", (tti+HARQ_DELAY_MS)%10240, grant->n_prb[0], grant->n_prb[0]+grant->L_prb, grant->mcs.tbs/8, grant->mcs.idx, rv, @@ -1246,7 +1246,7 @@ void phch_worker::set_ul_params(bool pregen_disabled) /* SR configuration */ I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; - + sr_configured = true; if (pregen_enabled && !pregen_disabled) { Info("Pre-generating UL signals worker=%d\n", get_id()); @@ -1288,18 +1288,13 @@ int phch_worker::read_ce_abs(float *ce_abs) { int sz = srslte_symbol_sz(cell.nof_prb); bzero(ce_abs, sizeof(float)*sz); int g = (sz - 12*cell.nof_prb)/2; -/* for (i = 0; i < 12*cell.nof_prb; i++) { + for (i = 0; i < 12*cell.nof_prb; i++) { ce_abs[g+i] = 20 * log10f(cabsf(ue_dl.ce_m[0][0][i])); if (isinf(ce_abs[g+i])) { ce_abs[g+i] = -80; } } -*/ - uint32_t nrefs = 2*ue_dl.cell.nof_prb; - for (i=0;iargs->snr_ema_coeff; if (chest_done) { - /* Compute ADC/RX gain offset every 20 ms */ - if ((tti%20) == 0 || phy->rx_gain_offset == 0) { + /* Compute ADC/RX gain offset every ~10s */ + if (tti== 0 || phy->rx_gain_offset == 0) { float rx_gain_offset = 0; if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) { - float rssi_all_signal = srslte_chest_dl_get_rssi(&ue_dl.chest); - if (rssi_all_signal) { - rx_gain_offset = 10*log10(rssi_all_signal)-phy->get_radio()->get_rssi(); - } else { - rx_gain_offset = 0; - } + float rssi_all_signal = 30+10*log10(srslte_vec_avg_power_cf(signal_buffer[0],SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb)))); + rx_gain_offset = 30+rssi_all_signal-phy->get_radio()->get_rssi(); } else { rx_gain_offset = phy->get_radio()->get_rx_gain(); } if (phy->rx_gain_offset) { - phy->rx_gain_offset = SRSLTE_VEC_EMA(phy->rx_gain_offset, rx_gain_offset, 0.1); + phy->rx_gain_offset = SRSLTE_VEC_EMA(rx_gain_offset, phy->rx_gain_offset, 0.5); } else { phy->rx_gain_offset = rx_gain_offset; } } // Average RSRQ - float cur_rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); - if (isnormal(cur_rsrq)) { - phy->avg_rsrq_db = SRSLTE_VEC_EMA(phy->avg_rsrq_db, cur_rsrq, snr_ema_coeff); + float rsrq_db = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); + if (isnormal(rsrq_db)) { + phy->avg_rsrq_db = SRSLTE_VEC_EMA(rsrq_db, phy->avg_rsrq_db, snr_ema_coeff); } - + // Average RSRP - float cur_rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); - if (isnormal(cur_rsrp)) { - phy->avg_rsrp = SRSLTE_VEC_EMA(phy->avg_rsrp, cur_rsrp, snr_ema_coeff); + float rsrp_lin = srslte_chest_dl_get_rsrp(&ue_dl.chest); + if (isnormal(rsrp_lin)) { + phy->avg_rsrp = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp, snr_ema_coeff); } /* Correct absolute power measurements by RX gain offset */ - float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - phy->rx_gain_offset; - float rssi = 10*log10(srslte_chest_dl_get_rssi(&ue_dl.chest)) + 30 - phy->rx_gain_offset; - - // TODO: Send UE measurements to RRC where filtering is done. Now do filtering here - if (isnormal(rsrp)) { - if (!phy->avg_rsrp_db) { - phy->avg_rsrp_db = rsrp; + float rsrp_dbm = 10*log10(rsrp_lin) + 30 - phy->rx_gain_offset; + float rssi_db = 10*log10(srslte_chest_dl_get_rssi(&ue_dl.chest)) + 30 - phy->rx_gain_offset; + + // Serving cell measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC + if (isnormal(rsrp_dbm)) { + if (!phy->avg_rsrp_dbm) { + phy->avg_rsrp_dbm= rsrp_dbm; } else { - uint32_t k = 4; // Set by RRC reconfiguration message - float coeff = pow(0.5,(float) k/4); - phy->avg_rsrp_db = SRSLTE_VEC_EMA(phy->avg_rsrp_db, rsrp, coeff); - } + phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff); + } + if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) { + phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti); + } } + // Compute PL float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power; - phy->pathloss = tx_crs_power - phy->avg_rsrp_db; + phy->pathloss = tx_crs_power - phy->avg_rsrp_dbm; // Average noise float cur_noise = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); @@ -1373,7 +1366,7 @@ void phch_worker::update_measurements() if (!phy->avg_noise) { phy->avg_noise = cur_noise; } else { - phy->avg_noise = SRSLTE_VEC_EMA(phy->avg_noise, cur_noise, snr_ema_coeff); + phy->avg_noise = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise, snr_ema_coeff); } } @@ -1382,9 +1375,9 @@ void phch_worker::update_measurements() // Store metrics dl_metrics.n = phy->avg_noise; - dl_metrics.rsrp = phy->avg_rsrp_db; + dl_metrics.rsrp = phy->avg_rsrp_dbm; dl_metrics.rsrq = phy->avg_rsrq_db; - dl_metrics.rssi = rssi; + dl_metrics.rssi = rssi_db; dl_metrics.pathloss = phy->pathloss; dl_metrics.sinr = phy->avg_snr_db; dl_metrics.turbo_iters = srslte_pdsch_last_noi(&ue_dl.pdsch); @@ -1451,7 +1444,7 @@ void *plot_thread_run(void *arg) { plot_real_init(&pce); plot_real_setTitle(&pce, (char*) "Channel Response - Magnitude"); plot_real_setLabels(&pce, (char*) "Index", (char*) "dB"); - plot_real_setYAxisScale(&pce, -1000, 1000); + plot_real_setYAxisScale(&pce, -40, 40); plot_scatter_init(&pconst); plot_scatter_setTitle(&pconst, (char*) "PDSCH - Equalized Symbols"); diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 0daecf0de..689426b2a 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -206,15 +206,11 @@ void phy::set_timeadv(uint32_t ta_cmd) { void phy::configure_prach_params() { - if (sf_recv.status_is_sync()) { - Debug("Configuring PRACH parameters\n"); - srslte_cell_t cell; - sf_recv.get_current_cell(&cell); - if (!prach_buffer.set_cell(cell)) { - Error("Configuring PRACH parameters\n"); - } - } else { - Error("Cell is not synchronized\n"); + Debug("Configuring PRACH parameters\n"); + srslte_cell_t cell; + sf_recv.get_current_cell(&cell); + if (!prach_buffer.set_cell(cell)) { + Error("Configuring PRACH parameters\n"); } } @@ -247,11 +243,27 @@ void phy::sync_reset() { sf_recv.reset_sync(); } +void phy::meas_reset() { + sf_recv.meas_reset(); +} + +int phy::meas_start(uint32_t earfcn, int pci) { + return sf_recv.meas_start(earfcn, pci); +} + +int phy::meas_stop(uint32_t earfcn, int pci) { + return sf_recv.meas_stop(earfcn, pci); +} + bool phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell) { return sf_recv.cell_select(earfcn, phy_cell); } +bool phy::cell_handover(srslte_cell_t cell) { + return sf_recv.cell_handover(cell); +} + float phy::get_phr() { float phr = radio_handler->get_max_tx_power() - workers_common.cur_pusch_power; @@ -283,9 +295,21 @@ void phy::pdcch_ul_search_reset() workers_common.set_ul_rnti(SRSLTE_RNTI_USER, 0); } -void phy::get_current_cell(srslte_cell_t *cell) +void phy::get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn) { - sf_recv.get_current_cell(cell); + sf_recv.get_current_cell(cell, current_earfcn); +} + +uint32_t phy::get_current_pci() { + srslte_cell_t cell; + sf_recv.get_current_cell(&cell); + return cell.id; +} + +uint32_t phy::get_current_earfcn() { + uint32_t earfcn; + sf_recv.get_current_cell(NULL, &earfcn); + return earfcn; } void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) @@ -309,6 +333,8 @@ void phy::reset() for(uint32_t i=0;iget_tx_gain(); // Correct CFO before transmission FIXME: UL SISO Only - srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer[0], cfo / srslte_symbol_sz(cell.nof_prb)); + srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb)); // If power control is enabled, choose amplitude and power if (args->ul_pwr_ctrl_en) { @@ -197,10 +193,10 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte radio_handler->set_tx_power(tx_power); // Scale signal - float digital_power = srslte_vec_avg_power_cf(signal_buffer[0], len); + float digital_power = srslte_vec_avg_power_cf(signal_buffer, len); float scale = sqrtf(pow(10,tx_power/10)/digital_power); - srslte_vec_sc_prod_cfc(signal_buffer[0], scale, signal_buffer[0], len); + srslte_vec_sc_prod_cfc(signal_buffer, scale, signal_buffer, len); log_h->console("PRACH: Pathloss=%.2f dB, Target power %.2f dBm, TX_power %.2f dBm, TX_gain %.1f dB\n", pathloss, target_power_dbm, tx_power, radio_handler->get_tx_gain(), scale); @@ -212,7 +208,8 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain); } - radio_handler->tx((void **) signal_buffer, len, tx_time); + void *tmp_buffer[SRSLTE_MAX_PORTS] = {signal_buffer, NULL, NULL, NULL}; + radio_handler->tx(tmp_buffer, len, tx_time); radio_handler->tx_end(); Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n", diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index b7e744bd8..2edf0fed5 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -104,13 +104,15 @@ bool ue::init(all_args_t *args_) usim_log.set_hex_limit(args->log.usim_hex_limit); // Set up pcap and trace - if(args->pcap.enable) - { + if(args->pcap.enable) { mac_pcap.open(args->pcap.filename.c_str()); mac.start_pcap(&mac_pcap); } - if(args->trace.enable) - { + if(args->pcap.nas_enable) { + nas_pcap.open(args->pcap.nas_filename.c_str()); + nas.start_pcap(&nas_pcap); + } + if(args->trace.enable) { phy.start_trace(); radio.start_trace(); } @@ -137,8 +139,7 @@ bool ue::init(all_args_t *args_) } printf("Opening RF device with %d RX antennas...\n", args->rf.nof_rx_ant); - if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name)) - { + if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name)) { printf("Failed to find device %s with args %s\n", args->rf.device_name.c_str(), args->rf.device_args.c_str()); return false; @@ -244,12 +245,13 @@ void ue::stop() radio.stop(); usleep(1e5); - if(args->pcap.enable) - { + if(args->pcap.enable) { mac_pcap.close(); } - if(args->trace.enable) - { + if(args->pcap.nas_enable) { + nas_pcap.close(); + } + if(args->trace.enable) { phy.write_trace(args->trace.phy_filename); radio.write_trace(args->trace.radio_filename); } diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 801cab581..1fb26c177 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -32,6 +32,7 @@ #include #include "srslte/asn1/liblte_rrc.h" #include "upper/nas.h" +#include "srslte/common/security.h" #include "srslte/common/bcd_helpers.h" using namespace srslte; @@ -108,7 +109,6 @@ void nas::attach_request() { } else if (state == EMM_STATE_REGISTERED) { nas_log->info("NAS state is registered, connecting to same PLMN\n"); rrc->plmn_select(current_plmn); - selecting_plmn = current_plmn; } else { nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); } @@ -125,6 +125,11 @@ void nas::deattach_request() { void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) { + // Do not process new PLMN if already selected + if (plmn_selection == PLMN_SELECTED) { + return; + } + // Check if already registered for (uint32_t i=0;iinfo_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", get_rb_name(lcid)); + + // Parse the message security header + liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &sec_hdr_type); + switch(sec_hdr_type) + { + case LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS: + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT: + case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST: + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY: + break; + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED: + mac_valid = integrity_check(pdu); + cipher_decrypt(pdu); + break; + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT: + break; + default: + nas_log->error("Not handling NAS message with SEC_HDR_TYPE=%02X\n",msg_type); + pool->deallocate(pdu); + break; + } - nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rrc->get_rb_name(lcid).c_str()); + // Write NAS pcap + if(pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } - // Parse the message + // Parse the message header liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) pdu, &pd, &msg_type); + nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s Decrypted PDU", get_rb_name(lcid)); + // TODO: Check if message type requieres specical security header type and if it isvalid + switch (msg_type) { case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT: parse_attach_accept(lcid, pdu); @@ -258,25 +294,32 @@ bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) { return true; } +/******************************************************************************* + PCAP +*******************************************************************************/ + +void nas::start_pcap(srslte::nas_pcap *pcap_) +{ + pcap = pcap_; +} + /******************************************************************************* * Security ******************************************************************************/ -void nas::integrity_generate(uint8_t integ_algo, - 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) { + switch (ctxt.integ_algo) { case INTEGRITY_ALGORITHM_ID_EIA0: break; case INTEGRITY_ALGORITHM_ID_128_EIA1: security_128_eia1(key_128, count, - rb_id, + 0, // Bearer always 0 for NAS direction, msg, msg_len, @@ -285,7 +328,7 @@ void nas::integrity_generate(uint8_t integ_algo, case INTEGRITY_ALGORITHM_ID_128_EIA2: security_128_eia2(key_128, count, - rb_id, + 0, // Bearer always 0 for NAS direction, msg, msg_len, @@ -296,16 +339,102 @@ void nas::integrity_generate(uint8_t integ_algo, } } -void nas::integrity_check() { - -} +// This function depends to a valid k_nas_int. +// This key is generated in the security mode command. -void nas::cipher_encrypt() { +bool nas::integrity_check(byte_buffer_t *pdu) +{ + uint8_t exp_mac[4]; + uint8_t *mac = &pdu->msg[1]; + int i; + integrity_generate(&k_nas_int[16], + ctxt.rx_count, + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[5], + pdu->N_bytes-5, + &exp_mac[0]); + + // Check if expected mac equals the sent mac + for(i=0; i<4; i++){ + if(exp_mac[i] != mac[i]){ + nas_log->warning("Integrity check failure. Local: count=%d, [%02x %02x %02x %02x], " + "Received: count=%d, [%02x %02x %02x %02x]\n", + ctxt.rx_count, exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], + pdu->msg[5], mac[0], mac[1], mac[2], mac[3]); + return false; + } + } + nas_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n", + ctxt.rx_count, pdu->msg[5]); + return true; } -void nas::cipher_decrypt() { +void nas::cipher_encrypt(byte_buffer_t *pdu) +{ + byte_buffer_t pdu_tmp; + switch(ctxt.cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&k_nas_enc[16], + pdu->msg[5], + 0, // Bearer always 0 for NAS + SECURITY_DIRECTION_UPLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &pdu_tmp.msg[6]); + memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&k_nas_enc[16], + pdu->msg[5], + 0, // Bearer always 0 for NAS + SECURITY_DIRECTION_UPLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &pdu_tmp.msg[6]); + memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6); + break; + default: + nas_log->error("Ciphering algorithmus not known"); + break; + } +} +void nas::cipher_decrypt(byte_buffer_t *pdu) +{ + byte_buffer_t tmp_pdu; + switch(ctxt.cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&k_nas_enc[16], + pdu->msg[5], + 0, // Bearer always 0 for NAS + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &tmp_pdu.msg[6]); + memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&k_nas_enc[16], + pdu->msg[5], + 0, // Bearer always 0 for NAS + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &tmp_pdu.msg[6]); + nas_log->debug_hex(tmp_pdu.msg, pdu->N_bytes, "Decrypted"); + memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6); + break; + default: + nas_log->error("Ciphering algorithmus not known"); + break; + } } bool nas::check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps) @@ -418,10 +547,14 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT *) pdu); - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], + // Write NAS pcap + if (pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } + + cipher_encrypt(pdu); + integrity_generate(&k_nas_int[16], ctxt.tx_count, - lcid - 1, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], pdu->N_bytes - 5, @@ -489,6 +622,10 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *) pdu); nas_log->info("Sending Authentication Response\n"); + // Write NAS pcap + if (pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } rrc->write_sdu(lcid, pdu); } else { nas_log->warning("Network authentication failure\n"); @@ -569,7 +706,7 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) return; } - // Reset counterd (as per 24.301 5.4.3.2) + // Reset counters (as per 24.301 5.4.3.2) ctxt.rx_count = 0; ctxt.tx_count = 0; @@ -585,43 +722,23 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) } // Generate NAS keys - usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, ctxt.cipher_algo, ctxt.integ_algo); + usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, + ctxt.cipher_algo, ctxt.integ_algo); nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); nas_log->debug("Generating integrity check. integ_algo:%d, count_dl:%d, lcid:%d\n", ctxt.integ_algo, ctxt.rx_count, lcid); - // Check incoming MAC - uint8_t *inMAC = &pdu->msg[1]; - uint8_t genMAC[4]; - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], - ctxt.rx_count, - lcid - 1, - SECURITY_DIRECTION_DOWNLINK, - &pdu->msg[5], - pdu->N_bytes - 5, - genMAC); - - nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); - nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); - - ctxt.rx_count++; - - bool match = true; - for (int i = 0; i < 4; i++) { - if (inMAC[i] != genMAC[i]) { - match = false; - } - } - if(!match) { + if (integrity_check(pdu) != true) { nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); - send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_MAC_FAILURE); pool->deallocate(pdu); return; } + ctxt.rx_count++; + // Take security context into use have_ctxt = true; @@ -638,20 +755,22 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) // Send response byte_buffer_t *sdu = pool_allocate; liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, - LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT, ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT *) sdu); - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], + if(pcap != NULL) { + pcap->write_nas(sdu->msg, sdu->N_bytes); + } + cipher_encrypt(sdu); + integrity_generate(&k_nas_int[16], ctxt.tx_count, - lcid - 1, SECURITY_DIRECTION_UPLINK, &sdu->msg[5], sdu->N_bytes - 5, &sdu->msg[1]); nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n", ctxt.tx_count, - rrc->get_rb_name(lcid).c_str()); + get_rb_name(lcid)); rrc->write_sdu(lcid, sdu); ctxt.tx_count++; pool->deallocate(pdu); @@ -727,10 +846,8 @@ void nas::send_attach_request() { (LIBLTE_BYTE_MSG_STRUCT *) msg); // Add MAC - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], + integrity_generate(&k_nas_int[16], ctxt.tx_count, - cfg.lcid-1, SECURITY_DIRECTION_UPLINK, &msg->msg[5], msg->N_bytes - 5, @@ -742,6 +859,10 @@ void nas::send_attach_request() { liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); } + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + nas_log->info("Sending attach request\n"); rrc->write_sdu(cfg.lcid, msg); @@ -777,6 +898,10 @@ void nas::send_security_mode_reject(uint8_t cause) { LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; sec_mode_rej.emm_cause = cause; liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg); + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + nas_log->info("Sending security mode reject\n"); rrc->write_sdu(cfg.lcid, msg); } @@ -793,10 +918,8 @@ void nas::send_service_request() { msg->N_bytes++; uint8_t mac[4]; - integrity_generate(ctxt.integ_algo, - &k_nas_int[16], + integrity_generate(&k_nas_int[16], ctxt.tx_count, - cfg.lcid-1, SECURITY_DIRECTION_UPLINK, &msg->msg[0], 2, @@ -806,6 +929,11 @@ void nas::send_service_request() { msg->N_bytes++; msg->msg[3] = mac[3]; msg->N_bytes++; + + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + nas_log->info("Sending service request\n"); rrc->write_sdu(cfg.lcid, msg); ctxt.tx_count++; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index ca0c31cb0..2ea1b877d 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include "upper/rrc.h" #include "srslte/asn1/liblte_rrc.h" #include "srslte/common/security.h" @@ -47,8 +48,8 @@ namespace srsue { rrc::rrc() :state(RRC_STATE_IDLE) ,drb_up(false) + ,sysinfo_index(0) { - sync_reset_cnt = 0; n310_cnt = 0; n311_cnt = 0; } @@ -88,13 +89,14 @@ void rrc::init(phy_interface_rrc *phy_, state = RRC_STATE_IDLE; si_acquire_state = SI_ACQUIRE_IDLE; + bzero(known_cells, MAX_KNOWN_CELLS*sizeof(cell_t)); + thread_running = true; start(); pthread_mutex_init(&mutex, NULL); first_stimsi_attempt = false; - reestablishment_in_progress = false; args.ue_category = SRSLTE_UE_CATEGORY; args.supported_bands[0] = 7; @@ -104,6 +106,7 @@ void rrc::init(phy_interface_rrc *phy_, t301 = mac_timers->timer_get_unique_id(); t310 = mac_timers->timer_get_unique_id(); t311 = mac_timers->timer_get_unique_id(); + t304 = mac_timers->timer_get_unique_id(); transaction_id = 0; @@ -113,11 +116,14 @@ void rrc::init(phy_interface_rrc *phy_, nof_sib1_trials = 0; last_win_start = 0; + pending_mob_reconf = false; + // Set default values for all layers set_rrc_default(); set_phy_default(); set_mac_default(); + measurements.init(this); // set seed for rand (used in attach) srand(time(NULL)); } @@ -127,6 +133,10 @@ void rrc::stop() { wait_thread_finish(); } +void rrc::run_tti(uint32_t tti) { + measurements.run_tti(tti); +} + rrc_state_t rrc::get_state() { return state; } @@ -150,6 +160,8 @@ void rrc::set_args(rrc_args_t *args) { */ void rrc::run_thread() { + uint32_t failure_test = 0; + while (thread_running) { if (state >= RRC_STATE_IDLE && state < RRC_STATE_CONNECTING) { @@ -165,14 +177,14 @@ void rrc::run_thread() { if (nas->is_attaching()) { sleep(1); rrc_log->info("RRC IDLE: NAS is attaching and camping on cell, reselecting...\n"); - plmn_select(selected_plmn_id); + plmn_select_rrc(selected_plmn_id); } // If not camping on a cell } else { // If NAS is attached, perform cell reselection on current PLMN if (nas->is_attached()) { rrc_log->info("RRC IDLE: NAS is attached, PHY not synchronized. Re-selecting cell...\n"); - plmn_select(selected_plmn_id); + plmn_select_rrc(selected_plmn_id); } else if (nas->is_attaching()) { sleep(1); rrc_log->info("RRC IDLE: NAS is attaching, searching again PLMN\n"); @@ -193,9 +205,14 @@ void rrc::run_thread() { } break; case RRC_STATE_CELL_SELECTING: + + /* During cell selection, apply SIB configurations if available or receive them if not. + * Cell is selected when all SIBs downloaded or applied. + */ if (phy->sync_status()) { if (!current_cell->has_valid_sib1) { si_acquire_state = SI_ACQUIRE_SIB1; + sysinfo_index = 0; } else if (!current_cell->has_valid_sib2) { si_acquire_state = SI_ACQUIRE_SIB2; } else { @@ -204,23 +221,41 @@ void rrc::run_thread() { state = RRC_STATE_CELL_SELECTED; } } - select_cell_timeout++; - if (select_cell_timeout >= RRC_SELECT_CELL_TIMEOUT) { - rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n"); - state = RRC_STATE_PLMN_SELECTION; - plmn_select_timeout = 0; - phy->cell_search_start(); + // Don't time out during restablishment (T311 running) + if (!mac_timers->timer_get(t311)->is_running()) { + select_cell_timeout++; + if (select_cell_timeout >= RRC_SELECT_CELL_TIMEOUT) { + rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n"); + plmn_select_timeout = 0; + select_cell_timeout = 0; + phy->cell_search_start(); + } } break; case RRC_STATE_CELL_SELECTED: - rrc_log->info("RRC Cell Selected: Sending connection request...\n"); - if (reestablishment_in_progress) { + + /* The cell is selected when the SIBs are received and applied. + * If we were in RRC_CONNECTED and arrive here it means a RLF occurred and we are in Reestablishment procedure. + * If T311 is running means there is a reestablishment in progress, send ConnectionReestablishmentRequest. + * If not, do a ConnectionRequest if NAS is established or go to IDLE an camp on cell otherwise. + */ + if (mac_timers->timer_get(t311)->is_running()) { + // + rrc_log->info("RRC Cell Selected: Sending connection reestablishment...\n"); con_restablish_cell_reselected(); - } else { + state = RRC_STATE_CONNECTING; + connecting_timeout = 0; + } else if (connection_requested) { + connection_requested = false; + rrc_log->info("RRC Cell Selected: Sending connection request...\n"); send_con_request(); + state = RRC_STATE_CONNECTING; + connecting_timeout = 0; + } else { + rrc_log->info("RRC Cell Selected: Starting paging and going to IDLE...\n"); + mac->pcch_start_rx(); + state = RRC_STATE_IDLE; } - state = RRC_STATE_CONNECTING; - connecting_timeout = 0; break; case RRC_STATE_CONNECTING: connecting_timeout++; @@ -231,22 +266,47 @@ void rrc::run_thread() { } break; case RRC_STATE_CONNECTED: + /* + failure_test++; + if (failure_test >= 100) { + mac_interface_rrc::ue_rnti_t ue_rnti; + mac->get_rntis(&ue_rnti); + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE, ue_rnti.crnti); + }*/ // Take measurements, cell reselection, etc break; + case RRC_STATE_HO_PREPARE: + if (ho_prepare()) { + state = RRC_STATE_HO_PROCESS; + } else { + state = RRC_STATE_CONNECTED; + } + break; + case RRC_STATE_HO_PROCESS: + // wait for HO to finish + break; case RRC_STATE_LEAVE_CONNECTED: usleep(60000); + rrc_log->console("RRC IDLE\n"); rrc_log->info("Leaving RRC_CONNECTED state\n"); drb_up = false; - reestablishment_in_progress = false; + measurements.reset(); pdcp->reset(); rlc->reset(); phy->reset(); mac->reset(); set_phy_default(); set_mac_default(); - mac->pcch_start_rx(); mac_timers->timer_get(t310)->stop(); mac_timers->timer_get(t311)->stop(); + if (phy->sync_status()) { + // Instruct MAC to look for P-RNTI + mac->pcch_start_rx(); + // Instruct PHY to measure serving cell for cell reselection + phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); + } + + // Move to RRC_IDLE state = RRC_STATE_IDLE; break; default: @@ -274,8 +334,8 @@ void rrc::run_thread() { // Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message -uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { - return (period * 10 * (1 + tti / (period * 10)) + x) % 10240; // the 1 means next opportunity +uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf) { + return (period*10*(1+tti/(period*10))+(offset*10)+sf)%10240; // the 1 means next opportunity } void rrc::run_si_acquisition_procedure() @@ -283,13 +343,14 @@ void rrc::run_si_acquisition_procedure() uint32_t tti; uint32_t si_win_start=0, si_win_len=0; uint16_t period; + uint32_t x, sf, offset; const int SIB1_SEARCH_TIMEOUT = 30; switch (si_acquire_state) { case SI_ACQUIRE_SIB1: // Instruct MAC to look for SIB1 tti = mac->get_current_tti(); - si_win_start = sib_start_tti(tti, 2, 5); + si_win_start = sib_start_tti(tti, 2, 0, 5); if (tti > last_win_start + 10) { last_win_start = si_win_start; mac->bcch_start_rx(si_win_start, 1); @@ -308,17 +369,30 @@ void rrc::run_si_acquisition_procedure() } break; case SI_ACQUIRE_SIB2: - // Instruct MAC to look for SIB2 only when selecting a cell - tti = mac->get_current_tti(); - period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]; - si_win_start = sib_start_tti(tti, period, 0); - if (tti > last_win_start + 10) { - last_win_start = si_win_start; - si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + // Instruct MAC to look for next SIB + if(sysinfo_index < current_cell->sib1.N_sched_info) { + si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + x = sysinfo_index*si_win_len; + sf = x%10; + offset = x/10; + + tti = mac->get_current_tti(); + period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[sysinfo_index].si_periodicity]; + si_win_start = sib_start_tti(tti, period, offset, sf); + + if (tti > last_win_start + 10) { + last_win_start = si_win_start; + si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + + mac->bcch_start_rx(si_win_start, si_win_len); + rrc_log->debug("Instructed MAC to search for system info, win_start=%d, win_len=%d\n", + si_win_start, si_win_len); + } - mac->bcch_start_rx(si_win_start, si_win_len); - rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", - si_win_start, si_win_len); + } else { + // We've received all SIBs, move on to connection request + si_acquire_state = SI_ACQUIRE_IDLE; + state = RRC_STATE_CELL_SELECTED; } break; default: @@ -371,8 +445,18 @@ void rrc::plmn_search() { plmn_select_timeout = 0; } +/* This is the NAS interface. When NAS requests to select a PLMN we have to + * connect to either register or because there is pending higher layer traffic. + */ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { + connection_requested = true; + plmn_select_rrc(plmn_id); +} +/* This is called by RRC only. In this case, we do not want to connect, just camp on the + * selected PLMN + */ +void rrc::plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { // If already camping on the selected PLMN, select this cell if (state == RRC_STATE_IDLE || state == RRC_STATE_CONNECTED || state == RRC_STATE_PLMN_SELECTION) { if (phy->sync_status() && selected_plmn_id.mcc == plmn_id.mcc && selected_plmn_id.mnc == plmn_id.mnc) { @@ -396,7 +480,7 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { } void rrc::select_next_cell_in_plmn() { - for (uint32_t i = last_selected_cell + 1; i < known_cells.size(); i++) { + for (uint32_t i = last_selected_cell + 1; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { for (uint32_t j = 0; j < known_cells[i].sib1.N_plmn_ids; j++) { if (known_cells[i].sib1.plmn_id[j].id.mcc == selected_plmn_id.mcc || known_cells[i].sib1.plmn_id[j].id.mnc == selected_plmn_id.mnc) { @@ -413,6 +497,9 @@ void rrc::select_next_cell_in_plmn() { { last_selected_cell = i; current_cell = &known_cells[i]; + rrc_log->info("Selected cell PCI=%d, EARFCN=%d, Cell ID=0x%x, addr=0x%x\n", + current_cell->phy_cell.id, current_cell->earfcn, + current_cell->sib1.cell_id, current_cell); return; } else { rrc_log->warning("Selecting cell EARFCN=%d, Cell ID=0x%x.\n", @@ -422,25 +509,61 @@ void rrc::select_next_cell_in_plmn() { } } } - rrc_log->info("No more known cells...\n"); + rrc_log->info("No more known cells. Starting again\n"); + last_selected_cell = -1; +} + +void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci) { + if (state != RRC_STATE_IDLE) { + measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti); + } else { + // If measurement is of the serving cell, evaluate cell reselection criteria + if ((earfcn == phy->get_current_earfcn() && pci == phy->get_current_pci()) || (earfcn == 0 && pci == 0)) { + cell_reselection_eval(rsrp, rsrq); + current_cell->rsrp = rsrp; + rrc_log->info("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti); + } else { + // Add/update cell measurement + srslte_cell_t cell; + phy->get_current_cell(&cell, NULL); + cell.id = pci; + add_new_cell(earfcn, cell, rsrp); + + rrc_log->info("MEAS: New measurement PCI=%d, RSRP=%.1f dBm.\n", pci, rsrp); + } + + srslte_cell_t best_cell; + uint32_t best_cell_idx = find_best_cell(phy->get_current_earfcn(), &best_cell); + + // Verify cell selection criteria + if (cell_selection_eval(known_cells[best_cell_idx].rsrp) && + known_cells[best_cell_idx].rsrp > current_cell->rsrp + 5 && + best_cell.id != phy->get_current_pci()) + { + rrc_log->info("Selecting best neighbour cell PCI=%d, rsrp=%.1f dBm\n", best_cell.id, known_cells[best_cell_idx].rsrp); + state = RRC_STATE_CELL_SELECTING; + current_cell = &known_cells[best_cell_idx]; + phy->cell_select(phy->get_current_earfcn(), best_cell); + } + } } void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { // find if cell_id-earfcn combination already exists - for (uint32_t i = 0; i < known_cells.size(); i++) { + for (uint32_t i = 0; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { if (earfcn == known_cells[i].earfcn && phy_cell.id == known_cells[i].phy_cell.id) { - known_cells[i].rsrp = rsrp; - known_cells[i].in_sync = true; current_cell = &known_cells[i]; - rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", known_cells[i].earfcn, - known_cells[i].phy_cell.id, known_cells[i].rsrp); + current_cell->rsrp = rsrp; + current_cell->in_sync = true; + rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", current_cell->earfcn, + current_cell->phy_cell.id, current_cell->rsrp); - if (!known_cells[i].has_valid_sib1) { + if (!current_cell->has_valid_sib1) { si_acquire_state = SI_ACQUIRE_SIB1; } else if (state == RRC_STATE_PLMN_SELECTION) { - for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { - nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); + for (uint32_t j = 0; j < current_cell->sib1.N_plmn_ids; j++) { + nas->plmn_found(current_cell->sib1.plmn_id[j].id, current_cell->sib1.tracking_area_code); } usleep(5000); phy->cell_search_next(); @@ -448,39 +571,142 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { return; } } - // add to list of known cells - cell_t cell; - cell.phy_cell = phy_cell; - cell.rsrp = rsrp; - cell.earfcn = earfcn; - cell.has_valid_sib1 = false; - cell.has_valid_sib2 = false; - known_cells.push_back(cell); - - // save current cell - current_cell = &known_cells.back(); + // add to list of known cells and set current_cell + current_cell = add_new_cell(earfcn, phy_cell, rsrp); + if(!current_cell) { + current_cell = &known_cells[0]; + rrc_log->error("Couldn't add new cell\n"); + return; + } si_acquire_state = SI_ACQUIRE_SIB1; - rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm\n", - cell.phy_cell.id, cell.phy_cell.nof_prb, cell.phy_cell.nof_ports, - cell.earfcn, cell.rsrp); + rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm, addr=0x%x\n", + current_cell->phy_cell.id, current_cell->phy_cell.nof_prb, current_cell->phy_cell.nof_ports, + current_cell->earfcn, current_cell->rsrp, current_cell); +} + +uint32_t rrc::find_best_cell(uint32_t earfcn, srslte_cell_t *cell) { + float best_rsrp = -INFINITY; + uint32_t best_cell_idx = 0; + for (int i=0;i best_rsrp) { + best_rsrp = known_cells[i].rsrp; + best_cell_idx = i; + } + } + } + if (cell) { + memcpy(cell, &known_cells[best_cell_idx].phy_cell, sizeof(srslte_cell_t)); + } + return best_cell_idx; +} + +rrc::cell_t* rrc::add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { + if (earfcn == 0) { + return NULL; + } + int idx = find_cell_idx(earfcn, phy_cell.id); + if (idx >= 0) { + known_cells[idx].rsrp = rsrp; + return &known_cells[idx]; + } + + // if does not exist, find empty slot + int i=0; + while(ierror("Can't add more cells\n"); + return NULL; + } + + known_cells[i].phy_cell = phy_cell; + known_cells[i].rsrp = rsrp; + known_cells[i].earfcn = earfcn; + known_cells[i].has_valid_sib1 = false; + known_cells[i].has_valid_sib2 = false; + known_cells[i].has_valid_sib3 = false; + return &known_cells[i]; +} + +void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) { + int idx = find_cell_idx(earfcn, pci); + if (idx >= 0) { + known_cells[idx].rsrp = rsrp; + return; + } + + rrc_log->info("Added neighbour cell earfcn=%d, pci=%d, rsrp=%f\n", earfcn, pci, rsrp); + + srslte_cell_t cell; + cell = current_cell->phy_cell; + cell.id = pci; + add_new_cell(earfcn, cell, rsrp); +} + +int rrc::find_cell_idx(uint32_t earfcn, uint32_t pci) { + for (uint32_t i = 0; i < MAX_KNOWN_CELLS; i++) { + if (earfcn == known_cells[i].earfcn && pci == known_cells[i].phy_cell.id) { + return (int) i; + } + } + return -1; } // PHY indicates that has gone through all known EARFCN void rrc::earfcn_end() { - rrc_log->debug("Finished searching cells in EARFCN set while in state %s\n", rrc_state_text[state]); + rrc_log->info("Finished searching cells in EARFCN set while in state %s\n", rrc_state_text[state]); // If searching for PLMN, indicate NAS we scanned all frequencies if (state == RRC_STATE_PLMN_SELECTION) { nas->plmn_search_end(); + } else if (state == RRC_STATE_CELL_SELECTING) { + select_cell_timeout = 0; + rrc_log->info("Starting cell search again\n"); + phy->cell_search_start(); } } +// Cell reselection in IDLE Section 5.2.4 of 36.304 +void rrc::cell_reselection_eval(float rsrp, float rsrq) +{ + // Intra-frequency cell-reselection criteria + + if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && rsrp > -95.0) { + // UE may not perform intra-frequency measurements. + phy->meas_reset(); + // keep measuring serving cell + phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); + } else { + // UE must start intra-frequency measurements + phy->meas_start(phy->get_current_earfcn(), -1); + } + // TODO: Inter-frequency cell reselection +} +// Cell selection in IDLE Section 5.2.3.2 of 36.304 +bool rrc::cell_selection_eval(float rsrp, float rsrq) +{ + if (get_srxlev(rsrp) > 0) { + return true; + } else { + return false; + } +} +float rrc::get_srxlev(float Qrxlevmeas) { + // TODO: Do max power limitation + float Pcompensation = 0; + return Qrxlevmeas - (cell_resel_cfg.Qrxlevmin + cell_resel_cfg.Qrxlevminoffset) - Pcompensation; +} +float rrc::get_squal(float Qqualmeas) { + return Qqualmeas - (cell_resel_cfg.Qqualmin + cell_resel_cfg.Qqualminoffset); +} @@ -497,12 +723,6 @@ void rrc::earfcn_end() { // Detection of physical layer problems (5.3.11.1) void rrc::out_of_sync() { // attempt resync - sync_reset_cnt++; - if (sync_reset_cnt >= SYNC_RESET_TIMEOUT) { - rrc_log->info("Detected %d out-of-sync from PHY. Resynchronizing PHY.\n", sync_reset_cnt); - phy->sync_reset(); - sync_reset_cnt = 0; - } current_cell->in_sync = false; if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) { n310_cnt++; @@ -540,7 +760,9 @@ void rrc::radio_link_failure() { if (state != RRC_STATE_CONNECTED) { state = RRC_STATE_LEAVE_CONNECTED; } else { - send_con_restablish_request(); + mac_interface_rrc::ue_rnti_t uernti; + mac->get_rntis(&uernti); + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE, uernti.crnti); } } @@ -571,9 +793,17 @@ void rrc::timer_expired(uint32_t timeout_id) { rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); state = RRC_STATE_LEAVE_CONNECTED; } else if (timeout_id == t301) { - rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); - state = RRC_STATE_LEAVE_CONNECTED; - } else { + if (state == RRC_STATE_IDLE) { + rrc_log->info("Timer T301 expired: Already in IDLE.\n"); + } else { + rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); + state = RRC_STATE_LEAVE_CONNECTED; + } + } else if (timeout_id == t304) { + rrc_log->console("Timer T304 expired: Handover failed\n"); + ho_failed(); + // fw to measurement + } else if (!measurements.timer_expired(timeout_id)) { rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); } } @@ -597,7 +827,6 @@ void rrc::timer_expired(uint32_t timeout_id) { void rrc::send_con_request() { rrc_log->debug("Preparing RRC Connection Request\n"); - LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; // Prepare ConnectionRequest packet @@ -612,76 +841,63 @@ void rrc::send_con_request() { } ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; - liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - pdcp_buf->set_timestamp(); + send_ul_ccch_msg(); - // Set UE contention resolution ID in MAC - uint64_t uecri = 0; - uint8_t *ue_cri_ptr = (uint8_t *) &uecri; - uint32_t nbytes = 6; - for (uint32_t i = 0; i < nbytes; i++) { - ue_cri_ptr[nbytes - i - 1] = pdcp_buf->msg[i]; - } - rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); - - mac->set_contention_id(uecri); - - rrc_log->info("Sending RRC Connection Request on SRB0\n"); - pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } /* RRC connection re-establishment procedure (5.3.7) */ -void rrc::send_con_restablish_request() { - - srslte_cell_t cell; - phy->get_current_cell(&cell); - - LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; - +void rrc::send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti) +{ // Compute shortMAC-I uint8_t varShortMAC[128], varShortMAC_packed[16]; bzero(varShortMAC, 128); bzero(varShortMAC_packed, 16); uint8_t *msg_ptr = varShortMAC; - liblte_rrc_pack_cell_identity_ie(0x1a2d0, &msg_ptr); - liblte_rrc_pack_phys_cell_id_ie(cell.id, &msg_ptr); - mac_interface_rrc::ue_rnti_t ue_rnti; - mac->get_rntis(&ue_rnti); - liblte_rrc_pack_c_rnti_ie(ue_rnti.crnti, &msg_ptr); - srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, msg_ptr - varShortMAC); - uint8_t mac_key[4]; - security_128_eia2(&k_rrc_int[16], - 1, - 1, - 1, - varShortMAC_packed, - 7, - mac_key); + // ASN.1 encode byte-aligned VarShortMAC-Input + liblte_rrc_pack_cell_identity_ie(current_cell->sib1.cell_id, &msg_ptr); + msg_ptr = &varShortMAC[4]; + liblte_rrc_pack_phys_cell_id_ie(phy->get_current_pci(), &msg_ptr); + msg_ptr = &varShortMAC[4+2]; + liblte_rrc_pack_c_rnti_ie(crnti, &msg_ptr); + srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, (4+2+4)*8); - mac_interface_rrc::ue_rnti_t uernti; - mac->get_rntis(&uernti); + rrc_log->info("Generated varShortMAC: cellId=0x%x, PCI=%d, rnti=%d\n", + current_cell->sib1.cell_id, phy->get_current_pci(), crnti); + + // Compute MAC-I + uint8_t mac_key[4]; + switch(integ_algo) { + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(&k_rrc_int[16], + 1, + 1, + 1, + varShortMAC_packed, + 10, + mac_key); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(&k_rrc_int[16], + 1, + 1, + 1, + varShortMAC_packed, + 10, + mac_key); + break; + default: + rrc_log->info("Unsupported integrity algorithm during reestablishment\n"); + return; + } // Prepare ConnectionRestalishmentRequest packet ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti = uernti.crnti; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id = cell.id; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[2] << 8 | mac_key[3]; - ul_ccch_msg.msg.rrc_con_reest_req.cause = LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE; - liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - - reestablishment_in_progress = true; + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti = crnti; + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id = phy->get_current_pci(); + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[1] << 8 | mac_key[0]; + ul_ccch_msg.msg.rrc_con_reest_req.cause = cause; rrc_log->info("Initiating RRC Connection Reestablishment Procedure\n"); rrc_log->console("RRC Connection Reestablishment\n"); @@ -693,69 +909,41 @@ void rrc::send_con_restablish_request() { set_phy_default(); mac->reset(); set_mac_default(); + state = RRC_STATE_CELL_SELECTING; } // Actions following cell reselection 5.3.7.3 void rrc::con_restablish_cell_reselected() { - reestablishment_in_progress = false; + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); mac_timers->timer_get(t301)->reset(); mac_timers->timer_get(t301)->run(); mac_timers->timer_get(t311)->stop(); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - - // Set UE contention resolution ID in MAC - uint64_t uecri = 0; - uint8_t *ue_cri_ptr = (uint8_t *) &uecri; - uint32_t nbytes = 6; - for (uint32_t i = 0; i < nbytes; i++) { - ue_cri_ptr[nbytes - i - 1] = pdcp_buf->msg[i]; - } - rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); - mac->set_contention_id(uecri); + send_ul_ccch_msg(); - rrc_log->info("Sending RRC Connection Reestablishment Request on SRB0\n"); - pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } void rrc::send_con_restablish_complete() { rrc_log->debug("Preparing RRC Connection Reestablishment Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + rrc_log->console("RRC Connected\n"); + state = RRC_STATE_CONNECTED; // Prepare ConnectionSetupComplete packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_REEST_COMPLETE; ul_dcch_msg.msg.rrc_con_reest_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - - state = RRC_STATE_CONNECTED; - rrc_log->console("RRC Connected\n"); - rrc_log->info("Sending RRC Connection Reestablishment Complete\n"); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); + send_ul_dcch_msg(); } void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { rrc_log->debug("Preparing RRC Connection Setup Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + state = RRC_STATE_CONNECTED; + rrc_log->console("RRC Connected\n"); // Prepare ConnectionSetupComplete packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE; @@ -764,123 +952,209 @@ void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { ul_dcch_msg.msg.rrc_con_setup_complete.selected_plmn_id = 1; memcpy(ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.msg, nas_msg->msg, nas_msg->N_bytes); ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.N_bytes = nas_msg->N_bytes; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - pdcp_buf->set_timestamp(); - state = RRC_STATE_CONNECTED; - rrc_log->console("RRC Connected\n"); - rrc_log->info("Sending RRC Connection Setup Complete\n"); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); + send_ul_dcch_msg(); } void rrc::send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu) { rrc_log->debug("Preparing RX Info Transfer\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; // Prepare RX INFO packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER; ul_dcch_msg.msg.ul_info_transfer.dedicated_info_type = LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS; memcpy(ul_dcch_msg.msg.ul_info_transfer.dedicated_info.msg, sdu->msg, sdu->N_bytes); ul_dcch_msg.msg.ul_info_transfer.dedicated_info.N_bytes = sdu->N_bytes; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - - // Reset and reuse sdu buffer - byte_buffer_t *pdu = sdu; - pdu->reset(); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - pdu->set_timestamp(); - - rrc_log->info("Sending RX Info Transfer\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(sdu); } void rrc::send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu) { rrc_log->debug("Preparing Security Mode Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE; ul_dcch_msg.msg.security_mode_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - rrc_log->info("Sending Security Mode Complete\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(pdu); } -void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu) { +void rrc::send_rrc_con_reconfig_complete(byte_buffer_t *pdu) { rrc_log->debug("Preparing RRC Connection Reconfig Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE; ul_dcch_msg.msg.rrc_con_reconfig_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + send_ul_dcch_msg(pdu); +} + +bool rrc::ho_prepare() { + if (pending_mob_reconf) { + rrc_log->info("Processing HO command to target PCell=%d\n", mob_reconf.mob_ctrl_info.target_pci); + + int cell_idx = find_cell_idx(phy->get_current_earfcn(), mob_reconf.mob_ctrl_info.target_pci); + if (cell_idx < 0) { + rrc_log->error("Could not find target cell pci=%d\n", mob_reconf.mob_ctrl_info.target_pci); + return false; + } + + // Section 5.3.5.4 + mac_timers->timer_get(t310)->stop(); + mac_timers->timer_get(t304)->set(this, liblte_rrc_t304_num[mob_reconf.mob_ctrl_info.t304]); + if (mob_reconf.mob_ctrl_info.carrier_freq_eutra_present && + mob_reconf.mob_ctrl_info.carrier_freq_eutra.dl_carrier_freq != current_cell->earfcn) { + rrc_log->warning("Received mobilityControlInfo for inter-frequency handover\n"); + } + + // Save cell and current configuration + ho_src_cell_idx = find_cell_idx(phy->get_current_earfcn(), phy->get_current_pci()); + if (ho_src_cell_idx < 0) { + rrc_log->error("Source cell not found in known cells. Reconnecting to cell 0 in case of failure\n"); + ho_src_cell_idx = 0; + } + phy->get_config(&ho_src_phy_cfg); + mac->get_config(&ho_src_mac_cfg); + mac_interface_rrc::ue_rnti_t uernti; + mac->get_rntis(&uernti); + ho_src_rnti = uernti.crnti; + + // Reset/Reestablish stack + phy->meas_reset(); + mac->wait_uplink(); + pdcp->reestablish(); + rlc->reestablish(); + mac->reset(); + phy->reset(); + mac->set_ho_rnti(mob_reconf.mob_ctrl_info.new_ue_id, mob_reconf.mob_ctrl_info.target_pci); + apply_rr_config_common_dl(&mob_reconf.mob_ctrl_info.rr_cnfg_common); + + rrc_log->info("Selecting new cell pci=%d\n", known_cells[cell_idx].phy_cell.id); + if (!phy->cell_handover(known_cells[cell_idx].phy_cell)) { + rrc_log->error("Could not synchronize with target cell pci=%d\n", known_cells[cell_idx].phy_cell.id); + return false; + } + + if (mob_reconf.mob_ctrl_info.rach_cnfg_ded_present) { + rrc_log->info("Starting non-contention based RA with preamble_idx=%d, mask_idx=%d\n", + mob_reconf.mob_ctrl_info.rach_cnfg_ded.preamble_index, + mob_reconf.mob_ctrl_info.rach_cnfg_ded.prach_mask_index); + mac->start_noncont_ho(mob_reconf.mob_ctrl_info.rach_cnfg_ded.preamble_index, + mob_reconf.mob_ctrl_info.rach_cnfg_ded.prach_mask_index); + } else { + rrc_log->info("Starting contention-based RA\n"); + mac->start_cont_ho(); + } + + int ncc = -1; + if (mob_reconf.sec_cnfg_ho_present) { + ncc = mob_reconf.sec_cnfg_ho.intra_lte.next_hop_chaining_count; + if (mob_reconf.sec_cnfg_ho.intra_lte.key_change_ind) { + rrc_log->console("keyChangeIndicator in securityConfigHO not supported\n"); + return false; + } + if (mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg_present) { + cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg.cipher_alg; + integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg.int_alg; + rrc_log->info("Changed Ciphering to %s and Integrity to %s\n", + ciphering_algorithm_id_text[cipher_algo], + integrity_algorithm_id_text[integ_algo]); + } + } + + usim->generate_as_keys_ho(mob_reconf.mob_ctrl_info.target_pci, phy->get_current_earfcn(), + ncc, + k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + + pdcp->config_security_all(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + send_rrc_con_reconfig_complete(NULL); } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); + return true; +} + +void rrc::ho_ra_completed(bool ra_successful) { + if (pending_mob_reconf) { - rrc_log->info("Sending RRC Connection Reconfig Complete\n"); - pdcp->write_sdu(lcid, pdu); + measurements.ho_finish(); + + if (mob_reconf.meas_cnfg_present) { + measurements.parse_meas_config(&mob_reconf.meas_cnfg); + } + + if (ra_successful) { + mac_timers->timer_get(t304)->stop(); + + apply_rr_config_common_ul(&mob_reconf.mob_ctrl_info.rr_cnfg_common); + if (mob_reconf.rr_cnfg_ded_present) { + apply_rr_config_dedicated(&mob_reconf.rr_cnfg_ded); + } + } + + rrc_log->info("HO %ssuccessful\n", ra_successful?"":"un"); + rrc_log->console("HO %ssuccessful\n", ra_successful?"":"un"); + + pending_mob_reconf = false; + if (ra_successful) { + state = RRC_STATE_CONNECTED; + } + } else { + rrc_log->error("Received HO random access completed but no pending mobility reconfiguration info\n"); + } } +// This is T304 expiry 5.3.5.6 +void rrc::ho_failed() { + + // Instruct PHY to resync with source PCI + if (!phy->cell_handover(known_cells[ho_src_cell_idx].phy_cell)) { + rrc_log->error("Could not synchronize with target cell pci=%d\n", known_cells[ho_src_cell_idx].phy_cell.id); + return; + } + + // Set previous PHY/MAC configuration + phy->set_config(&ho_src_phy_cfg); + mac->set_config(&ho_src_mac_cfg); + + // Start the Reestablishment Procedure + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_HANDOVER_FAILURE, ho_src_rnti); +} void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu) { uint32_t i; - if (reconfig->rr_cnfg_ded_present) { - apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); - } else { - printf("received con reconfig no rr confg present\n"); - } - if (reconfig->meas_cnfg_present) { - //TODO: handle meas_cnfg - } if (reconfig->mob_ctrl_info_present) { - //TODO: handle mob_ctrl_info - } - send_rrc_con_reconfig_complete(lcid, pdu); + if (reconfig->mob_ctrl_info.target_pci == phy->get_current_pci()) { + rrc_log->warning("Received HO command to own cell\n"); + send_rrc_con_reconfig_complete(pdu); + } else { + rrc_log->info("Received HO command to target PCell=%d\n", reconfig->mob_ctrl_info.target_pci); + rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n", + reconfig->mob_ctrl_info.target_pci, reconfig->sec_cnfg_ho.intra_lte.next_hop_chaining_count); + + // store mobilityControlInfo + memcpy(&mob_reconf, reconfig, sizeof(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT)); + pending_mob_reconf = true; + + state = RRC_STATE_HO_PREPARE; + } + + } else { + // Section 5.3.5.3 + if (reconfig->rr_cnfg_ded_present) { + apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); + } + if (reconfig->meas_cnfg_present) { + measurements.parse_meas_config(&reconfig->meas_cnfg); + } + + send_rrc_con_reconfig_complete(pdu); - byte_buffer_t *nas_sdu; - for (i = 0; i < reconfig->N_ded_info_nas; i++) { - nas_sdu = pool_allocate;; - memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); - nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; - nas->write_pdu(lcid, nas_sdu); + byte_buffer_t *nas_sdu; + for (i = 0; i < reconfig->N_ded_info_nas; i++) { + nas_sdu = pool_allocate; + memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); + nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; + nas->write_pdu(lcid, nas_sdu); + } } } @@ -918,6 +1192,8 @@ void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) { } void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { + mac->bcch_stop_rx(); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; @@ -926,72 +1202,120 @@ void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { pool->deallocate(pdu); liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dlsch_msg); - if (dlsch_msg.N_sibs > 0) { - if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { - mac->bcch_stop_rx(); + for(uint32_t i=0; iinfo("Processing SIB: %d\n", liblte_rrc_sys_info_block_type_num[dlsch_msg.sibs[i].sib_type]); - // Handle SIB1 - memcpy(¤t_cell->sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[i].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { + memcpy(¤t_cell->sib1, &dlsch_msg.sibs[i].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + current_cell->has_valid_sib1 = true; + handle_sib1(); + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib2) { + memcpy(¤t_cell->sib2, &dlsch_msg.sibs[i].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); + current_cell->has_valid_sib2 = true; + handle_sib2(); + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib3) { + memcpy(¤t_cell->sib3, &dlsch_msg.sibs[i].sib.sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT)); + current_cell->has_valid_sib3 = true; + handle_sib3(); + }else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib13) { + memcpy(¤t_cell->sib13, &dlsch_msg.sibs[0].sib.sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT)); + current_cell->has_valid_sib13 = true; + handle_sib13(); + } + } + if(current_cell->has_valid_sib2) { + sysinfo_index++; + } +} - rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", - current_cell->sib1.cell_id & 0xfff, - liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], - liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); +void rrc::handle_sib1() +{ + rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", + current_cell->sib1.cell_id&0xfff, + liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], + liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); + + // Print SIB scheduling info + uint32_t i,j; + for(i=0;isib1.N_sched_info;i++){ + for(j=0;jsib1.sched_info[i].N_sib_mapping_info;j++){ + LIBLTE_RRC_SIB_TYPE_ENUM t = current_cell->sib1.sched_info[i].sib_mapping_info[j].sib_type; + LIBLTE_RRC_SI_PERIODICITY_ENUM p = current_cell->sib1.sched_info[i].si_periodicity; + rrc_log->debug("SIB scheduling info, sib_type=%d, si_periodicity=%d\n", + liblte_rrc_sib_type_num[t], + liblte_rrc_si_periodicity_num[p]); + } + } + // Set TDD Config + if(current_cell->sib1.tdd) { + phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); + } - // Set TDD Config - if (current_cell->sib1.tdd) { - phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); - } + current_cell->has_valid_sib1 = true; - current_cell->has_valid_sib1 = true; + // Send PLMN and TAC to NAS + std::stringstream ss; + for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { + nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); + } - // Send PLMN and TAC to NAS - std::stringstream ss; - for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { - nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); - } + // Jump to next state + switch(state) { + case RRC_STATE_CELL_SELECTING: + si_acquire_state = SI_ACQUIRE_SIB2; + break; + case RRC_STATE_PLMN_SELECTION: + si_acquire_state = SI_ACQUIRE_IDLE; + rrc_log->info("SI Acquisition done. Searching next cell...\n"); + usleep(5000); + phy->cell_search_next(); + break; + default: + si_acquire_state = SI_ACQUIRE_IDLE; + } +} - // Jump to next state - switch(state) { - case RRC_STATE_CELL_SELECTING: - si_acquire_state = SI_ACQUIRE_SIB2; - break; - case RRC_STATE_PLMN_SELECTION: - si_acquire_state = SI_ACQUIRE_IDLE; - rrc_log->info("SI Acquisition done. Searching next cell...\n"); - usleep(5000); - phy->cell_search_next(); - break; - default: - si_acquire_state = SI_ACQUIRE_IDLE; - } +void rrc::handle_sib2() +{ + rrc_log->info("SIB2 received\n"); - } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && - SI_ACQUIRE_SIB2 == si_acquire_state) { - mac->bcch_stop_rx(); + apply_sib2_configs(¤t_cell->sib2); - // Handle SIB2 - memcpy(¤t_cell->sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); - rrc_log->info("SIB2 received\n"); +} - apply_sib2_configs(¤t_cell->sib2); +void rrc::handle_sib3() +{ + rrc_log->info("SIB3 received\n"); - current_cell->has_valid_sib2 = true; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = ¤t_cell->sib3; - // Jump to next state - switch(state) { - case RRC_STATE_CELL_SELECTING: - si_acquire_state = SI_ACQUIRE_IDLE; - state = RRC_STATE_CELL_SELECTED; - break; - default: - si_acquire_state = SI_ACQUIRE_IDLE; - } - } + // cellReselectionInfoCommon + cell_resel_cfg.q_hyst = liblte_rrc_q_hyst_num[sib3->q_hyst]; + + // cellReselectionServingFreqInfo + cell_resel_cfg.threshservinglow = sib3->thresh_serving_low; + + // intraFreqCellReselectionInfo + cell_resel_cfg.Qrxlevmin = sib3->q_rx_lev_min; + if (sib3->s_intra_search_present) { + cell_resel_cfg.s_intrasearchP = sib3->s_intra_search; + } else { + cell_resel_cfg.s_intrasearchP = INFINITY; } + } +void rrc::handle_sib13() +{ + rrc_log->info("SIB13 received\n"); + +// mac->set_config_mbsfn_sib13(¤t_cell->sib13.mbsfn_area_info_list_r9[0], +// current_cell->sib13.mbsfn_area_info_list_r9_size, +// ¤t_cell->sib13.mbsfn_notification_config); +} + + /******************************************************************************* @@ -1040,7 +1364,8 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { mac->pcch_stop_rx(); if (RRC_STATE_IDLE == state) { rrc_log->info("RRC in IDLE state - sending connection request.\n"); - state = RRC_STATE_CELL_SELECTING; + connection_requested = true; + state = RRC_STATE_CELL_SELECTED; } } } @@ -1057,17 +1382,72 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { -/******************************************************************************* -* -* -* -* Packet processing -* -* -* -*******************************************************************************/ +/******************************************************************************* +* +* +* +* Packet processing +* +* +*******************************************************************************/ +byte_buffer_t* rrc::byte_align_and_pack(byte_buffer_t *pdu) +{ + // Byte align and pack the message bits for PDCP + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + + // Reset and reuse sdu buffer if provided + byte_buffer_t *pdcp_buf = pdu; + + if (pdcp_buf) { + pdcp_buf->reset(); + } else { + pdcp_buf = pool_allocate; + } + + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits / 8; + pdcp_buf->set_timestamp(); + + return pdcp_buf; +} + +void rrc::send_ul_ccch_msg(byte_buffer_t *pdu) +{ + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + pdu = byte_align_and_pack(pdu); + + // Set UE contention resolution ID in MAC + uint64_t uecri = 0; + uint8_t *ue_cri_ptr = (uint8_t *) &uecri; + uint32_t nbytes = 6; + for (uint32_t i = 0; i < nbytes; i++) { + ue_cri_ptr[nbytes - i - 1] = pdu->msg[i]; + } + + rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); + mac->set_contention_id(uecri); + + rrc_log->info("Sending %s\n", liblte_rrc_ul_ccch_msg_type_text[ul_ccch_msg.msg_type]); + pdcp->write_sdu(RB_ID_SRB0, pdu); +} + +void rrc::send_ul_dcch_msg(byte_buffer_t *pdu) +{ + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + + pdu = byte_align_and_pack(pdu); + + rrc_log->info("Sending %s\n", liblte_rrc_ul_dcch_msg_type_text[ul_dcch_msg.msg_type]); + pdcp->write_sdu(RB_ID_SRB1, pdu); +} + void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid).c_str()); + + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU", get_rb_name(lcid)); switch (state) { case RRC_STATE_CONNECTING: send_con_setup_complete(sdu); @@ -1076,14 +1456,13 @@ void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { send_ul_info_transfer(lcid, sdu); break; default: - rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]); + rrc_log->error("SDU received from NAS while RRC state = %s\n", rrc_state_text[state]); break; } } void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", get_rb_name(lcid).c_str()); - rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); switch (lcid) { case RB_ID_SRB0: @@ -1094,7 +1473,7 @@ void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { parse_dl_dcch(lcid, pdu); break; default: - rrc_log->error("TX PDU with invalid bearer id: %s", lcid); + rrc_log->error("RX PDU with invalid bearer id: %s", lcid); break; } } @@ -1145,7 +1524,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_dcch_msg); rrc_log->info("%s - Received %s\n", - get_rb_name(lcid).c_str(), + get_rb_name(lcid), liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); // Reset and reuse pdu buffer if possible @@ -1164,12 +1543,23 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg; integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; - // Configure PDCP for security + rrc_log->info("Received Security Mode Command eea: %s, eia: %s\n", + ciphering_algorithm_id_text[cipher_algo], + integrity_algorithm_id_text[integ_algo]); + + // Generate AS security keys uint8_t k_asme[32]; nas->get_k_asme(k_asme, 32); usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + rrc_log->debug_hex(k_rrc_enc, 32, "RRC encryption key - k_rrc_enc"); + rrc_log->debug_hex(k_rrc_int, 32, "RRC integrity key - k_rrc_int"); + rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc"); + + // Configure PDCP for security pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp->enable_integrity(lcid); send_security_mode_complete(lcid, pdu); + pdcp->enable_encryption(lcid); break; case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG: transaction_id = dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id; @@ -1179,7 +1569,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { transaction_id = dl_dcch_msg.msg.ue_cap_enquiry.rrc_transaction_id; for (uint32_t i = 0; i < dl_dcch_msg.msg.ue_cap_enquiry.N_ue_cap_reqs; i++) { if (LIBLTE_RRC_RAT_TYPE_EUTRA == dl_dcch_msg.msg.ue_cap_enquiry.ue_capability_request[i]) { - send_rrc_ue_cap_info(lcid, pdu); + send_rrc_ue_cap_info(pdu); break; } } @@ -1215,9 +1605,8 @@ void rrc::enable_capabilities() { phy->set_config_64qam_en(enable_ul_64); } -void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { +void rrc::send_rrc_ue_cap_info(byte_buffer_t *pdu) { rrc_log->debug("Preparing UE Capability Info\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_CAPABILITY_INFO; ul_dcch_msg.msg.ue_capability_info.rrc_transaction_id = transaction_id; @@ -1265,18 +1654,7 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - - rrc_log->info("Sending UE Capability Info\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(pdu); } @@ -1298,6 +1676,54 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { * *******************************************************************************/ +void rrc::apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config) { + mac_interface_rrc::mac_cfg_t mac_cfg; + mac->get_config(&mac_cfg); + if (config->rach_cnfg_present) { + memcpy(&mac_cfg.rach, &config->rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); + } + mac_cfg.prach_config_index = config->prach_cnfg.root_sequence_index; + mac_cfg.ul_harq_params.max_harq_msg3_tx = config->rach_cnfg.max_harq_msg3_tx; + + mac->set_config(&mac_cfg); + + phy_interface_rrc::phy_cfg_t phy_cfg; + phy->get_config(&phy_cfg); + phy_interface_rrc::phy_cfg_common_t *common = &phy_cfg.common; + + if (config->pdsch_cnfg_present) { + memcpy(&common->pdsch_cnfg, &config->pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + } + common->prach_cnfg.root_sequence_index = config->prach_cnfg.root_sequence_index; + if (config->prach_cnfg.prach_cnfg_info_present) { + memcpy(&common->prach_cnfg.prach_cnfg_info, &config->prach_cnfg.prach_cnfg_info, sizeof(LIBLTE_RRC_PRACH_CONFIG_INFO_STRUCT)); + } + + phy->set_config_common(common); +} + +void rrc::apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config) { + phy_interface_rrc::phy_cfg_t phy_cfg; + phy->get_config(&phy_cfg); + phy_interface_rrc::phy_cfg_common_t *common = &phy_cfg.common; + + memcpy(&common->pusch_cnfg, &config->pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + if (config->pucch_cnfg_present) { + memcpy(&common->pucch_cnfg, &config->pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + } + if (config->ul_pwr_ctrl_present) { + memcpy(&common->ul_pwr_ctrl, &config->ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); + } + if (config->srs_ul_cnfg.present) { + memcpy(&common->srs_ul_cnfg, &config->srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); + } else { + // default is release + common->srs_ul_cnfg.present = false; + } + phy->set_config_common(common); + phy->configure_ul_params(); +} + void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { // Apply RACH timeAlginmentTimer configuration @@ -1308,6 +1734,11 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { memcpy(&cfg.rach, &sib2->rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); cfg.prach_config_index = sib2->rr_config_common_sib.prach_cnfg.root_sequence_index; cfg.ul_harq_params.max_harq_msg3_tx = cfg.rach.max_harq_msg3_tx; + // Apply MBSFN configuration +// cfg.mbsfn_subfr_cnfg_list_size = sib2->mbsfn_subfr_cnfg_list_size; +// for(uint8_t i=0;imbsfn_subfr_cnfg_list_size;i++) { +// memcpy(&cfg.mbsfn_subfr_cnfg_list[i], &sib2->mbsfn_subfr_cnfg_list[i], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT)); +// } mac->set_config(&cfg); @@ -1397,8 +1828,8 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT sizeof(LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT)); } else if (apply_defaults) { current_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; - current_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; - current_cfg->ul_pwr_ctrl_ded.accumulation_en = true; + current_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; + current_cfg->ul_pwr_ctrl_ded.accumulation_en = true; current_cfg->ul_pwr_ctrl_ded.p0_ue_pucch = 0; current_cfg->ul_pwr_ctrl_ded.p_srs_offset = 7; } @@ -1549,7 +1980,7 @@ void rrc::apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cnfg default_cfg.time_alignment_timer = mac_cnfg->time_alignment_timer; } - // Setup MAC configuration + // Setup MAC configuration mac->set_config_main(&default_cfg); // Update UL HARQ config @@ -1611,7 +2042,7 @@ void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) { void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) { mac_timers->timer_get(t301)->stop(); - // TODO: Restablish DRB1. Not done because never was suspended + // TODO: Reestablish DRB1. Not done because never was suspended // Apply the Radio Resource configuration apply_rr_config_dedicated(&setup->rr_cnfg); @@ -1627,6 +2058,8 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) { pdcp->add_bearer(srb_cnfg->srb_id, srslte_pdcp_config_t(true)); // Set PDCP config control flag if(RB_ID_SRB2 == srb_cnfg->srb_id) { pdcp->config_security(srb_cnfg->srb_id, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp->enable_integrity(srb_cnfg->srb_id); + pdcp->enable_encryption(srb_cnfg->srb_id); } // Setup RLC @@ -1665,7 +2098,7 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) { } srbs[srb_cnfg->srb_id] = *srb_cnfg; - rrc_log->info("Added radio bearer %s\n", get_rb_name(srb_cnfg->srb_id).c_str()); + rrc_log->info("Added radio bearer %s\n", get_rb_name(srb_cnfg->srb_id)); } void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { @@ -1693,7 +2126,8 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { } } pdcp->add_bearer(lcid, pdcp_cfg); - // TODO: setup PDCP security (using k_up_enc) + pdcp->config_security(lcid, k_up_enc, k_up_int, cipher_algo, integ_algo); + pdcp->enable_encryption(lcid); // Setup RLC rlc->add_bearer(lcid, srslte_rlc_config_t(&drb_cnfg->rlc_cnfg)); @@ -1723,7 +2157,7 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { drbs[lcid] = *drb_cnfg; drb_up = true; - rrc_log->info("Added radio bearer %s\n", get_rb_name(lcid).c_str()); + rrc_log->info("Added radio bearer %s\n", get_rb_name(lcid)); } void rrc::release_drb(uint8_t lcid) { @@ -1771,4 +2205,615 @@ void rrc::set_rrc_default() { } + + + + + + + + + + + + + + + + + +/************************************************************************ + * + * + * RRC Measurements + * + * + ************************************************************************/ + +void rrc::rrc_meas::init(rrc *parent) { + this->parent = parent; + this->log_h = parent->rrc_log; + this->phy = parent->phy; + this->mac_timers = parent->mac_timers; + s_measure_enabled = false; + reset(); +} + +void rrc::rrc_meas::reset() +{ + filter_k_rsrp = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + filter_k_rsrq = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + objects.clear(); + active.clear(); + reports_cfg.clear(); + phy->meas_reset(); + bzero(&pcell_measurement, sizeof(meas_value_t)); +} + +/* L3 filtering 5.5.3.2 */ +void rrc::rrc_meas::L3_filter(meas_value_t *value, float values[NOF_MEASUREMENTS]) +{ + for (int i=0;ims[i]) { + value->ms[i] = SRSLTE_VEC_EMA(values[i], value->ms[i], filter_a[i]); + } else { + value->ms[i] = values[i]; + } + } +} + +void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti) +{ + float values[NOF_MEASUREMENTS] = {rsrp, rsrq}; + // This indicates serving cell + if (earfcn == 0) { + + log_h->info("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti); + + L3_filter(&pcell_measurement, values); + } else { + // Add to known cells + parent->add_neighbour_cell(earfcn, pci, rsrp); + + log_h->info("MEAS: New measurement earfcn=%d, pci=%d, rsrp=%f, rsrq=%f, tti=%d\n", earfcn, pci, rsrp, rsrq, tti); + + // Save PHY measurement for all active measurements whose earfcn/pci matches + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t *m = &iter->second; + if (objects[m->object_id].earfcn == earfcn) { + // If it's a newly discovered cell, add it to objects + if (!m->cell_values.count(pci)) { + uint32_t cell_idx = objects[m->object_id].cells.size(); + objects[m->object_id].cells[cell_idx].pci = pci; + objects[m->object_id].cells[cell_idx].q_offset = 0; + } + // Update or add cell + L3_filter(&m->cell_values[pci], values); + return; + } + } + + parent->rrc_log->warning("MEAS: Received measurement from unknown EARFCN=%d\n", earfcn); + } +} + +void rrc::rrc_meas::run_tti(uint32_t tti) { + // Measurement Report Triggering Section 5.5.4 + calculate_triggers(tti); +} + +bool rrc::rrc_meas::find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t **object, int *cell_idx) { + if (object) { + *object = NULL; + } + for (std::map::iterator obj = objects.begin(); obj != objects.end(); ++obj) { + if (obj->second.earfcn == earfcn) { + if (object) { + *object = &obj->second; + } + for (std::map::iterator c = obj->second.cells.begin(); c != obj->second.cells.end(); ++c) { + if (c->second.pci == pci) { + if (cell_idx) { + *cell_idx = c->first; + return true; + } + } + } + // return true if cell idx not found but frequency is found + if (cell_idx) { + *cell_idx = -1; + } + return true; + } + } + return false; +} + +/* Generate report procedure 5.5.5 */ +void rrc::rrc_meas::generate_report(uint32_t meas_id) +{ + parent->ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT; + LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *report = &parent->ul_dcch_msg.msg.measurement_report; + + bzero(report, sizeof(LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT)); + + meas_t *m = &active[meas_id]; + report_cfg_t *cfg = &reports_cfg[m->report_id]; + + report->meas_id = meas_id; + report->pcell_rsrp_result = value_to_range(RSRP, pcell_measurement.ms[RSRP]); + report->pcell_rsrq_result = value_to_range(RSRQ, pcell_measurement.ms[RSRQ]); + + log_h->console("MEAS: Generate report MeasId=%d, rsrp=%f rsrq=%f\n", + report->meas_id, pcell_measurement.ms[RSRP], pcell_measurement.ms[RSRQ]); + + // TODO: report up to 8 best cells + for (std::map::iterator cell = m->cell_values.begin(); cell != m->cell_values.end(); ++cell) + { + if (cell->second.triggered && report->meas_result_neigh_cells.eutra.n_result < 8) + { + LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT *rc = &report->meas_result_neigh_cells.eutra.result_eutra_list[report->meas_result_neigh_cells.eutra.n_result]; + + rc->phys_cell_id = cell->first; + rc->meas_result.have_rsrp = cfg->report_quantity==RSRP || cfg->report_quantity==BOTH; + rc->meas_result.have_rsrq = cfg->report_quantity==RSRQ || cfg->report_quantity==BOTH; + rc->meas_result.rsrp_result = value_to_range(RSRP, cell->second.ms[RSRP]); + rc->meas_result.rsrq_result = value_to_range(RSRQ, cell->second.ms[RSRQ]); + + log_h->info("MEAS: Add neigh=%d, pci=%d, rsrp=%f, rsrq=%f\n", + report->meas_result_neigh_cells.eutra.n_result, rc->phys_cell_id, + cell->second.ms[RSRP], cell->second.ms[RSRQ]); + + report->meas_result_neigh_cells.eutra.n_result++; + } + } + report->have_meas_result_neigh_cells = report->meas_result_neigh_cells.eutra.n_result > 0; + + m->nof_reports_sent++; + mac_timers->timer_get(m->periodic_timer)->stop(); + + if (m->nof_reports_sent < cfg->amount) { + mac_timers->timer_get(m->periodic_timer)->reset(); + mac_timers->timer_get(m->periodic_timer)->run(); + } else { + if (cfg->trigger_type == report_cfg_t::PERIODIC) { + m->triggered = false; + } + } + + // Send to lower layers + parent->send_ul_dcch_msg(); +} + +/* Handle entering/leaving event conditions 5.5.4.1 */ +bool rrc::rrc_meas::process_event(LIBLTE_RRC_EVENT_EUTRA_STRUCT *event, uint32_t tti, + bool enter_condition, bool exit_condition, + meas_t *m, meas_value_t *cell) +{ + bool generate_report = false; + if (enter_condition && (!m->triggered || !cell->triggered)) { + if (!cell->timer_enter_triggered) { + cell->timer_enter_triggered = true; + cell->enter_tti = tti; + } else if (srslte_tti_interval(tti, cell->enter_tti) >= event->time_to_trigger) { + m->triggered = true; + cell->triggered = true; + m->nof_reports_sent = 0; + generate_report = true; + } + } else if (exit_condition) { + if (!cell->timer_exit_triggered) { + cell->timer_exit_triggered = true; + cell->exit_tti = tti; + } else if (srslte_tti_interval(tti, cell->exit_tti) >= event->time_to_trigger) { + m->triggered = false; + cell->triggered = false; + mac_timers->timer_get(m->periodic_timer)->stop(); + if (event) { + if (event->event_id == LIBLTE_RRC_EVENT_ID_EUTRA_A3 && event->event_a3.report_on_leave) { + generate_report = true; + } + } + } + } + if (!enter_condition) { + cell->timer_enter_triggered = false; + } + if (!enter_condition) { + cell->timer_exit_triggered = false; + } + return generate_report; +} + +/* Calculate trigger conditions for each cell 5.5.4 */ +void rrc::rrc_meas::calculate_triggers(uint32_t tti) +{ + float Ofp = 0, Ocp = 0; + meas_obj_t *serving_object = NULL; + int serving_cell_idx = 0; + + // Get serving cell + if (active.size()) { + if (find_earfcn_cell(phy->get_current_earfcn(), phy->get_current_pci(), &serving_object, &serving_cell_idx)) { + Ofp = serving_object->q_offset; + if (serving_cell_idx >= 0) { + Ocp = serving_object->cells[serving_cell_idx].q_offset; + } + } else { + log_h->warning("Can't find current eafcn=%d, pci=%d in objects list. Using Ofp=0, Ocp=0\n", + phy->get_current_earfcn(), phy->get_current_pci()); + } + } + + for (std::map::iterator m = active.begin(); m != active.end(); ++m) { + report_cfg_t *cfg = &reports_cfg[m->second.report_id]; + float hyst = 0.5*cfg->event.hysteresis; + float Mp = pcell_measurement.ms[cfg->trigger_quantity]; + + LIBLTE_RRC_EVENT_ID_EUTRA_ENUM event_id = cfg->event.event_id; + const char *event_str = liblte_rrc_event_id_eutra_text[event_id]; + + bool gen_report = false; + + if (cfg->trigger_type == report_cfg_t::EVENT) { + + // A1 & A2 are for serving cell only + if (event_id < LIBLTE_RRC_EVENT_ID_EUTRA_A3) { + + bool enter_condition; + bool exit_condition; + if (event_id == LIBLTE_RRC_EVENT_ID_EUTRA_A1) { + enter_condition = Mp - hyst > range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + exit_condition = Mp + hyst < range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + } else { + enter_condition = Mp + hyst < range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + exit_condition = Mp - hyst > range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + } + gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition, + &m->second, &m->second.cell_values[serving_cell_idx]); + + // Rest are evaluated for every cell in frequency + } else { + meas_obj_t *obj = &objects[m->second.object_id]; + for (std::map::iterator cell = obj->cells.begin(); cell != obj->cells.end(); ++cell) { + float Ofn = obj->q_offset; + float Ocn = cell->second.q_offset; + float Mn = m->second.cell_values[cell->second.pci].ms[cfg->trigger_quantity]; + float Off=0, th=0, th1=0, th2=0; + bool enter_condition = false; + bool exit_condition = false; + switch (event_id) { + case LIBLTE_RRC_EVENT_ID_EUTRA_A3: + Off = 0.5*cfg->event.event_a3.offset; + enter_condition = Mn + Ofn + Ocn - hyst > Mp + Ofp + Ocp + Off; + exit_condition = Mn + Ofn + Ocn + hyst < Mp + Ofp + Ocp + Off; + break; + case LIBLTE_RRC_EVENT_ID_EUTRA_A4: + th = range_to_value(cfg->trigger_quantity, cfg->event.event_a4.eutra.range); + enter_condition = Mn + Ofn + Ocn - hyst > th; + exit_condition = Mn + Ofn + Ocn + hyst < th; + break; + case LIBLTE_RRC_EVENT_ID_EUTRA_A5: + th1 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra1.range); + th2 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra2.range); + enter_condition = (Mp + hyst < th1) && (Mn + Ofn + Ocn - hyst > th2); + exit_condition = (Mp - hyst > th1) && (Mn + Ofn + Ocn + hyst < th2); + break; + default: + log_h->error("Error event %s not implemented\n", event_str); + } + gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition, + &m->second, &m->second.cell_values[cell->second.pci]); + } + } + } + if (gen_report) { + generate_report(m->first); + } + } +} + +// Procedure upon handover or reestablishment 5.5.6.1 +void rrc::rrc_meas::ho_finish() { + // Remove all measId with trigger periodic + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (reports_cfg[iter->second.report_id].trigger_type == report_cfg_t::PERIODIC) { + remove_meas_id(iter++); + } else { + ++iter; + } + } + + //TODO: Inter-frequency handover + + // Stop all reports + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + stop_reports(&iter->second); + } +} + +// 5.5.4.1 expiry of periodical reporting timer +bool rrc::rrc_meas::timer_expired(uint32_t timer_id) { + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + if (iter->second.periodic_timer == timer_id) { + generate_report(iter->first); + return true; + } + } + return false; +} + +void rrc::rrc_meas::stop_reports(meas_t *m) { + mac_timers->timer_get(m->periodic_timer)->stop(); + m->triggered = false; +} + +void rrc::rrc_meas::stop_reports_object(uint32_t object_id) { + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + if (iter->second.object_id == object_id) { + stop_reports(&iter->second); + } + } +} + +void rrc::rrc_meas::remove_meas_object(uint32_t object_id) { + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (iter->second.object_id == object_id) { + remove_meas_id(iter++); + } else { + ++iter; + } + } +} + +void rrc::rrc_meas::remove_meas_report(uint32_t report_id) { + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (iter->second.report_id == report_id) { + remove_meas_id(iter++); + } else { + ++iter; + } + } +} + +void rrc::rrc_meas::remove_meas_id(uint32_t measId) { + mac_timers->timer_get(active[measId].periodic_timer)->stop(); + mac_timers->timer_release_id(active[measId].periodic_timer); + log_h->info("MEAS: Removed measId=%d\n", measId); + active.erase(measId); +} + +void rrc::rrc_meas::remove_meas_id(std::map::iterator it) { + mac_timers->timer_get(it->second.periodic_timer)->stop(); + mac_timers->timer_release_id(it->second.periodic_timer); + log_h->info("MEAS: Removed measId=%d\n", it->first); + active.erase(it); +} + +/* Parses MeasConfig object from RRCConnectionReconfiguration message and applies configuration + * as per section 5.5.2 + */ +void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) +{ + + // Measurement object removal 5.5.2.4 + for (uint32_t i=0;iN_meas_obj_to_remove;i++) { + objects.erase(cfg->meas_obj_to_remove_list[i]); + remove_meas_object(cfg->meas_obj_to_remove_list[i]); + log_h->info("MEAS: Removed measObjectId=%d\n", cfg->meas_obj_to_remove_list[i]); + } + + // Measurement object addition/modification Section 5.5.2.5 + if (cfg->meas_obj_to_add_mod_list_present) { + for (uint32_t i=0;imeas_obj_to_add_mod_list.N_meas_obj;i++) { + if (cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_type == LIBLTE_RRC_MEAS_OBJECT_TYPE_EUTRA) { + LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT *src_obj = &cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_eutra; + + // Access the object if exists or create it + meas_obj_t *dst_obj = &objects[cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id]; + + dst_obj->earfcn = src_obj->carrier_freq;; + if (src_obj->offset_freq_not_default) { + dst_obj->q_offset = liblte_rrc_q_offset_range_num[src_obj->offset_freq]; + } else { + dst_obj->q_offset = 0; + } + + if (src_obj->black_cells_to_remove_list_present) { + for (uint32_t j=0;jblack_cells_to_remove_list.N_cell_idx;j++) { + dst_obj->cells.erase(src_obj->black_cells_to_remove_list.cell_idx[j]); + } + } + + for (uint32_t j=0;jN_cells_to_add_mod;j++) { + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset = liblte_rrc_q_offset_range_num[src_obj->cells_to_add_mod_list[j].cell_offset]; + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci = src_obj->cells_to_add_mod_list[j].pci; + + log_h->info("MEAS: Added measObjectId=%d, earfcn=%d, q_offset=%f, pci=%d, offset_cell=%f\n", + cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id, dst_obj->earfcn, dst_obj->q_offset, + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset, + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci); + + } + + // Untrigger reports and stop timers + stop_reports_object(cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id); + + // TODO: Blackcells + // TODO: meassubframepattern + + } else { + log_h->warning("MEAS: Unsupported MeasObject type %s\n", + liblte_rrc_meas_object_type_text[cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_type]); + } + } + } + + // Reporting configuration removal 5.5.2.6 + for (uint32_t i=0;iN_rep_cnfg_to_remove;i++) { + reports_cfg.erase(cfg->rep_cnfg_to_remove_list[i]); + remove_meas_report(cfg->rep_cnfg_to_remove_list[i]); + log_h->info("MEAS: Removed reportConfigId=%d\n", cfg->rep_cnfg_to_remove_list[i]); + } + + // Reporting configuration addition/modification 5.5.2.7 + if (cfg->rep_cnfg_to_add_mod_list_present) { + for (uint32_t i=0;irep_cnfg_to_add_mod_list.N_rep_cnfg;i++) { + if (cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_type == LIBLTE_RRC_REPORT_CONFIG_TYPE_EUTRA) { + LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT *src_rep = &cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_eutra; + // Access the object if exists or create it + report_cfg_t *dst_rep = &reports_cfg[cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id]; + + dst_rep->trigger_type = src_rep->trigger_type==LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT?report_cfg_t::EVENT:report_cfg_t::PERIODIC; + dst_rep->event = src_rep->event; + dst_rep->amount = liblte_rrc_report_amount_num[src_rep->report_amount]; + dst_rep->interval = liblte_rrc_report_interval_num[src_rep->report_interval]; + dst_rep->max_cell = src_rep->max_report_cells; + dst_rep->trigger_quantity = (quantity_t) src_rep->trigger_quantity; + dst_rep->report_quantity = src_rep->report_quantity==LIBLTE_RRC_REPORT_QUANTITY_SAME_AS_TRIGGER_QUANTITY?dst_rep->trigger_quantity:BOTH; + + log_h->info("MEAS: Added reportConfigId=%d, event=%s, amount=%d, interval=%d\n", + cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id, + liblte_rrc_event_id_eutra_text[dst_rep->event.event_id], + dst_rep->amount, dst_rep->interval); + + // Reset reports counter + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + if (iter->second.report_id == cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id) { + iter->second.nof_reports_sent = 0; + stop_reports(&iter->second); + } + } + } else { + log_h->warning("MEAS: Unsupported reportConfigType %s\n", liblte_rrc_report_config_type_text[cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_type]); + } + } + } + + // Quantity configuration 5.5.2.8 + if (cfg->quantity_cnfg_present && cfg->quantity_cnfg.qc_eutra_present) { + if (cfg->quantity_cnfg.qc_eutra.fc_rsrp_not_default) { + filter_k_rsrp = liblte_rrc_filter_coefficient_num[cfg->quantity_cnfg.qc_eutra.fc_rsrp]; + } else { + filter_k_rsrp = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + } + if (cfg->quantity_cnfg.qc_eutra.fc_rsrq_not_default) { + filter_k_rsrq = liblte_rrc_filter_coefficient_num[cfg->quantity_cnfg.qc_eutra.fc_rsrq]; + } else { + filter_k_rsrq = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + } + filter_a[RSRP] = pow(0.5, (float) filter_k_rsrp/4); + filter_a[RSRQ] = pow(0.5, (float) filter_k_rsrq/4); + + log_h->info("MEAS: Quantity configuration k_rsrp=%d, k_rsrq=%d\n", filter_k_rsrp, filter_k_rsrq); + } + + // Measurement identity removal 5.5.2.2 + for (uint32_t i=0;iN_meas_id_to_remove;i++) { + remove_meas_id(cfg->meas_id_to_remove_list[i]); + } + + // Measurement identity addition/modification 5.5.2.3 + if (cfg->meas_id_to_add_mod_list_present) { + for (uint32_t i=0;imeas_id_to_add_mod_list.N_meas_id;i++) { + LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_STRUCT *measId = &cfg->meas_id_to_add_mod_list.meas_id_list[i]; + // Stop the timer if the entry exists or create the timer if not + if (active.count(measId->meas_id)) { + mac_timers->timer_get(active[measId->meas_id].periodic_timer)->stop(); + } else { + active[measId->meas_id].periodic_timer = mac_timers->timer_get_unique_id(); + } + active[measId->meas_id].object_id = measId->meas_obj_id; + active[measId->meas_id].report_id = measId->rep_cnfg_id; + log_h->info("MEAS: Added measId=%d, measObjectId=%d, reportConfigId=%d\n", + measId->meas_id, measId->meas_obj_id, measId->rep_cnfg_id); + } + } + + // S-Measure + if (cfg->s_meas_present) { + if (cfg->s_meas) { + s_measure_enabled = true; + s_measure_value = range_to_value(RSRP, cfg->s_meas); + } else { + s_measure_enabled = false; + } + } + + update_phy(); +} + +/* Instruct PHY to start measurement */ +void rrc::rrc_meas::update_phy() +{ + phy->meas_reset(); + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t m = iter->second; + meas_obj_t o = objects[m.object_id]; + // Instruct PHY to look for neighbour cells on this frequency + phy->meas_start(o.earfcn); + for(std::map::iterator iter=o.cells.begin(); iter!=o.cells.end(); ++iter) { + // Instruct PHY to look for cells IDs on this frequency + phy->meas_start(o.earfcn, iter->second.pci); + } + } +} + + +uint8_t rrc::rrc_meas::value_to_range(quantity_t quant, float value) { + uint8_t range = 0; + switch(quant) { + case RSRP: + if (value < -140) { + range = 0; + } else if (-140 <= value && value < -44) { + range = 1 + (uint8_t) (value + 140); + } else { + range = 97; + } + break; + case RSRQ: + if (value < -19.5) { + range = 0; + } else if (-19.5 <= value && value < -3) { + range = 1 + (uint8_t) (2*(value + 19.5)); + } else { + range = 34; + } + break; + case BOTH: + printf("Error quantity both not supported in value_to_range\n"); + break; + } + return range; +} + +float rrc::rrc_meas::range_to_value(quantity_t quant, uint8_t range) { + float val = 0; + switch(quant) { + case RSRP: + val = -140+(float) range; + break; + case RSRQ: + val = -19.5+(float) range/2; + break; + case BOTH: + printf("Error quantity both not supported in range_to_value\n"); + break; + } + return val; +} + + + + + + + + + + } // namespace srsue diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index 7ae53988b..fe70797e3 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -223,6 +223,8 @@ void usim::generate_nas_keys(uint8_t *k_asme, integ_algo, k_nas_enc, k_nas_int); + + } /******************************************************************************* @@ -238,10 +240,75 @@ void usim::generate_as_keys(uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { + // Generate K_enb - security_generate_k_enb( k_asme, - count_ul, - k_enb); + security_generate_k_enb( k_asme, + count_ul, + k_enb); + + memcpy(this->k_asme, k_asme, 32); + + // Generate K_rrc_enc and K_rrc_int + security_generate_k_rrc( k_enb, + cipher_algo, + integ_algo, + k_rrc_enc, + k_rrc_int); + + // Generate K_up_enc and K_up_int + security_generate_k_up( k_enb, + cipher_algo, + integ_algo, + k_up_enc, + k_up_int); + + current_ncc = 0; +} + +void usim::generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + int ncc, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + uint8_t *enb_star_key = k_enb; + + if (ncc < 0) { + ncc = current_ncc; + } + + // Generate successive NH + while(current_ncc != (uint32_t) ncc) { + uint8_t *sync = NULL; + if (current_ncc) { + sync = nh; + } else { + sync = k_enb; + } + // Generate NH + security_generate_nh(k_asme, + sync, + nh); + + current_ncc++; + if (current_ncc == 7) { + current_ncc = 0; + } + enb_star_key = nh; + } + + // Generate K_enb + security_generate_k_enb_star( enb_star_key, + pci, + earfcn, + k_enb_star); + + // K_enb becomes K_enb* + memcpy(k_enb, k_enb_star, 32); // Generate K_rrc_enc and K_rrc_int security_generate_k_rrc( k_enb, diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 7bd6fae18..444f9e156 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -50,6 +50,8 @@ rx_gain = 40 [pcap] enable = false filename = /tmp/ue.pcap +nas_enable = false +nas_filename = /tmp/nas.pcap ##################################################################### # Log configuration @@ -152,6 +154,10 @@ enable = false # average_subframe_enabled: Averages in the time domain the channel estimates within 1 subframe. # Needs accurate CFO correction. # +# sic_pss_enabled: Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. +# Must be disabled if cells have identical channel and timing, for instance if generated from +# the same source. +# # metrics_csv_enable: Write UE metrics to CSV file. # # metrics_csv_filename: File path to use for CSV metrics. @@ -188,7 +194,8 @@ enable = false #sfo_correct_disable = false #sss_algorithm = full #estimator_fil_w = 0.1 -#average_subframe_enabled = true +#average_subframe_enabled = false +#sic_pss_enabled = true #pregenerate_signals = false #metrics_csv_enable = false #metrics_csv_filename = /tmp/ue_metrics.csv