Merge pull request #313 from softwareradiosystems/next_mme_encryption

NAS MME encryption
master
Andre Puschmann 6 years ago committed by GitHub
commit 646eb9c0e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -90,10 +90,6 @@ PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left #Changed
RawStringFormats:
- Delimiter: pb
Language: TextProto
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true

@ -2492,6 +2492,8 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8
#define LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT 0x3
#define LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT 0x4
#define LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST 0xC
const char* liblte_nas_sec_hdr_type_to_string(int code);
//Message Type
#define LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST 0x41
#define LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT 0x42

@ -11210,6 +11210,20 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_disconnect_request_msg(LIBLTE_BYTE_MSG_S
/*******************************************************************************
HELPER FUNCTIONS
*******************************************************************************/
const char* liblte_nas_sec_hdr_type_to_string(int code)
{
switch(code)
{
LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS);
LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY);
LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED);
LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT);
LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT);
LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST);
default: return "NAS Message Type Unknown";
}
}
const char* liblte_nas_msg_type_to_string(int code)
{
switch(code)

@ -13,6 +13,10 @@
# apn: Set Access Point Name (APN)
# mme_bind_addr: IP bind addr to listen for eNB S1-MME connnections
# 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]
@ -24,6 +28,8 @@ mnc = 01
mme_bind_addr = 127.0.1.100
apn = srsapn
dns_addr = 8.8.8.8
encryption_algo = EEA0
integrity_algo = EIA1
#####################################################################
# HSS configuration

@ -142,6 +142,8 @@ typedef struct {
uint16_t tac;
std::string apn;
std::string dns;
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
} nas_init_t;
class nas
@ -245,28 +247,31 @@ public:
srslte::log *nas_log);
/* Uplink NAS messages handling */
bool handle_authentication_response (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_esm_information_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_authentication_failure (srslte::byte_buffer_t *nas_rx);
bool handle_detach_request (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_attach_complete(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_tracking_area_update_request(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);
/* Downlink NAS messages packing */
bool pack_authentication_request (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_esm_information_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_service_reject (srslte::byte_buffer_t *nas_buffer);
bool pack_attach_accept (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_security_mode_command(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_emm_information(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);
/* Security functions */
bool integrity_check (srslte::byte_buffer_t *pdu);
bool short_integrity_check (srslte::byte_buffer_t *pdu);
bool integrity_check(srslte::byte_buffer_t* pdu);
bool short_integrity_check(srslte::byte_buffer_t* pdu);
void integrity_generate(srslte::byte_buffer_t* pdu, uint8_t *mac);
void cipher_decrypt(srslte::byte_buffer_t* pdu);
void cipher_encrypt(srslte::byte_buffer_t* pdu);
/* UE Context */
emm_ctx_t m_emm_ctx;

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

@ -38,47 +38,29 @@ namespace srsepc{
class s1ap_nas_transport
{
public:
static s1ap_nas_transport* m_instance;
static s1ap_nas_transport* get_instance(void);
static void cleanup(void);
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_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, 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_nas_detach_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_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_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT* ul_xport,
struct sctp_sndrcvinfo* enb_sri, 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_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:
s1ap_nas_transport();
virtual ~s1ap_nas_transport();
srslte::log *m_s1ap_log;
srslte::byte_buffer_pool *m_pool;
s1ap* m_s1ap;
hss_interface_nas* m_hss;
mme_gtpc* m_mme_gtpc;
srslte::log* m_s1ap_log;
srslte::byte_buffer_pool* m_pool;
s1ap* m_s1ap;
hss_interface_nas* m_hss;
mme_gtpc* m_mme_gtpc;
};
} //namespace srsepc
#endif // SRSEPC_S1AP_NAS_TRANSPORT_H

@ -87,6 +87,8 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
string mnc;
string mme_bind_addr;
string mme_apn;
string encryption_algo;
string integrity_algo;
string spgw_bind_addr;
string sgi_if_addr;
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.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.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.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")
@ -170,7 +174,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
// if no config file given, check users home path
if (!vm.count("config_file")) {
if (!config_exists(config_file, "epc.conf")) {
cout << "Failed to read ePC configuration file " << config_file << " - exiting" << endl;
cout << "Failed to read EPC configuration file " << config_file << " - exiting" << endl;
exit(1);
}
}
@ -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;
}
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_name = mme_name;
args->mme_args.s1ap_args.dns_addr = dns_addr;

@ -52,7 +52,10 @@ nas::init(nas_init_t args,
m_tac = args.tac;
m_apn = args.apn;
m_dns = args.dns;
m_sec_ctx.integ_algo = args.integ_algo;
m_sec_ctx.cipher_algo = args.cipher_algo;
m_s1ap = s1ap;
m_gtpc = gtpc;
m_hss = hss;
@ -381,7 +384,6 @@ nas::handle_guti_attach_request_known_ue( nas *nas_ctx,
nas_log->console("Found UE context. IMSI: %015" PRIu64 ", old eNB UE S1ap Id %d, old MME UE S1AP Id %d\n", emm_ctx->imsi, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id);
//Check NAS integrity
sec_ctx->ul_nas_count++;
msg_valid = nas_ctx->integrity_check(nas_rx);
if (msg_valid == true && emm_ctx->state == EMM_STATE_DEREGISTERED) {
nas_log->console("GUTI Attach -- NAS Integrity OK. UL count %d, DL count %d\n",sec_ctx->ul_nas_count, sec_ctx->dl_nas_count);
@ -434,6 +436,7 @@ nas::handle_guti_attach_request_known_ue( nas *nas_ctx,
nas_log->console("Getting subscription information -- QCI %d\n", nas_ctx->m_esm_ctx[default_bearer].qci);
gtpc->send_create_session_request(emm_ctx->imsi);
}
sec_ctx->ul_nas_count++;
pool->deallocate(nas_tx);
return true;
} else {
@ -563,7 +566,6 @@ nas::handle_service_request( uint32_t m_tmsi,
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx;
sec_ctx_t *sec_ctx = &nas_ctx->m_sec_ctx;
sec_ctx->ul_nas_count++;
mac_valid = nas_ctx->short_integrity_check(nas_rx);
if (mac_valid) {
nas_log->console("Service Request -- Short MAC valid\n");
@ -610,9 +612,10 @@ nas::handle_service_request( uint32_t m_tmsi,
//Save UE ctx to MME UE S1AP id
s1ap->add_nas_ctx_to_mme_ue_s1ap_id_map(nas_ctx);
s1ap->send_initial_context_setup_request(imsi,5);
sec_ctx->ul_nas_count++;
} else {
nas_log->console("Service Request -- Short MAC invalid. Ignoring service request\n");
nas_log->console("Service Request -- Short MAC invalid. Ignoring service request\n");
nas_log->warning("Service Request -- Short MAC invalid. Ignoring service request\n");
}
return true;
}
@ -1076,8 +1079,8 @@ nas::pack_security_mode_command(srslte::byte_buffer_t *nas_buffer)
//Pack NAS PDU
LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sm_cmd;
sm_cmd.selected_nas_sec_algs.type_of_eea = LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_EEA0;
sm_cmd.selected_nas_sec_algs.type_of_eia = LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_128_EIA1;
sm_cmd.selected_nas_sec_algs.type_of_eea = (LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_ENUM) m_sec_ctx.cipher_algo;
sm_cmd.selected_nas_sec_algs.type_of_eia = (LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_ENUM) m_sec_ctx.integ_algo;
sm_cmd.nas_ksi.tsc_flag=LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE;
sm_cmd.nas_ksi.nas_ksi=m_sec_ctx.eksi;
@ -1107,10 +1110,9 @@ nas::pack_security_mode_command(srslte::byte_buffer_t *nas_buffer)
}
//Generate EPS security context
uint8_t mac[4];
srslte::security_generate_k_nas( m_sec_ctx.k_asme,
srslte::CIPHERING_ALGORITHM_ID_EEA0,
srslte::INTEGRITY_ALGORITHM_ID_128_EIA1,
m_sec_ctx.cipher_algo,
m_sec_ctx.integ_algo,
m_sec_ctx.k_nas_enc,
m_sec_ctx.k_nas_int
);
@ -1123,16 +1125,10 @@ nas::pack_security_mode_command(srslte::byte_buffer_t *nas_buffer)
m_nas_log->info("Generating KeNB with UL NAS COUNT: %d\n", m_sec_ctx.ul_nas_count);
m_nas_log->console("Generating KeNB with UL NAS COUNT: %d\n", m_sec_ctx.ul_nas_count);
m_nas_log->info_hex(m_sec_ctx.k_enb, 32, "Key eNodeB (k_enb)\n");
//Generate MAC for integrity protection
//FIXME Write wrapper to support EIA1, EIA2, etc.
srslte::security_128_eia1 (&m_sec_ctx.k_nas_int[16],
m_sec_ctx.dl_nas_count,
0,
SECURITY_DIRECTION_DOWNLINK,
&nas_buffer->msg[5],
nas_buffer->N_bytes - 5,
mac
);
uint8_t mac[4];
integrity_generate(nas_buffer, mac);
memcpy(&nas_buffer->msg[1],mac,4);
return true;
}
@ -1156,16 +1152,11 @@ nas::pack_esm_information_request(srslte::byte_buffer_t *nas_buffer)
return false;
}
cipher_encrypt(nas_buffer);
uint8_t mac[4];
srslte::security_128_eia1 (&m_sec_ctx.k_nas_int[16],
m_sec_ctx.dl_nas_count,
0,
SECURITY_DIRECTION_DOWNLINK,
&nas_buffer->msg[5],
nas_buffer->N_bytes - 5,
mac
);
memcpy(&nas_buffer->msg[1],mac,4);
integrity_generate(nas_buffer, mac);
memcpy(&nas_buffer->msg[1], mac, 4);
return true;
}
@ -1257,7 +1248,7 @@ nas::pack_attach_accept(srslte::byte_buffer_t *nas_buffer)
act_def_eps_bearer_context_req.eps_qos.br_ext_present = false;
//set apn
strncpy(act_def_eps_bearer_context_req.apn.apn, m_apn.c_str(), LIBLTE_STRING_LEN);
strncpy(act_def_eps_bearer_context_req.apn.apn, m_apn.c_str(), LIBLTE_STRING_LEN-1);
act_def_eps_bearer_context_req.proc_transaction_id = m_emm_ctx.procedure_transaction_id; //FIXME
//Set DNS server
@ -1283,17 +1274,13 @@ nas::pack_attach_accept(srslte::byte_buffer_t *nas_buffer)
m_sec_ctx.dl_nas_count++;
liblte_mme_pack_activate_default_eps_bearer_context_request_msg(&act_def_eps_bearer_context_req, &attach_accept.esm_msg);
liblte_mme_pack_attach_accept_msg(&attach_accept, sec_hdr_type, m_sec_ctx.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
//Integrity protect NAS message
uint8_t mac[4];
srslte::security_128_eia1 (&m_sec_ctx.k_nas_int[16],
m_sec_ctx.dl_nas_count,
0,
SECURITY_DIRECTION_DOWNLINK,
&nas_buffer->msg[5],
nas_buffer->N_bytes - 5,
mac
);
// Encrypt NAS message
cipher_encrypt(nas_buffer);
// Integrity protect NAS message
uint8_t mac[4];
integrity_generate(nas_buffer, mac);
memcpy(&nas_buffer->msg[1],mac,4);
//Log attach accept info
@ -1334,7 +1321,7 @@ nas::pack_emm_information(srslte::byte_buffer_t *nas_buffer)
emm_info.utc_and_local_time_zone_present = false;
emm_info.net_dst_present = false;
uint8_t sec_hdr_type =2;
uint8_t sec_hdr_type =LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED;
m_sec_ctx.dl_nas_count++;
LIBLTE_ERROR_ENUM err = liblte_mme_pack_emm_information_msg(&emm_info, sec_hdr_type, m_sec_ctx.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
if (err != LIBLTE_SUCCESS) {
@ -1343,15 +1330,12 @@ nas::pack_emm_information(srslte::byte_buffer_t *nas_buffer)
return false;
}
// Encrypt NAS message
cipher_encrypt(nas_buffer);
// Integrity protect NAS message
uint8_t mac[4];
srslte::security_128_eia1 (&m_sec_ctx.k_nas_int[16],
m_sec_ctx.dl_nas_count,
0,
SECURITY_DIRECTION_DOWNLINK,
&nas_buffer->msg[5],
nas_buffer->N_bytes - 5,
mac
);
integrity_generate(nas_buffer,mac);
memcpy(&nas_buffer->msg[1],mac,4);
m_nas_log->info("Packed UE EMM information\n");
@ -1385,65 +1369,200 @@ nas::pack_service_reject(srslte::byte_buffer_t *nas_buffer)
* Security Functions
*
************************/
bool
nas::short_integrity_check(srslte::byte_buffer_t *pdu)
bool nas::short_integrity_check(srslte::byte_buffer_t* pdu)
{
uint8_t exp_mac[4];
uint8_t *mac = &pdu->msg[2];
int i;
uint8_t exp_mac[4] = {0x00, 0x00, 0x00, 0x00};
uint8_t* mac = &pdu->msg[2];
int i;
srslte::security_128_eia1(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.ul_nas_count,
0,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[0],
2,
&exp_mac[0]);
if (pdu->N_bytes < 4) {
m_nas_log->warning("NAS message to short for short integrity check (pdu len: %d)", pdu->N_bytes);
return false;
}
switch (m_sec_ctx.integ_algo)
{
case srslte::INTEGRITY_ALGORITHM_ID_EIA0:
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA1:
srslte::security_128_eia1(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.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(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.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]){
for (i = 0; i < 2; i++) {
if (exp_mac[i + 2] != mac[i]) {
m_nas_log->warning("Short integrity check failure. Local: count=%d, [%02x %02x %02x %02x], "
"Received: count=%d, [%02x %02x]\n",
m_sec_ctx.ul_nas_count, exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3],
pdu->msg[1] & 0x1F, mac[0], mac[1]);
"Received: count=%d, [%02x %02x]\n",
m_sec_ctx.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_nas_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n",
m_sec_ctx.ul_nas_count, pdu->msg[1] & 0x1F);
m_nas_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n", m_sec_ctx.ul_nas_count,
pdu->msg[1] & 0x1F);
return true;
}
bool
nas::integrity_check(srslte::byte_buffer_t *pdu)
bool nas::integrity_check(srslte::byte_buffer_t *pdu)
{
uint8_t exp_mac[4];
uint8_t exp_mac[4] = {0x00, 0x00, 0x00, 0x00};
uint8_t *mac = &pdu->msg[1];
int i;
srslte::security_128_eia1(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.ul_nas_count,
0,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[5],
pdu->N_bytes-5,
&exp_mac[0]);
switch (m_sec_ctx.integ_algo)
{
case srslte::INTEGRITY_ALGORITHM_ID_EIA0:
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA1:
srslte::security_128_eia1(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.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(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.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_nas_log->warning("Integrity check failure. UL Local: count=%d, [%02x %02x %02x %02x], "
"Received: UL count=%d, [%02x %02x %02x %02x]\n",
m_sec_ctx.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]);
for (i = 0; i < 4; i++) {
if (exp_mac[i] != mac[i]) {
m_nas_log->warning("Integrity check failure. Algorithm=EIA%d\n", (int)m_sec_ctx.integ_algo);
m_nas_log->warning("UL Local: count=%d, MAC=[%02x %02x %02x %02x], "
"Received: UL count=%d, MAC=[%02x %02x %02x %02x]\n",
m_sec_ctx.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_nas_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n",
m_sec_ctx.ul_nas_count, pdu->msg[5]);
return true;
m_sec_ctx.ul_nas_count, pdu->msg[5]);
return true;
}
void nas::integrity_generate(srslte::byte_buffer_t* pdu, uint8_t* mac)
{
switch (m_sec_ctx.integ_algo) {
case srslte::INTEGRITY_ALGORITHM_ID_EIA0:
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA1:
srslte::security_128_eia1(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.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(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.dl_nas_count,
0, // Bearer always 0 for NAS
SECURITY_DIRECTION_DOWNLINK,
&pdu->msg[5],
pdu->N_bytes - 5,
mac);
break;
default:
break;
}
}
void nas::cipher_decrypt(srslte::byte_buffer_t *pdu)
{
srslte::byte_buffer_t tmp_pdu;
switch(m_sec_ctx.cipher_algo)
{
case srslte::CIPHERING_ALGORITHM_ID_EEA0:
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA1:
srslte::security_128_eea1(&m_sec_ctx.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_nas_log->debug_hex(tmp_pdu.msg, pdu->N_bytes, "Decrypted");
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA2:
srslte::security_128_eea2(&m_sec_ctx.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_nas_log->debug_hex(tmp_pdu.msg, pdu->N_bytes, "Decrypted");
memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6);
break;
default:
m_nas_log->error("Ciphering algorithms not known\n");
break;
}
}
void nas::cipher_encrypt(srslte::byte_buffer_t *pdu)
{
srslte::byte_buffer_t pdu_tmp;
switch(m_sec_ctx.cipher_algo)
{
case srslte::CIPHERING_ALGORITHM_ID_EEA0:
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA1:
srslte::security_128_eea1(&m_sec_ctx.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_nas_log->debug_hex(pdu_tmp.msg, pdu->N_bytes, "Encrypted");
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA2:
srslte::security_128_eea2(&m_sec_ctx.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_nas_log->debug_hex(pdu_tmp.msg, pdu->N_bytes, "Encrypted");
break;
default:
m_nas_log->error("Ciphering algorithm not known\n");
break;
}
}
} //namespace srsepc

@ -33,158 +33,151 @@
namespace srsepc{
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL;
pthread_mutex_t s1ap_ctx_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL;
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()
{
}
s1ap_ctx_mngmt_proc*
s1ap_ctx_mngmt_proc::get_instance(void)
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance(void)
{
pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if(NULL == m_instance) {
if (NULL == m_instance) {
m_instance = new s1ap_ctx_mngmt_proc();
}
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
return(m_instance);
return (m_instance);
}
void
s1ap_ctx_mngmt_proc::cleanup(void)
void s1ap_ctx_mngmt_proc::cleanup(void)
{
pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if(NULL != m_instance) {
if (NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
}
void
s1ap_ctx_mngmt_proc::init(void)
void s1ap_ctx_mngmt_proc::init(void)
{
m_s1ap = s1ap::get_instance();
m_mme_gtpc = mme_gtpc::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1ap_args = m_s1ap->m_s1ap_args;
m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap = s1ap::get_instance();
m_mme_gtpc = mme_gtpc::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1ap_args = m_s1ap->m_s1ap_args;
m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance();
}
bool
s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas *nas_ctx, uint16_t erab_to_setup)
bool 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;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* init = &pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP;
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");
//Get UE Context/E-RAB Context to setup
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx;
esm_ctx_t *esm_ctx = &nas_ctx->m_esm_ctx[erab_to_setup];
sec_ctx_t *sec_ctx = &nas_ctx->m_sec_ctx;
// Get UE Context/E-RAB Context to setup
emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
esm_ctx_t* esm_ctx = &nas_ctx->m_esm_ctx[erab_to_setup];
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->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ecm_ctx->enb_ue_s1ap_id;
//Set UE-AMBR
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL.BitRate=1000000000;
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL.BitRate=1000000000;
// Set UE-AMBR
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL.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;
//Setup eRAB context
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;
//Setup E-RAB QoS parameters
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.pre_emptionCapability = LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION;
erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability = LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_PRE_EMPTABLE;
erab_ctx_req->e_RABlevelQoSParameters.gbrQosInformation_present=false;
//Set E-RAB S-GW F-TEID
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;
// Setup eRAB context
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;
// Setup E-RAB QoS parameters
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.pre_emptionCapability =
LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION;
erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability =
LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_PRE_EMPTABLE;
erab_ctx_req->e_RABlevelQoSParameters.gbrQosInformation_present = false;
// Set E-RAB S-GW F-TEID
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);
uint32_t sgw_s1u_teid = esm_ctx->sgw_s1u_fteid.teid;
srslte::uint32_to_uint8(sgw_s1u_teid,erab_ctx_req->gTP_TEID.buffer);
//Set UE security capabilities and k_enb
bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16);
bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16);
for (int i = 0; i<3; i++) {
if(sec_ctx->ue_network_cap.eea[i+1] == true){
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; //EEA supported
srslte::uint32_to_uint8(sgw_s1u_teid, erab_ctx_req->gTP_TEID.buffer);
// Set UE security capabilities and k_enb
bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer, sizeof(uint8_t) * 16);
bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer, sizeof(uint8_t) * 16);
for (int i = 0; i < 3; i++) {
if (sec_ctx->ue_network_cap.eea[i + 1] == true) {
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; // EEA supported
} 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){
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; //EEA supported
if (sec_ctx->ue_network_cap.eia[i + 1] == true) {
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; // EEA supported
} 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);
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) {
//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->info("Adding attach accept to Initial Context Setup Request\n");
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;
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;
}
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);
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);
if (err != LIBLTE_SUCCESS) {
m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n");
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");
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;
struct in_addr addr;
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("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 -- 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->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->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 -- 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 -- QCI %d \n", erab_ctx_req->e_RABlevelQoSParameters.qCI.QCI);
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;
}
bool
s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *in_ctxt_resp)
bool s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(
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;
nas *nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == NULL){
nas* nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == NULL) {
m_s1ap_log->error("Could not find UE's context in active UE's map\n");
return false;
}
emm_ctx_t * emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t * ecm_ctx = &nas_ctx->m_ecm_ctx;
emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
m_s1ap_log->console("Received Initial Context Setup Response\n");
//Setup E-RABs
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;
esm_ctx_t *esm_ctx = &nas_ctx->m_esm_ctx[erab_id];
// Setup E-RABs
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;
esm_ctx_t* esm_ctx = &nas_ctx->m_esm_ctx[erab_id];
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;
}
//Mark E-RAB with context setup
// Mark E-RAB with context setup
esm_ctx->state = ERAB_CTX_SETUP;
//Set the GTP information
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));
// Set the GTP information
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));
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);
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));
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));
if (err == NULL) {
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->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 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);
}
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;
}
bool
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)
bool 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)
{
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;
}
bool
s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas *nas_ctx)
bool 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;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASECOMMAND;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* init = &pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_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;
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.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->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.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);
if (err != LIBLTE_SUCCESS) {
@ -324,8 +316,8 @@ s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas *nas_ctx)
return false;
}
//Send Reply to eNB
if(!m_s1ap->s1ap_tx_pdu(reply_buffer,&nas_ctx->m_ecm_ctx.enb_sri)){
// Send Reply to eNB
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_pool->deallocate(reply_buffer);
return false;
@ -335,8 +327,8 @@ s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas *nas_ctx)
return true;
}
bool
s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *rel_comp)
bool s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT* rel_comp)
{
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);
@ -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;
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) {
//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->info("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 bearers 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);
//The handle_releease_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.
//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.
} else {
//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);
@ -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");
return true;
}
} //namespace srsepc

