[DIAM] Enhance Exception Handling in all Rx Callbacks

Add robust error checks and logging to MME, SMF, PCRF, and HSS
Diameter callback functions. Prevent assertion failures by
handling unexpected or late messages gracefully.
This commit is contained in:
Sukchan Lee
2025-08-02 15:13:58 +09:00
parent 4e21cff6e6
commit f23d7a5e95
10 changed files with 5683 additions and 2498 deletions

View File

@@ -34,7 +34,9 @@ extern "C" {
#define OGS_DIAM_AVP_CODE_FRAME_IPV6_PREFIX 97
/* Result-Code AVP */
#define OGS_DIAM_UNABLE_TO_DELIVER 3002
#define OGS_DIAM_UNKNOWN_PEER 3010
#define OGS_DIAM_OUT_OF_SPACE 4002
#define OGS_DIAM_AVP_UNSUPPORTED 5001
#define OGS_DIAM_UNKNOWN_SESSION_ID 5002
#define OGS_DIAM_AUTHORIZATION_REJECTED 5003

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/* Gx Interface, 3GPP TS 29.212 section 4
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@@ -752,6 +752,7 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
smf_sess_t *sess = NULL;
ogs_diam_gx_message_t *gx_message = NULL;
uint32_t req_slot, cc_request_number = 0;
int cleanup_needed = 0;
ogs_debug("[Credit-Control-Answer]");
@@ -773,7 +774,7 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
ogs_assert(ret == 0);
if (!sess_data) {
ogs_error("No Session Data");
return;
goto cleanup;
}
ogs_assert((void *)sess_data == data);
@@ -784,14 +785,15 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
ogs_assert(ret == 0);
if (!avp && req) {
/* Attempt searching for CC-Request-* in original request. Error
* messages (like DIAMETER_UNABLE_TO_DELIVER) crafted internally may not
* have them. */
* messages (like DIAMETER_UNABLE_TO_DELIVER) crafted internally may
* not have them. */
ret = fd_msg_search_avp(req, ogs_diam_gx_cc_request_number, &avp);
ogs_assert(ret == 0);
}
if (!avp) {
ogs_error("no_CC-Request-Number");
ogs_assert_if_reached();
error++;
goto cleanup;
}
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
@@ -801,11 +803,26 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
ogs_debug(" CC-Request-Number[%d]", cc_request_number);
sess = smf_sess_find_by_id(sess_data->sess_id);
ogs_assert(sess_data->xact_data[req_slot].cc_req_no == cc_request_number);
ogs_assert(sess);
if (!sess) {
ogs_error("Cannot find session by ID[%d]", sess_data->sess_id);
error++;
goto cleanup;
}
if (sess_data->xact_data[req_slot].cc_req_no != cc_request_number) {
ogs_error("CC-Request-Number mismatch: expected[%d], got[%d]",
sess_data->xact_data[req_slot].cc_req_no, cc_request_number);
error++;
goto cleanup;
}
/* Allocate message structure */
gx_message = ogs_calloc(1, sizeof(ogs_diam_gx_message_t));
ogs_assert(gx_message);
if (!gx_message) {
ogs_error("Failed to allocate gx_message");
error++;
goto cleanup;
}
/* Set Credit Control Command */
gx_message->cmd_code = OGS_DIAM_GX_CMD_CODE_CREDIT_CONTROL;
@@ -837,6 +854,7 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
} else {
ogs_error("no Result-Code");
error++;
goto cleanup;
}
}
@@ -848,9 +866,22 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
ogs_assert(ret == 0);
ogs_debug(" From '%.*s'",
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
/* Update peer host information */
if (sess_data->peer_host)
ogs_free(sess_data->peer_host);
sess_data->peer_host =
(os0_t)ogs_strndup((char *)hdr->avp_value->os.data,
hdr->avp_value->os.len);
if (!sess_data->peer_host) {
ogs_error("Failed to allocate peer_host");
error++;
goto cleanup;
}
} else {
ogs_error("no_Origin-Host");
error++;
goto cleanup;
}
/* Value of Origin-Realm */
@@ -864,6 +895,7 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
} else {
ogs_error("no_Origin-Realm");
error++;
goto cleanup;
}
/* Value of CC-Request-Type */
@@ -871,14 +903,15 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
ogs_assert(ret == 0);
if (!avp && req) {
/* Attempt searching for CC-Request-* in original request. Error
* messages (like DIAMETER_UNABLE_TO_DELIVER) crafted internally may not
* have them. */
* messages (like DIAMETER_UNABLE_TO_DELIVER) crafted internally may
* not have them. */
ret = fd_msg_search_avp(req, ogs_diam_gx_cc_request_type, &avp);
ogs_assert(ret == 0);
}
if (!avp) {
ogs_error("no_CC-Request-Number");
ogs_error("no_CC-Request-Type");
error++;
goto cleanup;
}
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
@@ -886,9 +919,10 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
if (gx_message->result_code != ER_DIAMETER_SUCCESS) {
ogs_warn("ERROR DIAMETER Result Code(%d)", gx_message->result_code);
goto out;
goto process_message;
}
/* Process QoS Information */
ret = fd_msg_search_avp(*msg, ogs_diam_gx_qos_information, &avp);
ogs_assert(ret == 0);
if (avp) {
@@ -911,6 +945,7 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
}
}
/* Process Default EPS Bearer QoS */
ret = fd_msg_search_avp(*msg, ogs_diam_gx_default_eps_bearer_qos, &avp);
ogs_assert(ret == 0);
if (avp) {
@@ -983,6 +1018,7 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
}
}
/* Process Charging Rule Install */
ret = fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL);
ogs_assert(ret == 0);
while (avp) {
@@ -991,25 +1027,18 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
switch (hdr->avp_code) {
case AC_SESSION_ID:
case AC_ORIGIN_HOST:
if (sess_data->peer_host)
ogs_free(sess_data->peer_host);
sess_data->peer_host =
(os0_t)ogs_strdup((char *)hdr->avp_value->os.data);
ogs_assert(sess_data->peer_host);
break;
case AC_ORIGIN_REALM:
case AC_DESTINATION_REALM:
case AC_RESULT_CODE:
case AC_ROUTE_RECORD:
case AC_PROXY_INFO:
case AC_AUTH_APPLICATION_ID:
break;
case OGS_DIAM_GX_AVP_CODE_CC_REQUEST_TYPE:
case OGS_DIAM_GX_AVP_CODE_CC_REQUEST_NUMBER:
case OGS_DIAM_GX_AVP_CODE_SUPPORTED_FEATURES:
break;
case OGS_DIAM_GX_AVP_CODE_QOS_INFORMATION:
case OGS_DIAM_GX_AVP_CODE_DEFAULT_EPS_BEARER_QOS:
/* Already processed above */
break;
case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_INSTALL:
ret = fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &avpch1, NULL);
@@ -1024,13 +1053,19 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
ogs_pcc_rule_t *pcc_rule = NULL;
smf_bearer_t *bearer = NULL;
int num_of_flow = 0;
int decode_error = 0;
pcc_rule = &gx_message->session_data.pcc_rule
[gx_message->session_data.num_of_pcc_rule];
rv = decode_pcc_rule_definition(
pcc_rule, avpch1, &error);
ogs_assert(rv == OGS_OK);
pcc_rule, avpch1, &decode_error);
if (rv != OGS_OK || decode_error) {
ogs_error("decode_pcc_rule_definition() failed");
OGS_PCC_RULE_FREE(pcc_rule);
error++;
break;
}
num_of_flow = pcc_rule->num_of_flow;
@@ -1066,10 +1101,15 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL);
}
out:
if (!error) {
process_message:
/* Send message to application if no critical errors occurred */
if (!error && gx_message) {
e = smf_event_new(SMF_EVT_GX_MESSAGE);
ogs_assert(e);
if (!e) {
ogs_error("Failed to create SMF event");
error++;
goto cleanup;
}
e->sess_id = sess->id;
e->gx_message = gx_message;
@@ -1077,36 +1117,45 @@ out:
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
OGS_SESSION_DATA_FREE(&gx_message->session_data);
ogs_free(gx_message);
ogs_event_free(e);
error++;
goto cleanup;
} else {
ogs_pollset_notify(ogs_app()->pollset);
gx_message = NULL; /* Transfer ownership to event */
}
} else {
}
cleanup:
/* Clean up allocated resources */
if (gx_message) {
OGS_SESSION_DATA_FREE(&gx_message->session_data);
ogs_free(gx_message);
}
/* Free the message */
/* Update statistics */
ogs_assert(pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0);
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_stats_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_stats_self()->stats.avg = (ogs_diam_stats_self()->stats.avg *
ogs_diam_stats_self()->stats.nb_recv + dur) /
(ogs_diam_stats_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_stats_self()->stats.shortest)
if (sess_data) {
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_stats_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_stats_self()->stats.avg =
(ogs_diam_stats_self()->stats.avg *
ogs_diam_stats_self()->stats.nb_recv + dur) /
(ogs_diam_stats_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_stats_self()->stats.shortest)
ogs_diam_stats_self()->stats.shortest = dur;
if (dur > ogs_diam_stats_self()->stats.longest)
ogs_diam_stats_self()->stats.longest = dur;
} else {
ogs_diam_stats_self()->stats.shortest = dur;
if (dur > ogs_diam_stats_self()->stats.longest)
ogs_diam_stats_self()->stats.longest = dur;
} else {
ogs_diam_stats_self()->stats.shortest = dur;
ogs_diam_stats_self()->stats.longest = dur;
ogs_diam_stats_self()->stats.avg = dur;
ogs_diam_stats_self()->stats.avg = dur;
}
}
if (error)
ogs_diam_stats_self()->stats.nb_errs++;
else
@@ -1114,34 +1163,49 @@ out:
ogs_assert(pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0);
/* Display how long it took */
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
/* Display timing information */
if (sess_data) {
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec)
/ 1000);
ogs_debug(" 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 ==
OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST &&
sess_data->cc_request_number <= cc_request_number) {
ogs_debug(" [LAST] 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(smf_gx_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == NULL);
ogs_debug(" 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);
/* Determine if session cleanup is needed */
if (sess_data->cc_request_type ==
OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST &&
sess_data->cc_request_number <= cc_request_number) {
ogs_debug(" [LAST] state_cleanup(): [%s]", sess_data->gx_sid);
cleanup_needed = 1;
}
}
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;
/* Manage session state */
if (sess_data) {
if (cleanup_needed) {
state_cleanup(sess_data, NULL, NULL);
} else {
ogs_debug(" fd_sess_state_store(): [%s]", sess_data->gx_sid);
ret = fd_sess_state_store(smf_gx_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == NULL);
}
}
/* Free the message */
if (*msg) {
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;
}
return;
}
@@ -1194,6 +1258,7 @@ static int smf_gx_rar_cb( struct msg **msg, struct avp *avp,
ogs_assert(ret == 0);
if (!sess_data) {
ogs_error("No Session Data");
error = 1;
goto out;
}
@@ -1201,6 +1266,7 @@ static int smf_gx_rar_cb( struct msg **msg, struct avp *avp,
sess = smf_sess_find_by_id(sess_data->sess_id);
if (!sess) {
ogs_error("No Session ID [%d]", sess_data->sess_id);
error = 1;
goto out;
}
@@ -1267,6 +1333,9 @@ static int smf_gx_rar_cb( struct msg **msg, struct avp *avp,
}
} else {
ogs_error("Overflow: Number of PCCRule");
error = 1;
result_code = OGS_DIAM_GX_DIAMETER_PCC_RULE_EVENT;
goto out;
}
break;
default:
@@ -1290,14 +1359,26 @@ static int smf_gx_rar_cb( struct msg **msg, struct avp *avp,
&gx_message->session_data.pcc_rule
[gx_message->session_data.num_of_pcc_rule];
pcc_rule->name = ogs_strdup(
(char*)hdr->avp_value->os.data);
ogs_assert(pcc_rule->name);
/* Initialize the rule before setting name */
memset(pcc_rule, 0, sizeof(*pcc_rule));
pcc_rule->name = ogs_strndup(
(char*)hdr->avp_value->os.data,
hdr->avp_value->os.len);
if (!pcc_rule->name) {
ogs_error("Failed to allocate PCC rule name");
error = 1;
result_code = OGS_DIAM_GX_DIAMETER_PCC_RULE_EVENT;
goto out;
}
pcc_rule->type = OGS_PCC_RULE_TYPE_REMOVE;
gx_message->session_data.num_of_pcc_rule++;
} else {
ogs_error("Overflow: Number of PCCRule");
error = 1;
result_code = OGS_DIAM_GX_DIAMETER_PCC_RULE_EVENT;
goto out;
}
break;
default:
@@ -1314,20 +1395,27 @@ static int smf_gx_rar_cb( struct msg **msg, struct avp *avp,
fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL);
}
/* Send Gx Event to SMF State Machine */
e = smf_event_new(SMF_EVT_GX_MESSAGE);
ogs_assert(e);
/* Send Gx Event to SMF State Machine only if no error occurred */
if (!error) {
e = smf_event_new(SMF_EVT_GX_MESSAGE);
ogs_assert(e);
e->sess_id = sess->id;
e->gx_message = gx_message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
OGS_SESSION_DATA_FREE(&gx_message->session_data);
ogs_free(gx_message);
ogs_event_free(e);
} else {
ogs_pollset_notify(ogs_app()->pollset);
e->sess_id = sess->id;
e->gx_message = gx_message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
OGS_SESSION_DATA_FREE(&gx_message->session_data);
ogs_free(gx_message);
ogs_event_free(e);
error = 1;
result_code = OGS_DIAM_UNABLE_TO_DELIVER;
goto out;
} else {
ogs_pollset_notify(ogs_app()->pollset);
/* gx_message ownership transferred to event queue */
gx_message = NULL;
}
}
/* Set the Auth-Application-Id AVP */
@@ -1339,7 +1427,7 @@ static int smf_gx_rar_cb( struct msg **msg, struct avp *avp,
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
/* Set the Origin-Host, Origin-Realm, and Result-Code AVPs */
ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
@@ -1362,6 +1450,12 @@ static int smf_gx_rar_cb( struct msg **msg, struct avp *avp,
return 0;
out:
/* Clean up gx_message if it still exists */
if (gx_message) {
OGS_SESSION_DATA_FREE(&gx_message->session_data);
ogs_free(gx_message);
}
if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) {
ret = fd_msg_rescode_set(ans,
(char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1);
@@ -1372,15 +1466,14 @@ out:
}
/* Store this value in the session */
ret = fd_sess_state_store(smf_gx_reg, session, &sess_data);
ogs_assert(sess_data == NULL);
if (sess_data) {
ret = fd_sess_state_store(smf_gx_reg, session, &sess_data);
ogs_assert(sess_data == NULL);
}
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
OGS_SESSION_DATA_FREE(&gx_message->session_data);
ogs_free(gx_message);
return 0;
}

View File

@@ -1,6 +1,7 @@
/* Gy Interface, 3GPP TS 32.299
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Copyright (C) 2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@@ -1003,25 +1004,38 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
ogs_assert(ret == 0);
if (!sess_data) {
ogs_error("No Session Data");
return;
goto cleanup;
}
ogs_assert((void *)sess_data == data);
ogs_debug(" Retrieve its data: [%s]", sess_data->gy_sid);
/* Allocate gy_message early to ensure proper cleanup */
gy_message = ogs_calloc(1, sizeof(ogs_diam_gy_message_t));
if (!gy_message) {
ogs_error("Failed to allocate gy_message");
error++;
goto cleanup;
}
/* Set Credit Control Command */
gy_message->cmd_code = OGS_DIAM_GY_CMD_CODE_CREDIT_CONTROL;
/* Initialize some values */
gy_message->cca.result_code = ER_DIAMETER_SUCCESS;
/* Value of CC-Request-Number */
ret = fd_msg_search_avp(*msg, ogs_diam_gy_cc_request_number, &avp);
ogs_assert(ret == 0);
if (!avp && req) {
/* Attempt searching for CC-Request-* in original request. Error
* messages (like DIAMETER_UNABLE_TO_DELIVER) crafted internally may not
* have them. */
/* Attempt searching for CC-Request-* in original request */
ret = fd_msg_search_avp(req, ogs_diam_gy_cc_request_number, &avp);
ogs_assert(ret == 0);
}
if (!avp) {
ogs_error("no_CC-Request-Number");
ogs_assert_if_reached();
error++;
goto cleanup;
}
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
@@ -1030,18 +1044,19 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
ogs_debug(" CC-Request-Number[%d]", cc_request_number);
ogs_assert(sess_data->xact_data[req_slot].cc_req_no == cc_request_number);
if (sess_data->xact_data[req_slot].cc_req_no != cc_request_number) {
ogs_error("CC-Request-Number mismatch: expected %d, got %d",
sess_data->xact_data[req_slot].cc_req_no, cc_request_number);
error++;
goto cleanup;
}
sess = smf_sess_find_by_id(sess_data->sess_id);
ogs_assert(sess);
gy_message = ogs_calloc(1, sizeof(ogs_diam_gy_message_t));
ogs_assert(gy_message);
/* Set Credit Control Command */
gy_message->cmd_code = OGS_DIAM_GY_CMD_CODE_CREDIT_CONTROL;
/* Initialize some values: */
gy_message->cca.result_code = ER_DIAMETER_SUCCESS;
if (!sess) {
ogs_error("Session not found: %d", sess_data->sess_id);
error++;
goto cleanup;
}
/* Value of Result Code */
ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp);
@@ -1070,6 +1085,7 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
} else {
ogs_error("no Result-Code");
error++;
goto cleanup;
}
}
@@ -1084,6 +1100,7 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
} else {
ogs_error("no_Origin-Host");
error++;
goto cleanup;
}
/* Value of Origin-Realm */
@@ -1097,21 +1114,21 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
} else {
ogs_error("no_Origin-Realm");
error++;
goto cleanup;
}
/* Value of CC-Request-Type */
ret = fd_msg_search_avp(*msg, ogs_diam_gy_cc_request_type, &avp);
ogs_assert(ret == 0);
if (!avp && req) {
/* Attempt searching for CC-Request-* in original request. Error
* messages (like DIAMETER_UNABLE_TO_DELIVER) crafted internally may not
* have them. */
/* Attempt searching for CC-Request-* in original request */
ret = fd_msg_search_avp(req, ogs_diam_gy_cc_request_type, &avp);
ogs_assert(ret == 0);
}
if (!avp) {
ogs_error("no_CC-Request-Number");
ogs_error("no_CC-Request-Type");
error++;
goto cleanup;
}
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
@@ -1119,9 +1136,10 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
if (gy_message->result_code != ER_DIAMETER_SUCCESS) {
ogs_warn("ERROR DIAMETER Result Code(%d)", gy_message->result_code);
goto out;
/* Continue processing even with error result code */
}
/* Parse message AVPs */
ret = fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL);
ogs_assert(ret == 0);
while (avp) {
@@ -1134,7 +1152,11 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
ogs_free(sess_data->peer_host);
sess_data->peer_host =
(os0_t)ogs_strdup((char *)hdr->avp_value->os.data);
ogs_assert(sess_data->peer_host);
if (!sess_data->peer_host) {
ogs_error("Failed to allocate peer_host");
error++;
goto cleanup;
}
break;
case AC_ORIGIN_REALM:
case AC_DESTINATION_REALM:
@@ -1161,8 +1183,10 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
case OGS_DIAM_GY_AVP_CODE_GRANTED_SERVICE_UNIT:
rv = decode_granted_service_unit(
&gy_message->cca.granted, avpch1, &error);
ogs_assert(rv == OGS_OK);
/*TODO: apply gsu */
if (rv != OGS_OK) {
ogs_error("Failed to decode granted service unit");
goto cleanup;
}
break;
case OGS_DIAM_GY_AVP_CODE_VALIDITY_TIME:
gy_message->cca.validity_time = hdr->avp_value->u32;
@@ -1176,7 +1200,10 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
case OGS_DIAM_GY_AVP_CODE_FINAL_UNIT_INDICATION:
rv = decode_final_unit_indication(
&gy_message->cca.final, avpch1, &error);
ogs_assert(rv == OGS_OK);
if (rv != OGS_OK) {
ogs_error("Failed to decode final unit indication");
goto cleanup;
}
break;
default:
ogs_warn("Not supported(%d)", hdr->avp_code);
@@ -1192,10 +1219,14 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL);
}
out:
/* Send event to SMF if no errors */
if (!error) {
e = smf_event_new(SMF_EVT_GY_MESSAGE);
ogs_assert(e);
if (!e) {
ogs_error("Failed to create SMF event");
error++;
goto cleanup;
}
e->sess_id = sess->id;
e->gy_message = gy_message;
@@ -1207,34 +1238,45 @@ out:
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_free(gy_message);
ogs_event_free(e);
error++;
goto cleanup;
} else {
ogs_pollset_notify(ogs_app()->pollset);
/* Transfer ownership of gy_message to event */
gy_message = NULL;
}
} else {
}
cleanup:
/* Free gy_message if it wasn't transferred to event */
if (gy_message) {
ogs_free(gy_message);
}
/* Free the message */
/* Update statistics */
ogs_assert(pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0);
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_stats_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_stats_self()->stats.avg = (ogs_diam_stats_self()->stats.avg *
ogs_diam_stats_self()->stats.nb_recv + dur) /
(ogs_diam_stats_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_stats_self()->stats.shortest)
if (sess_data) {
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_stats_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_stats_self()->stats.avg =
(ogs_diam_stats_self()->stats.avg *
ogs_diam_stats_self()->stats.nb_recv + dur) /
(ogs_diam_stats_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_stats_self()->stats.shortest)
ogs_diam_stats_self()->stats.shortest = dur;
if (dur > ogs_diam_stats_self()->stats.longest)
ogs_diam_stats_self()->stats.longest = dur;
} else {
ogs_diam_stats_self()->stats.shortest = dur;
if (dur > ogs_diam_stats_self()->stats.longest)
ogs_diam_stats_self()->stats.longest = dur;
} else {
ogs_diam_stats_self()->stats.shortest = dur;
ogs_diam_stats_self()->stats.longest = dur;
ogs_diam_stats_self()->stats.avg = dur;
ogs_diam_stats_self()->stats.avg = dur;
}
}
if (error)
ogs_diam_stats_self()->stats.nb_errs++;
else
@@ -1242,36 +1284,40 @@ out:
ogs_assert(pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0);
/* Display how long it took */
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
/* Display timing information */
if (sess_data) {
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_trace("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec)
/ 1000);
ogs_debug(" 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 ==
OGS_DIAM_GY_CC_REQUEST_TYPE_TERMINATION_REQUEST &&
sess_data->cc_request_number <= cc_request_number) {
ogs_debug(" [LAST] state_cleanup(): [%s]", sess_data->gy_sid);
state_cleanup(sess_data, NULL, NULL);
} else {
ogs_debug(" fd_sess_state_store(): [%s]", sess_data->gy_sid);
ret = fd_sess_state_store(smf_gy_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == NULL);
ogs_debug(" 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);
/* Clean up session if termination request */
if (sess_data->cc_request_type ==
OGS_DIAM_GY_CC_REQUEST_TYPE_TERMINATION_REQUEST &&
sess_data->cc_request_number <= cc_request_number) {
ogs_debug(" [LAST] state_cleanup(): [%s]", sess_data->gy_sid);
state_cleanup(sess_data, NULL, NULL);
} else {
ogs_debug(" fd_sess_state_store(): [%s]", sess_data->gy_sid);
ret = fd_sess_state_store(smf_gy_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == NULL);
}
}
/* Free the message */
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;
return;
}
static int smf_gy_fb_cb(struct msg **msg, struct avp *avp,
@@ -1283,7 +1329,7 @@ static int smf_gy_fb_cb(struct msg **msg, struct avp *avp,
return ENOTSUP;
}
static int smf_gy_rar_cb( struct msg **msg, struct avp *avp,
static int smf_gy_rar_cb(struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int rv;
@@ -1292,68 +1338,96 @@ static int smf_gy_rar_cb( struct msg **msg, struct avp *avp,
struct msg *ans;
union avp_value val;
struct sess_state *sess_data = NULL;
smf_event_t *e = NULL;
smf_sess_t *sess = NULL;
ogs_diam_gy_message_t *gy_message = NULL;
uint32_t result_code = OGS_DIAM_UNKNOWN_SESSION_ID;
ogs_assert(msg);
ogs_debug("Re-Auth-Request");
/* Allocate gy_message early for proper cleanup */
gy_message = ogs_calloc(1, sizeof(ogs_diam_gy_message_t));
ogs_assert(gy_message);
if (!gy_message) {
ogs_error("Failed to allocate gy_message");
result_code = OGS_DIAM_OUT_OF_SPACE;
goto error_out;
}
/* Set Credit Control Command */
gy_message->cmd_code = OGS_DIAM_GY_CMD_RE_AUTH;
/* Create answer header */
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
if (ret != 0) {
ogs_error("Failed to create answer message");
result_code = OGS_DIAM_OUT_OF_SPACE;
goto error_out;
}
ans = *msg;
/* Retrieve session state */
ret = fd_sess_state_retrieve(smf_gy_reg, session, &sess_data);
ogs_assert(ret == 0);
if (!sess_data) {
ogs_error("No Session Data");
goto out;
result_code = OGS_DIAM_UNKNOWN_SESSION_ID;
goto error_out;
}
/* Get Session Information */
sess = smf_sess_find_by_id(sess_data->sess_id);
ogs_assert(sess);
if (!sess) {
ogs_error("Session not found: %d", sess_data->sess_id);
result_code = OGS_DIAM_UNKNOWN_SESSION_ID;
goto error_out;
}
/* TODO: parsing of msg into gy_message */
/* Send Gy Event to SMF State Machine */
e = smf_event_new(SMF_EVT_GY_MESSAGE);
ogs_assert(e);
if (!e) {
ogs_error("Failed to create SMF event");
result_code = OGS_DIAM_OUT_OF_SPACE;
goto error_out;
}
e->sess_id = sess->id;
e->gy_message = gy_message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_free(gy_message);
ogs_event_free(e);
result_code = OGS_DIAM_OUT_OF_SPACE;
goto error_out;
} else {
ogs_pollset_notify(ogs_app()->pollset);
/* Transfer ownership of gy_message to event */
gy_message = NULL;
}
/* Set the Auth-Application-Id AVP */
ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp);
ogs_assert(ret == 0);
if (ret != 0) {
ogs_error("Failed to create Auth-Application-Id AVP");
result_code = OGS_DIAM_OUT_OF_SPACE;
goto error_out;
}
val.i32 = OGS_DIAM_GY_APPLICATION_ID;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
/* Set the Origin-Host, Origin-Realm, and Result-Code AVPs */
ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
if (ret != 0) {
ogs_error("Failed to set result code");
result_code = OGS_DIAM_OUT_OF_SPACE;
goto error_out;
}
/* Store this value in the session */
ret = fd_sess_state_store(smf_gy_reg, session, &sess_data);
@@ -1362,7 +1436,11 @@ static int smf_gy_rar_cb( struct msg **msg, struct avp *avp,
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
if (ret != 0) {
ogs_error("Failed to send answer message");
/* Message is already freed by fd_msg_send on error */
return ret;
}
ogs_debug("Re-Auth-Answer");
@@ -1373,7 +1451,13 @@ static int smf_gy_rar_cb( struct msg **msg, struct avp *avp,
return 0;
out:
error_out:
/* Free gy_message if it wasn't transferred to event */
if (gy_message) {
ogs_free(gy_message);
}
/* Set appropriate error result code */
if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) {
ret = fd_msg_rescode_set(ans,
(char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1);
@@ -1383,15 +1467,14 @@ out:
ogs_assert(ret == 0);
}
/* Store this value in the session */
/* Store session state (may be NULL) */
ret = fd_sess_state_store(smf_gy_reg, session, &sess_data);
ogs_assert(sess_data == NULL);
/* Send error response */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_free(gy_message);
return 0;
}

View File

@@ -1,5 +1,5 @@
/* 3GPP TS 29.273 section 9
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@@ -357,7 +357,6 @@ void smf_s6b_send_aar(smf_sess_t *sess, ogs_gtp_xact_t *xact)
static void smf_s6b_aaa_cb(void *data, struct msg **msg)
{
int ret;
struct sess_state *sess_data = NULL;
struct timespec ts;
struct session *session;
@@ -366,7 +365,6 @@ static void smf_s6b_aaa_cb(void *data, struct msg **msg)
unsigned long dur;
int error = 0;
int new;
smf_sess_t *sess = NULL;
smf_event_t *e = NULL;
ogs_diam_s6b_message_t *s6b_message = NULL;
@@ -387,7 +385,7 @@ static void smf_s6b_aaa_cb(void *data, struct msg **msg)
ogs_assert(ret == 0);
if (!sess_data) {
ogs_error("No Session Data");
return;
goto cleanup;
}
ogs_assert((void *)sess_data == data);
@@ -396,9 +394,14 @@ static void smf_s6b_aaa_cb(void *data, struct msg **msg)
sess = sess_data->sess;
ogs_assert(sess);
/* Allocate S6B message structure */
s6b_message = ogs_calloc(1, sizeof(ogs_diam_s6b_message_t));
ogs_assert(s6b_message);
/* Set Session Termination Command */
if (!s6b_message) {
ogs_error("Failed to allocate s6b_message");
goto cleanup;
}
/* Set Authentication Authorization Command */
s6b_message->cmd_code = OGS_DIAM_S6B_CMD_AUTHENTICATION_AUTHORIZATION;
/* Value of Result Code */
@@ -425,7 +428,8 @@ static void smf_s6b_aaa_cb(void *data, struct msg **msg)
ret = fd_msg_avp_hdr(avpch1, &hdr);
ogs_assert(ret == 0);
s6b_message->result_code = hdr->avp_value->i32;
ogs_error("Experimental Result Code: %d", s6b_message->result_code);
ogs_error("Experimental Result Code: %d",
s6b_message->result_code);
}
} else {
ogs_error("no Result-Code");
@@ -458,34 +462,52 @@ static void smf_s6b_aaa_cb(void *data, struct msg **msg)
error++;
}
/* Create and queue the event */
e = smf_event_new(SMF_EVT_S6B_MESSAGE);
ogs_assert(e);
if (!e) {
ogs_error("Failed to create SMF event");
goto cleanup;
}
if (error && s6b_message->result_code == ER_DIAMETER_SUCCESS)
s6b_message->result_code = error;
/* Override result code if there were parsing errors */
if (error && s6b_message->result_code == ER_DIAMETER_SUCCESS) {
s6b_message->result_code = error;
}
e->sess_id = sess->id;
e->gtp_xact_id = sess_data->xact_id;
e->s6b_message = s6b_message;
ret = ogs_queue_push(ogs_app()->queue, e);
if (ret != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)ret);
ogs_free(s6b_message);
ogs_event_free(e);
} else {
ogs_pollset_notify(ogs_app()->pollset);
goto cleanup;
}
/* Free the message */
/* Notify the event loop */
ogs_pollset_notify(ogs_app()->pollset);
/* Event successfully queued, clear pointer to avoid double-free */
s6b_message = NULL;
e = NULL;
cleanup:
/* Update statistics and cleanup */
ogs_assert(pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0);
/* Calculate response time */
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_stats_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_stats_self()->stats.avg = (ogs_diam_stats_self()->stats.avg *
ogs_diam_stats_self()->stats.nb_recv + dur) /
/* Update average response time */
ogs_diam_stats_self()->stats.avg =
(ogs_diam_stats_self()->stats.avg *
ogs_diam_stats_self()->stats.nb_recv + dur) /
(ogs_diam_stats_self()->stats.nb_recv + 1);
/* Min, max */
/* Update min/max response times */
if (dur < ogs_diam_stats_self()->stats.shortest)
ogs_diam_stats_self()->stats.shortest = dur;
if (dur > ogs_diam_stats_self()->stats.longest)
@@ -495,27 +517,39 @@ static void smf_s6b_aaa_cb(void *data, struct msg **msg)
ogs_diam_stats_self()->stats.longest = dur;
ogs_diam_stats_self()->stats.avg = dur;
}
if (error)
/* Update error/success counters */
if (error || s6b_message) /* s6b_message != NULL means cleanup case */
ogs_diam_stats_self()->stats.nb_errs++;
else
ogs_diam_stats_self()->stats.nb_recv++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0);
/* Display how long it took */
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_debug("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_debug("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
/* Display response time */
if (sess_data) {
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_debug("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_debug("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec)
/ 1000);
ret = fd_sess_state_store(smf_s6b_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == NULL);
/* Store session state */
ret = fd_sess_state_store(smf_s6b_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == NULL);
}
/* Free allocated memory if not successfully queued */
if (s6b_message) {
ogs_free(s6b_message);
}
/* Free the Diameter message */
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;
@@ -656,7 +690,6 @@ static void smf_s6b_sta_cb(void *data, struct msg **msg)
{
int ret;
int rv;
struct sess_state *sess_data = NULL;
struct timespec ts;
struct session *session;
@@ -665,7 +698,6 @@ static void smf_s6b_sta_cb(void *data, struct msg **msg)
unsigned long dur;
int error = 0;
int new;
smf_event_t *e = NULL;
smf_sess_t *sess = NULL;
ogs_diam_s6b_message_t *s6b_message = NULL;
@@ -686,7 +718,7 @@ static void smf_s6b_sta_cb(void *data, struct msg **msg)
ogs_assert(ret == 0);
if (!sess_data) {
ogs_error("No Session Data");
return;
goto cleanup;
}
ogs_assert((void *)sess_data == data);
@@ -695,8 +727,13 @@ static void smf_s6b_sta_cb(void *data, struct msg **msg)
sess = sess_data->sess;
ogs_assert(sess);
/* Allocate S6B message structure */
s6b_message = ogs_calloc(1, sizeof(ogs_diam_s6b_message_t));
ogs_assert(s6b_message);
if (!s6b_message) {
ogs_error("Failed to allocate s6b_message");
goto cleanup;
}
/* Set Session Termination Command */
s6b_message->cmd_code = OGS_DIAM_S6B_CMD_SESSION_TERMINATION;
@@ -760,64 +797,92 @@ static void smf_s6b_sta_cb(void *data, struct msg **msg)
error++;
}
/* Create and queue the event only if no critical errors */
if (!error) {
e = smf_event_new(SMF_EVT_S6B_MESSAGE);
ogs_assert(e);
if (!e) {
ogs_error("Failed to create SMF event");
goto cleanup;
}
e->sess_id = sess->id;
e->s6b_message = s6b_message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_free(s6b_message);
ogs_event_free(e);
} else {
ogs_pollset_notify(ogs_app()->pollset);
goto cleanup;
}
} else {
ogs_free(s6b_message);
/* Notify the event loop */
ogs_pollset_notify(ogs_app()->pollset);
/* Event successfully queued, clear pointer to avoid double-free */
s6b_message = NULL;
e = NULL;
}
/* Free the message */
cleanup:
/* Update statistics */
ogs_assert(pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0);
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_stats_self()->stats.nb_recv) {
/* Ponderate in the avg */
ogs_diam_stats_self()->stats.avg = (ogs_diam_stats_self()->stats.avg *
ogs_diam_stats_self()->stats.nb_recv + dur) /
(ogs_diam_stats_self()->stats.nb_recv + 1);
/* Min, max */
if (dur < ogs_diam_stats_self()->stats.shortest)
/* Calculate response time */
if (sess_data) {
dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) +
((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
if (ogs_diam_stats_self()->stats.nb_recv) {
/* Update average response time */
ogs_diam_stats_self()->stats.avg =
(ogs_diam_stats_self()->stats.avg *
ogs_diam_stats_self()->stats.nb_recv + dur) /
(ogs_diam_stats_self()->stats.nb_recv + 1);
/* Update min/max response times */
if (dur < ogs_diam_stats_self()->stats.shortest)
ogs_diam_stats_self()->stats.shortest = dur;
if (dur > ogs_diam_stats_self()->stats.longest)
ogs_diam_stats_self()->stats.longest = dur;
} else {
ogs_diam_stats_self()->stats.shortest = dur;
if (dur > ogs_diam_stats_self()->stats.longest)
ogs_diam_stats_self()->stats.longest = dur;
} else {
ogs_diam_stats_self()->stats.shortest = dur;
ogs_diam_stats_self()->stats.longest = dur;
ogs_diam_stats_self()->stats.avg = dur;
ogs_diam_stats_self()->stats.avg = dur;
}
}
if (error)
/* Update error/success counters */
if (error || s6b_message) /* s6b_message != NULL means cleanup case */
ogs_diam_stats_self()->stats.nb_errs++;
else
ogs_diam_stats_self()->stats.nb_recv++;
ogs_assert(pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0);
/* Display how long it took */
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_debug("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_debug("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
/* Display response time */
if (sess_data) {
if (ts.tv_nsec > sess_data->ts.tv_nsec)
ogs_debug("in %d.%06ld sec",
(int)(ts.tv_sec - sess_data->ts.tv_sec),
(long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000);
else
ogs_debug("in %d.%06ld sec",
(int)(ts.tv_sec + 1 - sess_data->ts.tv_sec),
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec)
/ 1000);
ret = fd_sess_state_store(smf_s6b_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == NULL);
/* Store session state */
ret = fd_sess_state_store(smf_s6b_reg, session, &sess_data);
ogs_assert(ret == 0);
ogs_assert(sess_data == NULL);
}
/* Free allocated memory if not successfully queued */
if (s6b_message) {
ogs_free(s6b_message);
}
/* Free the Diameter message */
ret = fd_msg_free(*msg);
ogs_assert(ret == 0);
*msg = NULL;