[#258] Test done for receiving unknown TEID

This commit is contained in:
Sukchan Lee 2019-11-11 23:09:35 +09:00
parent 71f54a4500
commit cdbbbc500b
13 changed files with 608 additions and 460 deletions

View File

@ -351,8 +351,7 @@ bool ogs_sockaddr_is_equal(void *p, void *q)
&a->sin6.sin6_addr, &b->sin6.sin6_addr, sizeof(struct in6_addr)) == 0)
return true;
else {
ogs_fatal("Unknown family(%d)", a->ogs_sa_family);
ogs_abort();
return false;
}
return false;

View File

@ -215,3 +215,53 @@ ogs_pkbuf_t *ogs_gtp_handle_echo_req(ogs_pkbuf_t *pkb)
return pkb_resp;
}
void ogs_gtp_send_error_message(
ogs_gtp_xact_t *xact, uint32_t teid, uint8_t type, uint8_t cause_value)
{
int rv;
ogs_gtp_message_t errmsg;
ogs_gtp_cause_t cause;
ogs_tlv_cause_t *tlv = NULL;
ogs_pkbuf_t *pkbuf = NULL;
memset(&errmsg, 0, sizeof(ogs_gtp_message_t));
errmsg.h.teid = teid;
errmsg.h.type = type;
switch (type) {
case OGS_GTP_CREATE_SESSION_RESPONSE_TYPE:
tlv = &errmsg.create_session_response.cause;
break;
case OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE:
tlv = &errmsg.modify_bearer_response.cause;
break;
case OGS_GTP_DELETE_SESSION_RESPONSE_TYPE:
tlv = &errmsg.delete_session_response.cause;
break;
case OGS_GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE:
tlv = &errmsg.release_access_bearers_response.cause;
break;
default:
ogs_assert_if_reached();
return;
}
ogs_assert(tlv);
memset(&cause, 0, sizeof cause);
cause.value = cause_value;
tlv->presence = 1;
tlv->len = sizeof(cause);
tlv->data = &cause;
rv = ogs_gtp_build_msg(&pkbuf, &errmsg);
ogs_assert(rv == OGS_OK);
rv = ogs_gtp_xact_update_tx(xact, &errmsg.h, pkbuf);
ogs_assert(rv == OGS_OK);
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
}

View File

@ -28,6 +28,8 @@
extern "C" {
#endif
typedef struct ogs_gtp_xact_s ogs_gtp_xact_t;
ogs_sock_t *ogs_gtp_server(ogs_socknode_t *node);
int ogs_gtp_connect(ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_gtp_node_t *gnode);
@ -38,6 +40,8 @@ int ogs_gtp_send(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf);
int ogs_gtp_sendto(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf);
ogs_pkbuf_t *ogs_gtp_handle_echo_req(ogs_pkbuf_t *pkt);
void ogs_gtp_send_error_message(
ogs_gtp_xact_t *xact, uint32_t teid, uint8_t type, uint8_t cause_value);
#ifdef __cplusplus
}

View File

