Skip to content

Commit

Permalink
fix(amf): handle and proper response the error code from subscriberdb…
Browse files Browse the repository at this point in the history
… during authentication

Signed-off-by: RahulKalsangra <rahul.kalsangra@wavelabs.ai>
  • Loading branch information
RahulKalsangra committed Feb 16, 2022
1 parent 0f16c0d commit 05ebfdc
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 21 deletions.
4 changes: 4 additions & 0 deletions lte/gateway/c/core/oai/include/amf_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#define MAX_APN_CORRECTION_MAP_LIST 10
#define AMF_S_NSSAI_ST_DEFAULT_VALUE 1
#define AMF_S_NSSAI_SD_INVALID_VALUE 0xffffff
#define AUTHENTICATION_COUNTER_MAX_RETRY "AUTHENTICATION_MAX_RETRY"
#define AUTHENTICATION_RETRY_TIMER_EXPIRY_MSECS "AUTHENTICATION_TIMER_EXPIRY"

#define AMF_CONFIG_STRING_AMF_CONFIG "AMF"
#define AMF_CONFIG_STRING_DEFAULT_DNS_IPV4_ADDRESS "DEFAULT_DNS_IPV4_ADDRESS"
Expand Down Expand Up @@ -179,6 +181,8 @@ typedef struct amf_config_s {
} ipv4;
bstring amf_name;
bstring default_dnn;
uint32_t auth_retry_interval;
uint32_t auth_retry_max_count;
} amf_config_t;

int amf_app_init(amf_config_t*);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ struct amf_procedures_t;
#define PDU_ADDR_IPV4_LEN 0x4
#define GNB_IPV4_ADDR_LEN 4
#define GNB_TEID_LEN 4

#define DIAMETER_TOO_BUSY 3004
#define NON_AMF_3GPP_ACCESS 2
#define AMF_3GPP_ACCESS_AND_NON_AMF_3GPP_ACCESS 3

Expand Down Expand Up @@ -350,6 +350,8 @@ typedef struct amf_context_s {
apn_config_profile_t apn_config_profile;

amf_nas_message_decode_status_t decode_status;
nas5g_timer_t auth_retry_timer;
int auth_retry_count = 0;
} amf_context_t;

