Merging David Ruprecth's mme_msg_encryption branch into next. Not compiling.

master
Pedro Alvarez 6 years ago
commit 31a25067f5

@ -13,6 +13,10 @@
# apn: Set Access Point Name (APN) # apn: Set Access Point Name (APN)
# mme_bind_addr: IP bind addr to listen for eNB S1-MME connnections # mme_bind_addr: IP bind addr to listen for eNB S1-MME connnections
# dns_addr: DNS server address for the UEs # dns_addr: DNS server address for the UEs
# encryption_algo: Preferred encryption algorithm for NAS layer
# (default: EEA0, support: EEA1, EEA2)
# integrity_algo: Preferred integrity protection algorithm for NAS
# (default: EIA1, support: EIA1, EIA2 (EIA0 not support)
# #
##################################################################### #####################################################################
[mme] [mme]
@ -24,6 +28,8 @@ mnc = 01
mme_bind_addr = 127.0.1.100 mme_bind_addr = 127.0.1.100
apn = srsapn apn = srsapn
dns_addr = 8.8.8.8 dns_addr = 8.8.8.8
encryption_algo = EEA0
integrity_algo = EIA1
##################################################################### #####################################################################
# HSS configuration # HSS configuration

@ -245,29 +245,34 @@ public:
srslte::log *nas_log); srslte::log *nas_log);
/* Uplink NAS messages handling */ /* Uplink NAS messages handling */
bool handle_authentication_response (srslte::byte_buffer_t *nas_rx); bool handle_authentication_response(srslte::byte_buffer_t* nas_rx);
bool handle_security_mode_complete (srslte::byte_buffer_t *nas_rx); bool handle_security_mode_complete(srslte::byte_buffer_t* nas_rx);
bool handle_attach_complete (srslte::byte_buffer_t *nas_rx); bool handle_attach_complete(srslte::byte_buffer_t* nas_rx);
bool handle_esm_information_response (srslte::byte_buffer_t *nas_rx); bool handle_esm_information_response(srslte::byte_buffer_t* nas_rx);
bool handle_identity_response (srslte::byte_buffer_t *nas_rx); bool handle_identity_response(srslte::byte_buffer_t* nas_rx);
bool handle_tracking_area_update_request (srslte::byte_buffer_t *nas_rx); bool handle_tracking_area_update_request(srslte::byte_buffer_t* nas_rx);
bool handle_authentication_failure (srslte::byte_buffer_t *nas_rx); bool handle_authentication_failure(srslte::byte_buffer_t* nas_rx);
bool handle_detach_request (srslte::byte_buffer_t *nas_rx); bool handle_detach_request(srslte::byte_buffer_t* nas_rx);
/* Downlink NAS messages packing */ /* Downlink NAS messages packing */
bool pack_authentication_request (srslte::byte_buffer_t *nas_buffer); bool pack_authentication_request(srslte::byte_buffer_t* nas_buffer);
bool pack_authentication_reject (srslte::byte_buffer_t *nas_buffer); bool pack_authentication_reject(srslte::byte_buffer_t* nas_buffer);
bool pack_security_mode_command (srslte::byte_buffer_t *nas_buffer); bool pack_security_mode_command(srslte::byte_buffer_t* nas_buffer);
bool pack_esm_information_request (srslte::byte_buffer_t *nas_buffer); bool pack_esm_information_request(srslte::byte_buffer_t* nas_buffer);
bool pack_identity_request (srslte::byte_buffer_t *nas_buffer); bool pack_identity_request(srslte::byte_buffer_t* nas_buffer);
bool pack_emm_information (srslte::byte_buffer_t *nas_buffer); bool pack_emm_information(srslte::byte_buffer_t* nas_buffer);
bool pack_service_reject (srslte::byte_buffer_t *nas_buffer); bool pack_service_reject(srslte::byte_buffer_t* nas_buffer);
bool pack_attach_accept (srslte::byte_buffer_t *nas_buffer); bool pack_attach_accept(srslte::byte_buffer_t* nas_buffer);
/* Security functions */ /* Security functions */
bool integrity_check (srslte::byte_buffer_t *pdu); bool integrity_check (srslte::byte_buffer_t *pdu);
bool short_integrity_check (srslte::byte_buffer_t *pdu); bool short_integrity_check (srslte::byte_buffer_t *pdu);
void cipher_decrypt(eps_sec_ctx_t* sec_ctxt, srslte::byte_buffer_t* pdu);
void cipher_encrypt(eps_sec_ctx_t* sec_ctxt, srslte::byte_buffer_t* pdu);
void integrity_generate(eps_sec_ctx_t* sec_ctxt, srslte::byte_buffer_t* pdu, uint8_t* mac);
/* UE Context */ /* UE Context */
emm_ctx_t m_emm_ctx; emm_ctx_t m_emm_ctx;
ecm_ctx_t m_ecm_ctx; ecm_ctx_t m_ecm_ctx;

@ -44,6 +44,8 @@ typedef struct{
std::string mme_apn; std::string mme_apn;
bool pcap_enable; bool pcap_enable;
std::string pcap_filename; std::string pcap_filename;
srslte::CIPHERING_ALGORITHM_ID_ENUM encryption_algo;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integrity_algo;
} s1ap_args_t; } s1ap_args_t;
typedef struct{ typedef struct{

@ -38,47 +38,29 @@ namespace srsepc{
class s1ap_nas_transport class s1ap_nas_transport
{ {
public: public:
static s1ap_nas_transport* m_instance; static s1ap_nas_transport* m_instance;
static s1ap_nas_transport* get_instance(void); static s1ap_nas_transport* get_instance(void);
static void cleanup(void); static void cleanup(void);
void init(hss_interface_nas * hss_); void init(hss_interface_nas * hss_);
bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag); bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT* init_ue, struct sctp_sndrcvinfo* enb_sri,
bool handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag); srslte::byte_buffer_t* reply_buffer, bool* reply_flag);
bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri); bool handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT* ul_xport,
struct sctp_sndrcvinfo* enb_sri, srslte::byte_buffer_t* reply_buffer,
bool handle_nas_detach_request( uint32_t m_tmsi, bool* reply_flag);
uint32_t enb_ue_s1ap_id, bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t* nas_msg,
srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri);
srslte::byte_buffer_t *reply_buffer,
bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_service_request( uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
srslte::byte_buffer_t *nas_msg,
srslte::byte_buffer_t *reply_buffer,
bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_tracking_area_update_request( uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
srslte::byte_buffer_t *nas_msg,
srslte::byte_buffer_t *reply_buffer,
bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri);
private: private:
s1ap_nas_transport(); s1ap_nas_transport();
virtual ~s1ap_nas_transport(); virtual ~s1ap_nas_transport();
srslte::log *m_s1ap_log; srslte::log* m_s1ap_log;
srslte::byte_buffer_pool *m_pool; srslte::byte_buffer_pool* m_pool;
s1ap* m_s1ap;
hss_interface_nas* m_hss;
mme_gtpc* m_mme_gtpc;
s1ap* m_s1ap;
hss_interface_nas* m_hss;
mme_gtpc* m_mme_gtpc;
}; };
} //namespace srsepc } //namespace srsepc
#endif // SRSEPC_S1AP_NAS_TRANSPORT_H #endif // SRSEPC_S1AP_NAS_TRANSPORT_H

