mirror of https://github.com/pvnis/srsRAN_4G.git
add upper layer code including tests
parent
ae186d8195
commit
3ea8d7c721
@ -0,0 +1,87 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GW_H
|
||||
#define GW_H
|
||||
|
||||
#include "common/buffer_pool.h"
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/msg_queue.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/threads.h"
|
||||
#include "upper/gw_metrics.h"
|
||||
|
||||
#include <linux/if.h>
|
||||
|
||||
namespace srsue {
|
||||
|
||||
class gw
|
||||
:public gw_interface_pdcp
|
||||
,public gw_interface_nas
|
||||
,public thread
|
||||
{
|
||||
public:
|
||||
gw();
|
||||
void init(pdcp_interface_gw *pdcp_, rrc_interface_gw *rrc_, ue_interface *ue_, srslte::log *gw_log_);
|
||||
void stop();
|
||||
|
||||
void get_metrics(gw_metrics_t &m);
|
||||
|
||||
// PDCP interface
|
||||
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu);
|
||||
|
||||
// NAS interface
|
||||
srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str);
|
||||
|
||||
private:
|
||||
|
||||
static const int GW_THREAD_PRIO = 7;
|
||||
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *gw_log;
|
||||
pdcp_interface_gw *pdcp;
|
||||
rrc_interface_gw *rrc;
|
||||
ue_interface *ue;
|
||||
bool running;
|
||||
bool run_enable;
|
||||
int32 tun_fd;
|
||||
struct ifreq ifr;
|
||||
int32 sock;
|
||||
bool if_up;
|
||||
|
||||
long ul_tput_bytes;
|
||||
long dl_tput_bytes;
|
||||
struct timeval metrics_time[3];
|
||||
|
||||
void run_thread();
|
||||
srslte::error_t init_if(char *err_str);
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // GW_H
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UE_GW_METRICS_H
|
||||
#define UE_GW_METRICS_H
|
||||
|
||||
|
||||
namespace srsue {
|
||||
|
||||
struct gw_metrics_t
|
||||
{
|
||||
double dl_tput_mbps;
|
||||
double ul_tput_mbps;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
#endif // UE_GW_METRICS_H
|
@ -0,0 +1,146 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NAS_H
|
||||
#define NAS_H
|
||||
|
||||
#include "common/buffer_pool.h"
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/security.h"
|
||||
#include "liblte_mme.h"
|
||||
|
||||
using srslte::byte_buffer_t;
|
||||
|
||||
namespace srsue {
|
||||
|
||||
// EMM states (3GPP 24.302 v10.0.0)
|
||||
typedef enum{
|
||||
EMM_STATE_NULL = 0,
|
||||
EMM_STATE_DEREGISTERED,
|
||||
EMM_STATE_REGISTERED_INITIATED,
|
||||
EMM_STATE_REGISTERED,
|
||||
EMM_STATE_SERVICE_REQUEST_INITIATED,
|
||||
EMM_STATE_DEREGISTERED_INITIATED,
|
||||
EMM_STATE_TAU_INITIATED,
|
||||
EMM_STATE_N_ITEMS,
|
||||
}emm_state_t;
|
||||
static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL",
|
||||
"DEREGISTERED",
|
||||
"REGISTERED INITIATED",
|
||||
"REGISTERED",
|
||||
"SERVICE REQUEST INITIATED",
|
||||
"DEREGISTERED INITIATED",
|
||||
"TRACKING AREA UPDATE INITIATED"};
|
||||
|
||||
class nas
|
||||
:public nas_interface_rrc
|
||||
{
|
||||
public:
|
||||
nas();
|
||||
void init(usim_interface_nas *usim_,
|
||||
rrc_interface_nas *rrc_,
|
||||
gw_interface_nas *gw_,
|
||||
srslte::log *nas_log_);
|
||||
void stop();
|
||||
|
||||
emm_state_t get_state();
|
||||
|
||||
// RRC interface
|
||||
void notify_connection_setup();
|
||||
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
||||
uint32_t get_ul_count();
|
||||
bool is_attached();
|
||||
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
|
||||
|
||||
private:
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *nas_log;
|
||||
rrc_interface_nas *rrc;
|
||||
usim_interface_nas *usim;
|
||||
gw_interface_nas *gw;
|
||||
|
||||
emm_state_t state;
|
||||
|
||||
// Save short MAC
|
||||
|
||||
// Identifiers
|
||||
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
|
||||
bool is_guti_set;
|
||||
|
||||
uint32_t ip_addr;
|
||||
uint8_t eps_bearer_id;
|
||||
|
||||
uint8_t transaction_id;
|
||||
|
||||
// NAS counters - incremented for each security-protected message recvd/sent
|
||||
uint32_t count_ul;
|
||||
uint32_t count_dl;
|
||||
|
||||
// Security
|
||||
uint8_t ksi;
|
||||
uint8_t k_nas_enc[32];
|
||||
uint8_t k_nas_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,
|
||||
uint32_t msg_len,
|
||||
uint8_t *mac);
|
||||
void integrity_check();
|
||||
void cipher_encrypt();
|
||||
void cipher_decrypt();
|
||||
|
||||
// Parsers
|
||||
void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu);
|
||||
|
||||
// Senders
|
||||
void send_attach_request();
|
||||
void send_identity_response();
|
||||
void send_service_request();
|
||||
void send_esm_information_response();
|
||||
|
||||
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // NAS_H
|
@ -0,0 +1,85 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PDCP_H
|
||||
#define PDCP_H
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "upper/pdcp_entity.h"
|
||||
|
||||
using srslte::byte_buffer_t;
|
||||
|
||||
namespace srsue {
|
||||
|
||||
class pdcp
|
||||
:public pdcp_interface_gw
|
||||
,public pdcp_interface_rlc
|
||||
,public pdcp_interface_rrc
|
||||
{
|
||||
public:
|
||||
pdcp();
|
||||
void init(rlc_interface_pdcp *rlc_,
|
||||
rrc_interface_pdcp *rrc_,
|
||||
gw_interface_pdcp *gw_,
|
||||
srslte::log *pdcp_log_,
|
||||
uint8_t direction_);
|
||||
void stop();
|
||||
|
||||
// RRC interface
|
||||
void reset();
|
||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
|
||||
void add_bearer(uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg = NULL);
|
||||
void config_security(uint32_t lcid,
|
||||
uint8_t *k_rrc_enc,
|
||||
uint8_t *k_rrc_int,
|
||||
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
||||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
|
||||
|
||||
// RLC interface
|
||||
void write_pdu(uint32_t lcid, byte_buffer_t *sdu);
|
||||
void write_pdu_bcch_bch(byte_buffer_t *sdu);
|
||||
void write_pdu_bcch_dlsch(byte_buffer_t *sdu);
|
||||
void write_pdu_pcch(byte_buffer_t *sdu);
|
||||
|
||||
private:
|
||||
srslte::log *pdcp_log;
|
||||
pdcp_entity pdcp_array[SRSUE_N_RADIO_BEARERS];
|
||||
|
||||
rlc_interface_pdcp *rlc;
|
||||
rrc_interface_pdcp *rrc;
|
||||
gw_interface_pdcp *gw;
|
||||
|
||||
uint8_t direction;
|
||||
|
||||
bool valid_lcid(uint32_t lcid);
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // PDCP_H
|
@ -0,0 +1,139 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PDCP_ENTITY_H
|
||||
#define PDCP_ENTITY_H
|
||||
|
||||
#include "common/buffer_pool.h"
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/security.h"
|
||||
|
||||
using srslte::byte_buffer_t;
|
||||
|
||||
|
||||
namespace srsue {
|
||||
|
||||
/****************************************************************************
|
||||
* Structs and Defines
|
||||
* Ref: 3GPP TS 36.323 v10.1.0
|
||||
***************************************************************************/
|
||||
|
||||
#define PDCP_CONTROL_MAC_I 0x00000000
|
||||
|
||||
#define PDCP_PDU_TYPE_PDCP_STATUS_REPORT 0x0
|
||||
#define PDCP_PDU_TYPE_INTERSPERSED_ROHC_FEEDBACK_PACKET 0x1
|
||||
|
||||
typedef enum{
|
||||
PDCP_D_C_CONTROL_PDU = 0,
|
||||
PDCP_D_C_DATA_PDU,
|
||||
PDCP_D_C_N_ITEMS,
|
||||
}pdcp_d_c_t;
|
||||
static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU",
|
||||
"Data PDU"};
|
||||
|
||||
/****************************************************************************
|
||||
* PDCP Entity interface
|
||||
* Common interface for all PDCP entities
|
||||
***************************************************************************/
|
||||
class pdcp_entity
|
||||
{
|
||||
public:
|
||||
pdcp_entity();
|
||||
void init(rlc_interface_pdcp *rlc_,
|
||||
rrc_interface_pdcp *rrc_,
|
||||
gw_interface_pdcp *gw_,
|
||||
srslte::log *log_,
|
||||
uint32_t lcid_,
|
||||
uint8_t direction_,
|
||||
LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg = NULL
|
||||
);
|
||||
void reset();
|
||||
|
||||
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_,
|
||||
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
|
||||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_);
|
||||
|
||||
// RLC interface
|
||||
void write_pdu(byte_buffer_t *pdu);
|
||||
|
||||
private:
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *log;
|
||||
rlc_interface_pdcp *rlc;
|
||||
rrc_interface_pdcp *rrc;
|
||||
gw_interface_pdcp *gw;
|
||||
|
||||
bool active;
|
||||
uint32_t lcid;
|
||||
bool do_security;
|
||||
u_int8_t direction;
|
||||
|
||||
uint8_t sn_len;
|
||||
// TODO: Support the following configurations
|
||||
// bool do_rohc;
|
||||
|
||||
uint32_t rx_count;
|
||||
uint32_t tx_count;
|
||||
uint8_t k_rrc_enc[32];
|
||||
uint8_t k_rrc_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,
|
||||
uint32_t msg_len,
|
||||
uint8_t *mac);
|
||||
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Pack/Unpack helper functions
|
||||
* Ref: 3GPP TS 36.323 v10.1.0
|
||||
***************************************************************************/
|
||||
|
||||
void pdcp_pack_control_pdu(uint32_t sn, byte_buffer_t *sdu);
|
||||
void pdcp_unpack_control_pdu(byte_buffer_t *sdu, uint32_t *sn);
|
||||
|
||||
void pdcp_pack_data_pdu_short_sn(uint32_t sn, byte_buffer_t *sdu);
|
||||
void pdcp_unpack_data_pdu_short_sn(byte_buffer_t *sdu, uint32_t *sn);
|
||||
void pdcp_pack_data_pdu_long_sn(uint32_t sn, byte_buffer_t *sdu);
|
||||
void pdcp_unpack_data_pdu_long_sn(byte_buffer_t *sdu, uint32_t *sn);
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // PDCP_ENTITY_H
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RLC_H
|
||||
#define RLC_H
|
||||
|
||||
#include "common/buffer_pool.h"
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/msg_queue.h"
|
||||
#include "upper/rlc_entity.h"
|
||||
#include "upper/rlc_metrics.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
/****************************************************************************
|
||||
* RLC Layer
|
||||
* Ref: 3GPP TS 36.322 v10.0.0
|
||||
* Single interface for RLC layer - contains separate RLC entities for
|
||||
* each bearer.
|
||||
***************************************************************************/
|
||||
class rlc
|
||||
:public rlc_interface_mac
|
||||
,public rlc_interface_pdcp
|
||||
,public rlc_interface_rrc
|
||||
{
|
||||
public:
|
||||
rlc();
|
||||
void init(pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
ue_interface *ue_,
|
||||
srslte::log *rlc_log_,
|
||||
srslte::mac_interface_timers *mac_timers_);
|
||||
void stop();
|
||||
|
||||
void get_metrics(rlc_metrics_t &m);
|
||||
|
||||
// PDCP interface
|
||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
|
||||
|
||||
// MAC interface
|
||||
uint32_t get_buffer_state(uint32_t lcid);
|
||||
uint32_t get_total_buffer_state(uint32_t lcid);
|
||||
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes);
|
||||
|
||||
// RRC interface
|
||||
void reset();
|
||||
void add_bearer(uint32_t lcid);
|
||||
void add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg);
|
||||
|
||||
private:
|
||||
void reset_metrics();
|
||||
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *rlc_log;
|
||||
pdcp_interface_rlc *pdcp;
|
||||
rrc_interface_rlc *rrc;
|
||||
srslte::mac_interface_timers *mac_timers;
|
||||
ue_interface *ue;
|
||||
rlc_entity rlc_array[SRSUE_N_RADIO_BEARERS];
|
||||
|
||||
long ul_tput_bytes[SRSUE_N_RADIO_BEARERS];
|
||||
long dl_tput_bytes[SRSUE_N_RADIO_BEARERS];
|
||||
struct timeval metrics_time[3];
|
||||
|
||||
bool valid_lcid(uint32_t lcid);
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // RLC_H
|
@ -0,0 +1,230 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RLC_AM_H
|
||||
#define RLC_AM_H
|
||||
|
||||
#include "common/buffer_pool.h"
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/msg_queue.h"
|
||||
#include "common/timeout.h"
|
||||
#include "upper/rlc_common.h"
|
||||
#include <map>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
|
||||
using srslte::byte_buffer_t;
|
||||
|
||||
namespace srsue {
|
||||
|
||||
|
||||
|
||||
struct rlc_amd_rx_pdu_t{
|
||||
rlc_amd_pdu_header_t header;
|
||||
byte_buffer_t *buf;
|
||||
};
|
||||
|
||||
struct rlc_amd_rx_pdu_segments_t{
|
||||
std::list<rlc_amd_rx_pdu_t> segments;
|
||||
};
|
||||
|
||||
struct rlc_amd_tx_pdu_t{
|
||||
rlc_amd_pdu_header_t header;
|
||||
byte_buffer_t *buf;
|
||||
uint32_t retx_count;
|
||||
bool is_acked;
|
||||
};
|
||||
|
||||
struct rlc_amd_retx_t{
|
||||
uint32_t sn;
|
||||
bool is_segment;
|
||||
uint32_t so_start;
|
||||
uint32_t so_end;
|
||||
};
|
||||
|
||||
|
||||
class rlc_am
|
||||
:public rlc_common
|
||||
{
|
||||
public:
|
||||
rlc_am();
|
||||
void init(srslte::log *rlc_entity_log_,
|
||||
uint32_t lcid_,
|
||||
pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
srslte::mac_interface_timers *mac_timers);
|
||||
void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg);
|
||||
void reset();
|
||||
void empty_queue();
|
||||
|
||||
rlc_mode_t get_mode();
|
||||
uint32_t get_bearer();
|
||||
|
||||
// PDCP interface
|
||||
void write_sdu(byte_buffer_t *sdu);
|
||||
|
||||
// MAC interface
|
||||
uint32_t get_buffer_state();
|
||||
uint32_t get_total_buffer_state();
|
||||
int read_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
|
||||
private:
|
||||
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *log;
|
||||
uint32_t lcid;
|
||||
pdcp_interface_rlc *pdcp;
|
||||
rrc_interface_rlc *rrc;
|
||||
|
||||
// TX SDU buffers
|
||||
srslte::msg_queue tx_sdu_queue;
|
||||
byte_buffer_t *tx_sdu;
|
||||
|
||||
// PDU being resegmented
|
||||
rlc_amd_tx_pdu_t tx_pdu_segments;
|
||||
|
||||
// Tx and Rx windows
|
||||
std::map<uint32_t, rlc_amd_tx_pdu_t> tx_window;
|
||||
std::deque<rlc_amd_retx_t> retx_queue;
|
||||
std::map<uint32_t, rlc_amd_rx_pdu_t> rx_window;
|
||||
std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments;
|
||||
|
||||
// RX SDU buffers
|
||||
byte_buffer_t *rx_sdu;
|
||||
|
||||
// Mutexes
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
bool poll_received;
|
||||
bool do_status;
|
||||
rlc_status_pdu_t status;
|
||||
|
||||
/****************************************************************************
|
||||
* Configurable parameters
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
|
||||
// TX configs
|
||||
int32_t t_poll_retx; // Poll retx timeout (ms)
|
||||
int32_t poll_pdu; // Insert poll bit after this many PDUs
|
||||
int32_t poll_byte; // Insert poll bit after this much data (KB)
|
||||
int32_t max_retx_thresh; // Max number of retx
|
||||
|
||||
// RX configs
|
||||
int32_t t_reordering; // Timer used by rx to detect PDU loss (ms)
|
||||
int32_t t_status_prohibit; // Timer used by rx to prohibit tx of status PDU (ms)
|
||||
|
||||
/****************************************************************************
|
||||
* State variables and counters
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
|
||||
// Tx state variables
|
||||
uint32_t vt_a; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window.
|
||||
uint32_t vt_ms; // Max send state. High edge of tx window. vt_a + window_size.
|
||||
uint32_t vt_s; // Send state. SN to be assigned for next PDU.
|
||||
uint32_t poll_sn; // Poll send state. SN of most recent PDU txed with poll bit set.
|
||||
|
||||
// Tx counters
|
||||
uint32_t pdu_without_poll;
|
||||
uint32_t byte_without_poll;
|
||||
|
||||
// Rx state variables
|
||||
uint32_t vr_r; // Receive state. SN following last in-sequence received PDU. Low edge of rx window
|
||||
uint32_t vr_mr; // Max acceptable receive state. High edge of rx window. vr_r + window size.
|
||||
uint32_t vr_x; // t_reordering state. SN following PDU which triggered t_reordering.
|
||||
uint32_t vr_ms; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU.
|
||||
uint32_t vr_h; // Highest rx state. SN following PDU with highest SN among rxed PDUs.
|
||||
|
||||
/****************************************************************************
|
||||
* Timers
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
srslte::timeout poll_retx_timeout;
|
||||
srslte::timeout reordering_timeout;
|
||||
srslte::timeout status_prohibit_timeout;
|
||||
|
||||
static const int reordering_timeout_id = 1;
|
||||
|
||||
// Timer checks
|
||||
bool status_prohibited();
|
||||
bool poll_retx();
|
||||
void check_reordering_timeout();
|
||||
|
||||
// Helpers
|
||||
bool poll_required();
|
||||
|
||||
int prepare_status();
|
||||
int build_status_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
int build_retx_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
int build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx);
|
||||
int build_data_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
|
||||
void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t header);
|
||||
void handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t header);
|
||||
void handle_control_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
|
||||
void reassemble_rx_sdus();
|
||||
|
||||
bool inside_tx_window(uint16_t sn);
|
||||
bool inside_rx_window(uint16_t sn);
|
||||
void debug_state();
|
||||
|
||||
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment);
|
||||
int required_buffer_size(rlc_amd_retx_t retx);
|
||||
bool retx_queue_has_sn(uint32_t sn);
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Header pack/unpack helper functions
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
|
||||
***************************************************************************/
|
||||
void rlc_am_read_data_pdu_header(byte_buffer_t *pdu, rlc_amd_pdu_header_t *header);
|
||||
void rlc_am_read_data_pdu_header(uint8_t **payload, uint32_t *nof_bytes, rlc_amd_pdu_header_t *header);
|
||||
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t *header, byte_buffer_t *pdu);
|
||||
void rlc_am_write_data_pdu_header(rlc_amd_pdu_header_t *header, uint8_t **payload);
|
||||
void rlc_am_read_status_pdu(byte_buffer_t *pdu, rlc_status_pdu_t *status);
|
||||
void rlc_am_read_status_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_status_pdu_t *status);
|
||||
void rlc_am_write_status_pdu(rlc_status_pdu_t *status, byte_buffer_t *pdu );
|
||||
int rlc_am_write_status_pdu(rlc_status_pdu_t *status, uint8_t *payload);
|
||||
|
||||
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header);
|
||||
uint32_t rlc_am_packed_length(rlc_status_pdu_t *status);
|
||||
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
|
||||
bool rlc_am_is_control_pdu(byte_buffer_t *pdu);
|
||||
bool rlc_am_is_control_pdu(uint8_t *payload);
|
||||
bool rlc_am_is_pdu_segment(uint8_t *payload);
|
||||
std::string rlc_am_to_string(rlc_status_pdu_t *status);
|
||||
bool rlc_am_start_aligned(uint8_t fi);
|
||||
bool rlc_am_end_aligned(uint8_t fi);
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // RLC_AM_H
|
@ -0,0 +1,184 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RLC_COMMON_H
|
||||
#define RLC_COMMON_H
|
||||
|
||||
namespace srsue {
|
||||
|
||||
/****************************************************************************
|
||||
* Structs and Defines
|
||||
* Ref: 3GPP TS 36.322 v10.0.0
|
||||
***************************************************************************/
|
||||
|
||||
#define RLC_AM_WINDOW_SIZE 512
|
||||
|
||||
typedef enum{
|
||||
RLC_MODE_TM = 0,
|
||||
RLC_MODE_UM,
|
||||
RLC_MODE_AM,
|
||||
RLC_MODE_N_ITEMS,
|
||||
}rlc_mode_t;
|
||||
static const char rlc_mode_text[RLC_MODE_N_ITEMS][20] = {"Transparent Mode",
|
||||
"Unacknowledged Mode",
|
||||
"Acknowledged Mode"};
|
||||
|
||||
typedef enum{
|
||||
RLC_FI_FIELD_START_AND_END_ALIGNED = 0,
|
||||
RLC_FI_FIELD_NOT_END_ALIGNED,
|
||||
RLC_FI_FIELD_NOT_START_ALIGNED,
|
||||
RLC_FI_FIELD_NOT_START_OR_END_ALIGNED,
|
||||
RLC_FI_FIELD_N_ITEMS,
|
||||
}rlc_fi_field_t;
|
||||
static const char rlc_fi_field_text[RLC_FI_FIELD_N_ITEMS][32] = {"Start and end aligned",
|
||||
"Not end aligned",
|
||||
"Not start aligned",
|
||||
"Not start or end aligned"};
|
||||
|
||||
typedef enum{
|
||||
RLC_DC_FIELD_CONTROL_PDU = 0,
|
||||
RLC_DC_FIELD_DATA_PDU,
|
||||
RLC_DC_FIELD_N_ITEMS,
|
||||
}rlc_dc_field_t;
|
||||
static const char rlc_dc_field_text[RLC_DC_FIELD_N_ITEMS][20] = {"Control PDU",
|
||||
"Data PDU"};
|
||||
|
||||
typedef enum{
|
||||
RLC_UMD_SN_SIZE_5_BITS = 0,
|
||||
RLC_UMD_SN_SIZE_10_BITS,
|
||||
RLC_UMD_SN_SIZE_N_ITEMS,
|
||||
}rlc_umd_sn_size_t;
|
||||
static const char rlc_umd_sn_size_text[RLC_UMD_SN_SIZE_N_ITEMS][20] = {"5 bits", "10 bits"};
|
||||
static const uint16_t rlc_umd_sn_size_num[RLC_UMD_SN_SIZE_N_ITEMS] = {5, 10};
|
||||
|
||||
// UMD PDU Header
|
||||
typedef struct{
|
||||
uint8_t fi; // Framing info
|
||||
rlc_umd_sn_size_t sn_size; // Sequence number size (5 or 10 bits)
|
||||
uint16_t sn; // Sequence number
|
||||
uint32_t N_li; // Number of length indicators
|
||||
uint16_t li[RLC_AM_WINDOW_SIZE]; // Array of length indicators
|
||||
}rlc_umd_pdu_header_t;
|
||||
|
||||
// AMD PDU Header
|
||||
struct rlc_amd_pdu_header_t{
|
||||
rlc_dc_field_t dc; // Data or control
|
||||
uint8_t rf; // Resegmentation flag
|
||||
uint8_t p; // Polling bit
|
||||
uint8_t fi; // Framing info
|
||||
uint16_t sn; // Sequence number
|
||||
uint8_t lsf; // Last segment flag
|
||||
uint16_t so; // Segment offset
|
||||
uint32_t N_li; // Number of length indicators
|
||||
uint16_t li[RLC_AM_WINDOW_SIZE]; // Array of length indicators
|
||||
|
||||
rlc_amd_pdu_header_t(){
|
||||
dc = RLC_DC_FIELD_CONTROL_PDU;
|
||||
rf = 0;
|
||||
p = 0;
|
||||
fi = 0;
|
||||
sn = 0;
|
||||
lsf = 0;
|
||||
so = 0;
|
||||
N_li=0;
|
||||
for(int i=0;i<RLC_AM_WINDOW_SIZE;i++)
|
||||
li[i] = 0;
|
||||
}
|
||||
rlc_amd_pdu_header_t(const rlc_amd_pdu_header_t& h)
|
||||
{
|
||||
copy(h);
|
||||
}
|
||||
rlc_amd_pdu_header_t& operator= (const rlc_amd_pdu_header_t& h)
|
||||
{
|
||||
copy(h);
|
||||
return *this;
|
||||
}
|
||||
void copy(const rlc_amd_pdu_header_t& h)
|
||||
{
|
||||
dc = h.dc;
|
||||
rf = h.rf;
|
||||
p = h.p;
|
||||
fi = h.fi;
|
||||
sn = h.sn;
|
||||
lsf = h.lsf;
|
||||
so = h.so;
|
||||
N_li = h.N_li;
|
||||
for(int i=0;i<h.N_li;i++)
|
||||
li[i] = h.li[i];
|
||||
}
|
||||
};
|
||||
|
||||
// NACK helper
|
||||
struct rlc_status_nack_t{
|
||||
uint16_t nack_sn;
|
||||
bool has_so;
|
||||
uint16_t so_start;
|
||||
uint16_t so_end;
|
||||
|
||||
rlc_status_nack_t(){has_so=false; nack_sn=0; so_start=0; so_end=0;}
|
||||
};
|
||||
|
||||
// STATUS PDU
|
||||
struct rlc_status_pdu_t{
|
||||
uint16_t ack_sn;
|
||||
uint32_t N_nack;
|
||||
rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE];
|
||||
|
||||
rlc_status_pdu_t(){N_nack=0; ack_sn=0;}
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* RLC Common interface
|
||||
* Common interface for all RLC entities
|
||||
***************************************************************************/
|
||||
class rlc_common
|
||||
{
|
||||
public:
|
||||
virtual void init(srslte::log *rlc_entity_log_,
|
||||
uint32_t lcid_,
|
||||
pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
srslte::mac_interface_timers *mac_timers_) = 0;
|
||||
virtual void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void empty_queue() = 0;
|
||||
|
||||
virtual rlc_mode_t get_mode() = 0;
|
||||
virtual uint32_t get_bearer() = 0;
|
||||
|
||||
// PDCP interface
|
||||
virtual void write_sdu(srslte::byte_buffer_t *sdu) = 0;
|
||||
|
||||
// MAC interface
|
||||
virtual uint32_t get_buffer_state() = 0;
|
||||
virtual uint32_t get_total_buffer_state() = 0;
|
||||
virtual int read_pdu(uint8_t *payload, uint32_t nof_bytes) = 0;
|
||||
virtual void write_pdu(uint8_t *payload, uint32_t nof_bytes) = 0;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
#endif // RLC_COMMON_H
|
@ -0,0 +1,85 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RLC_ENTITY_H
|
||||
#define RLC_ENTITY_H
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "upper/rlc_common.h"
|
||||
#include "upper/rlc_tm.h"
|
||||
#include "upper/rlc_um.h"
|
||||
#include "upper/rlc_am.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* RLC Entity
|
||||
* Common container for all RLC entities
|
||||
***************************************************************************/
|
||||
class rlc_entity
|
||||
{
|
||||
public:
|
||||
rlc_entity();
|
||||
void init(rlc_mode_t mode,
|
||||
srslte::log *rlc_entity_log_,
|
||||
uint32_t lcid_,
|
||||
pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
srslte::mac_interface_timers *mac_timers_);
|
||||
|
||||
void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg);
|
||||
void reset();
|
||||
bool active();
|
||||
|
||||
rlc_mode_t get_mode();
|
||||
uint32_t get_bearer();
|
||||
|
||||
// PDCP interface
|
||||
void write_sdu(byte_buffer_t *sdu);
|
||||
|
||||
// MAC interface
|
||||
uint32_t get_buffer_state();
|
||||
uint32_t get_total_buffer_state();
|
||||
int read_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
|
||||
|
||||
private:
|
||||
rlc_tm tm;
|
||||
rlc_um um;
|
||||
rlc_am am;
|
||||
|
||||
rlc_common *rlc;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // RLC_ENTITY_H
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UE_RLC_METRICS_H
|
||||
#define UE_RLC_METRICS_H
|
||||
|
||||
|
||||
namespace srsue {
|
||||
|
||||
struct rlc_metrics_t
|
||||
{
|
||||
float dl_tput_mbps;
|
||||
float ul_tput_mbps;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
#endif // UE_RLC_METRICS_H
|
@ -0,0 +1,80 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RLC_TM_H
|
||||
#define RLC_TM_H
|
||||
|
||||
#include "common/buffer_pool.h"
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/msg_queue.h"
|
||||
#include "upper/rlc_common.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
class rlc_tm
|
||||
:public rlc_common
|
||||
{
|
||||
public:
|
||||
rlc_tm();
|
||||
void init(srslte::log *rlc_entity_log_,
|
||||
uint32_t lcid_,
|
||||
pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
srslte::mac_interface_timers *mac_timers);
|
||||
void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg);
|
||||
void reset();
|
||||
void empty_queue();
|
||||
|
||||
rlc_mode_t get_mode();
|
||||
uint32_t get_bearer();
|
||||
|
||||
// PDCP interface
|
||||
void write_sdu(srslte::byte_buffer_t *sdu);
|
||||
|
||||
// MAC interface
|
||||
uint32_t get_buffer_state();
|
||||
uint32_t get_total_buffer_state();
|
||||
int read_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
|
||||
private:
|
||||
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *log;
|
||||
uint32_t lcid;
|
||||
pdcp_interface_rlc *pdcp;
|
||||
rrc_interface_rlc *rrc;
|
||||
|
||||
// Thread-safe queues for MAC messages
|
||||
srslte::msg_queue ul_queue;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // RLC_TM_H
|
@ -0,0 +1,158 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RLC_UM_H
|
||||
#define RLC_UM_H
|
||||
|
||||
#include "common/buffer_pool.h"
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/msg_queue.h"
|
||||
#include "upper/rlc_common.h"
|
||||
#include <pthread.h>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
namespace srsue {
|
||||
|
||||
struct rlc_umd_pdu_t{
|
||||
rlc_umd_pdu_header_t header;
|
||||
srslte::byte_buffer_t *buf;
|
||||
};
|
||||
|
||||
class rlc_um
|
||||
:public srslte::timer_callback
|
||||
,public rlc_common
|
||||
{
|
||||
public:
|
||||
rlc_um();
|
||||
|
||||
void init(srslte::log *rlc_entity_log_,
|
||||
uint32_t lcid_,
|
||||
pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
srslte::mac_interface_timers *mac_timers_);
|
||||
void configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg);
|
||||
void reset();
|
||||
void empty_queue();
|
||||
|
||||
rlc_mode_t get_mode();
|
||||
uint32_t get_bearer();
|
||||
|
||||
// PDCP interface
|
||||
void write_sdu(srslte::byte_buffer_t *sdu);
|
||||
|
||||
// MAC interface
|
||||
uint32_t get_buffer_state();
|
||||
uint32_t get_total_buffer_state();
|
||||
int read_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
|
||||
// Timeout callback interface
|
||||
void timer_expired(uint32_t timeout_id);
|
||||
|
||||
bool reordering_timeout_running();
|
||||
|
||||
private:
|
||||
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *log;
|
||||
uint32_t lcid;
|
||||
pdcp_interface_rlc *pdcp;
|
||||
rrc_interface_rlc *rrc;
|
||||
srslte::mac_interface_timers *mac_timers;
|
||||
|
||||
// TX SDU buffers
|
||||
srslte::msg_queue tx_sdu_queue;
|
||||
srslte::byte_buffer_t *tx_sdu;
|
||||
|
||||
// Rx window
|
||||
std::map<uint32_t, rlc_umd_pdu_t> rx_window;
|
||||
uint32_t rx_window_size;
|
||||
uint32_t rx_mod; // Rx counter modulus
|
||||
uint32_t tx_mod; // Tx counter modulus
|
||||
|
||||
// RX SDU buffers
|
||||
srslte::byte_buffer_t *rx_sdu;
|
||||
uint32_t vr_ur_in_rx_sdu;
|
||||
|
||||
// Mutexes
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
/****************************************************************************
|
||||
* Configurable parameters
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
|
||||
int32_t t_reordering; // Timer used by rx to detect PDU loss (ms)
|
||||
rlc_umd_sn_size_t tx_sn_field_length; // Number of bits used for tx (UL) sequence number
|
||||
rlc_umd_sn_size_t rx_sn_field_length; // Number of bits used for rx (DL) sequence number
|
||||
|
||||
/****************************************************************************
|
||||
* State variables and counters
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
|
||||
// Tx state variables
|
||||
uint32_t vt_us; // Send state. SN to be assigned for next PDU.
|
||||
|
||||
// Rx state variables
|
||||
uint32_t vr_ur; // Receive state. SN of earliest PDU still considered for reordering.
|
||||
uint32_t vr_ux; // t_reordering state. SN following PDU which triggered t_reordering.
|
||||
uint32_t vr_uh; // Highest rx state. SN following PDU with highest SN among rxed PDUs.
|
||||
|
||||
/****************************************************************************
|
||||
* Timers
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
uint32_t reordering_timeout_id;
|
||||
|
||||
bool pdu_lost;
|
||||
|
||||
int build_data_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
void reassemble_rx_sdus();
|
||||
bool inside_reordering_window(uint16_t sn);
|
||||
void debug_state();
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Header pack/unpack helper functions
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
|
||||
***************************************************************************/
|
||||
void rlc_um_read_data_pdu_header(srslte::byte_buffer_t *pdu, rlc_umd_sn_size_t sn_size, rlc_umd_pdu_header_t *header);
|
||||
void rlc_um_read_data_pdu_header(uint8_t *payload, uint32_t nof_bytes, rlc_umd_sn_size_t sn_size, rlc_umd_pdu_header_t *header);
|
||||
void rlc_um_write_data_pdu_header(rlc_umd_pdu_header_t *header, srslte::byte_buffer_t *pdu);
|
||||
|
||||
uint32_t rlc_um_packed_length(rlc_umd_pdu_header_t *header);
|
||||
bool rlc_um_start_aligned(uint8_t fi);
|
||||
bool rlc_um_end_aligned(uint8_t fi);
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // RLC_UM_H
|
@ -0,0 +1,211 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RRC_H
|
||||
#define RRC_H
|
||||
|
||||
#include "pthread.h"
|
||||
|
||||
#include "common/buffer_pool.h"
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/security.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using srslte::byte_buffer_t;
|
||||
|
||||
namespace srsue {
|
||||
|
||||
// RRC states (3GPP 36.331 v10.0.0)
|
||||
typedef enum{
|
||||
RRC_STATE_IDLE = 0,
|
||||
RRC_STATE_SIB1_SEARCH,
|
||||
RRC_STATE_SIB2_SEARCH,
|
||||
RRC_STATE_WAIT_FOR_CON_SETUP,
|
||||
RRC_STATE_COMPLETING_SETUP,
|
||||
RRC_STATE_RRC_CONNECTED,
|
||||
RRC_STATE_N_ITEMS,
|
||||
}rrc_state_t;
|
||||
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
|
||||
"SIB1_SEARCH",
|
||||
"SIB2_SEARCH",
|
||||
"WAIT FOR CON SETUP",
|
||||
"COMPLETING SETUP",
|
||||
"RRC CONNECTED"};
|
||||
|
||||
|
||||
class rrc
|
||||
:public rrc_interface_nas
|
||||
,public rrc_interface_phy
|
||||
,public rrc_interface_mac
|
||||
,public rrc_interface_gw
|
||||
,public rrc_interface_pdcp
|
||||
,public rrc_interface_rlc
|
||||
,public srslte::timer_callback
|
||||
{
|
||||
public:
|
||||
rrc();
|
||||
void init(phy_interface_rrc *phy_,
|
||||
mac_interface_rrc *mac_,
|
||||
rlc_interface_rrc *rlc_,
|
||||
pdcp_interface_rrc *pdcp_,
|
||||
nas_interface_rrc *nas_,
|
||||
usim_interface_rrc *usim_,
|
||||
srslte::mac_interface_timers *mac_timers_,
|
||||
srslte::log *rrc_log_);
|
||||
void stop();
|
||||
|
||||
rrc_state_t get_state();
|
||||
void set_ue_category(int category);
|
||||
|
||||
// Timeout callback interface
|
||||
void timer_expired(uint32_t timeout_id);
|
||||
|
||||
void test_con_restablishment();
|
||||
void liblte_rrc_log(char* str);
|
||||
|
||||
private:
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *rrc_log;
|
||||
phy_interface_rrc *phy;
|
||||
mac_interface_rrc *mac;
|
||||
rlc_interface_rrc *rlc;
|
||||
pdcp_interface_rrc *pdcp;
|
||||
nas_interface_rrc *nas;
|
||||
usim_interface_rrc *usim;
|
||||
|
||||
srslte::bit_buffer_t bit_buf;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
rrc_state_t state;
|
||||
uint8_t transaction_id;
|
||||
bool drb_up;
|
||||
|
||||
uint8_t k_rrc_enc[32];
|
||||
uint8_t k_rrc_int[32];
|
||||
uint8_t k_up_enc[32];
|
||||
uint8_t k_up_int[32]; // Not used: only for relay nodes (3GPP 33.401 Annex A.7)
|
||||
|
||||
CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
||||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
||||
|
||||
LIBLTE_RRC_MIB_STRUCT mib;
|
||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
|
||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
|
||||
|
||||
std::map<uint32_t, LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT> srbs;
|
||||
std::map<uint32_t, LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT> drbs;
|
||||
|
||||
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
|
||||
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
|
||||
|
||||
pthread_t sib_search_thread;
|
||||
|
||||
// RRC constants and timers
|
||||
srslte::mac_interface_timers *mac_timers;
|
||||
uint32_t n310_cnt, N310;
|
||||
uint32_t n311_cnt, N311;
|
||||
uint32_t t301, t310, t311;
|
||||
uint32_t safe_reset_timer;
|
||||
int ue_category;
|
||||
|
||||
|
||||
// NAS interface
|
||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
|
||||
uint16_t get_mcc();
|
||||
uint16_t get_mnc();
|
||||
void enable_capabilities();
|
||||
|
||||
// PHY interface
|
||||
void in_sync();
|
||||
void out_of_sync();
|
||||
|
||||
// MAC interface
|
||||
void release_pucch_srs();
|
||||
void ra_problem();
|
||||
|
||||
// GW interface
|
||||
bool rrc_connected();
|
||||
void rrc_connect();
|
||||
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);
|
||||
|
||||
// RLC interface
|
||||
void max_retx_attempted();
|
||||
|
||||
// Senders
|
||||
void send_con_request();
|
||||
void send_con_restablish_request();
|
||||
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);
|
||||
|
||||
// Parsers
|
||||
void parse_dl_ccch(byte_buffer_t *pdu);
|
||||
void parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu);
|
||||
|
||||
// Helpers
|
||||
void reset_ue();
|
||||
void rrc_connection_release();
|
||||
void radio_link_failure();
|
||||
static void* start_sib_thread(void *rrc_);
|
||||
void sib_search();
|
||||
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x);
|
||||
void apply_sib2_configs();
|
||||
void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup);
|
||||
void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup);
|
||||
void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu);
|
||||
void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg);
|
||||
void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
|
||||
void release_drb(uint8_t lcid);
|
||||
void apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
|
||||
void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults);
|
||||
void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults);
|
||||
|
||||
// Helpers for setting default values
|
||||
void set_phy_default_pucch_srs();
|
||||
void set_phy_default();
|
||||
void set_mac_default();
|
||||
void set_rrc_default();
|
||||
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // RRC_H
|
@ -0,0 +1,127 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef USIM_H
|
||||
#define USIM_H
|
||||
|
||||
#include <string>
|
||||
#include "common/log.h"
|
||||
#include "common/common.h"
|
||||
#include "common/interfaces.h"
|
||||
#include "common/security.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
typedef enum{
|
||||
auth_algo_milenage = 0,
|
||||
auth_algo_xor,
|
||||
}auth_algo_t;
|
||||
|
||||
typedef struct{
|
||||
std::string algo;
|
||||
std::string op;
|
||||
std::string amf;
|
||||
std::string imsi;
|
||||
std::string imei;
|
||||
std::string k;
|
||||
}usim_args_t;
|
||||
|
||||
class usim
|
||||
:public usim_interface_nas
|
||||
,public usim_interface_rrc
|
||||
{
|
||||
public:
|
||||
usim();
|
||||
void init(usim_args_t *args, srslte::log *usim_log_);
|
||||
void stop();
|
||||
|
||||
// NAS interface
|
||||
void get_imsi_vec(uint8_t* imsi_, uint32_t n);
|
||||
void get_imei_vec(uint8_t* imei_, uint32_t n);
|
||||
|
||||
void generate_authentication_response(uint8_t *rand,
|
||||
uint8_t *autn_enb,
|
||||
uint16_t mcc,
|
||||
uint16_t mnc,
|
||||
bool *net_valid,
|
||||
uint8_t *res);
|
||||
|
||||
void generate_nas_keys(uint8_t *k_nas_enc,
|
||||
uint8_t *k_nas_int,
|
||||
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
||||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
|
||||
|
||||
// RRC interface
|
||||
void generate_as_keys(uint32_t count_ul,
|
||||
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);
|
||||
|
||||
|
||||
private:
|
||||
void gen_auth_res_milenage( uint8_t *rand,
|
||||
uint8_t *autn_enb,
|
||||
uint16_t mcc,
|
||||
uint16_t mnc,
|
||||
bool *net_valid,
|
||||
uint8_t *res);
|
||||
void gen_auth_res_xor( uint8_t *rand,
|
||||
uint8_t *autn_enb,
|
||||
uint16_t mcc,
|
||||
uint16_t mnc,
|
||||
bool *net_valid,
|
||||
uint8_t *res);
|
||||
void str_to_hex(std::string str, uint8_t *hex);
|
||||
|
||||
srslte::log *usim_log;
|
||||
|
||||
// User data
|
||||
auth_algo_t auth_algo;
|
||||
uint8_t amf[2]; // 3GPP 33.102 v10.0.0 Annex H
|
||||
uint8_t op[16];
|
||||
uint64_t imsi;
|
||||
uint64_t imei;
|
||||
uint8_t k[16];
|
||||
|
||||
// Security variables
|
||||
uint8_t rand[16];
|
||||
uint8_t ck[16];
|
||||
uint8_t ik[16];
|
||||
uint8_t ak[6];
|
||||
uint8_t mac[8];
|
||||
uint8_t autn[16];
|
||||
uint8_t k_asme[32];
|
||||
uint8_t k_enb[32];
|
||||
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
||||
#endif // USIM_H
|
@ -0,0 +1,24 @@
|
||||
# Copyright 2015 Software Radio Systems Limited
|
||||
#
|
||||
# This file is part of srsUE
|
||||
#
|
||||
# srsUE is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# srsUE is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# A copy of the GNU Affero General Public License can be found in
|
||||
# the LICENSE file in the top-level directory of this distribution
|
||||
# and at http://www.gnu.org/licenses/.
|
||||
#
|
||||
|
||||
file(GLOB SOURCES "*.cc")
|
||||
add_library(srslte_upper SHARED ${SOURCES})
|
||||
target_link_libraries(srslte_upper srslte_common)
|
||||
INSTALL(TARGETS srslte_upper DESTINATION ${LIBRARY_DIR})
|
||||
SRSLTE_SET_PIC(srslte_upper)
|
@ -0,0 +1,290 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "upper/gw.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
namespace srsue{
|
||||
|
||||
gw::gw()
|
||||
:if_up(false)
|
||||
{}
|
||||
|
||||
void gw::init(pdcp_interface_gw *pdcp_, rrc_interface_gw *rrc_, ue_interface *ue_, srslte::log *gw_log_)
|
||||
{
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
pdcp = pdcp_;
|
||||
rrc = rrc_;
|
||||
ue = ue_;
|
||||
gw_log = gw_log_;
|
||||
run_enable = true;
|
||||
|
||||
gettimeofday(&metrics_time[1], NULL);
|
||||
dl_tput_bytes = 0;
|
||||
ul_tput_bytes = 0;
|
||||
}
|
||||
|
||||
void gw::stop()
|
||||
{
|
||||
if(run_enable)
|
||||
{
|
||||
run_enable = false;
|
||||
if(if_up)
|
||||
{
|
||||
close(tun_fd);
|
||||
|
||||
// Wait thread to exit gracefully otherwise might leave a mutex locked
|
||||
int cnt=0;
|
||||
while(running && cnt<100) {
|
||||
usleep(10000);
|
||||
cnt++;
|
||||
}
|
||||
if (running) {
|
||||
thread_cancel();
|
||||
}
|
||||
wait_thread_finish();
|
||||
}
|
||||
|
||||
// TODO: tear down TUN device?
|
||||
}
|
||||
}
|
||||
|
||||
void gw::get_metrics(gw_metrics_t &m)
|
||||
{
|
||||
|
||||
gettimeofday(&metrics_time[2], NULL);
|
||||
get_time_interval(metrics_time);
|
||||
double secs = (double) metrics_time[0].tv_sec+metrics_time[0].tv_usec*1e-6;
|
||||
|
||||
m.dl_tput_mbps = (dl_tput_bytes*8/(double)1e6)/secs;
|
||||
m.ul_tput_mbps = (ul_tput_bytes*8/(double)1e6)/secs;
|
||||
gw_log->info("RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n",
|
||||
m.dl_tput_mbps, m.ul_tput_mbps);
|
||||
|
||||
memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval));
|
||||
dl_tput_bytes = 0;
|
||||
ul_tput_bytes = 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
PDCP interface
|
||||
*******************************************************************************/
|
||||
void gw::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu)
|
||||
{
|
||||
gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX PDU");
|
||||
gw_log->info("RX PDU. Stack latency: %ld us\n", pdu->get_latency_us());
|
||||
dl_tput_bytes += pdu->N_bytes;
|
||||
if(!if_up)
|
||||
{
|
||||
gw_log->warning("TUN/TAP not up - dropping gw RX message\n");
|
||||
}else{
|
||||
int n = write(tun_fd, pdu->msg, pdu->N_bytes);
|
||||
if(pdu->N_bytes != n)
|
||||
{
|
||||
gw_log->warning("DL TUN/TAP write failure\n");
|
||||
}
|
||||
}
|
||||
pool->deallocate(pdu);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
NAS interface
|
||||
*******************************************************************************/
|
||||
srslte::error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str)
|
||||
{
|
||||
if(!if_up)
|
||||
{
|
||||
if(init_if(err_str))
|
||||
{
|
||||
gw_log->error("init_if failed\n");
|
||||
return(ERROR_CANT_START);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the IP address
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip_addr);
|
||||
if(0 > ioctl(sock, SIOCSIFADDR, &ifr))
|
||||
{
|
||||
err_str = strerror(errno);
|
||||
gw_log->debug("Failed to set socket address: %s\n", err_str);
|
||||
close(tun_fd);
|
||||
return(ERROR_CANT_START);
|
||||
}
|
||||
ifr.ifr_netmask.sa_family = AF_INET;
|
||||
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
|
||||
if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr))
|
||||
{
|
||||
err_str = strerror(errno);
|
||||
gw_log->debug("Failed to set socket netmask: %s\n", err_str);
|
||||
close(tun_fd);
|
||||
return(ERROR_CANT_START);
|
||||
}
|
||||
|
||||
// Setup a thread to receive packets from the TUN device
|
||||
start(GW_THREAD_PRIO);
|
||||
|
||||
return(ERROR_NONE);
|
||||
}
|
||||
|
||||
srslte::error_t gw::init_if(char *err_str)
|
||||
{
|
||||
if(if_up)
|
||||
{
|
||||
return(ERROR_ALREADY_STARTED);
|
||||
}
|
||||
|
||||
char dev[IFNAMSIZ] = "tun_srsue";
|
||||
|
||||
// Construct the TUN device
|
||||
tun_fd = open("/dev/net/tun", O_RDWR);
|
||||
gw_log->info("TUN file descriptor = %d\n", tun_fd);
|
||||
if(0 > tun_fd)
|
||||
{
|
||||
err_str = strerror(errno);
|
||||
gw_log->debug("Failed to open TUN device: %s\n", err_str);
|
||||
return(ERROR_CANT_START);
|
||||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ);
|
||||
if(0 > ioctl(tun_fd, TUNSETIFF, &ifr))
|
||||
{
|
||||
err_str = strerror(errno);
|
||||
gw_log->debug("Failed to set TUN device name: %s\n", err_str);
|
||||
close(tun_fd);
|
||||
return(ERROR_CANT_START);
|
||||
}
|
||||
|
||||
// Bring up the interface
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr))
|
||||
{
|
||||
err_str = strerror(errno);
|
||||
gw_log->debug("Failed to bring up socket: %s\n", err_str);
|
||||
close(tun_fd);
|
||||
return(ERROR_CANT_START);
|
||||
}
|
||||
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
|
||||
if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr))
|
||||
{
|
||||
err_str = strerror(errno);
|
||||
gw_log->debug("Failed to set socket flags: %s\n", err_str);
|
||||
close(tun_fd);
|
||||
return(ERROR_CANT_START);
|
||||
}
|
||||
|
||||
if_up = true;
|
||||
|
||||
return(ERROR_NONE);
|
||||
}
|
||||
|
||||
/********************/
|
||||
/* GW Receive */
|
||||
/********************/
|
||||
void gw::run_thread()
|
||||
{
|
||||
struct iphdr *ip_pkt;
|
||||
uint32 idx = 0;
|
||||
int32 N_bytes;
|
||||
byte_buffer_t *pdu = pool->allocate();
|
||||
|
||||
gw_log->info("GW IP packet receiver thread run_enable\n");
|
||||
|
||||
running = true;
|
||||
while(run_enable)
|
||||
{
|
||||
if (SRSUE_MAX_BUFFER_SIZE_BYTES-SRSUE_BUFFER_HEADER_OFFSET > idx) {
|
||||
N_bytes = read(tun_fd, &pdu->msg[idx], SRSUE_MAX_BUFFER_SIZE_BYTES-SRSUE_BUFFER_HEADER_OFFSET - idx);
|
||||
} else {
|
||||
gw_log->error("GW pdu buffer full - gw receive thread exiting.\n");
|
||||
gw_log->console("GW pdu buffer full - gw receive thread exiting.\n");
|
||||
break;
|
||||
}
|
||||
gw_log->debug("Read %d bytes from TUN fd=%d, idx=%d\n", N_bytes, tun_fd, idx);
|
||||
if(N_bytes > 0)
|
||||
{
|
||||
pdu->N_bytes = idx + N_bytes;
|
||||
ip_pkt = (struct iphdr*)pdu->msg;
|
||||
|
||||
// Warning: Accept only IPv4 packets
|
||||
if (ip_pkt->version == 4) {
|
||||
// Check if entire packet was received
|
||||
if(ntohs(ip_pkt->tot_len) == pdu->N_bytes)
|
||||
{
|
||||
gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU");
|
||||
|
||||
while(run_enable && (!rrc->rrc_connected() || !rrc->have_drb())) {
|
||||
rrc->rrc_connect();
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
if (!run_enable) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Send PDU directly to PDCP
|
||||
pdu->set_timestamp();
|
||||
ul_tput_bytes += pdu->N_bytes;
|
||||
pdcp->write_sdu(RB_ID_DRB1, pdu);
|
||||
|
||||
do {
|
||||
pdu = pool->allocate();
|
||||
if (!pdu) {
|
||||
printf("Not enough buffers in pool\n");
|
||||
usleep(100000);
|
||||
}
|
||||
} while(!pdu);
|
||||
idx = 0;
|
||||
}else{
|
||||
idx += N_bytes;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
gw_log->error("Failed to read from TUN interface - gw receive thread exiting.\n");
|
||||
gw_log->console("Failed to read from TUN interface - gw receive thread exiting.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
running = false;
|
||||
gw_log->info("GW IP receiver thread exiting.\n");
|
||||
}
|
||||
|
||||
} // namespace srsue
|
@ -0,0 +1,633 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "upper/nas.h"
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
namespace srsue{
|
||||
|
||||
nas::nas()
|
||||
:state(EMM_STATE_DEREGISTERED)
|
||||
,is_guti_set(false)
|
||||
,ip_addr(0)
|
||||
,eps_bearer_id(0)
|
||||
,count_ul(0)
|
||||
,count_dl(0)
|
||||
{}
|
||||
|
||||
void nas::init(usim_interface_nas *usim_,
|
||||
rrc_interface_nas *rrc_,
|
||||
gw_interface_nas *gw_,
|
||||
srslte::log *nas_log_)
|
||||
{
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
usim = usim_;
|
||||
rrc = rrc_;
|
||||
gw = gw_;
|
||||
nas_log = nas_log_;
|
||||
}
|
||||
|
||||
void nas::stop()
|
||||
{}
|
||||
|
||||
emm_state_t nas::get_state()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
RRC interface
|
||||
*******************************************************************************/
|
||||
|
||||
bool nas::is_attached()
|
||||
{
|
||||
return state == EMM_STATE_REGISTERED;
|
||||
}
|
||||
|
||||
void nas::notify_connection_setup()
|
||||
{
|
||||
nas_log->debug("State = %s\n", emm_state_text[state]);
|
||||
if(EMM_STATE_DEREGISTERED == state) {
|
||||
send_attach_request();
|
||||
} else {
|
||||
send_service_request();
|
||||
}
|
||||
}
|
||||
|
||||
void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
uint8 pd;
|
||||
uint8 msg_type;
|
||||
|
||||
nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rb_id_text[lcid]);
|
||||
|
||||
// Parse the message
|
||||
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &msg_type);
|
||||
switch(msg_type)
|
||||
{
|
||||
case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT:
|
||||
parse_attach_accept(lcid, pdu);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_ATTACH_REJECT:
|
||||
parse_attach_reject(lcid, pdu);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST:
|
||||
parse_authentication_request(lcid, pdu);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT:
|
||||
parse_authentication_reject(lcid, pdu);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST:
|
||||
parse_identity_request(lcid, pdu);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND:
|
||||
parse_security_mode_command(lcid, pdu);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_SERVICE_REJECT:
|
||||
parse_service_reject(lcid, pdu);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST:
|
||||
parse_esm_information_request(lcid, pdu);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_EMM_INFORMATION:
|
||||
parse_emm_information(lcid, pdu);
|
||||
break;
|
||||
default:
|
||||
nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n",msg_type);
|
||||
pool->deallocate(pdu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t nas::get_ul_count()
|
||||
{
|
||||
return count_ul;
|
||||
}
|
||||
|
||||
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi)
|
||||
{
|
||||
if(is_guti_set) {
|
||||
s_tmsi->mmec = guti.mme_code;
|
||||
s_tmsi->m_tmsi = guti.m_tmsi;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Security
|
||||
*******************************************************************************/
|
||||
|
||||
void nas::integrity_generate(uint8_t *key_128,
|
||||
uint32_t count,
|
||||
uint8_t rb_id,
|
||||
uint8_t direction,
|
||||
uint8_t *msg,
|
||||
uint32_t msg_len,
|
||||
uint8_t *mac)
|
||||
{
|
||||
switch(integ_algo)
|
||||
{
|
||||
case INTEGRITY_ALGORITHM_ID_EIA0:
|
||||
break;
|
||||
case INTEGRITY_ALGORITHM_ID_128_EIA1:
|
||||
security_128_eia1(key_128,
|
||||
count,
|
||||
rb_id,
|
||||
direction,
|
||||
msg,
|
||||
msg_len,
|
||||
mac);
|
||||
break;
|
||||
case INTEGRITY_ALGORITHM_ID_128_EIA2:
|
||||
security_128_eia2(key_128,
|
||||
count,
|
||||
rb_id,
|
||||
direction,
|
||||
msg,
|
||||
msg_len,
|
||||
mac);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void nas::integrity_check()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void nas::cipher_encrypt()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void nas::cipher_decrypt()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
Parsers
|
||||
*******************************************************************************/
|
||||
|
||||
void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept;
|
||||
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req;
|
||||
LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete;
|
||||
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept;
|
||||
|
||||
nas_log->info("Received Attach Accept\n");
|
||||
count_dl++;
|
||||
|
||||
liblte_mme_unpack_attach_accept_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &attach_accept);
|
||||
|
||||
if(attach_accept.eps_attach_result == LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY)
|
||||
{
|
||||
//FIXME: Handle t3412.unit
|
||||
//FIXME: Handle tai_list
|
||||
if(attach_accept.guti_present)
|
||||
{
|
||||
memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
|
||||
is_guti_set = true;
|
||||
// TODO: log message to console
|
||||
}
|
||||
if(attach_accept.lai_present)
|
||||
{
|
||||
}
|
||||
if(attach_accept.ms_id_present)
|
||||
{}
|
||||
if(attach_accept.emm_cause_present)
|
||||
{}
|
||||
if(attach_accept.t3402_present)
|
||||
{}
|
||||
if(attach_accept.t3423_present)
|
||||
{}
|
||||
if(attach_accept.equivalent_plmns_present)
|
||||
{}
|
||||
if(attach_accept.emerg_num_list_present)
|
||||
{}
|
||||
if(attach_accept.eps_network_feature_support_present)
|
||||
{}
|
||||
if(attach_accept.additional_update_result_present)
|
||||
{}
|
||||
if(attach_accept.t3412_ext_present)
|
||||
{}
|
||||
|
||||
liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req);
|
||||
|
||||
if(LIBLTE_MME_PDN_TYPE_IPV4 == act_def_eps_bearer_context_req.pdn_addr.pdn_type)
|
||||
{
|
||||
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[0] << 24;
|
||||
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[1] << 16;
|
||||
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[2] << 8;
|
||||
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[3];
|
||||
|
||||
nas_log->info("IP allocated by network %u.%u.%u.%u\n",
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[0],
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[1],
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[2],
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[3]);
|
||||
|
||||
nas_log->console("Network attach successful. IP: %u.%u.%u.%u\n",
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[0],
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[1],
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[2],
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[3]);
|
||||
|
||||
// Setup GW
|
||||
char *err_str = NULL;
|
||||
if(gw->setup_if_addr(ip_addr, err_str))
|
||||
{
|
||||
nas_log->error("Failed to set gateway address - %s\n", err_str);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nas_log->error("Not handling IPV6 or IPV4V6\n");
|
||||
pool->deallocate(pdu);
|
||||
return;
|
||||
}
|
||||
eps_bearer_id = act_def_eps_bearer_context_req.eps_bearer_id;
|
||||
if(act_def_eps_bearer_context_req.transaction_id_present)
|
||||
{
|
||||
transaction_id = act_def_eps_bearer_context_req.proc_transaction_id;
|
||||
}
|
||||
|
||||
//FIXME: Handle the following parameters
|
||||
// act_def_eps_bearer_context_req.eps_qos.qci
|
||||
// act_def_eps_bearer_context_req.eps_qos.br_present
|
||||
// act_def_eps_bearer_context_req.eps_qos.br_ext_present
|
||||
// act_def_eps_bearer_context_req.apn.apn
|
||||
// act_def_eps_bearer_context_req.negotiated_qos_present
|
||||
// act_def_eps_bearer_context_req.llc_sapi_present
|
||||
// act_def_eps_bearer_context_req.radio_prio_present
|
||||
// act_def_eps_bearer_context_req.packet_flow_id_present
|
||||
// act_def_eps_bearer_context_req.apn_ambr_present
|
||||
// act_def_eps_bearer_context_req.protocol_cnfg_opts_present
|
||||
// act_def_eps_bearer_context_req.connectivity_type_present
|
||||
|
||||
// FIXME: Setup the default EPS bearer context
|
||||
|
||||
state = EMM_STATE_REGISTERED;
|
||||
|
||||
// Send EPS bearer context accept and attach complete
|
||||
count_ul++;
|
||||
act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id;
|
||||
act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id;
|
||||
act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false;
|
||||
liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept, &attach_complete.esm_msg);
|
||||
liblte_mme_pack_attach_complete_msg(&attach_complete,
|
||||
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
|
||||
count_ul,
|
||||
(LIBLTE_BYTE_MSG_STRUCT*)pdu);
|
||||
integrity_generate(&k_nas_int[16],
|
||||
count_ul,
|
||||
lcid-1,
|
||||
SECURITY_DIRECTION_UPLINK,
|
||||
&pdu->msg[5],
|
||||
pdu->N_bytes-5,
|
||||
&pdu->msg[1]);
|
||||
|
||||
// Instruct RRC to enable capabilities
|
||||
rrc->enable_capabilities();
|
||||
|
||||
nas_log->info("Sending Attach Complete\n");
|
||||
rrc->write_sdu(lcid, pdu);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result);
|
||||
state = EMM_STATE_DEREGISTERED;
|
||||
pool->deallocate(pdu);
|
||||
}
|
||||
}
|
||||
|
||||
void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT attach_rej;
|
||||
|
||||
liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &attach_rej);
|
||||
nas_log->warning("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause);
|
||||
nas_log->console("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause);
|
||||
state = EMM_STATE_DEREGISTERED;
|
||||
pool->deallocate(pdu);
|
||||
// FIXME: Command RRC to release?
|
||||
}
|
||||
|
||||
void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
|
||||
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
|
||||
|
||||
nas_log->info("Received Authentication Request\n");;
|
||||
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &auth_req);
|
||||
|
||||
// Reuse the pdu for the response message
|
||||
pdu->reset();
|
||||
|
||||
// Generate authentication response using RAND, AUTN & KSI-ASME
|
||||
uint16 mcc, mnc;
|
||||
mcc = rrc->get_mcc();
|
||||
mnc = rrc->get_mnc();
|
||||
|
||||
nas_log->info("MCC=%d, MNC=%d\n", mcc, mnc);
|
||||
|
||||
bool net_valid;
|
||||
uint8_t res[16];
|
||||
usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, &net_valid, res);
|
||||
|
||||
if(net_valid)
|
||||
{
|
||||
nas_log->info("Network authentication successful\n");
|
||||
for(int i=0; i<8; i++)
|
||||
{
|
||||
auth_res.res[i] = res[i];
|
||||
}
|
||||
liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT*)pdu);
|
||||
|
||||
nas_log->info("Sending Authentication Response\n");
|
||||
rrc->write_sdu(lcid, pdu);
|
||||
}
|
||||
else
|
||||
{
|
||||
nas_log->warning("Network authentication failure\n");
|
||||
nas_log->console("Warning: Network authentication failure\n");
|
||||
pool->deallocate(pdu);
|
||||
}
|
||||
}
|
||||
|
||||
void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
nas_log->warning("Received Authentication Reject\n");
|
||||
pool->deallocate(pdu);
|
||||
state = EMM_STATE_DEREGISTERED;
|
||||
// FIXME: Command RRC to release?
|
||||
}
|
||||
|
||||
void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
nas_log->error("TODO:parse_identity_request\n");
|
||||
}
|
||||
|
||||
void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
bool success;
|
||||
LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd;
|
||||
LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp;
|
||||
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
|
||||
|
||||
nas_log->info("Received Security Mode Command\n");
|
||||
liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &sec_mode_cmd);
|
||||
|
||||
ksi = sec_mode_cmd.nas_ksi.nas_ksi;
|
||||
cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM)sec_mode_cmd.selected_nas_sec_algs.type_of_eea;
|
||||
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM)sec_mode_cmd.selected_nas_sec_algs.type_of_eia;
|
||||
// FIXME: Handle nonce_ue, nonce_mme
|
||||
// FIXME: Currently only handling ciphering EEA0 (null) and integrity EIA1,EIA2
|
||||
// FIXME: Use selected_nas_sec_algs to choose correct algos
|
||||
|
||||
nas_log->debug("Security details: ksi=%d, eea=%s, eia=%s\n",
|
||||
ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]);
|
||||
|
||||
|
||||
if(CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo ||
|
||||
(INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo &&
|
||||
INTEGRITY_ALGORITHM_ID_128_EIA1 != integ_algo) ||
|
||||
sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE)
|
||||
{
|
||||
sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH;
|
||||
nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n");
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate NAS encryption key and integrity protection key
|
||||
usim->generate_nas_keys(k_nas_enc, k_nas_int, cipher_algo, integ_algo);
|
||||
nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc");
|
||||
nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int");
|
||||
|
||||
// Check incoming MAC
|
||||
uint8_t *inMAC = &pdu->msg[1];
|
||||
uint8_t genMAC[4];
|
||||
integrity_generate(&k_nas_int[16],
|
||||
count_dl,
|
||||
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:");
|
||||
|
||||
bool match=true;
|
||||
for(int i=0;i<4;i++) {
|
||||
if(inMAC[i] != genMAC[i]) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
if(!match) {
|
||||
sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED;
|
||||
nas_log->warning("Sending Security Mode Reject due to integrity check failure\n");
|
||||
success = false;
|
||||
} else {
|
||||
|
||||
if(sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req)
|
||||
{
|
||||
sec_mode_comp.imeisv_present = true;
|
||||
sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV;
|
||||
usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15);
|
||||
sec_mode_comp.imeisv.imeisv[14] = 5;
|
||||
sec_mode_comp.imeisv.imeisv[15] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
sec_mode_comp.imeisv_present = false;
|
||||
}
|
||||
|
||||
// Reuse pdu for response
|
||||
pdu->reset();
|
||||
liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp,
|
||||
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
|
||||
count_ul,
|
||||
(LIBLTE_BYTE_MSG_STRUCT*)pdu);
|
||||
integrity_generate(&k_nas_int[16],
|
||||
count_ul,
|
||||
lcid-1,
|
||||
SECURITY_DIRECTION_UPLINK,
|
||||
&pdu->msg[5],
|
||||
pdu->N_bytes-5,
|
||||
&pdu->msg[1]);
|
||||
nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n",
|
||||
count_ul,
|
||||
rb_id_text[lcid]);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!success) {
|
||||
// Reuse pdu for response
|
||||
pdu->reset();
|
||||
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT*)pdu);
|
||||
}
|
||||
|
||||
rrc->write_sdu(lcid, pdu);
|
||||
}
|
||||
|
||||
void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
nas_log->error("TODO:parse_service_reject\n");
|
||||
}
|
||||
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
nas_log->error("TODO:parse_esm_information_request\n");
|
||||
}
|
||||
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
nas_log->error("TODO:parse_emm_information\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Senders
|
||||
*******************************************************************************/
|
||||
|
||||
void nas::send_attach_request()
|
||||
{
|
||||
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
|
||||
byte_buffer_t *msg = pool->allocate();
|
||||
u_int32_t i;
|
||||
|
||||
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
|
||||
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
attach_req.ue_network_cap.eea[i] = false;
|
||||
attach_req.ue_network_cap.eia[i] = false;
|
||||
}
|
||||
attach_req.ue_network_cap.eea[0] = true; // EEA0 supported
|
||||
attach_req.ue_network_cap.eia[0] = true; // EIA0 supported
|
||||
attach_req.ue_network_cap.eia[1] = true; // EIA1 supported
|
||||
attach_req.ue_network_cap.eia[2] = true; // EIA2 supported
|
||||
|
||||
attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos
|
||||
attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos
|
||||
|
||||
attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G)
|
||||
|
||||
attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI;
|
||||
usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15);
|
||||
|
||||
// ESM message (PDN connectivity request) for first default bearer
|
||||
gen_pdn_connectivity_request(&attach_req.esm_msg);
|
||||
|
||||
attach_req.old_p_tmsi_signature_present = false;
|
||||
attach_req.additional_guti_present = false;
|
||||
attach_req.last_visited_registered_tai_present = false;
|
||||
attach_req.drx_param_present = false;
|
||||
attach_req.ms_network_cap_present = false;
|
||||
attach_req.old_lai_present = false;
|
||||
attach_req.tmsi_status_present = false;
|
||||
attach_req.ms_cm2_present = false;
|
||||
attach_req.ms_cm3_present = false;
|
||||
attach_req.supported_codecs_present = false;
|
||||
attach_req.additional_update_type_present = false;
|
||||
attach_req.voice_domain_pref_and_ue_usage_setting_present = false;
|
||||
attach_req.device_properties_present = false;
|
||||
attach_req.old_guti_type_present = false;
|
||||
|
||||
// Pack the message
|
||||
liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT*)msg);
|
||||
|
||||
nas_log->info("Sending attach request\n");
|
||||
rrc->write_sdu(RB_ID_SRB1, msg);
|
||||
}
|
||||
|
||||
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg)
|
||||
{
|
||||
LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req;
|
||||
|
||||
nas_log->info("Generating PDN Connectivity Request\n");
|
||||
|
||||
// Set the PDN con req parameters
|
||||
pdn_con_req.eps_bearer_id = 0x00; // Unassigned bearer ID
|
||||
pdn_con_req.proc_transaction_id = 0x01; // First transaction ID
|
||||
pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4;
|
||||
pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST;
|
||||
|
||||
// Set the optional flags
|
||||
pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed
|
||||
pdn_con_req.apn_present = false;
|
||||
pdn_con_req.protocol_cnfg_opts_present = false;
|
||||
pdn_con_req.device_properties_present = false;
|
||||
|
||||
// Pack the message
|
||||
liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg);
|
||||
}
|
||||
|
||||
void nas::send_identity_response(){}
|
||||
|
||||
void nas::send_service_request()
|
||||
{
|
||||
byte_buffer_t *msg = pool->allocate();
|
||||
count_ul++;
|
||||
|
||||
// Pack the service request message directly
|
||||
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
|
||||
msg->N_bytes++;
|
||||
msg->msg[1] = (ksi & 0x07) << 5;
|
||||
msg->msg[1] |= count_ul & 0x1F;
|
||||
msg->N_bytes++;
|
||||
|
||||
uint8_t mac[4];
|
||||
integrity_generate(&k_nas_int[16],
|
||||
count_ul,
|
||||
RB_ID_SRB1-1,
|
||||
SECURITY_DIRECTION_UPLINK,
|
||||
&msg->msg[0],
|
||||
2,
|
||||
&mac[0]);
|
||||
// Set the short MAC
|
||||
msg->msg[2] = mac[2];
|
||||
msg->N_bytes++;
|
||||
msg->msg[3] = mac[3];
|
||||
msg->N_bytes++;
|
||||
nas_log->info("Sending service request\n");
|
||||
rrc->write_sdu(RB_ID_SRB1, msg);
|
||||
}
|
||||
|
||||
void nas::send_esm_information_response(){}
|
||||
|
||||
} // namespace srsue
|
@ -0,0 +1,132 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "upper/pdcp.h"
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
namespace srsue{
|
||||
|
||||
pdcp::pdcp()
|
||||
{}
|
||||
|
||||
void pdcp::init(rlc_interface_pdcp *rlc_, rrc_interface_pdcp *rrc_, gw_interface_pdcp *gw_, srslte::log *pdcp_log_, uint8_t direction_)
|
||||
{
|
||||
rlc = rlc_;
|
||||
rrc = rrc_;
|
||||
gw = gw_;
|
||||
pdcp_log = pdcp_log_;
|
||||
direction = direction_;
|
||||
|
||||
pdcp_array[0].init(rlc, rrc, gw, pdcp_log, RB_ID_SRB0, direction); // SRB0
|
||||
}
|
||||
|
||||
void pdcp::stop()
|
||||
{}
|
||||
|
||||
void pdcp::reset()
|
||||
{
|
||||
for(uint32_t i=0;i<SRSUE_N_RADIO_BEARERS;i++) {
|
||||
pdcp_array[i].reset();
|
||||
}
|
||||
|
||||
pdcp_array[0].init(rlc, rrc, gw, pdcp_log, RB_ID_SRB0, direction); // SRB0
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
RRC/GW interface
|
||||
*******************************************************************************/
|
||||
void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
|
||||
{
|
||||
if(valid_lcid(lcid))
|
||||
pdcp_array[lcid].write_sdu(sdu);
|
||||
}
|
||||
|
||||
void pdcp::add_bearer(uint32_t lcid, LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg)
|
||||
{
|
||||
if(lcid < 0 || lcid >= SRSUE_N_RADIO_BEARERS) {
|
||||
pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSUE_N_RADIO_BEARERS, lcid);
|
||||
return;
|
||||
}
|
||||
if (!pdcp_array[lcid].is_active()) {
|
||||
pdcp_array[lcid].init(rlc, rrc, gw, pdcp_log, lcid, direction, cnfg);
|
||||
pdcp_log->info("Added bearer %s\n", rb_id_text[lcid]);
|
||||
} else {
|
||||
pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rb_id_text[lcid]);
|
||||
}
|
||||
}
|
||||
|
||||
void pdcp::config_security(uint32_t lcid,
|
||||
uint8_t *k_rrc_enc,
|
||||
uint8_t *k_rrc_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);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
RLC interface
|
||||
*******************************************************************************/
|
||||
void pdcp::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
|
||||
{
|
||||
if(valid_lcid(lcid))
|
||||
pdcp_array[lcid].write_pdu(pdu);
|
||||
}
|
||||
|
||||
void pdcp::write_pdu_bcch_bch(byte_buffer_t *sdu)
|
||||
{
|
||||
rrc->write_pdu_bcch_bch(sdu);
|
||||
}
|
||||
void pdcp::write_pdu_bcch_dlsch(byte_buffer_t *sdu)
|
||||
{
|
||||
rrc->write_pdu_bcch_dlsch(sdu);
|
||||
}
|
||||
|
||||
void pdcp::write_pdu_pcch(byte_buffer_t *sdu)
|
||||
{
|
||||
rrc->write_pdu_pcch(sdu);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Helpers
|
||||
*******************************************************************************/
|
||||
bool pdcp::valid_lcid(uint32_t lcid)
|
||||
{
|
||||
if(lcid < 0 || lcid >= SRSUE_N_RADIO_BEARERS) {
|
||||
pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSUE_N_RADIO_BEARERS, lcid);
|
||||
return false;
|
||||
}
|
||||
if(!pdcp_array[lcid].is_active()) {
|
||||
pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace srsue
|
@ -0,0 +1,286 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "upper/pdcp_entity.h"
|
||||
#include "common/security.h"
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
namespace srsue{
|
||||
|
||||
pdcp_entity::pdcp_entity()
|
||||
:active(false)
|
||||
,tx_count(0)
|
||||
,rx_count(0)
|
||||
,do_security(false)
|
||||
,sn_len(12)
|
||||
{
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
}
|
||||
|
||||
void pdcp_entity::init(rlc_interface_pdcp *rlc_,
|
||||
rrc_interface_pdcp *rrc_,
|
||||
gw_interface_pdcp *gw_,
|
||||
srslte::log *log_,
|
||||
uint32_t lcid_,
|
||||
u_int8_t direction_,
|
||||
LIBLTE_RRC_PDCP_CONFIG_STRUCT *cnfg)
|
||||
{
|
||||
rlc = rlc_;
|
||||
rrc = rrc_;
|
||||
gw = gw_;
|
||||
log = log_;
|
||||
lcid = lcid_;
|
||||
direction = direction_;
|
||||
active = true;
|
||||
|
||||
tx_count = 0;
|
||||
rx_count = 0;
|
||||
do_security = false;
|
||||
|
||||
if(cnfg)
|
||||
{
|
||||
if(cnfg->rlc_um_pdcp_sn_size_present) {
|
||||
if(LIBLTE_RRC_PDCP_SN_SIZE_7_BITS == cnfg->rlc_um_pdcp_sn_size) {
|
||||
sn_len = 7;
|
||||
}
|
||||
}
|
||||
// TODO: handle remainder of cnfg
|
||||
}
|
||||
log->debug("Init %s\n", rb_id_text[lcid]);
|
||||
}
|
||||
|
||||
void pdcp_entity::reset()
|
||||
{
|
||||
active = false;
|
||||
if(log)
|
||||
log->debug("Reset %s\n", rb_id_text[lcid]);
|
||||
}
|
||||
|
||||
bool pdcp_entity::is_active()
|
||||
{
|
||||
return 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", rb_id_text[lcid], (do_security)?"true":"false");
|
||||
|
||||
// Handle SRB messages
|
||||
switch(lcid)
|
||||
{
|
||||
case RB_ID_SRB0:
|
||||
rlc->write_sdu(lcid, sdu);
|
||||
break;
|
||||
case RB_ID_SRB1: // Intentional fall-through
|
||||
case RB_ID_SRB2:
|
||||
pdcp_pack_control_pdu(tx_count, sdu);
|
||||
if(do_security)
|
||||
{
|
||||
integrity_generate(&k_rrc_int[16],
|
||||
tx_count,
|
||||
lcid-1,
|
||||
direction,
|
||||
sdu->msg,
|
||||
sdu->N_bytes-4,
|
||||
&sdu->msg[sdu->N_bytes-4]);
|
||||
}
|
||||
tx_count++;
|
||||
rlc->write_sdu(lcid, sdu);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle DRB messages
|
||||
if(lcid >= RB_ID_DRB1)
|
||||
{
|
||||
if(12 == sn_len)
|
||||
{
|
||||
pdcp_pack_data_pdu_long_sn(tx_count++, sdu);
|
||||
} else {
|
||||
pdcp_pack_data_pdu_short_sn(tx_count++, sdu);
|
||||
}
|
||||
rlc->write_sdu(lcid, sdu);
|
||||
}
|
||||
}
|
||||
|
||||
void pdcp_entity::config_security(uint8_t *k_rrc_enc_,
|
||||
uint8_t *k_rrc_int_,
|
||||
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
|
||||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_)
|
||||
{
|
||||
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];
|
||||
}
|
||||
cipher_algo = cipher_algo_;
|
||||
integ_algo = integ_algo_;
|
||||
}
|
||||
|
||||
// RLC interface
|
||||
void pdcp_entity::write_pdu(byte_buffer_t *pdu)
|
||||
{
|
||||
// Handle SRB messages
|
||||
switch(lcid)
|
||||
{
|
||||
case RB_ID_SRB0:
|
||||
// Simply pass on to RRC
|
||||
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rb_id_text[lcid]);
|
||||
rrc->write_pdu(RB_ID_SRB0, pdu);
|
||||
break;
|
||||
case RB_ID_SRB1: // Intentional fall-through
|
||||
case RB_ID_SRB2:
|
||||
uint32_t sn;
|
||||
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rb_id_text[lcid]);
|
||||
pdcp_unpack_control_pdu(pdu, &sn);
|
||||
log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d",
|
||||
rb_id_text[lcid], sn);
|
||||
rrc->write_pdu(lcid, pdu);
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle DRB messages
|
||||
if(lcid >= RB_ID_DRB1)
|
||||
{
|
||||
uint32_t sn;
|
||||
if(12 == 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", rb_id_text[lcid], sn);
|
||||
gw->write_pdu(lcid, pdu);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch(integ_algo)
|
||||
{
|
||||
case INTEGRITY_ALGORITHM_ID_EIA0:
|
||||
break;
|
||||
case INTEGRITY_ALGORITHM_ID_128_EIA1:
|
||||
security_128_eia1(key_128,
|
||||
count,
|
||||
rb_id,
|
||||
direction,
|
||||
msg,
|
||||
msg_len,
|
||||
mac);
|
||||
break;
|
||||
case INTEGRITY_ALGORITHM_ID_128_EIA2:
|
||||
security_128_eia2(key_128,
|
||||
count,
|
||||
rb_id,
|
||||
direction,
|
||||
msg,
|
||||
msg_len,
|
||||
mac);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Pack/Unpack helper functions
|
||||
* Ref: 3GPP TS 36.323 v10.1.0
|
||||
***************************************************************************/
|
||||
|
||||
void pdcp_pack_control_pdu(uint32_t sn, byte_buffer_t *sdu)
|
||||
{
|
||||
// Make room and add header
|
||||
sdu->msg--;
|
||||
sdu->N_bytes++;
|
||||
*sdu->msg = sn & 0x1F;
|
||||
|
||||
// Add MAC
|
||||
sdu->msg[sdu->N_bytes++] = (PDCP_CONTROL_MAC_I >> 24) & 0xFF;
|
||||
sdu->msg[sdu->N_bytes++] = (PDCP_CONTROL_MAC_I >> 16) & 0xFF;
|
||||
sdu->msg[sdu->N_bytes++] = (PDCP_CONTROL_MAC_I >> 8) & 0xFF;
|
||||
sdu->msg[sdu->N_bytes++] = PDCP_CONTROL_MAC_I & 0xFF;
|
||||
|
||||
}
|
||||
|
||||
void pdcp_unpack_control_pdu(byte_buffer_t *pdu, uint32_t *sn)
|
||||
{
|
||||
// Strip header
|
||||
*sn = *pdu->msg & 0x1F;
|
||||
pdu->msg++;
|
||||
pdu->N_bytes--;
|
||||
|
||||
// Strip MAC
|
||||
pdu->N_bytes -= 4;
|
||||
|
||||
// TODO: integrity check MAC
|
||||
}
|
||||
|
||||
void pdcp_pack_data_pdu_short_sn(uint32_t sn, byte_buffer_t *sdu)
|
||||
{
|
||||
// Make room and add header
|
||||
sdu->msg--;
|
||||
sdu->N_bytes++;
|
||||
sdu->msg[0] = (PDCP_D_C_DATA_PDU << 7) | (sn & 0x7F);
|
||||
}
|
||||
|
||||
void pdcp_unpack_data_pdu_short_sn(byte_buffer_t *sdu, uint32_t *sn)
|
||||
{
|
||||
// Strip header
|
||||
*sn = sdu->msg[0] & 0x7F;
|
||||
sdu->msg++;
|
||||
sdu->N_bytes--;
|
||||
}
|
||||
|
||||
void pdcp_pack_data_pdu_long_sn(uint32_t sn, byte_buffer_t *sdu)
|
||||
{
|
||||
// Make room and add header
|
||||
sdu->msg -= 2;
|
||||
sdu->N_bytes += 2;
|
||||
sdu->msg[0] = (PDCP_D_C_DATA_PDU << 7) | ((sn >> 8) & 0x0F);
|
||||
sdu->msg[1] = sn & 0xFF;
|
||||
}
|
||||
|
||||
void pdcp_unpack_data_pdu_long_sn(byte_buffer_t *sdu, uint32_t *sn)
|
||||
{
|
||||
// Strip header
|
||||
*sn = (sdu->msg[0] & 0x0F) << 8;
|
||||
*sn |= sdu->msg[1];
|
||||
sdu->msg += 2;
|
||||
sdu->N_bytes -= 2;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,264 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICRXAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "upper/rlc.h"
|
||||
#include "upper/rlc_tm.h"
|
||||
#include "upper/rlc_um.h"
|
||||
#include "upper/rlc_am.h"
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
namespace srsue{
|
||||
|
||||
rlc::rlc()
|
||||
{
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
}
|
||||
|
||||
void rlc::init(pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
ue_interface *ue_,
|
||||
srslte::log *rlc_log_,
|
||||
mac_interface_timers *mac_timers_)
|
||||
{
|
||||
pdcp = pdcp_;
|
||||
rrc = rrc_;
|
||||
ue = ue_;
|
||||
rlc_log = rlc_log_;
|
||||
mac_timers = mac_timers_;
|
||||
|
||||
gettimeofday(&metrics_time[1], NULL);
|
||||
reset_metrics();
|
||||
|
||||
rlc_array[0].init(RLC_MODE_TM, rlc_log, RB_ID_SRB0, pdcp, rrc, mac_timers); // SRB0
|
||||
}
|
||||
|
||||
void rlc::reset_metrics()
|
||||
{
|
||||
bzero(dl_tput_bytes, sizeof(long)*SRSUE_N_RADIO_BEARERS);
|
||||
bzero(ul_tput_bytes, sizeof(long)*SRSUE_N_RADIO_BEARERS);
|
||||
}
|
||||
|
||||
void rlc::stop()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void rlc::get_metrics(rlc_metrics_t &m)
|
||||
{
|
||||
|
||||
gettimeofday(&metrics_time[2], NULL);
|
||||
get_time_interval(metrics_time);
|
||||
double secs = (double)metrics_time[0].tv_sec + metrics_time[0].tv_usec*1e-6;
|
||||
|
||||
m.dl_tput_mbps = 0;
|
||||
m.ul_tput_mbps = 0;
|
||||
for (int i=0;i<SRSUE_N_RADIO_BEARERS;i++) {
|
||||
m.dl_tput_mbps += (dl_tput_bytes[i]*8/(double)1e6)/secs;
|
||||
m.ul_tput_mbps += (ul_tput_bytes[i]*8/(double)1e6)/secs;
|
||||
if(rlc_array[i].active()) {
|
||||
rlc_log->info("LCID=%d, RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n",
|
||||
i,
|
||||
(dl_tput_bytes[i]*8/(double)1e6)/secs,
|
||||
(ul_tput_bytes[i]*8/(double)1e6)/secs);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval));
|
||||
reset_metrics();
|
||||
}
|
||||
|
||||
void rlc::reset()
|
||||
{
|
||||
for(uint32_t i=0; i<SRSUE_N_RADIO_BEARERS; i++) {
|
||||
if(rlc_array[i].active())
|
||||
rlc_array[i].reset();
|
||||
}
|
||||
|
||||
rlc_array[0].init(RLC_MODE_TM, rlc_log, RB_ID_SRB0, pdcp, rrc, mac_timers); // SRB0
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
PDCP interface
|
||||
*******************************************************************************/
|
||||
void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
|
||||
{
|
||||
if(valid_lcid(lcid)) {
|
||||
rlc_array[lcid].write_sdu(sdu);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
MAC interface
|
||||
*******************************************************************************/
|
||||
uint32_t rlc::get_buffer_state(uint32_t lcid)
|
||||
{
|
||||
if(valid_lcid(lcid)) {
|
||||
return rlc_array[lcid].get_buffer_state();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t rlc::get_total_buffer_state(uint32_t lcid)
|
||||
{
|
||||
if(valid_lcid(lcid)) {
|
||||
return rlc_array[lcid].get_total_buffer_state();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int rlc::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
if(valid_lcid(lcid)) {
|
||||
ul_tput_bytes[lcid] += nof_bytes;
|
||||
return rlc_array[lcid].read_pdu(payload, nof_bytes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rlc::write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
if(valid_lcid(lcid)) {
|
||||
dl_tput_bytes[lcid] += nof_bytes;
|
||||
rlc_array[lcid].write_pdu(payload, nof_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
void rlc::write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
rlc_log->info_hex(payload, nof_bytes, "BCCH BCH message received.");
|
||||
dl_tput_bytes[0] += nof_bytes;
|
||||
byte_buffer_t *buf = pool->allocate();
|
||||
memcpy(buf->msg, payload, nof_bytes);
|
||||
buf->N_bytes = nof_bytes;
|
||||
buf->set_timestamp();
|
||||
pdcp->write_pdu_bcch_bch(buf);
|
||||
}
|
||||
|
||||
void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
rlc_log->info_hex(payload, nof_bytes, "BCCH TXSCH message received.");
|
||||
dl_tput_bytes[0] += nof_bytes;
|
||||
byte_buffer_t *buf = pool->allocate();
|
||||
memcpy(buf->msg, payload, nof_bytes);
|
||||
buf->N_bytes = nof_bytes;
|
||||
buf->set_timestamp();
|
||||
pdcp->write_pdu_bcch_dlsch(buf);
|
||||
}
|
||||
|
||||
void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
rlc_log->info_hex(payload, nof_bytes, "PCCH message received.");
|
||||
dl_tput_bytes[0] += nof_bytes;
|
||||
byte_buffer_t *buf = pool->allocate();
|
||||
memcpy(buf->msg, payload, nof_bytes);
|
||||
buf->N_bytes = nof_bytes;
|
||||
buf->set_timestamp();
|
||||
pdcp->write_pdu_pcch(buf);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
RRC interface
|
||||
*******************************************************************************/
|
||||
void rlc::add_bearer(uint32_t lcid)
|
||||
{
|
||||
// No config provided - use defaults for lcid
|
||||
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
|
||||
if(RB_ID_SRB1 == lcid || RB_ID_SRB2 == lcid)
|
||||
{
|
||||
if (!rlc_array[lcid].active()) {
|
||||
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM;
|
||||
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS45;
|
||||
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_INFINITY;
|
||||
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_INFINITY;
|
||||
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
|
||||
cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS35;
|
||||
cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0;
|
||||
add_bearer(lcid, &cnfg);
|
||||
} else {
|
||||
rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rb_id_text[lcid]);
|
||||
}
|
||||
}else{
|
||||
rlc_log->error("Radio bearer %s does not support default RLC configuration.",
|
||||
rb_id_text[lcid]);
|
||||
}
|
||||
}
|
||||
|
||||
void rlc::add_bearer(uint32_t lcid, LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg)
|
||||
{
|
||||
if(lcid < 0 || lcid >= SRSUE_N_RADIO_BEARERS) {
|
||||
rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSUE_N_RADIO_BEARERS, lcid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!rlc_array[lcid].active()) {
|
||||
rlc_log->info("Adding radio bearer %s with mode %s\n",
|
||||
rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode]);
|
||||
switch(cnfg->rlc_mode)
|
||||
{
|
||||
case LIBLTE_RRC_RLC_MODE_AM:
|
||||
rlc_array[lcid].init(RLC_MODE_AM, rlc_log, lcid, pdcp, rrc, mac_timers);
|
||||
break;
|
||||
case LIBLTE_RRC_RLC_MODE_UM_BI:
|
||||
rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers);
|
||||
break;
|
||||
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
|
||||
rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers);
|
||||
break;
|
||||
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
|
||||
rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers);
|
||||
break;
|
||||
default:
|
||||
rlc_log->error("Cannot add RLC entity - invalid mode\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
rlc_log->warning("Bearer %s already created.\n", rb_id_text[lcid]);
|
||||
}
|
||||
rlc_array[lcid].configure(cnfg);
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Helpers
|
||||
*******************************************************************************/
|
||||
bool rlc::valid_lcid(uint32_t lcid)
|
||||
{
|
||||
if(lcid < 0 || lcid >= SRSUE_N_RADIO_BEARERS) {
|
||||
return false;
|
||||
}
|
||||
if(!rlc_array[lcid].active()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace srsue
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,137 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "upper/rlc_entity.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
rlc_entity::rlc_entity()
|
||||
:rlc(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void rlc_entity::init(rlc_mode_t mode,
|
||||
srslte::log *rlc_entity_log_,
|
||||
uint32_t lcid_,
|
||||
pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
srslte::mac_interface_timers *mac_timers_)
|
||||
{
|
||||
tm.reset();
|
||||
um.reset();
|
||||
am.reset();
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case RLC_MODE_TM:
|
||||
rlc = &tm;
|
||||
break;
|
||||
case RLC_MODE_UM:
|
||||
rlc = &um;
|
||||
break;
|
||||
case RLC_MODE_AM:
|
||||
rlc = &am;
|
||||
break;
|
||||
default:
|
||||
rlc_entity_log_->error("Invalid RLC mode - defaulting to TM\n");
|
||||
rlc = &tm;
|
||||
break;
|
||||
}
|
||||
|
||||
rlc->init(rlc_entity_log_, lcid_, pdcp_, rrc_, mac_timers_);
|
||||
}
|
||||
|
||||
void rlc_entity::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg)
|
||||
{
|
||||
if(rlc)
|
||||
rlc->configure(cnfg);
|
||||
}
|
||||
|
||||
void rlc_entity::reset()
|
||||
{
|
||||
rlc->reset();
|
||||
rlc = NULL;
|
||||
}
|
||||
|
||||
bool rlc_entity::active()
|
||||
{
|
||||
return (rlc != NULL);
|
||||
}
|
||||
|
||||
rlc_mode_t rlc_entity::get_mode()
|
||||
{
|
||||
if(rlc)
|
||||
return rlc->get_mode();
|
||||
else
|
||||
return RLC_MODE_TM;
|
||||
}
|
||||
|
||||
uint32_t rlc_entity::get_bearer()
|
||||
{
|
||||
if(rlc)
|
||||
return rlc->get_bearer();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// PDCP interface
|
||||
void rlc_entity::write_sdu(byte_buffer_t *sdu)
|
||||
{
|
||||
if(rlc)
|
||||
rlc->write_sdu(sdu);
|
||||
}
|
||||
|
||||
// MAC interface
|
||||
uint32_t rlc_entity::get_buffer_state()
|
||||
{
|
||||
if(rlc)
|
||||
return rlc->get_buffer_state();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t rlc_entity::get_total_buffer_state()
|
||||
{
|
||||
if(rlc)
|
||||
return rlc->get_total_buffer_state();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rlc_entity::read_pdu(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
if(rlc)
|
||||
return rlc->read_pdu(payload, nof_bytes);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
void rlc_entity::write_pdu(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
if(rlc)
|
||||
rlc->write_pdu(payload, nof_bytes);
|
||||
}
|
||||
|
||||
} // namespace srsue
|
@ -0,0 +1,127 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "upper/rlc_tm.h"
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
namespace srsue{
|
||||
|
||||
rlc_tm::rlc_tm() : ul_queue(16)
|
||||
{
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
}
|
||||
|
||||
void rlc_tm::init(srslte::log *log_,
|
||||
uint32_t lcid_,
|
||||
pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
mac_interface_timers *mac_timers)
|
||||
{
|
||||
log = log_;
|
||||
lcid = lcid_;
|
||||
pdcp = pdcp_;
|
||||
rrc = rrc_;
|
||||
}
|
||||
|
||||
void rlc_tm::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg)
|
||||
{
|
||||
log->error("Attempted to configure TM RLC entity");
|
||||
}
|
||||
|
||||
void rlc_tm::empty_queue()
|
||||
{
|
||||
// Drop all messages in TX queue
|
||||
byte_buffer_t *buf;
|
||||
while(ul_queue.size() > 0) {
|
||||
ul_queue.read(&buf);
|
||||
pool->deallocate(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_tm::reset()
|
||||
{
|
||||
empty_queue();
|
||||
}
|
||||
|
||||
rlc_mode_t rlc_tm::get_mode()
|
||||
{
|
||||
return RLC_MODE_TM;
|
||||
}
|
||||
|
||||
uint32_t rlc_tm::get_bearer()
|
||||
{
|
||||
return lcid;
|
||||
}
|
||||
|
||||
// PDCP interface
|
||||
void rlc_tm::write_sdu(byte_buffer_t *sdu)
|
||||
{
|
||||
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rb_id_text[lcid]);
|
||||
ul_queue.write(sdu);
|
||||
}
|
||||
|
||||
// MAC interface
|
||||
uint32_t rlc_tm::get_buffer_state()
|
||||
{
|
||||
return ul_queue.size_bytes();
|
||||
}
|
||||
|
||||
uint32_t rlc_tm::get_total_buffer_state()
|
||||
{
|
||||
return get_buffer_state();
|
||||
}
|
||||
|
||||
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", rb_id_text[lcid]);
|
||||
return 0;
|
||||
}
|
||||
byte_buffer_t *buf;
|
||||
ul_queue.read(&buf);
|
||||
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",
|
||||
rb_id_text[lcid], buf->get_latency_us());
|
||||
pool->deallocate(buf);
|
||||
log->info_hex(payload, pdu_size, "TX %s, %s PDU", rb_id_text[lcid], rlc_mode_text[RLC_MODE_TM]);
|
||||
return pdu_size;
|
||||
}
|
||||
|
||||
void rlc_tm:: write_pdu(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
byte_buffer_t *buf = pool->allocate();
|
||||
memcpy(buf->msg, payload, nof_bytes);
|
||||
buf->N_bytes = nof_bytes;
|
||||
buf->set_timestamp();
|
||||
pdcp->write_pdu(lcid, buf);
|
||||
}
|
||||
|
||||
} // namespace srsue
|
@ -0,0 +1,701 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "upper/rlc_um.h"
|
||||
|
||||
#define RX_MOD_BASE(x) (x-vr_uh-rx_window_size)%rx_mod
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
namespace srsue{
|
||||
|
||||
rlc_um::rlc_um() : tx_sdu_queue(16)
|
||||
{
|
||||
tx_sdu = NULL;
|
||||
rx_sdu = NULL;
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
|
||||
vt_us = 0;
|
||||
vr_ur = 0;
|
||||
vr_ux = 0;
|
||||
vr_uh = 0;
|
||||
|
||||
vr_ur_in_rx_sdu = 0;
|
||||
|
||||
mac_timers = NULL;
|
||||
|
||||
pdu_lost = false;
|
||||
}
|
||||
|
||||
void rlc_um::init(srslte::log *log_,
|
||||
uint32_t lcid_,
|
||||
pdcp_interface_rlc *pdcp_,
|
||||
rrc_interface_rlc *rrc_,
|
||||
srslte::mac_interface_timers *mac_timers_)
|
||||
{
|
||||
log = log_;
|
||||
lcid = lcid_;
|
||||
pdcp = pdcp_;
|
||||
rrc = rrc_;
|
||||
mac_timers = mac_timers_;
|
||||
reordering_timeout_id = mac_timers->get_unique_id();
|
||||
}
|
||||
|
||||
void rlc_um::configure(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg)
|
||||
{
|
||||
switch(cnfg->rlc_mode)
|
||||
{
|
||||
case LIBLTE_RRC_RLC_MODE_UM_BI:
|
||||
t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_bi_rlc.t_reordering];
|
||||
rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_bi_rlc.sn_field_len;
|
||||
rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 16 : 512;
|
||||
rx_mod = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 32 : 1024;
|
||||
tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_bi_rlc.sn_field_len;
|
||||
tx_mod = (RLC_UMD_SN_SIZE_5_BITS == tx_sn_field_length) ? 32 : 1024;
|
||||
log->info("%s configured in %s mode: "
|
||||
"t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
|
||||
rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode],
|
||||
t_reordering,
|
||||
rlc_umd_sn_size_num[rx_sn_field_length],
|
||||
rlc_umd_sn_size_num[tx_sn_field_length]);
|
||||
break;
|
||||
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
|
||||
tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_uni_rlc.sn_field_len;
|
||||
tx_mod = (RLC_UMD_SN_SIZE_5_BITS == tx_sn_field_length) ? 32 : 1024;
|
||||
log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n",
|
||||
rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode],
|
||||
rlc_umd_sn_size_num[tx_sn_field_length]);
|
||||
break;
|
||||
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
|
||||
t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_uni_rlc.t_reordering];
|
||||
rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_uni_rlc.sn_field_len;
|
||||
rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 16 : 512;
|
||||
rx_mod = (RLC_UMD_SN_SIZE_5_BITS == rx_sn_field_length) ? 32 : 1024;
|
||||
log->info("%s configured in %s mode: "
|
||||
"t_reordering=%d ms, rx_sn_field_length=%u bits\n",
|
||||
rb_id_text[lcid], liblte_rrc_rlc_mode_text[cnfg->rlc_mode],
|
||||
liblte_rrc_t_reordering_num[t_reordering],
|
||||
rlc_umd_sn_size_num[rx_sn_field_length]);
|
||||
break;
|
||||
default:
|
||||
log->error("RLC configuration mode not recognized\n");
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_um::empty_queue() {
|
||||
// Drop all messages in TX SDU queue
|
||||
byte_buffer_t *buf;
|
||||
while(tx_sdu_queue.size() > 0) {
|
||||
tx_sdu_queue.read(&buf);
|
||||
pool->deallocate(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_um::reset()
|
||||
{
|
||||
|
||||
// Empty tx_sdu_queue before locking the mutex
|
||||
empty_queue();
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
vt_us = 0;
|
||||
vr_ur = 0;
|
||||
vr_ux = 0;
|
||||
vr_uh = 0;
|
||||
pdu_lost = false;
|
||||
if(rx_sdu)
|
||||
rx_sdu->reset();
|
||||
if(tx_sdu)
|
||||
tx_sdu->reset();
|
||||
if(mac_timers)
|
||||
mac_timers->get(reordering_timeout_id)->stop();
|
||||
|
||||
// Drop all messages in RX window
|
||||
std::map<uint32_t, rlc_umd_pdu_t>::iterator it;
|
||||
for(it = rx_window.begin(); it != rx_window.end(); it++) {
|
||||
pool->deallocate(it->second.buf);
|
||||
}
|
||||
rx_window.clear();
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
rlc_mode_t rlc_um::get_mode()
|
||||
{
|
||||
return RLC_MODE_UM;
|
||||
}
|
||||
|
||||
uint32_t rlc_um::get_bearer()
|
||||
{
|
||||
return lcid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* PDCP interface
|
||||
***************************************************************************/
|
||||
|
||||
void rlc_um::write_sdu(byte_buffer_t *sdu)
|
||||
{
|
||||
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rb_id_text[lcid]);
|
||||
tx_sdu_queue.write(sdu);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* MAC interface
|
||||
***************************************************************************/
|
||||
|
||||
uint32_t rlc_um::get_buffer_state()
|
||||
{
|
||||
// Bytes needed for tx SDUs
|
||||
uint32_t n_sdus = tx_sdu_queue.size();
|
||||
uint32_t n_bytes = tx_sdu_queue.size_bytes();
|
||||
if(tx_sdu)
|
||||
{
|
||||
n_sdus++;
|
||||
n_bytes += tx_sdu->N_bytes;
|
||||
}
|
||||
|
||||
// Room needed for header extensions? (integer rounding)
|
||||
if(n_sdus > 1)
|
||||
n_bytes += ((n_sdus-1)*1.5)+0.5;
|
||||
|
||||
// Room needed for fixed header?
|
||||
if(n_bytes > 0)
|
||||
n_bytes += 2;
|
||||
|
||||
return n_bytes;
|
||||
}
|
||||
|
||||
uint32_t rlc_um::get_total_buffer_state()
|
||||
{
|
||||
return get_buffer_state();
|
||||
}
|
||||
|
||||
int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
log->debug("MAC opportunity - %d bytes\n", nof_bytes);
|
||||
pthread_mutex_lock(&mutex);
|
||||
int r = build_data_pdu(payload, nof_bytes);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
handle_data_pdu(payload, nof_bytes);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Timeout callback interface
|
||||
***************************************************************************/
|
||||
|
||||
void rlc_um::timer_expired(uint32_t timeout_id)
|
||||
{
|
||||
if(reordering_timeout_id == timeout_id)
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
// 36.322 v10 Section 5.1.2.2.4
|
||||
log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n",
|
||||
rb_id_text[lcid]);
|
||||
|
||||
log->warning("Lost PDU SN: %d\n", vr_ur);
|
||||
pdu_lost = true;
|
||||
rx_sdu->reset();
|
||||
while(RX_MOD_BASE(vr_ur) < RX_MOD_BASE(vr_ux))
|
||||
{
|
||||
vr_ur = (vr_ur + 1)%rx_mod;
|
||||
log->debug("Entering Reassemble from timeout id=%d\n", timeout_id);
|
||||
reassemble_rx_sdus();
|
||||
log->debug("Finished reassemble from timeout id=%d\n", timeout_id);
|
||||
}
|
||||
mac_timers->get(reordering_timeout_id)->stop();
|
||||
if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur))
|
||||
{
|
||||
mac_timers->get(reordering_timeout_id)->set(this, t_reordering);
|
||||
mac_timers->get(reordering_timeout_id)->run();
|
||||
vr_ux = vr_uh;
|
||||
}
|
||||
|
||||
debug_state();
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
}
|
||||
|
||||
bool rlc_um::reordering_timeout_running()
|
||||
{
|
||||
return mac_timers->get(reordering_timeout_id)->is_running();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Helpers
|
||||
***************************************************************************/
|
||||
|
||||
int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
if(!tx_sdu && tx_sdu_queue.size() == 0)
|
||||
{
|
||||
log->info("No data available to be sent\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte_buffer_t *pdu = pool->allocate();
|
||||
if(!pdu || pdu->N_bytes != 0)
|
||||
{
|
||||
log->error("Failed to allocate PDU buffer\n");
|
||||
return 0;
|
||||
}
|
||||
rlc_umd_pdu_header_t header;
|
||||
header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED;
|
||||
header.sn = vt_us;
|
||||
header.N_li = 0;
|
||||
header.sn_size = tx_sn_field_length;
|
||||
|
||||
uint32_t to_move = 0;
|
||||
uint32_t last_li = 0;
|
||||
uint8_t *pdu_ptr = pdu->msg;
|
||||
|
||||
int head_len = rlc_um_packed_length(&header);
|
||||
int pdu_space = nof_bytes;
|
||||
|
||||
if(pdu_space <= head_len)
|
||||
{
|
||||
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
|
||||
rb_id_text[lcid], nof_bytes, head_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check for SDU segment
|
||||
if(tx_sdu)
|
||||
{
|
||||
to_move = ((pdu_space-head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space-head_len;
|
||||
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
|
||||
rb_id_text[lcid], to_move, tx_sdu->N_bytes);
|
||||
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
||||
last_li = to_move;
|
||||
pdu_ptr += to_move;
|
||||
pdu->N_bytes += to_move;
|
||||
tx_sdu->N_bytes -= to_move;
|
||||
tx_sdu->msg += to_move;
|
||||
if(tx_sdu->N_bytes == 0)
|
||||
{
|
||||
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
|
||||
rb_id_text[lcid], tx_sdu->get_latency_us());
|
||||
pool->deallocate(tx_sdu);
|
||||
tx_sdu = NULL;
|
||||
}
|
||||
pdu_space -= to_move;
|
||||
header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU
|
||||
}
|
||||
|
||||
// Pull SDUs from queue
|
||||
while(pdu_space > head_len && tx_sdu_queue.size() > 0)
|
||||
{
|
||||
log->debug("pdu_space=%d, head_len=%d\n", pdu_space, head_len);
|
||||
if(last_li > 0)
|
||||
header.li[header.N_li++] = last_li;
|
||||
head_len = rlc_um_packed_length(&header);
|
||||
tx_sdu_queue.read(&tx_sdu);
|
||||
to_move = ((pdu_space-head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space-head_len;
|
||||
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
|
||||
rb_id_text[lcid], to_move, tx_sdu->N_bytes);
|
||||
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
||||
last_li = to_move;
|
||||
pdu_ptr += to_move;
|
||||
pdu->N_bytes += to_move;
|
||||
tx_sdu->N_bytes -= to_move;
|
||||
tx_sdu->msg += to_move;
|
||||
if(tx_sdu->N_bytes == 0)
|
||||
{
|
||||
log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
|
||||
rb_id_text[lcid], tx_sdu->get_latency_us());
|
||||
pool->deallocate(tx_sdu);
|
||||
tx_sdu = NULL;
|
||||
}
|
||||
pdu_space -= to_move;
|
||||
}
|
||||
|
||||
if(tx_sdu)
|
||||
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
|
||||
|
||||
// Set SN
|
||||
header.sn = vt_us;
|
||||
vt_us = (vt_us + 1)%tx_mod;
|
||||
|
||||
// Add header and TX
|
||||
log->debug("%s packing PDU with length %d\n", rb_id_text[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("%sreturning length %d\n", rb_id_text[lcid], pdu->N_bytes);
|
||||
pool->deallocate(pdu);
|
||||
|
||||
debug_state();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
||||
{
|
||||
std::map<uint32_t, rlc_umd_pdu_t>::iterator it;
|
||||
rlc_umd_pdu_header_t header;
|
||||
rlc_um_read_data_pdu_header(payload, nof_bytes, rx_sn_field_length, &header);
|
||||
|
||||
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
|
||||
rb_id_text[lcid], header.sn);
|
||||
|
||||
if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-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",
|
||||
rb_id_text[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",
|
||||
rb_id_text[lcid], header.sn);
|
||||
return;
|
||||
}
|
||||
|
||||
// Write to rx window
|
||||
rlc_umd_pdu_t pdu;
|
||||
pdu.buf = pool->allocate();
|
||||
if (!pdu.buf) {
|
||||
log->error("Discarting packet: no space in buffer pool\n");
|
||||
return;
|
||||
}
|
||||
memcpy(pdu.buf->msg, payload, nof_bytes);
|
||||
pdu.buf->N_bytes = nof_bytes;
|
||||
//Strip header from PDU
|
||||
int header_len = rlc_um_packed_length(&header);
|
||||
pdu.buf->msg += header_len;
|
||||
pdu.buf->N_bytes -= header_len;
|
||||
pdu.header = header;
|
||||
rx_window[header.sn] = pdu;
|
||||
|
||||
// Update vr_uh
|
||||
if(!inside_reordering_window(header.sn))
|
||||
vr_uh = (header.sn + 1)%rx_mod;
|
||||
|
||||
// Reassemble and deliver SDUs, while updating vr_ur
|
||||
log->debug("Entering Reassemble from received PDU\n");
|
||||
reassemble_rx_sdus();
|
||||
log->debug("Finished reassemble from received PDU\n");
|
||||
|
||||
// Update reordering variables and timers
|
||||
if(mac_timers->get(reordering_timeout_id)->is_running())
|
||||
{
|
||||
if(RX_MOD_BASE(vr_ux) <= RX_MOD_BASE(vr_ur) ||
|
||||
(!inside_reordering_window(vr_ux) && vr_ux != vr_uh))
|
||||
{
|
||||
mac_timers->get(reordering_timeout_id)->stop();
|
||||
}
|
||||
}
|
||||
if(!mac_timers->get(reordering_timeout_id)->is_running())
|
||||
{
|
||||
if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur))
|
||||
{
|
||||
mac_timers->get(reordering_timeout_id)->set(this, t_reordering);
|
||||
mac_timers->get(reordering_timeout_id)->run();
|
||||
vr_ux = vr_uh;
|
||||
}
|
||||
}
|
||||
|
||||
debug_state();
|
||||
}
|
||||
|
||||
void rlc_um::reassemble_rx_sdus()
|
||||
{
|
||||
if(!rx_sdu)
|
||||
rx_sdu = pool->allocate();
|
||||
|
||||
// First catch up with lower edge of reordering window
|
||||
while(!inside_reordering_window(vr_ur))
|
||||
{
|
||||
if(rx_window.end() == rx_window.find(vr_ur))
|
||||
{
|
||||
rx_sdu->reset();
|
||||
}else{
|
||||
// Handle any SDU segments
|
||||
for(int i=0; i<rx_window[vr_ur].header.N_li; i++)
|
||||
{
|
||||
int len = rx_window[vr_ur].header.li[i];
|
||||
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len);
|
||||
rx_sdu->N_bytes += len;
|
||||
rx_window[vr_ur].buf->msg += len;
|
||||
rx_window[vr_ur].buf->N_bytes -= len;
|
||||
if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi) || vr_ur != ((vr_ur_in_rx_sdu+1)%rx_mod)) {
|
||||
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)", rb_id_text[lcid], vr_ur, i);
|
||||
rx_sdu->set_timestamp();
|
||||
pdcp->write_pdu(lcid, rx_sdu);
|
||||
rx_sdu = pool->allocate();
|
||||
}
|
||||
pdu_lost = false;
|
||||
}
|
||||
|
||||
// Handle last segment
|
||||
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes);
|
||||
rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes;
|
||||
log->debug("Writting last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d\n",
|
||||
vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes);
|
||||
vr_ur_in_rx_sdu = vr_ur;
|
||||
if(rlc_um_end_aligned(rx_window[vr_ur].header.fi))
|
||||
{
|
||||
if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
|
||||
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)", rb_id_text[lcid], vr_ur);
|
||||
rx_sdu->set_timestamp();
|
||||
pdcp->write_pdu(lcid, rx_sdu);
|
||||
rx_sdu = pool->allocate();
|
||||
}
|
||||
pdu_lost = false;
|
||||
}
|
||||
|
||||
// Clean up rx_window
|
||||
pool->deallocate(rx_window[vr_ur].buf);
|
||||
rx_window.erase(vr_ur);
|
||||
}
|
||||
|
||||
vr_ur = (vr_ur + 1)%rx_mod;
|
||||
}
|
||||
|
||||
|
||||
// Now update vr_ur until we reach an SN we haven't yet received
|
||||
while(rx_window.end() != rx_window.find(vr_ur))
|
||||
{
|
||||
// Handle any SDU segments
|
||||
for(int i=0; i<rx_window[vr_ur].header.N_li; i++)
|
||||
{
|
||||
int len = rx_window[vr_ur].header.li[i];
|
||||
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len);
|
||||
log->debug("Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d\n",
|
||||
len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, rx_mod, (vr_ur_in_rx_sdu+1)%rx_mod);
|
||||
rx_sdu->N_bytes += len;
|
||||
rx_window[vr_ur].buf->msg += len;
|
||||
rx_window[vr_ur].buf->N_bytes -= len;
|
||||
if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi) || vr_ur != ((vr_ur_in_rx_sdu+1)%rx_mod)) {
|
||||
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)", rb_id_text[lcid], vr_ur, i);
|
||||
rx_sdu->set_timestamp();
|
||||
pdcp->write_pdu(lcid, rx_sdu);
|
||||
rx_sdu = pool->allocate();
|
||||
}
|
||||
pdu_lost = false;
|
||||
}
|
||||
|
||||
// Handle last segment
|
||||
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes);
|
||||
rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes;
|
||||
log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n",
|
||||
vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes);
|
||||
vr_ur_in_rx_sdu = vr_ur;
|
||||
if(rlc_um_end_aligned(rx_window[vr_ur].header.fi))
|
||||
{
|
||||
if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
|
||||
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)", rb_id_text[lcid], vr_ur);
|
||||
rx_sdu->set_timestamp();
|
||||
pdcp->write_pdu(lcid, rx_sdu);
|
||||
rx_sdu = pool->allocate();
|
||||
}
|
||||
pdu_lost = false;
|
||||
}
|
||||
|
||||
// Clean up rx_window
|
||||
pool->deallocate(rx_window[vr_ur].buf);
|
||||
rx_window.erase(vr_ur);
|
||||
|
||||
vr_ur = (vr_ur + 1)%rx_mod;
|
||||
}
|
||||
}
|
||||
|
||||
bool rlc_um::inside_reordering_window(uint16_t sn)
|
||||
{
|
||||
if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-rx_window_size) &&
|
||||
RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh))
|
||||
{
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_um::debug_state()
|
||||
{
|
||||
log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n",
|
||||
rb_id_text[lcid], vt_us, vr_ur, vr_ux, vr_uh);
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Header pack/unpack helper functions
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
|
||||
***************************************************************************/
|
||||
|
||||
void rlc_um_read_data_pdu_header(byte_buffer_t *pdu, rlc_umd_sn_size_t sn_size, rlc_umd_pdu_header_t *header)
|
||||
{
|
||||
rlc_um_read_data_pdu_header(pdu->msg, pdu->N_bytes, sn_size, header);
|
||||
}
|
||||
|
||||
void rlc_um_read_data_pdu_header(uint8_t *payload, uint32_t nof_bytes, rlc_umd_sn_size_t sn_size, rlc_umd_pdu_header_t *header)
|
||||
{
|
||||
uint8_t ext;
|
||||
uint8_t *ptr = payload;
|
||||
|
||||
// Fixed part
|
||||
if(RLC_UMD_SN_SIZE_5_BITS == sn_size)
|
||||
{
|
||||
header->fi = (rlc_fi_field_t)((*ptr >> 6) & 0x03); // 2 bits FI
|
||||
ext = ((*ptr >> 5) & 0x01); // 1 bit EXT
|
||||
header->sn = *ptr & 0x1F; // 5 bits SN
|
||||
ptr++;
|
||||
}else{
|
||||
header->fi = (rlc_fi_field_t)((*ptr >> 3) & 0x03); // 2 bits FI
|
||||
ext = ((*ptr >> 2) & 0x01); // 1 bit EXT
|
||||
header->sn = (*ptr & 0x03) << 8; // 2 bits SN
|
||||
ptr++;
|
||||
header->sn |= (*ptr & 0xFF); // 8 bits SN
|
||||
ptr++;
|
||||
}
|
||||
|
||||
header->sn_size = sn_size;
|
||||
|
||||
// Extension part
|
||||
header->N_li = 0;
|
||||
while(ext)
|
||||
{
|
||||
if(header->N_li%2 == 0)
|
||||
{
|
||||
ext = ((*ptr >> 7) & 0x01);
|
||||
header->li[header->N_li] = (*ptr & 0x7F) << 4; // 7 bits of LI
|
||||
ptr++;
|
||||
header->li[header->N_li] |= (*ptr & 0xF0) >> 4; // 4 bits of LI
|
||||
header->N_li++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ext = (*ptr >> 3) & 0x01;
|
||||
header->li[header->N_li] = (*ptr & 0x07) << 8; // 3 bits of LI
|
||||
ptr++;
|
||||
header->li[header->N_li] |= (*ptr & 0xFF); // 8 bits of LI
|
||||
header->N_li++;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_um_write_data_pdu_header(rlc_umd_pdu_header_t *header, byte_buffer_t *pdu)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t ext = (header->N_li > 0) ? 1 : 0;
|
||||
|
||||
// Make room for the header
|
||||
uint32_t len = rlc_um_packed_length(header);
|
||||
pdu->msg -= len;
|
||||
uint8_t *ptr = pdu->msg;
|
||||
|
||||
// Fixed part
|
||||
if(RLC_UMD_SN_SIZE_5_BITS == header->sn_size)
|
||||
{
|
||||
*ptr = (header->fi & 0x03) << 6; // 2 bits FI
|
||||
*ptr |= (ext & 0x01) << 5; // 1 bit EXT
|
||||
*ptr |= header->sn & 0x1F; // 5 bits SN
|
||||
ptr++;
|
||||
}else{
|
||||
*ptr = (header->fi & 0x03) << 3; // 3 Reserved bits | 2 bits FI
|
||||
*ptr |= (ext & 0x01) << 2; // 1 bit EXT
|
||||
*ptr |= (header->sn & 0x300) >> 8; // 2 bits SN
|
||||
ptr++;
|
||||
*ptr = (header->sn & 0xFF); // 8 bits SN
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// Extension part
|
||||
i = 0;
|
||||
while(i < header->N_li)
|
||||
{
|
||||
ext = ((i+1) == header->N_li) ? 0 : 1;
|
||||
*ptr = (ext & 0x01) << 7; // 1 bit header
|
||||
*ptr |= (header->li[i] & 0x7F0) >> 4; // 7 bits of LI
|
||||
ptr++;
|
||||
*ptr = (header->li[i] & 0x00F) << 4; // 4 bits of LI
|
||||
i++;
|
||||
if(i < header->N_li)
|
||||
{
|
||||
ext = ((i+1) == header->N_li) ? 0 : 1;
|
||||
*ptr |= (ext & 0x01) << 3; // 1 bit header
|
||||
*ptr |= (header->li[i] & 0x700) >> 8; // 3 bits of LI
|
||||
ptr++;
|
||||
*ptr = (header->li[i] & 0x0FF); // 8 bits of LI
|
||||
ptr++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// Pad if N_li is odd
|
||||
if(header->N_li%2 == 1)
|
||||
ptr++;
|
||||
|
||||
pdu->N_bytes += ptr-pdu->msg;
|
||||
}
|
||||
|
||||
uint32_t rlc_um_packed_length(rlc_umd_pdu_header_t *header)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
if(RLC_UMD_SN_SIZE_5_BITS == header->sn_size)
|
||||
{
|
||||
len += 1; // Fixed part is 1 byte
|
||||
}else{
|
||||
len += 2; // Fixed part is 2 bytes
|
||||
}
|
||||
len += header->N_li * 1.5 + 0.5; // Extension part - integer rounding up
|
||||
return len;
|
||||
}
|
||||
|
||||
bool rlc_um_start_aligned(uint8_t fi)
|
||||
{
|
||||
return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_END_ALIGNED);
|
||||
}
|
||||
|
||||
bool rlc_um_end_aligned(uint8_t fi)
|
||||
{
|
||||
return (fi == RLC_FI_FIELD_START_AND_END_ALIGNED || fi == RLC_FI_FIELD_NOT_START_ALIGNED);
|
||||
}
|
||||
|
||||
} // namespace srsue
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,373 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "upper/usim.h"
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
namespace srsue{
|
||||
|
||||
usim::usim()
|
||||
{}
|
||||
|
||||
void usim::init(usim_args_t *args, srslte::log *usim_log_)
|
||||
{
|
||||
usim_log = usim_log_;
|
||||
|
||||
const char *imsi_str = args->imsi.c_str();
|
||||
const char *imei_str = args->imei.c_str();
|
||||
uint32_t i;
|
||||
|
||||
if(32 == args->op.length()) {
|
||||
str_to_hex(args->op, op);
|
||||
} else {
|
||||
usim_log->error("Invalid length for OP: %d should be %d", args->op.length(), 32);
|
||||
usim_log->console("Invalid length for OP: %d should be %d", args->op.length(), 32);
|
||||
}
|
||||
|
||||
if(4 == args->amf.length()) {
|
||||
str_to_hex(args->amf, amf);
|
||||
} else {
|
||||
usim_log->error("Invalid length for AMF: %d should be %d", args->amf.length(), 4);
|
||||
usim_log->console("Invalid length for AMF: %d should be %d", args->amf.length(), 4);
|
||||
}
|
||||
|
||||
if(15 == args->imsi.length()) {
|
||||
imsi = 0;
|
||||
for(i=0; i<15; i++)
|
||||
{
|
||||
imsi *= 10;
|
||||
imsi += imsi_str[i] - '0';
|
||||
}
|
||||
} else {
|
||||
usim_log->error("Invalid length for ISMI: %d should be %d", args->imsi.length(), 15);
|
||||
usim_log->console("Invalid length for IMSI: %d should be %d", args->imsi.length(), 15);
|
||||
}
|
||||
|
||||
if(15 == args->imei.length()) {
|
||||
imei = 0;
|
||||
for(i=0; i<15; i++)
|
||||
{
|
||||
imei *= 10;
|
||||
imei += imei_str[i] - '0';
|
||||
}
|
||||
} else {
|
||||
usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15);
|
||||
usim_log->console("Invalid length for IMEI: %d should be %d", args->imei.length(), 15);
|
||||
}
|
||||
|
||||
if(32 == args->k.length()) {
|
||||
str_to_hex(args->k, k);
|
||||
} else {
|
||||
usim_log->error("Invalid length for K: %d should be %d", args->k.length(), 32);
|
||||
usim_log->console("Invalid length for K: %d should be %d", args->k.length(), 32);
|
||||
}
|
||||
|
||||
auth_algo = auth_algo_milenage;
|
||||
if("xor" == args->algo) {
|
||||
auth_algo = auth_algo_xor;
|
||||
}
|
||||
}
|
||||
|
||||
void usim::stop()
|
||||
{}
|
||||
|
||||
/*******************************************************************************
|
||||
NAS interface
|
||||
*******************************************************************************/
|
||||
|
||||
void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
|
||||
{
|
||||
if(NULL == imsi_ || n < 15)
|
||||
{
|
||||
usim_log->error("Invalid parameters to get_imsi_vec");
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t temp = imsi;
|
||||
for(int i=14;i>=0;i--)
|
||||
{
|
||||
imsi_[i] = temp % 10;
|
||||
temp /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
|
||||
{
|
||||
if(NULL == imei_ || n < 15)
|
||||
{
|
||||
usim_log->error("Invalid parameters to get_imei_vec");
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 temp = imei;
|
||||
for(int i=14;i>=0;i--)
|
||||
{
|
||||
imei_[i] = temp % 10;
|
||||
temp /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
void usim::generate_authentication_response(uint8_t *rand,
|
||||
uint8_t *autn_enb,
|
||||
uint16_t mcc,
|
||||
uint16_t mnc,
|
||||
bool *net_valid,
|
||||
uint8_t *res)
|
||||
{
|
||||
if(auth_algo_xor == auth_algo) {
|
||||
gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res);
|
||||
} else {
|
||||
gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res);
|
||||
}
|
||||
}
|
||||
|
||||
void usim::generate_nas_keys(uint8_t *k_nas_enc,
|
||||
uint8_t *k_nas_int,
|
||||
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
||||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
|
||||
{
|
||||
// Generate K_nas_enc and K_nas_int
|
||||
security_generate_k_nas( k_asme,
|
||||
cipher_algo,
|
||||
integ_algo,
|
||||
k_nas_enc,
|
||||
k_nas_int);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
RRC interface
|
||||
*******************************************************************************/
|
||||
|
||||
void usim::generate_as_keys(uint32_t count_ul,
|
||||
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)
|
||||
{
|
||||
// Generate K_enb
|
||||
security_generate_k_enb( k_asme,
|
||||
count_ul,
|
||||
k_enb);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Helpers
|
||||
*******************************************************************************/
|
||||
|
||||
void usim::gen_auth_res_milenage( uint8_t *rand,
|
||||
uint8_t *autn_enb,
|
||||
uint16_t mcc,
|
||||
uint16_t mnc,
|
||||
bool *net_valid,
|
||||
uint8_t *res)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t sqn[6];
|
||||
|
||||
*net_valid = true;
|
||||
|
||||
// Use RAND and K to compute RES, CK, IK and AK
|
||||
security_milenage_f2345( k,
|
||||
op,
|
||||
rand,
|
||||
res,
|
||||
ck,
|
||||
ik,
|
||||
ak);
|
||||
|
||||
// Extract sqn from autn
|
||||
for(i=0;i<6;i++)
|
||||
{
|
||||
sqn[i] = autn_enb[i] ^ ak[i];
|
||||
}
|
||||
|
||||
// Generate MAC
|
||||
security_milenage_f1( k,
|
||||
op,
|
||||
rand,
|
||||
sqn,
|
||||
amf,
|
||||
mac);
|
||||
|
||||
// Construct AUTN
|
||||
for(i=0; i<6; i++)
|
||||
{
|
||||
autn[i] = sqn[i] ^ ak[i];
|
||||
}
|
||||
for(i=0; i<2; i++)
|
||||
{
|
||||
autn[6+i] = amf[i];
|
||||
}
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
autn[8+i] = mac[i];
|
||||
}
|
||||
|
||||
// Compare AUTNs
|
||||
for(i=0; i<16; i++)
|
||||
{
|
||||
if(autn[i] != autn_enb[i])
|
||||
{
|
||||
*net_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate K_asme
|
||||
security_generate_k_asme( ck,
|
||||
ik,
|
||||
ak,
|
||||
sqn,
|
||||
mcc,
|
||||
mnc,
|
||||
k_asme);
|
||||
}
|
||||
|
||||
// 3GPP TS 34.108 version 10.0.0 Section 8
|
||||
void usim::gen_auth_res_xor(uint8_t *rand,
|
||||
uint8_t *autn_enb,
|
||||
uint16_t mcc,
|
||||
uint16_t mnc,
|
||||
bool *net_valid,
|
||||
uint8_t *res)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t sqn[6];
|
||||
uint8_t xdout[16];
|
||||
uint8_t cdout[8];
|
||||
|
||||
*net_valid = true;
|
||||
|
||||
// Use RAND and K to compute RES, CK, IK and AK
|
||||
for(i=0; i<16; i++) {
|
||||
xdout[i] = k[i]^rand[i];
|
||||
}
|
||||
for(i=0; i<16; i++) {
|
||||
res[i] = xdout[i];
|
||||
ck[i] = xdout[(i+1)%16];
|
||||
ik[i] = xdout[(i+2)%16];
|
||||
}
|
||||
for(i=0; i<6; i++) {
|
||||
ak[i] = xdout[i+3];
|
||||
}
|
||||
|
||||
// Extract sqn from autn
|
||||
for(i=0;i<6;i++) {
|
||||
sqn[i] = autn_enb[i] ^ ak[i];
|
||||
}
|
||||
|
||||
// Generate cdout
|
||||
for(i=0; i<6; i++) {
|
||||
cdout[i] = sqn[i];
|
||||
}
|
||||
for(i=0; i<2; i++) {
|
||||
cdout[6+i] = amf[i];
|
||||
}
|
||||
|
||||
// Generate MAC
|
||||
for(i=0;i<8;i++) {
|
||||
mac[i] = xdout[i] ^ cdout[i];
|
||||
}
|
||||
|
||||
// Construct AUTN
|
||||
for(i=0; i<6; i++)
|
||||
{
|
||||
autn[i] = sqn[i] ^ ak[i];
|
||||
}
|
||||
for(i=0; i<2; i++)
|
||||
{
|
||||
autn[6+i] = amf[i];
|
||||
}
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
autn[8+i] = mac[i];
|
||||
}
|
||||
|
||||
// Compare AUTNs
|
||||
for(i=0; i<16; i++)
|
||||
{
|
||||
if(autn[i] != autn_enb[i])
|
||||
{
|
||||
*net_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate K_asme
|
||||
security_generate_k_asme( ck,
|
||||
ik,
|
||||
ak,
|
||||
sqn,
|
||||
mcc,
|
||||
mnc,
|
||||
k_asme);
|
||||
}
|
||||
|
||||
void usim::str_to_hex(std::string str, uint8_t *hex)
|
||||
{
|
||||
uint32_t i;
|
||||
const char *h_str = str.c_str();
|
||||
uint32_t len = str.length();
|
||||
|
||||
for(i=0; i<len/2; i++)
|
||||
{
|
||||
if(h_str[i*2+0] >= '0' && h_str[i*2+0] <= '9')
|
||||
{
|
||||
hex[i] = ( h_str[i*2+0] - '0') << 4;
|
||||
}else if( h_str[i*2+0] >= 'A' && h_str[i*2+0] <= 'F'){
|
||||
hex[i] = (( h_str[i*2+0] - 'A') + 0xA) << 4;
|
||||
}else{
|
||||
hex[i] = (( h_str[i*2+0] - 'a') + 0xA) << 4;
|
||||
}
|
||||
|
||||
if( h_str[i*2+1] >= '0' && h_str[i*2+1] <= '9')
|
||||
{
|
||||
hex[i] |= h_str[i*2+1] - '0';
|
||||
}else if( h_str[i*2+1] >= 'A' && h_str[i*2+1] <= 'F'){
|
||||
hex[i] |= ( h_str[i*2+1] - 'A') + 0xA;
|
||||
}else{
|
||||
hex[i] |= ( h_str[i*2+1] - 'a') + 0xA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace srsue
|
@ -0,0 +1,56 @@
|
||||
# Copyright 2015 Software Radio Systems Limited
|
||||
#
|
||||
# This file is part of srsUE
|
||||
#
|
||||
# srsUE is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# srsUE is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# A copy of the GNU Affero General Public License can be found in
|
||||
# the LICENSE file in the top-level directory of this distribution
|
||||
# and at http://www.gnu.org/licenses/.
|
||||
#
|
||||
|
||||
add_executable(rlc_am_data_test rlc_am_data_test.cc)
|
||||
target_link_libraries(rlc_am_data_test srslte_upper srslte_phy lte)
|
||||
add_test(rlc_am_data_test rlc_am_data_test)
|
||||
|
||||
add_executable(rlc_am_control_test rlc_am_control_test.cc)
|
||||
target_link_libraries(rlc_am_control_test srslte_upper srslte_phy lte)
|
||||
add_test(rlc_am_control_test rlc_am_control_test)
|
||||
|
||||
add_executable(rlc_am_test rlc_am_test.cc)
|
||||
target_link_libraries(rlc_am_test srslte_upper srslte_phy lte)
|
||||
add_test(rlc_am_test rlc_am_test)
|
||||
|
||||
add_executable(rlc_um_data_test rlc_um_data_test.cc)
|
||||
target_link_libraries(rlc_um_data_test srslte_upper srslte_phy lte)
|
||||
add_test(rlc_um_data_test rlc_um_data_test)
|
||||
|
||||
add_executable(rlc_um_test rlc_um_test.cc)
|
||||
target_link_libraries(rlc_um_test srslte_upper srslte_phy lte)
|
||||
add_test(rlc_um_test rlc_um_test)
|
||||
|
||||
add_executable(usim_test usim_test.cc)
|
||||
target_link_libraries(usim_test srslte_upper srslte_phy lte)
|
||||
add_test(usim_test usim_test)
|
||||
|
||||
add_executable(rrc_reconfig_test rrc_reconfig_test.cc)
|
||||
target_link_libraries(rrc_reconfig_test srslte_upper srslte_phy lte)
|
||||
add_test(rrc_reconfig_test rrc_reconfig_test)
|
||||
|
||||
########################################################################
|
||||
# Option to run command after build (useful for remote builds)
|
||||
########################################################################
|
||||
if (NOT ${BUILD_CMD} STREQUAL "")
|
||||
message(STATUS "Added custom post-build command: ${BUILD_CMD}")
|
||||
add_custom_command(TARGET ip_test POST_BUILD COMMAND ${BUILD_CMD})
|
||||
else(NOT ${BUILD_CMD} STREQUAL "")
|
||||
message(STATUS "No post-build command defined")
|
||||
endif (NOT ${BUILD_CMD} STREQUAL "")
|
@ -0,0 +1,183 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "upper/usim.h"
|
||||
#include "upper/nas.h"
|
||||
#include "upper/rlc.h"
|
||||
#include "upper/rrc.h"
|
||||
#include "mac/mac.h"
|
||||
#include "upper/pdcp_entity.h"
|
||||
#include "upper/pdcp.h"
|
||||
#include "common/log_stdout.h"
|
||||
#include "common/interfaces.h"
|
||||
|
||||
using namespace srsue;
|
||||
|
||||
|
||||
|
||||
uint8_t pdu1[] = {
|
||||
0x03, 0x22, 0x16, 0x15, 0xe8 , 0x00 , 0x00 , 0x03 , 0x13 , 0xb0 , 0x00 , 0x02 , 0x90 , 0x08,
|
||||
0x79, 0xf0, 0x00, 0x00, 0x40 , 0xb5 , 0x01 , 0x25 , 0x40 , 0xcc , 0x1d , 0x08 , 0x04 , 0x3c , 0x18 , 0x00,
|
||||
0x4c, 0x02, 0x20, 0x0f, 0xa8 , 0x00 , 0x65 , 0x48 , 0x07 , 0x04 , 0x04 , 0x24 , 0x1c , 0x19 , 0x05 , 0x41,
|
||||
0x39, 0x39, 0x4d, 0x38, 0x14 , 0x04 , 0x28 , 0xd1 , 0x5e , 0x6d , 0x78 , 0x13 , 0xfb , 0xf9 , 0x01 , 0xb1,
|
||||
0x40, 0x2f, 0xd8, 0x4c, 0x02 , 0x20 , 0x00 , 0x5b , 0x78 , 0x00 , 0x07 , 0xa1 , 0x25 , 0xa9 , 0xc1 , 0x3f,
|
||||
0xd9, 0x40, 0x41, 0xf5, 0x1b , 0x58 , 0x2f , 0x27 , 0x28 , 0xa0 , 0xed , 0xde , 0x54 , 0x43 , 0x48 , 0xc0,
|
||||
0x56, 0xcc, 0x00, 0x02, 0x84 , 0x00 , 0x42 , 0x0a , 0xf1 , 0x63 };
|
||||
|
||||
uint32_t PDU1_LEN = 104;
|
||||
|
||||
|
||||
#define LCID 3
|
||||
|
||||
namespace srsue {
|
||||
|
||||
// fake classes
|
||||
class pdcp_dummy : public rrc_interface_pdcp
|
||||
{
|
||||
public:
|
||||
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) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class rrc_dummy : public rrc_interface_nas
|
||||
{
|
||||
public:
|
||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint16_t get_mcc() { return 0x11; }
|
||||
uint16_t get_mnc() { return 0xff; }
|
||||
void enable_capabilities() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class gw_dummy : public gw_interface_nas, public gw_interface_pdcp
|
||||
{
|
||||
error_t setup_if_addr(uint32_t ip_addr, char *err_str) {}
|
||||
void write_pdu(uint32_t lcid, byte_buffer_t *pdu) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class usim_dummy : public usim_interface_nas
|
||||
{
|
||||
void get_imsi_vec(uint8_t* imsi_, uint32_t n){
|
||||
|
||||
}
|
||||
void get_imei_vec(uint8_t* imei_, uint32_t n){
|
||||
|
||||
}
|
||||
void generate_authentication_response(uint8_t *rand,
|
||||
uint8_t *autn_enb,
|
||||
uint16_t mcc,
|
||||
uint16_t mnc,
|
||||
bool *net_valid,
|
||||
uint8_t *res){
|
||||
|
||||
}
|
||||
|
||||
|
||||
void generate_nas_keys(uint8_t *k_nas_enc,
|
||||
uint8_t *k_nas_int,
|
||||
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
||||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo){
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
srslte::log_stdout nas_log("NAS");
|
||||
srslte::log_stdout pdcp_entity_log("PDCP");
|
||||
srslte::log_stdout rrc_log("RRC");
|
||||
srslte::log_stdout mac_log("MAC");
|
||||
|
||||
|
||||
nas_log.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
pdcp_entity_log.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
rrc_log.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
|
||||
nas_log.set_hex_limit(100000);
|
||||
rrc_log.set_hex_limit(100000);
|
||||
|
||||
usim_dummy usim;
|
||||
rrc_dummy rrc_dummy;
|
||||
gw_dummy gw;
|
||||
|
||||
pdcp_dummy pdcp_dummy;
|
||||
|
||||
|
||||
|
||||
|
||||
buffer_pool *pool;
|
||||
pool = buffer_pool::get_instance();
|
||||
|
||||
srsue::nas nas;
|
||||
nas.init(&usim, &rrc_dummy, &gw, &nas_log);
|
||||
|
||||
|
||||
|
||||
|
||||
byte_buffer_t* tmp = pool->allocate();
|
||||
memcpy(tmp->msg, &pdu1[0], PDU1_LEN);
|
||||
tmp->N_bytes = PDU1_LEN;
|
||||
|
||||
//byte_buffer_t tmp2;
|
||||
//memcpy(tmp2.msg, &pdu1[0], PDU1_LEN);
|
||||
//tmp2.N_bytes = PDU1_LEN;
|
||||
|
||||
//srsue::mac mac;
|
||||
//mac.init(NULL, NULL, NULL, &mac_log);
|
||||
|
||||
srsue::rrc rrc;
|
||||
rrc.init(NULL, NULL, NULL, NULL, &nas, NULL, NULL, &rrc_log);
|
||||
//rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log);
|
||||
|
||||
|
||||
srsue::pdcp_entity pdcp_entity;
|
||||
pdcp_entity.init(NULL, &rrc, &gw, &pdcp_entity_log, RB_ID_SRB1, NULL);
|
||||
|
||||
pdcp_entity.write_pdu(tmp);
|
||||
|
||||
//rrc.write_sdu(RB_ID_SRB2, tmp);
|
||||
|
||||
|
||||
//nas.write_pdu(LCID, tmp);
|
||||
|
||||
pool->cleanup();
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include "upper/rlc_am.h"
|
||||
|
||||
// Simple status PDU
|
||||
uint8_t pdu1[] = {0x00, 0x78};
|
||||
uint32_t PDU1_LEN = 2;
|
||||
|
||||
// Status PDU with 4 NACKs
|
||||
uint8_t pdu2[] = {0x00 ,0x22 ,0x00 ,0x40 ,0x0C ,0x01 ,0xC0 ,0x20};
|
||||
uint32_t PDU2_LEN = 8;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
srsue::rlc_status_pdu_t s;
|
||||
srslte::byte_buffer_t b1,b2;
|
||||
|
||||
memcpy(b1.msg, &pdu1[0], PDU1_LEN);
|
||||
b1.N_bytes = PDU1_LEN;
|
||||
rlc_am_read_status_pdu(&b1, &s);
|
||||
assert(s.ack_sn == 30);
|
||||
assert(s.N_nack == 0);
|
||||
rlc_am_write_status_pdu(&s, &b2);
|
||||
assert(b2.N_bytes == PDU1_LEN);
|
||||
for(int i=0;i<b2.N_bytes;i++)
|
||||
assert(b2.msg[i] == b1.msg[i]);
|
||||
|
||||
b1.reset();
|
||||
b2.reset();
|
||||
memset(&s, 0, sizeof(srsue::rlc_status_pdu_t));
|
||||
|
||||
memcpy(b1.msg, &pdu2[0], PDU2_LEN);
|
||||
b1.N_bytes = PDU2_LEN;
|
||||
rlc_am_read_status_pdu(&b1, &s);
|
||||
assert(s.ack_sn == 8);
|
||||
assert(s.N_nack == 4);
|
||||
assert(s.nacks[0].nack_sn == 0);
|
||||
assert(s.nacks[1].nack_sn == 1);
|
||||
assert(s.nacks[2].nack_sn == 3);
|
||||
assert(s.nacks[3].nack_sn == 4);
|
||||
rlc_am_write_status_pdu(&s, &b2);
|
||||
assert(b2.N_bytes == PDU2_LEN);
|
||||
for(int i=0;i<b2.N_bytes;i++)
|
||||
assert(b2.msg[i] == b1.msg[i]);
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include "upper/rlc_am.h"
|
||||
|
||||
// Fixed header only
|
||||
uint8_t pdu1[] = {0x88, 0x06};
|
||||
uint32_t PDU1_LEN = 2;
|
||||
|
||||
// Fixed + 2 LI fields (each 1500)
|
||||
uint8_t pdu2[] = {0x8C, 0x00, 0xDD, 0xC5, 0xDC};
|
||||
uint32_t PDU2_LEN = 5;
|
||||
|
||||
// Fixed + 3 LI fields (each 1500)
|
||||
uint8_t pdu3[] = {0x8C, 0x00, 0xDD, 0xCD, 0xDC, 0x5D, 0xC0};
|
||||
uint32_t PDU3_LEN = 7;
|
||||
|
||||
using namespace srsue;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
rlc_amd_pdu_header_t h;
|
||||
byte_buffer_t b1,b2;
|
||||
|
||||
memcpy(b1.msg, &pdu1[0], PDU1_LEN);
|
||||
b1.N_bytes = PDU1_LEN;
|
||||
rlc_am_read_data_pdu_header(&b1, &h);
|
||||
assert(RLC_DC_FIELD_DATA_PDU == h.dc);
|
||||
assert(0x01 == h.fi);
|
||||
assert(0 == h.N_li);
|
||||
assert(0 == h.lsf);
|
||||
assert(0 == h.p);
|
||||
assert(0 == h.rf);
|
||||
assert(0 == h.so);
|
||||
assert(6 == h.sn);
|
||||
rlc_am_write_data_pdu_header(&h, &b2);
|
||||
assert(b2.N_bytes == PDU1_LEN);
|
||||
for(int i=0;i<b2.N_bytes;i++)
|
||||
assert(b2.msg[i] == b1.msg[i]);
|
||||
|
||||
b1.reset();
|
||||
b2.reset();
|
||||
memset(&h, 0, sizeof(rlc_amd_pdu_header_t));
|
||||
|
||||
memcpy(b1.msg, &pdu2[0], PDU2_LEN);
|
||||
b1.N_bytes = PDU2_LEN;
|
||||
rlc_am_read_data_pdu_header(&b1, &h);
|
||||
assert(RLC_DC_FIELD_DATA_PDU == h.dc);
|
||||
assert(0x01 == h.fi);
|
||||
assert(2 == h.N_li);
|
||||
assert(1500 == h.li[0]);
|
||||
assert(1500 == h.li[1]);
|
||||
assert(0 == h.lsf);
|
||||
assert(0 == h.p);
|
||||
assert(0 == h.rf);
|
||||
assert(0 == h.so);
|
||||
assert(0 == h.sn);
|
||||
rlc_am_write_data_pdu_header(&h, &b2);
|
||||
assert(b2.N_bytes == PDU2_LEN);
|
||||
for(int i=0;i<b2.N_bytes;i++)
|
||||
assert(b2.msg[i] == b1.msg[i]);
|
||||
|
||||
b1.reset();
|
||||
b2.reset();
|
||||
memset(&h, 0, sizeof(rlc_amd_pdu_header_t));
|
||||
|
||||
memcpy(b1.msg, &pdu3[0], PDU3_LEN);
|
||||
b1.N_bytes = PDU3_LEN;
|
||||
rlc_am_read_data_pdu_header(&b1, &h);
|
||||
assert(RLC_DC_FIELD_DATA_PDU == h.dc);
|
||||
assert(0x01 == h.fi);
|
||||
assert(3 == h.N_li);
|
||||
assert(1500 == h.li[0]);
|
||||
assert(1500 == h.li[1]);
|
||||
assert(1500 == h.li[2]);
|
||||
assert(0 == h.lsf);
|
||||
assert(0 == h.p);
|
||||
assert(0 == h.rf);
|
||||
assert(0 == h.so);
|
||||
assert(0 == h.sn);
|
||||
rlc_am_write_data_pdu_header(&h, &b2);
|
||||
assert(b2.N_bytes == PDU3_LEN);
|
||||
for(int i=0;i<b2.N_bytes;i++)
|
||||
assert(b2.msg[i] == b1.msg[i]);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "upper/rlc_um.h"
|
||||
#include <assert.h>
|
||||
|
||||
// Fixed header only
|
||||
uint8_t pdu1[] = {0x18 ,0xE2};
|
||||
uint32_t PDU1_LEN = 2;
|
||||
|
||||
// Fixed + 1 LI field (value 104)
|
||||
uint8_t pdu2[] = {0x1C ,0xE1 ,0x06 ,0x80};
|
||||
uint32_t PDU2_LEN = 4;
|
||||
|
||||
using namespace srsue;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
rlc_umd_pdu_header_t h;
|
||||
srslte::byte_buffer_t b1,b2;
|
||||
|
||||
memcpy(b1.msg, &pdu1[0], PDU1_LEN);
|
||||
b1.N_bytes = PDU1_LEN;
|
||||
rlc_um_read_data_pdu_header(&b1, RLC_UMD_SN_SIZE_10_BITS, &h);
|
||||
assert(0x03 == h.fi);
|
||||
assert(0 == h.N_li);
|
||||
assert(226 == h.sn);
|
||||
rlc_um_write_data_pdu_header(&h, &b2);
|
||||
assert(b2.N_bytes == PDU1_LEN);
|
||||
for(int i=0;i<b2.N_bytes;i++)
|
||||
assert(b2.msg[i] == b1.msg[i]);
|
||||
|
||||
b1.reset();
|
||||
b2.reset();
|
||||
memset(&h, 0, sizeof(rlc_umd_pdu_header_t));
|
||||
|
||||
memcpy(b1.msg, &pdu2[0], PDU2_LEN);
|
||||
b1.N_bytes = PDU2_LEN;
|
||||
rlc_um_read_data_pdu_header(&b1, RLC_UMD_SN_SIZE_10_BITS, &h);
|
||||
assert(0x03 == h.fi);
|
||||
assert(225 == h.sn);
|
||||
assert(1 == h.N_li);
|
||||
assert(104 == h.li[0]);
|
||||
rlc_um_write_data_pdu_header(&h, &b2);
|
||||
assert(b2.N_bytes == PDU2_LEN);
|
||||
for(int i=0;i<b2.N_bytes;i++)
|
||||
assert(b2.msg[i] == b1.msg[i]);
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "common/log_stdout.h"
|
||||
#include "upper/rlc_um.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define NBUFS 5
|
||||
|
||||
using namespace srslte;
|
||||
using namespace srsue;
|
||||
|
||||
class mac_dummy_timers
|
||||
:public srslte::mac_interface_timers
|
||||
{
|
||||
public:
|
||||
srslte::timers::timer* get(uint32_t timer_id)
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
uint32_t get_unique_id(){return 0;}
|
||||
void step()
|
||||
{
|
||||
t.step();
|
||||
}
|
||||
|
||||
private:
|
||||
srslte::timers::timer t;
|
||||
};
|
||||
|
||||
class rlc_um_tester
|
||||
:public pdcp_interface_rlc
|
||||
,public rrc_interface_rlc
|
||||
{
|
||||
public:
|
||||
rlc_um_tester(){n_sdus = 0;}
|
||||
|
||||
// PDCP interface
|
||||
void write_pdu(uint32_t lcid, byte_buffer_t *sdu)
|
||||
{
|
||||
assert(lcid == 3);
|
||||
sdus[n_sdus++] = sdu;
|
||||
}
|
||||
void write_pdu_bcch_bch(byte_buffer_t *sdu) {}
|
||||
void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {}
|
||||
void write_pdu_pcch(byte_buffer_t *sdu) {}
|
||||
|
||||
// RRC interface
|
||||
void max_retx_attempted(){}
|
||||
|
||||
byte_buffer_t *sdus[5];
|
||||
int n_sdus;
|
||||
};
|
||||
|
||||
void basic_test()
|
||||
{
|
||||
srslte::log_stdout log1("RLC_UM_1");
|
||||
srslte::log_stdout log2("RLC_UM_2");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log2.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(-1);
|
||||
log2.set_hex_limit(-1);
|
||||
rlc_um_tester tester;
|
||||
mac_dummy_timers timers;
|
||||
|
||||
rlc_um rlc1;
|
||||
rlc_um rlc2;
|
||||
|
||||
int len;
|
||||
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log2.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
|
||||
rlc1.init(&log1, 3, &tester, &tester, &timers);
|
||||
rlc2.init(&log2, 3, &tester, &tester, &timers);
|
||||
|
||||
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
|
||||
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI;
|
||||
cnfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5;
|
||||
cnfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
|
||||
cnfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
|
||||
|
||||
rlc1.configure(&cnfg);
|
||||
rlc2.configure(&cnfg);
|
||||
|
||||
// Push 5 SDUs into RLC1
|
||||
byte_buffer_t sdu_bufs[NBUFS];
|
||||
for(int i=0;i<NBUFS;i++)
|
||||
{
|
||||
*sdu_bufs[i].msg = i; // Write the index into the buffer
|
||||
sdu_bufs[i].N_bytes = 1; // Give each buffer a size of 1 byte
|
||||
rlc1.write_sdu(&sdu_bufs[i]);
|
||||
}
|
||||
|
||||
assert(13 == rlc1.get_buffer_state());
|
||||
|
||||
// Read 5 PDUs from RLC1 (1 byte each)
|
||||
byte_buffer_t pdu_bufs[NBUFS];
|
||||
for(int i=0;i<NBUFS;i++)
|
||||
{
|
||||
len = rlc1.read_pdu(pdu_bufs[i].msg, 3); // 3 bytes for header + payload
|
||||
pdu_bufs[i].N_bytes = len;
|
||||
}
|
||||
|
||||
assert(0 == rlc1.get_buffer_state());
|
||||
|
||||
// Write 5 PDUs into RLC2
|
||||
for(int i=0;i<NBUFS;i++)
|
||||
{
|
||||
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
|
||||
}
|
||||
|
||||
assert(0 == rlc2.get_buffer_state());
|
||||
|
||||
assert(NBUFS == tester.n_sdus);
|
||||
for(int i=0; i<tester.n_sdus; i++)
|
||||
{
|
||||
assert(tester.sdus[i]->N_bytes == 1);
|
||||
assert(*(tester.sdus[i]->msg) == i);
|
||||
}
|
||||
}
|
||||
|
||||
void loss_test()
|
||||
{
|
||||
srslte::log_stdout log1("RLC_UM_1");
|
||||
srslte::log_stdout log2("RLC_UM_2");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log2.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(-1);
|
||||
log2.set_hex_limit(-1);
|
||||
rlc_um_tester tester;
|
||||
mac_dummy_timers timers;
|
||||
|
||||
rlc_um rlc1;
|
||||
rlc_um rlc2;
|
||||
|
||||
int len;
|
||||
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log2.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
|
||||
rlc1.init(&log1, 3, &tester, &tester, &timers);
|
||||
rlc2.init(&log2, 3, &tester, &tester, &timers);
|
||||
|
||||
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
|
||||
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI;
|
||||
cnfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5;
|
||||
cnfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
|
||||
cnfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
|
||||
|
||||
rlc1.configure(&cnfg);
|
||||
rlc2.configure(&cnfg);
|
||||
|
||||
// Push 5 SDUs into RLC1
|
||||
byte_buffer_t sdu_bufs[NBUFS];
|
||||
for(int i=0;i<NBUFS;i++)
|
||||
{
|
||||
*sdu_bufs[i].msg = i; // Write the index into the buffer
|
||||
sdu_bufs[i].N_bytes = 1; // Give each buffer a size of 1 byte
|
||||
rlc1.write_sdu(&sdu_bufs[i]);
|
||||
}
|
||||
|
||||
assert(13 == rlc1.get_buffer_state());
|
||||
|
||||
// Read 5 PDUs from RLC1 (1 byte each)
|
||||
byte_buffer_t pdu_bufs[NBUFS];
|
||||
for(int i=0;i<NBUFS;i++)
|
||||
{
|
||||
len = rlc1.read_pdu(pdu_bufs[i].msg, 3); // 3 bytes for header + payload
|
||||
pdu_bufs[i].N_bytes = len;
|
||||
}
|
||||
|
||||
assert(0 == rlc1.get_buffer_state());
|
||||
|
||||
// Write 5 PDUs into RLC2 (skip SN 1)
|
||||
for(int i=0;i<NBUFS;i++)
|
||||
{
|
||||
if(i != 1)
|
||||
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
|
||||
}
|
||||
|
||||
// Step the reordering timer until expiry
|
||||
while(!timers.get(1)->is_expired())
|
||||
timers.get(1)->step();
|
||||
|
||||
assert(NBUFS-1 == tester.n_sdus);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
basic_test();
|
||||
byte_buffer_pool::get_instance()->cleanup();
|
||||
loss_test();
|
||||
byte_buffer_pool::get_instance()->cleanup();
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <srslte/srslte.h>
|
||||
#include "common/log_stdout.h"
|
||||
#include "liblte_rrc.h"
|
||||
#include "liblte_mme.h"
|
||||
|
||||
void nas_test() {
|
||||
srslte::log_stdout log1("NAS");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(-1);
|
||||
|
||||
uint32_t nas_message_len = 73;
|
||||
uint8_t nas_message[128] = {0x27, 0x4f, 0xab, 0xef, 0x59, 0x01, 0x07, 0x42,
|
||||
0x01, 0x49, 0x06, 0x40, 0x00, 0xf1, 0x10, 0x31,
|
||||
0x32, 0x00, 0x22, 0x52, 0x01, 0xc1, 0x05, 0x07,
|
||||
0xff, 0xff, 0xff, 0xff, 0x0c, 0x0b, 0x76, 0x7a,
|
||||
0x77, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
|
||||
0x74, 0x05, 0x01, 0x0e, 0x0e, 0x0e, 0x01, 0x5e,
|
||||
0x04, 0xfe, 0xfe, 0x81, 0x4e, 0x50, 0x0b, 0xf6,
|
||||
0x00, 0xf1, 0x10, 0x00, 0x02, 0x01, 0x01, 0x00,
|
||||
0x00, 0x62, 0x17, 0x2c, 0x59, 0x49, 0x64, 0x01,
|
||||
0x03};
|
||||
|
||||
uint8 pd;
|
||||
uint8 msg_type;
|
||||
LIBLTE_BYTE_MSG_STRUCT buf;
|
||||
LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept;
|
||||
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req;
|
||||
|
||||
memcpy(buf.msg, nas_message, nas_message_len);
|
||||
buf.N_bytes = nas_message_len;
|
||||
liblte_mme_parse_msg_header(&buf, &pd, &msg_type);
|
||||
switch(msg_type)
|
||||
{
|
||||
case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT:
|
||||
liblte_mme_unpack_attach_accept_msg(&buf, &attach_accept);
|
||||
liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req);
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_ATTACH_REJECT:
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST:
|
||||
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT:
|
||||
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST:
|
||||
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND:
|
||||
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_SERVICE_REJECT:
|
||||
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST:
|
||||
|
||||
break;
|
||||
case LIBLTE_MME_MSG_TYPE_EMM_INFORMATION:
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void basic_test() {
|
||||
srslte::log_stdout log1("RRC");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(-1);
|
||||
|
||||
LIBLTE_BIT_MSG_STRUCT bit_buf;
|
||||
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
|
||||
|
||||
uint32_t rrc_message_len = 147;
|
||||
uint8_t rrc_message[256] = {0x22, 0x16, 0x95, 0xa0, 0x18, 0x00, 0x05, 0xaa,
|
||||
0x50, 0x36, 0x00, 0x61, 0x08, 0x9c, 0xe3, 0x40,
|
||||
0xb0, 0x84, 0x4e, 0x71, 0xc0, 0x30, 0x84, 0x6e,
|
||||
0x71, 0xe0, 0x70, 0x84, 0x6e, 0x70, 0x6c, 0x63,
|
||||
0x1a, 0xc6, 0xb9, 0x8e, 0x7b, 0x1e, 0x84, 0xc0,
|
||||
0x01, 0x24, 0x9d, 0x3e, 0xaf, 0xbd, 0x64, 0x04,
|
||||
0x1d, 0x08, 0x05, 0x24, 0x19, 0x00, 0x03, 0xc4,
|
||||
0x40, 0xc4, 0xc8, 0x00, 0x89, 0x48, 0x07, 0x04,
|
||||
0x14, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x30, 0x2d,
|
||||
0xd9, 0xe9, 0xdd, 0xa5, 0xb9, 0xd1, 0x95, 0xc9,
|
||||
0xb9, 0x95, 0xd0, 0x14, 0x04, 0x38, 0x38, 0x38,
|
||||
0x05, 0x78, 0x13, 0xfb, 0xfa, 0x05, 0x39, 0x40,
|
||||
0x2f, 0xd8, 0x03, 0xc4, 0x40, 0x00, 0x08, 0x04,
|
||||
0x04, 0x00, 0x01, 0x88, 0x5c, 0xb1, 0x65, 0x25,
|
||||
0x90, 0x04, 0x0d, 0xa9, 0xc0, 0x2a, 0x9a, 0x01,
|
||||
0x99, 0x3b, 0x01, 0xf5, 0x12, 0xf0, 0x85, 0x0d,
|
||||
0x85, 0xef, 0xc0, 0x01, 0xf2, 0x20, 0x60, 0x18,
|
||||
0x07, 0x97, 0x09, 0x1f, 0xc3, 0x06, 0x00, 0x81,
|
||||
0x00, 0x00, 0x11};
|
||||
|
||||
srslte_bit_unpack_vector(rrc_message, bit_buf.msg, rrc_message_len*8);
|
||||
bit_buf.N_bits = rrc_message_len*8;
|
||||
liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_dcch_msg);
|
||||
|
||||
printf("done\n");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
basic_test();
|
||||
nas_test();
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsUE library.
|
||||
*
|
||||
* srsUE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsUE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "upper/usim.h"
|
||||
#include "common/log_stdout.h"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace srsue;
|
||||
|
||||
/*
|
||||
Debug output generated from the OpenAirInterface HSS:
|
||||
|
||||
Converted 02f839 to plmn 208.93
|
||||
Query: SELECT `key`,`sqn`,`rand`,`OPc` FROM `users` WHERE `users`.`imsi`='208930000000001'
|
||||
Key: 8b.af.47.3f.2f.8f.d0.94.87.cc.cb.d7.09.7c.68.62.
|
||||
Received SQN 00000000000000006999 converted to 6999
|
||||
SQN: 00.00.00.00.1b.57.
|
||||
RAND: 7c.f6.e2.6b.20.0a.ca.27.a1.a0.91.40.f5.cf.9d.62.
|
||||
OPc: 8e.27.b6.af.0e.69.2e.75.0f.32.66.7a.3b.14.60.5d.
|
||||
Generated random
|
||||
RijndaelKeySchedule: K 8BAF473F2F8FD09487CCCBD7097C6862
|
||||
MAC_A : 84.ba.37.b0.f6.73.4d.d1.
|
||||
SQN : 00.00.00.00.1b.57.
|
||||
RAND : 88.38.c3.55.c8.78.aa.57.21.49.fe.69.db.68.6b.5a.
|
||||
RijndaelKeySchedule: K 8BAF473F2F8FD09487CCCBD7097C6862
|
||||
AK : d7.44.51.9b.3e.fd.
|
||||
CK : 05.d3.53.3d.fe.7b.e7.2d.42.c7.bb.02.f2.8e.da.7f.
|
||||
IK : 26.33.a2.0b.dc.a8.9d.78.58.ba.42.47.8b.e4.d2.4d.
|
||||
XRES : e5.5d.88.27.91.8d.ac.c6.
|
||||
AUTN : d7.44.51.9b.25.aa.80.00.84.ba.37.b0.f6.73.4d.d1.
|
||||
0x05 0xd3 0x53 0x3d 0xfe 0x7b 0xe7 0x2d 0x42 0xc7 0xbb 0x02 0xf2 0x8e
|
||||
0xda 0x7f 0x26 0x33 0xa2 0x0b 0xdc 0xa8 0x9d 0x78 0x58 0xba 0x42 0x47
|
||||
0x8b 0xe4 0xd2 0x4d 0x10 0x02 0xf8 0x39 0x00 0x03 0xd7 0x44 0x51 0x9b
|
||||
0x25 0xaa 0x00 0x06
|
||||
KASME : a8.27.57.5e.ea.1a.10.17.3a.a1.bf.ce.4b.0c.21.85.e0.51.ef.bd.91.7f.fe.f5.1f.74.29.61.f9.03.7a.35.
|
||||
*/
|
||||
|
||||
uint8_t rand_enb[] = {0x88, 0x38, 0xc3, 0x55, 0xc8, 0x78, 0xaa, 0x57, 0x21, 0x49, 0xfe, 0x69, 0xdb, 0x68, 0x6b, 0x5a};
|
||||
uint8_t autn_enb[] = {0xd7, 0x44, 0x51, 0x9b, 0x25, 0xaa, 0x80, 0x00, 0x84, 0xba, 0x37, 0xb0, 0xf6, 0x73, 0x4d, 0xd1};
|
||||
|
||||
uint16 mcc = 208;
|
||||
uint16 mnc = 93;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
srslte::log_stdout usim_log("USIM");
|
||||
bool net_valid;
|
||||
uint8_t res[16];
|
||||
|
||||
usim_args_t args;
|
||||
args.algo = "milenage";
|
||||
args.amf = "8000";
|
||||
args.imei = "35609204079301";
|
||||
args.imsi = "208930000000001";
|
||||
args.k = "8BAF473F2F8FD09487CCCBD7097C6862";
|
||||
args.op = "11111111111111111111111111111111";
|
||||
|
||||
srsue::usim usim;
|
||||
usim.init(&args, &usim_log);
|
||||
usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res);
|
||||
|
||||
assert(net_valid == true);
|
||||
}
|
Loading…
Reference in New Issue