mirror of
https://github.com/open5gs/open5gs.git
synced 2025-10-23 07:41:57 +00:00
[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:
@@ -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
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -109,151 +109,208 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp,
|
||||
{
|
||||
int rv;
|
||||
int ret;
|
||||
|
||||
struct msg *ans, *qry;
|
||||
struct avp *avpch1, *avpch2, *avpch3;
|
||||
struct avp_hdr *hdr;
|
||||
struct msg *ans = NULL, *qry = NULL;
|
||||
struct avp *avpch1 = NULL, *avpch2 = NULL, *avpch3 = NULL;
|
||||
struct avp_hdr *hdr = NULL;
|
||||
union avp_value val;
|
||||
struct sess_state *sess_data = NULL;
|
||||
size_t sidlen;
|
||||
|
||||
ogs_diam_rx_message_t rx_message;
|
||||
ogs_media_component_t *media_component = NULL;
|
||||
ogs_media_sub_component_t *sub = NULL;
|
||||
ogs_flow_t *flow = NULL;
|
||||
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
os0_t gx_sid = NULL;
|
||||
uint32_t result_code = OGS_DIAM_RX_DIAMETER_IP_CAN_SESSION_NOT_AVAILABLE;
|
||||
int error_occurred = 0;
|
||||
|
||||
ogs_debug("[PCRF] Rx AA-Request");
|
||||
|
||||
ogs_assert(msg);
|
||||
ogs_assert(sess);
|
||||
|
||||
ret = fd_sess_state_retrieve(pcrf_rx_reg, sess, &sess_data);
|
||||
ogs_assert(ret == 0);
|
||||
if (!sess_data) {
|
||||
os0_t sid = NULL;
|
||||
ret = fd_sess_getsid(sess, &sid, &sidlen);
|
||||
ogs_assert(ret == 0);
|
||||
|
||||
sess_data = new_state(sid);
|
||||
ogs_assert(sess_data);
|
||||
/* Validate input parameters */
|
||||
if (!msg || !*msg || !sess) {
|
||||
ogs_error("Invalid input parameters");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize Message */
|
||||
memset(&rx_message, 0, sizeof(ogs_diam_rx_message_t));
|
||||
rx_message.cmd_code = OGS_DIAM_RX_CMD_CODE_AA;
|
||||
|
||||
/* Retrieve session state */
|
||||
ret = fd_sess_state_retrieve(pcrf_rx_reg, sess, &sess_data);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to retrieve session state");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!sess_data) {
|
||||
os0_t sid = NULL;
|
||||
ret = fd_sess_getsid(sess, &sid, &sidlen);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to get session ID");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sess_data = new_state(sid);
|
||||
if (!sess_data) {
|
||||
ogs_error("Failed to create new session state");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create answer header */
|
||||
qry = *msg;
|
||||
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");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
ans = *msg;
|
||||
|
||||
/* 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");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
val.i32 = OGS_DIAM_RX_APPLICATION_ID;
|
||||
ret = fd_msg_avp_setvalue(avp, &val);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to set Auth-Application-Id value");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to add Auth-Application-Id AVP");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set the Auth-Request-Type AVP */
|
||||
ret = fd_msg_avp_new(ogs_diam_auth_request_type, 0, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to create Auth-Request-Type AVP");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
val.i32 = OGS_DIAM_AUTH_REQUEST_TYPE_AUTHENTICATE_ONLY;
|
||||
ret = fd_msg_avp_setvalue(avp, &val);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to set Auth-Request-Type value");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to add Auth-Request-Type AVP");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get Framed-IP-Address */
|
||||
ret = fd_msg_search_avp(qry, ogs_diam_rx_framed_ip_address, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (avp) {
|
||||
if (ret == 0 && avp) {
|
||||
ret = fd_msg_avp_hdr(avp, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0 && hdr) {
|
||||
gx_sid = (os0_t)pcrf_sess_find_by_ipv4(hdr->avp_value->os.data);
|
||||
if (!gx_sid) {
|
||||
ogs_warn("Cannot find Gx Sesson for IPv4:%s",
|
||||
ogs_warn("Cannot find Gx Session for IPv4:%s",
|
||||
OGS_INET_NTOP(hdr->avp_value->os.data, buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gx_sid) {
|
||||
/* Get Framed-IPv6-Prefix */
|
||||
ret = fd_msg_search_avp(qry, ogs_diam_rx_framed_ipv6_prefix, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (avp) {
|
||||
if (ret == 0 && avp) {
|
||||
ogs_paa_t *paa = NULL;
|
||||
|
||||
ret = fd_msg_avp_hdr(avp, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0 && hdr) {
|
||||
paa = (ogs_paa_t *)hdr->avp_value->os.data;
|
||||
ogs_assert(paa);
|
||||
ogs_assert(paa->len == OGS_IPV6_LEN * 8 /* 128bit */);
|
||||
if (paa && paa->len == OGS_IPV6_LEN * 8) {
|
||||
gx_sid = (os0_t)pcrf_sess_find_by_ipv6(paa->addr6);
|
||||
if (!gx_sid) {
|
||||
ogs_warn("Cannot find Gx Sesson for IPv6:%s",
|
||||
ogs_warn("Cannot find Gx Session for IPv6:%s",
|
||||
OGS_INET6_NTOP(hdr->avp_value->os.data, buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gx_sid) {
|
||||
ogs_error("No Gx Session");
|
||||
ogs_error("No Gx Session found");
|
||||
result_code = OGS_DIAM_RX_DIAMETER_IP_CAN_SESSION_NOT_AVAILABLE;
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Parse AVPs - with error checking for each browse operation */
|
||||
ret = fd_msg_browse(qry, MSG_BRW_FIRST_CHILD, &avpch1, NULL);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to browse message");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (avpch1) {
|
||||
ret = fd_msg_avp_hdr(avpch1, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to get AVP header");
|
||||
fd_msg_browse(avpch1, MSG_BRW_NEXT, &avpch1, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(hdr->avp_code) {
|
||||
case AC_SESSION_ID:
|
||||
case AC_ORIGIN_HOST:
|
||||
if (sess_data->peer_host)
|
||||
if (sess_data->peer_host) {
|
||||
ogs_free(sess_data->peer_host);
|
||||
sess_data->peer_host = NULL;
|
||||
}
|
||||
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 duplicate peer host");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case AC_ORIGIN_REALM:
|
||||
case AC_DESTINATION_REALM:
|
||||
case AC_ROUTE_RECORD:
|
||||
case AC_PROXY_INFO:
|
||||
case AC_AUTH_APPLICATION_ID:
|
||||
case OGS_DIAM_AVP_CODE_FRAME_IP_ADDRESS:
|
||||
case OGS_DIAM_AVP_CODE_FRAME_IPV6_PREFIX:
|
||||
case OGS_DIAM_RX_AVP_CODE_SUBSCRIPTION_ID:
|
||||
break;
|
||||
/* Gwt Specific-Action */
|
||||
case OGS_DIAM_RX_AVP_CODE_SPECIFIC_ACTION:
|
||||
break;
|
||||
/* Gwt Media-Component-Description */
|
||||
|
||||
case OGS_DIAM_RX_AVP_CODE_MEDIA_COMPONENT_DESCRIPTION:
|
||||
if (rx_message.ims_data.num_of_media_component >=
|
||||
OGS_ARRAY_SIZE(rx_message.ims_data.media_component)) {
|
||||
ogs_error("OVERFLOW rx_message.ims_data.num_of_media_component"
|
||||
"[%d:%d:%d]",
|
||||
rx_message.ims_data.num_of_media_component,
|
||||
OGS_MAX_NUM_OF_MEDIA_COMPONENT,
|
||||
" [%d:%d]", rx_message.ims_data.num_of_media_component,
|
||||
(int)OGS_ARRAY_SIZE(
|
||||
rx_message.ims_data.media_component));
|
||||
break;
|
||||
}
|
||||
|
||||
media_component = &rx_message.ims_data.
|
||||
media_component[rx_message.ims_data.num_of_media_component];
|
||||
|
||||
ret = fd_msg_browse(avpch1, MSG_BRW_FIRST_CHILD, &avpch2, NULL);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to browse media component");
|
||||
break;
|
||||
}
|
||||
|
||||
while (avpch2) {
|
||||
ret = fd_msg_avp_hdr(avpch2, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
fd_msg_browse(avpch2, MSG_BRW_NEXT, &avpch2, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (hdr->avp_code) {
|
||||
case OGS_DIAM_RX_AVP_CODE_MEDIA_COMPONENT_NUMBER:
|
||||
media_component->media_component_number =
|
||||
@@ -287,24 +344,32 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp,
|
||||
case OGS_DIAM_RX_AVP_CODE_FLOW_STATUS:
|
||||
media_component->flow_status = hdr->avp_value->i32;
|
||||
break;
|
||||
|
||||
case OGS_DIAM_RX_AVP_CODE_MEDIA_SUB_COMPONENT:
|
||||
if (media_component->num_of_sub >=
|
||||
OGS_ARRAY_SIZE(media_component->sub)) {
|
||||
ogs_error("OVERFLOW media_component->num_of_sub "
|
||||
"[%d:%d:%d]",
|
||||
ogs_error("OVERFLOW media_component->num_of_sub [%d:%d]",
|
||||
media_component->num_of_sub,
|
||||
OGS_MAX_NUM_OF_MEDIA_SUB_COMPONENT,
|
||||
(int)OGS_ARRAY_SIZE(media_component->sub));
|
||||
break;
|
||||
}
|
||||
|
||||
sub = &media_component->sub[media_component->num_of_sub];
|
||||
|
||||
ret = fd_msg_browse(avpch2, MSG_BRW_FIRST_CHILD,
|
||||
&avpch3, NULL);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to browse sub component");
|
||||
break;
|
||||
}
|
||||
|
||||
while (avpch3) {
|
||||
ret = fd_msg_avp_hdr(avpch3, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
fd_msg_browse(avpch3, MSG_BRW_NEXT, &avpch3, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (hdr->avp_code) {
|
||||
case OGS_DIAM_RX_AVP_CODE_FLOW_NUMBER:
|
||||
sub->flow_number = hdr->avp_value->i32;
|
||||
@@ -326,23 +391,26 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp,
|
||||
}
|
||||
break;
|
||||
case OGS_DIAM_RX_AVP_CODE_FLOW_DESCRIPTION:
|
||||
if (sub->num_of_flow >= OGS_ARRAY_SIZE(sub->flow)) {
|
||||
ogs_error(
|
||||
"OVERFLOW sub->num_of_flow [%d:%d:%d]",
|
||||
if (sub->num_of_flow >=
|
||||
OGS_ARRAY_SIZE(sub->flow)) {
|
||||
ogs_error("OVERFLOW sub->num_of_flow [%d:%d]",
|
||||
sub->num_of_flow,
|
||||
OGS_MAX_NUM_OF_FLOW_IN_MEDIA_SUB_COMPONENT,
|
||||
(int)OGS_ARRAY_SIZE(sub->flow));
|
||||
break;
|
||||
}
|
||||
|
||||
flow = &sub->flow[sub->num_of_flow];
|
||||
flow->description = ogs_strndup(
|
||||
(char*)hdr->avp_value->os.data,
|
||||
hdr->avp_value->os.len);
|
||||
ogs_assert(flow->description);
|
||||
if (!flow->description) {
|
||||
ogs_error("Failed to duplicate flow description");
|
||||
break;
|
||||
}
|
||||
sub->num_of_flow++;
|
||||
break;
|
||||
default:
|
||||
ogs_error("Not supported(%d)",
|
||||
ogs_warn("Not supported AVP code(%d)",
|
||||
hdr->avp_code);
|
||||
break;
|
||||
}
|
||||
@@ -352,7 +420,7 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp,
|
||||
media_component->num_of_sub++;
|
||||
break;
|
||||
default:
|
||||
ogs_warn("Not supported(%d)", hdr->avp_code);
|
||||
ogs_warn("Not supported AVP code(%d)", hdr->avp_code);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -361,62 +429,100 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp,
|
||||
|
||||
rx_message.ims_data.num_of_media_component++;
|
||||
break;
|
||||
|
||||
case AC_ORIGIN_REALM:
|
||||
case AC_DESTINATION_REALM:
|
||||
case AC_ROUTE_RECORD:
|
||||
case AC_PROXY_INFO:
|
||||
case AC_AUTH_APPLICATION_ID:
|
||||
case OGS_DIAM_AVP_CODE_FRAME_IP_ADDRESS:
|
||||
case OGS_DIAM_AVP_CODE_FRAME_IPV6_PREFIX:
|
||||
case OGS_DIAM_RX_AVP_CODE_SUBSCRIPTION_ID:
|
||||
case OGS_DIAM_RX_AVP_CODE_SPECIFIC_ACTION:
|
||||
break;
|
||||
default:
|
||||
ogs_warn("Not supported(%d)", hdr->avp_code);
|
||||
ogs_warn("Not supported AVP code(%d)", hdr->avp_code);
|
||||
break;
|
||||
}
|
||||
fd_msg_browse(avpch1, MSG_BRW_NEXT, &avpch1, NULL);
|
||||
}
|
||||
|
||||
if (!error_occurred) {
|
||||
/* Send Re-Auth Request */
|
||||
rv = pcrf_gx_send_rar(gx_sid, sess_data->rx_sid, &rx_message);
|
||||
if (rv != OGS_OK) {
|
||||
result_code = rx_message.result_code;
|
||||
if (result_code != ER_DIAMETER_SUCCESS) {
|
||||
ogs_error("pcrf_gx_send_rar() failed");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store Gx Session-Id in this session */
|
||||
if (!sess_data->gx_sid)
|
||||
if (!sess_data->gx_sid) {
|
||||
sess_data->gx_sid = (os0_t)ogs_strdup((char *)gx_sid);
|
||||
ogs_assert(sess_data->gx_sid);
|
||||
if (!sess_data->gx_sid) {
|
||||
ogs_error("Failed to duplicate gx_sid");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set IP-Can-Type */
|
||||
ret = fd_msg_avp_new(ogs_diam_rx_ip_can_type, 0, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0) {
|
||||
val.i32 = OGS_DIAM_RX_IP_CAN_TYPE_3GPP_EPS;
|
||||
ret = fd_msg_avp_setvalue(avp, &val);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0) {
|
||||
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
|
||||
ogs_assert(ret == 0);
|
||||
}
|
||||
}
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to add IP-Can-Type AVP");
|
||||
}
|
||||
|
||||
/* Set RAT-Type */
|
||||
ret = fd_msg_avp_new(ogs_diam_rat_type, 0, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0) {
|
||||
val.i32 = OGS_DIAM_RAT_TYPE_EUTRAN;
|
||||
ret = fd_msg_avp_setvalue(avp, &val);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0) {
|
||||
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
|
||||
ogs_assert(ret == 0);
|
||||
}
|
||||
}
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to add RAT-Type AVP");
|
||||
}
|
||||
|
||||
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
|
||||
/* Set success result code */
|
||||
ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to set success result code");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Store this value in the session */
|
||||
/* Store session state */
|
||||
ret = fd_sess_state_store(pcrf_rx_reg, sess, &sess_data);
|
||||
ogs_assert(ret == 0);
|
||||
ogs_assert(sess_data == NULL);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to store session state");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
sess_data = NULL; /* Ownership transferred */
|
||||
|
||||
/* Send the answer */
|
||||
ret = fd_msg_send(msg, NULL, NULL);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to send message");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ogs_debug("[PCRF] Tx AA-Answer");
|
||||
|
||||
/* Add this value to the stats */
|
||||
/* Add to stats */
|
||||
OGS_DIAM_STATS_MTX(
|
||||
OGS_DIAM_STATS_INC(nb_echoed);
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.rx_aar);
|
||||
@@ -424,36 +530,47 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp,
|
||||
)
|
||||
|
||||
ogs_ims_data_free(&rx_message.ims_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
out:
|
||||
/* Error handling */
|
||||
if (ans) {
|
||||
if (result_code == OGS_DIAM_AVP_UNSUPPORTED) {
|
||||
ret = fd_msg_rescode_set(ans,
|
||||
(char *)"DIAMETER_AVP_UNSUPPORTED", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
} else if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) {
|
||||
ret = fd_msg_rescode_set(ans,
|
||||
(char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
} else if (result_code == OGS_DIAM_MISSING_AVP) {
|
||||
ret = fd_msg_rescode_set(ans,
|
||||
(char *)"DIAMETER_MISSING_AVP", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
} else {
|
||||
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
|
||||
ogs_assert(ret == 0);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to set error result code");
|
||||
}
|
||||
|
||||
ret = fd_msg_send(msg, NULL, NULL);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to send error response");
|
||||
}
|
||||
}
|
||||
|
||||
/* Update error stats */
|
||||
OGS_DIAM_STATS_MTX(
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.rx_aar);
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.rx_aar_error);
|
||||
)
|
||||
|
||||
/* Cleanup session state if it wasn't stored */
|
||||
if (sess_data) {
|
||||
state_cleanup(sess_data, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Always free IMS data */
|
||||
ogs_ims_data_free(&rx_message.ims_data);
|
||||
|
||||
return 0;
|
||||
@@ -583,81 +700,120 @@ int pcrf_rx_send_asr(uint8_t *rx_sid, uint32_t abort_cause)
|
||||
static void pcrf_rx_asa_cb(void *data, struct msg **msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct session *session;
|
||||
struct avp *avp, *avpch1;
|
||||
struct avp_hdr *hdr;
|
||||
int new;
|
||||
struct session *session = NULL;
|
||||
struct avp *avp = NULL, *avpch1 = NULL;
|
||||
struct avp_hdr *hdr = NULL;
|
||||
int new = 0;
|
||||
int result_code = 0;
|
||||
|
||||
ogs_debug("[PCRF] Rx Abort-Session-Answer");
|
||||
|
||||
/* Validate input parameters */
|
||||
if (!msg || !*msg) {
|
||||
ogs_error("Invalid message pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Search the session, retrieve its data */
|
||||
ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new);
|
||||
ogs_assert(ret == 0);
|
||||
ogs_assert(new == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to get session from message");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (new != 0) {
|
||||
ogs_error("Session should already exist");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Value of Result Code */
|
||||
ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to search Result-Code AVP");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (avp) {
|
||||
ret = fd_msg_avp_hdr(avp, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to get Result-Code AVP header");
|
||||
goto cleanup;
|
||||
}
|
||||
result_code = hdr->avp_value->i32;
|
||||
ogs_debug(" Result Code: %d", hdr->avp_value->i32);
|
||||
ogs_debug(" Result Code: %d", result_code);
|
||||
} else {
|
||||
/* Try experimental result code */
|
||||
ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to search Experimental-Result AVP");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (avp) {
|
||||
ret = fd_avp_search_avp(avp, ogs_diam_experimental_result_code, &avpch1);
|
||||
ogs_assert(ret == 0);
|
||||
ret = fd_avp_search_avp(avp, ogs_diam_experimental_result_code,
|
||||
&avpch1);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to search Experimental-Result-Code AVP");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (avpch1) {
|
||||
ret = fd_msg_avp_hdr(avpch1, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to get Experimental-Result-Code header");
|
||||
goto cleanup;
|
||||
}
|
||||
result_code = hdr->avp_value->i32;
|
||||
ogs_debug(" Experimental Result Code: %d",
|
||||
result_code);
|
||||
ogs_debug(" Experimental Result Code: %d", result_code);
|
||||
}
|
||||
} else {
|
||||
ogs_error("no Result-Code");
|
||||
ogs_error("No Result-Code or Experimental-Result found");
|
||||
result_code = -1; /* Set error indicator */
|
||||
}
|
||||
}
|
||||
|
||||
/* Value of Origin-Host */
|
||||
ret = fd_msg_search_avp(*msg, ogs_diam_origin_host, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (avp) {
|
||||
if (ret == 0 && avp) {
|
||||
ret = fd_msg_avp_hdr(avp, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0 && hdr) {
|
||||
ogs_debug(" From '%.*s'",
|
||||
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
|
||||
}
|
||||
} else {
|
||||
ogs_error("no_Origin-Host ");
|
||||
ogs_warn("No Origin-Host found");
|
||||
}
|
||||
|
||||
/* Value of Origin-Realm */
|
||||
ret = fd_msg_search_avp(*msg, ogs_diam_origin_realm, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (avp) {
|
||||
if (ret == 0 && avp) {
|
||||
ret = fd_msg_avp_hdr(avp, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0 && hdr) {
|
||||
ogs_debug(" ('%.*s')",
|
||||
(int)hdr->avp_value->os.len, hdr->avp_value->os.data);
|
||||
}
|
||||
} else {
|
||||
ogs_error("no_Origin-Realm ");
|
||||
ogs_warn("No Origin-Realm found");
|
||||
}
|
||||
|
||||
if (result_code != ER_DIAMETER_SUCCESS) {
|
||||
ogs_error("ERROR DIAMETER Result Code(%d)", result_code);
|
||||
}
|
||||
|
||||
/* Update statistics */
|
||||
OGS_DIAM_STATS_MTX(
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.rx_asa);
|
||||
)
|
||||
|
||||
cleanup:
|
||||
/* Always free the message */
|
||||
if (msg && *msg) {
|
||||
ret = fd_msg_free(*msg);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to free message");
|
||||
}
|
||||
*msg = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -667,20 +823,21 @@ static int pcrf_rx_str_cb( struct msg **msg, struct avp *avp,
|
||||
{
|
||||
int rv;
|
||||
int ret;
|
||||
|
||||
struct msg *ans, *qry;
|
||||
struct avp_hdr *hdr;
|
||||
struct msg *ans = NULL, *qry = NULL;
|
||||
struct avp_hdr *hdr = NULL;
|
||||
union avp_value val;
|
||||
struct sess_state *sess_data = NULL;
|
||||
|
||||
ogs_diam_rx_message_t rx_message;
|
||||
|
||||
uint32_t result_code = OGS_DIAM_RX_DIAMETER_IP_CAN_SESSION_NOT_AVAILABLE;
|
||||
int error_occurred = 0;
|
||||
|
||||
ogs_debug("[PCRF] Rx Session-Termination-Request");
|
||||
|
||||
ogs_assert(msg);
|
||||
ogs_assert(sess);
|
||||
/* Validate input parameters */
|
||||
if (!msg || !*msg || !sess) {
|
||||
ogs_error("Invalid input parameters");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize Message */
|
||||
memset(&rx_message, 0, sizeof(ogs_diam_rx_message_t));
|
||||
@@ -689,42 +846,86 @@ static int pcrf_rx_str_cb( struct msg **msg, struct avp *avp,
|
||||
/* Create answer header */
|
||||
qry = *msg;
|
||||
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");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
ans = *msg;
|
||||
|
||||
/* 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");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
val.i32 = OGS_DIAM_RX_APPLICATION_ID;
|
||||
ret = fd_msg_avp_setvalue(avp, &val);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to set Auth-Application-Id value");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to add Auth-Application-Id AVP");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set the Auth-Request-Type AVP */
|
||||
ret = fd_msg_avp_new(ogs_diam_auth_request_type, 0, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
val.i32 = OGS_DIAM_AUTH_REQUEST_TYPE_AUTHENTICATE_ONLY;
|
||||
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);
|
||||
|
||||
ret = fd_sess_state_retrieve(pcrf_rx_reg, sess, &sess_data);
|
||||
ogs_assert(ret == 0);
|
||||
if (!sess_data) {
|
||||
ogs_error("Cannot find session in Session-Termination-Request");
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to create Auth-Request-Type AVP");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
val.i32 = OGS_DIAM_AUTH_REQUEST_TYPE_AUTHENTICATE_ONLY;
|
||||
ret = fd_msg_avp_setvalue(avp, &val);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to set Auth-Request-Type value");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to add Auth-Request-Type AVP");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Retrieve session state */
|
||||
ret = fd_sess_state_retrieve(pcrf_rx_reg, sess, &sess_data);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to retrieve session state");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!sess_data) {
|
||||
ogs_error("Cannot find session in Session-Termination-Request");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!sess_data->rx_sid) {
|
||||
ogs_error("No Rx Session-Id in session data");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!sess_data->gx_sid) {
|
||||
ogs_error("No Gx Session-Id in session data");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
ogs_assert(sess_data->rx_sid);
|
||||
ogs_assert(sess_data->gx_sid);
|
||||
|
||||
/* Get Termination-Cause */
|
||||
ret = fd_msg_search_avp(qry, ogs_diam_termination_cause, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (avp) {
|
||||
if (ret == 0 && avp) {
|
||||
ret = fd_msg_avp_hdr(avp, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret == 0 && hdr) {
|
||||
sess_data->termination_cause = hdr->avp_value->i32;
|
||||
switch (sess_data->termination_cause) {
|
||||
case OGS_DIAM_TERMINATION_CAUSE_DIAMETER_LOGOUT:
|
||||
@@ -735,75 +936,101 @@ static int pcrf_rx_str_cb( struct msg **msg, struct avp *avp,
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ogs_error("no_Termination-Cause");
|
||||
ogs_error("Failed to get Termination-Cause AVP header");
|
||||
}
|
||||
} else {
|
||||
ogs_warn("No Termination-Cause found");
|
||||
}
|
||||
|
||||
if (sess_data->state != SESSION_ABORTED) {
|
||||
/* Send Re-Auth Request if Abort-Session-Request is not initaited */
|
||||
/* Send Re-Auth Request if Abort-Session-Request is not initiated */
|
||||
rv = pcrf_gx_send_rar(
|
||||
sess_data->gx_sid, sess_data->rx_sid, &rx_message);
|
||||
if (rv != OGS_OK) {
|
||||
result_code = rx_message.result_code;
|
||||
if (result_code != ER_DIAMETER_SUCCESS) {
|
||||
ogs_error("pcrf_gx_send_rar() failed");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
|
||||
if (!error_occurred) {
|
||||
/* Set success result code */
|
||||
ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to set success result code");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Send the answer */
|
||||
ret = fd_msg_send(msg, NULL, NULL);
|
||||
ogs_assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to send message");
|
||||
error_occurred = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ogs_debug("[PCRF] Tx Session-Termination-Answer");
|
||||
|
||||
/* Add this value to the stats */
|
||||
/* Add to stats */
|
||||
OGS_DIAM_STATS_MTX(
|
||||
OGS_DIAM_STATS_INC(nb_echoed);
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.rx_str);
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.tx_sta);
|
||||
)
|
||||
|
||||
/* Clean up session state */
|
||||
state_cleanup(sess_data, NULL, NULL);
|
||||
ogs_ims_data_free(&rx_message.ims_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
out:
|
||||
/* Error handling */
|
||||
if (ans) {
|
||||
if (result_code == OGS_DIAM_AVP_UNSUPPORTED) {
|
||||
ret = fd_msg_rescode_set(ans,
|
||||
(char *)"DIAMETER_AVP_UNSUPPORTED", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
} else if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) {
|
||||
ret = fd_msg_rescode_set(ans,
|
||||
(char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
} else if (result_code == OGS_DIAM_MISSING_AVP) {
|
||||
ret = fd_msg_rescode_set(ans,
|
||||
(char *)"DIAMETER_MISSING_AVP", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
} else {
|
||||
ret = fd_msg_rescode_set(ans,
|
||||
(char *)"DIAMETER_MISSING_AVP", NULL, NULL, 1);
|
||||
ogs_assert(ret == 0);
|
||||
(char *)"DIAMETER_UNABLE_TO_COMPLY", NULL, NULL, 1);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to set error result code");
|
||||
}
|
||||
|
||||
ret = fd_msg_send(msg, NULL, NULL);
|
||||
ogs_assert(ret == 0);
|
||||
ogs_debug("[PCRF] Tx Session-Termination-Answer");
|
||||
if (ret != 0) {
|
||||
ogs_error("Failed to send error response");
|
||||
}
|
||||
|
||||
ogs_debug("[PCRF] Tx Session-Termination-Answer");
|
||||
}
|
||||
|
||||
/* Update error stats */
|
||||
OGS_DIAM_STATS_MTX(
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.rx_str);
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.rx_str_error);
|
||||
PCRF_DIAM_PRIV_STATS_INC(rx.tx_sta);
|
||||
)
|
||||
|
||||
if (sess_data)
|
||||
/* Clean up session state */
|
||||
if (sess_data) {
|
||||
state_cleanup(sess_data, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Always free IMS data */
|
||||
ogs_ims_data_free(&rx_message.ims_data);
|
||||
|
||||
return 0;
|
||||
|
@@ -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,24 +1117,31 @@ 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);
|
||||
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.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 */
|
||||
@@ -1107,6 +1154,8 @@ out:
|
||||
ogs_diam_stats_self()->stats.longest = dur;
|
||||
ogs_diam_stats_self()->stats.avg = dur;
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
ogs_diam_stats_self()->stats.nb_errs++;
|
||||
else
|
||||
@@ -1114,7 +1163,8 @@ out:
|
||||
|
||||
ogs_assert(pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0);
|
||||
|
||||
/* Display how long it took */
|
||||
/* 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),
|
||||
@@ -1122,15 +1172,25 @@ out:
|
||||
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);
|
||||
(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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@@ -1138,10 +1198,14 @@ out:
|
||||
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,7 +1395,8 @@ 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 */
|
||||
/* 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);
|
||||
|
||||
@@ -1326,8 +1408,14 @@ static int smf_gx_rar_cb( struct msg **msg, struct avp *avp,
|
||||
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 */
|
||||
@@ -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 */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -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,22 +1238,31 @@ 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);
|
||||
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.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 */
|
||||
@@ -1235,6 +1275,8 @@ out:
|
||||
ogs_diam_stats_self()->stats.longest = dur;
|
||||
ogs_diam_stats_self()->stats.avg = dur;
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
ogs_diam_stats_self()->stats.nb_errs++;
|
||||
else
|
||||
@@ -1242,7 +1284,8 @@ out:
|
||||
|
||||
ogs_assert(pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0);
|
||||
|
||||
/* Display how long it took */
|
||||
/* 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),
|
||||
@@ -1250,11 +1293,14 @@ out:
|
||||
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);
|
||||
(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);
|
||||
|
||||
/* 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) {
|
||||
@@ -1266,12 +1312,12 @@ out:
|
||||
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,
|
||||
@@ -1292,59 +1338,83 @@ 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);
|
||||
@@ -1353,7 +1423,11 @@ static int smf_gy_rar_cb( struct msg **msg, struct avp *avp,
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
/* 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 *
|
||||
/* 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,14 +517,17 @@ 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 */
|
||||
/* 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),
|
||||
@@ -510,12 +535,21 @@ static void smf_s6b_aaa_cb(void *data, struct msg **msg)
|
||||
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);
|
||||
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec)
|
||||
/ 1000);
|
||||
|
||||
/* 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,34 +797,49 @@ 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);
|
||||
}
|
||||
} else {
|
||||
ogs_free(s6b_message);
|
||||
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 */
|
||||
ogs_assert(pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0);
|
||||
|
||||
/* 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) {
|
||||
/* Ponderate in the avg */
|
||||
ogs_diam_stats_self()->stats.avg = (ogs_diam_stats_self()->stats.avg *
|
||||
/* 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)
|
||||
@@ -797,14 +849,18 @@ static void smf_s6b_sta_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 */
|
||||
/* 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),
|
||||
@@ -812,12 +868,21 @@ static void smf_s6b_sta_cb(void *data, struct msg **msg)
|
||||
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);
|
||||
(long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec)
|
||||
/ 1000);
|
||||
|
||||
/* 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;
|
||||
|
Reference in New Issue
Block a user