2017-02-13 05:17:26 +00:00
|
|
|
#define TRACE_MODULE _s1ap_path
|
2017-02-13 04:19:53 +00:00
|
|
|
|
|
|
|
#include "core_debug.h"
|
2017-10-18 16:09:06 +00:00
|
|
|
#include "core_thread.h"
|
2017-02-13 07:03:12 +00:00
|
|
|
|
2017-04-04 01:49:19 +00:00
|
|
|
#include "mme_event.h"
|
2017-03-26 06:34:34 +00:00
|
|
|
|
2017-09-07 06:56:31 +00:00
|
|
|
#include "nas_security.h"
|
2017-09-10 14:03:24 +00:00
|
|
|
#include "nas_path.h"
|
|
|
|
|
2017-09-12 14:07:55 +00:00
|
|
|
#include "s1ap_conv.h"
|
2017-09-10 14:03:24 +00:00
|
|
|
#include "s1ap_build.h"
|
2017-09-08 07:46:37 +00:00
|
|
|
#include "s1ap_path.h"
|
2017-02-13 04:19:53 +00:00
|
|
|
|
2017-12-08 05:29:35 +00:00
|
|
|
static status_t s1ap_server_list(list_t *list, int type);
|
|
|
|
static status_t s1ap_delete_list(list_t *list);
|
|
|
|
|
2017-11-24 16:08:26 +00:00
|
|
|
status_t s1ap_open(void)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
#if USE_USRSCTP != 1
|
|
|
|
int type = SOCK_STREAM;
|
|
|
|
#else
|
|
|
|
int type = SOCK_SEQPACKET;
|
|
|
|
#endif
|
2017-12-08 05:29:35 +00:00
|
|
|
|
|
|
|
rv = s1ap_server_list(&mme_self()->s1ap_list, type);
|
|
|
|
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
|
|
|
rv = s1ap_server_list(&mme_self()->s1ap_list6, type);
|
|
|
|
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t s1ap_close()
|
|
|
|
{
|
|
|
|
s1ap_delete_list(&mme_self()->s1ap_list);
|
|
|
|
s1ap_delete_list(&mme_self()->s1ap_list6);
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static status_t s1ap_server_list(list_t *list, int type)
|
|
|
|
{
|
|
|
|
status_t rv;
|
2017-12-08 03:43:35 +00:00
|
|
|
sock_node_t *snode = NULL;
|
2017-11-24 16:08:26 +00:00
|
|
|
|
2017-12-08 05:29:35 +00:00
|
|
|
d_assert(list, return CORE_ERROR,);
|
2017-12-08 03:43:35 +00:00
|
|
|
|
2017-12-08 05:29:35 +00:00
|
|
|
for (snode = list_first(list); snode; snode = list_next(snode))
|
2017-12-08 03:43:35 +00:00
|
|
|
{
|
2017-12-08 05:29:35 +00:00
|
|
|
rv = s1ap_server(snode, type);
|
2017-12-08 03:43:35 +00:00
|
|
|
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
2017-11-24 16:08:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-12-08 05:29:35 +00:00
|
|
|
static status_t s1ap_delete_list(list_t *list)
|
2017-11-24 16:08:26 +00:00
|
|
|
{
|
2017-12-08 03:43:35 +00:00
|
|
|
sock_node_t *snode = NULL;
|
2017-11-24 16:08:26 +00:00
|
|
|
|
2017-12-08 05:29:35 +00:00
|
|
|
for (snode = list_first(list); snode; snode = list_next(snode))
|
2017-11-24 16:08:26 +00:00
|
|
|
{
|
2017-12-08 03:43:35 +00:00
|
|
|
s1ap_delete(snode->sock);
|
2017-11-24 16:08:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-04-06 11:10:00 +00:00
|
|
|
status_t s1ap_send_to_enb(mme_enb_t *enb, pkbuf_t *pkbuf)
|
2017-02-13 04:19:53 +00:00
|
|
|
{
|
2018-01-22 14:14:20 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
|
|
|
status_t rv;
|
|
|
|
|
|
|
|
d_assert(enb, return CORE_ERROR,);
|
|
|
|
d_assert(pkbuf, return CORE_ERROR,);
|
|
|
|
d_assert(enb->sock, return CORE_ERROR,);
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2017-02-13 04:19:53 +00:00
|
|
|
|
2017-11-24 10:03:48 +00:00
|
|
|
rv = s1ap_send(enb->sock, pkbuf,
|
|
|
|
enb->sock_type == SOCK_STREAM ? NULL : enb->addr);
|
2017-03-26 16:50:01 +00:00
|
|
|
if (rv != CORE_OK)
|
|
|
|
{
|
|
|
|
d_error("s1_send error");
|
|
|
|
pkbuf_free(pkbuf);
|
|
|
|
}
|
2017-03-07 05:47:17 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
return CORE_OK;;
|
2017-02-13 04:19:53 +00:00
|
|
|
}
|
2017-09-07 06:56:31 +00:00
|
|
|
|
2017-09-18 10:30:03 +00:00
|
|
|
status_t s1ap_delayed_send_to_enb(
|
|
|
|
mme_enb_t *enb, pkbuf_t *pkbuf, c_uint32_t duration)
|
|
|
|
{
|
|
|
|
tm_block_id timer = 0;
|
|
|
|
|
|
|
|
d_assert(enb, return CORE_ERROR,);
|
|
|
|
d_assert(pkbuf, return CORE_ERROR,);
|
|
|
|
|
|
|
|
if (duration)
|
|
|
|
{
|
|
|
|
timer = timer_create(
|
|
|
|
&mme_self()->tm_service, MME_EVT_S1AP_DELAYED_SEND, duration);
|
|
|
|
d_assert(timer, return CORE_ERROR,);
|
|
|
|
|
|
|
|
timer_set_param1(timer, (c_uintptr_t)enb->index);
|
|
|
|
timer_set_param2(timer, (c_uintptr_t)pkbuf);
|
|
|
|
timer_set_param3(timer, timer);
|
|
|
|
|
|
|
|
tm_start(timer);
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return s1ap_send_to_enb(enb, pkbuf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-07 06:56:31 +00:00
|
|
|
status_t s1ap_send_to_esm(mme_ue_t *mme_ue, pkbuf_t *esmbuf)
|
|
|
|
{
|
|
|
|
event_t e;
|
|
|
|
|
|
|
|
d_assert(mme_ue, return CORE_ERROR, "Null param");
|
|
|
|
d_assert(esmbuf, return CORE_ERROR, "Null param");
|
|
|
|
|
|
|
|
event_set(&e, MME_EVT_ESM_MESSAGE);
|
2017-09-21 07:03:42 +00:00
|
|
|
event_set_param1(&e, (c_uintptr_t)mme_ue->index);
|
2017-09-07 06:56:31 +00:00
|
|
|
event_set_param2(&e, (c_uintptr_t)esmbuf);
|
|
|
|
mme_event_send(&e);
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2018-02-03 13:55:05 +00:00
|
|
|
status_t s1ap_send_to_nas(enb_ue_t *enb_ue,
|
2018-03-05 14:01:07 +00:00
|
|
|
S1AP_ProcedureCode_t procedureCode, S1AP_NAS_PDU_t *nasPdu)
|
2017-09-07 06:56:31 +00:00
|
|
|
{
|
|
|
|
nas_security_header_t *sh = NULL;
|
|
|
|
nas_security_header_type_t security_header_type;
|
|
|
|
|
|
|
|
nas_emm_header_t *h = NULL;
|
|
|
|
pkbuf_t *nasbuf = NULL;
|
|
|
|
event_t e;
|
|
|
|
|
|
|
|
d_assert(enb_ue, return CORE_ERROR, "Null param");
|
|
|
|
d_assert(nasPdu, return CORE_ERROR, "Null param");
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
nasbuf = pkbuf_alloc(NAS_HEADROOM, nasPdu->size);
|
|
|
|
d_assert(nasbuf, return CORE_ERROR, "Null param");
|
|
|
|
memcpy(nasbuf->payload, nasPdu->buf, nasPdu->size);
|
|
|
|
|
|
|
|
sh = nasbuf->payload;
|
|
|
|
d_assert(sh, return CORE_ERROR, "Null param");
|
|
|
|
|
|
|
|
memset(&security_header_type, 0, sizeof(nas_security_header_type_t));
|
|
|
|
switch(sh->security_header_type)
|
|
|
|
{
|
|
|
|
case NAS_SECURITY_HEADER_PLAIN_NAS_MESSAGE:
|
|
|
|
break;
|
|
|
|
case NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE:
|
|
|
|
security_header_type.service_request = 1;
|
|
|
|
break;
|
|
|
|
case NAS_SECURITY_HEADER_INTEGRITY_PROTECTED:
|
|
|
|
security_header_type.integrity_protected = 1;
|
|
|
|
d_assert(pkbuf_header(nasbuf, -6) == CORE_OK,
|
|
|
|
return CORE_ERROR, "pkbuf_header error");
|
|
|
|
break;
|
|
|
|
case NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED:
|
|
|
|
security_header_type.integrity_protected = 1;
|
|
|
|
security_header_type.ciphered = 1;
|
|
|
|
d_assert(pkbuf_header(nasbuf, -6) == CORE_OK,
|
|
|
|
return CORE_ERROR, "pkbuf_header error");
|
|
|
|
break;
|
|
|
|
case NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_NEW_SECURITY_CONTEXT:
|
|
|
|
security_header_type.integrity_protected = 1;
|
|
|
|
security_header_type.new_security_context = 1;
|
|
|
|
d_assert(pkbuf_header(nasbuf, -6) == CORE_OK,
|
|
|
|
return CORE_ERROR, "pkbuf_header error");
|
|
|
|
break;
|
|
|
|
case NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHTERD_WITH_NEW_INTEGRITY_CONTEXT:
|
|
|
|
security_header_type.integrity_protected = 1;
|
|
|
|
security_header_type.ciphered = 1;
|
|
|
|
security_header_type.new_security_context = 1;
|
|
|
|
d_assert(pkbuf_header(nasbuf, -6) == CORE_OK,
|
|
|
|
return CORE_ERROR, "pkbuf_header error");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
d_error("Not implemented(securiry header type:0x%x)",
|
|
|
|
sh->security_header_type);
|
|
|
|
return CORE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enb_ue->mme_ue)
|
|
|
|
{
|
|
|
|
d_assert(nas_security_decode(
|
|
|
|
enb_ue->mme_ue, security_header_type, nasbuf) == CORE_OK,
|
|
|
|
pkbuf_free(nasbuf);return CORE_ERROR, "nas_security_decode failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
h = nasbuf->payload;
|
|
|
|
d_assert(h, pkbuf_free(nasbuf); return CORE_ERROR, "Null param");
|
|
|
|
if (h->protocol_discriminator == NAS_PROTOCOL_DISCRIMINATOR_EMM)
|
|
|
|
{
|
|
|
|
event_set(&e, MME_EVT_EMM_MESSAGE);
|
|
|
|
event_set_param1(&e, (c_uintptr_t)enb_ue->index);
|
2018-02-03 13:55:05 +00:00
|
|
|
event_set_param2(&e, (c_uintptr_t)procedureCode);
|
|
|
|
event_set_param3(&e, (c_uintptr_t)security_header_type.type);
|
|
|
|
event_set_param4(&e, (c_uintptr_t)nasbuf);
|
2017-09-07 06:56:31 +00:00
|
|
|
mme_event_send(&e);
|
|
|
|
}
|
|
|
|
else if (h->protocol_discriminator == NAS_PROTOCOL_DISCRIMINATOR_ESM)
|
|
|
|
{
|
|
|
|
mme_ue_t *mme_ue = enb_ue->mme_ue;
|
|
|
|
d_assert(mme_ue, return CORE_ERROR, "Null param");
|
|
|
|
s1ap_send_to_esm(mme_ue, nasbuf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
d_assert(0, pkbuf_free(nasbuf); return CORE_ERROR,
|
|
|
|
"Unknown protocol:%d", h->protocol_discriminator);
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-09-10 14:03:24 +00:00
|
|
|
status_t s1ap_send_initial_context_setup_request(mme_ue_t *mme_ue)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
d_assert(mme_ue, return CORE_ERROR, "Null param");
|
|
|
|
|
2017-09-11 05:01:11 +00:00
|
|
|
rv = s1ap_build_initial_context_setup_request(&s1apbuf, mme_ue, NULL);
|
2017-09-10 14:03:24 +00:00
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = nas_send_to_enb(mme_ue, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK, return CORE_ERROR, "s1ap send error");
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
2017-09-07 06:56:31 +00:00
|
|
|
|
2018-01-21 11:31:28 +00:00
|
|
|
status_t s1ap_send_ue_context_release_command(
|
2018-03-05 14:01:07 +00:00
|
|
|
enb_ue_t *enb_ue, S1AP_Cause_PR group, long cause,
|
2018-01-21 11:31:28 +00:00
|
|
|
c_uint8_t action, c_uint32_t delay)
|
2017-09-08 07:46:37 +00:00
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
mme_enb_t *enb = NULL;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
2018-01-11 13:12:48 +00:00
|
|
|
d_assert(action != S1AP_UE_CTX_REL_INVALID_ACTION, return CORE_ERROR,
|
|
|
|
"Should give valid action for UE Context Release Command");
|
|
|
|
|
2017-09-08 07:46:37 +00:00
|
|
|
d_assert(enb_ue, return CORE_ERROR, "Null param");
|
2018-01-11 13:12:48 +00:00
|
|
|
enb_ue->ue_ctx_rel_action = action;
|
2017-09-08 07:46:37 +00:00
|
|
|
enb = enb_ue->enb;
|
|
|
|
d_assert(enb, return CORE_ERROR, "Null param");
|
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] UE Context release command\n");
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Group[%d] Cause[%d] Action[%d] Delay[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
group, cause, action, delay);
|
|
|
|
|
2018-01-21 11:31:28 +00:00
|
|
|
rv = s1ap_build_ue_context_release_command(&s1apbuf, enb_ue, group, cause);
|
2017-09-08 07:46:37 +00:00
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
2017-09-18 10:30:03 +00:00
|
|
|
rv = s1ap_delayed_send_to_enb(enb, s1apbuf, delay);
|
2017-09-11 12:14:55 +00:00
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
2018-01-22 14:14:20 +00:00
|
|
|
|
2017-09-08 07:46:37 +00:00
|
|
|
return CORE_OK;
|
|
|
|
}
|
2017-09-11 12:14:55 +00:00
|
|
|
|
|
|
|
status_t s1ap_send_path_switch_ack(mme_ue_t *mme_ue)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
d_assert(mme_ue, return CORE_ERROR, "Null param");
|
|
|
|
|
|
|
|
rv = s1ap_build_path_switch_ack(&s1apbuf, mme_ue);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = nas_send_to_enb(mme_ue, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK, return CORE_ERROR, "s1ap send error");
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t s1ap_send_path_switch_failure(mme_enb_t *enb,
|
2018-01-21 11:31:28 +00:00
|
|
|
c_uint32_t enb_ue_s1ap_id, c_uint32_t mme_ue_s1ap_id,
|
2018-03-05 14:01:07 +00:00
|
|
|
S1AP_Cause_PR group, long cause)
|
2017-09-11 12:14:55 +00:00
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
d_assert(enb, return CORE_ERROR, "Null param");
|
|
|
|
|
|
|
|
rv = s1ap_build_path_switch_failure(&s1apbuf,
|
2018-01-21 11:31:28 +00:00
|
|
|
enb_ue_s1ap_id, mme_ue_s1ap_id, group, cause);
|
2017-09-11 12:14:55 +00:00
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = s1ap_send_to_enb(enb, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2017-09-15 04:28:07 +00:00
|
|
|
|
|
|
|
status_t s1ap_send_handover_command(enb_ue_t *source_ue)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
mme_enb_t *enb = NULL;
|
|
|
|
|
|
|
|
d_assert(source_ue, return CORE_ERROR,);
|
|
|
|
enb = source_ue->enb;
|
|
|
|
d_assert(enb, return CORE_ERROR,);
|
|
|
|
|
|
|
|
rv = s1ap_build_handover_command(&s1apbuf, source_ue);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = s1ap_send_to_enb(enb, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t s1ap_send_handover_preparation_failure(
|
2018-03-05 14:01:07 +00:00
|
|
|
enb_ue_t *source_ue, S1AP_Cause_t *cause)
|
2017-09-15 04:28:07 +00:00
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
mme_enb_t *enb = NULL;
|
|
|
|
|
|
|
|
d_assert(source_ue, return CORE_ERROR,);
|
2018-01-21 11:31:28 +00:00
|
|
|
d_assert(cause, return CORE_ERROR,);
|
2017-09-15 04:28:07 +00:00
|
|
|
enb = source_ue->enb;
|
|
|
|
d_assert(enb, return CORE_ERROR,);
|
|
|
|
|
|
|
|
rv = s1ap_build_handover_preparation_failure(&s1apbuf, source_ue, cause);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = s1ap_send_to_enb(enb, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t s1ap_send_handover_cancel_ack(enb_ue_t *source_ue)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
mme_enb_t *enb = NULL;
|
|
|
|
|
|
|
|
d_assert(source_ue, return CORE_ERROR,);
|
|
|
|
enb = source_ue->enb;
|
|
|
|
d_assert(enb, return CORE_ERROR,);
|
|
|
|
|
|
|
|
rv = s1ap_build_handover_cancel_ack(&s1apbuf, source_ue);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = s1ap_send_to_enb(enb, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-12 14:07:55 +00:00
|
|
|
status_t s1ap_send_handover_request(
|
2018-03-13 14:16:01 +00:00
|
|
|
mme_ue_t *mme_ue,
|
2018-03-23 04:14:56 +00:00
|
|
|
mme_enb_t *target_enb,
|
2018-03-13 14:16:01 +00:00
|
|
|
S1AP_ENB_UE_S1AP_ID_t *enb_ue_s1ap_id,
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *mme_ue_s1ap_id,
|
|
|
|
S1AP_HandoverType_t *handovertype,
|
|
|
|
S1AP_Cause_t *cause,
|
|
|
|
S1AP_Source_ToTarget_TransparentContainer_t
|
|
|
|
*source_totarget_transparentContainer)
|
2017-09-12 14:07:55 +00:00
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
2017-09-14 10:33:58 +00:00
|
|
|
enb_ue_t *source_ue = NULL, *target_ue = NULL;
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Handover request\n");
|
2018-03-23 04:14:56 +00:00
|
|
|
|
|
|
|
d_assert(target_enb, return CORE_ERROR, "Cannot find target eNB");
|
2018-01-22 14:14:20 +00:00
|
|
|
|
2017-09-12 14:07:55 +00:00
|
|
|
d_assert(mme_ue, return CORE_ERROR,);
|
2017-09-14 10:33:58 +00:00
|
|
|
source_ue = mme_ue->enb_ue;
|
|
|
|
d_assert(source_ue, return CORE_ERROR,);
|
|
|
|
d_assert(source_ue->target_ue == NULL, return CORE_ERROR,
|
|
|
|
"Handover Required Duplicated");
|
|
|
|
|
2017-09-14 09:01:26 +00:00
|
|
|
target_ue = enb_ue_add(target_enb);
|
|
|
|
d_assert(target_ue, return CORE_ERROR,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
|
2018-01-28 06:08:52 +00:00
|
|
|
d_trace(5, " Target : ENB_UE_S1AP_ID[Unknown] MME_UE_S1AP_ID[%d]\n",
|
|
|
|
target_ue->mme_ue_s1ap_id);
|
2018-01-22 14:14:20 +00:00
|
|
|
|
2017-09-18 12:30:04 +00:00
|
|
|
rv = source_ue_associate_target_ue(source_ue, target_ue);
|
|
|
|
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
rv = s1ap_build_handover_request(&s1apbuf, mme_ue, target_ue,
|
|
|
|
enb_ue_s1ap_id, mme_ue_s1ap_id,
|
2018-03-23 04:14:56 +00:00
|
|
|
handovertype, cause,
|
2018-03-13 14:16:01 +00:00
|
|
|
source_totarget_transparentContainer);
|
2018-01-29 05:48:51 +00:00
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2017-09-14 09:01:26 +00:00
|
|
|
rv = s1ap_send_to_enb(target_enb, s1apbuf);
|
2018-01-29 05:48:51 +00:00
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
2017-09-12 14:07:55 +00:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2017-09-13 12:51:02 +00:00
|
|
|
|
2017-09-14 02:12:02 +00:00
|
|
|
status_t s1ap_send_mme_status_transfer(
|
2018-03-13 14:16:01 +00:00
|
|
|
enb_ue_t *target_ue,
|
|
|
|
S1AP_ENB_StatusTransfer_TransparentContainer_t
|
|
|
|
*enb_statustransfer_transparentContainer)
|
2017-09-14 02:12:02 +00:00
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
mme_enb_t *enb = NULL;
|
|
|
|
|
2017-09-15 03:06:26 +00:00
|
|
|
d_assert(target_ue, return CORE_ERROR,);
|
|
|
|
enb = target_ue->enb;
|
2017-09-14 02:12:02 +00:00
|
|
|
d_assert(enb, return CORE_ERROR,);
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
rv = s1ap_build_mme_status_transfer(&s1apbuf, target_ue,
|
|
|
|
enb_statustransfer_transparentContainer);
|
2017-09-14 02:12:02 +00:00
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = s1ap_send_to_enb(enb, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2018-02-03 02:48:15 +00:00
|
|
|
|
2018-03-07 12:53:53 +00:00
|
|
|
status_t s1ap_send_mme_configuration_transfer(
|
2018-03-08 14:29:02 +00:00
|
|
|
mme_enb_t *target_enb, pkbuf_t *recvbuf)
|
2018-03-07 12:53:53 +00:00
|
|
|
{
|
2018-03-08 14:29:02 +00:00
|
|
|
status_t rv;
|
2018-03-18 09:50:36 +00:00
|
|
|
unsigned char *payload;
|
2018-03-08 14:29:02 +00:00
|
|
|
pkbuf_t *sendbuf = NULL;
|
|
|
|
|
|
|
|
d_assert(target_enb, return CORE_ERROR,);
|
|
|
|
d_assert(recvbuf, return CORE_ERROR,);
|
|
|
|
|
|
|
|
sendbuf = pkbuf_copy(recvbuf);
|
|
|
|
d_assert(sendbuf, return CORE_ERROR,);
|
|
|
|
|
|
|
|
payload = sendbuf->payload;
|
2018-03-09 12:02:17 +00:00
|
|
|
payload[1] = S1AP_ProcedureCode_id_MMEConfigurationTransfer;
|
|
|
|
payload[8] = S1AP_ProtocolIE_ID_id_SONConfigurationTransferMCT;
|
2018-03-08 14:29:02 +00:00
|
|
|
|
|
|
|
rv = s1ap_send_to_enb(target_enb, sendbuf);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
2018-03-07 12:53:53 +00:00
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2018-02-03 02:48:15 +00:00
|
|
|
status_t s1ap_send_error_indication(
|
2018-03-12 14:06:14 +00:00
|
|
|
mme_enb_t *enb,
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *mme_ue_s1ap_id,
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *enb_ue_s1ap_id,
|
2018-03-14 08:59:56 +00:00
|
|
|
S1AP_Cause_PR group, long cause)
|
2018-02-03 02:48:15 +00:00
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
d_assert(enb, return CORE_ERROR,);
|
|
|
|
|
|
|
|
rv = s1ap_build_error_indication(&s1apbuf,
|
2018-03-14 08:59:56 +00:00
|
|
|
mme_ue_s1ap_id, enb_ue_s1ap_id, group, cause);
|
2018-02-03 02:48:15 +00:00
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = s1ap_send_to_enb(enb, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2018-03-21 07:10:20 +00:00
|
|
|
|
|
|
|
status_t s1ap_send_s1_reset_ack(
|
|
|
|
mme_enb_t *enb,
|
|
|
|
S1AP_UE_associatedLogicalS1_ConnectionListRes_t *partOfS1_Interface)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
|
|
|
|
d_assert(enb, return CORE_ERROR,);
|
|
|
|
|
|
|
|
rv = s1ap_build_s1_reset_ack(&s1apbuf, partOfS1_Interface);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
|
|
|
|
|
|
|
|
rv = s1ap_send_to_enb(enb, s1apbuf);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|