diff --git a/lib/include/srslte/interfaces/epc_interfaces.h b/lib/include/srslte/interfaces/epc_interfaces.h index 60238b7f9..703a59912 100644 --- a/lib/include/srslte/interfaces/epc_interfaces.h +++ b/lib/include/srslte/interfaces/epc_interfaces.h @@ -11,6 +11,7 @@ class hss_interface_s1ap { public: virtual bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres) = 0; + virtual bool gen_update_loc_answer(uint64_t imsi, uint8_t *qci) = 0; virtual bool resync_sqn(uint64_t imsi, uint8_t *auts) = 0; }; diff --git a/srsepc/hdr/hss/hss.h b/srsepc/hdr/hss/hss.h index 6679e737c..7160cb54d 100644 --- a/srsepc/hdr/hss/hss.h +++ b/srsepc/hdr/hss/hss.h @@ -78,6 +78,8 @@ public: void stop(void); bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres); + bool gen_update_loc_answer(uint64_t imsi, uint8_t* qci); + bool resync_sqn(uint64_t imsi, uint8_t *auts); private: diff --git a/srsepc/hdr/mme/s1ap_common.h b/srsepc/hdr/mme/s1ap_common.h index 7465f9696..1910bf2bd 100644 --- a/srsepc/hdr/mme/s1ap_common.h +++ b/srsepc/hdr/mme/s1ap_common.h @@ -111,7 +111,7 @@ typedef struct{ typedef struct{ uint8_t eksi; - uint8_t k_asme[32]; + uint8_t k_asme[32]; uint8_t xres[16]; //minimum 6, maximum 16 uint32_t dl_nas_count; uint32_t ul_nas_count; @@ -128,6 +128,7 @@ typedef struct{ typedef struct{ enum erab_state state; uint8_t erab_id; + uint8_t qci; srslte::gtpc_f_teid_ie enb_fteid; srslte::gtpc_f_teid_ie sgw_s1u_fteid; srslte::gtpc_pdn_address_allocation_ie pdn_addr_alloc; diff --git a/srsepc/src/hss/hss.cc b/srsepc/src/hss/hss.cc index 1cce6e652..3cb82e5d3 100644 --- a/srsepc/src/hss/hss.cc +++ b/srsepc/src/hss/hss.cc @@ -289,90 +289,8 @@ hss::gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t } -bool -hss::resync_sqn(uint64_t imsi, uint8_t *auts) -{ - bool ret = false; - switch (m_auth_algo) - { - case HSS_ALGO_XOR: - ret = resync_sqn_xor(imsi, auts); - break; - case HSS_ALGO_MILENAGE: - ret = resync_sqn_milenage(imsi, auts); - break; - } - increment_ue_sqn(imsi); - return ret; -} - -bool -hss::resync_sqn_xor(uint64_t imsi, uint8_t *auts) -{ - m_hss_log->error("XOR SQN synchronization not supported yet\n"); - m_hss_log->console("XOR SQNs synchronization not supported yet\n"); - return false; -} -bool -hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts) -{ - uint8_t last_rand[16]; - uint8_t ak[6]; - uint8_t mac_s[8]; - uint8_t sqn_ms_xor_ak[6]; - - uint8_t k[16]; - uint8_t amf[2]; - uint8_t opc[16]; - uint8_t sqn[6]; - - if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn)) - { - return false; - } - - get_last_rand(imsi, last_rand); - - for(int i=0; i<6; i++){ - sqn_ms_xor_ak[i] = auts[i]; - } - - for(int i=0; i<8; i++){ - mac_s[i] = auts[i+6]; - } - - m_hss_log->debug_hex(k, 16, "User Key : "); - m_hss_log->debug_hex(opc, 16, "User OPc : "); - m_hss_log->debug_hex(last_rand, 16, "User Last Rand : "); - m_hss_log->debug_hex(auts, 16, "AUTS : "); - m_hss_log->debug_hex(sqn_ms_xor_ak, 6, "SQN xor AK : "); - m_hss_log->debug_hex(mac_s, 8, "MAC : "); - - security_milenage_f5_star(k, opc, last_rand, ak); - m_hss_log->debug_hex(ak, 6, "Resynch AK : "); - - uint8_t sqn_ms[6]; - for(int i=0; i<6; i++){ - sqn_ms[i] = sqn_ms_xor_ak[i] ^ ak[i]; - } - m_hss_log->debug_hex(sqn_ms, 6, "SQN MS : "); - m_hss_log->debug_hex(sqn , 6, "SQN HE : "); - - m_hss_log->debug_hex(amf, 2, "AMF : "); - - uint8_t mac_s_tmp[8]; - - security_milenage_f1_star(k, opc, last_rand, sqn_ms, amf, mac_s_tmp); - - m_hss_log->debug_hex(mac_s_tmp, 8, "MAC calc : "); - - set_sqn(imsi, sqn_ms); - - return true; -} - bool hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres) { @@ -536,7 +454,7 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin mcc, mnc, k_asme); - + m_hss_log->debug("User MCC : %x MNC : %x \n", mcc, mnc); m_hss_log->debug_hex(k_asme, 32, "User k_asme : "); @@ -561,6 +479,23 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin return true; } +bool +hss::gen_update_loc_answer(uint64_t imsi, uint8_t* qci) +{ + std::map::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi); + if(ue_ctx_it == m_imsi_to_ue_ctx.end()) + { + m_hss_log->info("User not found. IMSI: %015lu\n",imsi); + m_hss_log->console("User not found. IMSI: %015lu\n",imsi); + return false; + } + hss_ue_ctx_t *ue_ctx = ue_ctx_it->second; + m_hss_log->info("Found User %015lu\n",imsi); + *qci = ue_ctx->qci; + return true; +} + + bool hss::get_k_amf_opc_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *opc, uint8_t *sqn) @@ -583,6 +518,90 @@ hss::get_k_amf_opc_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *opc, ui return true; } +bool +hss::resync_sqn(uint64_t imsi, uint8_t *auts) +{ + bool ret = false; + switch (m_auth_algo) + { + case HSS_ALGO_XOR: + ret = resync_sqn_xor(imsi, auts); + break; + case HSS_ALGO_MILENAGE: + ret = resync_sqn_milenage(imsi, auts); + break; + } + increment_ue_sqn(imsi); + return ret; +} + +bool +hss::resync_sqn_xor(uint64_t imsi, uint8_t *auts) +{ + m_hss_log->error("XOR SQN synchronization not supported yet\n"); + m_hss_log->console("XOR SQNs synchronization not supported yet\n"); + return false; +} + + +bool +hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts) +{ + uint8_t last_rand[16]; + uint8_t ak[6]; + uint8_t mac_s[8]; + uint8_t sqn_ms_xor_ak[6]; + + uint8_t k[16]; + uint8_t amf[2]; + uint8_t opc[16]; + uint8_t sqn[6]; + + if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn)) + { + return false; + } + + get_last_rand(imsi, last_rand); + + for(int i=0; i<6; i++){ + sqn_ms_xor_ak[i] = auts[i]; + } + + for(int i=0; i<8; i++){ + mac_s[i] = auts[i+6]; + } + + m_hss_log->debug_hex(k, 16, "User Key : "); + m_hss_log->debug_hex(opc, 16, "User OPc : "); + m_hss_log->debug_hex(last_rand, 16, "User Last Rand : "); + m_hss_log->debug_hex(auts, 16, "AUTS : "); + m_hss_log->debug_hex(sqn_ms_xor_ak, 6, "SQN xor AK : "); + m_hss_log->debug_hex(mac_s, 8, "MAC : "); + + security_milenage_f5_star(k, opc, last_rand, ak); + m_hss_log->debug_hex(ak, 6, "Resynch AK : "); + + uint8_t sqn_ms[6]; + for(int i=0; i<6; i++){ + sqn_ms[i] = sqn_ms_xor_ak[i] ^ ak[i]; + } + m_hss_log->debug_hex(sqn_ms, 6, "SQN MS : "); + m_hss_log->debug_hex(sqn , 6, "SQN HE : "); + + m_hss_log->debug_hex(amf, 2, "AMF : "); + + uint8_t mac_s_tmp[8]; + + security_milenage_f1_star(k, opc, last_rand, sqn_ms, amf, mac_s_tmp); + + m_hss_log->debug_hex(mac_s_tmp, 8, "MAC calc : "); + + set_sqn(imsi, sqn_ms); + + return true; +} + void hss::increment_ue_sqn(uint64_t imsi) { @@ -615,6 +634,7 @@ hss::increment_sqn(uint8_t *sqn, uint8_t *next_sqn) } return; } + void hss::set_sqn(uint64_t imsi, uint8_t *sqn) { @@ -670,7 +690,7 @@ bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx) m_hss_log->info("User not found. IMSI: %015lu\n",imsi); return false; } - + *ue_ctx = ue_ctx_it->second; return true; } @@ -715,15 +735,4 @@ hss::hex_string(uint8_t *hex, int size) } return ss.str(); } - /* -uint64_t -string_to_imsi() -{ - uint64_t imsi = 0; - for(int i=0;i<=14;i++){ - imsi += attach_req.eps_mobile_id.imsi[i]*std::pow(10,14-i); - } - return imsi; -} - */ } //namespace srsepc diff --git a/srsepc/src/mme/mme_gtpc.cc b/srsepc/src/mme/mme_gtpc.cc index 7c30bfa3b..631d0d76c 100644 --- a/srsepc/src/mme/mme_gtpc.cc +++ b/srsepc/src/mme/mme_gtpc.cc @@ -92,7 +92,7 @@ mme_gtpc::get_new_ctrl_teid() return m_next_ctrl_teid++; //FIXME Use a Id pool? } void -mme_gtpc::send_create_session_request(uint64_t imsi) +mme_gtpc::send_create_session_request(uint64_t imsi, uint8_t qci) { m_mme_gtpc_log->info("Sending Create Session Request.\n"); m_mme_gtpc_log->console("Sending Create Session Request.\n"); @@ -124,9 +124,14 @@ mme_gtpc::send_create_session_request(uint64_t imsi) // APN strncpy(cs_req->apn, m_s1ap->m_s1ap_args.mme_apn.c_str(), sizeof(cs_req->apn)-1); cs_req->apn[sizeof(cs_req->apn)-1] = 0; + // RAT Type //cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN; + //Bearer QoS + cs_req->eps_bearer_context_created.ebi = 5; + cs_req->eps_bearer_context_created.bearer_qos.qci=qci; + //Check whether this UE is already registed std::map::iterator it = m_imsi_to_gtpc_ctx.find(imsi); if(it != m_imsi_to_gtpc_ctx.end()) diff --git a/srsepc/src/mme/s1ap_nas_transport.cc b/srsepc/src/mme/s1ap_nas_transport.cc index fd28c0c7b..ec65ce8d1 100644 --- a/srsepc/src/mme/s1ap_nas_transport.cc +++ b/srsepc/src/mme/s1ap_nas_transport.cc @@ -227,9 +227,8 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA (msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY)) { //Only identity response and authentication response are valid as plain NAS. - //Sometimes authentication response and identity are sent as integrity protected, + //Sometimes authentication response/failure and identity response are sent as integrity protected, //but these messages are sent when the securty context is not setup yet, so we cannot integrity check it. - //FIXME Double-check switch(msg_type) { case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE: @@ -1082,9 +1081,13 @@ s1ap_nas_transport::handle_nas_security_mode_complete(srslte::byte_buffer_t *nas } else { + //Get subscriber info from HSS + uint8_t qci; + m_hss->gen_update_loc_answer(emm_ctx->imsi,&qci); + m_s1ap_log->console("QCI %d\n", qci); //FIXME The packging of GTP-C messages is not ready. //This means that GTP-U tunnels are created with function calls, as opposed to GTP-C. - m_mme_gtpc->send_create_session_request(emm_ctx->imsi); + m_mme_gtpc->send_create_session_request(emm_ctx->imsi,qci); *reply_flag = false; //No reply needed } return true; diff --git a/srsepc/src/spgw/spgw.cc b/srsepc/src/spgw/spgw.cc index cbd3e524b..40dc0b97f 100644 --- a/srsepc/src/spgw/spgw.cc +++ b/srsepc/src/spgw/spgw.cc @@ -537,6 +537,10 @@ spgw::handle_create_session_request(struct srslte::gtpc_create_session_request * cs_resp->eps_bearer_context_created.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED; cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present=true; cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid = tunnel_ctx->up_user_fteid; + + //Bearer QoS + cs_resp->eps_bearer_context_created.bearer_qos.qci = cs_req->eps_bearer_context_created.bearer_qos.qci; + //Fill in the PAA cs_resp->paa_present = true; cs_resp->paa.pdn_type = srslte::GTPC_PDN_TYPE_IPV4;