mirror of https://github.com/PentHertz/srsLTE.git
Merge pull request #109 from softwareradiosystems/guti_attach
Guti attach
This commit is contained in:
commit
8a09454d7c
|
@ -2721,6 +2721,10 @@ typedef struct{
|
||||||
// Functions
|
// Functions
|
||||||
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
|
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
|
||||||
LIBLTE_BYTE_MSG_STRUCT *msg);
|
LIBLTE_BYTE_MSG_STRUCT *msg);
|
||||||
|
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
|
||||||
|
uint8 sec_hdr_type,
|
||||||
|
uint32 count,
|
||||||
|
LIBLTE_BYTE_MSG_STRUCT *msg);
|
||||||
LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
|
LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
|
||||||
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req);
|
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req);
|
||||||
|
|
||||||
|
|
|
@ -52,16 +52,20 @@ class ue_interface
|
||||||
class usim_interface_nas
|
class usim_interface_nas
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
|
virtual std::string get_imsi_str() = 0;
|
||||||
virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
|
virtual std::string get_imei_str() = 0;
|
||||||
virtual int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0;
|
virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
|
||||||
|
virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
|
||||||
|
virtual bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0;
|
||||||
virtual void generate_authentication_response(uint8_t *rand,
|
virtual void generate_authentication_response(uint8_t *rand,
|
||||||
uint8_t *autn_enb,
|
uint8_t *autn_enb,
|
||||||
uint16_t mcc,
|
uint16_t mcc,
|
||||||
uint16_t mnc,
|
uint16_t mnc,
|
||||||
bool *net_valid,
|
bool *net_valid,
|
||||||
uint8_t *res) = 0;
|
uint8_t *res,
|
||||||
virtual void generate_nas_keys(uint8_t *k_nas_enc,
|
uint8_t *k_asme) = 0;
|
||||||
|
virtual void generate_nas_keys(uint8_t *k_asme,
|
||||||
|
uint8_t *k_nas_enc,
|
||||||
uint8_t *k_nas_int,
|
uint8_t *k_nas_int,
|
||||||
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
||||||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
|
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
|
||||||
|
@ -71,7 +75,8 @@ public:
|
||||||
class usim_interface_rrc
|
class usim_interface_rrc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void generate_as_keys(uint32_t count_ul,
|
virtual void generate_as_keys(uint8_t *k_asme,
|
||||||
|
uint32_t count_ul,
|
||||||
uint8_t *k_rrc_enc,
|
uint8_t *k_rrc_enc,
|
||||||
uint8_t *k_rrc_int,
|
uint8_t *k_rrc_int,
|
||||||
uint8_t *k_up_enc,
|
uint8_t *k_up_enc,
|
||||||
|
@ -104,6 +109,7 @@ public:
|
||||||
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
|
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
|
||||||
virtual uint32_t get_ul_count() = 0;
|
virtual uint32_t get_ul_count() = 0;
|
||||||
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
|
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
|
||||||
|
virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0;
|
||||||
virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
|
virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
|
||||||
virtual void plmn_search_end() = 0;
|
virtual void plmn_search_end() = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1411,9 +1411,9 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_mobile_id_ie(LIBLTE_MME_EPS_MOBILE_ID_STRU
|
||||||
**ie_ptr = (((eps_mobile_id->guti.mnc/10) % 10) << 4) | ((eps_mobile_id->guti.mnc/100) % 10);
|
**ie_ptr = (((eps_mobile_id->guti.mnc/10) % 10) << 4) | ((eps_mobile_id->guti.mnc/100) % 10);
|
||||||
*ie_ptr += 1;
|
*ie_ptr += 1;
|
||||||
}
|
}
|
||||||
**ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0x0F;
|
**ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0xFF;
|
||||||
*ie_ptr += 1;
|
*ie_ptr += 1;
|
||||||
**ie_ptr = eps_mobile_id->guti.mme_group_id & 0x0F;
|
**ie_ptr = eps_mobile_id->guti.mme_group_id & 0xFF;
|
||||||
*ie_ptr += 1;
|
*ie_ptr += 1;
|
||||||
**ie_ptr = eps_mobile_id->guti.mme_code;
|
**ie_ptr = eps_mobile_id->guti.mme_code;
|
||||||
*ie_ptr += 1;
|
*ie_ptr += 1;
|
||||||
|
@ -5518,6 +5518,14 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_reject_msg(LIBLTE_BYTE_MSG_STRUCT
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
|
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
|
||||||
LIBLTE_BYTE_MSG_STRUCT *msg)
|
LIBLTE_BYTE_MSG_STRUCT *msg)
|
||||||
|
{
|
||||||
|
return liblte_mme_pack_attach_request_msg(attach_req, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, 0, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
|
||||||
|
uint8 sec_hdr_type,
|
||||||
|
uint32 count,
|
||||||
|
LIBLTE_BYTE_MSG_STRUCT *msg)
|
||||||
{
|
{
|
||||||
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
|
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
|
||||||
uint8 *msg_ptr = msg->msg;
|
uint8 *msg_ptr = msg->msg;
|
||||||
|
@ -5525,6 +5533,20 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_M
|
||||||
if(attach_req != NULL &&
|
if(attach_req != NULL &&
|
||||||
msg != NULL)
|
msg != NULL)
|
||||||
{
|
{
|
||||||
|
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type)
|
||||||
|
{
|
||||||
|
// Protocol Discriminator and Security Header Type
|
||||||
|
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
|
||||||
|
msg_ptr++;
|
||||||
|
|
||||||
|
// MAC will be filled in later
|
||||||
|
msg_ptr += 4;
|
||||||
|
|
||||||
|
// Sequence Number
|
||||||
|
*msg_ptr = count & 0xFF;
|
||||||
|
msg_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
// Protocol Discriminator and Security Header Type
|
// Protocol Discriminator and Security Header Type
|
||||||
*msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
|
*msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
|
||||||
msg_ptr++;
|
msg_ptr++;
|
||||||
|
|
|
@ -57,6 +57,9 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL",
|
||||||
"DEREGISTERED INITIATED",
|
"DEREGISTERED INITIATED",
|
||||||
"TRACKING AREA UPDATE INITIATED"};
|
"TRACKING AREA UPDATE INITIATED"};
|
||||||
|
|
||||||
|
static const bool eia_caps[8] = {false, true, true, false, false, false, false, false};
|
||||||
|
static const bool eea_caps[8] = {true, false, false, false, false, false, false, false};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PLMN_NOT_SELECTED = 0,
|
PLMN_NOT_SELECTED = 0,
|
||||||
PLMN_SELECTED
|
PLMN_SELECTED
|
||||||
|
@ -80,16 +83,12 @@ public:
|
||||||
|
|
||||||
// RRC interface
|
// RRC interface
|
||||||
void notify_connection_setup();
|
void notify_connection_setup();
|
||||||
|
|
||||||
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
uint32_t get_ul_count();
|
uint32_t get_ul_count();
|
||||||
|
|
||||||
bool is_attached();
|
bool is_attached();
|
||||||
bool is_attaching();
|
bool is_attaching();
|
||||||
|
|
||||||
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
|
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
|
||||||
|
bool get_k_asme(uint8_t *k_asme_, uint32_t n);
|
||||||
void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
|
void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
|
||||||
void plmn_search_end();
|
void plmn_search_end();
|
||||||
|
|
||||||
|
@ -115,72 +114,73 @@ private:
|
||||||
|
|
||||||
std::vector<LIBLTE_RRC_PLMN_IDENTITY_STRUCT > known_plmns;
|
std::vector<LIBLTE_RRC_PLMN_IDENTITY_STRUCT > known_plmns;
|
||||||
|
|
||||||
// Save short MAC
|
LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info;
|
||||||
|
|
||||||
// Identifiers
|
// Identifiers
|
||||||
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
|
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
|
||||||
bool is_guti_set;
|
bool have_guti;
|
||||||
|
|
||||||
|
// Security context
|
||||||
|
struct nas_sec_ctxt{
|
||||||
|
uint8_t ksi;
|
||||||
|
uint8_t k_asme[32];
|
||||||
|
uint32_t tx_count;
|
||||||
|
uint32_t rx_count;
|
||||||
|
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
||||||
|
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool have_ctxt;
|
||||||
|
nas_sec_ctxt ctxt;
|
||||||
|
|
||||||
uint32_t ip_addr;
|
uint32_t ip_addr;
|
||||||
uint8_t eps_bearer_id;
|
uint8_t eps_bearer_id;
|
||||||
|
|
||||||
uint8_t transaction_id;
|
uint8_t transaction_id;
|
||||||
|
|
||||||
// NAS counters - incremented for each security-protected message recvd/sent
|
|
||||||
uint32_t count_ul;
|
|
||||||
uint32_t count_dl;
|
|
||||||
|
|
||||||
// Security
|
// Security
|
||||||
uint8_t ksi;
|
|
||||||
uint8_t k_nas_enc[32];
|
uint8_t k_nas_enc[32];
|
||||||
uint8_t k_nas_int[32];
|
uint8_t k_nas_int[32];
|
||||||
|
|
||||||
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
void integrity_generate(uint8_t integ_algo,
|
||||||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
uint8_t *key_128,
|
||||||
|
|
||||||
void integrity_generate(uint8_t *key_128,
|
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
uint8_t rb_id,
|
uint8_t rb_id,
|
||||||
uint8_t direction,
|
uint8_t direction,
|
||||||
uint8_t *msg,
|
uint8_t *msg,
|
||||||
uint32_t msg_len,
|
uint32_t msg_len,
|
||||||
uint8_t *mac);
|
uint8_t *mac);
|
||||||
|
|
||||||
void integrity_check();
|
void integrity_check();
|
||||||
|
|
||||||
void cipher_encrypt();
|
void cipher_encrypt();
|
||||||
|
|
||||||
void cipher_decrypt();
|
void cipher_decrypt();
|
||||||
|
bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps);
|
||||||
|
|
||||||
// Parsers
|
// Parsers
|
||||||
void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_attach_reject(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_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_authentication_reject(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_identity_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_security_mode_command(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_service_reject(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_esm_information_request(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);
|
void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
// Senders
|
// Senders
|
||||||
void send_attach_request();
|
void send_attach_request();
|
||||||
|
|
||||||
void send_identity_response();
|
void send_identity_response();
|
||||||
|
|
||||||
void send_service_request();
|
void send_service_request();
|
||||||
|
|
||||||
void send_esm_information_response();
|
void send_esm_information_response();
|
||||||
|
|
||||||
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
|
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
|
||||||
|
void send_security_mode_reject(uint8_t cause);
|
||||||
|
|
||||||
|
// guti persistence file
|
||||||
|
bool read_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT *guti);
|
||||||
|
bool write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti);
|
||||||
|
|
||||||
|
// security context persistence file
|
||||||
|
bool read_ctxt_file(nas_sec_ctxt *ctxt);
|
||||||
|
bool write_ctxt_file(nas_sec_ctxt ctxt);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace srsue
|
} // namespace srsue
|
||||||
|
|
|
@ -40,8 +40,6 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool stmsi_attach;
|
|
||||||
LIBLTE_RRC_S_TMSI_STRUCT stmsi_value;
|
|
||||||
uint32_t ue_category;
|
uint32_t ue_category;
|
||||||
uint32_t feature_group;
|
uint32_t feature_group;
|
||||||
uint8_t supported_bands[LIBLTE_RRC_BAND_N_ITEMS];
|
uint8_t supported_bands[LIBLTE_RRC_BAND_N_ITEMS];
|
||||||
|
@ -198,21 +196,16 @@ private:
|
||||||
|
|
||||||
// MAC interface
|
// MAC interface
|
||||||
void release_pucch_srs();
|
void release_pucch_srs();
|
||||||
|
|
||||||
void ra_problem();
|
void ra_problem();
|
||||||
|
|
||||||
// GW interface
|
// GW interface
|
||||||
bool is_connected();
|
bool is_connected();
|
||||||
|
|
||||||
bool have_drb();
|
bool have_drb();
|
||||||
|
|
||||||
// PDCP interface
|
// PDCP interface
|
||||||
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void write_pdu_bcch_bch(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_bcch_dlsch(byte_buffer_t *pdu);
|
||||||
|
|
||||||
void write_pdu_pcch(byte_buffer_t *pdu);
|
void write_pdu_pcch(byte_buffer_t *pdu);
|
||||||
|
|
||||||
// Radio bearers
|
// Radio bearers
|
||||||
|
@ -280,11 +273,6 @@ private:
|
||||||
void set_mac_default();
|
void set_mac_default();
|
||||||
void set_rrc_default();
|
void set_rrc_default();
|
||||||
void set_bearers();
|
void set_bearers();
|
||||||
|
|
||||||
// s-tmsi persistent file
|
|
||||||
bool read_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
|
|
||||||
bool write_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace srsue
|
} // namespace srsue
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* \section COPYRIGHT
|
* \section COPYRIGHT
|
||||||
*
|
*
|
||||||
|
@ -59,24 +59,30 @@ public:
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
// NAS interface
|
// NAS interface
|
||||||
void get_imsi_vec(uint8_t* imsi_, uint32_t n);
|
std::string get_imsi_str();
|
||||||
void get_imei_vec(uint8_t* imei_, uint32_t n);
|
std::string get_imei_str();
|
||||||
int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id);
|
|
||||||
|
bool get_imsi_vec(uint8_t* imsi_, uint32_t n);
|
||||||
|
bool get_imei_vec(uint8_t* imei_, uint32_t n);
|
||||||
|
bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id);
|
||||||
|
|
||||||
void generate_authentication_response(uint8_t *rand,
|
void generate_authentication_response(uint8_t *rand,
|
||||||
uint8_t *autn_enb,
|
uint8_t *autn_enb,
|
||||||
uint16_t mcc,
|
uint16_t mcc,
|
||||||
uint16_t mnc,
|
uint16_t mnc,
|
||||||
bool *net_valid,
|
bool *net_valid,
|
||||||
uint8_t *res);
|
uint8_t *res,
|
||||||
|
uint8_t *k_asme);
|
||||||
|
|
||||||
void generate_nas_keys(uint8_t *k_nas_enc,
|
void generate_nas_keys(uint8_t *k_asme,
|
||||||
|
uint8_t *k_nas_enc,
|
||||||
uint8_t *k_nas_int,
|
uint8_t *k_nas_int,
|
||||||
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
||||||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
|
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
|
||||||
|
|
||||||
// RRC interface
|
// RRC interface
|
||||||
void generate_as_keys(uint32_t count_ul,
|
void generate_as_keys(uint8_t *k_asme,
|
||||||
|
uint32_t count_ul,
|
||||||
uint8_t *k_rrc_enc,
|
uint8_t *k_rrc_enc,
|
||||||
uint8_t *k_rrc_int,
|
uint8_t *k_rrc_int,
|
||||||
uint8_t *k_up_enc,
|
uint8_t *k_up_enc,
|
||||||
|
@ -91,13 +97,15 @@ private:
|
||||||
uint16_t mcc,
|
uint16_t mcc,
|
||||||
uint16_t mnc,
|
uint16_t mnc,
|
||||||
bool *net_valid,
|
bool *net_valid,
|
||||||
uint8_t *res);
|
uint8_t *res,
|
||||||
|
uint8_t *k_asme);
|
||||||
void gen_auth_res_xor( uint8_t *rand,
|
void gen_auth_res_xor( uint8_t *rand,
|
||||||
uint8_t *autn_enb,
|
uint8_t *autn_enb,
|
||||||
uint16_t mcc,
|
uint16_t mcc,
|
||||||
uint16_t mnc,
|
uint16_t mnc,
|
||||||
bool *net_valid,
|
bool *net_valid,
|
||||||
uint8_t *res);
|
uint8_t *res,
|
||||||
|
uint8_t *k_asme);
|
||||||
void str_to_hex(std::string str, uint8_t *hex);
|
void str_to_hex(std::string str, uint8_t *hex);
|
||||||
|
|
||||||
srslte::log *usim_log;
|
srslte::log *usim_log;
|
||||||
|
@ -110,6 +118,9 @@ private:
|
||||||
uint64_t imei;
|
uint64_t imei;
|
||||||
uint8_t k[16];
|
uint8_t k[16];
|
||||||
|
|
||||||
|
std::string imsi_str;
|
||||||
|
std::string imei_str;
|
||||||
|
|
||||||
// Security variables
|
// Security variables
|
||||||
uint8_t rand[16];
|
uint8_t rand[16];
|
||||||
uint8_t ck[16];
|
uint8_t ck[16];
|
||||||
|
@ -117,7 +128,6 @@ private:
|
||||||
uint8_t ak[6];
|
uint8_t ak[6];
|
||||||
uint8_t mac[8];
|
uint8_t mac[8];
|
||||||
uint8_t autn[16];
|
uint8_t autn[16];
|
||||||
uint8_t k_asme[32];
|
|
||||||
uint8_t k_enb[32];
|
uint8_t k_enb[32];
|
||||||
|
|
||||||
bool initiated;
|
bool initiated;
|
||||||
|
|
|
@ -77,17 +77,12 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
|
||||||
"Transmission time advance")
|
"Transmission time advance")
|
||||||
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
|
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
|
||||||
|
|
||||||
("rrc.stmsi_attach", bpo::value<bool>(&args->rrc.stmsi_attach)->default_value(false),"If enabled, always tries first an S-TMSI attach using the\n"
|
|
||||||
"S-TMSI value stored in .stimsi file generated in previous run")
|
|
||||||
("rrc.mmec_value", bpo::value<uint8_t>(&args->rrc.stmsi_value.mmec)->default_value(0), "If defined (non-zero), overwrites the value stored in .stimsi file")
|
|
||||||
("rrc.mtmsi_value", bpo::value<uint32_t>(&args->rrc.stmsi_value.m_tmsi)->default_value(0), "If defined (non-zero), overwrites the value stored in .stimsi file")
|
|
||||||
|
|
||||||
("rrc.feature_group", bpo::value<uint32_t>(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the"
|
("rrc.feature_group", bpo::value<uint32_t>(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the"
|
||||||
"UECapabilityInformation message. Default 0xe6041c00")
|
"UECapabilityInformation message. Default 0xe6041c00")
|
||||||
("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
|
("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
|
||||||
|
|
||||||
|
|
||||||
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false),
|
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false),
|
||||||
"Enable MAC packet captures for wireshark")
|
"Enable MAC packet captures for wireshark")
|
||||||
("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")
|
("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
#include "srslte/asn1/liblte_rrc.h"
|
#include "srslte/asn1/liblte_rrc.h"
|
||||||
#include "upper/nas.h"
|
#include "upper/nas.h"
|
||||||
#include "srslte/common/bcd_helpers.h"
|
#include "srslte/common/bcd_helpers.h"
|
||||||
|
@ -33,9 +38,78 @@ using namespace srslte;
|
||||||
|
|
||||||
namespace srsue {
|
namespace srsue {
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Conversion helpers
|
||||||
|
********************************************************************/
|
||||||
|
std::string hex_to_string(uint8_t *hex, int size)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
ss << std::hex << std::setfill('0');
|
||||||
|
for(int i=0; i<size; i++) {
|
||||||
|
ss << std::setw(2) << static_cast<unsigned>(hex[i]);
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_to_hex(std::string hex_str, uint8_t *hex, uint32_t len)
|
||||||
|
{
|
||||||
|
static const char* const lut = "0123456789abcdef";
|
||||||
|
uint32_t str_len = hex_str.length();
|
||||||
|
if(str_len & 1) {
|
||||||
|
return false; // uneven hex_str length
|
||||||
|
}
|
||||||
|
if(str_len > len*2) {
|
||||||
|
return false; // not enough space in hex buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<str_len; i+=2)
|
||||||
|
{
|
||||||
|
char a = hex_str[i];
|
||||||
|
const char* p = std::lower_bound(lut, lut + 16, a);
|
||||||
|
if (*p != a) {
|
||||||
|
return false; // invalid char
|
||||||
|
}
|
||||||
|
|
||||||
|
char b = hex_str[i+1];
|
||||||
|
const char* q = std::lower_bound(lut, lut + 16, b);
|
||||||
|
if (*q != b) {
|
||||||
|
return false; // invalid char
|
||||||
|
}
|
||||||
|
|
||||||
|
hex[i/2] = ((p - lut) << 4) | (q - lut);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string emm_info_str(LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *info)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
if(info->full_net_name_present) {
|
||||||
|
ss << info->full_net_name.name;
|
||||||
|
}
|
||||||
|
if(info->short_net_name_present) {
|
||||||
|
ss << " (" << info->short_net_name.name << ")";
|
||||||
|
}
|
||||||
|
if(info->utc_and_local_time_zone_present) {
|
||||||
|
ss << " " << (int)info->utc_and_local_time_zone.day;
|
||||||
|
ss << "/" << (int)info->utc_and_local_time_zone.month;
|
||||||
|
ss << "/" << (int)info->utc_and_local_time_zone.year;
|
||||||
|
ss << " " << (int)info->utc_and_local_time_zone.hour;
|
||||||
|
ss << ":" << (int)info->utc_and_local_time_zone.minute;
|
||||||
|
ss << ":" << (int)info->utc_and_local_time_zone.second;
|
||||||
|
ss << " TZ:" << (int)info->utc_and_local_time_zone.tz;
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
nas::nas()
|
nas::nas()
|
||||||
: state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), is_guti_set(false), ip_addr(0), eps_bearer_id(0),
|
: state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), ip_addr(0), eps_bearer_id(0)
|
||||||
count_ul(0), count_dl(0) {}
|
{
|
||||||
|
ctxt.rx_count = 0;
|
||||||
|
ctxt.tx_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void nas::init(usim_interface_nas *usim_,
|
void nas::init(usim_interface_nas *usim_,
|
||||||
rrc_interface_nas *rrc_,
|
rrc_interface_nas *rrc_,
|
||||||
|
@ -51,15 +125,26 @@ void nas::init(usim_interface_nas *usim_,
|
||||||
state = EMM_STATE_DEREGISTERED;
|
state = EMM_STATE_DEREGISTERED;
|
||||||
plmn_selection = PLMN_NOT_SELECTED;
|
plmn_selection = PLMN_NOT_SELECTED;
|
||||||
|
|
||||||
if (usim->get_home_plmn_id(&home_plmn)) {
|
if (!usim->get_home_plmn_id(&home_plmn)) {
|
||||||
nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n");
|
nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n");
|
||||||
home_plmn.mcc = 61441; // This is 001
|
home_plmn.mcc = 61441; // This is 001
|
||||||
home_plmn.mnc = 65281; // This is 01
|
home_plmn.mnc = 65281; // This is 01
|
||||||
}
|
}
|
||||||
cfg = cfg_;
|
cfg = cfg_;
|
||||||
|
|
||||||
|
if((have_guti = read_guti_file(&guti))) {
|
||||||
|
if((have_ctxt = read_ctxt_file(&ctxt))) {
|
||||||
|
usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int,
|
||||||
|
ctxt.cipher_algo, ctxt.integ_algo);
|
||||||
|
nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc");
|
||||||
|
nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::stop() {}
|
void nas::stop() {
|
||||||
|
write_ctxt_file(ctxt);
|
||||||
|
}
|
||||||
|
|
||||||
emm_state_t nas::get_state() {
|
emm_state_t nas::get_state() {
|
||||||
return state;
|
return state;
|
||||||
|
@ -207,11 +292,11 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t nas::get_ul_count() {
|
uint32_t nas::get_ul_count() {
|
||||||
return count_ul;
|
return ctxt.tx_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
|
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
|
||||||
if (is_guti_set) {
|
if (have_guti) {
|
||||||
s_tmsi->mmec = guti.mme_code;
|
s_tmsi->mmec = guti.mme_code;
|
||||||
s_tmsi->m_tmsi = guti.m_tmsi;
|
s_tmsi->m_tmsi = guti.m_tmsi;
|
||||||
return true;
|
return true;
|
||||||
|
@ -220,11 +305,26 @@ bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) {
|
||||||
|
if(!have_ctxt) {
|
||||||
|
nas_log->error("K_asme requested before security context established\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(NULL == k_asme_ || n < 32) {
|
||||||
|
nas_log->error("Invalid parameters to get_k_asme");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(k_asme_, ctxt.k_asme, 32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
Security
|
Security
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
void nas::integrity_generate(uint8_t *key_128,
|
void nas::integrity_generate(uint8_t integ_algo,
|
||||||
|
uint8_t *key_128,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
uint8_t rb_id,
|
uint8_t rb_id,
|
||||||
uint8_t direction,
|
uint8_t direction,
|
||||||
|
@ -269,6 +369,16 @@ void nas::cipher_decrypt() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nas::check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps)
|
||||||
|
{
|
||||||
|
for(uint32_t i=0; i<8; i++) {
|
||||||
|
if(caps->eea[i] != eea_caps[i] || caps->eia[i] != eia_caps[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
Parsers
|
Parsers
|
||||||
|
@ -289,8 +399,8 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
//FIXME: Handle tai_list
|
//FIXME: Handle tai_list
|
||||||
if (attach_accept.guti_present) {
|
if (attach_accept.guti_present) {
|
||||||
memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
|
memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
|
||||||
is_guti_set = true;
|
have_guti = true;
|
||||||
// TODO: log message to console
|
write_guti_file(guti);
|
||||||
}
|
}
|
||||||
if (attach_accept.lai_present) {
|
if (attach_accept.lai_present) {
|
||||||
}
|
}
|
||||||
|
@ -358,10 +468,9 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
state = EMM_STATE_REGISTERED;
|
state = EMM_STATE_REGISTERED;
|
||||||
current_plmn = selecting_plmn;
|
current_plmn = selecting_plmn;
|
||||||
|
|
||||||
count_dl++;
|
ctxt.rx_count++;
|
||||||
|
|
||||||
// Send EPS bearer context accept and attach complete
|
// 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.eps_bearer_id = eps_bearer_id;
|
||||||
act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id;
|
act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id;
|
||||||
act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false;
|
act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false;
|
||||||
|
@ -369,10 +478,11 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
&attach_complete.esm_msg);
|
&attach_complete.esm_msg);
|
||||||
liblte_mme_pack_attach_complete_msg(&attach_complete,
|
liblte_mme_pack_attach_complete_msg(&attach_complete,
|
||||||
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
|
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
|
||||||
count_ul,
|
ctxt.tx_count,
|
||||||
(LIBLTE_BYTE_MSG_STRUCT *) pdu);
|
(LIBLTE_BYTE_MSG_STRUCT *) pdu);
|
||||||
integrity_generate(&k_nas_int[16],
|
integrity_generate(ctxt.integ_algo,
|
||||||
count_ul,
|
&k_nas_int[16],
|
||||||
|
ctxt.tx_count,
|
||||||
lcid - 1,
|
lcid - 1,
|
||||||
SECURITY_DIRECTION_UPLINK,
|
SECURITY_DIRECTION_UPLINK,
|
||||||
&pdu->msg[5],
|
&pdu->msg[5],
|
||||||
|
@ -384,6 +494,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
|
|
||||||
nas_log->info("Sending Attach Complete\n");
|
nas_log->info("Sending Attach Complete\n");
|
||||||
rrc->write_sdu(lcid, pdu);
|
rrc->write_sdu(lcid, pdu);
|
||||||
|
ctxt.tx_count++;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result);
|
nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result);
|
||||||
|
@ -407,7 +518,7 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
|
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
|
||||||
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
|
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
|
||||||
|
|
||||||
nas_log->info("Received Authentication Request\n");;
|
nas_log->info("Received Authentication Request\n");
|
||||||
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
|
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
|
||||||
|
|
||||||
// Reuse the pdu for the response message
|
// Reuse the pdu for the response message
|
||||||
|
@ -422,7 +533,15 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
|
|
||||||
bool net_valid;
|
bool net_valid;
|
||||||
uint8_t res[16];
|
uint8_t res[16];
|
||||||
usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, &net_valid, res);
|
usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc,
|
||||||
|
&net_valid, res, ctxt.k_asme);
|
||||||
|
nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str());
|
||||||
|
if(LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE == auth_req.nas_ksi.tsc_flag) {
|
||||||
|
ctxt.ksi = auth_req.nas_ksi.nas_ksi;
|
||||||
|
} else {
|
||||||
|
nas_log->error("NAS mapped security context not currently supported\n");
|
||||||
|
nas_log->console("Warning: NAS mapped security context not currently supported\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (net_valid) {
|
if (net_valid) {
|
||||||
nas_log->info("Network authentication successful\n");
|
nas_log->info("Network authentication successful\n");
|
||||||
|
@ -438,9 +557,6 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
nas_log->console("Warning: Network authentication failure\n");
|
nas_log->console("Warning: Network authentication failure\n");
|
||||||
pool->deallocate(pdu);
|
pool->deallocate(pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset DL counter (as per 24.301 5.4.3.2)
|
|
||||||
count_dl = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
|
@ -451,108 +567,154 @@ void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) {
|
void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
nas_log->error("TODO:parse_identity_request\n");
|
LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req;
|
||||||
|
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp;
|
||||||
|
|
||||||
|
liblte_mme_unpack_identity_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &id_req);
|
||||||
|
nas_log->info("Received Identity Request. ID type: %d\n", id_req.id_type);
|
||||||
|
|
||||||
|
switch(id_req.id_type) {
|
||||||
|
case LIBLTE_MME_MOBILE_ID_TYPE_IMSI:
|
||||||
|
id_resp.mobile_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMSI;
|
||||||
|
usim->get_imsi_vec(id_resp.mobile_id.imsi, 15);
|
||||||
|
break;
|
||||||
|
case LIBLTE_MME_MOBILE_ID_TYPE_IMEI:
|
||||||
|
id_resp.mobile_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEI;
|
||||||
|
usim->get_imei_vec(id_resp.mobile_id.imei, 15);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nas_log->error("Unhandled ID type: %d\n");
|
||||||
|
pool->deallocate(pdu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdu->reset();
|
||||||
|
liblte_mme_pack_identity_response_msg(&id_resp, (LIBLTE_BYTE_MSG_STRUCT *) pdu);
|
||||||
|
rrc->write_sdu(lcid, pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) {
|
void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
|
||||||
bool success;
|
{
|
||||||
LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd;
|
LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd;
|
||||||
LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp;
|
LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp;
|
||||||
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
|
|
||||||
|
|
||||||
nas_log->info("Received Security Mode Command\n");
|
|
||||||
liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd);
|
liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd);
|
||||||
|
nas_log->info("Received Security Mode Command ksi: %d, eea: %s, eia: %s\n",
|
||||||
|
sec_mode_cmd.nas_ksi.nas_ksi,
|
||||||
|
ciphering_algorithm_id_text[sec_mode_cmd.selected_nas_sec_algs.type_of_eea],
|
||||||
|
integrity_algorithm_id_text[sec_mode_cmd.selected_nas_sec_algs.type_of_eia]);
|
||||||
|
|
||||||
ksi = sec_mode_cmd.nas_ksi.nas_ksi;
|
if(sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) {
|
||||||
cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea;
|
nas_log->error("Mapped security context not supported\n");
|
||||||
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia;
|
pool->deallocate(pdu);
|
||||||
// FIXME: Handle nonce_ue, nonce_mme
|
return;
|
||||||
// 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",
|
if(sec_mode_cmd.nas_ksi.nas_ksi != ctxt.ksi)
|
||||||
ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]);
|
{
|
||||||
|
nas_log->warning("Sending Security Mode Reject due to key set ID mismatch\n");
|
||||||
|
send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED);
|
||||||
|
pool->deallocate(pdu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// MME is setting up security context
|
||||||
|
|
||||||
|
// TODO: check nonce (not sent by Amari)
|
||||||
|
|
||||||
if (CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo ||
|
// Check capabilities replay
|
||||||
(INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo &&
|
if(!check_cap_replay(&sec_mode_cmd.ue_security_cap)) {
|
||||||
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");
|
nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n");
|
||||||
nas_log->console("Unsupported Security Mode Command settings: use ciphering algorithm EEA0 and integrity check EIA1 or EIA2.\n");
|
send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH);
|
||||||
success = false;
|
pool->deallocate(pdu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset counterd (as per 24.301 5.4.3.2)
|
||||||
|
ctxt.rx_count = 0;
|
||||||
|
ctxt.tx_count = 0;
|
||||||
|
|
||||||
|
ctxt.cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea;
|
||||||
|
ctxt.integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia;
|
||||||
|
|
||||||
|
// Check capabilities
|
||||||
|
if(!eea_caps[ctxt.cipher_algo] || !eia_caps[ctxt.integ_algo]) {
|
||||||
|
nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n");
|
||||||
|
send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH);
|
||||||
|
pool->deallocate(pdu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate NAS keys
|
||||||
|
usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, ctxt.cipher_algo, ctxt.integ_algo);
|
||||||
|
nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc");
|
||||||
|
nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int");
|
||||||
|
|
||||||
|
nas_log->debug("Generating integrity check. integ_algo:%d, count_dl:%d, lcid:%d\n",
|
||||||
|
ctxt.integ_algo, ctxt.rx_count, lcid);
|
||||||
|
|
||||||
|
// Check incoming MAC
|
||||||
|
uint8_t *inMAC = &pdu->msg[1];
|
||||||
|
uint8_t genMAC[4];
|
||||||
|
integrity_generate(ctxt.integ_algo,
|
||||||
|
&k_nas_int[16],
|
||||||
|
ctxt.rx_count,
|
||||||
|
lcid - 1,
|
||||||
|
SECURITY_DIRECTION_DOWNLINK,
|
||||||
|
&pdu->msg[5],
|
||||||
|
pdu->N_bytes - 5,
|
||||||
|
genMAC);
|
||||||
|
|
||||||
|
nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:");
|
||||||
|
nas_log->info_hex(genMAC, 4, "Generated PDU MAC:");
|
||||||
|
|
||||||
|
ctxt.rx_count++;
|
||||||
|
|
||||||
|
bool match = true;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (inMAC[i] != genMAC[i]) {
|
||||||
|
match = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!match) {
|
||||||
|
nas_log->warning("Sending Security Mode Reject due to integrity check failure\n");
|
||||||
|
send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED);
|
||||||
|
pool->deallocate(pdu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take security context into use
|
||||||
|
have_ctxt = true;
|
||||||
|
|
||||||
|
if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) {
|
||||||
|
sec_mode_comp.imeisv_present = true;
|
||||||
|
sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV;
|
||||||
|
usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15);
|
||||||
|
sec_mode_comp.imeisv.imeisv[14] = 5;
|
||||||
|
sec_mode_comp.imeisv.imeisv[15] = 3;
|
||||||
} else {
|
} else {
|
||||||
// Generate NAS encryption key and integrity protection key
|
sec_mode_comp.imeisv_present = false;
|
||||||
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,
|
|
||||||
rrc->get_rb_name(lcid).c_str());
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count_dl++;
|
// Send response
|
||||||
|
byte_buffer_t *sdu = pool_allocate;
|
||||||
if (!success) {
|
liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp,
|
||||||
// Reuse pdu for response
|
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
|
||||||
pdu->reset();
|
ctxt.tx_count,
|
||||||
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) pdu);
|
(LIBLTE_BYTE_MSG_STRUCT *) sdu);
|
||||||
}
|
integrity_generate(ctxt.integ_algo,
|
||||||
|
&k_nas_int[16],
|
||||||
rrc->write_sdu(lcid, pdu);
|
ctxt.tx_count,
|
||||||
|
lcid - 1,
|
||||||
|
SECURITY_DIRECTION_UPLINK,
|
||||||
|
&sdu->msg[5],
|
||||||
|
sdu->N_bytes - 5,
|
||||||
|
&sdu->msg[1]);
|
||||||
|
nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n",
|
||||||
|
ctxt.tx_count,
|
||||||
|
rrc->get_rb_name(lcid).c_str());
|
||||||
|
rrc->write_sdu(lcid, sdu);
|
||||||
|
ctxt.tx_count++;
|
||||||
|
pool->deallocate(pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
|
@ -561,10 +723,15 @@ void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
|
|
||||||
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) {
|
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
nas_log->error("TODO:parse_esm_information_request\n");
|
nas_log->error("TODO:parse_esm_information_request\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
|
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
nas_log->error("TODO:parse_emm_information\n");
|
liblte_mme_unpack_emm_information_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &emm_info);
|
||||||
|
std::string str = emm_info_str(&emm_info);
|
||||||
|
nas_log->info("Received EMM Information: %s\n", str.c_str());
|
||||||
|
nas_log->console("%s\n", str.c_str());
|
||||||
|
ctxt.rx_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -579,25 +746,13 @@ void nas::send_attach_request() {
|
||||||
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
|
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
attach_req.ue_network_cap.eea[i] = false;
|
attach_req.ue_network_cap.eea[i] = eea_caps[i];
|
||||||
attach_req.ue_network_cap.eia[i] = false;
|
attach_req.ue_network_cap.eia[i] = eia_caps[i];
|
||||||
}
|
}
|
||||||
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.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.old_p_tmsi_signature_present = false;
|
attach_req.old_p_tmsi_signature_present = false;
|
||||||
attach_req.additional_guti_present = false;
|
attach_req.additional_guti_present = false;
|
||||||
attach_req.last_visited_registered_tai_present = false;
|
attach_req.last_visited_registered_tai_present = false;
|
||||||
|
@ -613,11 +768,47 @@ void nas::send_attach_request() {
|
||||||
attach_req.device_properties_present = false;
|
attach_req.device_properties_present = false;
|
||||||
attach_req.old_guti_type_present = false;
|
attach_req.old_guti_type_present = false;
|
||||||
|
|
||||||
// Pack the message
|
// ESM message (PDN connectivity request) for first default bearer
|
||||||
liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg);
|
gen_pdn_connectivity_request(&attach_req.esm_msg);
|
||||||
|
|
||||||
|
// GUTI or IMSI attach
|
||||||
|
if(have_guti && have_ctxt) {
|
||||||
|
attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI;
|
||||||
|
memcpy(&attach_req.eps_mobile_id.guti, &guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
|
||||||
|
attach_req.old_guti_type = LIBLTE_MME_GUTI_TYPE_NATIVE;
|
||||||
|
attach_req.old_guti_type_present = true;
|
||||||
|
attach_req.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE;
|
||||||
|
attach_req.nas_ksi.nas_ksi = ctxt.ksi;
|
||||||
|
nas_log->info("Requesting GUTI attach. "
|
||||||
|
"m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n",
|
||||||
|
guti.m_tmsi, guti.mcc, guti.mnc, guti.mme_group_id, guti.mme_code);
|
||||||
|
liblte_mme_pack_attach_request_msg(&attach_req,
|
||||||
|
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY,
|
||||||
|
ctxt.tx_count,
|
||||||
|
(LIBLTE_BYTE_MSG_STRUCT *) msg);
|
||||||
|
|
||||||
|
// Add MAC
|
||||||
|
integrity_generate(ctxt.integ_algo,
|
||||||
|
&k_nas_int[16],
|
||||||
|
ctxt.tx_count,
|
||||||
|
cfg.lcid-1,
|
||||||
|
SECURITY_DIRECTION_UPLINK,
|
||||||
|
&msg->msg[5],
|
||||||
|
msg->N_bytes - 5,
|
||||||
|
&msg->msg[1]);
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
nas_log->info("Requesting IMSI attach. imsi: %s\n", usim->get_imsi_str());
|
||||||
|
liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg);
|
||||||
|
}
|
||||||
|
|
||||||
nas_log->info("Sending attach request\n");
|
nas_log->info("Sending attach request\n");
|
||||||
rrc->write_sdu(cfg.lcid, msg);
|
rrc->write_sdu(cfg.lcid, msg);
|
||||||
|
|
||||||
|
if(have_ctxt) {
|
||||||
|
ctxt.tx_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
|
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
|
||||||
|
@ -641,27 +832,36 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
|
||||||
liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg);
|
liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nas::send_security_mode_reject(uint8_t cause) {
|
||||||
|
byte_buffer_t *msg = pool_allocate;
|
||||||
|
|
||||||
|
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
|
||||||
|
sec_mode_rej.emm_cause = cause;
|
||||||
|
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg);
|
||||||
|
rrc->write_sdu(cfg.lcid, msg);
|
||||||
|
}
|
||||||
|
|
||||||
void nas::send_identity_response() {}
|
void nas::send_identity_response() {}
|
||||||
|
|
||||||
void nas::send_service_request() {
|
void nas::send_service_request() {
|
||||||
byte_buffer_t *msg = pool_allocate;
|
byte_buffer_t *msg = pool_allocate;
|
||||||
count_ul++;
|
|
||||||
|
|
||||||
// Pack the service request message directly
|
// Pack the service request message directly
|
||||||
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
|
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
|
||||||
msg->N_bytes++;
|
msg->N_bytes++;
|
||||||
msg->msg[1] = (ksi & 0x07) << 5;
|
msg->msg[1] = (ctxt.ksi & 0x07) << 5;
|
||||||
msg->msg[1] |= count_ul & 0x1F;
|
msg->msg[1] |= ctxt.tx_count & 0x1F;
|
||||||
msg->N_bytes++;
|
msg->N_bytes++;
|
||||||
|
|
||||||
uint8_t mac[4];
|
uint8_t mac[4];
|
||||||
integrity_generate(&k_nas_int[16],
|
integrity_generate(ctxt.integ_algo,
|
||||||
count_ul,
|
&k_nas_int[16],
|
||||||
cfg.lcid-1,
|
ctxt.tx_count,
|
||||||
SECURITY_DIRECTION_UPLINK,
|
cfg.lcid-1,
|
||||||
&msg->msg[0],
|
SECURITY_DIRECTION_UPLINK,
|
||||||
2,
|
&msg->msg[0],
|
||||||
&mac[0]);
|
2,
|
||||||
|
&mac[0]);
|
||||||
// Set the short MAC
|
// Set the short MAC
|
||||||
msg->msg[2] = mac[2];
|
msg->msg[2] = mac[2];
|
||||||
msg->N_bytes++;
|
msg->N_bytes++;
|
||||||
|
@ -669,8 +869,239 @@ void nas::send_service_request() {
|
||||||
msg->N_bytes++;
|
msg->N_bytes++;
|
||||||
nas_log->info("Sending service request\n");
|
nas_log->info("Sending service request\n");
|
||||||
rrc->write_sdu(cfg.lcid, msg);
|
rrc->write_sdu(cfg.lcid, msg);
|
||||||
|
ctxt.tx_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::send_esm_information_response() {}
|
void nas::send_esm_information_response() {}
|
||||||
|
|
||||||
|
bool nas::read_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT *guti)
|
||||||
|
{
|
||||||
|
std::ifstream file;
|
||||||
|
std::string line;
|
||||||
|
if (!guti) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *m_tmsi_str = "m_tmsi=";
|
||||||
|
size_t m_tmsi_str_len = strlen(m_tmsi_str);
|
||||||
|
const char *mcc_str = "mcc=";
|
||||||
|
size_t mcc_str_len = strlen(mcc_str);
|
||||||
|
const char *mnc_str = "mnc=";
|
||||||
|
size_t mnc_str_len = strlen(mnc_str);
|
||||||
|
const char *mme_group_id_str = "mme_group_id=";
|
||||||
|
size_t mme_group_id_str_len = strlen(mme_group_id_str);
|
||||||
|
const char *mme_code_str = "mme_code=";
|
||||||
|
size_t mme_code_str_len = strlen(mme_code_str);
|
||||||
|
|
||||||
|
file.open(".guti", std::ios::in);
|
||||||
|
if (file.is_open()) {
|
||||||
|
bool read_ok = true;
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,m_tmsi_str_len).compare(m_tmsi_str)) {
|
||||||
|
guti->m_tmsi = atoi(line.substr(m_tmsi_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,mcc_str_len).compare(mcc_str)) {
|
||||||
|
guti->mcc = atoi(line.substr(mcc_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,mnc_str_len).compare(mnc_str)) {
|
||||||
|
guti->mnc = atoi(line.substr(mnc_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,mme_group_id_str_len).compare(mme_group_id_str)) {
|
||||||
|
guti->mme_group_id = atoi(line.substr(mme_group_id_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,mme_code_str_len).compare(mme_code_str)) {
|
||||||
|
guti->mme_code = atoi(line.substr(mme_code_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
if (read_ok) {
|
||||||
|
nas_log->info("Read GUTI from file .guti. "
|
||||||
|
"m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n",
|
||||||
|
guti->m_tmsi, guti->mcc, guti->mnc, guti->mme_group_id, guti->mme_code);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
nas_log->error("Invalid GUTI file format\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nas::write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti) {
|
||||||
|
std::ofstream file;
|
||||||
|
if (!have_guti) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
file.open(".guti", std::ios::out | std::ios::trunc);
|
||||||
|
if (file.is_open()) {
|
||||||
|
file << "m_tmsi=" << (int) guti.m_tmsi << std::endl;
|
||||||
|
file << "mcc=" << (int) guti.mcc << std::endl;
|
||||||
|
file << "mnc=" << (int) guti.mnc << std::endl;
|
||||||
|
file << "mme_group_id=" << (int) guti.mme_group_id << std::endl;
|
||||||
|
file << "mme_code=" << (int) guti.mme_code << std::endl;
|
||||||
|
nas_log->info("Saved GUTI to file .guti. "
|
||||||
|
"m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n",
|
||||||
|
guti.m_tmsi, guti.mcc, guti.mnc, guti.mme_group_id, guti.mme_code);
|
||||||
|
file.close();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nas::read_ctxt_file(nas_sec_ctxt *ctxt)
|
||||||
|
{
|
||||||
|
std::ifstream file;
|
||||||
|
std::string line;
|
||||||
|
if (!ctxt) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ksi_str = "ksi=";
|
||||||
|
size_t ksi_str_len = strlen(ksi_str);
|
||||||
|
const char *k_asme_str = "k_asme=";
|
||||||
|
size_t k_asme_str_len = strlen(k_asme_str);
|
||||||
|
const char *tx_count_str = "tx_count=";
|
||||||
|
size_t tx_count_str_len = strlen(tx_count_str);
|
||||||
|
const char *rx_count_str = "rx_count=";
|
||||||
|
size_t rx_count_str_len = strlen(rx_count_str);
|
||||||
|
const char *int_alg_str = "int_alg=";
|
||||||
|
size_t int_alg_str_len = strlen(int_alg_str);
|
||||||
|
const char *enc_alg_str = "enc_alg=";
|
||||||
|
size_t enc_alg_str_len = strlen(enc_alg_str);
|
||||||
|
|
||||||
|
file.open(".ctxt", std::ios::in);
|
||||||
|
if (file.is_open()) {
|
||||||
|
bool read_ok = true;
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,ksi_str_len).compare(ksi_str)) {
|
||||||
|
ctxt->ksi = atoi(line.substr(ksi_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,k_asme_str_len).compare(k_asme_str)) {
|
||||||
|
std::string tmp = line.substr(k_asme_str_len);
|
||||||
|
if(!string_to_hex(tmp, ctxt->k_asme, 32)) {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,tx_count_str_len).compare(tx_count_str)) {
|
||||||
|
ctxt->tx_count = atoi(line.substr(tx_count_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,rx_count_str_len).compare(rx_count_str)) {
|
||||||
|
ctxt->rx_count = atoi(line.substr(rx_count_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,int_alg_str_len).compare(int_alg_str)) {
|
||||||
|
ctxt->integ_algo = (srslte::INTEGRITY_ALGORITHM_ID_ENUM)atoi(line.substr(int_alg_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
if (std::getline(file, line)) {
|
||||||
|
if (!line.substr(0,enc_alg_str_len).compare(enc_alg_str)) {
|
||||||
|
ctxt->cipher_algo = (srslte::CIPHERING_ALGORITHM_ID_ENUM)atoi(line.substr(enc_alg_str_len).c_str());
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
read_ok = false;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
if (read_ok) {
|
||||||
|
nas_log->info("Read security ctxt from file .ctxt. "
|
||||||
|
"ksi: %x, k_asme: %s, "
|
||||||
|
"tx_count: %x, rx_count: %x, "
|
||||||
|
"int_alg: %d, enc_alg: %d\n",
|
||||||
|
ctxt->ksi, hex_to_string(ctxt->k_asme,32).c_str(),
|
||||||
|
ctxt->tx_count, ctxt->rx_count,
|
||||||
|
ctxt->integ_algo, ctxt->cipher_algo);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
nas_log->error("Invalid security ctxt file format\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nas::write_ctxt_file(nas_sec_ctxt ctxt)
|
||||||
|
{
|
||||||
|
std::ofstream file;
|
||||||
|
file.open(".ctxt", std::ios::out | std::ios::trunc);
|
||||||
|
if (file.is_open()) {
|
||||||
|
file << "ksi=" << (int) ctxt.ksi << std::endl;
|
||||||
|
file << "k_asme=" << hex_to_string(ctxt.k_asme, 32) << std::endl;
|
||||||
|
file << "tx_count=" << (int) ctxt.tx_count << std::endl;
|
||||||
|
file << "rx_count=" << (int) ctxt.rx_count << std::endl;
|
||||||
|
file << "int_alg=" << (int) ctxt.integ_algo << std::endl;
|
||||||
|
file << "enc_alg=" << (int) ctxt.cipher_algo << std::endl;
|
||||||
|
nas_log->info("Saved security ctxt to file .ctxt. "
|
||||||
|
"ksi: %x, k_asme: %s, "
|
||||||
|
"tx_count: %x, rx_count: %x, "
|
||||||
|
"int_alg: %d, enc_alg: %d\n",
|
||||||
|
ctxt.ksi, hex_to_string(ctxt.k_asme,32).c_str(),
|
||||||
|
ctxt.tx_count, ctxt.rx_count,
|
||||||
|
ctxt.integ_algo, ctxt.cipher_algo);
|
||||||
|
file.close();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace srsue
|
} // namespace srsue
|
||||||
|
|
|
@ -27,8 +27,9 @@
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
#include "upper/rrc.h"
|
#include "upper/rrc.h"
|
||||||
#include "srslte/asn1/liblte_rrc.h"
|
#include "srslte/asn1/liblte_rrc.h"
|
||||||
#include "srslte/common/security.h"
|
#include "srslte/common/security.h"
|
||||||
|
@ -99,7 +100,6 @@ void rrc::init(phy_interface_rrc *phy_,
|
||||||
args.supported_bands[0] = 7;
|
args.supported_bands[0] = 7;
|
||||||
args.nof_supported_bands = 1;
|
args.nof_supported_bands = 1;
|
||||||
args.feature_group = 0xe6041c00;
|
args.feature_group = 0xe6041c00;
|
||||||
args.stmsi_attach = false;
|
|
||||||
|
|
||||||
t301 = mac_timers->timer_get_unique_id();
|
t301 = mac_timers->timer_get_unique_id();
|
||||||
t310 = mac_timers->timer_get_unique_id();
|
t310 = mac_timers->timer_get_unique_id();
|
||||||
|
@ -117,6 +117,9 @@ void rrc::init(phy_interface_rrc *phy_,
|
||||||
set_rrc_default();
|
set_rrc_default();
|
||||||
set_phy_default();
|
set_phy_default();
|
||||||
set_mac_default();
|
set_mac_default();
|
||||||
|
|
||||||
|
// set seed for rand (used in attach)
|
||||||
|
srand(time(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrc::stop() {
|
void rrc::stop() {
|
||||||
|
@ -592,66 +595,6 @@ void rrc::timer_expired(uint32_t timeout_id) {
|
||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
bool rrc::read_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
|
|
||||||
std::ifstream file;
|
|
||||||
std::string line;
|
|
||||||
if (!s_tmsi) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *mmec_str = "mmec=";
|
|
||||||
size_t mmec_str_len = strlen(mmec_str);
|
|
||||||
const char *mtmsi_str = "mtmsi=";
|
|
||||||
size_t mtmsi_str_len = strlen(mtmsi_str);
|
|
||||||
|
|
||||||
file.open(".stmsi", std::ios::in);
|
|
||||||
if (file.is_open()) {
|
|
||||||
bool read_ok = true;
|
|
||||||
if (std::getline(file, line)) {
|
|
||||||
if (!line.substr(0,mmec_str_len).compare(mmec_str)) {
|
|
||||||
s_tmsi->mmec = atoi(line.substr(5).c_str());
|
|
||||||
} else {
|
|
||||||
read_ok = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
read_ok = false;
|
|
||||||
}
|
|
||||||
if (std::getline(file, line)) {
|
|
||||||
if (!line.substr(0,mtmsi_str_len).compare(mtmsi_str)) {
|
|
||||||
s_tmsi->m_tmsi = atoi(line.substr(mtmsi_str_len).c_str());
|
|
||||||
} else {
|
|
||||||
read_ok = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
read_ok = false;
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
if (read_ok) {
|
|
||||||
rrc_log->info("Read S-TMSI value: %x:%x\n", s_tmsi->mmec, s_tmsi->m_tmsi);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
rrc_log->error("Invalid s-tmsi persistent file format\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rrc::write_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) {
|
|
||||||
std::ofstream file;
|
|
||||||
file.open(".stmsi", std::ios::out | std::ios::trunc);
|
|
||||||
if (file.is_open()) {
|
|
||||||
file << "mmec=" << (int) s_tmsi.mmec << std::endl;
|
|
||||||
file << "mtmsi=" << (int) s_tmsi.m_tmsi << std::endl;
|
|
||||||
rrc_log->info("Saved S-TMSI in persistent file: %x:%x\n", s_tmsi.mmec, s_tmsi.m_tmsi);
|
|
||||||
file.close();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rrc::send_con_request() {
|
void rrc::send_con_request() {
|
||||||
rrc_log->debug("Preparing RRC Connection Request\n");
|
rrc_log->debug("Preparing RRC Connection Request\n");
|
||||||
LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg;
|
LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg;
|
||||||
|
@ -659,30 +602,13 @@ void rrc::send_con_request() {
|
||||||
|
|
||||||
// Prepare ConnectionRequest packet
|
// Prepare ConnectionRequest packet
|
||||||
ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ;
|
ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ;
|
||||||
bool valid_stmsi = false;
|
|
||||||
|
|
||||||
if (nas->get_s_tmsi(&s_tmsi) || (args.stmsi_attach && !first_stimsi_attempt)) {
|
if (nas->get_s_tmsi(&s_tmsi)) {
|
||||||
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI;
|
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI;
|
||||||
if (nas->get_s_tmsi(&s_tmsi)) {
|
ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi;
|
||||||
ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi;
|
} else {
|
||||||
valid_stmsi = true;
|
|
||||||
} else {
|
|
||||||
first_stimsi_attempt = true;
|
|
||||||
if (args.stmsi_value.m_tmsi) {
|
|
||||||
ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = args.stmsi_value;
|
|
||||||
valid_stmsi = true;
|
|
||||||
} else {
|
|
||||||
if (!read_stimsi_file(&ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi)) {
|
|
||||||
rrc_log->warning("Could not read S-TMSI from persistent file. Trying normal attach.\n");
|
|
||||||
} else {
|
|
||||||
valid_stmsi = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!valid_stmsi) {
|
|
||||||
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE;
|
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE;
|
||||||
ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000;
|
ul_ccch_msg.msg.rrc_con_req.ue_id.random = rand() % 2^40;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING;
|
ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING;
|
||||||
|
@ -956,14 +882,6 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU
|
||||||
nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes;
|
nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes;
|
||||||
nas->write_pdu(lcid, nas_sdu);
|
nas->write_pdu(lcid, nas_sdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get S-TMSI from NAS and store it in persistent file
|
|
||||||
LIBLTE_RRC_S_TMSI_STRUCT s_tmsi;
|
|
||||||
if (nas->get_s_tmsi(&s_tmsi)) {
|
|
||||||
if (!write_stimsi_file(s_tmsi)) {
|
|
||||||
rrc_log->warning("Could not store S-TMSI in persistent file\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */
|
/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */
|
||||||
|
@ -1247,7 +1165,9 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) {
|
||||||
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg;
|
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg;
|
||||||
|
|
||||||
// Configure PDCP for security
|
// Configure PDCP for security
|
||||||
usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo);
|
uint8_t k_asme[32];
|
||||||
|
nas->get_k_asme(k_asme, 32);
|
||||||
|
usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo);
|
||||||
pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo);
|
pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo);
|
||||||
send_security_mode_complete(lcid, pdu);
|
send_security_mode_complete(lcid, pdu);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -39,9 +39,11 @@ usim::usim() : initiated(false)
|
||||||
void usim::init(usim_args_t *args, srslte::log *usim_log_)
|
void usim::init(usim_args_t *args, srslte::log *usim_log_)
|
||||||
{
|
{
|
||||||
usim_log = usim_log_;
|
usim_log = usim_log_;
|
||||||
|
imsi_str = args->imsi;
|
||||||
|
imei_str = args->imei;
|
||||||
|
|
||||||
const char *imsi_str = args->imsi.c_str();
|
const char *imsi_c = args->imsi.c_str();
|
||||||
const char *imei_str = args->imei.c_str();
|
const char *imei_c = args->imei.c_str();
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
if(32 == args->op.length()) {
|
if(32 == args->op.length()) {
|
||||||
|
@ -63,7 +65,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_)
|
||||||
for(i=0; i<15; i++)
|
for(i=0; i<15; i++)
|
||||||
{
|
{
|
||||||
imsi *= 10;
|
imsi *= 10;
|
||||||
imsi += imsi_str[i] - '0';
|
imsi += imsi_c[i] - '0';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
usim_log->error("Invalid length for ISMI: %d should be %d", args->imsi.length(), 15);
|
usim_log->error("Invalid length for ISMI: %d should be %d", args->imsi.length(), 15);
|
||||||
|
@ -75,7 +77,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_)
|
||||||
for(i=0; i<15; i++)
|
for(i=0; i<15; i++)
|
||||||
{
|
{
|
||||||
imei *= 10;
|
imei *= 10;
|
||||||
imei += imei_str[i] - '0';
|
imei += imei_c[i] - '0';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15);
|
usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15);
|
||||||
|
@ -103,16 +105,25 @@ void usim::stop()
|
||||||
NAS interface
|
NAS interface
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
|
std::string usim::get_imsi_str()
|
||||||
|
{
|
||||||
|
return imsi_str;
|
||||||
|
}
|
||||||
|
std::string usim::get_imei_str()
|
||||||
|
{
|
||||||
|
return imei_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
|
||||||
{
|
{
|
||||||
if (!initiated) {
|
if (!initiated) {
|
||||||
fprintf(stderr, "USIM not initiated!\n");
|
fprintf(stderr, "USIM not initiated!\n");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NULL == imsi_ || n < 15) {
|
if(NULL == imsi_ || n < 15) {
|
||||||
usim_log->error("Invalid parameters to get_imsi_vec");
|
usim_log->error("Invalid parameters to get_imsi_vec");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t temp = imsi;
|
uint64_t temp = imsi;
|
||||||
|
@ -120,18 +131,19 @@ void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
|
||||||
imsi_[i] = temp % 10;
|
imsi_[i] = temp % 10;
|
||||||
temp /= 10;
|
temp /= 10;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
|
bool usim::get_imei_vec(uint8_t* imei_, uint32_t n)
|
||||||
{
|
{
|
||||||
if (!initiated) {
|
if (!initiated) {
|
||||||
fprintf(stderr, "USIM not initiated!\n");
|
fprintf(stderr, "USIM not initiated!\n");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NULL == imei_ || n < 15) {
|
if(NULL == imei_ || n < 15) {
|
||||||
usim_log->error("Invalid parameters to get_imei_vec");
|
usim_log->error("Invalid parameters to get_imei_vec");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 temp = imei;
|
uint64 temp = imei;
|
||||||
|
@ -140,13 +152,14 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
|
||||||
imei_[i] = temp % 10;
|
imei_[i] = temp % 10;
|
||||||
temp /= 10;
|
temp /= 10;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
|
bool usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
|
||||||
{
|
{
|
||||||
if (!initiated) {
|
if (!initiated) {
|
||||||
fprintf(stderr, "USIM not initiated!\n");
|
fprintf(stderr, "USIM not initiated!\n");
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mcc_len = 3;
|
int mcc_len = 3;
|
||||||
|
@ -180,7 +193,7 @@ int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
|
||||||
usim_log->info("Read Home PLMN Id=%s\n",
|
usim_log->info("Read Home PLMN Id=%s\n",
|
||||||
plmn_id_to_string(*home_plmn_id).c_str());
|
plmn_id_to_string(*home_plmn_id).c_str());
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usim::generate_authentication_response(uint8_t *rand,
|
void usim::generate_authentication_response(uint8_t *rand,
|
||||||
|
@ -188,16 +201,18 @@ void usim::generate_authentication_response(uint8_t *rand,
|
||||||
uint16_t mcc,
|
uint16_t mcc,
|
||||||
uint16_t mnc,
|
uint16_t mnc,
|
||||||
bool *net_valid,
|
bool *net_valid,
|
||||||
uint8_t *res)
|
uint8_t *res,
|
||||||
|
uint8_t *k_asme)
|
||||||
{
|
{
|
||||||
if(auth_algo_xor == auth_algo) {
|
if(auth_algo_xor == auth_algo) {
|
||||||
gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res);
|
gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res, k_asme);
|
||||||
} else {
|
} else {
|
||||||
gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res);
|
gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res, k_asme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void usim::generate_nas_keys(uint8_t *k_nas_enc,
|
void usim::generate_nas_keys(uint8_t *k_asme,
|
||||||
|
uint8_t *k_nas_enc,
|
||||||
uint8_t *k_nas_int,
|
uint8_t *k_nas_int,
|
||||||
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
|
||||||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
|
INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
|
||||||
|
@ -214,7 +229,8 @@ void usim::generate_nas_keys(uint8_t *k_nas_enc,
|
||||||
RRC interface
|
RRC interface
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
void usim::generate_as_keys(uint32_t count_ul,
|
void usim::generate_as_keys(uint8_t *k_asme,
|
||||||
|
uint32_t count_ul,
|
||||||
uint8_t *k_rrc_enc,
|
uint8_t *k_rrc_enc,
|
||||||
uint8_t *k_rrc_int,
|
uint8_t *k_rrc_int,
|
||||||
uint8_t *k_up_enc,
|
uint8_t *k_up_enc,
|
||||||
|
@ -251,7 +267,8 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
|
||||||
uint16_t mcc,
|
uint16_t mcc,
|
||||||
uint16_t mnc,
|
uint16_t mnc,
|
||||||
bool *net_valid,
|
bool *net_valid,
|
||||||
uint8_t *res)
|
uint8_t *res,
|
||||||
|
uint8_t *k_asme)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t sqn[6];
|
uint8_t sqn[6];
|
||||||
|
@ -320,7 +337,8 @@ void usim::gen_auth_res_xor(uint8_t *rand,
|
||||||
uint16_t mcc,
|
uint16_t mcc,
|
||||||
uint16_t mnc,
|
uint16_t mnc,
|
||||||
bool *net_valid,
|
bool *net_valid,
|
||||||
uint8_t *res)
|
uint8_t *res,
|
||||||
|
uint8_t *k_asme)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t sqn[6];
|
uint8_t sqn[6];
|
||||||
|
|
Loading…
Reference in New Issue