@ -87,6 +87,8 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
string mnc; string mnc;
string mme_bind_addr; string mme_bind_addr;
string mme_apn; string mme_apn;
string encryption_algo;
string integrity_algo;
string spgw_bind_addr; string spgw_bind_addr;
string sgi_if_addr; string sgi_if_addr;
string sgi_if_name; string sgi_if_name;
@ -115,6 +117,8 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"), "IP address of MME for S1 connection") ("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"), "IP address of MME for S1 connection")
("mme.dns_addr", bpo::value<string>(&dns_addr)->default_value("8.8.8.8"), "IP address of the DNS server for the UEs") ("mme.dns_addr", bpo::value<string>(&dns_addr)->default_value("8.8.8.8"), "IP address of the DNS server for the UEs")
("mme.apn", bpo::value<string>(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services") ("mme.apn", bpo::value<string>(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services")
("mme.encryption_algo", bpo::value<string>(&encryption_algo)->default_value("EEA0"), "Set preferred encryption algorithm for NAS layer ")
("mme.integrity_algo", bpo::value<string>(&integrity_algo)->default_value("EIA1"), "Set preferred integrity protection algorithm for NAS")
("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"), ".csv file that stores UE's keys") ("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"), ".csv file that stores UE's keys")
("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"), "HSS uthentication algorithm.") ("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"), "HSS uthentication algorithm.")
("spgw.gtpu_bind_addr", bpo::value<string>(&spgw_bind_addr)->default_value("127.0.0.1"), "IP address of SP-GW for the S1-U connection") ("spgw.gtpu_bind_addr", bpo::value<string>(&spgw_bind_addr)->default_value("127.0.0.1"), "IP address of SP-GW for the S1-U connection")
@ -219,6 +223,31 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
cout << "Error parsing mme.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl; cout << "Error parsing mme.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
} }
if(boost::iequals(encryption_algo, "eea0")){
args->mme_args.s1ap_args.encryption_algo = srslte::CIPHERING_ALGORITHM_ID_EEA0;
} else if (boost::iequals(encryption_algo, "eea1")){
args->mme_args.s1ap_args.encryption_algo = srslte::CIPHERING_ALGORITHM_ID_128_EEA1;
} else if (boost::iequals(encryption_algo, "eea2")){
args->mme_args.s1ap_args.encryption_algo = srslte::CIPHERING_ALGORITHM_ID_128_EEA2;
} else{
args->mme_args.s1ap_args.encryption_algo = srslte::CIPHERING_ALGORITHM_ID_EEA0;
cout << "Error parsing mme.encryption_algo:" << encryption_algo << " - must be EEA0, EEA1, or EEA2." << endl;
cout << "Using default mme.encryption_algo: EEA0" << endl;
}
if (boost::iequals(integrity_algo, "eia0")){
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_EIA0;
cout << "Warning parsing mme.integrity_algo:" << encryption_algo << " - EIA0 will not supported by UEs use EIA1 or EIA2" << endl;
} else if (boost::iequals(integrity_algo, "eia1")) {
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1;
} else if (boost::iequals(integrity_algo, "eia2")) {
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_128_EIA2;
} else {
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1;
cout << "Error parsing mme.integrity_algo:" << encryption_algo << " - must be EIA0, EIA1, or EIA2." << endl;
cout << "Using default mme.integrity_algo: EIA1" << endl;
}
args->mme_args.s1ap_args.mme_bind_addr = mme_bind_addr; args->mme_args.s1ap_args.mme_bind_addr = mme_bind_addr;
args->mme_args.s1ap_args.mme_name = mme_name; args->mme_args.s1ap_args.mme_name = mme_name;
args->mme_args.s1ap_args.dns_addr = dns_addr; args->mme_args.s1ap_args.dns_addr = dns_addr;

