From 9e3ebf9a1608823ab3e9bb6e8e2de44cbf559d06 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Fri, 14 Jun 2019 14:24:17 +0900 Subject: [PATCH] fix the bug (#195), But more work is needed --- lib/fd/gx/gx-message.h | 6 +- src/mme/s1ap-handler.c | 2 + src/pgw/pgw-fd-path.c | 60 +++++-- src/pgw/pgw-sm.c | 339 ++++++++++++++++++------------------ tests/complex/attach-test.c | 5 +- 5 files changed, 225 insertions(+), 187 deletions(-) diff --git a/lib/fd/gx/gx-message.h b/lib/fd/gx/gx-message.h index 6ede2e63b..be6f1a832 100644 --- a/lib/fd/gx/gx-message.h +++ b/lib/fd/gx/gx-message.h @@ -29,7 +29,7 @@ extern "C" { typedef struct _gx_message_t { #define GX_CMD_CODE_CREDIT_CONTROL 272 #define GX_CMD_RE_AUTH 258 - uint16_t cmd_code; + uint16_t cmd_code; /* Experimental-Result-Codes */ #define GX_DIAMETER_ERROR_LATE_OVERLAPPING_REQUEST 5453 @@ -42,13 +42,13 @@ typedef struct _gx_message_t { #define GX_DIAMETER_ERROR_CONFLICTING_REQUEST 5147 #define GX_DIAMETER_ADC_RULE_EVENT 5148 #define GX_DIAMETER_ERROR_NBIFOM_NOT_AUTHORIZED 5149 - uint32_t result_code; + uint32_t result_code; #define GX_CC_REQUEST_TYPE_INITIAL_REQUEST 1 #define GX_CC_REQUEST_TYPE_UPDATE_REQUEST 2 #define GX_CC_REQUEST_TYPE_TERMINATION_REQUEST 3 #define GX_CC_REQUEST_TYPE_EVENT_REQUEST 4 - uint32_t cc_request_type; + uint32_t cc_request_type; pdn_t pdn; pcc_rule_t pcc_rule[MAX_NUM_OF_PCC_RULE]; diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index bb3ff65af..b5364cb24 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -611,7 +611,9 @@ void s1ap_handle_initial_context_setup_failure( { ogs_debug(" NOT EMM-Registered"); ogs_assert(mme_ue); +#if 0 /* FIXME */ ogs_msleep(300); +#endif rv = mme_send_delete_session_or_ue_context_release(mme_ue, enb_ue); ogs_assert(rv == OGS_OK); } diff --git a/src/pgw/pgw-fd-path.c b/src/pgw/pgw-fd-path.c index 8e91fa901..457eed528 100644 --- a/src/pgw/pgw-fd-path.c +++ b/src/pgw/pgw-fd-path.c @@ -32,9 +32,10 @@ static struct disp_hdl *hdl_gx_rar = NULL; struct sess_state { os0_t gx_sid; /* Gx Session-Id */ +#define MAX_CC_REQUEST_NUMBER 32 pgw_sess_t *sess; - gtp_xact_t *xact; - ogs_pkbuf_t *gtpbuf; + gtp_xact_t *xact[MAX_CC_REQUEST_NUMBER]; + ogs_pkbuf_t *gtpbuf[MAX_CC_REQUEST_NUMBER]; uint32_t cc_request_type; uint32_t cc_request_number; @@ -138,10 +139,19 @@ void pgw_gx_send_ccr(pgw_sess_t *sess, gtp_xact_t *xact, } else ogs_debug(" Retrieve session: [%s]", sess_data->gx_sid); - /* Update session state */ - sess_data->sess = sess; - sess_data->xact = xact; - sess_data->gtpbuf = gtpbuf; + /* + * 8.2. CC-Request-Number AVP + * + * The CC-Request-Number AVP (AVP Code 415) is of type Unsigned32 and + * identifies this request within one session. As Session-Id AVPs are + * globally unique, the combination of Session-Id and CC-Request-Number + * AVPs is also globally unique and can be used in matching credit- + * control messages with confirmations. An easy way to produce unique + * numbers is to set the value to 0 for a credit-control request of type + * INITIAL_REQUEST and EVENT_REQUEST and to set the value to 1 for the + * first UPDATE_REQUEST, to 2 for the second, and so on until the value + * for TERMINATION_REQUEST is one more than for the last UPDATE_REQUEST. + */ sess_data->cc_request_type = cc_request_type; if (cc_request_type == GX_CC_REQUEST_TYPE_INITIAL_REQUEST || @@ -152,6 +162,12 @@ void pgw_gx_send_ccr(pgw_sess_t *sess, gtp_xact_t *xact, ogs_debug(" CC Request Type[%d] Number[%d]", sess_data->cc_request_type, sess_data->cc_request_number); + ogs_assert(sess_data->cc_request_number <= MAX_CC_REQUEST_NUMBER); + + /* Update session state */ + sess_data->sess = sess; + sess_data->xact[sess_data->cc_request_number] = xact; + sess_data->gtpbuf[sess_data->cc_request_number] = gtpbuf; /* Set Origin-Host & Origin-Realm */ ret = fd_msg_add_origin(req, 0); @@ -462,6 +478,7 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) ogs_pkbuf_t *gxbuf = NULL, *gtpbuf = NULL; gx_message_t *gx_message = NULL; uint16_t gxbuf_len = 0; + uint32_t cc_request_number = 0; ogs_debug("[Credit-Control-Answer]"); @@ -482,11 +499,25 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) ogs_debug(" Retrieve its data: [%s]", sess_data->gx_sid); - xact = sess_data->xact; + /* Value of CC-Request-Number */ + ret = fd_msg_search_avp(*msg, gx_cc_request_number, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + cc_request_number = hdr->avp_value->i32; + } else { + ogs_error("no_CC-Request-Number"); + ogs_assert_if_reached(); + } + + ogs_debug(" CC-Request-Number[%d]", cc_request_number); + + xact = sess_data->xact[cc_request_number]; ogs_assert(xact); sess = sess_data->sess; ogs_assert(sess); - gtpbuf = sess_data->gtpbuf; + gtpbuf = sess_data->gtpbuf[cc_request_number]; ogs_assert(gtpbuf); gxbuf_len = sizeof(gx_message_t); @@ -558,6 +589,7 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) goto out; } + /* Value of CC-Request-Type */ ret = fd_msg_search_avp(*msg, gx_cc_request_type, &avp); ogs_assert(ret == 0); if (avp) { @@ -748,14 +780,18 @@ out: (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); - if (sess_data->cc_request_type != GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { + ogs_debug(" [LAST] CC-Request-Type[%d] Number[%d] in Session Data", + sess_data->cc_request_type, sess_data->cc_request_number); + ogs_debug(" Current CC-Request-Number[%d]", cc_request_number); + if (sess_data->cc_request_type == GX_CC_REQUEST_TYPE_TERMINATION_REQUEST && + sess_data->cc_request_number <= cc_request_number) { + ogs_debug(" state_cleanup(): [%s]", sess_data->gx_sid); + state_cleanup(sess_data, NULL, NULL); + } else { ogs_debug(" fd_sess_state_store(): [%s]", sess_data->gx_sid); ret = fd_sess_state_store(pgw_gx_reg, session, &sess_data); ogs_assert(ret == 0); ogs_assert(sess_data == NULL); - } else { - ogs_debug(" state_cleanup(): [%s]", sess_data->gx_sid); - state_cleanup(sess_data, NULL, NULL); } ret = fd_msg_free(*msg); diff --git a/src/pgw/pgw-sm.c b/src/pgw/pgw-sm.c index a1932c118..f104adc81 100644 --- a/src/pgw/pgw-sm.c +++ b/src/pgw/pgw-sm.c @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * 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 . + */ + #include "gtp/gtp-node.h" #include "fd/fd-lib.h" #include "fd/gx/gx-message.h" @@ -34,193 +53,173 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e) ogs_assert(s); - switch (e->id) + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + rv = pgw_gtp_open(); + if (rv != OGS_OK) + ogs_fatal("Can't establish PGW path"); + break; + case OGS_FSM_EXIT_SIG: + pgw_gtp_close(); + break; + case PGW_EVT_S5C_MESSAGE: { - case OGS_FSM_ENTRY_SIG: - { - rv = pgw_gtp_open(); - if (rv != OGS_OK) - { - ogs_error("Can't establish PGW path"); - break; - } - break; + int rv; + ogs_pkbuf_t *recvbuf = NULL; + ogs_pkbuf_t *copybuf = NULL; + uint16_t copybuf_len = 0; + gtp_xact_t *xact = NULL; + gtp_message_t *message = NULL; + pgw_sess_t *sess = NULL; + + ogs_assert(e); + recvbuf = e->gtpbuf; + ogs_assert(recvbuf); + + copybuf_len = sizeof(gtp_message_t); + copybuf = ogs_pkbuf_alloc(NULL, copybuf_len); + ogs_pkbuf_put(copybuf, copybuf_len); + message = copybuf->data; + ogs_assert(message); + + rv = gtp_parse_msg(message, recvbuf); + ogs_assert(rv == OGS_OK); + + if (message->h.teid == 0) { + gtp_node_t *sgw = pgw_sgw_add_by_message(message); + ogs_assert(sgw); + sess = pgw_sess_add_by_message(message); + SETUP_GTP_NODE(sess, sgw); + } else { + sess = pgw_sess_find_by_teid(message->h.teid); } - case OGS_FSM_EXIT_SIG: - { - pgw_gtp_close(); - break; - } - case PGW_EVT_S5C_MESSAGE: - { - int rv; - ogs_pkbuf_t *recvbuf = NULL; - ogs_pkbuf_t *copybuf = NULL; - uint16_t copybuf_len = 0; - gtp_xact_t *xact = NULL; - gtp_message_t *message = NULL; - pgw_sess_t *sess = NULL; + ogs_assert(sess); - ogs_assert(e); - recvbuf = e->gtpbuf; - ogs_assert(recvbuf); - - copybuf_len = sizeof(gtp_message_t); - copybuf = ogs_pkbuf_alloc(NULL, copybuf_len); - ogs_pkbuf_put(copybuf, copybuf_len); - message = copybuf->data; - ogs_assert(message); - - rv = gtp_parse_msg(message, recvbuf); - ogs_assert(rv == OGS_OK); - - if (message->h.teid == 0) - { - gtp_node_t *sgw = pgw_sgw_add_by_message(message); - ogs_assert(sgw); - sess = pgw_sess_add_by_message(message); - SETUP_GTP_NODE(sess, sgw); - } - else - { - sess = pgw_sess_find_by_teid(message->h.teid); - } - ogs_assert(sess); - - rv = gtp_xact_receive(sess->gnode, &message->h, &xact); - if (rv != OGS_OK) - { - ogs_pkbuf_free(recvbuf); - ogs_pkbuf_free(copybuf); - break; - } - - switch(message->h.type) - { - case GTP_CREATE_SESSION_REQUEST_TYPE: - pgw_s5c_handle_create_session_request( - sess, xact, &message->create_session_request); - pgw_gx_send_ccr(sess, xact, copybuf, - GX_CC_REQUEST_TYPE_INITIAL_REQUEST); - break; - case GTP_DELETE_SESSION_REQUEST_TYPE: - pgw_s5c_handle_delete_session_request( - sess, xact, &message->delete_session_request); - pgw_gx_send_ccr(sess, xact, copybuf, - GX_CC_REQUEST_TYPE_TERMINATION_REQUEST); - break; - case GTP_CREATE_BEARER_RESPONSE_TYPE: - pgw_s5c_handle_create_bearer_response( - sess, xact, &message->create_bearer_response); - ogs_pkbuf_free(copybuf); - break; - case GTP_UPDATE_BEARER_RESPONSE_TYPE: - pgw_s5c_handle_update_bearer_response( - sess, xact, &message->update_bearer_response); - ogs_pkbuf_free(copybuf); - break; - case GTP_DELETE_BEARER_RESPONSE_TYPE: - pgw_s5c_handle_delete_bearer_response( - sess, xact, &message->delete_bearer_response); - ogs_pkbuf_free(copybuf); - break; - default: - ogs_warn("Not implmeneted(type:%d)", message->h.type); - ogs_pkbuf_free(copybuf); - break; - } + rv = gtp_xact_receive(sess->gnode, &message->h, &xact); + if (rv != OGS_OK) { ogs_pkbuf_free(recvbuf); + ogs_pkbuf_free(copybuf); break; } - case PGW_EVT_GX_MESSAGE: + + switch(message->h.type) { + case GTP_CREATE_SESSION_REQUEST_TYPE: + pgw_s5c_handle_create_session_request( + sess, xact, &message->create_session_request); + pgw_gx_send_ccr(sess, xact, copybuf, + GX_CC_REQUEST_TYPE_INITIAL_REQUEST); + break; + case GTP_DELETE_SESSION_REQUEST_TYPE: + pgw_s5c_handle_delete_session_request( + sess, xact, &message->delete_session_request); + pgw_gx_send_ccr(sess, xact, copybuf, + GX_CC_REQUEST_TYPE_TERMINATION_REQUEST); + break; + case GTP_CREATE_BEARER_RESPONSE_TYPE: + pgw_s5c_handle_create_bearer_response( + sess, xact, &message->create_bearer_response); + ogs_pkbuf_free(copybuf); + break; + case GTP_UPDATE_BEARER_RESPONSE_TYPE: + pgw_s5c_handle_update_bearer_response( + sess, xact, &message->update_bearer_response); + ogs_pkbuf_free(copybuf); + break; + case GTP_DELETE_BEARER_RESPONSE_TYPE: + pgw_s5c_handle_delete_bearer_response( + sess, xact, &message->delete_bearer_response); + ogs_pkbuf_free(copybuf); + break; + default: + ogs_warn("Not implmeneted(type:%d)", message->h.type); + ogs_pkbuf_free(copybuf); + break; + } + ogs_pkbuf_free(recvbuf); + break; + } + case PGW_EVT_GX_MESSAGE: + { + ogs_index_t sess_index; + pgw_sess_t *sess = NULL; + ogs_pkbuf_t *gxbuf = NULL; + gx_message_t *gx_message = NULL; + + ogs_assert(e); + + gxbuf = e->gxbuf; + ogs_assert(gxbuf); + gx_message = gxbuf->data; + ogs_assert(gx_message); + + sess_index = e->sess_index; + ogs_assert(sess_index); + sess = pgw_sess_find(sess_index); + + switch(gx_message->cmd_code) { + case GX_CMD_CODE_CREDIT_CONTROL: { - ogs_index_t sess_index; - pgw_sess_t *sess = NULL; - ogs_pkbuf_t *gxbuf = NULL; - gx_message_t *gx_message = NULL; + uint32_t xact_index; + gtp_xact_t *xact = NULL; - ogs_assert(e); - sess_index = e->sess_index; - ogs_assert(sess_index); - sess = pgw_sess_find(sess_index); - ogs_assert(sess); + ogs_pkbuf_t *gtpbuf = NULL; + gtp_message_t *message = NULL; - gxbuf = e->gxbuf; - ogs_assert(gxbuf); - gx_message = gxbuf->data; - ogs_assert(gx_message); + xact_index = e->xact_index; + ogs_assert(xact_index); + xact = gtp_xact_find(xact_index); + ogs_assert(xact); - switch(gx_message->cmd_code) - { - case GX_CMD_CODE_CREDIT_CONTROL: - { - uint32_t xact_index; - gtp_xact_t *xact = NULL; + gtpbuf = e->gtpbuf; + ogs_assert(gtpbuf); + message = gtpbuf->data; - ogs_pkbuf_t *gtpbuf = NULL; - gtp_message_t *message = NULL; - - xact_index = e->xact_index; - ogs_assert(xact_index); - xact = gtp_xact_find(xact_index); - ogs_assert(xact); - - gtpbuf = e->gtpbuf; - ogs_assert(gtpbuf); - message = gtpbuf->data; - - if (gx_message->result_code != ER_DIAMETER_SUCCESS) - { - ogs_error("Diameter Error(%d)", gx_message->result_code); - break; - } - switch(gx_message->cc_request_type) - { - case GX_CC_REQUEST_TYPE_INITIAL_REQUEST: - { - pgw_gx_handle_cca_initial_request( - sess, gx_message, xact, - &message->create_session_request); - break; - } - case GX_CC_REQUEST_TYPE_TERMINATION_REQUEST: - { - pgw_gx_handle_cca_termination_request( - sess, gx_message, xact, - &message->delete_session_request); - break; - } - default: - { - ogs_error("Not implemented(%d)", - gx_message->cc_request_type); - break; - } - } - - ogs_pkbuf_free(gtpbuf); - break; - } - case GX_CMD_RE_AUTH: - { - pgw_gx_handle_re_auth_request(sess, gx_message); - break; - } - default: - { - ogs_error("Invalid type(%d)", gx_message->cmd_code); - break; - } + if (!sess) { + ogs_error("No Session"); + ogs_pkbuf_free(gtpbuf); + break; } - gx_message_free(gx_message); - ogs_pkbuf_free(gxbuf); + if (gx_message->result_code != ER_DIAMETER_SUCCESS) { + ogs_error("Diameter Error(%d)", gx_message->result_code); + ogs_pkbuf_free(gtpbuf); + break; + } + + switch(gx_message->cc_request_type) { + case GX_CC_REQUEST_TYPE_INITIAL_REQUEST: + pgw_gx_handle_cca_initial_request( + sess, gx_message, xact, + &message->create_session_request); + break; + case GX_CC_REQUEST_TYPE_TERMINATION_REQUEST: + pgw_gx_handle_cca_termination_request( + sess, gx_message, xact, + &message->delete_session_request); + break; + default: + ogs_error("Not implemented(%d)", + gx_message->cc_request_type); + break; + } + + ogs_pkbuf_free(gtpbuf); break; } + case GX_CMD_RE_AUTH: + pgw_gx_handle_re_auth_request(sess, gx_message); + break; default: - { - ogs_error("No handler for event %s", pgw_event_get_name(e)); + ogs_error("Invalid type(%d)", gx_message->cmd_code); break; } + + gx_message_free(gx_message); + ogs_pkbuf_free(gxbuf); + break; + } + default: + ogs_error("No handler for event %s", pgw_event_get_name(e)); + break; } } diff --git a/tests/complex/attach-test.c b/tests/complex/attach-test.c index ec508bf2f..9597c50b9 100644 --- a/tests/complex/attach-test.c +++ b/tests/complex/attach-test.c @@ -1872,14 +1872,15 @@ abts_suite *test_attach(abts_suite *suite) { suite = ADD_SUITE(suite) -#if 0 +#if 1 abts_run_test(suite, attach_test1, NULL); abts_run_test(suite, attach_test2, NULL); abts_run_test(suite, attach_test3, NULL); abts_run_test(suite, attach_test4, NULL); abts_run_test(suite, attach_test5, NULL); -#endif +#else abts_run_test(suite, attach_test6, NULL); +#endif return suite; }