// Amf-Map Declarations:
Expand Down
45 changes: 37 additions & 8 deletions lte/gateway/c/core/oai/tasks/amf/amf_authentication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ static int start_authentication_information_procedure(
OAILOG_FUNC_IN(LOG_NAS_AMF);

int rc = RETURNerror;
char imsi_str[IMSI_BCD_DIGITS_MAX + 1];
uint8_t snni[40] = {0};

amf_ue_ngap_id_t ue_id =
PARENT_STRUCT(amf_context, ue_m5gmm_context_s, amf_context)
Expand All @@ -121,30 +119,61 @@ static int start_authentication_information_procedure(
auth_info_proc->ue_id = ue_id;
auth_info_proc->resync = auth_info_proc->request_sent;

bool is_initial_req = !(auth_info_proc->request_sent);
auth_info_proc->request_sent = true;
auth_proc->auts = auts;

rc = amf_authentication_request_sent(ue_id);
if (rc != RETURNok) {
OAILOG_FUNC_RETURN(LOG_NAS_AMF, rc);
}

OAILOG_FUNC_RETURN(LOG_NAS_AMF, RETURNok);
}

int amf_authentication_request_sent(amf_ue_ngap_id_t ue_id) {
ue_m5gmm_context_s* ue_mm_context = NULL;
amf_context_t* amf_context = NULL;
char imsi_str[IMSI_BCD_DIGITS_MAX + 1];
int rc = RETURNerror;
ue_mm_context = amf_ue_context_exists_amf_ue_ngap_id(ue_id);
uint8_t snni[40] = {0};
if (!ue_mm_context) {
OAILOG_WARNING(LOG_NAS_AMF,
"AMF-PROC - Failed authentication request the UE due to NULL"
"ue_context\n");
OAILOG_FUNC_RETURN(LOG_NAS_AMF, rc);
}
amf_context = &ue_mm_context->amf_context;
nas5g_amf_auth_proc_t* auth_proc =
get_nas5g_common_procedure_authentication(amf_context);

if (!auth_proc) {
OAILOG_WARNING(LOG_NAS_AMF, "authentication procedure not present\n");
OAILOG_FUNC_RETURN(LOG_NAS_AMF, rc);
}
IMSI64_TO_STRING(amf_context->imsi64, imsi_str, IMSI_LENGTH);

rc = calculate_amf_serving_network_name(amf_context, snni);
if (rc != RETURNok) {
OAILOG_FUNC_RETURN(LOG_NAS_AMF, rc);
}

if (is_initial_req) {
nas5g_auth_info_proc_t* auth_info_proc =
get_nas5g_cn_procedure_auth_info(amf_context);
auth_info_proc->request_sent = true;
if (!auth_proc->auts) {
OAILOG_INFO(LOG_AMF_APP,
"Sending msg(grpc) to :[subscriberdb] for ue: [%s] auth-info\n",
imsi_str);
AMFClientServicer::getInstance().get_subs_auth_info(
imsi_str, IMSI_LENGTH, reinterpret_cast<const char*>(snni), ue_id);
} else if (auts->data) {
} else if (auth_proc->auts) {
OAILOG_INFO(
LOG_AMF_APP,
"Sending msg(grpc) to :[subscriberdb] for ue: [%s] auth-info-resync\n",
imsi_str);
AMFClientServicer::getInstance().get_subs_auth_info_resync(
imsi_str, IMSI_LENGTH, reinterpret_cast<const char*>(snni), auts->data,
RAND_LENGTH_OCTETS + AUTS_LENGTH, ue_id);
imsi_str, IMSI_LENGTH, reinterpret_cast<const char*>(snni),
auth_proc->auts->data, RAND_LENGTH_OCTETS + AUTS_LENGTH, ue_id);
}

OAILOG_FUNC_RETURN(LOG_NAS_AMF, RETURNok);
Expand Down
3 changes: 2 additions & 1 deletion lte/gateway/c/core/oai/tasks/amf/amf_authentication.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ typedef struct nas5g_amf_auth_proc_s {
int amf_cause;
int retry_sync_failure;
#define MAX_SYNC_FAILURES 2
const_bstring auts;
} nas5g_amf_auth_proc_t;

typedef struct nas5g_auth_info_proc_s {
Expand Down Expand Up @@ -77,7 +78,7 @@ int amf_send_authentication_request(amf_context_t* amf_context,

// To be called when authentication is successful from subscriberdb
int amf_authentication_proc_success(amf_context_t* amf_context);

int amf_authentication_request_sent(amf_ue_ngap_id_t ue_id);
int amf_nas_proc_authentication_info_answer(itti_amf_subs_auth_info_ans_t* aia);
nas5g_amf_auth_proc_t* get_nas5g_common_procedure_authentication(
const amf_context_t* const ctxt);
Expand Down
11 changes: 11 additions & 0 deletions lte/gateway/c/core/oai/tasks/amf/amf_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,17 @@ int amf_config_parse_file(amf_config_t* config_pP,
(const char**)&astring)) {
config_pP->default_dnn = bfromcstr(astring);
}
// DEFAULT AUTH MAX RETRY COUNT
if (config_setting_lookup_string(
setting_amf, AUTHENTICATION_COUNTER_MAX_RETRY, &astring)) {
config_pP->auth_retry_max_count = (uint32_t)atoi(astring);
}

// DEFAULT AUTH RETRY TIMER EXPIRES MSECS
if (config_setting_lookup_string(
setting_amf, AUTHENTICATION_RETRY_TIMER_EXPIRY_MSECS, &astring)) {
config_pP->auth_retry_interval = (uint32_t)atoi(astring);
}

// AMF_PLMN_SUPPORT SETTING
setting = config_setting_get_member(setting_amf,
Expand Down
87 changes: 76 additions & 11 deletions lte/gateway/c/core/oai/tasks/amf/nas_proc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ extern task_zmq_ctx_s amf_app_task_zmq_ctx;
AmfMsg amf_msg_obj;
extern std::unordered_map<imsi64_t, guti_and_amf_id_t> amf_supi_guti_map;
static int identification_t3570_handler(zloop_t* loop, int timer_id, void* arg);
static int subs_auth_retry(zloop_t* loop, int timer_id, void* output);
int nas_proc_establish_ind(const amf_ue_ngap_id_t ue_id,
const bool is_mm_ctx_new,
const tai_t originating_tai, const ecgi_t ecgi,
Expand Down Expand Up @@ -411,10 +412,54 @@ int amf_nas_proc_auth_param_res(amf_ue_ngap_id_t amf_ue_ngap_id,
OAILOG_FUNC_RETURN(LOG_NAS_AMF, rc);
}

static int subs_auth_retry(zloop_t* loop, int timer_id, void* arg) {
amf_ue_ngap_id_t ue_id = 0;
amf_context_t* amf_ctxt_p = NULL;
int amf_cause = -1;
nas5g_auth_info_proc_t* auth_info_proc = NULL;
int rc = RETURNerror;
ue_m5gmm_context_s* ue_mm_context = NULL;
if (!amf_pop_timer_arg(timer_id, &ue_id)) {
OAILOG_WARNING(
LOG_AMF_APP,
"auth_retry_timer: Invalid Timer Id expiration, Timer Id: %d \n",
timer_id);
OAILOG_FUNC_RETURN(LOG_NAS_AMF, RETURNok);
}
ue_mm_context = amf_ue_context_exists_amf_ue_ngap_id(ue_id);
amf_ctxt_p = &ue_mm_context->amf_context;
if (amf_ctxt_p->auth_retry_count < amf_config.auth_retry_max_count) {
amf_ctxt_p->auth_retry_count++;
OAILOG_INFO(LOG_AMF_APP,
"auth_retry_timer: Incrementing auth_retry_count to %d\n",
amf_ctxt_p->auth_retry_count);
rc = amf_authentication_request_sent(ue_id);
amf_ctxt_p->auth_retry_timer.id =
amf_app_start_timer(amf_config.auth_retry_interval, TIMER_REPEAT_ONCE,
subs_auth_retry, ue_id);
} else {
auth_info_proc = get_nas5g_cn_procedure_auth_info(amf_ctxt_p);
OAILOG_ERROR(
LOG_NAS_AMF,
"auth_retry_timer is expired . Authentication reject with cause "
"AMF_UE_ILLEGAL\n");
amf_cause = AMF_UE_ILLEGAL;

rc = amf_proc_registration_reject(ue_id, amf_cause);
if (auth_info_proc) {
nas5g_delete_cn_procedure(amf_ctxt_p, &auth_info_proc->cn_proc);
}

amf_free_ue_context(ue_mm_context);
}

return rc;
}

int amf_nas_proc_authentication_info_answer(
itti_amf_subs_auth_info_ans_t* aia) {
imsi64_t imsi64 = INVALID_IMSI64;
int rc = RETURNerror;
int rc = RETURNok;
amf_context_t* amf_ctxt_p = NULL;
ue_m5gmm_context_s* ue_5gmm_context_p = NULL;
int amf_cause = -1;
Expand Down Expand Up @@ -444,8 +489,13 @@ int amf_nas_proc_authentication_info_answer(
"Received Authentication Information Answer from Subscriberdb for"
" UE ID = " AMF_UE_NGAP_ID_FMT,
amf_ue_ngap_id);

if (aia->auth_info.nb_of_vectors) {
if ((NAS5G_TIMER_INACTIVE_ID != amf_ctxt_p->auth_retry_timer.id) &&
(0 != amf_ctxt_p->auth_retry_timer.id)) {
OAILOG_DEBUG(LOG_NAS_AMF, "Stopping: Timer auth_retry_timer.\n");
amf_app_stop_timer(amf_ctxt_p->auth_retry_timer.id);
amf_ctxt_p->auth_retry_timer.id = NAS5G_TIMER_INACTIVE_ID;
}
/*
* Check that list is not empty and contain at most MAX_EPS_AUTH_VECTORS
* elements
Expand All @@ -466,17 +516,32 @@ int amf_nas_proc_authentication_info_answer(
} else {
/* Get Auth Info Pro */
auth_info_proc = get_nas5g_cn_procedure_auth_info(amf_ctxt_p);
OAILOG_ERROR(LOG_NAS_AMF,
"result=%d, nb_of_vectors received is zero from subscriberdb",
aia->result);
amf_cause = AMF_UE_ILLEGAL;
rc = amf_proc_registration_reject(amf_ue_ngap_id, amf_cause);
if (auth_info_proc) {
nas5g_delete_cn_procedure(amf_ctxt_p, &auth_info_proc->cn_proc);
amf_ctxt_p->auth_retry_count = 0;
if (aia->result != DIAMETER_TOO_BUSY) {
if ((NAS5G_TIMER_INACTIVE_ID != amf_ctxt_p->auth_retry_timer.id) &&
(0 != amf_ctxt_p->auth_retry_timer.id)) {
OAILOG_DEBUG(LOG_NAS_AMF, "Stopping: Timer auth_retry_timer.\n");
amf_app_stop_timer(amf_ctxt_p->auth_retry_timer.id);
amf_ctxt_p->auth_retry_timer.id = NAS5G_TIMER_INACTIVE_ID;
}
OAILOG_ERROR(
LOG_NAS_AMF,
"result=%d, nb_of_vectors received is zero from subscriberdb",
aia->result);
amf_cause = AMF_UE_ILLEGAL;
rc = amf_proc_registration_reject(amf_ue_ngap_id, amf_cause);
if (auth_info_proc) {
nas5g_delete_cn_procedure(amf_ctxt_p, &auth_info_proc->cn_proc);
}
amf_free_ue_context(ue_5gmm_context_p);
return rc;
} else {
amf_ctxt_p->auth_retry_timer.id =
amf_app_start_timer(amf_config.auth_retry_interval, TIMER_REPEAT_ONCE,
subs_auth_retry, aia->ue_id);
rc = RETURNok;
}
amf_free_ue_context(ue_5gmm_context_p);
}

OAILOG_FUNC_RETURN(LOG_NAS_AMF, rc);
}

Expand Down
47 changes: 47 additions & 0 deletions lte/gateway/c/core/oai/tasks/ngap/ngap_amf_decoder.c.orig
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright 2020 The Magma Authors.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/****************************************************************************
Subsystem Access and Mobility Management Function
Description Defines NG Application Protocol Messages
*****************************************************************************/

#include <stdbool.h>
#include <string.h>

#include "lte/gateway/c/core/oai/tasks/ngap/ngap_amf_decoder.h"
#include "lte/gateway/c/core/oai/lib/bstr/bstrlib.h"
#include "lte/gateway/c/core/oai/common/log.h"
#include "lte/gateway/c/core/oai/common/assertions.h"
#include "lte/gateway/c/core/oai/common/common_defs.h"
#include "Ngap_NGAP-PDU.h"
#include "Ngap_InitiatingMessage.h"
#include "Ngap_ProcedureCode.h"
#include "Ngap_SuccessfulOutcome.h"
#include "Ngap_UnsuccessfulOutcome.h"
#include "asn_codecs.h"
#include "constr_TYPE.h"
#include "per_decoder.h"

int ngap_amf_decode_pdu(Ngap_NGAP_PDU_t* pdu, const_bstring const raw) {
asn_dec_rval_t dec_ret;
DevAssert(pdu != NULL);
DevAssert(blength(raw) != 0);
dec_ret = aper_decode(NULL, &asn_DEF_Ngap_NGAP_PDU, (void**)&pdu, bdata(raw),
blength(raw), 0, 0);

if (dec_ret.code != RC_OK) {
OAILOG_ERROR(LOG_NGAP, "Failed to decode PDU\n");
return -1;
}
return 0;
}
35 changes: 35 additions & 0 deletions lte/gateway/c/core/oai/test/amf/test_amf_procedures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1292,4 +1292,39 @@ TEST_F(AMFAppProcedureTest, ServiceRequestMTWithPDU) {

EXPECT_TRUE(expected_Ids == AMFClientServicer::getInstance().msgtype_stack);
}

TEST_F(AMFAppProcedureTest, TestAuthFailureFromSubscribeDbLock) {
amf_ue_ngap_id_t ue_id = 0;
amf_context_t* amf_ctxt_p = NULL;
nas5g_auth_info_proc_t* auth_info_proc = NULL;
ue_m5gmm_context_s* ue_context_p = nullptr;
std::vector<MessagesIds> expected_Ids{
AMF_APP_NGAP_AMF_UE_ID_NOTIFICATION, // new registration notification
// indication to ngap
NGAP_NAS_DL_DATA_REQ, // Registration Reject
NGAP_UE_CONTEXT_RELEASE_COMMAND // UEContextReleaseCommand
};

/* Send the initial UE message */
imsi64_t imsi64 = 0;
imsi64 = send_initial_ue_message_no_tmsi(amf_app_desc_p, 36, 1, 1, 0, plmn,
initial_ue_message_hexbuf,
sizeof(initial_ue_message_hexbuf));
/* Check if UE Context is created with correct imsi */
EXPECT_TRUE(get_ue_id_from_imsi(amf_app_desc_p, imsi64, &ue_id));

/* Send the authentication response message from subscriberdb */
itti_amf_subs_auth_info_ans_t aia_itti_msg = {};
strncpy(aia_itti_msg.imsi, imsi.c_str(), imsi.size());
aia_itti_msg.imsi_length = imsi.size();
aia_itti_msg.result = DIAMETER_TOO_BUSY;
int rc = RETURNerror;
rc = amf_nas_proc_authentication_info_answer(&aia_itti_msg);
EXPECT_TRUE(rc == RETURNok);
ue_context_p = amf_ue_context_exists_amf_ue_ngap_id(ue_id);
amf_ctxt_p = &ue_context_p->amf_context;
auth_info_proc = get_nas5g_cn_procedure_auth_info(amf_ctxt_p);
nas5g_delete_cn_procedure(amf_ctxt_p, &auth_info_proc->cn_proc);
amf_free_ue_context(ue_context_p);
}
} // namespace magma5g
2 changes: 2 additions & 0 deletions lte/gateway/configs/templates/mme.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ AMF :
DEFAULT_DNS_SEC_IPV4_ADDRESS = "{{ ipv4_sec_dns }}";
AMF_NAME = "{{ amf_name }}";
DEFAULT_DNN = "{{ default_dnn }}";
AUTHENTICATION_MAX_RETRY = "{{ auth_retry_max_count }}";
AUTHENTICATION_TIMER_EXPIRY = "{{ auth_retry_interval }}";
PLMN_SUPPORT_LIST = (
{ MCC="{{ mcc }}" ; MNC="{{ mnc }}"; AMF_DEFAULT_SLICE_SERVICE_TYPE="{{ amf_default_slice_service_type }}" ; AMF_DEFAULT_SLICE_DIFFERENTIATOR="{{ amf_default_slice_differentiator }}"; }
);
Expand Down

0 comments on commit 05ebfdc

Please sign in to comment.