diff --git a/include/osmocom/msc/vlr.h b/include/osmocom/msc/vlr.h index 499aa37c0..86a72f203 100644 --- a/include/osmocom/msc/vlr.h +++ b/include/osmocom/msc/vlr.h @@ -68,6 +68,7 @@ enum vlr_lu_event { VLR_ULA_E_SEND_ID_ACK, /* Result of Send-ID from PVLR */ VLR_ULA_E_SEND_ID_NACK, /* Result of Send-ID from PVLR */ VLR_ULA_E_AUTH_SUCCESS, /* Successful result of auth procedure */ + VLR_ULA_E_AUTH_NO_INFO, /* HLR returned SAI NACK, possibly continue without auth */ VLR_ULA_E_AUTH_FAILURE, /* Auth procedure failed */ VLR_ULA_E_CIPH_RES, /* Result of Ciphering Mode Command */ VLR_ULA_E_ID_IMSI, /* IMSI received from MS */ @@ -438,6 +439,7 @@ enum proc_arq_vlr_event { PR_ARQ_E_START, PR_ARQ_E_ID_IMSI, PR_ARQ_E_AUTH_RES, + PR_ARQ_E_AUTH_NO_INFO, PR_ARQ_E_AUTH_FAILURE, PR_ARQ_E_CIPH_RES, PR_ARQ_E_UPD_LOC_RES, diff --git a/src/libvlr/vlr_access_req_fsm.c b/src/libvlr/vlr_access_req_fsm.c index 2c9009eba..629625ea4 100644 --- a/src/libvlr/vlr_access_req_fsm.c +++ b/src/libvlr/vlr_access_req_fsm.c @@ -40,6 +40,7 @@ static const struct value_string proc_arq_vlr_event_names[] = { OSMO_VALUE_STRING(PR_ARQ_E_START), OSMO_VALUE_STRING(PR_ARQ_E_ID_IMSI), OSMO_VALUE_STRING(PR_ARQ_E_AUTH_RES), + OSMO_VALUE_STRING(PR_ARQ_E_AUTH_NO_INFO), OSMO_VALUE_STRING(PR_ARQ_E_AUTH_FAILURE), OSMO_VALUE_STRING(PR_ARQ_E_CIPH_RES), OSMO_VALUE_STRING(PR_ARQ_E_UPD_LOC_RES), @@ -289,7 +290,10 @@ static void _proc_arq_vlr_node2(struct osmo_fsm_inst *fi) LOGPFSM(fi, "%s()\n", __func__); - if (!is_cmc_smc_to_be_attempted(par)) { + /* Continue with ciphering, if enabled. + * If auth/ciph is optional and the HLR returned no auth info, continue without ciphering. */ + if (!is_cmc_smc_to_be_attempted(par) + || (vsub->sec_ctx == VLR_SEC_CTX_NONE && !par->is_ciphering_required)) { _proc_arq_vlr_node2_post_ciph(fi); return; } @@ -345,7 +349,7 @@ static void proc_arq_vlr_fn_post_imsi(struct osmo_fsm_inst *fi) 0, 0); vsub->auth_fsm = auth_fsm_start(vsub, fi, PR_ARQ_E_AUTH_RES, - PR_ARQ_E_AUTH_FAILURE, + PR_ARQ_E_AUTH_NO_INFO, PR_ARQ_E_AUTH_FAILURE, par->is_r99, par->is_utran); @@ -439,6 +443,7 @@ static void proc_arq_vlr_fn_w_obt_imsi(struct osmo_fsm_inst *fi, static void proc_arq_vlr_fn_w_auth(struct osmo_fsm_inst *fi, uint32_t event, void *data) { + struct proc_arq_priv *par = fi->priv; enum gsm48_reject_value *cause = data; switch (event) { @@ -448,7 +453,19 @@ static void proc_arq_vlr_fn_w_auth(struct osmo_fsm_inst *fi, return; case PR_ARQ_E_AUTH_FAILURE: - proc_arq_fsm_done(fi, cause? *cause : GSM48_REJECT_NETWORK_FAILURE); + proc_arq_fsm_done(fi, cause ? *cause : GSM48_REJECT_NETWORK_FAILURE); + return; + + case PR_ARQ_E_AUTH_NO_INFO: + /* HLR returned no auth info for the subscriber. Continue only if authentication is optional. */ + if (par->authentication_required) { + proc_arq_fsm_done(fi, cause ? *cause : GSM48_REJECT_NETWORK_FAILURE); + return; + } + LOGPFSML(fi, LOGL_INFO, + "Attaching subscriber without auth (auth is optional, and no auth info received from HLR)\n"); + /* Node 2 */ + _proc_arq_vlr_node2(fi); return; default: @@ -559,6 +576,7 @@ static const struct osmo_fsm_state proc_arq_vlr_states[] = { [PR_ARQ_S_WAIT_AUTH] = { .name = OSMO_STRINGIFY(PR_ARQ_S_WAIT_AUTH), .in_event_mask = S(PR_ARQ_E_AUTH_RES) | + S(PR_ARQ_E_AUTH_NO_INFO) | S(PR_ARQ_E_AUTH_FAILURE), .out_state_mask = S(PR_ARQ_S_DONE) | S(PR_ARQ_S_WAIT_CIPH) | diff --git a/src/libvlr/vlr_lu_fsm.c b/src/libvlr/vlr_lu_fsm.c index a65421caa..7500c8622 100644 --- a/src/libvlr/vlr_lu_fsm.c +++ b/src/libvlr/vlr_lu_fsm.c @@ -643,6 +643,7 @@ static const struct value_string fsm_lu_event_names[] = { OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_ACK), OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_NACK), OSMO_VALUE_STRING(VLR_ULA_E_AUTH_SUCCESS), + OSMO_VALUE_STRING(VLR_ULA_E_AUTH_NO_INFO), OSMO_VALUE_STRING(VLR_ULA_E_AUTH_FAILURE), OSMO_VALUE_STRING(VLR_ULA_E_CIPH_RES), OSMO_VALUE_STRING(VLR_ULA_E_ID_IMSI), @@ -861,7 +862,10 @@ static void vlr_loc_upd_post_auth(struct osmo_fsm_inst *fi) OSMO_ASSERT(vsub); - if (!is_cmc_smc_to_be_attempted(lfp)) { + /* Continue with ciphering, if enabled. + * If auth/ciph is optional and the HLR returned no auth info, continue without ciphering. */ + if (!is_cmc_smc_to_be_attempted(lfp) + || (vsub->sec_ctx == VLR_SEC_CTX_NONE && !lfp->is_ciphering_required)) { vlr_loc_upd_post_ciph(fi); return; } @@ -913,7 +917,7 @@ static void vlr_loc_upd_node1(struct osmo_fsm_inst *fi) vsub->auth_fsm = auth_fsm_start(lfp->vsub, fi, VLR_ULA_E_AUTH_SUCCESS, - VLR_ULA_E_AUTH_FAILURE, + VLR_ULA_E_AUTH_NO_INFO, VLR_ULA_E_AUTH_FAILURE, lfp->is_r99, lfp->is_utran); @@ -1156,7 +1160,18 @@ static void lu_fsm_wait_auth(struct osmo_fsm_inst *fi, uint32_t event, return; case VLR_ULA_E_AUTH_FAILURE: - lu_fsm_failure(fi, res? *res : GSM48_REJECT_NETWORK_FAILURE); + lu_fsm_failure(fi, res ? *res : GSM48_REJECT_NETWORK_FAILURE); + return; + + case VLR_ULA_E_AUTH_NO_INFO: + /* HLR returned no auth info for the subscriber. Continue only if authentication is optional. */ + if (lfp->authentication_required || lfp->is_ciphering_required) { + lu_fsm_failure(fi, res ? *res : GSM48_REJECT_NETWORK_FAILURE); + return; + } + LOGPFSML(fi, LOGL_INFO, + "Attaching subscriber without auth (auth is optional, and no auth info received from HLR)\n"); + vlr_loc_upd_post_auth(fi); return; default: @@ -1377,6 +1392,7 @@ static const struct osmo_fsm_state vlr_lu_fsm_states[] = { }, [VLR_ULA_S_WAIT_AUTH] = { .in_event_mask = S(VLR_ULA_E_AUTH_SUCCESS) | + S(VLR_ULA_E_AUTH_NO_INFO) | S(VLR_ULA_E_AUTH_FAILURE), .out_state_mask = S(VLR_ULA_S_WAIT_CIPH) | S(VLR_ULA_S_WAIT_LU_COMPL) | diff --git a/tests/msc_vlr/msc_vlr_test_hlr_reject.err b/tests/msc_vlr/msc_vlr_test_hlr_reject.err index 45a92ca6e..26d573604 100644 --- a/tests/msc_vlr/msc_vlr_test_hlr_reject.err +++ b/tests/msc_vlr/msc_vlr_test_hlr_reject.err @@ -47,7 +47,7 @@ DVLR VLR_Authenticate(IMSI-901700000004620:GERAN-A:LU){VLR_SUB_AS_NEEDS_AUTH_WAI DVLR VLR_Authenticate(IMSI-901700000004620:GERAN-A:LU){VLR_SUB_AS_NEEDS_AUTH_WAIT_AI}: state_chg to VLR_SUB_AS_AUTH_FAILED DVLR VLR_Authenticate(IMSI-901700000004620:GERAN-A:LU){VLR_SUB_AS_AUTH_FAILED}: Terminating (cause = OSMO_FSM_TERM_REGULAR) DVLR VLR_Authenticate(IMSI-901700000004620:GERAN-A:LU){VLR_SUB_AS_AUTH_FAILED}: Removing from parent vlr_lu_fsm(IMSI-901700000004620:GERAN-A:LU) -DVLR vlr_lu_fsm(IMSI-901700000004620:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: Received Event VLR_ULA_E_AUTH_FAILURE +DVLR vlr_lu_fsm(IMSI-901700000004620:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: Received Event VLR_ULA_E_AUTH_NO_INFO - sending LU Reject for IMSI-901700000004620:GERAN-A:LU, cause 2 DVLR vlr_lu_fsm(IMSI-901700000004620:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: state_chg to VLR_ULA_S_DONE DMSC msc_a(IMSI-901700000004620:GERAN-A:LU){MSC_A_ST_AUTH_CIPH}: Received Event MSC_A_EV_CN_CLOSE @@ -146,7 +146,7 @@ DVLR VLR_Authenticate(IMSI-901700000004620:GERAN-A:LU){VLR_SUB_AS_NEEDS_AUTH_WAI DVLR VLR_Authenticate(IMSI-901700000004620:GERAN-A:LU){VLR_SUB_AS_NEEDS_AUTH_WAIT_AI}: state_chg to VLR_SUB_AS_AUTH_FAILED DVLR VLR_Authenticate(IMSI-901700000004620:GERAN-A:LU){VLR_SUB_AS_AUTH_FAILED}: Terminating (cause = OSMO_FSM_TERM_REGULAR) DVLR VLR_Authenticate(IMSI-901700000004620:GERAN-A:LU){VLR_SUB_AS_AUTH_FAILED}: Removing from parent vlr_lu_fsm(IMSI-901700000004620:GERAN-A:LU) -DVLR vlr_lu_fsm(IMSI-901700000004620:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: Received Event VLR_ULA_E_AUTH_FAILURE +DVLR vlr_lu_fsm(IMSI-901700000004620:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: Received Event VLR_ULA_E_AUTH_NO_INFO - sending LU Reject for IMSI-901700000004620:GERAN-A:LU, cause 17 DVLR vlr_lu_fsm(IMSI-901700000004620:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: state_chg to VLR_ULA_S_DONE DMSC msc_a(IMSI-901700000004620:GERAN-A:LU){MSC_A_ST_AUTH_CIPH}: Received Event MSC_A_EV_CN_CLOSE @@ -742,7 +742,7 @@ DVLR VLR_Authenticate(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_SUB_AS_N DVLR VLR_Authenticate(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_SUB_AS_NEEDS_AUTH_WAIT_AI}: state_chg to VLR_SUB_AS_AUTH_FAILED DVLR VLR_Authenticate(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_SUB_AS_AUTH_FAILED}: Terminating (cause = OSMO_FSM_TERM_REGULAR) DVLR VLR_Authenticate(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_SUB_AS_AUTH_FAILED}: Removing from parent vlr_lu_fsm(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU) -DVLR vlr_lu_fsm(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: Received Event VLR_ULA_E_AUTH_FAILURE +DVLR vlr_lu_fsm(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: Received Event VLR_ULA_E_AUTH_NO_INFO - sending LU Reject for IMSI-901700000004620:MSISDN-46071:GERAN-A:LU, cause 17 DVLR vlr_lu_fsm(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: state_chg to VLR_ULA_S_DONE DMSC msc_a(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){MSC_A_ST_AUTH_CIPH}: Received Event MSC_A_EV_CN_CLOSE @@ -1010,7 +1010,7 @@ DVLR VLR_Authenticate(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_SUB_AS_N DVLR VLR_Authenticate(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_SUB_AS_NEEDS_AUTH_WAIT_AI}: state_chg to VLR_SUB_AS_AUTH_FAILED DVLR VLR_Authenticate(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_SUB_AS_AUTH_FAILED}: Terminating (cause = OSMO_FSM_TERM_REGULAR) DVLR VLR_Authenticate(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_SUB_AS_AUTH_FAILED}: Removing from parent vlr_lu_fsm(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU) -DVLR vlr_lu_fsm(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: Received Event VLR_ULA_E_AUTH_FAILURE +DVLR vlr_lu_fsm(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: Received Event VLR_ULA_E_AUTH_NO_INFO - sending LU Reject for IMSI-901700000004620:MSISDN-46071:GERAN-A:LU, cause 2 DVLR vlr_lu_fsm(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){VLR_ULA_S_WAIT_AUTH}: state_chg to VLR_ULA_S_DONE DMSC msc_a(IMSI-901700000004620:MSISDN-46071:GERAN-A:LU){MSC_A_ST_AUTH_CIPH}: Received Event MSC_A_EV_CN_CLOSE