open5gs/src/mme/nas-path.c

976 lines
26 KiB
C
Raw Normal View History

2019-07-11 12:53:54 +00:00
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2019-06-01 09:52:38 +00:00
#include "s1ap-path.h"
2019-06-11 13:10:47 +00:00
#include "s1ap-build.h"
#include "esm-build.h"
#include "emm-build.h"
#include "nas-path.h"
#include "mme-event.h"
2019-07-20 12:28:36 +00:00
#include "mme-timer.h"
2019-06-11 13:10:47 +00:00
#include "mme-sm.h"
2017-08-10 08:02:53 +00:00
2020-05-23 02:24:48 +00:00
int nas_eps_send_to_enb(mme_ue_t *mme_ue, ogs_pkbuf_t *pkbuf)
2017-08-10 08:02:53 +00:00
{
int rv;
ogs_assert(pkbuf);
2017-08-10 08:02:53 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
ogs_pkbuf_free(pkbuf);
return OGS_NOTFOUND;
}
2017-08-10 08:02:53 +00:00
rv = s1ap_send_to_enb_ue(mme_ue->enb_ue, pkbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-08-10 08:02:53 +00:00
}
2020-05-23 02:24:48 +00:00
int nas_eps_send_emm_to_esm(mme_ue_t *mme_ue,
2019-09-13 12:07:47 +00:00
ogs_nas_esm_message_container_t *esm_message_container)
2017-09-07 06:56:31 +00:00
{
2019-11-30 07:45:09 +00:00
int rv;
2019-04-27 14:54:30 +00:00
ogs_pkbuf_t *esmbuf = NULL;
2017-09-07 06:56:31 +00:00
[SEC] Several vulnerabilities have been resolved. 1. Reachable assertion in ogs_nas_5gmm_decode Location: lib/nas/5gs/decoder.c:4445 ```c int ogs_nas_5gmm_decode(ogs_nas_5gs_message_t *message, ogs_pkbuf_t *pkbuf) { int size = 0; int decoded = 0; ogs_assert(pkbuf); ogs_assert(pkbuf->data); ogs_assert(pkbuf->len); ``` When a NAS payload is received over `src/amf/context.c:1675`NGAP that has no data, the ogs_assert(pkbuf->len) assertion will be triggered. 2.Reachable assertion in ogs_nas_emm_decode ``` int ogs_nas_emm_decode(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf) { int size = 0; int decoded = 0; ogs_assert(pkbuf); ogs_assert(pkbuf->data); ogs_assert(pkbuf->len); ``` Nearly identical to (1), but for LTE. 3. Reachable assertion in nas_eps_send_emm_to_esm ``` int nas_eps_send_emm_to_esm(mme_ue_t *mme_ue, ogs_nas_esm_message_container_t *esm_message_container) { int rv; ogs_pkbuf_t *esmbuf = NULL; if (!mme_ue_cycle(mme_ue)) { ogs_error("UE(mme-ue) context has already been removed"); return OGS_NOTFOUND; } ogs_assert(esm_message_container); ogs_assert(esm_message_container->length); ``` The ESM message payload may be 0-length, as the length is determined by a field in the NAS payload (which can be chosen arbitrarily by an attacker). This leads to the length assertion above being triggered. 5. Reachable assertion and incorrect hash calculation in ogs_kdf_hash_mme ``` void ogs_kdf_hash_mme(const uint8_t *message, uint8_t message_len, uint8_t *hash_mme) { uint8_t key[32]; uint8_t output[OGS_SHA256_DIGEST_SIZE]; ogs_assert(message); ogs_assert(message_len); ogs_assert(hash_mme); memset(key, 0, 32); ogs_hmac_sha256(key, 32, message, message_len, output, OGS_SHA256_DIGEST_SIZE); memcpy(hash_mme, output+24, OGS_HASH_MME_LEN); } ``` When handling NAS attach requests or TAU requests, the ogs_kdf_hash_mme function is passed the NAS payload. However, the length field is represented as an unsigned 8-bit integer, which the passed length of the packet may overflow. This leads to the passed value being truncated. When the passed value is a multiple of 256, the above assertion (ogs_assert(message_len)) is triggered. Otherwise, the hash is computed on only the first n bits of the message (where n = actual_message_len % 256).
2024-02-03 01:37:36 +00:00
ogs_assert(esm_message_container);
if (!esm_message_container->length) {
ogs_error("Invalid ESM Message Container");
return OGS_ERROR;
}
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
2017-09-07 06:56:31 +00:00
/* The Packet Buffer(pkbuf_t) for NAS message MUST make a HEADROOM.
* When calculating AES_CMAC, we need to use the headroom of the packet. */
2019-09-13 12:07:47 +00:00
esmbuf = ogs_pkbuf_alloc(NULL,
OGS_NAS_HEADROOM+esm_message_container->length);
ogs_assert(esmbuf);
2019-09-13 12:07:47 +00:00
ogs_pkbuf_reserve(esmbuf, OGS_NAS_HEADROOM);
2019-04-27 14:54:30 +00:00
ogs_pkbuf_put_data(esmbuf,
2017-09-07 06:56:31 +00:00
esm_message_container->buffer, esm_message_container->length);
rv = s1ap_send_to_esm(mme_ue, esmbuf, 0, OGS_GTP_CREATE_IN_ATTACH_REQUEST);
ogs_expect(rv == OGS_OK);
2017-09-07 06:56:31 +00:00
2019-11-30 07:45:09 +00:00
return rv;
2017-09-07 06:56:31 +00:00
}
int nas_eps_send_to_downlink_nas_transport(
enb_ue_t *enb_ue, ogs_pkbuf_t *pkbuf)
2017-08-10 08:02:53 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *s1apbuf = NULL;
2017-08-10 08:02:53 +00:00
ogs_assert(pkbuf);
if (!enb_ue_cycle(enb_ue)) {
ogs_error("S1 context has already been removed");
ogs_pkbuf_free(pkbuf);
return OGS_NOTFOUND;
}
2017-08-10 08:02:53 +00:00
s1apbuf = s1ap_build_downlink_nas_transport(enb_ue, pkbuf);
if (!s1apbuf) {
ogs_error("s1ap_build_downlink_nas_transport() failed");
return OGS_ERROR;
}
rv = s1ap_send_to_enb_ue(enb_ue, s1apbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-08-10 08:02:53 +00:00
}
2017-09-07 06:56:31 +00:00
int nas_eps_send_attach_accept(mme_ue_t *mme_ue)
2017-09-07 06:56:31 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
2017-09-07 06:56:31 +00:00
mme_sess_t *sess = NULL;
mme_bearer_t *bearer = NULL;
2019-04-27 14:54:30 +00:00
ogs_pkbuf_t *s1apbuf = NULL;
ogs_pkbuf_t *esmbuf = NULL, *emmbuf = NULL;
2017-09-07 06:56:31 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-07 06:56:31 +00:00
sess = mme_sess_first(mme_ue);
2019-04-27 14:54:30 +00:00
ogs_assert(sess);
ogs_assert(mme_sess_next(sess) == NULL);
bearer = mme_default_bearer_in_sess(sess);
2019-04-27 14:54:30 +00:00
ogs_assert(bearer);
ogs_assert(mme_bearer_next(bearer) == NULL);
2017-09-07 06:56:31 +00:00
ogs_debug("[%s] Attach accept", mme_ue->imsi_bcd);
esmbuf = esm_build_activate_default_bearer_context_request(
sess, OGS_GTP_CREATE_IN_ATTACH_REQUEST);
if (!esmbuf) {
ogs_error("esm_build_activate_default_bearer_context_request() failed");
return OGS_ERROR;
}
2017-09-07 06:56:31 +00:00
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_attach_accept(mme_ue, esmbuf);
if (!emmbuf) {
ogs_error("emm_build_attach_accept() failed");
return OGS_ERROR;
}
2017-09-07 06:56:31 +00:00
CLEAR_MME_UE_TIMER(mme_ue->t3450);
mme_ue->t3450.pkbuf = ogs_pkbuf_copy(emmbuf);
if (!mme_ue->t3450.pkbuf) {
ogs_error("ogs_pkbuf_copy(mme_ue->t3450.pkbuf) failed");
ogs_pkbuf_free(emmbuf);
return OGS_ERROR;
}
ogs_timer_start(mme_ue->t3450.timer,
mme_timer_cfg(MME_TIMER_T3450)->duration);
/*
* Issue #2040
*
* TS24.301
* 5.5.1 Attach procedure
* 5.5.1.2 Attach procedure for EPS services
* 5.5.1.2.4 Attach accepted by the network
*
* If the attach request is accepted by the network,
* the MME shall delete the stored UE radio capability information
* or the UE radio capability ID, if any.
*/
OGS_ASN_CLEAR_DATA(&mme_ue->ueRadioCapability);
2019-11-30 07:45:09 +00:00
s1apbuf = s1ap_build_initial_context_setup_request(mme_ue, emmbuf);
if (!s1apbuf) {
ogs_error("s1ap_build_initial_context_setup_request() failed");
return OGS_ERROR;
}
2017-09-07 06:56:31 +00:00
2020-05-23 02:24:48 +00:00
rv = nas_eps_send_to_enb(mme_ue, s1apbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-09-07 06:56:31 +00:00
}
int nas_eps_send_attach_reject(enb_ue_t *enb_ue, mme_ue_t *mme_ue,
2019-09-13 12:07:47 +00:00
ogs_nas_emm_cause_t emm_cause, ogs_nas_esm_cause_t esm_cause)
2017-09-07 06:56:31 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
2017-09-07 06:56:31 +00:00
mme_sess_t *sess = NULL;
2019-04-27 14:54:30 +00:00
ogs_pkbuf_t *esmbuf = NULL, *emmbuf = NULL;
2017-09-07 06:56:31 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
2017-09-07 06:56:31 +00:00
if (!enb_ue_cycle(enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
ogs_debug("[%s] Attach reject", mme_ue->imsi_bcd);
ogs_debug(" Cause[%d]", emm_cause);
2018-01-22 14:14:20 +00:00
2017-09-07 06:56:31 +00:00
sess = mme_sess_first(mme_ue);
2019-07-11 12:53:54 +00:00
if (sess) {
esmbuf = esm_build_pdn_connectivity_reject(
sess, esm_cause, OGS_GTP_CREATE_IN_ATTACH_REQUEST);
if (!esmbuf) {
ogs_error("esm_build_pdn_connectivity_reject() failed");
return OGS_ERROR;
}
2017-09-07 06:56:31 +00:00
}
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_attach_reject(emm_cause, esmbuf);
if (!emmbuf) {
ogs_error("emm_build_attach_reject() failed");
return OGS_ERROR;
}
rv = nas_eps_send_to_downlink_nas_transport(enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-09-11 09:41:14 +00:00
}
int nas_eps_send_identity_request(mme_ue_t *mme_ue)
2018-01-22 07:35:12 +00:00
{
int rv;
2019-04-27 14:54:30 +00:00
ogs_pkbuf_t *emmbuf = NULL;
2018-01-22 07:35:12 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2018-01-22 07:35:12 +00:00
2020-10-01 17:27:58 +00:00
ogs_debug("Identity request");
2019-07-20 12:49:47 +00:00
if (mme_ue->t3470.pkbuf) {
emmbuf = mme_ue->t3470.pkbuf;
} else {
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_identity_request(mme_ue);
if (!emmbuf) {
ogs_error("emm_build_identity_request() failed");
return OGS_ERROR;
}
2019-07-20 12:49:47 +00:00
}
mme_ue->t3470.pkbuf = ogs_pkbuf_copy(emmbuf);
if (!mme_ue->t3470.pkbuf) {
ogs_error("ogs_pkbuf_copy(mme_ue->t3470.pkbuf) failed");
ogs_pkbuf_free(emmbuf);
return OGS_ERROR;
}
2019-07-20 12:49:47 +00:00
ogs_timer_start(mme_ue->t3470.timer,
mme_timer_cfg(MME_TIMER_T3470)->duration);
2018-01-22 07:35:12 +00:00
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
2022-03-22 13:47:45 +00:00
return rv;
2018-01-22 07:35:12 +00:00
}
int nas_eps_send_authentication_request(mme_ue_t *mme_ue)
2017-09-11 09:41:14 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *emmbuf = NULL;
2017-09-11 09:41:14 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-11 09:41:14 +00:00
ogs_debug("[%s] Authentication request", mme_ue->imsi_bcd);
2018-01-22 14:14:20 +00:00
2019-07-20 12:28:36 +00:00
if (mme_ue->t3460.pkbuf) {
emmbuf = mme_ue->t3460.pkbuf;
} else {
emmbuf = emm_build_authentication_request(mme_ue);
if (!emmbuf) {
ogs_error("emm_build_authentication_request() failed");
return OGS_ERROR;
}
2019-07-20 12:28:36 +00:00
}
mme_ue->t3460.pkbuf = ogs_pkbuf_copy(emmbuf);
if (!mme_ue->t3460.pkbuf) {
ogs_error("ogs_pkbuf_copy(mme_ue->t3460.pkbuf) failed");
ogs_pkbuf_free(emmbuf);
return OGS_ERROR;
}
2019-07-20 12:28:36 +00:00
ogs_timer_start(mme_ue->t3460.timer,
mme_timer_cfg(MME_TIMER_T3460)->duration);
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
2022-03-22 13:47:45 +00:00
return rv;
2019-07-20 12:28:36 +00:00
}
int nas_eps_send_security_mode_command(mme_ue_t *mme_ue)
2019-07-20 12:28:36 +00:00
{
int rv;
ogs_pkbuf_t *emmbuf = NULL;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2019-07-20 12:28:36 +00:00
ogs_debug("[%s] Security mode command", mme_ue->imsi_bcd);
2019-07-20 12:28:36 +00:00
if (mme_ue->t3460.pkbuf) {
emmbuf = mme_ue->t3460.pkbuf;
} else {
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_security_mode_command(mme_ue);
if (!emmbuf) {
ogs_error("emm_build_security_mode_command() failed");
return OGS_ERROR;
}
2019-07-20 12:28:36 +00:00
}
mme_ue->t3460.pkbuf = ogs_pkbuf_copy(emmbuf);
if (!mme_ue->t3460.pkbuf) {
ogs_error("ogs_pkbuf_copy(mme_ue->t3460.pkbuf) failed");
ogs_pkbuf_free(emmbuf);
return OGS_ERROR;
}
2019-07-20 12:28:36 +00:00
ogs_timer_start(mme_ue->t3460.timer,
mme_timer_cfg(MME_TIMER_T3460)->duration);
2017-09-11 09:41:14 +00:00
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
2022-03-22 13:47:45 +00:00
return rv;
2017-09-11 09:41:14 +00:00
}
int nas_eps_send_authentication_reject(mme_ue_t *mme_ue)
2017-09-11 09:41:14 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *emmbuf = NULL;
2017-09-11 09:41:14 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-11 09:41:14 +00:00
ogs_debug("[%s] Authentication reject", mme_ue->imsi_bcd);
2018-01-22 14:14:20 +00:00
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_authentication_reject();
if (!emmbuf) {
ogs_error("emm_build_authentication_reject() failed");
return OGS_ERROR;
}
2017-09-11 09:41:14 +00:00
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
return rv;
}
int nas_eps_send_detach_request(mme_ue_t *mme_ue)
{
int rv;
ogs_pkbuf_t *emmbuf = NULL;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
ogs_debug("[%s] Detach request to UE", mme_ue->imsi_bcd);
if (mme_ue->t3422.pkbuf) {
emmbuf = mme_ue->t3422.pkbuf;
} else {
emmbuf = emm_build_detach_request(mme_ue);
if (!emmbuf) {
ogs_error("emm_build_detach_request() failed");
return OGS_ERROR;
}
}
mme_ue->t3422.pkbuf = ogs_pkbuf_copy(emmbuf);
if (!mme_ue->t3422.pkbuf) {
ogs_error("ogs_pkbuf_copy(mme_ue->t3422.pkbuf) failed");
ogs_pkbuf_free(emmbuf);
return OGS_ERROR;
}
ogs_timer_start(mme_ue->t3422.timer,
mme_timer_cfg(MME_TIMER_T3422)->duration);
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-09-07 06:56:31 +00:00
}
int nas_eps_send_detach_accept(mme_ue_t *mme_ue)
{
int rv;
2019-04-27 14:54:30 +00:00
ogs_pkbuf_t *emmbuf = NULL;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
ogs_debug("[%s] Detach accept", mme_ue->imsi_bcd);
/* reply with detach accept */
2019-07-11 12:53:54 +00:00
if (mme_ue->nas_eps.detach.switch_off == 0) {
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_detach_accept(mme_ue);
if (!emmbuf) {
ogs_error("emm_build_detach_accept() failed");
return OGS_ERROR;
}
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
if (rv != OGS_OK) {
ogs_error("nas_eps_send_to_downlink_nas_transport() failed");
return rv;
}
}
rv = s1ap_send_ue_context_release_command(mme_ue->enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_detach,
S1AP_UE_CTX_REL_S1_REMOVE_AND_UNLINK, 0);
ogs_expect(rv == OGS_OK);
return rv;
}
int nas_eps_send_pdn_connectivity_reject(
mme_sess_t *sess, ogs_nas_esm_cause_t esm_cause, int create_action)
2017-09-08 09:50:27 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
2017-09-08 09:50:27 +00:00
mme_ue_t *mme_ue;
2019-04-27 14:54:30 +00:00
ogs_pkbuf_t *esmbuf = NULL;
2017-09-08 09:50:27 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(sess);
2017-09-08 09:50:27 +00:00
mme_ue = sess->mme_ue;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-08 09:50:27 +00:00
if (create_action == OGS_GTP_CREATE_IN_ATTACH_REQUEST) {
/* During the UE-attach process, we'll send Attach-Reject
* with pyggybacking PDN-connectivity-Reject */
rv = nas_eps_send_attach_reject(mme_ue->enb_ue, mme_ue,
OGS_NAS_EMM_CAUSE_ESM_FAILURE, esm_cause);
if (rv != OGS_OK) {
ogs_error("nas_eps_send_attach_reject() failed");
return rv;
}
rv = s1ap_send_ue_context_release_command(mme_ue->enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);
ogs_expect(rv == OGS_OK);
} else {
esmbuf = esm_build_pdn_connectivity_reject(
sess, esm_cause, create_action);
if (!esmbuf) {
ogs_error("esm_build_pdn_connectivity_reject() failed");
return OGS_ERROR;
}
2017-09-08 09:50:27 +00:00
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, esmbuf);
ogs_expect(rv == OGS_OK);
2019-05-26 03:57:29 +00:00
}
return rv;
2017-09-08 09:50:27 +00:00
}
int nas_eps_send_esm_information_request(mme_bearer_t *bearer)
{
2019-04-27 14:54:30 +00:00
int rv;
mme_ue_t *mme_ue = NULL;
2019-04-27 14:54:30 +00:00
ogs_pkbuf_t *esmbuf = NULL;
2019-04-27 14:54:30 +00:00
ogs_assert(bearer);
mme_ue = bearer->mme_ue;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2019-07-20 14:06:54 +00:00
if (bearer->t3489.pkbuf) {
esmbuf = bearer->t3489.pkbuf;
} else {
2019-11-30 07:45:09 +00:00
esmbuf = esm_build_information_request(bearer);
if (!esmbuf) {
ogs_error("esm_build_information_request() failed");
return OGS_ERROR;
}
2019-07-20 14:06:54 +00:00
}
bearer->t3489.pkbuf = ogs_pkbuf_copy(esmbuf);
if (!bearer->t3489.pkbuf) {
ogs_error("ogs_pkbuf_copy(bearer->t3489) failed");
ogs_pkbuf_free(esmbuf);
return OGS_ERROR;
}
2019-07-20 14:06:54 +00:00
ogs_timer_start(bearer->t3489.timer,
mme_timer_cfg(MME_TIMER_T3489)->duration);
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, esmbuf);
ogs_expect(rv == OGS_OK);
2022-03-22 13:47:45 +00:00
return rv;
}
int nas_eps_send_activate_default_bearer_context_request(
mme_bearer_t *bearer, int create_action)
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *s1apbuf = NULL;
ogs_pkbuf_t *esmbuf = NULL;
mme_sess_t *sess = NULL;
mme_ue_t *mme_ue = NULL;
2019-04-27 14:54:30 +00:00
ogs_assert(bearer);
sess = bearer->sess;
2019-04-27 14:54:30 +00:00
ogs_assert(sess);
mme_ue = bearer->mme_ue;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
esmbuf = esm_build_activate_default_bearer_context_request(
sess, create_action);
if (!esmbuf) {
ogs_error("esm_build_activate_default_bearer_context_request() failed");
return OGS_ERROR;
}
2019-11-30 07:45:09 +00:00
s1apbuf = s1ap_build_e_rab_setup_request(bearer, esmbuf);
if (!s1apbuf) {
ogs_error("s1ap_build_e_rab_setup_request() failed");
return OGS_ERROR;
}
2020-05-23 02:24:48 +00:00
rv = nas_eps_send_to_enb(mme_ue, s1apbuf);
ogs_expect(rv == OGS_OK);
return rv;
}
int nas_eps_send_activate_dedicated_bearer_context_request(
mme_bearer_t *bearer)
2017-09-07 06:56:31 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *s1apbuf = NULL;
ogs_pkbuf_t *esmbuf = NULL;
mme_ue_t *mme_ue = NULL;
2017-09-07 06:56:31 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(bearer);
mme_ue = bearer->mme_ue;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-07 06:56:31 +00:00
2019-11-30 07:45:09 +00:00
esmbuf = esm_build_activate_dedicated_bearer_context_request(bearer);
if (!esmbuf) {
ogs_error(
"esm_build_activate_dedicated_bearer_context_request() failed");
return OGS_ERROR;
}
2017-09-07 06:56:31 +00:00
2019-11-30 07:45:09 +00:00
s1apbuf = s1ap_build_e_rab_setup_request(bearer, esmbuf);
if (!s1apbuf) {
ogs_error("s1ap_build_e_rab_setup_request() failed");
return OGS_ERROR;
}
2017-09-07 06:56:31 +00:00
2020-05-23 02:24:48 +00:00
rv = nas_eps_send_to_enb(mme_ue, s1apbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-09-07 06:56:31 +00:00
}
2017-09-07 14:41:05 +00:00
2020-05-23 02:24:48 +00:00
void nas_eps_send_activate_all_dedicated_bearers(mme_bearer_t *default_bearer)
2018-02-01 12:38:59 +00:00
{
int r;
2019-04-27 14:54:30 +00:00
ogs_assert(default_bearer);
2018-02-01 12:38:59 +00:00
mme_bearer_t *dedicated_bearer = mme_bearer_next(default_bearer);
2019-07-11 12:53:54 +00:00
while (dedicated_bearer) {
r = nas_eps_send_activate_dedicated_bearer_context_request(
2018-02-01 12:38:59 +00:00
dedicated_bearer);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
2018-02-01 12:38:59 +00:00
dedicated_bearer = mme_bearer_next(dedicated_bearer);
}
}
int nas_eps_send_modify_bearer_context_request(
mme_bearer_t *bearer, int qos_presence, int tft_presence)
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *s1apbuf = NULL;
ogs_pkbuf_t *esmbuf = NULL;
mme_ue_t *mme_ue = NULL;
2019-04-27 14:54:30 +00:00
ogs_assert(bearer);
mme_ue = bearer->mme_ue;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2019-11-30 07:45:09 +00:00
esmbuf = esm_build_modify_bearer_context_request(
bearer, qos_presence, tft_presence);
if (!esmbuf) {
ogs_error("esm_build_modify_bearer_context_request() failed");
return OGS_ERROR;
}
2019-07-11 12:53:54 +00:00
if (qos_presence == 1) {
2019-11-30 07:45:09 +00:00
s1apbuf = s1ap_build_e_rab_modify_request(bearer, esmbuf);
if (!s1apbuf) {
ogs_error("s1ap_build_e_rab_modify_request() failed");
return OGS_ERROR;
}
2020-05-23 02:24:48 +00:00
rv = nas_eps_send_to_enb(mme_ue, s1apbuf);
ogs_expect(rv == OGS_OK);
2019-07-11 12:53:54 +00:00
} else {
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, esmbuf);
ogs_expect(rv == OGS_OK);
}
return rv;
}
int nas_eps_send_deactivate_bearer_context_request(mme_bearer_t *bearer)
2017-09-07 14:41:05 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *s1apbuf = NULL;
ogs_pkbuf_t *esmbuf = NULL;
mme_ue_t *mme_ue = NULL;
2017-09-07 14:41:05 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(bearer);
mme_ue = bearer->mme_ue;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-07 14:41:05 +00:00
2019-11-30 07:45:09 +00:00
esmbuf = esm_build_deactivate_bearer_context_request(
bearer, OGS_NAS_ESM_CAUSE_REGULAR_DEACTIVATION);
if (!esmbuf) {
ogs_error("esm_build_deactivate_bearer_context_request() failed");
return OGS_ERROR;
}
2017-09-07 14:41:05 +00:00
2019-11-30 07:45:09 +00:00
s1apbuf = s1ap_build_e_rab_release_command(bearer, esmbuf,
2018-03-05 14:01:07 +00:00
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release);
if (!s1apbuf) {
ogs_error("s1ap_build_e_rab_release_command() failed");
return OGS_ERROR;
}
2017-09-07 14:41:05 +00:00
2020-05-23 02:24:48 +00:00
rv = nas_eps_send_to_enb(mme_ue, s1apbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-09-07 14:41:05 +00:00
}
2017-09-08 07:46:37 +00:00
int nas_eps_send_bearer_resource_allocation_reject(
mme_ue_t *mme_ue, uint8_t pti, ogs_nas_esm_cause_t esm_cause)
{
int rv;
ogs_pkbuf_t *esmbuf = NULL;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
ogs_assert(pti != OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED);
esmbuf = esm_build_bearer_resource_allocation_reject(
mme_ue, pti, esm_cause);
if (!esmbuf) {
ogs_error("esm_build_bearer_resource_allocation_reject() failed");
return OGS_ERROR;
}
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, esmbuf);
ogs_expect(rv == OGS_OK);
return rv;
}
int nas_eps_send_bearer_resource_modification_reject(
mme_ue_t *mme_ue, uint8_t pti, ogs_nas_esm_cause_t esm_cause)
{
int rv;
ogs_pkbuf_t *esmbuf = NULL;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
ogs_assert(pti != OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED);
esmbuf = esm_build_bearer_resource_modification_reject(
mme_ue, pti, esm_cause);
if (!esmbuf) {
ogs_error("esm_build_bearer_resource_modification_reject() failed");
return OGS_ERROR;
}
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, esmbuf);
ogs_expect(rv == OGS_OK);
return rv;
}
int nas_eps_send_tau_accept(
2018-03-05 14:01:07 +00:00
mme_ue_t *mme_ue, S1AP_ProcedureCode_t procedureCode)
2017-09-08 07:46:37 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *emmbuf = NULL;
2017-09-08 07:46:37 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-08 07:46:37 +00:00
ogs_debug("[%s] Tracking area update accept", mme_ue->imsi_bcd);
2018-02-03 02:48:15 +00:00
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_tau_accept(mme_ue);
if (!emmbuf) {
ogs_error("emm_build_tau_accept() failed");
return OGS_ERROR;
}
2022-03-22 13:47:45 +00:00
if (mme_ue->next.m_tmsi) {
CLEAR_MME_UE_TIMER(mme_ue->t3450);
mme_ue->t3450.pkbuf = ogs_pkbuf_copy(emmbuf);
if (!mme_ue->t3450.pkbuf) {
ogs_error("ogs_pkbuf_copy(mme_ue->t3450.pkbuf) failed");
ogs_pkbuf_free(emmbuf);
return OGS_ERROR;
}
2022-03-22 13:47:45 +00:00
ogs_timer_start(mme_ue->t3450.timer,
mme_timer_cfg(MME_TIMER_T3450)->duration);
}
2019-07-11 12:53:54 +00:00
if (procedureCode == S1AP_ProcedureCode_id_InitialContextSetup) {
2019-04-27 14:54:30 +00:00
ogs_pkbuf_t *s1apbuf = NULL;
2019-11-30 07:45:09 +00:00
s1apbuf = s1ap_build_initial_context_setup_request(mme_ue, emmbuf);
if (!s1apbuf) {
ogs_error("s1ap_build_initial_context_setup_request() failed");
return OGS_ERROR;
}
2020-05-23 02:24:48 +00:00
rv = nas_eps_send_to_enb(mme_ue, s1apbuf);
ogs_expect(rv == OGS_OK);
2019-07-11 12:53:54 +00:00
} else if (procedureCode == S1AP_ProcedureCode_id_downlinkNASTransport) {
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
2019-07-11 12:53:54 +00:00
} else
2019-04-27 14:54:30 +00:00
ogs_assert_if_reached();
return rv;
2017-09-08 07:46:37 +00:00
}
int nas_eps_send_tau_reject(
enb_ue_t *enb_ue, mme_ue_t *mme_ue, ogs_nas_emm_cause_t emm_cause)
2017-09-08 07:46:37 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *emmbuf = NULL;
2017-09-08 07:46:37 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-08 07:46:37 +00:00
ogs_debug("[%s] Tracking area update reject", mme_ue->imsi_bcd);
2017-09-08 07:46:37 +00:00
/* Build TAU reject */
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_tau_reject(emm_cause, mme_ue);
if (!emmbuf) {
ogs_error("emm_build_tau_reject() failed");
return OGS_ERROR;
}
2017-09-08 22:56:42 +00:00
rv = nas_eps_send_to_downlink_nas_transport(enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-09-08 22:56:42 +00:00
}
int nas_eps_send_service_reject(
enb_ue_t *enb_ue, mme_ue_t *mme_ue, ogs_nas_emm_cause_t emm_cause)
2017-09-08 22:56:42 +00:00
{
2019-04-27 14:54:30 +00:00
int rv;
ogs_pkbuf_t *emmbuf = NULL;
2017-09-08 22:56:42 +00:00
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2017-09-08 22:56:42 +00:00
ogs_debug("[%s] Service reject", mme_ue->imsi_bcd);
2017-09-11 05:18:18 +00:00
/* Build Service Reject */
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_service_reject(emm_cause, mme_ue);
if (!emmbuf) {
ogs_error("emm_build_service_reject() failed");
return OGS_ERROR;
}
2017-09-08 07:46:37 +00:00
rv = nas_eps_send_to_downlink_nas_transport(enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
return rv;
2017-09-08 07:46:37 +00:00
}
2019-07-11 09:14:32 +00:00
int nas_eps_send_cs_service_notification(mme_ue_t *mme_ue)
2019-07-11 09:14:32 +00:00
{
int rv;
ogs_pkbuf_t *emmbuf = NULL;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2019-07-11 09:14:32 +00:00
ogs_debug("[%s] CS Service Notification", mme_ue->imsi_bcd);
2019-07-11 09:14:32 +00:00
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_cs_service_notification(mme_ue);
if (!emmbuf) {
ogs_error("emm_build_cs_service_notification() failed");
return OGS_ERROR;
}
2019-07-11 09:14:32 +00:00
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
return rv;
2019-07-11 09:14:32 +00:00
}
2019-07-13 13:52:50 +00:00
int nas_eps_send_downlink_nas_transport(
2019-07-13 13:52:50 +00:00
mme_ue_t *mme_ue, uint8_t *buffer, uint8_t length)
{
int rv;
ogs_pkbuf_t *emmbuf = NULL;
if (!mme_ue_cycle(mme_ue)) {
ogs_error("UE(mme-ue) context has already been removed");
return OGS_NOTFOUND;
}
if (!enb_ue_cycle(mme_ue->enb_ue)) {
ogs_error("S1 context has already been removed");
return OGS_NOTFOUND;
}
2019-07-13 13:52:50 +00:00
ogs_assert(buffer);
ogs_assert(length);
ogs_debug("[%s] Downlink NAS transport", mme_ue->imsi_bcd);
2019-07-13 13:52:50 +00:00
2019-11-30 07:45:09 +00:00
emmbuf = emm_build_downlink_nas_transport(mme_ue, buffer, length);
if (!emmbuf) {
ogs_error("emm_build_downlink_nas_transport() failed");
return OGS_ERROR;
}
2019-07-13 13:52:50 +00:00
rv = nas_eps_send_to_downlink_nas_transport(mme_ue->enb_ue, emmbuf);
ogs_expect(rv == OGS_OK);
return rv;
2019-07-13 13:52:50 +00:00
}