@ -33,158 +33,151 @@
namespace srsepc{ namespace srsepc{
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL; s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL;
pthread_mutex_t s1ap_ctx_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t s1ap_ctx_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_ctx_mngmt_proc::s1ap_ctx_mngmt_proc() {}
s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc() {}
s1ap_ctx_mngmt_proc::s1ap_ctx_mngmt_proc() s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance(void)
{
}
s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc()
{
}
s1ap_ctx_mngmt_proc*
s1ap_ctx_mngmt_proc::get_instance(void)
{ {
pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex); pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if(NULL == m_instance) { if (NULL == m_instance) {
m_instance = new s1ap_ctx_mngmt_proc(); m_instance = new s1ap_ctx_mngmt_proc();
} }
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex); pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
return(m_instance); return (m_instance);
} }
void void s1ap_ctx_mngmt_proc::cleanup(void)
s1ap_ctx_mngmt_proc::cleanup(void)
{ {
pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex); pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if(NULL != m_instance) { if (NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex); pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
} }
void void s1ap_ctx_mngmt_proc::init(void)
s1ap_ctx_mngmt_proc::init(void)
{ {
m_s1ap = s1ap::get_instance(); m_s1ap = s1ap::get_instance();
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log; m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1ap_args = m_s1ap->m_s1ap_args; m_s1ap_args = m_s1ap->m_s1ap_args;
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); m_s1ap_nas_transport = s1ap_nas_transport::get_instance();
} }
bool bool s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas* nas_ctx, uint16_t erab_to_setup)
s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas *nas_ctx, uint16_t erab_to_setup)
{ {
//Prepare reply PDU // Prepare reply PDU
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu; LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT)); bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &pdu.choice.initiatingMessage; LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* init = &pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP; init->procedureCode = LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST; init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST;
LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *in_ctxt_req = &init->choice.InitialContextSetupRequest; LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT* in_ctxt_req = &init->choice.InitialContextSetupRequest;
m_s1ap_log->info("Preparing to send Initial Context Setup request\n"); m_s1ap_log->info("Preparing to send Initial Context Setup request\n");
//Get UE Context/E-RAB Context to setup // Get UE Context/E-RAB Context to setup
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx; emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx; ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
esm_ctx_t *esm_ctx = &nas_ctx->m_esm_ctx[erab_to_setup]; esm_ctx_t* esm_ctx = &nas_ctx->m_esm_ctx[erab_to_setup];
sec_ctx_t *sec_ctx = &nas_ctx->m_sec_ctx; sec_ctx_t* sec_ctx = &nas_ctx->m_sec_ctx;
//Add MME and eNB S1AP Ids // Add MME and eNB S1AP Ids
in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ecm_ctx->mme_ue_s1ap_id; in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ecm_ctx->mme_ue_s1ap_id;
in_ctxt_req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ecm_ctx->enb_ue_s1ap_id; in_ctxt_req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ecm_ctx->enb_ue_s1ap_id;
//Set UE-AMBR // Set UE-AMBR
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL.BitRate=1000000000; in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL.BitRate = 1000000000;
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL.BitRate=1000000000; in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL.BitRate = 1000000000;
//Number of E-RABs to be setup // Number of E-RABs to be setup
in_ctxt_req->E_RABToBeSetupListCtxtSUReq.len = 1; in_ctxt_req->E_RABToBeSetupListCtxtSUReq.len = 1;
//Setup eRAB context // Setup eRAB context
LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab_ctx_req = &in_ctxt_req->E_RABToBeSetupListCtxtSUReq.buffer[0]; LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT* erab_ctx_req = &in_ctxt_req->E_RABToBeSetupListCtxtSUReq.buffer[0];
erab_ctx_req->e_RAB_ID.E_RAB_ID = esm_ctx->erab_id; erab_ctx_req->e_RAB_ID.E_RAB_ID = esm_ctx->erab_id;
//Setup E-RAB QoS parameters // Setup E-RAB QoS parameters
erab_ctx_req->e_RABlevelQoSParameters.qCI.QCI = esm_ctx->qci; erab_ctx_req->e_RABlevelQoSParameters.qCI.QCI = esm_ctx->qci;
erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel.PriorityLevel = 15 ;//Lowest erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel.PriorityLevel = 15; // Lowest
erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability = LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION; erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability =
erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability = LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_PRE_EMPTABLE; LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION;
erab_ctx_req->e_RABlevelQoSParameters.gbrQosInformation_present=false; erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability =
LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_PRE_EMPTABLE;
//Set E-RAB S-GW F-TEID erab_ctx_req->e_RABlevelQoSParameters.gbrQosInformation_present = false;
erab_ctx_req->transportLayerAddress.n_bits = 32; //IPv4
uint32_t sgw_s1u_ip = htonl(esm_ctx->sgw_s1u_fteid.ipv4); // Set E-RAB S-GW F-TEID
uint8_t *tmp_ptr = erab_ctx_req->transportLayerAddress.buffer; erab_ctx_req->transportLayerAddress.n_bits = 32; // IPv4
uint32_t sgw_s1u_ip = htonl(esm_ctx->sgw_s1u_fteid.ipv4);
uint8_t* tmp_ptr = erab_ctx_req->transportLayerAddress.buffer;
liblte_value_2_bits(sgw_s1u_ip, &tmp_ptr, 32); liblte_value_2_bits(sgw_s1u_ip, &tmp_ptr, 32);
uint32_t sgw_s1u_teid = esm_ctx->sgw_s1u_fteid.teid; uint32_t sgw_s1u_teid = esm_ctx->sgw_s1u_fteid.teid;
srslte::uint32_to_uint8(sgw_s1u_teid,erab_ctx_req->gTP_TEID.buffer); srslte::uint32_to_uint8(sgw_s1u_teid, erab_ctx_req->gTP_TEID.buffer);
//Set UE security capabilities and k_enb // Set UE security capabilities and k_enb
bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16); bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer, sizeof(uint8_t) * 16);
bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16); bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer, sizeof(uint8_t) * 16);
for (int i = 0; i<3; i++) { for (int i = 0; i < 3; i++) {
if(sec_ctx->ue_network_cap.eea[i+1] == true){ if (sec_ctx->ue_network_cap.eea[i + 1] == true) {
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; //EEA supported in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; // EEA supported
} else { } else {
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 0; //EEA not supported in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 0; // EEA not supported
} }
if(sec_ctx->ue_network_cap.eia[i+1] == true){ if (sec_ctx->ue_network_cap.eia[i + 1] == true) {
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; //EEA supported in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; // EEA supported
} else { } else {
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 0; //EEA not supported in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 0; // EEA not supported
} }
} }
//Get K eNB // Get K eNB
liblte_unpack(sec_ctx->k_enb, 32, in_ctxt_req->SecurityKey.buffer); liblte_unpack(sec_ctx->k_enb, 32, in_ctxt_req->SecurityKey.buffer);
m_s1ap_log->info_hex(sec_ctx->k_enb, 32, "Initial Context Setup Request -- Key eNB (k_enb)\n"); m_s1ap_log->info_hex(sec_ctx->k_enb, 32, "Initial Context Setup Request -- Key eNB (k_enb)\n");
srslte::byte_buffer_t *nas_buffer = m_pool->allocate(); srslte::byte_buffer_t* nas_buffer = m_pool->allocate();
if (emm_ctx->state == EMM_STATE_DEREGISTERED) { if (emm_ctx->state == EMM_STATE_DEREGISTERED) {
//Attach procedure initiated from an attach request // Attach procedure initiated from an attach request
m_s1ap_log->console("Adding attach accept to Initial Context Setup Request\n"); m_s1ap_log->console("Adding attach accept to Initial Context Setup Request\n");
m_s1ap_log->info("Adding attach accept to Initial Context Setup Request\n"); m_s1ap_log->info("Adding attach accept to Initial Context Setup Request\n");
nas_ctx->pack_attach_accept(nas_buffer); nas_ctx->pack_attach_accept(nas_buffer);
//Add nas message to context setup request // Add nas message to context setup request
erab_ctx_req->nAS_PDU_present = true; erab_ctx_req->nAS_PDU_present = true;
memcpy(erab_ctx_req->nAS_PDU.buffer, nas_buffer->msg, nas_buffer->N_bytes); memcpy(erab_ctx_req->nAS_PDU.buffer, nas_buffer->msg, nas_buffer->N_bytes);
erab_ctx_req->nAS_PDU.n_octets = nas_buffer->N_bytes; erab_ctx_req->nAS_PDU.n_octets = nas_buffer->N_bytes;
} }
srslte::byte_buffer_t *reply_buffer = m_pool->allocate(); srslte::byte_buffer_t* reply_buffer = m_pool->allocate();
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer); LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer);
if (err != LIBLTE_SUCCESS) { if (err != LIBLTE_SUCCESS) {
m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n"); m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n");
return false; return false;
} }
if (!m_s1ap->s1ap_tx_pdu(reply_buffer,&ecm_ctx->enb_sri)) { if (!m_s1ap->s1ap_tx_pdu(reply_buffer, &ecm_ctx->enb_sri)) {
m_s1ap_log->error("Error sending Initial Context Setup Request.\n"); m_s1ap_log->error("Error sending Initial Context Setup Request.\n");
return false; return false;
} }
//Change E-RAB state to Context Setup Requested and save S-GW control F-TEID // Change E-RAB state to Context Setup Requested and save S-GW control F-TEID
esm_ctx->state = ERAB_CTX_REQUESTED; esm_ctx->state = ERAB_CTX_REQUESTED;
struct in_addr addr; struct in_addr addr;
addr.s_addr = htonl(sgw_s1u_ip); addr.s_addr = htonl(sgw_s1u_ip);
m_s1ap_log->info("Sent Initial Context Setup Request. E-RAB id %d \n",erab_ctx_req->e_RAB_ID.E_RAB_ID); m_s1ap_log->info("Sent Initial Context Setup Request. E-RAB id %d \n", erab_ctx_req->e_RAB_ID.E_RAB_ID);
m_s1ap_log->info("Initial Context -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid,inet_ntoa(addr)); m_s1ap_log->info("Initial Context -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid, inet_ntoa(addr));
m_s1ap_log->console("Initial Context Setup Request -- eNB UE S1AP Id %d, MME UE S1AP Id %d\n",in_ctxt_req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID, in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID); m_s1ap_log->console("Initial Context Setup Request -- eNB UE S1AP Id %d, MME UE S1AP Id %d\n",
m_s1ap_log->console("Initial Context Setup Request -- E-RAB id %d\n",erab_ctx_req->e_RAB_ID.E_RAB_ID); in_ctxt_req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID, in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID);
m_s1ap_log->console("Initial Context Setup Request -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid,inet_ntoa(addr)); m_s1ap_log->console("Initial Context Setup Request -- E-RAB id %d\n", erab_ctx_req->e_RAB_ID.E_RAB_ID);
m_s1ap_log->console("Initial Context Setup Request -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid,inet_ntoa(addr)); m_s1ap_log->console("Initial Context Setup Request -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid, inet_ntoa(addr));
m_s1ap_log->console("Initial Context Setup Request -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid, inet_ntoa(addr));
m_s1ap_log->console("Initial Context Setup Request -- QCI %d \n", erab_ctx_req->e_RABlevelQoSParameters.qCI.QCI); m_s1ap_log->console("Initial Context Setup Request -- QCI %d \n", erab_ctx_req->e_RABlevelQoSParameters.qCI.QCI);
m_pool->deallocate(reply_buffer); m_pool->deallocate(reply_buffer);
@ -192,48 +185,47 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas *nas_ctx, uint16_t e
return true; return true;
} }
bool bool s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(
s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *in_ctxt_resp) LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT* in_ctxt_resp)
{ {
uint32_t mme_ue_s1ap_id = in_ctxt_resp->MME_UE_S1AP_ID.MME_UE_S1AP_ID; uint32_t mme_ue_s1ap_id = in_ctxt_resp->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
nas *nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id); nas* nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == NULL){ if (nas_ctx == NULL) {
m_s1ap_log->error("Could not find UE's context in active UE's map\n"); m_s1ap_log->error("Could not find UE's context in active UE's map\n");
return false; return false;
} }
emm_ctx_t * emm_ctx = &nas_ctx->m_emm_ctx; emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t * ecm_ctx = &nas_ctx->m_ecm_ctx; ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
m_s1ap_log->console("Received Initial Context Setup Response\n"); m_s1ap_log->console("Received Initial Context Setup Response\n");
//Setup E-RABs // Setup E-RABs
for (uint32_t i=0; i<in_ctxt_resp->E_RABSetupListCtxtSURes.len;i++) { for (uint32_t i = 0; i < in_ctxt_resp->E_RABSetupListCtxtSURes.len; i++) {
uint8_t erab_id = in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].e_RAB_ID.E_RAB_ID; uint8_t erab_id = in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].e_RAB_ID.E_RAB_ID;
esm_ctx_t *esm_ctx = &nas_ctx->m_esm_ctx[erab_id]; esm_ctx_t* esm_ctx = &nas_ctx->m_esm_ctx[erab_id];
if (esm_ctx->state != ERAB_CTX_REQUESTED) { if (esm_ctx->state != ERAB_CTX_REQUESTED) {
m_s1ap_log->error("E-RAB requested was not previously requested %d\n",erab_id); m_s1ap_log->error("E-RAB requested was not previously requested %d\n", erab_id);
return false; return false;
} }
//Mark E-RAB with context setup // Mark E-RAB with context setup
esm_ctx->state = ERAB_CTX_SETUP; esm_ctx->state = ERAB_CTX_SETUP;
//Set the GTP information // Set the GTP information
uint8_t *bit_ptr = in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].transportLayerAddress.buffer; uint8_t* bit_ptr = in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].transportLayerAddress.buffer;
esm_ctx->enb_fteid.ipv4 = htonl(liblte_bits_2_value(&bit_ptr,32)); esm_ctx->enb_fteid.ipv4 = htonl(liblte_bits_2_value(&bit_ptr, 32));
memcpy(&esm_ctx->enb_fteid.teid, in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].gTP_TEID.buffer, 4); memcpy(&esm_ctx->enb_fteid.teid, in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].gTP_TEID.buffer, 4);
esm_ctx->enb_fteid.teid = ntohl(esm_ctx->enb_fteid.teid); esm_ctx->enb_fteid.teid = ntohl(esm_ctx->enb_fteid.teid);
char enb_addr_str[INET_ADDRSTRLEN+1]; char enb_addr_str[INET_ADDRSTRLEN + 1];
const char *err = inet_ntop(AF_INET, &esm_ctx->enb_fteid.ipv4,enb_addr_str,sizeof(enb_addr_str)); const char* err = inet_ntop(AF_INET, &esm_ctx->enb_fteid.ipv4, enb_addr_str, sizeof(enb_addr_str));
if (err == NULL) { if (err == NULL) {
m_s1ap_log->error("Error converting IP to string\n"); m_s1ap_log->error("Error converting IP to string\n");
} }
m_s1ap_log->info("E-RAB Context Setup. E-RAB id %d\n", esm_ctx->erab_id);
m_s1ap_log->info("E-RAB Context Setup. E-RAB id %d\n",esm_ctx->erab_id);
m_s1ap_log->info("E-RAB Context -- eNB TEID 0x%x, eNB Address %s\n", esm_ctx->enb_fteid.teid, enb_addr_str); m_s1ap_log->info("E-RAB Context -- eNB TEID 0x%x, eNB Address %s\n", esm_ctx->enb_fteid.teid, enb_addr_str);
m_s1ap_log->console("E-RAB Context Setup. E-RAB id %d\n",esm_ctx->erab_id); m_s1ap_log->console("E-RAB Context Setup. E-RAB id %d\n", esm_ctx->erab_id);
m_s1ap_log->console("E-RAB Context -- eNB TEID 0x%x; eNB GTP-U Address %s\n", esm_ctx->enb_fteid.teid, enb_addr_str); m_s1ap_log->console("E-RAB Context -- eNB TEID 0x%x; eNB GTP-U Address %s\n", esm_ctx->enb_fteid.teid,
enb_addr_str);
} }
if (emm_ctx->state == EMM_STATE_REGISTERED) { if (emm_ctx->state == EMM_STATE_REGISTERED) {
@ -244,8 +236,9 @@ s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_I
return true; return true;
} }
bool bool s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT* ue_rel,
s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *ue_rel, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag) struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer, bool* reply_flag)
{ {
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT ue_rel_req; LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT ue_rel_req;
@ -294,28 +287,27 @@ s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECON
return true; return true;
} }
bool bool s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas* nas_ctx)
s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas *nas_ctx)
{ {
srslte::byte_buffer_t *reply_buffer = m_pool->allocate(); srslte::byte_buffer_t* reply_buffer = m_pool->allocate();
//Prepare reply PDU // Prepare reply PDU
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu; LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT)); bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &pdu.choice.initiatingMessage; LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* init = &pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE; init->procedureCode = LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASECOMMAND; init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASECOMMAND;
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT *ctx_rel_cmd = &init->choice.UEContextReleaseCommand; LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT* ctx_rel_cmd = &init->choice.UEContextReleaseCommand;
ctx_rel_cmd->UE_S1AP_IDs.choice_type = LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UE_S1AP_ID_PAIR; ctx_rel_cmd->UE_S1AP_IDs.choice_type = LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UE_S1AP_ID_PAIR;
ctx_rel_cmd->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID.MME_UE_S1AP_ID = nas_ctx->m_ecm_ctx.mme_ue_s1ap_id; ctx_rel_cmd->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID.MME_UE_S1AP_ID = nas_ctx->m_ecm_ctx.mme_ue_s1ap_id;
ctx_rel_cmd->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = nas_ctx->m_ecm_ctx.enb_ue_s1ap_id; ctx_rel_cmd->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = nas_ctx->m_ecm_ctx.enb_ue_s1ap_id;
ctx_rel_cmd->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_NAS; ctx_rel_cmd->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_NAS;
ctx_rel_cmd->Cause.choice.nas.ext = false; ctx_rel_cmd->Cause.choice.nas.ext = false;
ctx_rel_cmd->Cause.choice.nas.e = LIBLTE_S1AP_CAUSENAS_NORMAL_RELEASE; ctx_rel_cmd->Cause.choice.nas.e = LIBLTE_S1AP_CAUSENAS_NORMAL_RELEASE;
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer); LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer);
if (err != LIBLTE_SUCCESS) { if (err != LIBLTE_SUCCESS) {
@ -324,8 +316,8 @@ s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas *nas_ctx)
return false; return false;
} }
//Send Reply to eNB // Send Reply to eNB
if(!m_s1ap->s1ap_tx_pdu(reply_buffer,&nas_ctx->m_ecm_ctx.enb_sri)){ if (!m_s1ap->s1ap_tx_pdu(reply_buffer, &nas_ctx->m_ecm_ctx.enb_sri)) {
m_s1ap_log->error("Error sending UE Context Release Command.\n"); m_s1ap_log->error("Error sending UE Context Release Command.\n");
m_pool->deallocate(reply_buffer); m_pool->deallocate(reply_buffer);
return false; return false;
@ -335,8 +327,8 @@ s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas *nas_ctx)
return true; return true;
} }
bool bool s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(
s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *rel_comp) LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT* rel_comp)
{ {
uint32_t mme_ue_s1ap_id = rel_comp->MME_UE_S1AP_ID.MME_UE_S1AP_ID; uint32_t mme_ue_s1ap_id = rel_comp->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
m_s1ap_log->info("Received UE Context Release Complete. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id); m_s1ap_log->info("Received UE Context Release Complete. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
@ -351,14 +343,14 @@ s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECO
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx; emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx; ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx;
//Delete user plane context at the SPGW (but keep GTP-C connection). // Delete user plane context at the SPGW (but keep GTP-C connection).
if (ecm_ctx->state == ECM_STATE_CONNECTED) { if (ecm_ctx->state == ECM_STATE_CONNECTED) {
//There are active E-RABs, send release access mearers request // There are active E-RABs, send release access mearers request
m_s1ap_log->console("There are active E-RABs, send release access mearers request"); m_s1ap_log->console("There are active E-RABs, send release access bearers request");
m_s1ap_log->info("There are active E-RABs, send release access mearers request"); m_s1ap_log->info("There are active E-RABs, send release access bearers request");
m_mme_gtpc->send_release_access_bearers_request(emm_ctx->imsi); m_mme_gtpc->send_release_access_bearers_request(emm_ctx->imsi);
//The handle_releease_access_bearers_response function will make sure to mark E-RABS DEACTIVATED //The handle_release_access_bearers_response function will make sure to mark E-RABS DEACTIVATED
//It will release the UEs downstream S1-u and keep the upstream S1-U connection active. //It will release the UEs downstream S1-U and keep the upstream S1-U connection active.
} else { } else {
//No ECM Context to release //No ECM Context to release
m_s1ap_log->info("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id); m_s1ap_log->info("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id);
@ -375,6 +367,4 @@ s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECO
m_s1ap_log->console("UE Context Release Completed.\n"); m_s1ap_log->console("UE Context Release Completed.\n");
return true; return true;
} }
} //namespace srsepc } //namespace srsepc

@ -34,53 +34,45 @@
namespace srsepc{ namespace srsepc{
s1ap_nas_transport* s1ap_nas_transport::m_instance = NULL; s1ap_nas_transport* s1ap_nas_transport::m_instance = NULL;
pthread_mutex_t s1ap_nas_transport_instance_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t s1ap_nas_transport_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_nas_transport::s1ap_nas_transport() s1ap_nas_transport::s1ap_nas_transport() {}
{ s1ap_nas_transport::~s1ap_nas_transport() {}
}
s1ap_nas_transport::~s1ap_nas_transport()
{
}
s1ap_nas_transport* s1ap_nas_transport* s1ap_nas_transport::get_instance(void)
s1ap_nas_transport::get_instance(void)
{ {
pthread_mutex_lock(&s1ap_nas_transport_instance_mutex); pthread_mutex_lock(&s1ap_nas_transport_instance_mutex);
if(NULL == m_instance) { if (NULL == m_instance) {
m_instance = new s1ap_nas_transport(); m_instance = new s1ap_nas_transport();
} }
pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex); pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex);
return(m_instance); return (m_instance);
} }
void void s1ap_nas_transport::cleanup(void)
s1ap_nas_transport::cleanup(void)
{ {
pthread_mutex_lock(&s1ap_nas_transport_instance_mutex); pthread_mutex_lock(&s1ap_nas_transport_instance_mutex);
if(NULL != m_instance) { if (NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex); pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex);
} }
void void s1ap_nas_transport::init(hss_interface_nas* hss_)
s1ap_nas_transport::init(hss_interface_nas * hss_)
{ {
m_s1ap = s1ap::get_instance(); m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log; m_s1ap_log = m_s1ap->m_s1ap_log;
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
m_hss = hss_; m_hss = hss_;
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
} }
bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT* init_ue,
bool struct sctp_sndrcvinfo* enb_sri, srslte::byte_buffer_t* reply_buffer,
s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag) bool* reply_flag)
{ {
bool err, mac_valid; bool err, mac_valid;
uint8_t pd, msg_type, sec_hdr_type; uint8_t pd, msg_type, sec_hdr_type;
@ -106,73 +98,111 @@ s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSA
nas_init.dns = m_s1ap->m_s1ap_args.dns_addr; nas_init.dns = m_s1ap->m_s1ap_args.dns_addr;
if(init_ue->S_TMSI_present){ if(init_ue->S_TMSI_present){
m_tmsi = ntohl(*((uint32_t*) &init_ue->S_TMSI.m_TMSI.buffer)); m_tmsi = srslte::uint8_to_uint32(init_ue->S_TMSI.m_TMSI.buffer);
} }
switch (msg_type) switch (msg_type) {
{ case LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST:
case LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST: m_s1ap_log->console("Received Initial UE message -- Attach Request\n");
m_s1ap_log->console("Received Initial UE message -- Attach Request\n"); m_s1ap_log->info("Received Initial UE message -- Attach Request\n");
m_s1ap_log->info("Received Initial UE message -- Attach Request\n"); err = nas::handle_attach_request(enb_ue_s1ap_id, enb_sri, nas_msg, nas_init, m_s1ap, m_mme_gtpc, m_hss,
err = nas::handle_attach_request(enb_ue_s1ap_id, enb_sri, nas_msg, nas_init, m_s1ap->m_nas_log);
m_s1ap, m_mme_gtpc, m_hss, m_s1ap->m_nas_log); break;
break; case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST:
case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST: m_s1ap_log->console("Received Initial UE message -- Service Request\n");
m_s1ap_log->console("Received Initial UE message -- Service Request\n"); m_s1ap_log->info("Received Initial UE message -- Service Request\n");
m_s1ap_log->info("Received Initial UE message -- Service Request\n"); err = nas::handle_service_request(m_tmsi, enb_ue_s1ap_id, enb_sri, nas_msg, nas_init, m_s1ap, m_mme_gtpc, m_hss,
err = nas::handle_service_request(m_tmsi, enb_ue_s1ap_id, enb_sri, nas_msg, nas_init, m_s1ap->m_nas_log);
m_s1ap, m_mme_gtpc, m_hss, m_s1ap->m_nas_log); break;
break; case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST: m_s1ap_log->console("Received Initial UE message -- Detach Request\n");
m_s1ap_log->console("Received Initial UE message -- Detach Request\n"); m_s1ap_log->info("Received Initial UE message -- Detach Request\n");
m_s1ap_log->info("Received Initial UE message -- Detach Request\n"); err = nas::handle_detach_request(m_tmsi, enb_ue_s1ap_id, enb_sri, nas_msg, nas_init, m_s1ap, m_mme_gtpc, m_hss,
err = nas::handle_detach_request(m_tmsi, enb_ue_s1ap_id, enb_sri, nas_msg, nas_init, m_s1ap->m_nas_log);
m_s1ap, m_mme_gtpc, m_hss, m_s1ap->m_nas_log); break;
break; case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST:
case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST: m_s1ap_log->console("Received Initial UE message -- Tracking Area Update Request\n");
m_s1ap_log->console("Received Initial UE message -- Tracking Area Update Request\n"); m_s1ap_log->info("Received Initial UE message -- Tracking Area Update Request\n");
m_s1ap_log->info("Received Initial UE message -- Tracking Area Update Request\n"); err = nas::handle_tracking_area_update_request(m_tmsi, enb_ue_s1ap_id, enb_sri, nas_msg, nas_init, m_s1ap,
err = nas::handle_tracking_area_update_request(m_tmsi, enb_ue_s1ap_id, enb_sri, nas_msg, nas_init, m_mme_gtpc, m_hss, m_s1ap->m_nas_log);
m_s1ap, m_mme_gtpc, m_hss, m_s1ap->m_nas_log); break;
break; default:
default: m_s1ap_log->info("Unhandled Initial UE Message 0x%x \n", msg_type);
m_s1ap_log->info("Unhandled Initial UE Message 0x%x \n", msg_type); m_s1ap_log->console("Unhandled Initial UE Message 0x%x \n", msg_type);
m_s1ap_log->console("Unhandled Initial UE Message 0x%x \n", msg_type); err = false;
err = false;
} }
m_pool->deallocate(nas_msg); m_pool->deallocate(nas_msg);
return err; return err;
} }
bool bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT* ul_xport,
s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag) struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer, bool* reply_flag)
{ {
uint8_t pd, msg_type, sec_hdr_type; uint8_t pd, msg_type, sec_hdr_type;
uint32_t enb_ue_s1ap_id = ul_xport->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID; uint32_t enb_ue_s1ap_id = ul_xport->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID;
uint32_t mme_ue_s1ap_id = ul_xport->MME_UE_S1AP_ID.MME_UE_S1AP_ID; uint32_t mme_ue_s1ap_id = ul_xport->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
bool mac_valid = false; bool mac_valid = false;
bool increase_ul_nas_cnt = true;
//Get UE ECM context
nas *nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id); // Get UE NAS context
nas* nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == NULL) { if (nas_ctx == NULL) {
m_s1ap_log->warning("Received uplink NAS, but could not find UE NAS context. MME-UE S1AP id: %d\n",mme_ue_s1ap_id); m_s1ap_log->warning("Received uplink NAS, but could not find UE NAS context. MME-UE S1AP id: %d\n", mme_ue_s1ap_id);
return false; return false;
} }
m_s1ap_log->debug("Received uplink NAS and found UE NAS context. MME-UE S1AP id: %d\n",mme_ue_s1ap_id); m_s1ap_log->debug("Received uplink NAS and found UE NAS context. MME-UE S1AP id: %d\n", mme_ue_s1ap_id);
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx; emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx; ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
sec_ctx_t *sec_ctx = &nas_ctx->m_sec_ctx; sec_ctx_t* sec_ctx = &nas_ctx->m_sec_ctx;
//Parse NAS message header // Parse NAS message header
srslte::byte_buffer_t *nas_msg = m_pool->allocate(); srslte::byte_buffer_t* nas_msg = m_pool->allocate();
memcpy(nas_msg->msg, &ul_xport->NAS_PDU.buffer, ul_xport->NAS_PDU.n_octets); memcpy(nas_msg->msg, &ul_xport->NAS_PDU.buffer, ul_xport->NAS_PDU.n_octets);
nas_msg->N_bytes = ul_xport->NAS_PDU.n_octets; nas_msg->N_bytes = ul_xport->NAS_PDU.n_octets;
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &pd, &msg_type); bool msg_encrypted = false;
// Parse the message security header // Parse the message security header
liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &sec_hdr_type); liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &sec_hdr_type);
// Invalid Security Header Type simply return function
if (!(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT ||
sec_hdr_type ==LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT))
{
m_s1ap_log->error("Unhandled security header type in Uplink NAS Transport: %d\n", sec_hdr_type);
m_pool->deallocate(nas_msg);
return false;
}
// Todo: Check on count mismatch of uplink count and do resync nas counter...
// Check MAC if message is integrity protected
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT)
{
mac_valid = nas_ctx->integrity_check(nas_msg);
if (mac_valid == false){
m_s1ap_log->warning("Invalid MAC message. Even if security header indicates integrity protection (Maybe: Identity Response or Authenticatio Response)\n" );
}
}
// Decrypt message if indicated
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT)
{
nas_ctx->cipher_decrypt(nas_msg);
msg_encrypted = true;
}
// Now parse message header and handle message
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &pd, &msg_type);
//Find UE EMM context if message is security protected. //Find UE EMM context if message is security protected.
if (sec_hdr_type != LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS) { if (sec_hdr_type != LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS) {
//Make sure EMM context is set-up, to do integrity check/de-chiphering //Make sure EMM context is set-up, to do integrity check/de-chiphering
@ -187,122 +217,106 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA
} }
} }
if( sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS || // Handle message and check if security requirements for messages
(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) || // 4.4.4.3 Integrity checking of NAS signalling messages in the MME
(msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) || // Except the messages listed below, no NAS signalling messages shall be processed...
(msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY)) { // - ATTACH REQUEST;
// - IDENTITY RESPONSE (if requested identification parameter is IMSI);
//Only identity response and authentication response are valid as plain NAS. // - AUTHENTICATION RESPONSE;
//Sometimes authentication response/failure and identity response are sent as integrity protected, // - AUTHENTICATION FAILURE;
//but these messages are sent when the securty context is not setup yet, so we cannot integrity check it. // - SECURITY MODE REJECT;
switch(msg_type) // - DETACH REQUEST;
{ // - DETACH ACCEPT;
case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE: // - TRACKING AREA UPDATE REQUEST.
m_s1ap_log->info("Uplink NAS: Received Identity Response\n");
m_s1ap_log->console("Uplink NAS: Received Identity Response\n"); m_s1ap_log->info("UL NAS: sec_hdr_type: 0x%x, mac_vaild: %s, msg_encrypted: %s\n",sec_hdr_type, mac_valid == true ? "yes" : "no", msg_encrypted == true ? "yes" : "no");
nas_ctx->handle_identity_response(nas_msg); switch (msg_type)
break; {
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE: case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE:
m_s1ap_log->info("Uplink NAS: Received Authentication Response\n"); m_s1ap_log->info("UL NAS: Received Identity Response\n");
m_s1ap_log->console("Uplink NAS: Received Authentication Response\n"); m_s1ap_log->console("UL NAS: Received Identity Response\n");
nas_ctx->handle_authentication_response(nas_msg); nas_ctx->handle_identity_response(nas_msg);
break; break;
// Authentication failure with the option sync failure can be sent not integrity protected case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE:
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE: m_s1ap_log->info("UL NAS: Received Authentication Response\n");
m_s1ap_log->info("Plain UL NAS: Authentication Failure\n"); m_s1ap_log->console("UL NAS: Received Authentication Response\n");
m_s1ap_log->console("Plain UL NAS: Authentication Failure\n"); nas_ctx->handle_authentication_response(nas_msg);
nas_ctx->handle_authentication_failure(nas_msg); // In case of a successful authentication response, security mode command follows. Reset counter for incoming security mode complete
break; emm_ctx->security_ctxt.ul_nas_count = 0;
// Detach request can be sent not integrity protected when "power off" option is used emm_ctx->security_ctxt.dl_nas_count = 0;
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST: increase_ul_nas_cnt = false;
m_s1ap_log->info("Plain Protected UL NAS: Detach Request\n"); break;
m_s1ap_log->console("Plain Protected UL NAS: Detach Request\n"); // Authentication failure with the option sync failure can be sent not integrity protected
nas_ctx->handle_detach_request(nas_msg); case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
break; m_s1ap_log->info("UL NAS: Authentication Failure\n");
default: m_s1ap_log->console("UL NAS: Authentication Failure\n");
m_s1ap_log->warning("Unhandled Plain NAS message 0x%x\n", msg_type); handle_authentication_failure(nas_msg, ue_ctx, reply_buffer, reply_flag);
m_s1ap_log->console("Unhandled Plain NAS message 0x%x\n", msg_type); break;
m_pool->deallocate(nas_msg); // Detach request can be sent not integrity protected when "power off" option is used
return false; case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
} m_s1ap_log->info("UL NAS: Detach Request\n");
//Increment UL NAS count. m_s1ap_log->console("UL NAS: Detach Request\n");
sec_ctx->ul_nas_count++; // FIXME: check integrity protection in detach request
} else if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT || nas_ctx->handle_nas_detach_request(nas_msg);
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT) { break;
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE:
//Integrity Protected Messages, possibly chiphered, with new EPS context. m_s1ap_log->info("UL NAS: Received Security Mode Complete\n");
switch (msg_type) { m_s1ap_log->console("UL NAS: Received Security Mode Complete\n");
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE: if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT && mac_valid == true){
m_s1ap_log->info("Uplink NAS: Received Security Mode Complete\n"); handle_nas_security_mode_complete(nas_msg, ue_ctx, reply_buffer, reply_flag);
m_s1ap_log->console("Uplink NAS: Received Security Mode Complete\n"); } else {
sec_ctx->ul_nas_count = 0; // Security Mode Complete was not integrity protected
sec_ctx->dl_nas_count = 0; m_s1ap_log->console("Security Mode Complete not integrity protected. Discard message.\n");
mac_valid = nas_ctx->integrity_check(nas_msg); m_s1ap_log->warning("Security Mode Complete not integrity protected. Discard message.\n");
if(mac_valid){ increase_ul_nas_cnt = false;
nas_ctx->handle_security_mode_complete(nas_msg);
} else {
m_s1ap_log->warning("Invalid MAC in Security Mode Command Complete message.\n" );
}
break;
default:
m_s1ap_log->warning("Unhandled NAS message with new EPS security context 0x%x\n", msg_type );
m_s1ap_log->warning("Unhandled NAS message with new EPS security context 0x%x\n", msg_type );
} }
break;
} else if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY || case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE:
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED) { m_s1ap_log->info("UL NAS: Received Attach Complete\n");
m_s1ap_log->console("UL NAS: Received Attach Complete\n");
//Integrity protected NAS message, possibly ciphered. if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true){
sec_ctx->ul_nas_count++; handle_nas_attach_complete(nas_msg, ue_ctx, reply_buffer, reply_flag);
mac_valid = nas_ctx->integrity_check(nas_msg); } else {
if(!mac_valid){ // Attach Complete was not integrity protected
m_s1ap_log->warning("Invalid MAC in NAS message type 0x%x.\n", msg_type); m_s1ap_log->console("Attach Complete not integrity protected. Discard message.\n");
m_pool->deallocate(nas_msg); m_s1ap_log->warning("Attach Complete not integrity protected. Discard message.\n");
return false; increase_ul_nas_cnt = false;
} }
switch (msg_type) { break;
case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE: case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE:
m_s1ap_log->info("Integrity Protected UL NAS: Received Attach Complete\n"); m_s1ap_log->info("UL NAS: Received ESM Information Response\n");
m_s1ap_log->console("Integrity Protected UL NAS: Received Attach Complete\n"); m_s1ap_log->console("UL NAS: Received ESM Information Response\n");
nas_ctx->handle_attach_complete(nas_msg); if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true){
break; handle_esm_information_response(nas_msg, ue_ctx, reply_buffer, reply_flag);
case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE: } else {
m_s1ap_log->info("Integrity Protected UL NAS: Received ESM Information Response\n"); // Attach Complete was not integrity protected
m_s1ap_log->console("Integrity Protected UL NAS: Received ESM Information Response\n"); m_s1ap_log->console("ESM Information Response not integrity protected. Discard message.\n");
nas_ctx->handle_esm_information_response(nas_msg); m_s1ap_log->warning("ESM Information Response not integrity protected. Discard message.\n");
break; increase_ul_nas_cnt = false;
case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST:
m_s1ap_log->info("Integrity Protected UL NAS: Tracking Area Update Request\n");
m_s1ap_log->console("Integrity Protected UL NAS: Tracking Area Update Request\n");
nas_ctx->handle_tracking_area_update_request(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
m_s1ap_log->info("Integrity Protected UL NAS: Authentication Failure\n");
m_s1ap_log->console("Integrity Protected UL NAS: Authentication Failure\n");
nas_ctx->handle_authentication_failure(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
m_s1ap_log->info("Integrity Protected UL NAS: Detach Request\n");
m_s1ap_log->console("Integrity Protected UL NAS: Detach Request\n");
nas_ctx->handle_detach_request(nas_msg);
break;
default:
m_s1ap_log->warning("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type));
m_s1ap_log->console("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type));
m_pool->deallocate(nas_msg);
return false;
} }
} else { break;
m_s1ap_log->error("Unhandled security header type in Uplink NAS Transport: %d\n", sec_hdr_type); case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST:
m_s1ap_log->info("UL NAS: Tracking Area Update Request\n");
m_s1ap_log->console("UL NAS: Tracking Area Update Request\n");
handle_tracking_area_update_request(nas_msg, ue_ctx, reply_buffer, reply_flag);
break;
default:
m_s1ap_log->warning("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type));
m_s1ap_log->console("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type));
m_pool->deallocate(nas_msg); m_pool->deallocate(nas_msg);
return false; return false;
} }
//Increment UL NAS count. if counter not resetted in function, e.g., DL Security mode command after Authentication response
if (increase_ul_nas_cnt == true) {
emm_ctx->security_ctxt.ul_nas_count++;
}
m_pool->deallocate(nas_msg); m_pool->deallocate(nas_msg);
return true; return true;
} }
bool bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id,
s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri) srslte::byte_buffer_t* nas_msg, struct sctp_sndrcvinfo enb_sri)
{ {
//Allocate Reply buffer //Allocate Reply buffer
srslte::byte_buffer_t *reply_msg = m_pool->allocate(); srslte::byte_buffer_t *reply_msg = m_pool->allocate();
@ -343,4 +357,202 @@ s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_
return true; return true;
} }
//Security Functions
bool s1ap_nas_transport::short_integrity_check(eps_sec_ctx_t* sec_ctxt, srslte::byte_buffer_t* pdu)
{
uint8_t exp_mac[4] = {0x00, 0x00, 0x00, 0x00};
uint8_t *mac = &pdu->msg[2];
int i;
if(pdu->N_bytes < 4){
m_s1ap_log->warning("NAS message to short for short integrity check (pdu len: %d)", pdu->N_bytes);
return false;
}
switch (sec_ctxt->integ_algo)
{
case srslte::INTEGRITY_ALGORITHM_ID_EIA0:
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA1:
srslte::security_128_eia1(&sec_ctxt->k_nas_int[16],
sec_ctxt->ul_nas_count,
0,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[0],
2,
&exp_mac[0]);
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA2:
srslte::security_128_eia2(&sec_ctxt->k_nas_int[16],
sec_ctxt->ul_nas_count,
0,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[0],
2,
&exp_mac[0]);
break;
default:
break;
}
// Check if expected mac equals the sent mac
for(i=0; i<2; i++){
if(exp_mac[i+2] != mac[i]){
m_s1ap_log->warning("Short integrity check failure. Local: count=%d, [%02x %02x %02x %02x], "
"Received: count=%d, [%02x %02x]\n",
sec_ctxt->ul_nas_count, exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3],
pdu->msg[1] & 0x1F, mac[0], mac[1]);
return false;
}
}
m_s1ap_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n",
sec_ctxt->ul_nas_count, pdu->msg[1] & 0x1F);
return true;
}
bool s1ap_nas_transport::integrity_check(eps_sec_ctx_t *sec_ctxt, srslte::byte_buffer_t *pdu)
{
uint8_t exp_mac[4] = {0x00, 0x00, 0x00, 0x00};
uint8_t *mac = &pdu->msg[1];
int i;
switch (sec_ctxt->integ_algo)
{
case srslte::INTEGRITY_ALGORITHM_ID_EIA0:
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA1:
srslte::security_128_eia1(&sec_ctxt->k_nas_int[16],
sec_ctxt->ul_nas_count,
0,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[5],
pdu->N_bytes - 5,
&exp_mac[0]);
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA2:
srslte::security_128_eia2(&sec_ctxt->k_nas_int[16],
sec_ctxt->ul_nas_count,
0,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[5],
pdu->N_bytes - 5,
&exp_mac[0]);
break;
default:
break;
}
// Check if expected mac equals the sent mac
for (i = 0; i < 4; i++) {
if (exp_mac[i] != mac[i]) {
m_s1ap_log->warning("Integrity check failure. UL Local: count=%d, [%02x %02x %02x %02x], "
"Received: UL count=%d, [%02x %02x %02x %02x]\n",
sec_ctxt->ul_nas_count, exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3],
pdu->msg[5], mac[0], mac[1], mac[2], mac[3]);
return false;
}
}
m_s1ap_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n",
sec_ctxt->ul_nas_count, pdu->msg[5]);
return true;
}
void s1ap_nas_transport::cipher_decrypt(eps_sec_ctx_t * sec_ctxt, srslte::byte_buffer_t *pdu)
{
srslte::byte_buffer_t tmp_pdu;
switch(sec_ctxt->cipher_algo)
{
case srslte::CIPHERING_ALGORITHM_ID_EEA0:
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA1:
srslte::security_128_eea1(&sec_ctxt->k_nas_enc[16],
pdu->msg[5],
0, // Bearer always 0 for NAS
SECURITY_DIRECTION_UPLINK,
&pdu->msg[6],
pdu->N_bytes-6,
&tmp_pdu.msg[6]);
memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6);
m_s1ap_log->debug_hex(tmp_pdu.msg, pdu->N_bytes, "Decrypted");
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA2:
srslte::security_128_eea2(&sec_ctxt->k_nas_enc[16],
pdu->msg[5],
0, // Bearer always 0 for NAS
SECURITY_DIRECTION_UPLINK,
&pdu->msg[6],
pdu->N_bytes-6,
&tmp_pdu.msg[6]);
m_s1ap_log->debug_hex(tmp_pdu.msg, pdu->N_bytes, "Decrypted");
memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6);
break;
default:
m_s1ap_log->error("Ciphering algorithms not known\n");
break;
}
}
void s1ap_nas_transport::cipher_encrypt(eps_sec_ctx_t * sec_ctxt, srslte::byte_buffer_t *pdu)
{
srslte::byte_buffer_t pdu_tmp;
switch(sec_ctxt->cipher_algo)
{
case srslte::CIPHERING_ALGORITHM_ID_EEA0:
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA1:
srslte::security_128_eea1(&sec_ctxt->k_nas_enc[16],
pdu->msg[5],
0, // Bearer always 0 for NAS
SECURITY_DIRECTION_DOWNLINK,
&pdu->msg[6],
pdu->N_bytes-6,
&pdu_tmp.msg[6]);
memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6);
m_s1ap_log->debug_hex(pdu_tmp.msg, pdu->N_bytes, "Encrypted");
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA2:
srslte::security_128_eea2(&sec_ctxt->k_nas_enc[16],
pdu->msg[5],
0, // Bearer always 0 for NAS
SECURITY_DIRECTION_DOWNLINK,
&pdu->msg[6],
pdu->N_bytes-6,
&pdu_tmp.msg[6]);
memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6);
m_s1ap_log->debug_hex(pdu_tmp.msg, pdu->N_bytes, "Encrypted");
break;
default:
m_s1ap_log->error("Ciphering algorithm not known\n");
break;
}
}
void s1ap_nas_transport::integrity_generate(eps_sec_ctx_t *sec_ctxt,
srslte::byte_buffer_t *pdu,
uint8_t *mac) {
switch (sec_ctxt->integ_algo) {
case srslte::INTEGRITY_ALGORITHM_ID_EIA0:
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA1:
srslte::security_128_eia1(&sec_ctxt->k_nas_int[16],
sec_ctxt->dl_nas_count,
0, // Bearer always 0 for NAS
SECURITY_DIRECTION_DOWNLINK,
&pdu->msg[5],
pdu->N_bytes - 5,
mac);
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA2:
srslte::security_128_eia2(&sec_ctxt->k_nas_int[16],
sec_ctxt->dl_nas_count,
0, // Bearer always 0 for NAS
SECURITY_DIRECTION_DOWNLINK,
&pdu->msg[5],
pdu->N_bytes - 5,
mac);
break;
default:
break;
}
}
} //namespace srsepc } //namespace srsepc

Loading…
Cancel
Save