@ -31,56 +31,49 @@
#include "srsepc/hdr/mme/s1ap_nas_transport.h"
#include "srslte/common/security.h"
#include "srslte/common/liblte_security.h"
#include "srslte/common/int_helpers.h"
namespace srsepc{
s1ap_nas_transport* s1ap_nas_transport::m_instance = NULL;
pthread_mutex_t s1ap_nas_transport_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_nas_transport* s1ap_nas_transport::m_instance = NULL;
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::get_instance(void)
s1ap_nas_transport* s1ap_nas_transport::get_instance(void)
{
pthread_mutex_lock(&s1ap_nas_transport_instance_mutex);
if(NULL == m_instance) {
if (NULL == m_instance) {
m_instance = new s1ap_nas_transport();
}
pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex);
return(m_instance);
return (m_instance);
}
void
s1ap_nas_transport::cleanup(void)
void s1ap_nas_transport::cleanup(void)
{
pthread_mutex_lock(&s1ap_nas_transport_instance_mutex);
if(NULL != m_instance) {
if (NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex);
}
void
s1ap_nas_transport::init(hss_interface_nas * hss_)
void 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_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();
}
bool
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 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 err, mac_valid;
uint8_t pd, msg_type, sec_hdr_type;
@ -104,74 +97,116 @@ s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSA
nas_init.tac = m_s1ap->m_s1ap_args.tac;
nas_init.apn = m_s1ap->m_s1ap_args.mme_apn;
nas_init.dns = m_s1ap->m_s1ap_args.dns_addr;
nas_init.integ_algo = m_s1ap->m_s1ap_args.integrity_algo;
nas_init.cipher_algo = m_s1ap->m_s1ap_args.encryption_algo;
if(init_ue->S_TMSI_present){
m_tmsi = ntohl(*((uint32_t*) &init_ue->S_TMSI.m_TMSI.buffer));
srslte::uint8_to_uint32(init_ue->S_TMSI.m_TMSI.buffer, &m_tmsi);
}
switch (msg_type)
{
case LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST:
m_s1ap_log->console("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, m_s1ap->m_nas_log);
break;
case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST:
m_s1ap_log->console("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, m_s1ap->m_nas_log);
break;
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
m_s1ap_log->console("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, m_s1ap->m_nas_log);
break;
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->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, m_mme_gtpc, m_hss, m_s1ap->m_nas_log);
break;
default:
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);
err = false;
switch (msg_type) {
case LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST:
m_s1ap_log->console("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,
m_s1ap->m_nas_log);
break;
case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST:
m_s1ap_log->console("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,
m_s1ap->m_nas_log);
break;
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
m_s1ap_log->console("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,
m_s1ap->m_nas_log);
break;
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->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,
m_mme_gtpc, m_hss, m_s1ap->m_nas_log);
break;
default:
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);
err = false;
}
m_pool->deallocate(nas_msg);
return err;
}
bool
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)
bool 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)
{
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 mme_ue_s1ap_id = ul_xport->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
bool mac_valid = false;
//Get UE ECM context
nas *nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
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 mme_ue_s1ap_id = ul_xport->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
bool mac_valid = false;
bool increase_ul_nas_cnt = true;
// 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) {
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;
}
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;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx;
sec_ctx_t *sec_ctx = &nas_ctx->m_sec_ctx;
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;
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
sec_ctx_t* sec_ctx = &nas_ctx->m_sec_ctx;
//Parse NAS message header
srslte::byte_buffer_t *nas_msg = m_pool->allocate();
// Parse NAS message header
srslte::byte_buffer_t* nas_msg = m_pool->allocate();
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;
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &pd, &msg_type);
nas_msg->N_bytes = ul_xport->NAS_PDU.n_octets;
bool msg_encrypted = false;
// Parse the message security header
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)
{
m_s1ap_log->debug_hex(nas_msg->msg, nas_msg->N_bytes, "Encrypted");
nas_ctx->cipher_decrypt(nas_msg);
msg_encrypted = true;
m_s1ap_log->debug_hex(nas_msg->msg, nas_msg->N_bytes, "Decrypted");
}
// 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.
if (sec_hdr_type != LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS) {
@ -187,122 +222,109 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA
}
}
if( sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS ||
(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) ||
(msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) ||
(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/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.
switch(msg_type)
{
case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE:
m_s1ap_log->info("Uplink NAS: Received Identity Response\n");
m_s1ap_log->console("Uplink NAS: Received Identity Response\n");
nas_ctx->handle_identity_response(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE:
m_s1ap_log->info("Uplink NAS: Received Authentication Response\n");
m_s1ap_log->console("Uplink NAS: Received Authentication Response\n");
nas_ctx->handle_authentication_response(nas_msg);
break;
// Authentication failure with the option sync failure can be sent not integrity protected
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
m_s1ap_log->info("Plain UL NAS: Authentication Failure\n");
m_s1ap_log->console("Plain UL NAS: Authentication Failure\n");
nas_ctx->handle_authentication_failure(nas_msg);
break;
// Detach request can be sent not integrity protected when "power off" option is used
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
m_s1ap_log->info("Plain Protected UL NAS: Detach Request\n");
m_s1ap_log->console("Plain Protected UL NAS: Detach Request\n");
nas_ctx->handle_detach_request(nas_msg);
break;
default:
m_s1ap_log->warning("Unhandled Plain NAS message 0x%x\n", msg_type);
m_s1ap_log->console("Unhandled Plain NAS message 0x%x\n", msg_type);
m_pool->deallocate(nas_msg);
return false;
}
//Increment UL NAS count.
sec_ctx->ul_nas_count++;
} else if (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) {
//Integrity Protected Messages, possibly chiphered, with new EPS context.
switch (msg_type) {
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE:
m_s1ap_log->info("Uplink NAS: Received Security Mode Complete\n");
m_s1ap_log->console("Uplink NAS: Received Security Mode Complete\n");
sec_ctx->ul_nas_count = 0;
sec_ctx->dl_nas_count = 0;
mac_valid = nas_ctx->integrity_check(nas_msg);
if(mac_valid){
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 );
}
} else if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED) {
// Handle message and check if security requirements for messages
// 4.4.4.3 Integrity checking of NAS signalling messages in the MME
// Except the messages listed below, no NAS signalling messages shall be processed...
// - ATTACH REQUEST;
// - IDENTITY RESPONSE (if requested identification parameter is IMSI);
// - AUTHENTICATION RESPONSE;
// - AUTHENTICATION FAILURE;
// - SECURITY MODE REJECT;
// - DETACH REQUEST;
// - DETACH ACCEPT;
// - TRACKING AREA UPDATE REQUEST.
m_s1ap_log->info("UL NAS: sec_hdr_type: %s, mac_vaild: %s, msg_encrypted: %s\n",
liblte_nas_sec_hdr_type_to_string(sec_hdr_type), mac_valid == true ? "yes" : "no",
msg_encrypted == true ? "yes" : "no");
//Integrity protected NAS message, possibly ciphered.
sec_ctx->ul_nas_count++;
mac_valid = nas_ctx->integrity_check(nas_msg);
if(!mac_valid){
m_s1ap_log->warning("Invalid MAC in NAS message type 0x%x.\n", msg_type);
m_pool->deallocate(nas_msg);
return false;
switch (msg_type)
{
case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE:
m_s1ap_log->info("UL NAS: Received Identity Response\n");
m_s1ap_log->console("UL NAS: Received Identity Response\n");
nas_ctx->handle_identity_response(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE:
m_s1ap_log->info("UL NAS: Received Authentication Response\n");
m_s1ap_log->console("UL NAS: Received Authentication Response\n");
nas_ctx->handle_authentication_response(nas_msg);
// In case of a successful authentication response, security mode command follows.
// Reset counter for incoming security mode complete
sec_ctx->ul_nas_count = 0;
sec_ctx->dl_nas_count = 0;
increase_ul_nas_cnt = false;
break;
// Authentication failure with the option sync failure can be sent not integrity protected
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
m_s1ap_log->info("UL NAS: Authentication Failure\n");
m_s1ap_log->console("UL NAS: Authentication Failure\n");
nas_ctx->handle_authentication_failure(nas_msg);
break;
// Detach request can be sent not integrity protected when "power off" option is used
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
m_s1ap_log->info("UL NAS: Detach Request\n");
m_s1ap_log->console("UL NAS: Detach Request\n");
// FIXME: check integrity protection in detach request
nas_ctx->handle_detach_request(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE:
m_s1ap_log->info("UL NAS: Received Security Mode Complete\n");
m_s1ap_log->console("UL NAS: Received Security Mode Complete\n");
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT && mac_valid == true){
nas_ctx->handle_security_mode_complete(nas_msg);
} else {
// Security Mode Complete was not integrity protected
m_s1ap_log->console("Security Mode Complete %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
m_s1ap_log->warning("Security Mode Complete %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
increase_ul_nas_cnt = false;
}
switch (msg_type) {
case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE:
m_s1ap_log->info("Integrity Protected UL NAS: Received Attach Complete\n");
m_s1ap_log->console("Integrity Protected UL NAS: Received Attach Complete\n");
break;
case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE:
m_s1ap_log->info("UL NAS: Received Attach Complete\n");
m_s1ap_log->console("UL NAS: Received Attach Complete\n");
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true){
nas_ctx->handle_attach_complete(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE:
m_s1ap_log->info("Integrity Protected UL NAS: Received ESM Information Response\n");
m_s1ap_log->console("Integrity Protected UL NAS: Received ESM Information Response\n");
} else {
// Attach Complete was not integrity protected
m_s1ap_log->console("Attach Complete not integrity protected. Discard message.\n");
m_s1ap_log->warning("Attach Complete not integrity protected. Discard message.\n");
increase_ul_nas_cnt = false;
}
break;
case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE:
m_s1ap_log->info("UL NAS: Received ESM Information Response\n");
m_s1ap_log->console("UL NAS: Received ESM Information Response\n");
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true){
nas_ctx->handle_esm_information_response(nas_msg);
break;
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 {
// Attach Complete was not integrity protected
m_s1ap_log->console("ESM Information Response %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
m_s1ap_log->warning("ESM Information Response %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
increase_ul_nas_cnt = false;
}
} else {
m_s1ap_log->error("Unhandled security header type in Uplink NAS Transport: %d\n", sec_hdr_type);
break;
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");
nas_ctx->handle_tracking_area_update_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;
}
//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) {
sec_ctx->ul_nas_count++;
}
m_pool->deallocate(nas_msg);
return true;
}
bool
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)
bool 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)
{
//Allocate Reply buffer
srslte::byte_buffer_t *reply_msg = m_pool->allocate();
@ -343,4 +365,5 @@ s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_
return true;
}
} //namespace srsepc

@ -1349,11 +1349,11 @@ void nas::send_detach_request(bool switch_off)
memcpy(&detach_request.eps_mobile_id.guti, &ctxt.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
detach_request.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE;
detach_request.nas_ksi.nas_ksi = ctxt.ksi;
nas_log->info("Requesting Detach with GUTI\n");
nas_log->info("Requesting Detach with GUTI\n"); //If sent as an Initial UE message, it cannot be chiphered
liblte_mme_pack_detach_request_msg(&detach_request,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY,
ctxt.tx_count,
(LIBLTE_BYTE_MSG_STRUCT *) pdu);
rrc->is_connected() ? LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED
: LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY,
ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT*)pdu);
if(pcap != NULL) {
pcap->write_nas(pdu->msg, pdu->N_bytes);
@ -1361,7 +1361,9 @@ void nas::send_detach_request(bool switch_off)
// Add MAC
if (pdu->N_bytes > 5) {
cipher_encrypt(pdu);
if (rrc->is_connected()) {
cipher_encrypt(pdu);
}
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,

Loading…
Cancel
Save