@ -43,11 +43,13 @@ void mme_s11_handle_create_session_response(
ogs_pdn_t *pdn = NULL;
ogs_assert(xact);
ogs_assert(mme_ue);
ogs_assert(rsp);
ogs_debug("[MME] Create Session Response");
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
if (rsp->sender_f_teid_for_control_plane.presence == 0) {
ogs_error("No S11 TEID");
return;
@ -70,7 +72,6 @@ void mme_s11_handle_create_session_response(
}
ogs_assert(mme_ue);
bearer = mme_bearer_find_by_ue_ebi(mme_ue,
rsp->bearer_contexts_created.eps_bearer_id.u8);
ogs_assert(bearer);
@ -104,9 +105,6 @@ void mme_s11_handle_create_session_response(
rv = ogs_gtp_f_teid_to_ip(sgw_s1u_teid, &bearer->sgw_s1u_ip);
ogs_assert(rv == OGS_OK);
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_initial_context_setup)) {
mme_csmap_t *csmap = mme_csmap_find_by_tai(&mme_ue->tai);
mme_ue->csmap = csmap;
@ -129,19 +127,36 @@ void mme_s11_handle_modify_bearer_response(
ogs_gtp_modify_bearer_response_t *rsp)
{
int rv;
ogs_gtp_cause_t *cause = NULL;
enb_ue_t *source_ue = NULL, *target_ue = NULL;
ogs_assert(mme_ue);
ogs_assert(xact);
ogs_assert(rsp);
ogs_debug("[MME] Modify Bearer Response");
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
if (rsp->cause.presence == 0) {
ogs_error("No Cause");
return;
}
cause = rsp->cause.data;
ogs_assert(cause);
if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
ogs_warn("No Accept [%d]", cause->value);
return;
}
if (!mme_ue) {
ogs_warn("No Context");
return;
}
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_PATH_SWITCH,
rv = s1ap_send_path_switch_ack(mme_ue);
ogs_assert(rv == OGS_OK);
@ -167,16 +182,11 @@ void mme_s11_handle_delete_session_response(
ogs_gtp_xact_t *xact, mme_ue_t *mme_ue,
ogs_gtp_delete_session_response_t *rsp)
{
ogs_gtp_cause_t cause;
int rv;
ogs_gtp_cause_t *cause = NULL;
mme_sess_t *sess = NULL;
ogs_assert(xact);
sess = OGS_GTP_XACT_RETRIEVE_SESSION(xact);
ogs_assert(sess);
mme_ue = sess->mme_ue;
ogs_assert(mme_ue);
ogs_assert(rsp);
ogs_debug("[MME] Delete Session Response");
@ -184,14 +194,20 @@ void mme_s11_handle_delete_session_response(
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
sess = OGS_GTP_XACT_RETRIEVE_SESSION(xact);
ogs_assert(sess);
mme_ue = sess->mme_ue;
ogs_assert(mme_ue);
if (rsp->cause.presence == 0) {
ogs_error("No Cause");
goto cleanup;
}
memcpy(&cause, rsp->cause.data, rsp->cause.len);
if (cause.value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
ogs_warn("No Accept [%d]", cause.value);
cause = rsp->cause.data;
ogs_assert(cause);
if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
ogs_warn("No Accept [%d]", cause->value);
goto cleanup;
}
@ -287,7 +303,6 @@ void mme_s11_handle_create_bearer_request(
ogs_gtp_bearer_qos_t bearer_qos;
ogs_assert(xact);
ogs_assert(mme_ue);
ogs_assert(req);
ogs_debug("[MME] Create Bearer Response");
@ -317,6 +332,7 @@ void mme_s11_handle_create_bearer_request(
return;
}
ogs_assert(mme_ue);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
@ -376,10 +392,10 @@ void mme_s11_handle_update_bearer_request(
ogs_gtp_bearer_qos_t bearer_qos;
ogs_assert(xact);
ogs_assert(mme_ue);
ogs_assert(req);
ogs_debug("[MME] Update Bearer Request");
if (req->bearer_contexts.presence == 0) {
ogs_error("No Bearer");
return;
@ -388,6 +404,8 @@ void mme_s11_handle_update_bearer_request(
ogs_error("No EPS Bearer ID");
return;
}
ogs_assert(mme_ue);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
@ -457,10 +475,10 @@ void mme_s11_handle_delete_bearer_request(
mme_bearer_t *bearer = NULL;
ogs_assert(xact);
ogs_assert(mme_ue);
ogs_assert(req);
ogs_debug("[MME] Delete Bearer Request");
if (req->linked_eps_bearer_id.presence == 1) {
bearer = mme_bearer_find_by_ue_ebi(
mme_ue, req->linked_eps_bearer_id.u8);
@ -473,6 +491,8 @@ void mme_s11_handle_delete_bearer_request(
ogs_error("No Linked EBI or EPS Bearer ID");
return;
}
ogs_assert(mme_ue);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
@ -502,17 +522,13 @@ void mme_s11_handle_release_access_bearers_response(
ogs_gtp_release_access_bearers_response_t *rsp)
{
int rv;
ogs_gtp_cause_t *cause = NULL;
enb_ue_t *enb_ue = NULL;
ogs_assert(xact);
ogs_assert(mme_ue);
ogs_assert(rsp);
ogs_debug("[MME] Release Access Bearers Response");
enb_ue = mme_ue->enb_ue;
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
@ -521,18 +537,34 @@ void mme_s11_handle_release_access_bearers_response(
ogs_error("No Cause");
return;
}
cause = rsp->cause.data;
ogs_assert(cause);
if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
ogs_warn("No Accept [%d]", cause->value);
return;
}
if (!mme_ue) {
ogs_warn("No Context");
return;
}
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = CLEAR_BEARER_CONTEXT(mme_ue);
ogs_assert(rv == OGS_OK);
enb_ue = mme_ue->enb_ue;
if (enb_ue) {
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_S1_NORMAL_RELEASE, 0);
ogs_assert(rv == OGS_OK);
} else
} else {
ogs_warn("ENB-S1 Context has already been removed");
}
}
void mme_s11_handle_downlink_data_notification(
@ -544,10 +576,11 @@ void mme_s11_handle_downlink_data_notification(
ogs_pkbuf_t *s11buf = NULL;
ogs_assert(xact);
ogs_assert(mme_ue);
ogs_assert(noti);
ogs_debug("[MME] Downlink Data Notification");
ogs_assert(mme_ue);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
@ -571,6 +604,7 @@ void mme_s11_handle_create_indirect_data_forwarding_tunnel_response(
ogs_gtp_create_indirect_data_forwarding_tunnel_response_t *rsp)
{
int rv;
ogs_gtp_cause_t *cause = NULL;
mme_bearer_t *bearer = NULL;
enb_ue_t *source_ue = NULL;
int i;
@ -579,23 +613,32 @@ void mme_s11_handle_create_indirect_data_forwarding_tunnel_response(
ogs_gtp_f_teid_t *teid = NULL;
ogs_assert(xact);
ogs_assert(mme_ue);
ogs_assert(rsp);
source_ue = mme_ue->enb_ue;
ogs_assert(source_ue);
ogs_debug("[MME] Create Indirect Data Forwarding Tunnel Response");
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
if (rsp->cause.presence == 0) {
ogs_error("No Cause");
return;
}
cause = rsp->cause.data;
ogs_assert(cause);
if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
ogs_warn("No Accept [%d]", cause->value);
return;
}
if (!mme_ue) {
ogs_warn("No Context");
return;
}
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
ogs_gtp_bearers_in_create_indirect_tunnel_response(&bearers, rsp);
for (i = 0; bearers[i]->presence; i++) {
@ -626,6 +669,9 @@ void mme_s11_handle_create_indirect_data_forwarding_tunnel_response(
}
}
source_ue = mme_ue->enb_ue;
ogs_assert(source_ue);
rv = s1ap_send_handover_command(source_ue);
ogs_assert(rv == OGS_OK);
}
@ -635,22 +681,35 @@ void mme_s11_handle_delete_indirect_data_forwarding_tunnel_response(
ogs_gtp_delete_indirect_data_forwarding_tunnel_response_t *rsp)
{
int rv;
ogs_gtp_cause_t *cause = NULL;
ogs_assert(xact);
ogs_assert(mme_ue);
ogs_assert(rsp);
ogs_debug("[MME] Delete Indirect Data Forwarding Tunnel Response");
if (rsp->cause.presence == 0) {
ogs_error("No Cause");
return;
}
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = ogs_gtp_xact_commit(xact);
ogs_assert(rv == OGS_OK);
if (rsp->cause.presence == 0) {
ogs_error("No Cause");
return;
}
cause = rsp->cause.data;
ogs_assert(cause);
if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
ogs_warn("No Accept [%d]", cause->value);
return;
}
if (!mme_ue) {
ogs_warn("No Context");
return;
}
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
rv = mme_ue_clear_indirect_tunnel(mme_ue);
ogs_assert(rv == OGS_OK);
}

View File

@ -20,11 +20,16 @@
#include "pgw-event.h"
#include "pgw-context.h"
#include "pgw-gtp-path.h"
#include "pgw-fd-path.h"
#include "pgw-s5c-handler.h"
#define SEND_ERROR_MESSAGE(XACT, SESS, TYPE, CAUSE) \
ogs_gtp_send_error_message( \
(XACT), ((SESS) ? ((SESS)->sgw_s5c_teid) : 0), (TYPE), (CAUSE))
void pgw_s5c_handle_create_session_request(
pgw_sess_t *sess, ogs_gtp_xact_t *xact,
ogs_gtp_create_session_request_t *req)
ogs_pkbuf_t *gtpbuf, ogs_gtp_create_session_request_t *req)
{
int rv;
ogs_gtp_f_teid_t *sgw_s5c_teid, *sgw_s5u_teid;
@ -36,36 +41,69 @@ void pgw_s5c_handle_create_session_request(
uint16_t decoded = 0;
ogs_assert(xact);
ogs_assert(sess);
ogs_assert(req);
bearer = pgw_default_bearer_in_sess(sess);
ogs_assert(bearer);
ogs_debug("[PGW] Create Session Reqeust");
if (req->imsi.presence == 0) {
ogs_error("No IMSI");
SEND_ERROR_MESSAGE(xact, sess,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
ogs_pkbuf_free(gtpbuf);
return;
}
if (req->sender_f_teid_for_control_plane.presence == 0) {
ogs_error("No TEID");
SEND_ERROR_MESSAGE(xact, sess,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
ogs_pkbuf_free(gtpbuf);
return;
}
if (req->bearer_contexts_to_be_created.presence == 0) {
ogs_error("No Bearer");
SEND_ERROR_MESSAGE(xact, sess,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
ogs_pkbuf_free(gtpbuf);
return;
}
if (req->bearer_contexts_to_be_created.bearer_level_qos.presence == 0) {
ogs_error("No EPS Bearer QoS");
SEND_ERROR_MESSAGE(xact, sess,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
ogs_pkbuf_free(gtpbuf);
return;
}
if (req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.presence == 0) {
ogs_error("No TEID");
SEND_ERROR_MESSAGE(xact, sess,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
ogs_pkbuf_free(gtpbuf);
return;
}
if (req->user_location_information.presence == 0) {
ogs_error("No User Location Inforamtion");
SEND_ERROR_MESSAGE(xact, sess,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
ogs_pkbuf_free(gtpbuf);
return;
}
if (sess) {
bearer = pgw_default_bearer_in_sess(sess);
ogs_assert(bearer);
}
if (!bearer) {
ogs_warn("No Context");
SEND_ERROR_MESSAGE(xact, sess,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
}
/* Set IMSI */
sess->imsi_len = req->imsi.len;
@ -128,17 +166,34 @@ void pgw_s5c_handle_create_session_request(
sess->tai.tac = uli.tai.tac;
memcpy(&sess->e_cgi.plmn_id, &uli.e_cgi.plmn_id, sizeof(uli.e_cgi.plmn_id));
sess->e_cgi.cell_id = uli.e_cgi.cell_id;
pgw_gx_send_ccr(sess, xact, gtpbuf,
OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST);
}
void pgw_s5c_handle_delete_session_request(
pgw_sess_t *sess, ogs_gtp_xact_t *xact,
ogs_gtp_delete_session_request_t *req)
ogs_pkbuf_t *gtpbuf, ogs_gtp_delete_session_request_t *req)
{
ogs_assert(sess);
ogs_debug("[PGW] Delete Session Request");
ogs_assert(xact);
ogs_assert(req);
if (!sess) {
ogs_warn("No Context");
SEND_ERROR_MESSAGE(xact, sess,
OGS_GTP_DELETE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
ogs_pkbuf_free(gtpbuf);
return;
}
ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
pgw_gx_send_ccr(sess, xact, gtpbuf,
OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST);
}
void pgw_s5c_handle_create_bearer_response(

View File

@ -28,10 +28,10 @@ extern "C" {
void pgw_s5c_handle_create_session_request(
pgw_sess_t *sess, ogs_gtp_xact_t *xact,
ogs_gtp_create_session_request_t *req);
ogs_pkbuf_t *gtpbuf, ogs_gtp_create_session_request_t *req);
void pgw_s5c_handle_delete_session_request(
pgw_sess_t *sess, ogs_gtp_xact_t *xact,
ogs_gtp_delete_session_request_t *req);
ogs_pkbuf_t *gtpbuf, ogs_gtp_delete_session_request_t *req);
void pgw_s5c_handle_create_bearer_response(
pgw_sess_t *sess, ogs_gtp_xact_t *xact,
ogs_gtp_create_bearer_response_t *req);

View File

@ -150,15 +150,11 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e)
OGS_SETUP_GTP_NODE(sess, gnode);
}
pgw_s5c_handle_create_session_request(
sess, xact, &message->create_session_request);
pgw_gx_send_ccr(sess, xact, copybuf,
OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST);
sess, xact, copybuf, &message->create_session_request);
break;
case OGS_GTP_DELETE_SESSION_REQUEST_TYPE:
pgw_s5c_handle_delete_session_request(
sess, xact, &message->delete_session_request);
pgw_gx_send_ccr(sess, xact, copybuf,
OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST);
sess, xact, copybuf, &message->delete_session_request);
break;
case OGS_GTP_CREATE_BEARER_RESPONSE_TYPE:
pgw_s5c_handle_create_bearer_response(

View File

@ -430,10 +430,8 @@ sgw_ue_t *sgw_ue_add_by_message(ogs_gtp_message_t *message)
* the message is received with a TEID not set to zero in the header.
*/
sgw_ue = sgw_ue_find_by_imsi(req->imsi.data, req->imsi.len);
if (sgw_ue) {
ogs_warn("OLD UE Context Release [IMSI:%s]", sgw_ue->imsi_bcd);
if (sgw_ue)
sgw_ue_remove(sgw_ue);
}
sgw_ue = sgw_ue_add(req->imsi.data, req->imsi.len);
ogs_assert(sgw_ue);
@ -795,11 +793,13 @@ sgw_tunnel_t *sgw_tunnel_find_by_interface_type(
sgw_tunnel_t *sgw_s1u_tunnel_in_bearer(sgw_bearer_t *bearer)
{
ogs_assert(bearer);
return sgw_tunnel_find_by_interface_type(
bearer, OGS_GTP_F_TEID_S1_U_SGW_GTP_U);
}
sgw_tunnel_t *sgw_s5u_tunnel_in_bearer(sgw_bearer_t *bearer)
{
ogs_assert(bearer);
return sgw_tunnel_find_by_interface_type(
bearer, OGS_GTP_F_TEID_S5_S8_SGW_GTP_U);
}

View File

@ -26,6 +26,7 @@
extern "C" {
#endif
typedef struct ogs_gtp_node_s ogs_gtp_node_t;
typedef struct sgw_bearer_s sgw_bearer_t;
typedef enum {
@ -44,8 +45,7 @@ typedef struct sgw_event_s {
int id;
ogs_pkbuf_t *pkbuf;
ogs_sock_t *sock;
ogs_sockaddr_t *addr;
ogs_gtp_node_t *gnode;
sgw_bearer_t *bearer;
} sgw_event_t;

View File

@ -29,9 +29,12 @@ static void _gtpv2_c_recv_cb(short when, ogs_socket_t fd, void *data)
int rv;
ssize_t size;
ogs_gtp_header_t *gtp_h = NULL;
#if 0
uint32_t teid = 0;
#endif
ogs_pkbuf_t *pkbuf = NULL;
ogs_sockaddr_t from;
ogs_gtp_node_t *gnode = NULL;
ogs_assert(fd != INVALID_SOCKET);
@ -51,26 +54,62 @@ static void _gtpv2_c_recv_cb(short when, ogs_socket_t fd, void *data)
gtp_h = (ogs_gtp_header_t *)pkbuf->data;
ogs_assert(gtp_h);
ogs_assert(gtp_h->teid_presence);
#if 0
teid = ntohl(gtp_h->teid);
#endif
if (SGW_S5C_TEID(teid))
/*
* 5.5.2 in spec 29.274
*
* If a peer's TEID is not available, the TEID field still shall be
* present in the header and its value shall be set to "0" in the
* following messages:
*
* - Create Session Request message on S2a/S2b/S5/S8
*
* - Create Session Request message on S4/S11, if for a given UE,
* the SGSN/MME has not yet obtained the Control TEID of the SGW.
*
* - If a node receives a message and the TEID-C in the GTPv2 header of
* the received message is not known, it shall respond with
* "Context not found" Cause in the corresponding response message
* to the sender, the TEID used in the GTPv2-C header in the response
* message shall be then set to zero.
*
* - If a node receives a request message containing protocol error,
* e.g. Mandatory IE missing, which requires the receiver to reject
* the message as specified in clause 7.7, it shall reject
* the request message. For the response message, the node should
* look up the remote peer's TEID and accordingly set the GTPv2-C
* header TEID and the message cause code. As an implementation
* option, the node may not look up the remote peer's TEID and
* set the GTPv2-C header TEID to zero in the response message.
* However in this case, the cause code shall not be set to
* "Context not found".
*/
gnode = ogs_gtp_node_find_by_addr(&sgw_self()->pgw_s5c_list, &from);
if (gnode) {
e = sgw_event_new(SGW_EVT_S5C_MESSAGE);
else
e->gnode = gnode;
} else {
e = sgw_event_new(SGW_EVT_S11_MESSAGE);
gnode = ogs_gtp_node_find_by_addr(&sgw_self()->mme_s11_list, &from);
if (!gnode) {
gnode = ogs_gtp_node_add_by_addr(
&sgw_self()->mme_s11_list, &from);
ogs_assert(gnode);
gnode->sock = data;
}
e->gnode = gnode;
}
ogs_assert(e);
e->pkbuf = pkbuf;
e->sock = data;
ogs_assert(e->sock);
e->addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
ogs_assert(e->addr);
memcpy(e->addr, &from, sizeof(ogs_sockaddr_t));
rv = ogs_queue_push(sgw_self()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_pkbuf_free(e->pkbuf);
ogs_free(e->addr);
sgw_event_free(e);
}
}

View File

@ -22,11 +22,13 @@
#include "sgw-gtp-path.h"
#include "sgw-s11-handler.h"
#define SEND_ERROR_MESSAGE(XACT, SGW_UE, TYPE, CAUSE) \
ogs_gtp_send_error_message( \
(XACT), ((SGW_UE) ? ((SGW_UE)->mme_s11_teid) : 0), (TYPE), (CAUSE))
void sgw_s11_handle_create_session_request(ogs_gtp_xact_t *s11_xact,
sgw_ue_t *sgw_ue, ogs_gtp_message_t *message)
{
ogs_gtp_cause_t cause;
int rv;
uint16_t decoded;
ogs_gtp_create_session_request_t *req = NULL;
@ -48,75 +50,69 @@ void sgw_s11_handle_create_session_request(ogs_gtp_xact_t *s11_xact,
ogs_assert(s11_xact);
ogs_assert(message);
req = &message->create_session_request;
ogs_debug("[SGW] Create Session Request");
memset(&cause, 0, sizeof cause);
if (!sgw_ue) {
ogs_warn("No Context");
cause.value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND;
}
req = &message->create_session_request;
if (req->imsi.presence == 0) {
ogs_error("No IMSI");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (req->bearer_contexts_to_be_created.presence == 0) {
ogs_error("No Bearer");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) {
ogs_error("No EPS Bearer ID");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (req->access_point_name.presence == 0) {
ogs_error("No APN");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (req->sender_f_teid_for_control_plane.presence == 0) {
ogs_error("No Sender F-TEID");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (req->pgw_s5_s8_address_for_control_plane_or_pmip.presence == 0) {
ogs_error("No PGW IP");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (req->user_location_information.presence == 0) {
ogs_error("No User Location Inforamtion");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (cause.value) {
ogs_gtp_message_t errmsg;
ogs_gtp_create_session_response_t *rsp = NULL;
ogs_debug("[SGW] Create Session Response");
rsp = &errmsg.create_session_response;
memset(&errmsg, 0, sizeof(ogs_gtp_message_t));
/* Set Cause */
rsp->cause.presence = 1;
rsp->cause.len = sizeof(cause);
rsp->cause.data = &cause;
errmsg.h.type = OGS_GTP_CREATE_SESSION_RESPONSE_TYPE;
if (sgw_ue)
errmsg.h.teid = sgw_ue->mme_s11_teid;
rv = ogs_gtp_build_msg(&pkbuf, &errmsg);
ogs_assert(rv == OGS_OK);
rv = ogs_gtp_xact_update_tx(s11_xact, &errmsg.h, pkbuf);
ogs_assert(rv == OGS_OK);
rv = ogs_gtp_xact_commit(s11_xact);
ogs_assert(rv == OGS_OK);
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (!sgw_ue) {
ogs_warn("No Context");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
return;
}
ogs_fqdn_parse(apn,
req->access_point_name.data, req->access_point_name.len);
sess = sgw_sess_find_by_ebi(sgw_ue,
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
if (sess) {
@ -124,9 +120,6 @@ void sgw_s11_handle_create_session_request(ogs_gtp_xact_t *s11_xact,
sgw_ue->imsi_bcd, sess->pdn.apn);
sgw_sess_remove(sess);
}
ogs_fqdn_parse(apn,
req->access_point_name.data, req->access_point_name.len);
sess = sgw_sess_add(sgw_ue, apn,
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
ogs_assert(sess);
@ -217,8 +210,6 @@ void sgw_s11_handle_create_session_request(ogs_gtp_xact_t *s11_xact,
void sgw_s11_handle_modify_bearer_request(ogs_gtp_xact_t *s11_xact,
sgw_ue_t *sgw_ue, ogs_gtp_modify_bearer_request_t *req)
{
ogs_gtp_cause_t cause;
int rv;
char buf[OGS_ADDRSTRLEN];
@ -230,6 +221,7 @@ void sgw_s11_handle_modify_bearer_request(ogs_gtp_xact_t *s11_xact,
ogs_pkbuf_t *pkbuf = NULL;
ogs_gtp_message_t message;
ogs_gtp_cause_t cause;
ogs_gtp_f_teid_t *enb_s1u_teid = NULL;
ogs_gtp_uli_t uli;
@ -238,132 +230,142 @@ void sgw_s11_handle_modify_bearer_request(ogs_gtp_xact_t *s11_xact,
ogs_debug("[SGW] Modify Bearer Reqeust");
rsp = &message.modify_bearer_response;
if (req->bearer_contexts_to_be_modified.presence == 0) {
ogs_error("No Bearer");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (req->bearer_contexts_to_be_modified.eps_bearer_id.presence == 0) {
ogs_error("No EPS Bearer ID");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.presence == 0) {
ogs_error("No eNB TEID");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (sgw_ue) {
bearer = sgw_bearer_find_by_ue_ebi(sgw_ue,
req->bearer_contexts_to_be_modified.eps_bearer_id.u8);
ogs_assert(bearer);
}
if (!bearer) {
ogs_warn("No Context");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE,
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
return;
}
rsp = &message.modify_bearer_response;
memset(&message, 0, sizeof(ogs_gtp_message_t));
message.h.type = OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE;
if (sgw_ue)
message.h.teid = sgw_ue->mme_s11_teid;
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
ogs_assert(s1u_tunnel);
/* Data Plane(DL) : eNB-S1U */
enb_s1u_teid =
req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.data;
s1u_tunnel->remote_teid = ntohl(enb_s1u_teid->teid);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
ogs_debug(" ENB_S1U_TEID[%d] SGW_S1U_TEID[%d]",
s1u_tunnel->remote_teid, s1u_tunnel->local_teid);
enb = ogs_gtp_node_find_by_f_teid(
&sgw_self()->enb_s1u_list, enb_s1u_teid);
if (!enb) {
enb = ogs_gtp_node_add(&sgw_self()->enb_s1u_list, enb_s1u_teid,
sgw_self()->gtpu_port,
ogs_config()->parameter.no_ipv4,
ogs_config()->parameter.no_ipv6,
ogs_config()->parameter.prefer_ipv4);
ogs_assert(enb);
rv = ogs_gtp_connect(sgw_self()->gtpu_sock, sgw_self()->gtpu_sock6, enb);
ogs_assert(rv == OGS_OK);
}
/* Copy Bearer-Contexts-Modified from Modify-Bearer-Request
*
* TS 29.274 Table 7.2.7-2
* NOTE 1: The SGW shall not change its F-TEID for a given interface
* during the Handover, Service Request, E-UTRAN Initial Attach,
* UE Requested PDN connectivity and PDP Context Activation procedures.
* The SGW F-TEID shall be same for S1-U, S4-U and S12. During Handover
* and Service Request the target eNodeB/RNC/SGSN may use a different
* IP type than the one used by the source eNodeB/RNC/SGSN.
* In order to support such a scenario, the SGW F-TEID should contain
* both an IPv4 address and an IPv6 address
* (see also subclause 8.22 "F-TEID").
*/
rsp->bearer_contexts_modified.presence = 1;
rsp->bearer_contexts_modified.eps_bearer_id.presence = 1;
rsp->bearer_contexts_modified.eps_bearer_id.u8 =
req->bearer_contexts_to_be_modified.eps_bearer_id.u8;
rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.presence = 1;
rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.data =
req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.data;
rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.len =
req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.len;
rsp->bearer_contexts_modified.cause.presence = 1;
rsp->bearer_contexts_modified.cause.len = sizeof(cause);
rsp->bearer_contexts_modified.cause.data = &cause;
/* if GTP Node changes, End Marker is sent out or not */
if (req->user_location_information.presence == 1) {
/* Set User Location Information */
decoded = ogs_gtp_parse_uli(&uli, &req->user_location_information);
ogs_assert(req->user_location_information.len == decoded);
memcpy(&bearer->tai.plmn_id, &uli.tai.plmn_id,
sizeof(uli.tai.plmn_id));
bearer->tai.tac = uli.tai.tac;
memcpy(&bearer->e_cgi.plmn_id, &uli.e_cgi.plmn_id,
sizeof(uli.e_cgi.plmn_id));
bearer->e_cgi.cell_id = uli.e_cgi.cell_id;
ogs_debug(" TAI[PLMN_ID:%06x,TAC:%d]",
ogs_plmn_id_hexdump(&bearer->tai.plmn_id),
bearer->tai.tac);
ogs_debug(" E_CGI[PLMN_ID:%06x,CELL_ID:%d]",
ogs_plmn_id_hexdump(&bearer->e_cgi.plmn_id),
bearer->e_cgi.cell_id);
}
if (s1u_tunnel->gnode && s1u_tunnel->gnode != enb) {
ogs_assert(s1u_tunnel->gnode->sock);
ogs_debug("[SGW] SEND End Marker to ENB[%s]: TEID[0x%x]",
OGS_ADDR(&s1u_tunnel->gnode->remote_addr, buf),
s1u_tunnel->remote_teid);
rv = sgw_gtp_send_end_marker(s1u_tunnel);
if (rv != OGS_OK)
ogs_error("gtp send end marker failed");
}
/* Setup GTP Node */
OGS_SETUP_GTP_NODE(s1u_tunnel, enb);
/* Reset UE state */
SGW_RESET_UE_STATE(sgw_ue, SGW_S1U_INACTIVE);
memset(&cause, 0, sizeof(cause));
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
rsp->cause.presence = 1;
rsp->cause.data = &cause;
rsp->cause.len = sizeof(cause);
if (req->bearer_contexts_to_be_modified.presence == 0) {
ogs_error("No Bearer");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
} else {
if (sgw_ue) {
bearer = sgw_bearer_find_by_ue_ebi(sgw_ue,
req->bearer_contexts_to_be_modified.eps_bearer_id.u8);
}
if (!bearer) {
ogs_warn("No Context");
cause.value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND;
}
}
if (req->bearer_contexts_to_be_modified.eps_bearer_id.presence == 0) {
ogs_error("No EPS Bearer ID");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.presence == 0) {
ogs_error("No eNB TEID");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (bearer) {
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
ogs_assert(s1u_tunnel);
/* Data Plane(DL) : eNB-S1U */
enb_s1u_teid = req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.data;
s1u_tunnel->remote_teid = ntohl(enb_s1u_teid->teid);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
ogs_debug(" ENB_S1U_TEID[%d] SGW_S1U_TEID[%d]",
s1u_tunnel->remote_teid, s1u_tunnel->local_teid);
enb = ogs_gtp_node_find_by_f_teid(
&sgw_self()->enb_s1u_list, enb_s1u_teid);
if (!enb) {
enb = ogs_gtp_node_add(&sgw_self()->enb_s1u_list, enb_s1u_teid,
sgw_self()->gtpu_port,
ogs_config()->parameter.no_ipv4,
ogs_config()->parameter.no_ipv6,
ogs_config()->parameter.prefer_ipv4);
ogs_assert(enb);
rv = ogs_gtp_connect(sgw_self()->gtpu_sock, sgw_self()->gtpu_sock6, enb);
ogs_assert(rv == OGS_OK);
}
/* Copy Bearer-Contexts-Modified from Modify-Bearer-Request
*
* TS 29.274 Table 7.2.7-2
* NOTE 1: The SGW shall not change its F-TEID for a given interface
* during the Handover, Service Request, E-UTRAN Initial Attach,
* UE Requested PDN connectivity and PDP Context Activation procedures.
* The SGW F-TEID shall be same for S1-U, S4-U and S12. During Handover
* and Service Request the target eNodeB/RNC/SGSN may use a different
* IP type than the one used by the source eNodeB/RNC/SGSN.
* In order to support such a scenario, the SGW F-TEID should contain
* both an IPv4 address and an IPv6 address
* (see also subclause 8.22 "F-TEID").
*/
rsp->bearer_contexts_modified.presence = 1;
rsp->bearer_contexts_modified.eps_bearer_id.presence = 1;
rsp->bearer_contexts_modified.eps_bearer_id.u8 =
req->bearer_contexts_to_be_modified.eps_bearer_id.u8;
rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.presence = 1;
rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.data =
req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.data;
rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.len =
req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.len;
rsp->bearer_contexts_modified.cause.presence = 1;
rsp->bearer_contexts_modified.cause.len = sizeof(cause);
rsp->bearer_contexts_modified.cause.data = &cause;
/* if GTP Node changes, End Marker is sent out or not */
if (req->user_location_information.presence == 1) {
/* Set User Location Information */
decoded = ogs_gtp_parse_uli(&uli, &req->user_location_information);
ogs_assert(req->user_location_information.len == decoded);
memcpy(&bearer->tai.plmn_id, &uli.tai.plmn_id,
sizeof(uli.tai.plmn_id));
bearer->tai.tac = uli.tai.tac;
memcpy(&bearer->e_cgi.plmn_id, &uli.e_cgi.plmn_id,
sizeof(uli.e_cgi.plmn_id));
bearer->e_cgi.cell_id = uli.e_cgi.cell_id;
ogs_debug(" TAI[PLMN_ID:%06x,TAC:%d]",
ogs_plmn_id_hexdump(&bearer->tai.plmn_id),
bearer->tai.tac);
ogs_debug(" E_CGI[PLMN_ID:%06x,CELL_ID:%d]",
ogs_plmn_id_hexdump(&bearer->e_cgi.plmn_id),
bearer->e_cgi.cell_id);
}
if (s1u_tunnel->gnode && s1u_tunnel->gnode != enb) {
ogs_assert(s1u_tunnel->gnode->sock);
ogs_debug("[SGW] SEND End Marker to ENB[%s]: TEID[0x%x]",
OGS_ADDR(&s1u_tunnel->gnode->remote_addr, buf),
s1u_tunnel->remote_teid);
rv = sgw_gtp_send_end_marker(s1u_tunnel);
if (rv != OGS_OK)
ogs_error("gtp send end marker failed");
}
/* Setup GTP Node */
OGS_SETUP_GTP_NODE(s1u_tunnel, enb);
/* Reset UE state */
SGW_RESET_UE_STATE(sgw_ue, SGW_S1U_INACTIVE);
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
}
message.h.type = OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE;
message.h.teid = sgw_ue->mme_s11_teid;
rv = ogs_gtp_build_msg(&pkbuf, &message);
ogs_assert(rv == OGS_OK);
@ -378,8 +380,6 @@ void sgw_s11_handle_modify_bearer_request(ogs_gtp_xact_t *s11_xact,
void sgw_s11_handle_delete_session_request(ogs_gtp_xact_t *s11_xact,
sgw_ue_t *sgw_ue, ogs_gtp_message_t *message)
{
ogs_gtp_cause_t cause;
int rv;
ogs_pkbuf_t *pkbuf = NULL;
ogs_gtp_xact_t *s5c_xact = NULL;
@ -389,52 +389,26 @@ void sgw_s11_handle_delete_session_request(ogs_gtp_xact_t *s11_xact,
ogs_assert(s11_xact);
ogs_assert(message);
req = &message->delete_session_request;
ogs_assert(req);
ogs_debug("[SGW] Delete Session Reqeust");
memset(&cause, 0, sizeof cause);
if (!sgw_ue) {
ogs_warn("No Context");
cause.value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND;
}
req = &message->delete_session_request;
if (req->linked_eps_bearer_id.presence == 0) {
ogs_error("No EPS Bearer ID");
cause.value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
}
if (cause.value) {
ogs_gtp_message_t errmsg;
ogs_gtp_delete_session_response_t *rsp = NULL;
ogs_debug("[SGW] Delete Session Response");
rsp = &errmsg.delete_session_response;
memset(&errmsg, 0, sizeof(ogs_gtp_message_t));
/* Set Cause */
rsp->cause.presence = 1;
rsp->cause.len = sizeof(cause);
rsp->cause.data = &cause;
errmsg.h.type = OGS_GTP_DELETE_SESSION_RESPONSE_TYPE;
if (sgw_ue)
errmsg.h.teid = sgw_ue->mme_s11_teid;
rv = ogs_gtp_build_msg(&pkbuf, &errmsg);
ogs_assert(rv == OGS_OK);
rv = ogs_gtp_xact_update_tx(s11_xact, &errmsg.h, pkbuf);
ogs_assert(rv == OGS_OK);
rv = ogs_gtp_xact_commit(s11_xact);
ogs_assert(rv == OGS_OK);
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_DELETE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (!sgw_ue) {
ogs_warn("No Context");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_DELETE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
return;
}
ogs_assert(sgw_ue);
sess = sgw_sess_find_by_ebi(sgw_ue, req->linked_eps_bearer_id.u8);
ogs_assert(sess);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
@ -482,9 +456,8 @@ void sgw_s11_handle_create_bearer_response(ogs_gtp_xact_t *s11_xact,
ogs_assert(s5c_xact);
ogs_debug("[SGW] Cerate Bearer Reqeust");
req = &message->create_bearer_response;
ogs_assert(req);
req = &message->create_bearer_response;
if (req->bearer_contexts.presence == 0) {
ogs_error("No Bearer");
return;
@ -614,10 +587,9 @@ void sgw_s11_handle_update_bearer_response(ogs_gtp_xact_t *s11_xact,
s5c_xact = s11_xact->assoc_xact;
ogs_assert(s5c_xact);
req = &message->update_bearer_response;
ogs_assert(req);
ogs_debug("[SGW] Update Bearer Reqeust");
req = &message->update_bearer_response;
if (req->bearer_contexts.presence == 0) {
ogs_error("No Bearer");
return;
@ -667,10 +639,9 @@ void sgw_s11_handle_delete_bearer_response(ogs_gtp_xact_t *s11_xact,
s5c_xact = s11_xact->assoc_xact;
ogs_assert(s5c_xact);
req = &message->delete_bearer_response;
ogs_assert(req);
ogs_debug("[SGW] Delete Bearer Response");
req = &message->delete_bearer_response;
if (req->bearer_contexts.presence == 0) {
ogs_error("No Bearer");
return;
@ -724,49 +695,50 @@ void sgw_s11_handle_release_access_bearers_request(ogs_gtp_xact_t *s11_xact,
ogs_debug("[SGW] Release Access Bearers Request");
rsp = &message.release_access_bearers_response;
if (!sgw_ue) {
ogs_warn("No Context");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE,
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
return;
}
rsp = &message.release_access_bearers_response;
memset(&message, 0, sizeof(ogs_gtp_message_t));
message.h.type = OGS_GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE;
if (sgw_ue)
message.h.teid = sgw_ue->mme_s11_teid;
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
/* Set UE state to S1UE_INACTIVE */
SGW_SET_UE_STATE(sgw_ue, SGW_S1U_INACTIVE);
/* ReSet UE state to S1UE_INACTIVE */
SGW_RESET_UE_STATE(sgw_ue, SGW_DL_NOTI_SENT);
/* Release S1U(DL) path */
sess = sgw_sess_first(sgw_ue);
while (sess) {
bearer = ogs_list_first(&sess->bearer_list);
while (bearer) {
next_bearer = ogs_list_next(bearer);
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
ogs_assert(s1u_tunnel);
s1u_tunnel->remote_teid = 0;
bearer = next_bearer;
}
sess = sgw_sess_next(sess);
}
memset(&cause, 0, sizeof(cause));
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
rsp->cause.presence = 1;
rsp->cause.data = &cause;
rsp->cause.len = sizeof(cause);
if (!sgw_ue) {
ogs_warn("No Context");
cause.value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND;
} else {
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
/* Set UE state to S1UE_INACTIVE */
SGW_SET_UE_STATE(sgw_ue, SGW_S1U_INACTIVE);
/* ReSet UE state to S1UE_INACTIVE */
SGW_RESET_UE_STATE(sgw_ue, SGW_DL_NOTI_SENT);
/* Release S1U(DL) path */
sess = sgw_sess_first(sgw_ue);
while (sess) {
bearer = ogs_list_first(&sess->bearer_list);
while (bearer) {
next_bearer = ogs_list_next(bearer);
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
ogs_assert(s1u_tunnel);
s1u_tunnel->remote_teid = 0;
bearer = next_bearer;
}
sess = sgw_sess_next(sess);
}
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
}
message.h.type = OGS_GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE;
message.h.teid = sgw_ue->mme_s11_teid;
rv = ogs_gtp_build_msg(&pkbuf, &message);
ogs_assert(rv == OGS_OK);
@ -828,15 +800,17 @@ void sgw_s11_handle_downlink_data_notification_ack(
ogs_gtp_downlink_data_notification_acknowledge_t *ack)
{
int rv;
ogs_assert(sgw_ue);
ogs_assert(s11_xact);
ogs_debug("[SGW] Downlink Data Notification Acknowledge");
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
rv = ogs_gtp_xact_commit(s11_xact);
ogs_assert(rv == OGS_OK);
ogs_assert(sgw_ue);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
}
void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
@ -861,27 +835,21 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
ogs_gtp_f_teid_t rsp_ul_teid[GTP_MAX_NUM_OF_INDIRECT_TUNNEL];
int len;
ogs_assert(sgw_ue);
ogs_assert(s11_xact);
ogs_assert(req);
ogs_debug("[SGW] Create Indirect Data Forwarding Tunnel Request");
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
rsp = &message.create_indirect_data_forwarding_tunnel_response;
memset(&message, 0, sizeof(ogs_gtp_message_t));
ogs_assert(sgw_ue);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
ogs_gtp_bearers_in_create_indirect_tunnel_request(&req_bearers, req);
ogs_gtp_bearers_in_create_indirect_tunnel_response(&rsp_bearers, rsp);
memset(&cause, 0, sizeof(cause));
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
rsp->cause.presence = 1;
rsp->cause.data = &cause;
rsp->cause.len = sizeof(cause);
for (i = 0; req_bearers[i]->presence; i++) {
if (req_bearers[i]->eps_bearer_id.presence == 0) {
ogs_error("No EBI");
@ -979,6 +947,12 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request(
}
}
memset(&cause, 0, sizeof(cause));
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
rsp->cause.presence = 1;
rsp->cause.data = &cause;
rsp->cause.len = sizeof(cause);
message.h.type =
OGS_GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE_TYPE;
message.h.teid = sgw_ue->mme_s11_teid;
@ -1007,10 +981,14 @@ void sgw_s11_handle_delete_indirect_data_forwarding_tunnel_request(
ogs_gtp_cause_t cause;
ogs_assert(sgw_ue);
ogs_assert(s11_xact);
ogs_debug("[SGW] Delete Indirect Data Forwarding Tunnel Request");
rsp = &message.delete_indirect_data_forwarding_tunnel_response;
memset(&message, 0, sizeof(ogs_gtp_message_t));
ogs_assert(sgw_ue);
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
@ -1039,12 +1017,8 @@ void sgw_s11_handle_delete_indirect_data_forwarding_tunnel_request(
sess = sgw_sess_next(sess);
}
rsp = &message.delete_indirect_data_forwarding_tunnel_response;
memset(&message, 0, sizeof(ogs_gtp_message_t));
memset(&cause, 0, sizeof(cause));
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
rsp->cause.presence = 1;
rsp->cause.data = &cause;
rsp->cause.len = sizeof(cause);

View File

@ -22,6 +22,10 @@
#include "sgw-gtp-path.h"
#include "sgw-s5c-handler.h"
#define SEND_ERROR_MESSAGE(XACT, SGW_UE, TYPE, CAUSE) \
ogs_gtp_send_error_message( \
(XACT), ((SGW_UE) ? ((SGW_UE)->mme_s11_teid) : 0), (TYPE), (CAUSE))
void sgw_s5c_handle_create_session_response(ogs_gtp_xact_t *s5c_xact,
sgw_sess_t *sess, ogs_gtp_message_t *gtp_message)
{
@ -31,6 +35,7 @@ void sgw_s5c_handle_create_session_response(ogs_gtp_xact_t *s5c_xact,
sgw_bearer_t *bearer = NULL;
sgw_tunnel_t *s1u_tunnel = NULL, *s5u_tunnel = NULL;
ogs_gtp_create_session_response_t *rsp = NULL;
ogs_gtp_cause_t *cause = NULL;
ogs_pkbuf_t *pkbuf = NULL;
sgw_ue_t *sgw_ue = NULL;
@ -40,46 +45,87 @@ void sgw_s5c_handle_create_session_response(ogs_gtp_xact_t *s5c_xact,
ogs_gtp_f_teid_t sgw_s1u_teid;
int len;
ogs_assert(sess);
sgw_ue = sess->sgw_ue;
ogs_assert(sgw_ue);
ogs_assert(s5c_xact);
s11_xact = s5c_xact->assoc_xact;
ogs_assert(s11_xact);
ogs_assert(gtp_message);
ogs_debug("[SGW] Create Session Response");
rsp = &gtp_message->create_session_response;
if (rsp->cause.presence == 0) {
ogs_error("No Cause");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
cause = rsp->cause.data;
ogs_assert(cause);
if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
ogs_warn("No Accept [%d]", cause->value);
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
cause->value);
return;
}
if (rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.
presence == 0) {
ogs_error("No GTP TEID");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (rsp->bearer_contexts_created.presence == 0) {
ogs_error("No Bearer");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (rsp->bearer_contexts_created.eps_bearer_id.presence == 0) {
ogs_error("No EPS Bearer ID");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (rsp->bearer_contexts_created.cause.presence == 0) {
ogs_error("No EPS Bearer Cause");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
if (rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence == 0) {
ogs_error("No GTP TEID");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
bearer = sgw_bearer_find_by_sess_ebi(sess,
rsp->bearer_contexts_created.eps_bearer_id.u8);
ogs_assert(bearer);
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
ogs_assert(s1u_tunnel);
s5u_tunnel = sgw_s5u_tunnel_in_bearer(bearer);
ogs_assert(s5u_tunnel);
if (sess) {
bearer = sgw_bearer_find_by_sess_ebi(sess,
rsp->bearer_contexts_created.eps_bearer_id.u8);
ogs_assert(bearer);
s1u_tunnel = sgw_s1u_tunnel_in_bearer(bearer);
ogs_assert(s1u_tunnel);
s5u_tunnel = sgw_s5u_tunnel_in_bearer(bearer);
ogs_assert(s5u_tunnel);
sgw_ue = sess->sgw_ue;
ogs_assert(sgw_ue);
}
if (!bearer) {
ogs_warn("No Context");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
return;
}
/* Receive Control Plane(UL) : PGW-S5C */
pgw_s5c_teid = rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.
@ -162,54 +208,58 @@ void sgw_s5c_handle_delete_session_response(ogs_gtp_xact_t *s5c_xact,
ogs_gtp_xact_t *s11_xact = NULL;
ogs_gtp_delete_session_response_t *rsp = NULL;
ogs_pkbuf_t *pkbuf = NULL;
uint32_t mme_s11_teid;
ogs_gtp_cause_t *cause = NULL;
sgw_ue_t *sgw_ue = NULL;
ogs_assert(sess);
sgw_ue = sess->sgw_ue;
ogs_assert(s5c_xact);
s11_xact = s5c_xact->assoc_xact;
ogs_assert(s11_xact);
ogs_assert(gtp_message);
rsp = &gtp_message->delete_session_response;
ogs_debug("[SGW] Delete Session Response");
rsp = &gtp_message->delete_session_response;
if (rsp->cause.presence == 0) {
ogs_error("No Cause");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_DELETE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_MANDATORY_IE_MISSING);
return;
}
cause = rsp->cause.data;
ogs_assert(cause);
/* Remove a pgw session */
if (sess) {
ogs_debug("[SGW] Delete Session Response");
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
/* backup sgw_s5c_teid in session context */
mme_s11_teid = sgw_ue->mme_s11_teid;
if (sgw_sess_remove(sess) != OGS_OK)
{
ogs_error("Error on PGW session removal");
cause->value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND;
}
} else {
cause->value = OGS_GTP_CAUSE_INVALID_PEER;
ogs_error("Cannot find session");
if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
ogs_warn("No Accept [%d]", cause->value);
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_DELETE_SESSION_RESPONSE_TYPE,
cause->value);
return;
}
if (!sess) {
ogs_warn("No Context");
SEND_ERROR_MESSAGE(s11_xact, sgw_ue,
OGS_GTP_DELETE_SESSION_RESPONSE_TYPE,
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
return;
}
sgw_ue = sess->sgw_ue;
ogs_assert(sgw_ue);
/* Remove a pgw session */
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);
ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]",
sess->sgw_s5c_teid, sess->pgw_s5c_teid);
sgw_sess_remove(sess);
rv = ogs_gtp_xact_commit(s5c_xact);
ogs_assert(rv == OGS_OK);
gtp_message->h.type = OGS_GTP_DELETE_SESSION_RESPONSE_TYPE;
gtp_message->h.teid = mme_s11_teid;
gtp_message->h.teid = sgw_ue->mme_s11_teid;
rv = ogs_gtp_build_msg(&pkbuf, gtp_message);
ogs_assert(rv == OGS_OK);

View File

@ -49,7 +49,6 @@ void sgw_state_operational(ogs_fsm_t *s, sgw_event_t *e)
sgw_ue_t *sgw_ue = NULL;
sgw_sess_t *sess = NULL;
sgw_bearer_t *bearer = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_gtp_node_t *gnode = NULL;
sgw_sm_debug(e);
@ -74,39 +73,6 @@ void sgw_state_operational(ogs_fsm_t *s, sgw_event_t *e)
rv = ogs_gtp_parse_msg(&message, pkbuf);
ogs_assert(rv == OGS_OK);
addr = e->addr;
ogs_assert(addr);
ogs_free(e->addr);
/*
* 5.5.2 in spec 29.274
*
* If a peer's TEID is not available, the TEID field still shall be
* present in the header and its value shall be set to "0" in the
* following messages:
*
* - Create Session Request message on S2a/S2b/S5/S8
*
* - Create Session Request message on S4/S11, if for a given UE,
* the SGSN/MME has not yet obtained the Control TEID of the SGW.
*
* - If a node receives a message and the TEID-C in the GTPv2 header of
* the received message is not known, it shall respond with
* "Context not found" Cause in the corresponding response message
* to the sender, the TEID used in the GTPv2-C header in the response
* message shall be then set to zero.
*
* - If a node receives a request message containing protocol error,
* e.g. Mandatory IE missing, which requires the receiver to reject
* the message as specified in clause 7.7, it shall reject
* the request message. For the response message, the node should
* look up the remote peer's TEID and accordingly set the GTPv2-C
* header TEID and the message cause code. As an implementation
* option, the node may not look up the remote peer's TEID and
* set the GTPv2-C header TEID to zero in the response message.
* However in this case, the cause code shall not be set to
* "Context not found".
*/
if (message.h.teid != 0) {
/* Cause is not "Context not found" */
sgw_ue = sgw_ue_find_by_teid(message.h.teid);
@ -115,20 +81,10 @@ void sgw_state_operational(ogs_fsm_t *s, sgw_event_t *e)
if (sgw_ue) {
gnode = sgw_ue->gnode;
ogs_assert(gnode);
} else {
ogs_assert(e->addr);
gnode = ogs_gtp_node_find_by_addr(
&sgw_self()->mme_s11_list, e->addr);
if (!gnode) {
gnode = ogs_gtp_node_add_by_addr(
&sgw_self()->mme_s11_list, e->addr);
ogs_assert(gnode);
gnode->sock = e->sock;
}
gnode = e->gnode;
ogs_assert(gnode);
}
ogs_free(e->addr);
rv = ogs_gtp_xact_receive(gnode, &message.h, &xact);
if (rv != OGS_OK) {
@ -200,35 +156,6 @@ void sgw_state_operational(ogs_fsm_t *s, sgw_event_t *e)
rv = ogs_gtp_parse_msg(&message, pkbuf);
ogs_assert(rv == OGS_OK);
/*
* 5.5.2 in spec 29.274
*
* If a peer's TEID is not available, the TEID field still shall be
* present in the header and its value shall be set to "0" in the
* following messages:
*
* - Create Session Request message on S2a/S2b/S5/S8
*
* - Create Session Request message on S4/S11, if for a given UE,
* the SGSN/MME has not yet obtained the Control TEID of the SGW.
*
* - If a node receives a message and the TEID-C in the GTPv2 header of
* the received message is not known, it shall respond with
* "Context not found" Cause in the corresponding response message
* to the sender, the TEID used in the GTPv2-C header in the response
* message shall be then set to zero.
*
* - If a node receives a request message containing protocol error,
* e.g. Mandatory IE missing, which requires the receiver to reject
* the message as specified in clause 7.7, it shall reject
* the request message. For the response message, the node should
* look up the remote peer's TEID and accordingly set the GTPv2-C
* header TEID and the message cause code. As an implementation
* option, the node may not look up the remote peer's TEID and
* set the GTPv2-C header TEID to zero in the response message.
* However in this case, the cause code shall not be set to
* "Context not found".
*/
if (message.h.teid != 0) {
sess = sgw_sess_find_by_teid(message.h.teid);
}
@ -236,15 +163,10 @@ void sgw_state_operational(ogs_fsm_t *s, sgw_event_t *e)
if (sess) {
gnode = sess->gnode;
ogs_assert(gnode);
} else {
ogs_assert(e->addr);
gnode = ogs_gtp_node_find_by_addr(
&sgw_self()->pgw_s5c_list, e->addr);
gnode = e->gnode;
ogs_assert(gnode);
}
ogs_free(e->addr);
rv = ogs_gtp_xact_receive(gnode, &message.h, &xact);
if (rv != OGS_OK) {