forked from acouzens/open5gs
[AMF/MME] PLMN access control
These mechanisms are described in the GSMA roaming guidelines. Chapters called Access Control. For 4g: https://www.gsma.com/newsroom/wp-content/uploads//IR.88-v21.0.pdf For 5g: https://www.gsma.com/newsroom/wp-content/uploads//NG.113-v6.0.pdf
This commit is contained in:
parent
5f37777280
commit
d469809192
|
@ -417,6 +417,41 @@ sbi:
|
||||||
# s_nssai:
|
# s_nssai:
|
||||||
# - sst: 1
|
# - sst: 1
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# <Access Control>
|
||||||
|
#
|
||||||
|
# If access_control is not specified, then all networks are allowed
|
||||||
|
# If access_control is defined,
|
||||||
|
# no other networks are allowed other than matching plmn_id.
|
||||||
|
#
|
||||||
|
# default_reject_cause may be used to overwrite the default error cause #11
|
||||||
|
# for non matching plmn_id
|
||||||
|
#
|
||||||
|
# for matching plmn_id with reject_cause defined,
|
||||||
|
# the AMF rejects access with the reject_cause error cause
|
||||||
|
#
|
||||||
|
# for matching plmn_id without reject_cause defined,
|
||||||
|
# the AMF accepts the PLMN traffic
|
||||||
|
#
|
||||||
|
# o The example below only accepts 002/02 and 999/70 PLMNs.
|
||||||
|
# 001/01 is rejected with cause 15,
|
||||||
|
# and the rest of the PLMNs are rejected with default cause 13.
|
||||||
|
#
|
||||||
|
# amf:
|
||||||
|
# access_control:
|
||||||
|
# - default_reject_cause: 13
|
||||||
|
# - plmn_id:
|
||||||
|
# reject_cause: 15
|
||||||
|
# mcc: 001
|
||||||
|
# mnc: 01
|
||||||
|
# - plmn_id:
|
||||||
|
# mcc: 002
|
||||||
|
# mnc: 02
|
||||||
|
# - plmn_id:
|
||||||
|
# mcc: 999
|
||||||
|
# mnc: 70
|
||||||
|
#
|
||||||
|
#
|
||||||
# <Network Name>
|
# <Network Name>
|
||||||
#
|
#
|
||||||
# amf:
|
# amf:
|
||||||
|
|
|
@ -269,6 +269,41 @@ logger:
|
||||||
# mnc: 09
|
# mnc: 09
|
||||||
# tac: [70, 80]
|
# tac: [70, 80]
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# <Access Control>
|
||||||
|
#
|
||||||
|
# If access_control is not specified, then all networks are allowed
|
||||||
|
# If access_control is defined,
|
||||||
|
# no other networks are allowed other than matching plmn_id.
|
||||||
|
#
|
||||||
|
# default_reject_cause may be used to overwrite the default error cause #11
|
||||||
|
# for non matching plmn_id
|
||||||
|
#
|
||||||
|
# for matching plmn_id with reject_cause defined,
|
||||||
|
# the MME rejects access with the reject_cause error cause
|
||||||
|
#
|
||||||
|
# for matching plmn_id without reject_cause defined,
|
||||||
|
# the MME accepts the PLMN traffic
|
||||||
|
#
|
||||||
|
# o The example below only accepts 002/02 and 999/70 PLMNs.
|
||||||
|
# 001/01 is rejected with cause 15,
|
||||||
|
# and the rest of the PLMNs are rejected with default cause 13.
|
||||||
|
#
|
||||||
|
# mme:
|
||||||
|
# access_control:
|
||||||
|
# - default_reject_cause: 13
|
||||||
|
# - plmn_id:
|
||||||
|
# reject_cause: 15
|
||||||
|
# mcc: 001
|
||||||
|
# mnc: 01
|
||||||
|
# - plmn_id:
|
||||||
|
# mcc: 002
|
||||||
|
# mnc: 02
|
||||||
|
# - plmn_id:
|
||||||
|
# mcc: 999
|
||||||
|
# mnc: 70
|
||||||
|
#
|
||||||
|
#
|
||||||
# <Network Name>
|
# <Network Name>
|
||||||
# mme:
|
# mme:
|
||||||
# network_name:
|
# network_name:
|
||||||
|
|
|
@ -125,30 +125,6 @@ smf:
|
||||||
- identity: pcrf.localdomain
|
- identity: pcrf.localdomain
|
||||||
addr: 127.0.0.9
|
addr: 127.0.0.9
|
||||||
|
|
||||||
#
|
|
||||||
# <For Indirect Communication with Delegated Discovery>
|
|
||||||
#
|
|
||||||
# o (Default) If you do not set Delegated Discovery as shown below,
|
|
||||||
#
|
|
||||||
# sbi:
|
|
||||||
# - addr: 127.0.0.5
|
|
||||||
# port: 7777
|
|
||||||
#
|
|
||||||
# - Use SCP if SCP avaiable. Otherwise NRF is used.
|
|
||||||
# => App fails if both NRF and SCP are unavailable.
|
|
||||||
#
|
|
||||||
# sbi:
|
|
||||||
# - addr: 127.0.0.5
|
|
||||||
# port: 7777
|
|
||||||
# discovery:
|
|
||||||
# delegated: auto
|
|
||||||
#
|
|
||||||
# o To use SCP always => App fails if no SCP available.
|
|
||||||
# delegated: yes
|
|
||||||
#
|
|
||||||
# o Don't use SCP server => App fails if no NRF available.
|
|
||||||
# delegated: no
|
|
||||||
#
|
|
||||||
amf:
|
amf:
|
||||||
sbi:
|
sbi:
|
||||||
- addr: 127.0.0.5
|
- addr: 127.0.0.5
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2019-2022 by Sukchan Lee <acetcom@gmail.com>
|
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||||
*
|
*
|
||||||
* This file is part of Open5GS.
|
* This file is part of Open5GS.
|
||||||
*
|
*
|
||||||
|
@ -84,6 +84,7 @@ extern "C" {
|
||||||
|
|
||||||
#define OGS_MAX_NUM_OF_SERVED_GUAMI 8
|
#define OGS_MAX_NUM_OF_SERVED_GUAMI 8
|
||||||
#define OGS_MAX_NUM_OF_SERVED_TAI OGS_MAX_NUM_OF_TAI
|
#define OGS_MAX_NUM_OF_SERVED_TAI OGS_MAX_NUM_OF_TAI
|
||||||
|
#define OGS_MAX_NUM_OF_ACCESS_CONTROL 8
|
||||||
#define OGS_MAX_NUM_OF_ALGORITHM 8
|
#define OGS_MAX_NUM_OF_ALGORITHM 8
|
||||||
|
|
||||||
#define OGS_MAX_NUM_OF_BPLMN 6
|
#define OGS_MAX_NUM_OF_BPLMN 6
|
||||||
|
|
|
@ -755,6 +755,81 @@ int amf_context_parse_config(void)
|
||||||
}
|
}
|
||||||
} while (ogs_yaml_iter_type(&plmn_support_array) ==
|
} while (ogs_yaml_iter_type(&plmn_support_array) ==
|
||||||
YAML_SEQUENCE_NODE);
|
YAML_SEQUENCE_NODE);
|
||||||
|
} else if (!strcmp(amf_key, "access_control")) {
|
||||||
|
ogs_yaml_iter_t access_control_array, access_control_iter;
|
||||||
|
ogs_yaml_iter_recurse(&amf_iter, &access_control_array);
|
||||||
|
do {
|
||||||
|
ogs_assert(self.num_of_access_control <
|
||||||
|
OGS_MAX_NUM_OF_ACCESS_CONTROL);
|
||||||
|
|
||||||
|
if (ogs_yaml_iter_type(&access_control_array) ==
|
||||||
|
YAML_MAPPING_NODE) {
|
||||||
|
memcpy(&access_control_iter, &access_control_array,
|
||||||
|
sizeof(ogs_yaml_iter_t));
|
||||||
|
} else if (ogs_yaml_iter_type(&access_control_array) ==
|
||||||
|
YAML_SEQUENCE_NODE) {
|
||||||
|
if (!ogs_yaml_iter_next(&access_control_array))
|
||||||
|
break;
|
||||||
|
ogs_yaml_iter_recurse(&access_control_array,
|
||||||
|
&access_control_iter);
|
||||||
|
} else if (ogs_yaml_iter_type(&access_control_array) ==
|
||||||
|
YAML_SCALAR_NODE) {
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
ogs_assert_if_reached();
|
||||||
|
|
||||||
|
while (ogs_yaml_iter_next(&access_control_iter)) {
|
||||||
|
const char *mnc = NULL, *mcc = NULL;
|
||||||
|
int reject_cause = 0;
|
||||||
|
const char *access_control_key =
|
||||||
|
ogs_yaml_iter_key(&access_control_iter);
|
||||||
|
ogs_assert(access_control_key);
|
||||||
|
if (!strcmp(access_control_key,
|
||||||
|
"default_reject_cause")) {
|
||||||
|
const char *v = ogs_yaml_iter_value(
|
||||||
|
&access_control_iter);
|
||||||
|
if (v) self.default_reject_cause = atoi(v);
|
||||||
|
} else if (!strcmp(access_control_key, "plmn_id")) {
|
||||||
|
ogs_yaml_iter_t plmn_id_iter;
|
||||||
|
|
||||||
|
ogs_yaml_iter_recurse(&access_control_iter,
|
||||||
|
&plmn_id_iter);
|
||||||
|
while (ogs_yaml_iter_next(&plmn_id_iter)) {
|
||||||
|
const char *plmn_id_key =
|
||||||
|
ogs_yaml_iter_key(&plmn_id_iter);
|
||||||
|
ogs_assert(plmn_id_key);
|
||||||
|
if (!strcmp(plmn_id_key, "reject_cause")) {
|
||||||
|
const char *v = ogs_yaml_iter_value(
|
||||||
|
&plmn_id_iter);
|
||||||
|
if (v) reject_cause = atoi(v);
|
||||||
|
} else if (!strcmp(plmn_id_key, "mcc")) {
|
||||||
|
mcc = ogs_yaml_iter_value(
|
||||||
|
&plmn_id_iter);
|
||||||
|
} else if (!strcmp(plmn_id_key, "mnc")) {
|
||||||
|
mnc = ogs_yaml_iter_value(
|
||||||
|
&plmn_id_iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mcc && mnc) {
|
||||||
|
ogs_plmn_id_build(
|
||||||
|
&self.access_control[
|
||||||
|
self.num_of_access_control].
|
||||||
|
plmn_id,
|
||||||
|
atoi(mcc), atoi(mnc), strlen(mnc));
|
||||||
|
if (reject_cause)
|
||||||
|
self.access_control[
|
||||||
|
self.num_of_access_control].
|
||||||
|
reject_cause = reject_cause;
|
||||||
|
self.num_of_access_control++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ogs_warn("unknown key `%s`",
|
||||||
|
access_control_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (ogs_yaml_iter_type(&access_control_array) ==
|
||||||
|
YAML_SEQUENCE_NODE);
|
||||||
} else if (!strcmp(amf_key, "security")) {
|
} else if (!strcmp(amf_key, "security")) {
|
||||||
ogs_yaml_iter_t security_iter;
|
ogs_yaml_iter_t security_iter;
|
||||||
ogs_yaml_iter_recurse(&amf_iter, &security_iter);
|
ogs_yaml_iter_recurse(&amf_iter, &security_iter);
|
||||||
|
@ -847,7 +922,8 @@ int amf_context_parse_config(void)
|
||||||
} while (
|
} while (
|
||||||
ogs_yaml_iter_type(&ciphering_order_iter) ==
|
ogs_yaml_iter_type(&ciphering_order_iter) ==
|
||||||
YAML_SEQUENCE_NODE);
|
YAML_SEQUENCE_NODE);
|
||||||
}
|
} else
|
||||||
|
ogs_warn("unknown key `%s`", security_key);
|
||||||
}
|
}
|
||||||
} else if (!strcmp(amf_key, "network_name")) {
|
} else if (!strcmp(amf_key, "network_name")) {
|
||||||
ogs_yaml_iter_t network_name_iter;
|
ogs_yaml_iter_t network_name_iter;
|
||||||
|
@ -891,7 +967,8 @@ int amf_context_parse_config(void)
|
||||||
network_short_name->length = size*2+1;
|
network_short_name->length = size*2+1;
|
||||||
network_short_name->coding_scheme = 1;
|
network_short_name->coding_scheme = 1;
|
||||||
network_short_name->ext = 1;
|
network_short_name->ext = 1;
|
||||||
}
|
} else
|
||||||
|
ogs_warn("unknown key `%s`", network_name_key);
|
||||||
}
|
}
|
||||||
} else if (!strcmp(amf_key, "amf_name")) {
|
} else if (!strcmp(amf_key, "amf_name")) {
|
||||||
self.amf_name = ogs_yaml_iter_value(&amf_iter);
|
self.amf_name = ogs_yaml_iter_value(&amf_iter);
|
||||||
|
|
|
@ -66,6 +66,14 @@ typedef struct amf_context_s {
|
||||||
ogs_s_nssai_t s_nssai[OGS_MAX_NUM_OF_SLICE];
|
ogs_s_nssai_t s_nssai[OGS_MAX_NUM_OF_SLICE];
|
||||||
} plmn_support[OGS_MAX_NUM_OF_PLMN];
|
} plmn_support[OGS_MAX_NUM_OF_PLMN];
|
||||||
|
|
||||||
|
/* Access Control */
|
||||||
|
int default_reject_cause;
|
||||||
|
int num_of_access_control;
|
||||||
|
struct {
|
||||||
|
int reject_cause;
|
||||||
|
ogs_plmn_id_t plmn_id;
|
||||||
|
} access_control[OGS_MAX_NUM_OF_ACCESS_CONTROL];
|
||||||
|
|
||||||
/* defined in 'nas_ies.h'
|
/* defined in 'nas_ies.h'
|
||||||
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
|
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
|
||||||
* #define NAS_SECURITY_ALGORITHMS_128_EEA1 1
|
* #define NAS_SECURITY_ALGORITHMS_128_EEA1 1
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
|
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||||
*
|
*
|
||||||
* This file is part of Open5GS.
|
* This file is part of Open5GS.
|
||||||
*
|
*
|
||||||
|
@ -32,11 +32,14 @@ static ogs_nas_5gmm_cause_t gmm_handle_nas_message_container(
|
||||||
amf_ue_t *amf_ue, uint8_t message_type,
|
amf_ue_t *amf_ue, uint8_t message_type,
|
||||||
ogs_nas_message_container_t *nas_message_container);
|
ogs_nas_message_container_t *nas_message_container);
|
||||||
|
|
||||||
|
static uint8_t gmm_cause_from_access_control(ogs_plmn_id_t *plmn_id);
|
||||||
|
|
||||||
ogs_nas_5gmm_cause_t gmm_handle_registration_request(amf_ue_t *amf_ue,
|
ogs_nas_5gmm_cause_t gmm_handle_registration_request(amf_ue_t *amf_ue,
|
||||||
ogs_nas_security_header_type_t h, NGAP_ProcedureCode_t ngap_code,
|
ogs_nas_security_header_type_t h, NGAP_ProcedureCode_t ngap_code,
|
||||||
ogs_nas_5gs_registration_request_t *registration_request)
|
ogs_nas_5gs_registration_request_t *registration_request)
|
||||||
{
|
{
|
||||||
int served_tai_index = 0;
|
int served_tai_index = 0;
|
||||||
|
uint8_t gmm_cause;
|
||||||
|
|
||||||
ran_ue_t *ran_ue = NULL;
|
ran_ue_t *ran_ue = NULL;
|
||||||
ogs_nas_5gs_registration_type_t *registration_type = NULL;
|
ogs_nas_5gs_registration_type_t *registration_type = NULL;
|
||||||
|
@ -281,6 +284,18 @@ ogs_nas_5gmm_cause_t gmm_handle_registration_request(amf_ue_t *amf_ue,
|
||||||
memcpy(&amf_ue->nr_cgi, &ran_ue->saved.nr_cgi, sizeof(ogs_nr_cgi_t));
|
memcpy(&amf_ue->nr_cgi, &ran_ue->saved.nr_cgi, sizeof(ogs_nr_cgi_t));
|
||||||
amf_ue->ue_location_timestamp = ogs_time_now();
|
amf_ue->ue_location_timestamp = ogs_time_now();
|
||||||
|
|
||||||
|
/* Check PLMN-ID access control */
|
||||||
|
gmm_cause = gmm_cause_from_access_control(&amf_ue->nr_tai.plmn_id);
|
||||||
|
if (gmm_cause != OGS_5GMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in TAI) access control");
|
||||||
|
return gmm_cause;
|
||||||
|
}
|
||||||
|
gmm_cause = gmm_cause_from_access_control(&amf_ue->nr_cgi.plmn_id);
|
||||||
|
if (gmm_cause != OGS_5GMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in CGI) access control");
|
||||||
|
return gmm_cause;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check TAI */
|
/* Check TAI */
|
||||||
served_tai_index = amf_find_served_tai(&amf_ue->nr_tai);
|
served_tai_index = amf_find_served_tai(&amf_ue->nr_tai);
|
||||||
if (served_tai_index < 0) {
|
if (served_tai_index < 0) {
|
||||||
|
@ -511,6 +526,7 @@ ogs_nas_5gmm_cause_t gmm_handle_service_request(amf_ue_t *amf_ue,
|
||||||
ogs_nas_5gs_service_request_t *service_request)
|
ogs_nas_5gs_service_request_t *service_request)
|
||||||
{
|
{
|
||||||
int served_tai_index = 0;
|
int served_tai_index = 0;
|
||||||
|
uint8_t gmm_cause;
|
||||||
|
|
||||||
ran_ue_t *ran_ue = NULL;
|
ran_ue_t *ran_ue = NULL;
|
||||||
ogs_nas_key_set_identifier_t *ngksi = NULL;
|
ogs_nas_key_set_identifier_t *ngksi = NULL;
|
||||||
|
@ -605,6 +621,18 @@ ogs_nas_5gmm_cause_t gmm_handle_service_request(amf_ue_t *amf_ue,
|
||||||
memcpy(&amf_ue->nr_cgi, &ran_ue->saved.nr_cgi, sizeof(ogs_nr_cgi_t));
|
memcpy(&amf_ue->nr_cgi, &ran_ue->saved.nr_cgi, sizeof(ogs_nr_cgi_t));
|
||||||
amf_ue->ue_location_timestamp = ogs_time_now();
|
amf_ue->ue_location_timestamp = ogs_time_now();
|
||||||
|
|
||||||
|
/* Check PLMN-ID access control */
|
||||||
|
gmm_cause = gmm_cause_from_access_control(&amf_ue->nr_tai.plmn_id);
|
||||||
|
if (gmm_cause != OGS_5GMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in TAI) access control");
|
||||||
|
return gmm_cause;
|
||||||
|
}
|
||||||
|
gmm_cause = gmm_cause_from_access_control(&amf_ue->nr_cgi.plmn_id);
|
||||||
|
if (gmm_cause != OGS_5GMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in CGI) access control");
|
||||||
|
return gmm_cause;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check TAI */
|
/* Check TAI */
|
||||||
served_tai_index = amf_find_served_tai(&amf_ue->nr_tai);
|
served_tai_index = amf_find_served_tai(&amf_ue->nr_tai);
|
||||||
if (served_tai_index < 0) {
|
if (served_tai_index < 0) {
|
||||||
|
@ -1411,3 +1439,29 @@ static ogs_nas_5gmm_cause_t gmm_handle_nas_message_container(
|
||||||
ogs_pkbuf_free(nasbuf);
|
ogs_pkbuf_free(nasbuf);
|
||||||
return gmm_cause;
|
return gmm_cause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t gmm_cause_from_access_control(ogs_plmn_id_t *plmn_id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ogs_assert(plmn_id);
|
||||||
|
|
||||||
|
/* No Access Control */
|
||||||
|
if (amf_self()->num_of_access_control == 0)
|
||||||
|
return OGS_5GMM_CAUSE_REQUEST_ACCEPTED;
|
||||||
|
|
||||||
|
for (i = 0; i < amf_self()->num_of_access_control; i++) {
|
||||||
|
if (memcmp(&amf_self()->access_control[i].plmn_id,
|
||||||
|
plmn_id, OGS_PLMN_ID_LEN) == 0) {
|
||||||
|
if (amf_self()->access_control[i].reject_cause)
|
||||||
|
return amf_self()->access_control[i].reject_cause;
|
||||||
|
else
|
||||||
|
return OGS_5GMM_CAUSE_REQUEST_ACCEPTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amf_self()->default_reject_cause)
|
||||||
|
return amf_self()->default_reject_cause;
|
||||||
|
|
||||||
|
return OGS_5GMM_CAUSE_PLMN_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
|
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
||||||
*
|
*
|
||||||
* This file is part of Open5GS.
|
* This file is part of Open5GS.
|
||||||
*
|
*
|
||||||
|
@ -32,10 +32,13 @@
|
||||||
#undef OGS_LOG_DOMAIN
|
#undef OGS_LOG_DOMAIN
|
||||||
#define OGS_LOG_DOMAIN __emm_log_domain
|
#define OGS_LOG_DOMAIN __emm_log_domain
|
||||||
|
|
||||||
|
static uint8_t emm_cause_from_access_control(ogs_plmn_id_t *plmn_id);
|
||||||
|
|
||||||
int emm_handle_attach_request(mme_ue_t *mme_ue,
|
int emm_handle_attach_request(mme_ue_t *mme_ue,
|
||||||
ogs_nas_eps_attach_request_t *attach_request, ogs_pkbuf_t *pkbuf)
|
ogs_nas_eps_attach_request_t *attach_request, ogs_pkbuf_t *pkbuf)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
uint8_t emm_cause;
|
||||||
int served_tai_index = 0;
|
int served_tai_index = 0;
|
||||||
|
|
||||||
ogs_nas_eps_mobile_identity_guti_t *eps_mobile_identity_guti = NULL;
|
ogs_nas_eps_mobile_identity_guti_t *eps_mobile_identity_guti = NULL;
|
||||||
|
@ -132,6 +135,26 @@ int emm_handle_attach_request(mme_ue_t *mme_ue,
|
||||||
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
|
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
|
||||||
mme_ue->ue_location_timestamp = ogs_time_now();
|
mme_ue->ue_location_timestamp = ogs_time_now();
|
||||||
|
|
||||||
|
/* Check PLMN-ID access control */
|
||||||
|
emm_cause = emm_cause_from_access_control(&mme_ue->tai.plmn_id);
|
||||||
|
if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in TAI) access control");
|
||||||
|
r = nas_eps_send_attach_reject(mme_ue,
|
||||||
|
emm_cause, OGS_NAS_ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
|
||||||
|
ogs_expect(r == OGS_OK);
|
||||||
|
ogs_assert(r != OGS_ERROR);
|
||||||
|
return OGS_ERROR;
|
||||||
|
}
|
||||||
|
emm_cause = emm_cause_from_access_control(&mme_ue->e_cgi.plmn_id);
|
||||||
|
if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in CGI) access control");
|
||||||
|
r = nas_eps_send_attach_reject(mme_ue,
|
||||||
|
emm_cause, OGS_NAS_ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
|
||||||
|
ogs_expect(r == OGS_OK);
|
||||||
|
ogs_assert(r != OGS_ERROR);
|
||||||
|
return OGS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check TAI */
|
/* Check TAI */
|
||||||
served_tai_index = mme_find_served_tai(&mme_ue->tai);
|
served_tai_index = mme_find_served_tai(&mme_ue->tai);
|
||||||
if (served_tai_index < 0) {
|
if (served_tai_index < 0) {
|
||||||
|
@ -504,6 +527,7 @@ int emm_handle_tau_request(mme_ue_t *mme_ue,
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
int served_tai_index = 0;
|
int served_tai_index = 0;
|
||||||
|
uint8_t emm_cause;
|
||||||
|
|
||||||
ogs_nas_eps_mobile_identity_guti_t *eps_mobile_identity_guti = NULL;
|
ogs_nas_eps_mobile_identity_guti_t *eps_mobile_identity_guti = NULL;
|
||||||
ogs_nas_eps_guti_t nas_guti;
|
ogs_nas_eps_guti_t nas_guti;
|
||||||
|
@ -570,6 +594,24 @@ int emm_handle_tau_request(mme_ue_t *mme_ue,
|
||||||
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
|
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
|
||||||
mme_ue->ue_location_timestamp = ogs_time_now();
|
mme_ue->ue_location_timestamp = ogs_time_now();
|
||||||
|
|
||||||
|
/* Check PLMN-ID access control */
|
||||||
|
emm_cause = emm_cause_from_access_control(&mme_ue->tai.plmn_id);
|
||||||
|
if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in TAI) access control");
|
||||||
|
r = nas_eps_send_tau_reject(mme_ue, emm_cause);
|
||||||
|
ogs_expect(r == OGS_OK);
|
||||||
|
ogs_assert(r != OGS_ERROR);
|
||||||
|
return OGS_ERROR;
|
||||||
|
}
|
||||||
|
emm_cause = emm_cause_from_access_control(&mme_ue->e_cgi.plmn_id);
|
||||||
|
if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in CGI) access control");
|
||||||
|
r = nas_eps_send_tau_reject(mme_ue, emm_cause);
|
||||||
|
ogs_expect(r == OGS_OK);
|
||||||
|
ogs_assert(r != OGS_ERROR);
|
||||||
|
return OGS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check TAI */
|
/* Check TAI */
|
||||||
served_tai_index = mme_find_served_tai(&mme_ue->tai);
|
served_tai_index = mme_find_served_tai(&mme_ue->tai);
|
||||||
if (served_tai_index < 0) {
|
if (served_tai_index < 0) {
|
||||||
|
@ -644,6 +686,7 @@ int emm_handle_extended_service_request(mme_ue_t *mme_ue,
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
int served_tai_index = 0;
|
int served_tai_index = 0;
|
||||||
|
uint8_t emm_cause;
|
||||||
|
|
||||||
ogs_nas_service_type_t *service_type =
|
ogs_nas_service_type_t *service_type =
|
||||||
&extended_service_request->service_type;
|
&extended_service_request->service_type;
|
||||||
|
@ -690,6 +733,24 @@ int emm_handle_extended_service_request(mme_ue_t *mme_ue,
|
||||||
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
|
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
|
||||||
mme_ue->ue_location_timestamp = ogs_time_now();
|
mme_ue->ue_location_timestamp = ogs_time_now();
|
||||||
|
|
||||||
|
/* Check PLMN-ID access control */
|
||||||
|
emm_cause = emm_cause_from_access_control(&mme_ue->tai.plmn_id);
|
||||||
|
if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in TAI) access control");
|
||||||
|
r = nas_eps_send_tau_reject(mme_ue, emm_cause);
|
||||||
|
ogs_expect(r == OGS_OK);
|
||||||
|
ogs_assert(r != OGS_ERROR);
|
||||||
|
return OGS_ERROR;
|
||||||
|
}
|
||||||
|
emm_cause = emm_cause_from_access_control(&mme_ue->e_cgi.plmn_id);
|
||||||
|
if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
ogs_error("Rejected by PLMN-ID(in CGI) access control");
|
||||||
|
r = nas_eps_send_tau_reject(mme_ue, emm_cause);
|
||||||
|
ogs_expect(r == OGS_OK);
|
||||||
|
ogs_assert(r != OGS_ERROR);
|
||||||
|
return OGS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check TAI */
|
/* Check TAI */
|
||||||
served_tai_index = mme_find_served_tai(&mme_ue->tai);
|
served_tai_index = mme_find_served_tai(&mme_ue->tai);
|
||||||
if (served_tai_index < 0) {
|
if (served_tai_index < 0) {
|
||||||
|
@ -767,3 +828,29 @@ int emm_handle_security_mode_complete(mme_ue_t *mme_ue,
|
||||||
|
|
||||||
return OGS_OK;
|
return OGS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t emm_cause_from_access_control(ogs_plmn_id_t *plmn_id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ogs_assert(plmn_id);
|
||||||
|
|
||||||
|
/* No Access Control */
|
||||||
|
if (mme_self()->num_of_access_control == 0)
|
||||||
|
return OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED;
|
||||||
|
|
||||||
|
for (i = 0; i < mme_self()->num_of_access_control; i++) {
|
||||||
|
if (memcmp(&mme_self()->access_control[i].plmn_id,
|
||||||
|
plmn_id, OGS_PLMN_ID_LEN) == 0) {
|
||||||
|
if (mme_self()->access_control[i].reject_cause)
|
||||||
|
return mme_self()->access_control[i].reject_cause;
|
||||||
|
else
|
||||||
|
return OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mme_self()->default_reject_cause)
|
||||||
|
return mme_self()->default_reject_cause;
|
||||||
|
|
||||||
|
return OGS_NAS_EMM_CAUSE_PLMN_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
|
@ -626,8 +626,7 @@ int mme_context_parse_config()
|
||||||
const char *plmn_id_key =
|
const char *plmn_id_key =
|
||||||
ogs_yaml_iter_key(&plmn_id_iter);
|
ogs_yaml_iter_key(&plmn_id_iter);
|
||||||
ogs_assert(plmn_id_key);
|
ogs_assert(plmn_id_key);
|
||||||
if (!strcmp(plmn_id_key, "mcc"))
|
if (!strcmp(plmn_id_key, "mcc")) {
|
||||||
{
|
|
||||||
mcc = ogs_yaml_iter_value(
|
mcc = ogs_yaml_iter_value(
|
||||||
&plmn_id_iter);
|
&plmn_id_iter);
|
||||||
} else if (!strcmp(
|
} else if (!strcmp(
|
||||||
|
@ -910,6 +909,81 @@ int mme_context_parse_config()
|
||||||
if (list2->num || num_of_list1 || num_of_list0) {
|
if (list2->num || num_of_list1 || num_of_list0) {
|
||||||
self.num_of_served_tai++;
|
self.num_of_served_tai++;
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(mme_key, "access_control")) {
|
||||||
|
ogs_yaml_iter_t access_control_array, access_control_iter;
|
||||||
|
ogs_yaml_iter_recurse(&mme_iter, &access_control_array);
|
||||||
|
do {
|
||||||
|
ogs_assert(self.num_of_access_control <
|
||||||
|
OGS_MAX_NUM_OF_ACCESS_CONTROL);
|
||||||
|
|
||||||
|
if (ogs_yaml_iter_type(&access_control_array) ==
|
||||||
|
YAML_MAPPING_NODE) {
|
||||||
|
memcpy(&access_control_iter, &access_control_array,
|
||||||
|
sizeof(ogs_yaml_iter_t));
|
||||||
|
} else if (ogs_yaml_iter_type(&access_control_array) ==
|
||||||
|
YAML_SEQUENCE_NODE) {
|
||||||
|
if (!ogs_yaml_iter_next(&access_control_array))
|
||||||
|
break;
|
||||||
|
ogs_yaml_iter_recurse(&access_control_array,
|
||||||
|
&access_control_iter);
|
||||||
|
} else if (ogs_yaml_iter_type(&access_control_array) ==
|
||||||
|
YAML_SCALAR_NODE) {
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
ogs_assert_if_reached();
|
||||||
|
|
||||||
|
while (ogs_yaml_iter_next(&access_control_iter)) {
|
||||||
|
const char *mnc = NULL, *mcc = NULL;
|
||||||
|
int reject_cause = 0;
|
||||||
|
const char *access_control_key =
|
||||||
|
ogs_yaml_iter_key(&access_control_iter);
|
||||||
|
ogs_assert(access_control_key);
|
||||||
|
if (!strcmp(access_control_key,
|
||||||
|
"default_reject_cause")) {
|
||||||
|
const char *v = ogs_yaml_iter_value(
|
||||||
|
&access_control_iter);
|
||||||
|
if (v) self.default_reject_cause = atoi(v);
|
||||||
|
} else if (!strcmp(access_control_key, "plmn_id")) {
|
||||||
|
ogs_yaml_iter_t plmn_id_iter;
|
||||||
|
|
||||||
|
ogs_yaml_iter_recurse(&access_control_iter,
|
||||||
|
&plmn_id_iter);
|
||||||
|
while (ogs_yaml_iter_next(&plmn_id_iter)) {
|
||||||
|
const char *plmn_id_key =
|
||||||
|
ogs_yaml_iter_key(&plmn_id_iter);
|
||||||
|
ogs_assert(plmn_id_key);
|
||||||
|
if (!strcmp(plmn_id_key, "reject_cause")) {
|
||||||
|
const char *v = ogs_yaml_iter_value(
|
||||||
|
&plmn_id_iter);
|
||||||
|
if (v) reject_cause = atoi(v);
|
||||||
|
} else if (!strcmp(plmn_id_key, "mcc")) {
|
||||||
|
mcc = ogs_yaml_iter_value(
|
||||||
|
&plmn_id_iter);
|
||||||
|
} else if (!strcmp(plmn_id_key, "mnc")) {
|
||||||
|
mnc = ogs_yaml_iter_value(
|
||||||
|
&plmn_id_iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mcc && mnc) {
|
||||||
|
ogs_plmn_id_build(
|
||||||
|
&self.access_control[
|
||||||
|
self.num_of_access_control].
|
||||||
|
plmn_id,
|
||||||
|
atoi(mcc), atoi(mnc), strlen(mnc));
|
||||||
|
if (reject_cause)
|
||||||
|
self.access_control[
|
||||||
|
self.num_of_access_control].
|
||||||
|
reject_cause = reject_cause;
|
||||||
|
self.num_of_access_control++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ogs_warn("unknown key `%s`",
|
||||||
|
access_control_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (ogs_yaml_iter_type(&access_control_array) ==
|
||||||
|
YAML_SEQUENCE_NODE);
|
||||||
} else if (!strcmp(mme_key, "security")) {
|
} else if (!strcmp(mme_key, "security")) {
|
||||||
ogs_yaml_iter_t security_iter;
|
ogs_yaml_iter_t security_iter;
|
||||||
ogs_yaml_iter_recurse(&mme_iter, &security_iter);
|
ogs_yaml_iter_recurse(&mme_iter, &security_iter);
|
||||||
|
@ -1002,7 +1076,8 @@ int mme_context_parse_config()
|
||||||
} while (
|
} while (
|
||||||
ogs_yaml_iter_type(&ciphering_order_iter) ==
|
ogs_yaml_iter_type(&ciphering_order_iter) ==
|
||||||
YAML_SEQUENCE_NODE);
|
YAML_SEQUENCE_NODE);
|
||||||
}
|
} else
|
||||||
|
ogs_warn("unknown key `%s`", security_key);
|
||||||
}
|
}
|
||||||
} else if (!strcmp(mme_key, "network_name")) {
|
} else if (!strcmp(mme_key, "network_name")) {
|
||||||
ogs_yaml_iter_t network_name_iter;
|
ogs_yaml_iter_t network_name_iter;
|
||||||
|
@ -1046,7 +1121,8 @@ int mme_context_parse_config()
|
||||||
network_short_name->length = size*2+1;
|
network_short_name->length = size*2+1;
|
||||||
network_short_name->coding_scheme = 1;
|
network_short_name->coding_scheme = 1;
|
||||||
network_short_name->ext = 1;
|
network_short_name->ext = 1;
|
||||||
}
|
} else
|
||||||
|
ogs_warn("unknown key `%s`", network_name_key);
|
||||||
}
|
}
|
||||||
} else if (!strcmp(mme_key, "sgsap")) {
|
} else if (!strcmp(mme_key, "sgsap")) {
|
||||||
ogs_yaml_iter_t sgsap_array, sgsap_iter;
|
ogs_yaml_iter_t sgsap_array, sgsap_iter;
|
||||||
|
|
|
@ -109,6 +109,14 @@ typedef struct mme_context_s {
|
||||||
ogs_eps_tai2_list_t list2;
|
ogs_eps_tai2_list_t list2;
|
||||||
} served_tai[OGS_MAX_NUM_OF_SERVED_TAI];
|
} served_tai[OGS_MAX_NUM_OF_SERVED_TAI];
|
||||||
|
|
||||||
|
/* Access Control */
|
||||||
|
int default_reject_cause;
|
||||||
|
int num_of_access_control;
|
||||||
|
struct {
|
||||||
|
int reject_cause;
|
||||||
|
ogs_plmn_id_t plmn_id;
|
||||||
|
} access_control[OGS_MAX_NUM_OF_ACCESS_CONTROL];
|
||||||
|
|
||||||
/* defined in 'nas_ies.h'
|
/* defined in 'nas_ies.h'
|
||||||
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
|
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
|
||||||
* #define NAS_SECURITY_ALGORITHMS_128_EEA1 1
|
* #define NAS_SECURITY_ALGORITHMS_128_EEA1 1
|
||||||
|
|
Loading…
Reference in New Issue