From f23d7a5e959acd8f37b925dc29b85f26b7d391cb Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sat, 2 Aug 2025 15:13:58 +0900 Subject: [PATCH] [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. --- lib/diameter/common/message.h | 2 + src/hss/hss-cx-path.c | 1719 +++++++++++++++++++++++---------- src/hss/hss-s6a-path.c | 1533 ++++++++++++++++++++--------- src/hss/hss-swx-path.c | 1553 +++++++++++++++++++++-------- src/mme/mme-fd-path.c | 942 +++++++++++------- src/pcrf/pcrf-gx-path.c | 942 +++++++++++++----- src/pcrf/pcrf-rx-path.c | 761 ++++++++++----- src/smf/gx-path.c | 273 ++++-- src/smf/gy-path.c | 253 +++-- src/smf/s6b-path.c | 203 ++-- 10 files changed, 5683 insertions(+), 2498 deletions(-) diff --git a/lib/diameter/common/message.h b/lib/diameter/common/message.h index 159394c43..a4016d297 100644 --- a/lib/diameter/common/message.h +++ b/lib/diameter/common/message.h @@ -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 diff --git a/src/hss/hss-cx-path.c b/src/hss/hss-cx-path.c index 37b4275bf..db9726f97 100644 --- a/src/hss/hss-cx-path.c +++ b/src/hss/hss-cx-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -47,256 +47,455 @@ static int hss_ogs_diam_cx_fb_cb(struct msg **msg, struct avp *avp, } /* Callback for incoming User-Authorization-Request messages */ -static int hss_ogs_diam_cx_uar_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_cx_uar_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int rv, ret; uint32_t result_code = 0; - - struct msg *ans, *qry; - - struct avp_hdr *hdr; + struct msg *ans = NULL, *qry = NULL; + struct avp_hdr *hdr = NULL; union avp_value val; char *user_name = NULL; char *public_identity = NULL; char *visited_network_identifier = NULL; char *server_name = NULL; - char imsi_or_msisdn_bcd[OGS_MAX_IMSI_BCD_LEN+1]; - ogs_msisdn_data_t msisdn_data; - - ogs_assert(msg); + int error_occurred = 0; ogs_debug("Rx User-Authorization-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + + /* Initialize variables */ + memset(imsi_or_msisdn_bcd, 0, sizeof(imsi_or_msisdn_bcd)); + memset(&msisdn_data, 0, sizeof(ogs_msisdn_data_t)); + /* 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; /* Get User-Name AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search User-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No User-Name AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } user_name = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(user_name); + if (!user_name) { + ogs_error("Failed to duplicate User-Name"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } ogs_extract_digit_from_string(imsi_or_msisdn_bcd, user_name); /* Get Public-Identity AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_cx_public_identity, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - - public_identity = ogs_strndup( - (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(public_identity); - - /* Get Visited-Network-Identifier AVP (Mandatory) */ - ret = fd_msg_search_avp(qry, ogs_diam_visited_network_identifier, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - - visited_network_identifier = ogs_strndup( - (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(visited_network_identifier); - - memset(&msisdn_data, 0, sizeof(ogs_msisdn_data_t)); - rv = hss_db_msisdn_data(imsi_or_msisdn_bcd, &msisdn_data); - if (rv != OGS_OK) { - ogs_error("Cannot get MSISDN-Data for IMSI or MSISDN:'%s'", - imsi_or_msisdn_bcd); - result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN; + if (ret != 0) { + ogs_error("Failed to search Public-Identity AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_CX_APPLICATION_ID); - ogs_assert(ret == 0); - - /* Associate IMPI(User-Name) with IMPU(Public-Identity) */ - hss_cx_associate_identity(user_name, public_identity); - - /* Set IMSI for IMPI(User-Name) */ - hss_cx_set_imsi_bcd(user_name, - msisdn_data.imsi.bcd, visited_network_identifier); - - /* Get Server-Name by IMPU(Public-Identity) */ - server_name = hss_cx_get_server_name(public_identity); - if (!server_name) - result_code = OGS_DIAM_CX_FIRST_REGISTRATION; - else - result_code = OGS_DIAM_CX_SUBSEQUENT_REGISTRATION; - - /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); - - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Server-Name AVP */ - if (server_name) { - ret = fd_msg_avp_new(ogs_diam_cx_server_name, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)server_name; - val.os.len = strlen(server_name); - 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); + if (!avp) { + ogs_error("No Public-Identity AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; } - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Public-Identity AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } - ogs_debug("Tx User-Authorization-Answer"); + public_identity = ogs_strndup( + (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); + if (!public_identity) { + ogs_error("Failed to duplicate Public-Identity"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(cx.rx_uar); - HSS_DIAM_PRIV_STATS_INC(cx.tx_uaa); - ) + /* Get Visited-Network-Identifier AVP (Mandatory) */ + ret = fd_msg_search_avp(qry, ogs_diam_visited_network_identifier, &avp); + if (ret != 0) { + ogs_error("Failed to search Visited-Network-Identifier AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } - ogs_free(user_name); - ogs_free(public_identity); - ogs_free(visited_network_identifier); + if (!avp) { + ogs_error("No Visited-Network-Identifier AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } - return 0; + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Visited-Network-Identifier AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + + visited_network_identifier = ogs_strndup( + (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); + if (!visited_network_identifier) { + ogs_error("Failed to duplicate Visited-Network-Identifier"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + + /* Get MSISDN data from database */ + rv = hss_db_msisdn_data(imsi_or_msisdn_bcd, &msisdn_data); + if (rv != OGS_OK) { + ogs_error("Cannot get MSISDN-Data for IMSI or MSISDN: %s", + imsi_or_msisdn_bcd); + result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN; + error_occurred = 1; + goto out; + } + + if (!error_occurred) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } + + /* Associate IMPI(User-Name) with IMPU(Public-Identity) */ + hss_cx_associate_identity(user_name, public_identity); + + /* Set IMSI for IMPI(User-Name) */ + hss_cx_set_imsi_bcd(user_name, + msisdn_data.imsi.bcd, visited_network_identifier); + + /* Get Server-Name by IMPU(Public-Identity) */ + server_name = hss_cx_get_server_name(public_identity); + if (!server_name) + result_code = OGS_DIAM_CX_FIRST_REGISTRATION; + else + result_code = OGS_DIAM_CX_SUBSEQUENT_REGISTRATION; + + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + if (ret != 0) { + ogs_error("Failed to set experimental result code"); + error_occurred = 1; + goto out; + } + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State 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-Session-State AVP"); + error_occurred = 1; + goto out; + } + + /* Set the Server-Name AVP */ + if (server_name) { + ret = fd_msg_avp_new(ogs_diam_cx_server_name, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Server-Name AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)server_name; + val.os.len = strlen(server_name); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Server-Name 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 Server-Name AVP"); + error_occurred = 1; + goto out; + } + } + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } + + ogs_debug("Tx User-Authorization-Answer"); + + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(cx.rx_uar); + HSS_DIAM_PRIV_STATS_INC(cx.tx_uaa); + ) + + /* Cleanup resources */ + if (user_name) ogs_free(user_name); + if (public_identity) ogs_free(public_identity); + if (visited_network_identifier) ogs_free(visited_network_identifier); + + return 0; + } out: - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_CX_APPLICATION_ID); - ogs_assert(ret == 0); + /* Error handling */ + if (ans) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); - /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } + } + /* Update error stats */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(cx.rx_uar); HSS_DIAM_PRIV_STATS_INC(cx.rx_uar_error); ) - ogs_free(user_name); - ogs_free(public_identity); - ogs_free(visited_network_identifier); + /* Cleanup resources */ + if (user_name) ogs_free(user_name); + if (public_identity) ogs_free(public_identity); + if (visited_network_identifier) ogs_free(visited_network_identifier); return 0; } /* Callback for incoming Multimedia-Auth-Request messages */ -static int hss_ogs_diam_cx_mar_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_cx_mar_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int rv, ret; uint32_t result_code = 0; - - struct msg *ans, *qry; - + struct msg *ans = NULL, *qry = NULL; struct avp *sip_auth_data_item_avp = NULL; struct avp *authentication_scheme_avp = NULL; struct avp *sip_authorization_avp = NULL; - struct avp *avpch = NULL; - struct avp_hdr *hdr; + struct avp_hdr *hdr = NULL; union avp_value val; char *user_name = NULL; char *public_identity = NULL; char *server_name = NULL; char *authentication_scheme = NULL; - char *imsi_bcd = NULL; ogs_dbi_auth_info_t auth_info; uint8_t zero[OGS_RAND_LEN]; - uint8_t authenticate[OGS_KEY_LEN*2]; - uint8_t opc[OGS_KEY_LEN]; uint8_t sqn[OGS_SQN_LEN]; - uint8_t autn[OGS_AUTN_LEN]; uint8_t ik[OGS_KEY_LEN]; uint8_t ck[OGS_KEY_LEN]; uint8_t ak[OGS_AK_LEN]; uint8_t xres[OGS_MAX_RES_LEN]; size_t xres_len = 8; - uint8_t mac_s[OGS_MAC_S_LEN]; bool matched = false; - - ogs_assert(msg); + int error_occurred = 0; ogs_debug("Rx Multimedia-Auth-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + + /* Initialize variables */ + memset(&auth_info, 0, sizeof(auth_info)); + /* 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; /* Get User-Name AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search User-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No User-Name AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } user_name = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(user_name); + if (!user_name) { + ogs_error("Failed to duplicate User-Name"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } /* Get Public-Identity AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_cx_public_identity, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Public-Identity AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Public-Identity AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Public-Identity AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } public_identity = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(public_identity); + if (!public_identity) { + ogs_error("Failed to duplicate Public-Identity"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } /* Get Server-Name AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_cx_server_name, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Server-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Server-Name AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Server-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } server_name = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(server_name); + if (!server_name) { + ogs_error("Failed to duplicate Server-Name"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } /* Check if IMPI(User-Name) + IMPU(Public-Identity) is associated */ matched = hss_cx_identity_is_associated(user_name, public_identity); @@ -304,6 +503,7 @@ static int hss_ogs_diam_cx_mar_cb( struct msg **msg, struct avp *avp, ogs_error("User-Name[%s] Public-Identity[%s] is not associated", user_name, public_identity); result_code = OGS_DIAM_CX_ERROR_IDENTITIES_DONT_MATCH; + error_occurred = 1; goto out; } @@ -313,27 +513,50 @@ static int hss_ogs_diam_cx_mar_cb( struct msg **msg, struct avp *avp, ogs_error("Cannot find IMSI for User-Name[%s] Public-Identity[%s]", user_name, public_identity); result_code = OGS_DIAM_CX_ERROR_IDENTITY_NOT_REGISTERED; + error_occurred = 1; goto out; } /* Get the SIP-Auth-Data-Item AVP (Mandatory) */ ret = fd_msg_search_avp( qry, ogs_diam_cx_sip_auth_data_item, &sip_auth_data_item_avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search SIP-Auth-Data-Item AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!sip_auth_data_item_avp) { + ogs_error("No SIP-Auth-Data-Item AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(sip_auth_data_item_avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get SIP-Auth-Data-Item AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } /* Get the Authentication-Scheme AVP */ ret = fd_msg_search_avp(sip_auth_data_item_avp, ogs_diam_cx_sip_authentication_scheme, &authentication_scheme_avp); - ogs_assert(ret == 0); - if (authentication_scheme_avp) { + if (ret == 0 && authentication_scheme_avp) { ret = fd_msg_avp_hdr(authentication_scheme_avp, &hdr); - ogs_assert(ret == 0); - - authentication_scheme = ogs_strndup( - (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(authentication_scheme); + if (ret == 0 && hdr) { + authentication_scheme = ogs_strndup( + (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); + if (!authentication_scheme) { + ogs_error("Failed to duplicate Authentication-Scheme"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + } } /* IMS_AKA is only supported */ @@ -345,14 +568,16 @@ static int hss_ogs_diam_cx_mar_cb( struct msg **msg, struct avp *avp, ogs_error("Authentication-Scheme[%s] is not supported", authentication_scheme); result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED; + error_occurred = 1; goto out; } /* DB : HSS Auth-Info */ rv = hss_db_auth_info(imsi_bcd, &auth_info); if (rv != OGS_OK) { - ogs_error("Cannot get IMS-Data for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot get IMS-Data for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN; + error_occurred = 1; goto out; } @@ -372,47 +597,51 @@ static int hss_ogs_diam_cx_mar_cb( struct msg **msg, struct avp *avp, /* Get the SIP-Authorization AVP */ ret = fd_msg_search_avp(sip_auth_data_item_avp, ogs_diam_cx_sip_authorization, &sip_authorization_avp); - ogs_assert(ret == 0); - if (sip_authorization_avp) { + if (ret == 0 && sip_authorization_avp) { ret = fd_msg_avp_hdr(sip_authorization_avp, &hdr); - ogs_assert(ret == 0); + if (ret == 0 && hdr) { + ogs_auc_sqn(opc, auth_info.k, + hdr->avp_value->os.data, + hdr->avp_value->os.data + OGS_RAND_LEN, + sqn, mac_s); + if (memcmp(mac_s, hdr->avp_value->os.data + + OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) { + ogs_random(auth_info.rand, OGS_RAND_LEN); + auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN); + /* 33.102 C.3.4 Guide : IND + 1 */ + auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN; + } else { + ogs_error("Re-synch MAC failed for IMSI: %s", imsi_bcd); - ogs_auc_sqn(opc, auth_info.k, - hdr->avp_value->os.data, - hdr->avp_value->os.data + OGS_RAND_LEN, - sqn, mac_s); - if (memcmp(mac_s, hdr->avp_value->os.data + - OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) { - ogs_random(auth_info.rand, OGS_RAND_LEN); - auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN); - /* 33.102 C.3.4 Guide : IND + 1 */ - auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN; - } else { - ogs_error("Re-synch MAC failed for IMSI:`%s`", imsi_bcd); - ogs_log_print(OGS_LOG_ERROR, "MAC_S: "); - ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN); - ogs_log_hexdump(OGS_LOG_ERROR, - (void*)(hdr->avp_value->os.data + - OGS_RAND_LEN + OGS_SQN_LEN), - OGS_MAC_S_LEN); - ogs_log_print(OGS_LOG_ERROR, "SQN: "); - ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN); - result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED; - goto out; + ogs_log_print(OGS_LOG_ERROR, "MAC_S: "); + ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN); + ogs_log_hexdump(OGS_LOG_ERROR, + (void*)(hdr->avp_value->os.data + + OGS_RAND_LEN + OGS_SQN_LEN), + OGS_MAC_S_LEN); + ogs_log_print(OGS_LOG_ERROR, "SQN: "); + ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN); + + result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED; + error_occurred = 1; + goto out; + } } } rv = hss_db_update_sqn(imsi_bcd, auth_info.rand, auth_info.sqn); if (rv != OGS_OK) { - ogs_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot update rand and sqn for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE; + error_occurred = 1; goto out; } rv = hss_db_increment_sqn(imsi_bcd); if (rv != OGS_OK) { - ogs_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot increment sqn for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE; + error_occurred = 1; goto out; } @@ -445,243 +674,454 @@ static int hss_ogs_diam_cx_mar_cb( struct msg **msg, struct avp *avp, ogs_log_print(OGS_LOG_DEBUG, "xles - "); ogs_log_hexdump(OGS_LOG_DEBUG, xres, xres_len); - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_CX_APPLICATION_ID); - ogs_assert(ret == 0); + if (!error_occurred) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State 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-Session-State AVP"); + error_occurred = 1; + goto out; + } - /* 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); + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } - /* Set the User-Name AVP */ - ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)user_name; - val.os.len = strlen(user_name); - 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 User-Name AVP */ + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create User-Name AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set User-Name 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 User-Name AVP"); + error_occurred = 1; + goto out; + } - /* Set the Public-Identity AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_public_identity, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)public_identity; - val.os.len = strlen(public_identity); - 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 Public-Identity AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_public_identity, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Public-Identity AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)public_identity; + val.os.len = strlen(public_identity); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Public-Identity 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 Public-Identity AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Number-Auth-Items AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_number_auth_items, 0, &avp); - ogs_assert(ret == 0); - val.u32 = 1; - 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 SIP-Number-Auth-Items AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_number_auth_items, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create SIP-Number-Auth-Items AVP"); + error_occurred = 1; + goto out; + } + val.u32 = 1; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Number-Auth-Items 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 SIP-Number-Auth-Items AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Auth-Data-Item AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_auth_data_item, 0, &avp); - ogs_assert(ret == 0); + /* Set the SIP-Auth-Data-Item AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_auth_data_item, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create SIP-Auth-Data-Item AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Item-Number AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_item_number, 0, &avpch); - ogs_assert(ret == 0); - val.u32 = 1; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the SIP-Item-Number AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_item_number, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create SIP-Item-Number AVP"); + error_occurred = 1; + goto out; + } + val.u32 = 1; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Item-Number value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add SIP-Item-Number AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Authentication-Scheme AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_authentication_scheme, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)OGS_DIAM_CX_AUTH_SCHEME_IMS_AKA; - val.os.len = strlen(OGS_DIAM_CX_AUTH_SCHEME_IMS_AKA); - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the SIP-Authentication-Scheme AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authentication_scheme, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create SIP-Authentication-Scheme AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)OGS_DIAM_CX_AUTH_SCHEME_IMS_AKA; + val.os.len = strlen(OGS_DIAM_CX_AUTH_SCHEME_IMS_AKA); + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Authentication-Scheme value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add SIP-Authentication-Scheme AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Authenticatie AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_authenticate, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = authenticate; - val.os.len = OGS_KEY_LEN * 2; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the SIP-Authenticate AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authenticate, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create SIP-Authenticate AVP"); + error_occurred = 1; + goto out; + } + val.os.data = authenticate; + val.os.len = OGS_KEY_LEN * 2; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Authenticate value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add SIP-Authenticate AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Authorization AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_authorization, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = xres; - val.os.len = xres_len; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the SIP-Authorization AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authorization, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create SIP-Authorization AVP"); + error_occurred = 1; + goto out; + } + val.os.data = xres; + val.os.len = xres_len; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Authorization value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add SIP-Authorization AVP"); + error_occurred = 1; + goto out; + } - /* Set the Confidentiality-Key AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_confidentiality_key, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = ck; - val.os.len = OGS_KEY_LEN; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the Confidentiality-Key AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_confidentiality_key, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create Confidentiality-Key AVP"); + error_occurred = 1; + goto out; + } + val.os.data = ck; + val.os.len = OGS_KEY_LEN; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set Confidentiality-Key value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add Confidentiality-Key AVP"); + error_occurred = 1; + goto out; + } - /* Set the Integrity-Key AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_integrity_key, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = ik; - val.os.len = OGS_KEY_LEN; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the Integrity-Key AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_integrity_key, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create Integrity-Key AVP"); + error_occurred = 1; + goto out; + } + val.os.data = ik; + val.os.len = OGS_KEY_LEN; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set Integrity-Key value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add Integrity-Key AVP"); + error_occurred = 1; + goto out; + } - ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_error("Failed to add SIP-Auth-Data-Item AVP"); + error_occurred = 1; + goto out; + } - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } - ogs_debug("Tx Multimedia-Auth-Answer"); + ogs_debug("Tx Multimedia-Auth-Answer"); - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(cx.rx_mar); - HSS_DIAM_PRIV_STATS_INC(cx.tx_maa); - ) + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(cx.rx_mar); + HSS_DIAM_PRIV_STATS_INC(cx.tx_maa); + ) - if (authentication_scheme) - ogs_free(authentication_scheme); + /* Cleanup resources */ + if (authentication_scheme) ogs_free(authentication_scheme); + if (user_name) ogs_free(user_name); + if (public_identity) ogs_free(public_identity); + if (server_name) ogs_free(server_name); - ogs_free(user_name); - ogs_free(public_identity); - ogs_free(server_name); - - return 0; + return 0; + } out: - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_CX_APPLICATION_ID); - ogs_assert(ret == 0); + /* Error handling */ + if (ans) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); - /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - - if (authentication_scheme) - ogs_free(authentication_scheme); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } + } + /* Update error stats */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(cx.rx_mar); HSS_DIAM_PRIV_STATS_INC(cx.rx_mar_error); ) - ogs_free(user_name); - ogs_free(public_identity); - ogs_free(server_name); + /* Cleanup resources */ + if (authentication_scheme) ogs_free(authentication_scheme); + if (user_name) ogs_free(user_name); + if (public_identity) ogs_free(public_identity); + if (server_name) ogs_free(server_name); return 0; } /* Callback for incoming Server-Assignment-Request messages */ -static int hss_ogs_diam_cx_sar_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_cx_sar_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int rv, ret; uint32_t result_code = 0; - - struct msg *ans, *qry; - + struct msg *ans = NULL, *qry = NULL; bool matched = false; struct avp *user_name_avp = NULL; struct avp *avpch = NULL; - struct avp_hdr *hdr; + struct avp_hdr *hdr = NULL; union avp_value val; char *user_name = NULL; char *public_identity = NULL; char *server_name = NULL; char *user_data = NULL; - char *imsi_bcd = NULL; char *visited_network_identifier = NULL; ogs_ims_data_t ims_data; - - ogs_assert(msg); + int error_occurred = 0; ogs_debug("Rx Server-Assignment-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + + /* Initialize variables */ + memset(&ims_data, 0, sizeof(ogs_ims_data_t)); + /* 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; /* Get Public-Identity AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_cx_public_identity, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Public-Identity AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Public-Identity AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Public-Identity AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } public_identity = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(public_identity); + if (!public_identity) { + ogs_error("Failed to duplicate Public-Identity"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } /* Get Server-Name AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_cx_server_name, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Server-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Server-Name AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Server-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } server_name = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(server_name); + if (!server_name) { + ogs_error("Failed to duplicate Server-Name"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } - /* Get User-Name AVP */ + /* Get User-Name AVP (Optional) */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &user_name_avp); - ogs_assert(ret == 0); - if (user_name_avp) { + if (ret == 0 && user_name_avp) { ret = fd_msg_avp_hdr(user_name_avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } user_name = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(user_name); + if (!user_name) { + ogs_error("Failed to duplicate User-Name"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } /* Check if IMPI(User-Name) + IMPU(Public-Identity) is associated */ matched = hss_cx_identity_is_associated(user_name, public_identity); @@ -689,19 +1129,26 @@ static int hss_ogs_diam_cx_sar_cb( struct msg **msg, struct avp *avp, ogs_error("User-Name[%s] Public-Identity[%s] is not associated", user_name, public_identity); result_code = OGS_DIAM_CX_ERROR_IDENTITIES_DONT_MATCH; + error_occurred = 1; goto out; } } else { - user_name = hss_cx_get_user_name(public_identity); - if (!user_name) { + const char *temp_user_name = hss_cx_get_user_name(public_identity); + if (!temp_user_name) { ogs_error("Cannot find User-Name for Public-Identity[%s]", public_identity); result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN; + error_occurred = 1; goto out; } - user_name = ogs_strdup(user_name); - ogs_assert(user_name); + user_name = ogs_strdup(temp_user_name); + if (!user_name) { + ogs_error("Failed to duplicate User-Name from context"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } } /* Check if IMSI */ @@ -710,6 +1157,7 @@ static int hss_ogs_diam_cx_sar_cb( struct msg **msg, struct avp *avp, ogs_error("Cannot find IMSI for User-Name[%s] Public-Identity[%s]", user_name, public_identity); result_code = OGS_DIAM_CX_ERROR_IDENTITY_NOT_REGISTERED; + error_occurred = 1; goto out; } @@ -721,283 +1169,496 @@ static int hss_ogs_diam_cx_sar_cb( struct msg **msg, struct avp *avp, "for User-Name[%s] Public-Identity[%s]", user_name, public_identity); result_code = OGS_DIAM_CX_ERROR_IDENTITY_NOT_REGISTERED; + error_occurred = 1; goto out; } /* DB : HSS IMS Service Profile */ - memset(&ims_data, 0, sizeof(ogs_ims_data_t)); rv = hss_db_ims_data(imsi_bcd, &ims_data); if (rv != OGS_OK) { - ogs_error("Cannot get IMS-Data for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot get IMS-Data for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN; + error_occurred = 1; goto out; } /* Overwrite Server-Name for IMPU(Public-Identity) */ hss_cx_set_server_name(public_identity, server_name, true); - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_CX_APPLICATION_ID); - ogs_assert(ret == 0); + if (!error_occurred) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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, and Result-Code AVPs */ - ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); - ogs_assert(ret == 0); - - if (user_name_avp) { - /* Set the User-Name AVP */ - ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)user_name; - val.os.len = strlen(user_name); + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State 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-Session-State AVP"); + error_occurred = 1; + goto out; + } + + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } + + if (user_name_avp) { + /* Set the User-Name AVP */ + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create User-Name AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set User-Name 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 User-Name AVP"); + error_occurred = 1; + goto out; + } + } + + /* Get Server-Assignment-Type AVP (Mandatory) */ + ret = fd_msg_search_avp(qry, + ogs_diam_cx_server_assignment_type, &avp); + if (ret != 0) { + ogs_error("Failed to search Server-Assignment-Type AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Server-Assignment-Type AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Server-Assignment-Type AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + + if (hdr->avp_value->i32 == OGS_DIAM_CX_SERVER_ASSIGNMENT_REGISTRATION || + hdr->avp_value->i32 == + OGS_DIAM_CX_SERVER_ASSIGNMENT_RE_REGISTRATION) { + + /* Get User-Data-Already-Available AVP (Mandatory) */ + ret = fd_msg_search_avp( + qry, ogs_diam_cx_user_data_already_available, &avp); + if (ret != 0) { + ogs_error("Failed to search User-Data-Already-Available AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No User-Data-Already-Available AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Data-Already-Available header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + + if (hdr->avp_value->i32 == + OGS_DIAM_CX_USER_DATA_ALREADY_AVAILABLE) { + /* Nothing to do */ + } else { + /* Set the User-Data AVP */ + user_data = hss_cx_download_user_data( + user_name, visited_network_identifier, &ims_data); + if (!user_data) { + ogs_error("Failed to download user data"); + result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_new(ogs_diam_cx_user_data, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create User-Data AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)user_data; + val.os.len = strlen(user_data); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set User-Data 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 User-Data AVP"); + error_occurred = 1; + goto out; + } + + /* Set the Charging-Information AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_charging_information, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Charging-Information AVP"); + error_occurred = 1; + goto out; + } + + /* Set the Primary-Charging-Collection-Function-Name AVP */ + ret = fd_msg_avp_new( + ogs_diam_cx_primary_charging_collection_function_name, 0, + &avpch); + if (ret != 0) { + ogs_error("Failed to create Primary-Charging-Collection-" + "Function-Name AVP"); + error_occurred = 1; + goto out; + } +#define PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME "pcrf" + val.os.data = + (uint8_t *)PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME; + val.os.len = strlen(PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME); + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set Primary-Charging-Collection-" + "Function-Name value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add Primary-Charging-Collection-" + "Function-Name AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_error("Failed to add Charging-Information AVP"); + error_occurred = 1; + goto out; + } + } + } + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } + + ogs_debug("Tx Server-Assignment-Answer"); + + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(cx.rx_sar); + HSS_DIAM_PRIV_STATS_INC(cx.tx_saa); + ) + + /* Cleanup resources */ + if (user_data) ogs_free(user_data); + if (user_name) ogs_free(user_name); + if (public_identity) ogs_free(public_identity); + if (server_name) ogs_free(server_name); + + return 0; } - /* Get Server-Assignment-Type AVP (Mandatory) */ - ret = fd_msg_search_avp(qry, - ogs_diam_cx_server_assignment_type, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - if (hdr->avp_value->i32 == OGS_DIAM_CX_SERVER_ASSIGNMENT_REGISTRATION || - hdr->avp_value->i32 == OGS_DIAM_CX_SERVER_ASSIGNMENT_RE_REGISTRATION) { +out: + /* Error handling */ + if (ans) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); - /* Get User-Data-Already-Available AVP (Mandatory) */ - ret = fd_msg_search_avp( - qry, ogs_diam_cx_user_data_already_available, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + } - if (hdr->avp_value->i32 == OGS_DIAM_CX_USER_DATA_ALREADY_AVAILABLE) { - /* Nothing to do */ - } else { - /* Set the User-Data AVP */ - user_data = hss_cx_download_user_data( - user_name, visited_network_identifier, &ims_data); - ogs_assert(user_data); - - ret = fd_msg_avp_new(ogs_diam_cx_user_data, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)user_data; - val.os.len = strlen(user_data); + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; 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); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } - /* Set the Charging-Information AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_charging_information, 0, &avp); - ogs_assert(ret == 0); - - /* Set the Charging-Information AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_charging_information, 0, &avp); - ogs_assert(ret == 0); - - /* Set the Primary-Charging-Collection-Function-Name AVP */ - ret = fd_msg_avp_new( - ogs_diam_cx_primary_charging_collection_function_name, 0, - &avpch); - ogs_assert(ret == 0); -#define PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME "pcrf" - val.os.data = (uint8_t *)PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME; - val.os.len = strlen(PRIMARY_CHARGING_COLLECTION_FUNCTION_NAME); - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); - - ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); } } - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - - ogs_debug("Tx Server-Assignment-Answer"); - - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(cx.rx_sar); - HSS_DIAM_PRIV_STATS_INC(cx.tx_saa); - ) - - if (user_data) - ogs_free(user_data); - ogs_free(user_name); - ogs_free(public_identity); - ogs_free(server_name); - - return 0; - -out: - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_CX_APPLICATION_ID); - ogs_assert(ret == 0); - - /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); - - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - + /* Update error stats */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(cx.rx_sar); HSS_DIAM_PRIV_STATS_INC(cx.rx_sar_error); ) - if (user_data) - ogs_free(user_data); - ogs_free(user_name); - ogs_free(public_identity); - ogs_free(server_name); + /* Cleanup resources */ + if (user_data) ogs_free(user_data); + if (user_name) ogs_free(user_name); + if (public_identity) ogs_free(public_identity); + if (server_name) ogs_free(server_name); return 0; } /* Callback for incoming Location-Info-Request messages */ -static int hss_ogs_diam_cx_lir_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_cx_lir_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int ret; uint32_t result_code = 0; - - struct msg *ans, *qry; - - struct avp_hdr *hdr; + struct msg *ans = NULL, *qry = NULL; + struct avp_hdr *hdr = NULL; union avp_value val; char *public_identity = NULL; char *server_name = NULL; - - ogs_assert(msg); + int error_occurred = 0; ogs_debug("Rx Location-Info-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + /* 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; /* Get Public-Identity AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_cx_public_identity, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Public-Identity AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Public-Identity AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Public-Identity AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } public_identity = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(public_identity); + if (!public_identity) { + ogs_error("Failed to duplicate Public-Identity"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } /* Get Server-Name by IMPU(Public-Identity) */ server_name = hss_cx_get_server_name(public_identity); if (!server_name) { ogs_error("No Server-Name in Public-Identity[%s]", public_identity); result_code = OGS_DIAM_CX_SERVER_NAME_NOT_STORED; + error_occurred = 1; goto out; } - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_CX_APPLICATION_ID); - ogs_assert(ret == 0); + if (!error_occurred) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State 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-Session-State AVP"); + error_occurred = 1; + goto out; + } - /* 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); + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } - /* Set Server-Name AVPs */ - ret = fd_msg_avp_new(ogs_diam_cx_server_name, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)server_name; - val.os.len = strlen(server_name); - 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 Server-Name AVPs */ + ret = fd_msg_avp_new(ogs_diam_cx_server_name, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Server-Name AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)server_name; + val.os.len = strlen(server_name); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Server-Name 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 Server-Name AVP"); + error_occurred = 1; + goto out; + } - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } - ogs_debug("Tx Location-Info-Answer"); + ogs_debug("Tx Location-Info-Answer"); - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(cx.rx_lir); - HSS_DIAM_PRIV_STATS_INC(cx.tx_lia); - ) + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(cx.rx_lir); + HSS_DIAM_PRIV_STATS_INC(cx.tx_lia); + ) - ogs_free(public_identity); + /* Cleanup resources */ + if (public_identity) ogs_free(public_identity); - return 0; + return 0; + } out: - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_CX_APPLICATION_ID); - ogs_assert(ret == 0); + /* Error handling */ + if (ans) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + if (ret != 0) { + ogs_warn("Failed to set Vendor-Specific-Application-Id in error"); + } - /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + if (ret != 0) { + ogs_warn("Failed to set experimental result code"); + } + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_warn("Failed to add Auth-Session-State AVP in error"); + } + } else { + ogs_warn("Failed to set Auth-Session-State value in error"); + } + } else { + ogs_warn("Failed to create Auth-Session-State AVP in error"); + } - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } + } + /* Update error stats */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(cx.rx_lir); HSS_DIAM_PRIV_STATS_INC(cx.rx_lir_error); ) - ogs_free(public_identity); + /* Cleanup resources */ + if (public_identity) ogs_free(public_identity); return 0; } diff --git a/src/hss/hss-s6a-path.c b/src/hss/hss-s6a-path.c index 4b0481b84..56a028042 100644 --- a/src/hss/hss-s6a-path.c +++ b/src/hss/hss-s6a-path.c @@ -71,15 +71,15 @@ static int hss_ogs_diam_s6a_fb_cb(struct msg **msg, struct avp *avp, } /* Callback for incoming Authentication-Information-Request messages */ -static int hss_ogs_diam_s6a_air_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_s6a_air_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int ret; - - struct msg *ans, *qry; - struct avp *avpch; - struct avp *avp_e_utran_vector, *avp_xres, *avp_kasme, *avp_rand, *avp_autn; - struct avp_hdr *hdr; + struct msg *ans = NULL, *qry = NULL; + struct avp *avpch = NULL; + struct avp *avp_e_utran_vector = NULL, *avp_xres = NULL, + *avp_kasme = NULL, *avp_rand = NULL, *avp_autn = NULL; + struct avp_hdr *hdr = NULL; union avp_value val; char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; @@ -92,105 +92,169 @@ static int hss_ogs_diam_s6a_air_cb( struct msg **msg, struct avp *avp, uint8_t xres[OGS_MAX_RES_LEN]; uint8_t kasme[OGS_SHA256_DIGEST_SIZE]; size_t xres_len = 8; - uint8_t mac_s[OGS_MAC_S_LEN]; ogs_dbi_auth_info_t auth_info; uint8_t zero[OGS_RAND_LEN]; int rv; uint32_t result_code = 0; - ogs_plmn_id_t visited_plmn_id; - - ogs_assert(msg); + int error_occurred = 0; ogs_debug("Rx Authentication-Information-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + + /* Initialize variables */ + memset(imsi_bcd, 0, sizeof(imsi_bcd)); + memset(&auth_info, 0, sizeof(auth_info)); + memset(&visited_plmn_id, 0, sizeof(visited_plmn_id)); + /* 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; + /* Get User-Name AVP */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data, - ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1); - - rv = hss_db_auth_info(imsi_bcd, &auth_info); - if (rv != OGS_OK) { - result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; + if (ret != 0) { + ogs_error("Failed to search User-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } + if (!avp) { + ogs_error("No User-Name AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + + ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data, + ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1); + + /* Get authentication info from database */ + rv = hss_db_auth_info(imsi_bcd, &auth_info); + if (rv != OGS_OK) { + ogs_warn("Failed to get auth info for IMSI: %s", imsi_bcd); + result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; + error_occurred = 1; + goto out; + } + + /* Generate RAND if not set */ memset(zero, 0, sizeof(zero)); if (memcmp(auth_info.rand, zero, OGS_RAND_LEN) == 0) { ogs_random(auth_info.rand, OGS_RAND_LEN); } + /* Calculate OPC */ if (auth_info.use_opc) memcpy(opc, auth_info.opc, sizeof(opc)); else milenage_opc(auth_info.k, auth_info.op, opc); + /* Check for re-synchronization */ ret = fd_msg_search_avp(qry, ogs_diam_s6a_req_eutran_auth_info, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_avp_search_avp( - avp, ogs_diam_s6a_re_synchronization_info, &avpch); - ogs_assert(ret == 0); - if (avpch) { + if (ret == 0 && avp) { + ret = fd_avp_search_avp(avp, ogs_diam_s6a_re_synchronization_info, + &avpch); + if (ret == 0 && avpch) { ret = fd_msg_avp_hdr(avpch, &hdr); - ogs_assert(ret == 0); - ogs_auc_sqn(opc, auth_info.k, - hdr->avp_value->os.data, - hdr->avp_value->os.data + OGS_RAND_LEN, - sqn, mac_s); - if (memcmp(mac_s, hdr->avp_value->os.data + - OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) { - ogs_random(auth_info.rand, OGS_RAND_LEN); - auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN); - /* 33.102 C.3.4 Guide : IND + 1 */ - auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN; - } else { - ogs_error("Re-synch MAC failed for IMSI:`%s`", imsi_bcd); - ogs_log_print(OGS_LOG_ERROR, "MAC_S: "); - ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN); - ogs_log_hexdump(OGS_LOG_ERROR, - (void*)(hdr->avp_value->os.data + - OGS_RAND_LEN + OGS_SQN_LEN), - OGS_MAC_S_LEN); - ogs_log_print(OGS_LOG_ERROR, "SQN: "); - ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN); - result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE; - goto out; + if (ret == 0 && hdr) { + ogs_auc_sqn(opc, auth_info.k, + hdr->avp_value->os.data, + hdr->avp_value->os.data + OGS_RAND_LEN, + sqn, mac_s); + if (memcmp(mac_s, hdr->avp_value->os.data + + OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) { + ogs_random(auth_info.rand, OGS_RAND_LEN); + auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN); + /* 33.102 C.3.4 Guide : IND + 1 */ + auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN; + } else { + ogs_error("Re-synch MAC failed for IMSI: %s", imsi_bcd); + + ogs_log_print(OGS_LOG_ERROR, "MAC_S: "); + ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN); + ogs_log_hexdump(OGS_LOG_ERROR, + (void*)(hdr->avp_value->os.data + + OGS_RAND_LEN + OGS_SQN_LEN), + OGS_MAC_S_LEN); + ogs_log_print(OGS_LOG_ERROR, "SQN: "); + ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN); + + result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE; + error_occurred = 1; + goto out; + } } } } + /* Update SQN in database */ rv = hss_db_update_sqn(imsi_bcd, auth_info.rand, auth_info.sqn); if (rv != OGS_OK) { - ogs_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot update rand and sqn for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE; + error_occurred = 1; goto out; } rv = hss_db_increment_sqn(imsi_bcd); if (rv != OGS_OK) { - ogs_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot increment sqn for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE; + error_occurred = 1; goto out; } + /* Get Visited-PLMN-Id */ ret = fd_msg_search_avp(qry, ogs_diam_visited_plmn_id, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Visited-PLMN-Id AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Visited-PLMN-Id AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Visited-PLMN-Id AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + memcpy(&visited_plmn_id, hdr->avp_value->os.data, ogs_min(hdr->avp_value->os.len, sizeof(visited_plmn_id))); + /* Generate authentication vectors */ milenage_generate(opc, auth_info.amf, auth_info.k, ogs_uint64_to_buffer(auth_info.sqn, OGS_SQN_LEN, sqn), auth_info.rand, autn, ik, ck, ak, xres, &xres_len); @@ -198,105 +262,213 @@ static int hss_ogs_diam_s6a_air_cb( struct msg **msg, struct avp *avp, /* Set the Authentication-Info */ ret = fd_msg_avp_new(ogs_diam_s6a_authentication_info, 0, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_new(ogs_diam_s6a_e_utran_vector, 0, &avp_e_utran_vector); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Authentication-Info AVP"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_new(ogs_diam_s6a_e_utran_vector, 0, &avp_e_utran_vector); + if (ret != 0) { + ogs_error("Failed to create E-UTRAN-Vector AVP"); + error_occurred = 1; + goto out; + } + + /* Add RAND */ ret = fd_msg_avp_new(ogs_diam_s6a_rand, 0, &avp_rand); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create RAND AVP"); + error_occurred = 1; + goto out; + } val.os.data = auth_info.rand; val.os.len = OGS_KEY_LEN; ret = fd_msg_avp_setvalue(avp_rand, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set RAND value"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_rand); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add RAND AVP"); + error_occurred = 1; + goto out; + } + /* Add XRES */ ret = fd_msg_avp_new(ogs_diam_s6a_xres, 0, &avp_xres); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create XRES AVP"); + error_occurred = 1; + goto out; + } val.os.data = xres; val.os.len = xres_len; ret = fd_msg_avp_setvalue(avp_xres, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set XRES value"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_xres); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add XRES AVP"); + error_occurred = 1; + goto out; + } + /* Add AUTN */ ret = fd_msg_avp_new(ogs_diam_s6a_autn, 0, &avp_autn); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create AUTN AVP"); + error_occurred = 1; + goto out; + } val.os.data = autn; val.os.len = OGS_AUTN_LEN; ret = fd_msg_avp_setvalue(avp_autn, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set AUTN value"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_autn); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add AUTN AVP"); + error_occurred = 1; + goto out; + } + /* Add KASME */ ret = fd_msg_avp_new(ogs_diam_s6a_kasme, 0, &avp_kasme); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create KASME AVP"); + error_occurred = 1; + goto out; + } val.os.data = kasme; val.os.len = OGS_SHA256_DIGEST_SIZE; ret = fd_msg_avp_setvalue(avp_kasme, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set KASME value"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_kasme); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add KASME AVP"); + error_occurred = 1; + goto out; + } + /* Add E-UTRAN-Vector to Authentication-Info */ ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_e_utran_vector); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add E-UTRAN-Vector AVP"); + error_occurred = 1; + goto out; + } + + /* Add Authentication-Info to answer */ ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Authentication-Info AVP"); + error_occurred = 1; + goto out; + } - /* 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 (!error_occurred) { + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State 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-Session-State AVP"); + error_occurred = 1; + goto out; + } - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_S6A_APPLICATION_ID); - ogs_assert(ret == 0); + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_S6A_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } - ogs_debug("Tx Authentication-Information-Answer"); + ogs_debug("Tx Authentication-Information-Answer"); - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(s6a.rx_air); - HSS_DIAM_PRIV_STATS_INC(s6a.tx_aia); - ) + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(s6a.rx_air); + HSS_DIAM_PRIV_STATS_INC(s6a.tx_aia); + ) - return 0; + return 0; + } out: - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); + /* Error handling */ + if (ans) { + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + if (ret != 0) { + ogs_error("Failed to set experimental result code"); + } + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_S6A_APPLICATION_ID); - ogs_assert(ret == 0); + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_S6A_APPLICATION_ID); - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } + } + /* Update error stats */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(s6a.rx_air); HSS_DIAM_PRIV_STATS_INC(s6a.rx_air_error); @@ -757,104 +929,161 @@ static int hss_s6a_avp_add_subscription_data( } /* Callback for incoming Update-Location-Request messages */ -static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_s6a_ulr_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int ret; - struct msg *ans, *qry; - - struct avp_hdr *hdr; - struct avp *avpch1; + struct msg *ans = NULL, *qry = NULL; + struct avp_hdr *hdr = NULL; + struct avp *avpch1 = NULL; union avp_value val; char *imsi_bcd = NULL; char imeisv_bcd[OGS_MAX_IMEISV_BCD_LEN+1]; - char *mme_host = NULL; char *mme_realm = NULL; int rv; uint32_t result_code = 0; ogs_subscription_data_t subscription_data; - ogs_plmn_id_t visited_plmn_id; - - ogs_assert(msg); + int error_occurred = 0; ogs_debug("Rx Update-Location-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + + /* Initialize variables */ memset(&subscription_data, 0, sizeof(ogs_subscription_data_t)); + memset(imeisv_bcd, 0, sizeof(imeisv_bcd)); + memset(&visited_plmn_id, 0, sizeof(visited_plmn_id)); /* 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; /* Get User-Name AVP */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search User-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + if (avp) { ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } imsi_bcd = ogs_strndup( (char*)hdr->avp_value->os.data, ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN) + 1); - ogs_assert(imsi_bcd); + if (!imsi_bcd) { + ogs_error("Failed to duplicate IMSI"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } } else { - ogs_error("no_User-Name"); + ogs_error("No User-Name AVP found"); result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } + /* Get subscription data from database */ rv = hss_db_subscription_data(imsi_bcd, &subscription_data); if (rv != OGS_OK) { - ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot get Subscription-Data for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; + error_occurred = 1; goto out; } /* Get Origin-Host */ ret = fd_msg_search_avp(qry, ogs_diam_origin_host, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Origin-Host AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + if (avp) { ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Origin-Host AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } mme_host = ogs_strndup( (char*)hdr->avp_value->os.data, ogs_min(hdr->avp_value->os.len, OGS_MAX_FQDN_LEN) + 1); - ogs_assert(mme_host); + if (!mme_host) { + ogs_error("Failed to duplicate MME host"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } } else { - ogs_error("no_Origin-Host"); + ogs_error("No Origin-Host AVP found"); result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } /* Get Origin-Realm */ ret = fd_msg_search_avp(qry, ogs_diam_origin_realm, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Origin-Realm AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + if (avp) { ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Origin-Realm AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } mme_realm = ogs_strndup( (char*)hdr->avp_value->os.data, ogs_min(hdr->avp_value->os.len, OGS_MAX_FQDN_LEN) + 1); - ogs_assert(mme_realm); + if (!mme_realm) { + ogs_error("Failed to duplicate MME realm"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } } else { - ogs_error("no_Origin-Realm"); + ogs_error("No Origin-Realm AVP found"); result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } - ogs_assert(mme_host); - ogs_assert(mme_realm); - - /* If UE is not purged at MME, determine if the MME sending the ULR - * is different from the one that was last used. if so, send CLR. - */ + /* Check if CLR needs to be sent to previous MME */ if (subscription_data.mme_host != NULL && subscription_data.mme_realm != NULL) { if (!subscription_data.purge_flag) { @@ -870,250 +1099,412 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, } /* Update database with current MME and timestamp */ - ogs_assert(OGS_OK == hss_db_update_mme(imsi_bcd, mme_host, mme_realm, - false)); + rv = hss_db_update_mme(imsi_bcd, mme_host, mme_realm, false); + if (rv != OGS_OK) { + ogs_error("Failed to update MME info for IMSI: %s", imsi_bcd); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + /* Process Terminal-Information if present */ ret = fd_msg_search_avp(qry, ogs_diam_s6a_terminal_information, &avp); - ogs_assert(ret == 0); - if (avp) { + if (ret == 0 && avp) { char *p, *last; p = imeisv_bcd; last = imeisv_bcd + OGS_MAX_IMEISV_BCD_LEN + 1; ret = fd_avp_search_avp(avp, ogs_diam_s6a_imei, &avpch1); - ogs_assert(ret == 0); - if (avpch1) { + if (ret == 0 && avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - if (hdr->avp_value->os.len) { - char *s = NULL; - - ogs_assert(hdr->avp_value->os.data); - s = ogs_strndup( + if (ret == 0 && hdr && hdr->avp_value->os.len) { + char *s = ogs_strndup( (const char *)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(s); - p = ogs_slprintf(p, last, "%s", s); - - ogs_free(s); + if (s) { + p = ogs_slprintf(p, last, "%s", s); + ogs_free(s); + } } } ret = fd_avp_search_avp(avp, ogs_diam_s6a_software_version, &avpch1); - ogs_assert(ret == 0); - if (avpch1) { + if (ret == 0 && avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - if (hdr->avp_value->os.len) { - char *s = NULL; - - ogs_assert(hdr->avp_value->os.data); - s = ogs_strndup( + if (ret == 0 && hdr && hdr->avp_value->os.len) { + char *s = ogs_strndup( (const char *)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(s); - p = ogs_slprintf(p, last, "%s", s); - - ogs_free(s); + if (s) { + p = ogs_slprintf(p, last, "%s", s); + ogs_free(s); + } } } - ogs_assert(OGS_OK == hss_db_update_imeisv(imsi_bcd, imeisv_bcd)); + if (strlen(imeisv_bcd) > 0) { + rv = hss_db_update_imeisv(imsi_bcd, imeisv_bcd); + if (rv != OGS_OK) { + ogs_warn("Failed to update IMEISV for IMSI: %s", imsi_bcd); + } + } } + /* Get Visited-PLMN-Id */ ret = fd_msg_search_avp(qry, ogs_diam_visited_plmn_id, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - memcpy(&visited_plmn_id, hdr->avp_value->os.data, - ogs_min(hdr->avp_value->os.len, sizeof(visited_plmn_id))); + if (ret != 0) { + ogs_error("Failed to search Visited-PLMN-Id AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Visited-PLMN-Id AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + memcpy(&visited_plmn_id, hdr->avp_value->os.data, + ogs_min(hdr->avp_value->os.len, sizeof(visited_plmn_id))); + } + + /* Check ULR-Flags */ ret = fd_msg_search_avp(qry, ogs_diam_s6a_ulr_flags, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - if (!(hdr->avp_value->u32 & OGS_DIAM_S6A_ULR_SKIP_SUBSCRIBER_DATA)) { - /* Set the Subscription Data */ - ret = fd_msg_avp_new(ogs_diam_s6a_subscription_data, 0, &avp); - ogs_assert(ret == 0); - rv = hss_s6a_avp_add_subscription_data(&subscription_data, - avp, OGS_DIAM_S6A_SUBDATA_ALL); - if (rv != OGS_OK) { - result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION; + if (ret != 0) { + ogs_error("Failed to search ULR-Flags AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0 || !hdr) { + ogs_error("Failed to get ULR-Flags AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + + if (!(hdr->avp_value->u32 & OGS_DIAM_S6A_ULR_SKIP_SUBSCRIBER_DATA)) { + /* Set the Subscription Data */ + ret = fd_msg_avp_new(ogs_diam_s6a_subscription_data, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Subscription-Data AVP"); + error_occurred = 1; + goto out; + } + + rv = hss_s6a_avp_add_subscription_data(&subscription_data, + avp, OGS_DIAM_S6A_SUBDATA_ALL); + if (rv != OGS_OK) { + ogs_error("Failed to add subscription data"); + result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_error("Failed to add Subscription-Data AVP"); + error_occurred = 1; + goto out; + } + } + } + + if (!error_occurred) { + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State 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-Session-State AVP"); + error_occurred = 1; + goto out; + } + + /* Set the ULA Flags */ + ret = fd_msg_avp_new(ogs_diam_s6a_ula_flags, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create ULA-Flags AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_S6A_ULA_FLAGS_MME_REGISTERED_FOR_SMS; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set ULA-Flags 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 ULA-Flags AVP"); + error_occurred = 1; + goto out; + } + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_S6A_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } + + /* Set Supported-Features (Feature-List-ID: 1) */ + ret = fd_msg_avp_new(ogs_diam_s6a_supported_features, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Supported-Features AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_new(ogs_diam_vendor_id, 0, &avpch1); + if (ret != 0) { + ogs_error("Failed to create Vendor-Id AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_3GPP_VENDOR_ID; + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set Vendor-Id value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add Vendor-Id AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_new(ogs_diam_s6a_feature_list_id, 0, &avpch1); + if (ret != 0) { + ogs_error("Failed to create Feature-List-ID AVP"); + error_occurred = 1; + goto out; + } + val.i32 = 1; + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set Feature-List-ID value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add Feature-List-ID AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_new(ogs_diam_s6a_feature_list, 0, &avpch1); + if (ret != 0) { + ogs_error("Failed to create Feature-List AVP"); + error_occurred = 1; + goto out; + } + val.u32 = 0x0000000b; + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set Feature-List value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add Feature-List AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_error("Failed to add Supported-Features AVP"); + error_occurred = 1; + goto out; + } + + /* Set Supported-Features (Feature-List-ID: 2) */ + ret = fd_msg_avp_new(ogs_diam_s6a_supported_features, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create second Supported-Features AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_new(ogs_diam_vendor_id, 0, &avpch1); + if (ret != 0) { + ogs_error("Failed to create second Vendor-Id AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_3GPP_VENDOR_ID; + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set second Vendor-Id value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add second Vendor-Id AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_new(ogs_diam_s6a_feature_list_id, 0, &avpch1); + if (ret != 0) { + ogs_error("Failed to create second Feature-List-ID AVP"); + error_occurred = 1; + goto out; + } + val.i32 = 2; + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set second Feature-List-ID value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add second Feature-List-ID AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_new(ogs_diam_s6a_feature_list, 0, &avpch1); + if (ret != 0) { + ogs_error("Failed to create second Feature-List AVP"); + error_occurred = 1; + goto out; + } + val.u32 = 0x08000001; + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set second Feature-List value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add second Feature-List AVP"); + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_error("Failed to add second Supported-Features AVP"); + error_occurred = 1; + goto out; + } + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } + + ogs_debug("Tx Update-Location-Answer"); + + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(s6a.rx_ulr); + HSS_DIAM_PRIV_STATS_INC(s6a.tx_ula); + ) + + /* Cleanup resources */ + ogs_subscription_data_free(&subscription_data); + if (imsi_bcd) ogs_free(imsi_bcd); + if (mme_host) ogs_free(mme_host); + if (mme_realm) ogs_free(mme_realm); + + return 0; } - /* 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); - - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 ULA Flags */ - ret = fd_msg_avp_new(ogs_diam_s6a_ula_flags, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_S6A_ULA_FLAGS_MME_REGISTERED_FOR_SMS; - 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 Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_S6A_APPLICATION_ID); - ogs_assert(ret == 0); - - /* - * AVP 628 Supported-Features - * AVP 629 Feature-List-ID: 1 - * AVP 630 Feature-List: (misc subscriber restrictions) - */ - ret = fd_msg_avp_new(ogs_diam_s6a_supported_features, 0, &avp); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_vendor_id, 0, &avpch1); - ogs_assert(ret == 0); - val.i32 = OGS_3GPP_VENDOR_ID; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_s6a_feature_list_id, 0, &avpch1); - ogs_assert(ret == 0); - val.i32 = 1; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_s6a_feature_list, 0, &avpch1); - ogs_assert(ret == 0); - val.u32 = 0x0000000b; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* - * AVP 628 Supported-Features - * AVP 629 Feature-List-ID: 2 - * AVP 630 Feature-List: (“NR as Secondary RAT: Supported”) - */ - ret = fd_msg_avp_new(ogs_diam_s6a_supported_features, 0, &avp); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_vendor_id, 0, &avpch1); - ogs_assert(ret == 0); - val.i32 = OGS_3GPP_VENDOR_ID; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_s6a_feature_list_id, 0, &avpch1); - ogs_assert(ret == 0); - val.i32 = 2; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_s6a_feature_list, 0, &avpch1); - ogs_assert(ret == 0); - val.u32 = 0x08000001; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - - ogs_debug("Tx Update-Location-Answer"); - - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(s6a.rx_ulr); - HSS_DIAM_PRIV_STATS_INC(s6a.tx_ula); - ) - - ogs_subscription_data_free(&subscription_data); - - if (imsi_bcd) - ogs_free(imsi_bcd); - if (mme_host) - ogs_free(mme_host); - if (mme_realm) - ogs_free(mme_realm); - - return 0; - out: - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); + /* Error handling */ + if (ans) { + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + if (ret != 0) { + ogs_error("Failed to set experimental result code"); + } + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_S6A_APPLICATION_ID); - ogs_assert(ret == 0); + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_S6A_APPLICATION_ID); - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } + } + /* Update error stats */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(s6a.rx_ulr); HSS_DIAM_PRIV_STATS_INC(s6a.rx_ulr_error); ) + /* Cleanup resources */ ogs_subscription_data_free(&subscription_data); - - if (imsi_bcd) - ogs_free(imsi_bcd); - if (mme_host) - ogs_free(mme_host); - if (mme_realm) - ogs_free(mme_realm); + if (imsi_bcd) ogs_free(imsi_bcd); + if (mme_host) ogs_free(mme_host); + if (mme_realm) ogs_free(mme_realm); return 0; } /* Callback for incoming Purge-UE-Request messages */ -static int hss_ogs_diam_s6a_pur_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_s6a_pur_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int ret, rv; - - struct msg *ans, *qry; - struct avp_hdr *hdr; + struct msg *ans = NULL, *qry = NULL; + struct avp_hdr *hdr = NULL; union avp_value val; ogs_subscription_data_t subscription_data; @@ -1123,129 +1514,267 @@ static int hss_ogs_diam_s6a_pur_cb( struct msg **msg, struct avp *avp, char mme_realm[OGS_MAX_FQDN_LEN+1]; uint32_t result_code = 0; - - ogs_assert(msg); + int error_occurred = 0; + int use_experimental_code = 1; ogs_debug("Rx Purge-UE-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + + /* Initialize variables */ memset(&subscription_data, 0, sizeof(ogs_subscription_data_t)); + memset(imsi_bcd, 0, sizeof(imsi_bcd)); + memset(mme_host, 0, sizeof(mme_host)); + memset(mme_realm, 0, sizeof(mme_realm)); /* 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; + /* Get User-Name AVP */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); - ogs_assert(ret == 0); - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data, - ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1); - - rv = hss_db_subscription_data(imsi_bcd, &subscription_data); - if (rv != OGS_OK) { - ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd); - result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; + if (ret != 0) { + ogs_error("Failed to search User-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No User-Name AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } - ret = fd_msg_search_avp(qry, ogs_diam_origin_host, &avp); - ogs_assert(ret == 0); ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + + ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data, + ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1); + + /* Get subscription data from database */ + rv = hss_db_subscription_data(imsi_bcd, &subscription_data); + if (rv != OGS_OK) { + ogs_error("Cannot get Subscription-Data for IMSI: %s", imsi_bcd); + result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; + error_occurred = 1; + goto out; + } + + /* Get Origin-Host */ + ret = fd_msg_search_avp(qry, ogs_diam_origin_host, &avp); + if (ret != 0) { + ogs_error("Failed to search Origin-Host AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Origin-Host AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Origin-Host AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + ogs_cpystrn(mme_host, (char*)hdr->avp_value->os.data, ogs_min(hdr->avp_value->os.len, OGS_MAX_FQDN_LEN)+1); + /* Get Origin-Realm */ ret = fd_msg_search_avp(qry, ogs_diam_origin_realm, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Origin-Realm AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Origin-Realm AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Origin-Realm AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + ogs_cpystrn(mme_realm, (char*)hdr->avp_value->os.data, ogs_min(hdr->avp_value->os.len, OGS_MAX_FQDN_LEN)+1); - if (!strcmp(subscription_data.mme_host, mme_host) && - !strcmp(subscription_data.mme_realm, mme_realm)) { + /* Check if the MME matches the one in subscription data */ + if (subscription_data.mme_host && subscription_data.mme_realm && + !strcmp(subscription_data.mme_host, mme_host) && + !strcmp(subscription_data.mme_realm, mme_realm)) { + rv = hss_db_update_mme(imsi_bcd, mme_host, mme_realm, true); if (rv != OGS_OK) { - ogs_error("Cannot update UE Purged at MME flag:'%s'", imsi_bcd); + ogs_error("Cannot update UE Purged at MME flag: %s", imsi_bcd); ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_UNABLE_TO_COMPLY", NULL, NULL, 1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set DIAMETER_UNABLE_TO_COMPLY"); + } + use_experimental_code = 0; + error_occurred = 1; goto outnoexp; } } - /* Set the PUA Flags */ - ret = fd_msg_avp_new(ogs_diam_s6a_pua_flags, 0, &avp); - ogs_assert(ret == 0); - if (!strcmp(subscription_data.mme_host, mme_host) && + if (!error_occurred) { + /* Set the PUA Flags */ + ret = fd_msg_avp_new(ogs_diam_s6a_pua_flags, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create PUA-Flags AVP"); + error_occurred = 1; + goto out; + } + + if (subscription_data.mme_host && subscription_data.mme_realm && + !strcmp(subscription_data.mme_host, mme_host) && !strcmp(subscription_data.mme_realm, mme_realm)) { - val.i32 = OGS_DIAM_S6A_PUA_FLAGS_FREEZE_MTMSI; - } else { - val.i32 = 0; + val.i32 = OGS_DIAM_S6A_PUA_FLAGS_FREEZE_MTMSI; + } else { + val.i32 = 0; + } + + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set PUA-Flags 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 PUA-Flags AVP"); + error_occurred = 1; + goto out; + } + + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State 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-Session-State AVP"); + error_occurred = 1; + goto out; + } + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_S6A_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } + + ogs_debug("Tx Purge-UE-Answer"); + + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(s6a.rx_pur); + HSS_DIAM_PRIV_STATS_INC(s6a.tx_pua); + ) + + ogs_subscription_data_free(&subscription_data); + return 0; } - 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, and Result-Code AVPs */ - ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); - ogs_assert(ret == 0); - - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_S6A_APPLICATION_ID); - ogs_assert(ret == 0); - - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - - ogs_debug("Tx Purge-UE-Answer"); - - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(s6a.rx_pur); - HSS_DIAM_PRIV_STATS_INC(s6a.tx_pua); - ) - - ogs_subscription_data_free(&subscription_data); - - return 0; out: - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); + /* Error handling with experimental result code */ + if (ans && use_experimental_code) { + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + if (ret != 0) { + ogs_error("Failed to set experimental result code"); + } + } + } + outnoexp: - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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); + /* Common error handling */ + if (ans) { + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_S6A_APPLICATION_ID); - ogs_assert(ret == 0); + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_S6A_APPLICATION_ID); - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } + } + /* Update error stats */ OGS_DIAM_STATS_MTX( OGS_DIAM_STATS_INC(nb_echoed); HSS_DIAM_PRIV_STATS_INC(s6a.rx_pur); @@ -1253,7 +1782,6 @@ outnoexp: ) ogs_subscription_data_free(&subscription_data); - return 0; } @@ -1390,54 +1918,87 @@ void hss_s6a_send_clr(char *imsi_bcd, char *mme_host, char *mme_realm, static void hss_s6a_cla_cb(void *data, struct msg **msg) { int ret; - struct sess_state *sess_data = NULL; - struct session *session; - int new; + struct session *session = NULL; + int new = 0; + int error_occurred = 0; ogs_debug("[HSS] Rx Cancel-Location-Answer"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + error_occurred = 1; + goto cleanup; + } + /* Search the session, retrieve its data */ ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); if (ret != 0) { - ogs_error("fd_msg_sess_get() failed"); - goto out; - } - if (new != 0) { - ogs_error("fd_msg_sess_get() failed"); - goto out; + ogs_error("fd_msg_sess_get() failed with error: %d", ret); + error_occurred = 1; + goto cleanup; } + if (new != 0) { + ogs_error("Session should already exist, but new session flag is set"); + error_occurred = 1; + goto cleanup; + } + + if (!session) { + ogs_error("Session is NULL"); + error_occurred = 1; + goto cleanup; + } + + /* Retrieve session state */ ret = fd_sess_state_retrieve(hss_s6a_reg, session, &sess_data); if (ret != 0) { - ogs_error("fd_sess_state_retrieve() failed"); - goto out; + ogs_error("fd_sess_state_retrieve() failed with error: %d", ret); + error_occurred = 1; + goto cleanup; } + if (!sess_data) { - ogs_error("fd_sess_state_retrieve() failed"); - goto out; + ogs_error("Session state is NULL"); + error_occurred = 1; + goto cleanup; } + + /* Validate data pointer consistency */ if ((void *)sess_data != data) { - ogs_error("fd_sess_state_retrieve() failed"); - goto out; + ogs_error("Session data pointer mismatch - expected: %p, got: %p", + data, sess_data); + error_occurred = 1; + goto cleanup; } - ret = fd_msg_free(*msg); - ogs_assert(ret == 0); - *msg = NULL; +cleanup: + /* Always try to free the message if it exists */ + if (msg && *msg) { + ret = fd_msg_free(*msg); + if (ret != 0) { + ogs_error("Failed to free message: %d", ret); + error_occurred = 1; + } + *msg = NULL; + } - state_cleanup(sess_data, NULL, NULL); + /* Clean up session state if it exists */ + if (sess_data) { + state_cleanup(sess_data, NULL, NULL); + sess_data = NULL; + } + /* Update statistics */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(s6a.rx_cla); + if (error_occurred) + HSS_DIAM_PRIV_STATS_INC(s6a.rx_cla_error); ) + return; - -out: - OGS_DIAM_STATS_MTX( - HSS_DIAM_PRIV_STATS_INC(s6a.rx_cla); - HSS_DIAM_PRIV_STATS_INC(s6a.rx_cla_error); - ) } /* HSS Sends Insert Subscriber Data Request to MME */ @@ -1605,54 +2166,86 @@ int hss_s6a_send_idr(char *imsi_bcd, uint32_t idr_flags, uint32_t subdata_mask) static void hss_s6a_ida_cb(void *data, struct msg **msg) { int ret; - struct sess_state *sess_data = NULL; - struct session *session; - int new; + struct session *session = NULL; + int new = 0; + int error_occurred = 0; ogs_debug("[HSS] Rx Insert-Subscriber-Data-Answer"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + error_occurred = 1; + goto cleanup; + } + /* Search the session, retrieve its data */ ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); if (ret != 0) { - ogs_error("fd_msg_sess_get() failed"); - goto out; - } - if (new != 0) { - ogs_error("fd_msg_sess_get() failed"); - goto out; + ogs_error("fd_msg_sess_get() failed with error: %d", ret); + error_occurred = 1; + goto cleanup; } + if (new != 0) { + ogs_error("Session should already exist, but new session flag is set"); + error_occurred = 1; + goto cleanup; + } + + if (!session) { + ogs_error("Session is NULL"); + error_occurred = 1; + goto cleanup; + } + + /* Retrieve session state */ ret = fd_sess_state_retrieve(hss_s6a_reg, session, &sess_data); if (ret != 0) { - ogs_error("fd_sess_state_retrieve() failed"); - goto out; + ogs_error("fd_sess_state_retrieve() failed with error: %d", ret); + error_occurred = 1; + goto cleanup; } + if (!sess_data) { - ogs_error("fd_sess_state_retrieve() failed"); - goto out; + ogs_error("Session state is NULL"); + error_occurred = 1; + goto cleanup; } + + /* Validate data pointer consistency */ if ((void *)sess_data != data) { - ogs_error("fd_sess_state_retrieve() failed"); - goto out; + ogs_error("Session data pointer mismatch - expected: %p, got: %p", + data, sess_data); + error_occurred = 1; + goto cleanup; } - ret = fd_msg_free(*msg); - ogs_assert(ret == 0); - *msg = NULL; +cleanup: + /* Always try to free the message if it exists */ + if (msg && *msg) { + ret = fd_msg_free(*msg); + if (ret != 0) { + ogs_error("Failed to free message: %d", ret); + error_occurred = 1; + } + *msg = NULL; + } - state_cleanup(sess_data, NULL, NULL); + /* Clean up session state if it exists */ + if (sess_data) { + state_cleanup(sess_data, NULL, NULL); + sess_data = NULL; + } + /* Update statistics */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(s6a.rx_ida); + if (error_occurred) + HSS_DIAM_PRIV_STATS_INC(s6a.rx_ida_error); ) - return; -out: - OGS_DIAM_STATS_MTX( - HSS_DIAM_PRIV_STATS_INC(s6a.rx_ida); - HSS_DIAM_PRIV_STATS_INC(s6a.rx_ida_error); - ) return; } diff --git a/src/hss/hss-swx-path.c b/src/hss/hss-swx-path.c index 881d6a10a..1cad071fa 100644 --- a/src/hss/hss-swx-path.c +++ b/src/hss/hss-swx-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -43,84 +43,135 @@ static int hss_ogs_diam_swx_fb_cb(struct msg **msg, struct avp *avp, } /* Callback for incoming Multimedia-Auth-Request messages */ -static int hss_ogs_diam_swx_mar_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_swx_mar_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int rv, ret; uint32_t result_code = 0; - - struct msg *ans, *qry; - + struct msg *ans = NULL, *qry = NULL; struct avp *sip_auth_data_item_avp = NULL; struct avp *authentication_scheme_avp = NULL; struct avp *sip_authorization_avp = NULL; - struct avp *avpch = NULL; - struct avp_hdr *hdr; + struct avp_hdr *hdr = NULL; union avp_value val; char *user_name = NULL; char *authentication_scheme = NULL; - char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; ogs_dbi_auth_info_t auth_info; uint8_t zero[OGS_RAND_LEN]; - uint8_t authenticate[OGS_KEY_LEN*2]; - uint8_t opc[OGS_KEY_LEN]; uint8_t sqn[OGS_SQN_LEN]; - uint8_t autn[OGS_AUTN_LEN]; uint8_t ik[OGS_KEY_LEN]; uint8_t ck[OGS_KEY_LEN]; uint8_t ak[OGS_AK_LEN]; uint8_t xres[OGS_MAX_RES_LEN]; size_t xres_len = 8; - uint8_t mac_s[OGS_MAC_S_LEN]; - ogs_assert(msg); + int error_occurred = 0; ogs_debug("Rx Multimedia-Auth-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + + /* Initialize variables */ + memset(imsi_bcd, 0, sizeof(imsi_bcd)); + memset(&auth_info, 0, sizeof(auth_info)); + /* 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; /* Get User-Name AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search User-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No User-Name AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } user_name = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(user_name); + if (!user_name) { + ogs_error("Failed to duplicate User-Name"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } ogs_extract_digit_from_string(imsi_bcd, user_name); /* Get the SIP-Auth-Data-Item AVP (Mandatory) */ ret = fd_msg_search_avp( qry, ogs_diam_cx_sip_auth_data_item, &sip_auth_data_item_avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search SIP-Auth-Data-Item AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!sip_auth_data_item_avp) { + ogs_error("No SIP-Auth-Data-Item AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(sip_auth_data_item_avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get SIP-Auth-Data-Item AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } /* Get the Authentication-Scheme AVP */ ret = fd_msg_search_avp(sip_auth_data_item_avp, ogs_diam_cx_sip_authentication_scheme, &authentication_scheme_avp); - ogs_assert(ret == 0); - if (authentication_scheme_avp) { + if (ret == 0 && authentication_scheme_avp) { ret = fd_msg_avp_hdr(authentication_scheme_avp, &hdr); - ogs_assert(ret == 0); - - authentication_scheme = ogs_strndup( - (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(authentication_scheme); + if (ret == 0 && hdr) { + authentication_scheme = ogs_strndup( + (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); + if (!authentication_scheme) { + ogs_error("Failed to duplicate Authentication-Scheme"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + } } /* EAP-AKA is only supported */ @@ -130,14 +181,16 @@ static int hss_ogs_diam_swx_mar_cb( struct msg **msg, struct avp *avp, ogs_error("Authentication-Scheme[%s] is not supported", authentication_scheme); result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED; + error_occurred = 1; goto out; } /* DB : HSS Auth-Info */ rv = hss_db_auth_info(imsi_bcd, &auth_info); if (rv != OGS_OK) { - ogs_error("Cannot get IMS-Data for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot get IMS-Data for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN; + error_occurred = 1; goto out; } @@ -154,47 +207,51 @@ static int hss_ogs_diam_swx_mar_cb( struct msg **msg, struct avp *avp, /* Get the SIP-Authorization AVP */ ret = fd_msg_search_avp(sip_auth_data_item_avp, ogs_diam_cx_sip_authorization, &sip_authorization_avp); - ogs_assert(ret == 0); - if (sip_authorization_avp) { + if (ret == 0 && sip_authorization_avp) { ret = fd_msg_avp_hdr(sip_authorization_avp, &hdr); - ogs_assert(ret == 0); + if (ret == 0 && hdr) { + ogs_auc_sqn(opc, auth_info.k, + hdr->avp_value->os.data, + hdr->avp_value->os.data + OGS_RAND_LEN, + sqn, mac_s); + if (memcmp(mac_s, hdr->avp_value->os.data + + OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) { + ogs_random(auth_info.rand, OGS_RAND_LEN); + auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN); + /* 33.102 C.3.4 Guide : IND + 1 */ + auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN; + } else { + ogs_error("Re-synch MAC failed for IMSI: %s", imsi_bcd); - ogs_auc_sqn(opc, auth_info.k, - hdr->avp_value->os.data, - hdr->avp_value->os.data + OGS_RAND_LEN, - sqn, mac_s); - if (memcmp(mac_s, hdr->avp_value->os.data + - OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) { - ogs_random(auth_info.rand, OGS_RAND_LEN); - auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN); - /* 33.102 C.3.4 Guide : IND + 1 */ - auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN; - } else { - ogs_error("Re-synch MAC failed for IMSI:`%s`", imsi_bcd); - ogs_log_print(OGS_LOG_ERROR, "MAC_S: "); - ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN); - ogs_log_hexdump(OGS_LOG_ERROR, - (void*)(hdr->avp_value->os.data + - OGS_RAND_LEN + OGS_SQN_LEN), - OGS_MAC_S_LEN); - ogs_log_print(OGS_LOG_ERROR, "SQN: "); - ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN); - result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED; - goto out; + ogs_log_print(OGS_LOG_ERROR, "MAC_S: "); + ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN); + ogs_log_hexdump(OGS_LOG_ERROR, + (void*)(hdr->avp_value->os.data + + OGS_RAND_LEN + OGS_SQN_LEN), + OGS_MAC_S_LEN); + ogs_log_print(OGS_LOG_ERROR, "SQN: "); + ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN); + + result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED; + error_occurred = 1; + goto out; + } } } rv = hss_db_update_sqn(imsi_bcd, auth_info.rand, auth_info.sqn); if (rv != OGS_OK) { - ogs_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot update rand and sqn for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE; + error_occurred = 1; goto out; } rv = hss_db_increment_sqn(imsi_bcd); if (rv != OGS_OK) { - ogs_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd); + ogs_error("Cannot increment sqn for IMSI: %s", imsi_bcd); result_code = OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE; + error_occurred = 1; goto out; } @@ -227,188 +284,325 @@ static int hss_ogs_diam_swx_mar_cb( struct msg **msg, struct avp *avp, ogs_log_print(OGS_LOG_DEBUG, "xles - "); ogs_log_hexdump(OGS_LOG_DEBUG, xres, xres_len); - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_SWX_APPLICATION_ID); - ogs_assert(ret == 0); + if (!error_occurred) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_SWX_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State 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-Session-State AVP"); + error_occurred = 1; + goto out; + } - /* 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); + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } - /* Set the User-Name AVP */ - ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)user_name; - val.os.len = strlen(user_name); - 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 User-Name AVP */ + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create User-Name AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set User-Name 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 User-Name AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Number-Auth-Items AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_number_auth_items, 0, &avp); - ogs_assert(ret == 0); - val.u32 = 1; - 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 SIP-Number-Auth-Items AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_number_auth_items, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create SIP-Number-Auth-Items AVP"); + error_occurred = 1; + goto out; + } + val.u32 = 1; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Number-Auth-Items 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 SIP-Number-Auth-Items AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Auth-Data-Item AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_auth_data_item, 0, &avp); - ogs_assert(ret == 0); + /* Set the SIP-Auth-Data-Item AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_auth_data_item, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create SIP-Auth-Data-Item AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Item-Number AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_item_number, 0, &avpch); - ogs_assert(ret == 0); - val.u32 = 1; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the SIP-Item-Number AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_item_number, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create SIP-Item-Number AVP"); + error_occurred = 1; + goto out; + } + val.u32 = 1; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Item-Number value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add SIP-Item-Number AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Authentication-Scheme AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_authentication_scheme, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA; - val.os.len = strlen(OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA); - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the SIP-Authentication-Scheme AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authentication_scheme, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create SIP-Authentication-Scheme AVP"); + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA; + val.os.len = strlen(OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA); + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Authentication-Scheme value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add SIP-Authentication-Scheme AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Authenticatie AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_authenticate, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = authenticate; - val.os.len = OGS_KEY_LEN * 2; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the SIP-Authenticate AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authenticate, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create SIP-Authenticate AVP"); + error_occurred = 1; + goto out; + } + val.os.data = authenticate; + val.os.len = OGS_KEY_LEN * 2; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Authenticate value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add SIP-Authenticate AVP"); + error_occurred = 1; + goto out; + } - /* Set the SIP-Authorization AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_sip_authorization, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = xres; - val.os.len = xres_len; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the SIP-Authorization AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authorization, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create SIP-Authorization AVP"); + error_occurred = 1; + goto out; + } + val.os.data = xres; + val.os.len = xres_len; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set SIP-Authorization value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add SIP-Authorization AVP"); + error_occurred = 1; + goto out; + } - /* Set the Confidentiality-Key AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_confidentiality_key, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = ck; - val.os.len = OGS_KEY_LEN; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the Confidentiality-Key AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_confidentiality_key, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create Confidentiality-Key AVP"); + error_occurred = 1; + goto out; + } + val.os.data = ck; + val.os.len = OGS_KEY_LEN; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set Confidentiality-Key value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add Confidentiality-Key AVP"); + error_occurred = 1; + goto out; + } - /* Set the Integrity-Key AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_integrity_key, 0, &avpch); - ogs_assert(ret == 0); - val.os.data = ik; - val.os.len = OGS_KEY_LEN; - ret = fd_msg_avp_setvalue(avpch, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); - ogs_assert(ret == 0); + /* Set the Integrity-Key AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_integrity_key, 0, &avpch); + if (ret != 0) { + ogs_error("Failed to create Integrity-Key AVP"); + error_occurred = 1; + goto out; + } + val.os.data = ik; + val.os.len = OGS_KEY_LEN; + ret = fd_msg_avp_setvalue(avpch, &val); + if (ret != 0) { + ogs_error("Failed to set Integrity-Key value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + if (ret != 0) { + ogs_error("Failed to add Integrity-Key AVP"); + error_occurred = 1; + goto out; + } - ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_error("Failed to add SIP-Auth-Data-Item AVP"); + error_occurred = 1; + goto out; + } - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } - ogs_debug("Tx Multimedia-Auth-Answer"); + ogs_debug("Tx Multimedia-Auth-Answer"); - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(swx.rx_mar); - HSS_DIAM_PRIV_STATS_INC(swx.tx_maa); - ) + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(swx.rx_mar); + HSS_DIAM_PRIV_STATS_INC(swx.tx_maa); + ) - if (authentication_scheme) - ogs_free(authentication_scheme); + /* Cleanup resources */ + if (authentication_scheme) ogs_free(authentication_scheme); + if (user_name) ogs_free(user_name); - ogs_free(user_name); - - return 0; + return 0; + } out: - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_SWX_APPLICATION_ID); - ogs_assert(ret == 0); + /* Error handling */ + if (ans) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_SWX_APPLICATION_ID); - /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + } - /* Set the User-Name AVP */ - ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)user_name; - val.os.len = strlen(user_name); - 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 User-Name AVP */ + if (user_name) { + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + if (ret == 0) { + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } + } + /* Update error stats */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(swx.rx_mar); HSS_DIAM_PRIV_STATS_INC(swx.rx_mar_error); ) - if (authentication_scheme) - ogs_free(authentication_scheme); - - ogs_free(user_name); + /* Cleanup resources */ + if (authentication_scheme) ogs_free(authentication_scheme); + if (user_name) ogs_free(user_name); return 0; } /* Callback for incoming Server-Assignment-Request messages */ -static int hss_ogs_diam_swx_sar_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_swx_sar_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int rv, ret; uint32_t result_code = 0; + int error_occurred = 0; - struct msg *ans, *qry; - - struct avp_hdr *hdr; + struct msg *ans = NULL, *qry = NULL; + struct avp_hdr *hdr = NULL; union avp_value val; char *user_name = NULL; - char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; ogs_subscription_data_t subscription_data; @@ -416,27 +610,63 @@ static int hss_ogs_diam_swx_sar_cb( struct msg **msg, struct avp *avp, struct sockaddr_in sin; struct sockaddr_in6 sin6; - ogs_assert(msg); - ogs_debug("Rx Server-Assignment-Request"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return EINVAL; + } + + /* Initialize variables */ + memset(imsi_bcd, 0, sizeof(imsi_bcd)); memset(&subscription_data, 0, sizeof(ogs_subscription_data_t)); + memset(&sin, 0, sizeof(sin)); + memset(&sin6, 0, sizeof(sin6)); /* 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; + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + goto out; + } ans = *msg; /* Get User-Name AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search User-Name AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No User-Name AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get User-Name AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } user_name = ogs_strndup( (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); - ogs_assert(user_name); + if (!user_name) { + ogs_error("Failed to duplicate User-Name"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } ogs_extract_digit_from_string(imsi_bcd, user_name); @@ -445,108 +675,262 @@ static int hss_ogs_diam_swx_sar_cb( struct msg **msg, struct avp *avp, if (rv != OGS_OK) { ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd); result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; + error_occurred = 1; goto out; } /* Get Server-Assignment-Type AVP (Mandatory) */ ret = fd_msg_search_avp(qry, ogs_diam_cx_server_assignment_type, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Server-Assignment-Type AVP"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + + if (!avp) { + ogs_error("No Server-Assignment-Type AVP found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0 || !hdr) { + ogs_error("Failed to get Server-Assignment-Type AVP header"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + if (hdr->avp_value->i32 == OGS_DIAM_CX_SERVER_ASSIGNMENT_REGISTRATION || hdr->avp_value->i32 == OGS_DIAM_CX_SERVER_ASSIGNMENT_AAA_USER_DATA_REQUEST) { - struct avp *avp_subscription_id; - struct avp *avp_subscription_id_type, *avp_subscription_id_data; - struct avp *avp_non_3gpp_ip_access, *avp_non_3gpp_ip_access_apn; - struct avp *avp_ambr, *avp_max_bandwidth_ul, *avp_max_bandwidth_dl; + struct avp *avp_subscription_id = NULL; + struct avp *avp_subscription_id_type = NULL; + struct avp *avp_subscription_id_data = NULL; + struct avp *avp_non_3gpp_ip_access = NULL; + struct avp *avp_non_3gpp_ip_access_apn = NULL; + struct avp *avp_ambr = NULL; + struct avp *avp_max_bandwidth_ul = NULL; + struct avp *avp_max_bandwidth_dl = NULL; /* Set the APN Configuration Profile */ - struct avp *context_identifier; + struct avp *context_identifier = NULL; int i; /* Set the Non-3GPP-User-Data */ ret = fd_msg_avp_new(ogs_diam_swx_non_3gpp_user_data, 0, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Non-3GPP-User-Data AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set Subscription-Id */ - if (subscription_data.num_of_msisdn >= 1) { + if (subscription_data.num_of_msisdn >= 1) { ret = fd_msg_avp_new(ogs_diam_subscription_id, 0, &avp_subscription_id); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Subscription-Id AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_subscription_id_type, 0, &avp_subscription_id_type); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Subscription-Id-Type AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_E164; - ret = fd_msg_avp_setvalue (avp_subscription_id_type, &val); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avp_subscription_id_type, &val); + if (ret != 0) { + ogs_error("Failed to set Subscription-Id-Type value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp_subscription_id, MSG_BRW_LAST_CHILD, avp_subscription_id_type); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Subscription-Id-Type AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_subscription_id_data, 0, &avp_subscription_id_data); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Subscription-Id-Data AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)subscription_data.msisdn[0].bcd; val.os.len = strlen(subscription_data.msisdn[0].bcd); - ret = fd_msg_avp_setvalue (avp_subscription_id_data, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp_subscription_id, MSG_BRW_LAST_CHILD, + ret = fd_msg_avp_setvalue(avp_subscription_id_data, &val); + if (ret != 0) { + ogs_error("Failed to set Subscription-Id-Data value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_add(avp_subscription_id, MSG_BRW_LAST_CHILD, avp_subscription_id_data); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Subscription-Id-Data AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_subscription_id); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Subscription-Id AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } } /* Set Non-3GPP-IP-Access */ ret = fd_msg_avp_new(ogs_diam_swx_non_3gpp_ip_access, 0, &avp_non_3gpp_ip_access); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Non-3GPP-IP-Access AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_SWX_NON_3GPP_SUBSCRIPTION_ALLOWED; ret = fd_msg_avp_setvalue(avp_non_3gpp_ip_access, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Non-3GPP-IP-Access value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_non_3gpp_ip_access); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Non-3GPP-IP-Access AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set Non-3GPP-IP-Access-APN */ ret = fd_msg_avp_new(ogs_diam_swx_non_3gpp_ip_access_apn, 0, &avp_non_3gpp_ip_access_apn); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Non-3GPP-IP-Access-APN AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.i32 = OGS_DIAM_SWX_NON_3GPP_APNS_ENABLE; ret = fd_msg_avp_setvalue(avp_non_3gpp_ip_access_apn, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Non-3GPP-IP-Access-APN value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_non_3gpp_ip_access_apn); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Non-3GPP-IP-Access-APN AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set the AMBR */ ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create AMBR AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_new( ogs_diam_s6a_max_bandwidth_ul, 0, &avp_max_bandwidth_ul); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Max-Bandwidth-UL AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.u32 = ogs_uint64_to_uint32(subscription_data.ambr.uplink); ret = fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Max-Bandwidth-UL value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add( avp_ambr, MSG_BRW_LAST_CHILD, avp_max_bandwidth_ul); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Max-Bandwidth-UL AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_new( ogs_diam_s6a_max_bandwidth_dl, 0, &avp_max_bandwidth_dl); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Max-Bandwidth-DL AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.u32 = ogs_uint64_to_uint32(subscription_data.ambr.downlink); ret = fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Max-Bandwidth-DL value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add( avp_ambr, MSG_BRW_LAST_CHILD, avp_max_bandwidth_dl); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Max-Bandwidth-DL AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_ambr); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add AMBR AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* For EPC, we'll use first Slice in Subscription */ if (subscription_data.num_of_slice) @@ -555,34 +939,60 @@ static int hss_ogs_diam_swx_sar_cb( struct msg **msg, struct avp *avp, if (!slice_data) { ogs_error("[%s] Cannot find S-NSSAI", imsi_bcd); result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION; + error_occurred = 1; goto out; } if (!slice_data->num_of_session) { ogs_error("[%s] No PDN", imsi_bcd); result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION; + error_occurred = 1; goto out; } ret = fd_msg_avp_new(ogs_diam_s6a_context_identifier, 0, &context_identifier); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Context-Identifier AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.i32 = 1; /* Context Identifier : 1 */ ret = fd_msg_avp_setvalue(context_identifier, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Context-Identifier value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, context_identifier); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Context-Identifier AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } for (i = 0; i < slice_data->num_of_session; i++) { /* Set the APN Configuration */ - struct avp *apn_configuration, *context_identifier, *pdn_type; - struct avp *served_party_ip_address, *service_selection; - struct avp *eps_subscribed_qos_profile, *qos_class_identifier; - struct avp *allocation_retention_priority, *priority_level; - struct avp *pre_emption_capability, *pre_emption_vulnerability; - struct avp *mip6_agent_info, *mip_home_agent_address; - struct avp *pdn_gw_allocation_type; - struct avp *vplmn_dynamic_address_allowed; + struct avp *apn_configuration = NULL; + struct avp *context_identifier_sub = NULL; + struct avp *pdn_type = NULL; + struct avp *served_party_ip_address = NULL; + struct avp *service_selection = NULL; + struct avp *eps_subscribed_qos_profile = NULL; + struct avp *qos_class_identifier = NULL; + struct avp *allocation_retention_priority = NULL; + struct avp *priority_level = NULL; + struct avp *pre_emption_capability = NULL; + struct avp *pre_emption_vulnerability = NULL; + struct avp *mip6_agent_info = NULL; + struct avp *mip_home_agent_address = NULL; + struct avp *pdn_gw_allocation_type = NULL; + struct avp *vplmn_dynamic_address_allowed = NULL; ogs_session_t *session = NULL; @@ -593,33 +1003,75 @@ static int hss_ogs_diam_swx_sar_cb( struct msg **msg, struct avp *avp, } session = &slice_data->session[i]; - ogs_assert(session); + if (!session) { + ogs_error("Invalid session at index %d", i); + continue; + } session->context_identifier = i+1; ret = fd_msg_avp_new(ogs_diam_s6a_apn_configuration, 0, &apn_configuration); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create APN-Configuration AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set Context-Identifier */ ret = fd_msg_avp_new(ogs_diam_s6a_context_identifier, 0, - &context_identifier); - ogs_assert(ret == 0); + &context_identifier_sub); + if (ret != 0) { + ogs_error("Failed to create Context-Identifier AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.i32 = session->context_identifier; - ret = fd_msg_avp_setvalue(context_identifier, &val); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(context_identifier_sub, &val); + if (ret != 0) { + ogs_error("Failed to set Context-Identifier value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(apn_configuration, - MSG_BRW_LAST_CHILD, context_identifier); - ogs_assert(ret == 0); + MSG_BRW_LAST_CHILD, context_identifier_sub); + if (ret != 0) { + ogs_error("Failed to add Context-Identifier AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set PDN-Type */ ret = fd_msg_avp_new(ogs_diam_s6a_pdn_type, 0, &pdn_type); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create PDN-Type AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.i32 = OGS_PDU_SESSION_TYPE_TO_DIAMETER(session->session_type); ret = fd_msg_avp_setvalue(pdn_type, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set PDN-Type value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, pdn_type); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add PDN-Type AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set Served-Party-IP-Address */ if ((session->session_type == OGS_PDU_SESSION_TYPE_IPV4 || @@ -627,14 +1079,31 @@ static int hss_ogs_diam_swx_sar_cb( struct msg **msg, struct avp *avp, session->ue_ip.ipv4) { ret = fd_msg_avp_new(ogs_diam_s6a_served_party_ip_address, 0, &served_party_ip_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Served-Party-IP-Address AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + sin.sin_family = AF_INET; sin.sin_addr.s_addr = session->ue_ip.addr; ret = fd_msg_avp_value_encode(&sin, served_party_ip_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to encode IPv4 address"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, served_party_ip_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Served-Party-IP-Address AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } } if ((session->session_type == OGS_PDU_SESSION_TYPE_IPV6 || @@ -642,281 +1111,595 @@ static int hss_ogs_diam_swx_sar_cb( struct msg **msg, struct avp *avp, session->ue_ip.ipv6) { ret = fd_msg_avp_new(ogs_diam_s6a_served_party_ip_address, 0, &served_party_ip_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Served-Party-IP-Address AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + sin6.sin6_family = AF_INET6; memcpy(sin6.sin6_addr.s6_addr, session->ue_ip.addr6, OGS_IPV6_LEN); ret = fd_msg_avp_value_encode(&sin6, served_party_ip_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to encode IPv6 address"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, served_party_ip_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Served-Party-IP-Address AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } } /* Set Service-Selection */ ret = fd_msg_avp_new(ogs_diam_service_selection, 0, &service_selection); - ogs_assert(ret == 0); - ogs_assert(session->name); + if (ret != 0) { + ogs_error("Failed to create Service-Selection AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + + if (!session->name) { + ogs_error("Session name is NULL"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + error_occurred = 1; + goto out; + } + val.os.data = (uint8_t *)session->name; val.os.len = strlen(session->name); ret = fd_msg_avp_setvalue(service_selection, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Service-Selection value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, service_selection); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Service-Selection AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set the EPS Subscribed QoS Profile */ ret = fd_msg_avp_new(ogs_diam_s6a_eps_subscribed_qos_profile, 0, &eps_subscribed_qos_profile); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create EPS-Subscribed-QoS-Profile AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_s6a_qos_class_identifier, 0, &qos_class_identifier); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create QoS-Class-Identifier AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.i32 = session->qos.index; ret = fd_msg_avp_setvalue(qos_class_identifier, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set QoS-Class-Identifier value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(eps_subscribed_qos_profile, MSG_BRW_LAST_CHILD, qos_class_identifier); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add QoS-Class-Identifier AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } - /* Set Allocation retention priority */ + /* Set Allocation retention priority */ ret = fd_msg_avp_new(ogs_diam_s6a_allocation_retention_priority, 0, &allocation_retention_priority); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Allocation-Retention-Priority"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new( ogs_diam_s6a_priority_level, 0, &priority_level); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Priority-Level AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.u32 = session->qos.arp.priority_level; ret = fd_msg_avp_setvalue(priority_level, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Priority-Level value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(allocation_retention_priority, MSG_BRW_LAST_CHILD, priority_level); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Priority-Level AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_s6a_pre_emption_capability, 0, &pre_emption_capability); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Pre-emption-Capability AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.u32 = OGS_EPC_PRE_EMPTION_DISABLED; if (session->qos.arp.pre_emption_capability == OGS_5GC_PRE_EMPTION_ENABLED) val.u32 = OGS_EPC_PRE_EMPTION_ENABLED; ret = fd_msg_avp_setvalue(pre_emption_capability, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Pre-emption-Capability value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(allocation_retention_priority, MSG_BRW_LAST_CHILD, pre_emption_capability); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Pre-emption-Capability AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_s6a_pre_emption_vulnerability, 0, &pre_emption_vulnerability); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Pre-emption-Vulnerability AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.u32 = OGS_EPC_PRE_EMPTION_DISABLED; if (session->qos.arp.pre_emption_vulnerability == OGS_5GC_PRE_EMPTION_ENABLED) val.u32 = OGS_EPC_PRE_EMPTION_ENABLED; ret = fd_msg_avp_setvalue(pre_emption_vulnerability, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set Pre-emption-Vulnerability value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(allocation_retention_priority, MSG_BRW_LAST_CHILD, pre_emption_vulnerability); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Pre-emption-Vulnerability AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(eps_subscribed_qos_profile, MSG_BRW_LAST_CHILD, allocation_retention_priority); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Allocation-Retention-Priority AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, eps_subscribed_qos_profile); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add EPS-Subscribed-QoS-Profile AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set MIP6-Agent-Info */ if (session->smf_ip.ipv4 || session->smf_ip.ipv6) { ret = fd_msg_avp_new(ogs_diam_mip6_agent_info, 0, &mip6_agent_info); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create MIP6-Agent-Info AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } if (session->smf_ip.ipv4) { ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0, &mip_home_agent_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create MIP-Home-Agent-Address"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + sin.sin_family = AF_INET; sin.sin_addr.s_addr = session->smf_ip.addr; - ret = fd_msg_avp_value_encode ( - &sin, mip_home_agent_address ); - ogs_assert(ret == 0); + ret = fd_msg_avp_value_encode(&sin, mip_home_agent_address); + if (ret != 0) { + ogs_error("Failed to encode SMF IPv4 address"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(mip6_agent_info, MSG_BRW_LAST_CHILD, mip_home_agent_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add MIP-Home-Agent-Address AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } } if (session->smf_ip.ipv6) { ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0, &mip_home_agent_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create MIP-Home-Agent-Address"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + sin6.sin6_family = AF_INET6; memcpy(sin6.sin6_addr.s6_addr, session->smf_ip.addr6, sizeof session->smf_ip.addr6); - ret = fd_msg_avp_value_encode ( - &sin6, mip_home_agent_address ); - ogs_assert(ret == 0); + ret = fd_msg_avp_value_encode(&sin6, mip_home_agent_address); + if (ret != 0) { + ogs_error("Failed to encode SMF IPv6 address"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(mip6_agent_info, MSG_BRW_LAST_CHILD, mip_home_agent_address); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add MIP-Home-Agent-Address AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } } ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, mip6_agent_info); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add MIP6-Agent-Info AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_s6a_pdn_gw_allocation_type, 0, &pdn_gw_allocation_type); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create PDN-GW-Allocation-Type AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } val.u32 = OGS_DIAM_S6A_PDN_GW_ALLOCATION_DYNAMIC; ret = fd_msg_avp_setvalue(pdn_gw_allocation_type, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set PDN-GW-Allocation-Type value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, pdn_gw_allocation_type); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add PDN-GW-Allocation-Type AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } } /* Set VPLMN-Dynamic-Address-Allowed */ ret = fd_msg_avp_new(ogs_diam_s6a_vplmn_dynamic_address_allowed, 0, &vplmn_dynamic_address_allowed); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create VPLMN-Dynamic-Address-Allowed"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } val.u32 = OGS_DIAM_S6A_VPLMN_DYNAMIC_ADDRESS_ALLOWED; ret = fd_msg_avp_setvalue(vplmn_dynamic_address_allowed, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set VPLMN-Dynamic-Address-Allowed value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, vplmn_dynamic_address_allowed); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add VPLMN-Dynamic-Address-Allowed AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } /* Set AMBR */ if (session->ambr.downlink || session->ambr.uplink) { - ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr); - ogs_assert(ret == 0); + struct avp *session_ambr = NULL; + struct avp *session_max_bandwidth_ul = NULL; + struct avp *session_max_bandwidth_dl = NULL; + + ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &session_ambr); + if (ret != 0) { + ogs_error("Failed to create session AMBR AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_new(ogs_diam_s6a_max_bandwidth_ul, 0, - &avp_max_bandwidth_ul); - ogs_assert(ret == 0); + &session_max_bandwidth_ul); + if (ret != 0) { + ogs_error("Failed to create session Max-Bandwidth-UL"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.u32 = ogs_uint64_to_uint32(session->ambr.uplink); - ret = fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD, - avp_max_bandwidth_ul); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(session_max_bandwidth_ul, &val); + if (ret != 0) { + ogs_error("Failed to set session Max-Bandwidth-UL value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_add(session_ambr, MSG_BRW_LAST_CHILD, + session_max_bandwidth_ul); + if (ret != 0) { + ogs_error("Failed to add session Max-Bandwidth-UL AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_new(ogs_diam_s6a_max_bandwidth_dl, 0, - &avp_max_bandwidth_dl); - ogs_assert(ret == 0); + &session_max_bandwidth_dl); + if (ret != 0) { + ogs_error("Failed to create session Max-Bandwidth-DL"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + val.u32 = ogs_uint64_to_uint32(session->ambr.downlink); - ret = fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD, - avp_max_bandwidth_dl); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(session_max_bandwidth_dl, &val); + if (ret != 0) { + ogs_error("Failed to set session Max-Bandwidth-DL value"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } + + ret = fd_msg_avp_add(session_ambr, MSG_BRW_LAST_CHILD, + session_max_bandwidth_dl); + if (ret != 0) { + ogs_error("Failed to add session Max-Bandwidth-DL AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } ret = fd_msg_avp_add(apn_configuration, - MSG_BRW_LAST_CHILD, avp_ambr); - ogs_assert(ret == 0); + MSG_BRW_LAST_CHILD, session_ambr); + if (ret != 0) { + ogs_error("Failed to add session AMBR AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } } ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, apn_configuration); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add APN-Configuration AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + 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 Non-3GPP-User-Data AVP"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + error_occurred = 1; + goto out; + } } - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_SWX_APPLICATION_ID); - ogs_assert(ret == 0); + if (!error_occurred) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_SWX_APPLICATION_ID); + if (ret != 0) { + ogs_error("Failed to set Vendor-Specific-Application-Id"); + error_occurred = 1; + goto out; + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } - /* 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); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set Auth-Session-State value"); + error_occurred = 1; + goto out; + } - /* Set the User-Name AVP */ - ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)user_name; - val.os.len = strlen(user_name); - 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_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_error("Failed to add Auth-Session-State AVP"); + error_occurred = 1; + goto out; + } - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + /* Set the Origin-Host, Origin-Realm, and Result-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } - ogs_debug("Tx Server-Assignment-Answer"); + /* Set the User-Name AVP */ + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + if (ret != 0) { + ogs_error("Failed to create User-Name AVP"); + error_occurred = 1; + goto out; + } - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - HSS_DIAM_PRIV_STATS_INC(swx.rx_sar); - HSS_DIAM_PRIV_STATS_INC(swx.tx_saa); - ) + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret != 0) { + ogs_error("Failed to set User-Name value"); + error_occurred = 1; + goto out; + } - ogs_subscription_data_free(&subscription_data); - ogs_free(user_name); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + if (ret != 0) { + ogs_error("Failed to add User-Name AVP"); + error_occurred = 1; + goto out; + } - return 0; + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } + + ogs_debug("Tx Server-Assignment-Answer"); + + /* Add this value to the stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + HSS_DIAM_PRIV_STATS_INC(swx.rx_sar); + HSS_DIAM_PRIV_STATS_INC(swx.tx_saa); + ) + + /* Cleanup resources */ + ogs_subscription_data_free(&subscription_data); + if (user_name) ogs_free(user_name); + + return 0; + } out: - /* Set Vendor-Specific-Application-Id AVP */ - ret = ogs_diam_message_vendor_specific_appid_set( - ans, OGS_DIAM_SWX_APPLICATION_ID); - ogs_assert(ret == 0); + /* Error handling */ + if (ans) { + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_SWX_APPLICATION_ID); - /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + if (result_code != 0) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + } - /* Set the Auth-Session-State AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; - 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 Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + if (ret == 0) { + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } - /* Set the User-Name AVP */ - ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)user_name; - val.os.len = strlen(user_name); - 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 User-Name AVP */ + if (user_name) { + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + if (ret == 0) { + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } + } - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } + } + /* Update error stats */ OGS_DIAM_STATS_MTX( HSS_DIAM_PRIV_STATS_INC(swx.rx_sar); HSS_DIAM_PRIV_STATS_INC(swx.rx_sar_error); ) + /* Cleanup resources */ ogs_subscription_data_free(&subscription_data); - ogs_free(user_name); + if (user_name) ogs_free(user_name); return 0; } diff --git a/src/mme/mme-fd-path.c b/src/mme/mme-fd-path.c index 75109ed0c..40ac5eb7d 100644 --- a/src/mme/mme-fd-path.c +++ b/src/mme/mme-fd-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -882,24 +882,36 @@ void mme_s6a_send_air_from_gn(enb_ue_t *enb_ue, mme_ue_t *mme_ue, ogs_gtp_xact_t /* MME received Authentication Information Answer from HSS */ static void mme_s6a_aia_cb(void *data, struct msg **msg) { - int ret; - - struct sess_state *sess_data = NULL; + int ret, rv, new; + struct sess_state *sess_data; struct timespec ts; struct session *session; struct avp *avp, *avpch; struct avp *avp_e_utran_vector, *avp_xres, *avp_kasme, *avp_rand, *avp_autn; struct avp_hdr *hdr; unsigned long dur; - int error = 0; - int new; + int error; + mme_event_t *e; + mme_ue_t *mme_ue; + enb_ue_t *enb_ue; + ogs_diam_s6a_message_t *s6a_message; + ogs_diam_s6a_aia_message_t *aia_message; + ogs_diam_e_utran_vector_t *e_utran_vector; - mme_event_t *e = NULL; - mme_ue_t *mme_ue = NULL; - enb_ue_t *enb_ue = NULL; - ogs_diam_s6a_message_t *s6a_message = NULL; - ogs_diam_s6a_aia_message_t *aia_message = NULL; - ogs_diam_e_utran_vector_t *e_utran_vector = NULL; + /* Initialize variables */ + sess_data = NULL; + avp_e_utran_vector = NULL; + avp_xres = NULL; + avp_kasme = NULL; + avp_rand = NULL; + avp_autn = NULL; + error = 0; + e = NULL; + mme_ue = NULL; + enb_ue = NULL; + s6a_message = NULL; + aia_message = NULL; + e_utran_vector = NULL; ogs_debug("[MME] Authentication-Information-Answer"); @@ -910,50 +922,59 @@ static void mme_s6a_aia_cb(void *data, struct msg **msg) ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); if (ret != 0) { ogs_error("fd_msg_sess_get() failed"); - return; + goto cleanup; } if (new != 0) { - ogs_error("fd_msg_sess_get() failed"); - return; + ogs_error("fd_msg_sess_get() failed - unexpected new session"); + goto cleanup; } ret = fd_sess_state_retrieve(mme_s6a_reg, session, &sess_data); if (ret != 0) { ogs_error("fd_sess_state_retrieve() failed"); - return; + goto cleanup; } if (!sess_data) { - ogs_error("fd_sess_state_retrieve() failed"); - return; + ogs_error("fd_sess_state_retrieve() failed - no session data"); + goto cleanup; } if ((void *)sess_data != data) { - ogs_error("fd_sess_state_retrieve() failed"); - return; + ogs_error("fd_sess_state_retrieve() failed - data mismatch"); + goto cleanup; } mme_ue = mme_ue_find_by_id(sess_data->mme_ue_id); if (!mme_ue) { ogs_error("MME-UE Context has already been removed [%d]", sess_data->mme_ue_id); - return; + goto cleanup; } enb_ue = enb_ue_find_by_id(sess_data->enb_ue_id); if (!enb_ue) { ogs_error("[%s] ENB-S1 Context has already been removed [%d]", mme_ue->imsi_bcd, sess_data->enb_ue_id); - return; + goto cleanup; + } + + /* Allocate message structure early for proper cleanup */ + s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); + if (!s6a_message) { + ogs_error("Failed to allocate s6a_message"); + error++; + goto cleanup; } /* Set Authentication-Information Command */ - s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); - ogs_assert(s6a_message); s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_AUTHENTICATION_INFORMATION; aia_message = &s6a_message->aia_message; - ogs_assert(aia_message); e_utran_vector = &aia_message->e_utran_vector; - ogs_assert(e_utran_vector); - /* Value of Result Code */ + /* AVP: 'Result-Code'(268) + * The Result-Code AVP indicates whether a particular request was completed + * successfully or whether an error occurred. The Result-Code data field + * contains an IANA-managed 32-bit address space representing errors. + * Reference: RFC 6733 + */ ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp); ogs_assert(ret == 0); if (avp) { @@ -980,10 +1001,16 @@ static void mme_s6a_aia_cb(void *data, struct msg **msg) } else { ogs_error("no Result-Code"); error++; + goto cleanup; } } - /* Value of Origin-Host */ + /* AVP: 'Origin-Host'(264) + * The Origin-Host AVP identifies the endpoint that originated the Diameter + * message. Relay agents MUST NOT modify this AVP. The value of the + * Origin-Host AVP is guaranteed to be unique within a single host. + * Reference: RFC 6733 + */ ret = fd_msg_search_avp(*msg, ogs_diam_origin_host, &avp); ogs_assert(ret == 0); if (avp) { @@ -992,11 +1019,17 @@ static void mme_s6a_aia_cb(void *data, struct msg **msg) ogs_debug(" From '%.*s'", (int)hdr->avp_value->os.len, hdr->avp_value->os.data); } else { - ogs_error("no_Origin-Host "); + ogs_error("no_Origin-Host"); error++; + goto cleanup; } - /* Value of Origin-Realm */ + /* AVP: 'Origin-Realm'(296) + * This AVP contains the Realm of the originator of any Diameter message + * and MUST be present in all messages. This AVP SHOULD be placed as close + * to the Diameter header as possible. + * Reference: RFC 6733 + */ ret = fd_msg_search_avp(*msg, ogs_diam_origin_realm, &avp); ogs_assert(ret == 0); if (avp) { @@ -1005,8 +1038,9 @@ static void mme_s6a_aia_cb(void *data, struct msg **msg) ogs_debug(" ('%.*s')", (int)hdr->avp_value->os.len, hdr->avp_value->os.data); } else { - ogs_error("no_Origin-Realm "); + ogs_error("no_Origin-Realm"); error++; + goto cleanup; } if (s6a_message->result_code != ER_DIAMETER_SUCCESS) { @@ -1020,92 +1054,137 @@ static void mme_s6a_aia_cb(void *data, struct msg **msg) s6a_message->result_code); ogs_assert_if_reached(); } - goto out; - } - - ret = fd_msg_search_avp(*msg, ogs_diam_s6a_authentication_info, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + /* Continue processing even with error result code */ } else { - ogs_error("no_Authentication-Info "); - error++; - } + /* Parse authentication info only if result is success */ - ret = fd_avp_search_avp( - avp, ogs_diam_s6a_e_utran_vector, &avp_e_utran_vector); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp_e_utran_vector, &hdr); + /* AVP: 'Authentication-Info'(1413) + * The Authentication-Info AVP contains the re-synchronization + * information in case of a re-synchronization and one or more + * E-UTRAN vectors used for EPS authentication and key agreement. + * Reference: 3GPP TS 29.272 7.3.17 + */ + ret = fd_msg_search_avp(*msg, ogs_diam_s6a_authentication_info, &avp); ogs_assert(ret == 0); - } else { - ogs_error("no_E-UTRAN-Vector-Info "); - error++; - } + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + } else { + ogs_error("no_Authentication-Info"); + error++; + goto cleanup; + } - ret = fd_avp_search_avp(avp_e_utran_vector, ogs_diam_s6a_xres, &avp_xres); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp_xres, &hdr); + /* AVP: 'E-UTRAN-Vector'(1414) + * The E-UTRAN-Vector AVP is of type Grouped. The E-UTRAN-Vector AVP + * contains an E-UTRAN vector used for EPS authentication and key + * agreement. + * Reference: 3GPP TS 29.272 7.3.18 + */ + ret = fd_avp_search_avp( + avp, ogs_diam_s6a_e_utran_vector, &avp_e_utran_vector); ogs_assert(ret == 0); - e_utran_vector->xres_len = - ogs_min(hdr->avp_value->os.len, - OGS_ARRAY_SIZE(e_utran_vector->xres)); - memcpy(e_utran_vector->xres, - hdr->avp_value->os.data, e_utran_vector->xres_len); - } else { - ogs_error("no_XRES"); - error++; - } + if (avp_e_utran_vector) { + ret = fd_msg_avp_hdr(avp_e_utran_vector, &hdr); + ogs_assert(ret == 0); + } else { + ogs_error("no_E-UTRAN-Vector-Info"); + error++; + goto cleanup; + } - ret = fd_avp_search_avp(avp_e_utran_vector, ogs_diam_s6a_kasme, &avp_kasme); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp_kasme, &hdr); + /* AVP: 'XRES'(1415) + * The XRES AVP is of type OctetString. This AVP contains the + * expected result of the authentication challenge when the UICC + * and the AuC apply the UMTS AKA algorithms. + * Reference: 3GPP TS 29.272 7.3.62 + */ + ret = fd_avp_search_avp(avp_e_utran_vector, ogs_diam_s6a_xres, + &avp_xres); ogs_assert(ret == 0); - memcpy(e_utran_vector->kasme, hdr->avp_value->os.data, + if (avp_xres) { + ret = fd_msg_avp_hdr(avp_xres, &hdr); + ogs_assert(ret == 0); + e_utran_vector->xres_len = ogs_min(hdr->avp_value->os.len, - OGS_ARRAY_SIZE(e_utran_vector->kasme))); - } else { - ogs_error("no_KASME"); - error++; - } + OGS_ARRAY_SIZE(e_utran_vector->xres)); + memcpy(e_utran_vector->xres, + hdr->avp_value->os.data, e_utran_vector->xres_len); + } else { + ogs_error("no_XRES"); + error++; + goto cleanup; + } - - ret = fd_avp_search_avp(avp_e_utran_vector, ogs_diam_s6a_rand, &avp_rand); - /* Clang scan-build SA: Value stored is not used: add ogs_assert(). */ - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp_rand, &hdr); - /* Clang scan-build SA: Value stored is not used: add ogs_assert(). */ + /* AVP: 'KASME'(1450) + * The KASME AVP is of type OctetString. This AVP contains the + * security key KASME. + * Reference: 3GPP TS 29.272 7.3.23 + */ + ret = fd_avp_search_avp(avp_e_utran_vector, ogs_diam_s6a_kasme, + &avp_kasme); ogs_assert(ret == 0); - memcpy(e_utran_vector->rand, hdr->avp_value->os.data, - ogs_min(hdr->avp_value->os.len, - OGS_ARRAY_SIZE(e_utran_vector->rand))); - } else { - ogs_error("no_RAND"); - error++; - } + if (avp_kasme) { + ret = fd_msg_avp_hdr(avp_kasme, &hdr); + ogs_assert(ret == 0); + memcpy(e_utran_vector->kasme, hdr->avp_value->os.data, + ogs_min(hdr->avp_value->os.len, + OGS_ARRAY_SIZE(e_utran_vector->kasme))); + } else { + ogs_error("no_KASME"); + error++; + goto cleanup; + } - ret = fd_avp_search_avp(avp_e_utran_vector, ogs_diam_s6a_autn, &avp_autn); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp_autn, &hdr); + /* AVP: 'RAND'(1447) + * The RAND AVP is of type OctetString. This AVP contains the + * random challenge RAND generated by the AuC. + * Reference: 3GPP TS 29.272 7.3.53 + */ + ret = fd_avp_search_avp(avp_e_utran_vector, ogs_diam_s6a_rand, + &avp_rand); ogs_assert(ret == 0); - memcpy(e_utran_vector->autn, hdr->avp_value->os.data, - ogs_min(hdr->avp_value->os.len, - OGS_ARRAY_SIZE(e_utran_vector->autn))); - } else { - ogs_error("no_AUTN"); - error++; + if (avp_rand) { + ret = fd_msg_avp_hdr(avp_rand, &hdr); + ogs_assert(ret == 0); + memcpy(e_utran_vector->rand, hdr->avp_value->os.data, + ogs_min(hdr->avp_value->os.len, + OGS_ARRAY_SIZE(e_utran_vector->rand))); + } else { + ogs_error("no_RAND"); + error++; + goto cleanup; + } + + /* AVP: 'AUTN'(1449) + * The AUTN AVP is of type OctetString. This AVP contains the + * authentication token AUTN. + * Reference: 3GPP TS 29.272 7.3.24 + */ + ret = fd_avp_search_avp(avp_e_utran_vector, ogs_diam_s6a_autn, + &avp_autn); + ogs_assert(ret == 0); + if (avp_autn) { + ret = fd_msg_avp_hdr(avp_autn, &hdr); + ogs_assert(ret == 0); + memcpy(e_utran_vector->autn, hdr->avp_value->os.data, + ogs_min(hdr->avp_value->os.len, + OGS_ARRAY_SIZE(e_utran_vector->autn))); + } else { + ogs_error("no_AUTN"); + error++; + goto cleanup; + } } -out: + /* Send event to MME if no errors */ if (!error) { - int rv; e = mme_event_new(MME_EVENT_S6A_MESSAGE); - ogs_assert(e); + if (!e) { + ogs_error("Failed to create MME event"); + error++; + goto cleanup; + } e->mme_ue_id = mme_ue->id; e->enb_ue_id = enb_ue->id; e->gtp_xact_id = sess_data->gtp_xact_id; @@ -1113,32 +1192,56 @@ out: rv = ogs_queue_push(ogs_app()->queue, e); if (rv != OGS_OK) { ogs_error("ogs_queue_push() failed:%d", (int)rv); - ogs_free(s6a_message); mme_event_free(e); + error++; + goto cleanup; } else { ogs_pollset_notify(ogs_app()->pollset); + /* Transfer ownership of s6a_message to event */ + s6a_message = NULL; } } - /* Free the message */ - 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) - 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; +cleanup: + /* Free s6a_message if it wasn't transferred to event */ + if (s6a_message) { + ogs_free(s6a_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.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; + ogs_diam_stats_self()->stats.longest = dur; + ogs_diam_stats_self()->stats.avg = dur; + } + + /* Display timing information */ + 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); + } + if (error) ogs_diam_stats_self()->stats.nb_errs++; else @@ -1146,22 +1249,15 @@ 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); - + /* Free the message */ ret = fd_msg_free(*msg); ogs_assert(ret == 0); *msg = NULL; - state_cleanup(sess_data, NULL, NULL); - return; + /* Clean up session data */ + if (sess_data) { + state_cleanup(sess_data, NULL, NULL); + } } /* MME Sends Update Location Request to HSS */ @@ -1324,25 +1420,35 @@ void mme_s6a_send_ulr(enb_ue_t *enb_ue, mme_ue_t *mme_ue) } /* MME received Update Location Answer from HSS */ +/* Fixed mme_s6a_ula_cb() function with proper error handling and C89 compliance */ static void mme_s6a_ula_cb(void *data, struct msg **msg) { - int ret; - - struct sess_state *sess_data = NULL; + int ret, rv, new; + struct sess_state *sess_data; struct timespec ts; struct session *session; struct avp *avp, *avpch; struct avp_hdr *hdr; unsigned long dur; - int error = 0; - int new; + int error; + mme_event_t *e; + mme_ue_t *mme_ue; + enb_ue_t *enb_ue; + ogs_diam_s6a_message_t *s6a_message; + ogs_diam_s6a_ula_message_t *ula_message; + ogs_subscription_data_t *subscription_data; + uint32_t subdatamask; - mme_event_t *e = NULL; - mme_ue_t *mme_ue = NULL; - enb_ue_t *enb_ue = NULL; - ogs_diam_s6a_message_t *s6a_message = NULL; - ogs_diam_s6a_ula_message_t *ula_message = NULL; - ogs_subscription_data_t *subscription_data = NULL; + /* Initialize variables */ + sess_data = NULL; + error = 0; + e = NULL; + mme_ue = NULL; + enb_ue = NULL; + s6a_message = NULL; + ula_message = NULL; + subscription_data = NULL; + subdatamask = 0; ogs_debug("[MME] Update-Location-Answer"); @@ -1353,48 +1459,52 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); if (ret != 0) { ogs_error("fd_msg_sess_get() failed"); - return; + goto cleanup; } if (new != 0) { - ogs_error("fd_msg_sess_get() failed"); - return; + ogs_error("fd_msg_sess_get() failed - unexpected new session"); + goto cleanup; } ret = fd_sess_state_retrieve(mme_s6a_reg, session, &sess_data); if (ret != 0) { ogs_error("fd_sess_state_retrieve() failed"); - return; + goto cleanup; } if (!sess_data) { - ogs_error("fd_sess_state_retrieve() failed"); - return; + ogs_error("fd_sess_state_retrieve() failed - no session data"); + goto cleanup; } if ((void *)sess_data != data) { - ogs_error("fd_sess_state_retrieve() failed"); - return; + ogs_error("fd_sess_state_retrieve() failed - data mismatch"); + goto cleanup; } mme_ue = mme_ue_find_by_id(sess_data->mme_ue_id); if (!mme_ue) { ogs_error("MME-UE Context has already been removed [%d]", sess_data->mme_ue_id); - return; + goto cleanup; } enb_ue = enb_ue_find_by_id(sess_data->enb_ue_id); if (!enb_ue) { ogs_error("[%s] ENB-S1 Context has already been removed [%d]", mme_ue->imsi_bcd, sess_data->enb_ue_id); - return; + goto cleanup; + } + + /* Allocate message structure early for proper cleanup */ + s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); + if (!s6a_message) { + ogs_error("Failed to allocate s6a_message"); + error++; + goto cleanup; } /* Set Update-Location Command */ - s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); - ogs_assert(s6a_message); s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_UPDATE_LOCATION; ula_message = &s6a_message->ula_message; - ogs_assert(ula_message); subscription_data = &ula_message->subscription_data; - ogs_assert(subscription_data); /* AVP: 'Result-Code'(268) * The Result-Code AVP indicates whether a particular request was completed @@ -1428,6 +1538,7 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) } else { ogs_error("no Result-Code"); error++; + goto cleanup; } } @@ -1447,6 +1558,7 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) } else { ogs_error("no_Origin-Host"); error++; + goto cleanup; } /* AVP: 'Origin-Realm'(296) @@ -1465,6 +1577,7 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) } else { ogs_error("no_Origin-Realm"); error++; + goto cleanup; } /* AVP: 'ULA-Flags'(1406) @@ -1478,9 +1591,11 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) ret = fd_msg_avp_hdr(avp, &hdr); ogs_assert(ret == 0); ula_message->ula_flags = hdr->avp_value->i32; + ogs_debug(" ULA-Flags: %d", ula_message->ula_flags); } else { ogs_error("no_ULA-Flags"); error++; + goto cleanup; } /* AVP: 'Subscription-Data'(1400) @@ -1491,12 +1606,15 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) ret = fd_msg_search_avp(*msg, ogs_diam_s6a_subscription_data, &avp); ogs_assert(ret == 0); if (avp) { - uint32_t subdatamask = 0; - ret = mme_s6a_subscription_data_from_avp(avp, subscription_data, mme_ue, - &subdatamask); - /* Clang scan-build SA: Value stored is not used: add ogs_assert(). */ - ogs_assert(ret == 0); + ret = mme_s6a_subscription_data_from_avp(avp, subscription_data, + mme_ue, &subdatamask); + if (ret != 0) { + ogs_error("Failed to parse subscription data"); + error++; + goto cleanup; + } + /* Validate required subscription data fields */ if (!(subdatamask & OGS_DIAM_S6A_SUBDATA_NAM)) { mme_ue->network_access_mode = 0; ogs_warn("no subscribed Network-Access-Mode, defaulting to " @@ -1510,6 +1628,7 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) if (!(subdatamask & OGS_DIAM_S6A_SUBDATA_UEAMBR)) { ogs_error("no_AMBR"); error++; + goto cleanup; } if (!(subdatamask & OGS_DIAM_S6A_SUBDATA_RAU_TAU_TIMER)) { subscription_data->subscribed_rau_tau_timer = @@ -1518,53 +1637,82 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) if (!(subdatamask & OGS_DIAM_S6A_SUBDATA_APN_CONFIG)) { ogs_error("no_APN-Configuration-Profile"); error++; + goto cleanup; } } else { ogs_error("no_Subscription-Data"); error++; + goto cleanup; } + /* Send event to MME if no errors */ if (!error) { - int rv; e = mme_event_new(MME_EVENT_S6A_MESSAGE); - ogs_assert(e); + if (!e) { + ogs_error("Failed to create MME event"); + error++; + goto cleanup; + } e->mme_ue_id = mme_ue->id; e->enb_ue_id = enb_ue->id; e->s6a_message = s6a_message; rv = ogs_queue_push(ogs_app()->queue, e); if (rv != OGS_OK) { ogs_error("ogs_queue_push() failed:%d", (int)rv); - ogs_subscription_data_free(subscription_data); - ogs_free(s6a_message); mme_event_free(e); + error++; + goto cleanup; } else { ogs_pollset_notify(ogs_app()->pollset); + /* Transfer ownership of s6a_message to event */ + s6a_message = NULL; + } + } + +cleanup: + /* Free s6a_message if it wasn't transferred to event */ + if (s6a_message) { + /* Free subscription data if it was allocated */ + if (subscription_data) { + ogs_subscription_data_free(subscription_data); } - } else { - ogs_subscription_data_free(subscription_data); ogs_free(s6a_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; + } + + /* Display timing information */ + 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); } + if (error) ogs_diam_stats_self()->stats.nb_errs++; else @@ -1572,22 +1720,15 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) 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); - + /* Free the message */ ret = fd_msg_free(*msg); ogs_assert(ret == 0); *msg = NULL; - state_cleanup(sess_data, NULL, NULL); - return; + /* Clean up session data */ + if (sess_data) { + state_cleanup(sess_data, NULL, NULL); + } } /* MME Sends Purge UE Request to HSS */ @@ -1685,24 +1826,31 @@ void mme_s6a_send_pur(enb_ue_t *enb_ue, mme_ue_t *mme_ue) } /* MME received Purge UE Answer from HSS */ +/* Fixed mme_s6a_pua_cb() function with proper error handling and C89 compliance */ static void mme_s6a_pua_cb(void *data, struct msg **msg) { - int ret; - - struct sess_state *sess_data = NULL; + int ret, rv, new; + struct sess_state *sess_data; struct timespec ts; struct session *session; struct avp *avp, *avpch; struct avp_hdr *hdr; unsigned long dur; - int error = 0; - int new; + int error; + mme_event_t *e; + mme_ue_t *mme_ue; + enb_ue_t *enb_ue; + ogs_diam_s6a_message_t *s6a_message; + ogs_diam_s6a_pua_message_t *pua_message; - mme_event_t *e = NULL; - mme_ue_t *mme_ue = NULL; - enb_ue_t *enb_ue = NULL; - ogs_diam_s6a_message_t *s6a_message = NULL; - ogs_diam_s6a_pua_message_t *pua_message = NULL; + /* Initialize variables */ + sess_data = NULL; + error = 0; + e = NULL; + mme_ue = NULL; + enb_ue = NULL; + s6a_message = NULL; + pua_message = NULL; ogs_debug("[MME] Purge-UE-Answer"); @@ -1713,46 +1861,51 @@ static void mme_s6a_pua_cb(void *data, struct msg **msg) ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); if (ret != 0) { ogs_error("fd_msg_sess_get() failed"); - return; + goto cleanup; } if (new != 0) { - ogs_error("fd_msg_sess_get() failed"); - return; + ogs_error("fd_msg_sess_get() failed - unexpected new session"); + goto cleanup; } ret = fd_sess_state_retrieve(mme_s6a_reg, session, &sess_data); if (ret != 0) { ogs_error("fd_sess_state_retrieve() failed"); - return; + goto cleanup; } if (!sess_data) { - ogs_error("fd_sess_state_retrieve() failed"); - return; + ogs_error("fd_sess_state_retrieve() failed - no session data"); + goto cleanup; } if ((void *)sess_data != data) { - ogs_error("fd_sess_state_retrieve() failed"); - return; + ogs_error("fd_sess_state_retrieve() failed - data mismatch"); + goto cleanup; } mme_ue = mme_ue_find_by_id(sess_data->mme_ue_id); if (!mme_ue) { ogs_error("MME-UE Context has already been removed [%d]", sess_data->mme_ue_id); - return; + goto cleanup; } enb_ue = enb_ue_find_by_id(sess_data->enb_ue_id); if (!enb_ue) { ogs_error("[%s] ENB-S1 Context has already been removed [%d]", mme_ue->imsi_bcd, sess_data->enb_ue_id); - return; + goto cleanup; + } + + /* Allocate message structure early for proper cleanup */ + s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); + if (!s6a_message) { + ogs_error("Failed to allocate s6a_message"); + error++; + goto cleanup; } /* Set Purge-UE Command */ - s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); - ogs_assert(s6a_message); s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_PURGE_UE; pua_message = &s6a_message->pua_message; - ogs_assert(pua_message); /* AVP: 'Result-Code'(268) * The Result-Code AVP indicates whether a particular request was completed @@ -1786,6 +1939,7 @@ static void mme_s6a_pua_cb(void *data, struct msg **msg) } else { ogs_error("no Result-Code"); error++; + goto cleanup; } } @@ -1805,6 +1959,7 @@ static void mme_s6a_pua_cb(void *data, struct msg **msg) } else { ogs_error("no_Origin-Host"); error++; + goto cleanup; } /* AVP: 'Origin-Realm'(296) @@ -1823,12 +1978,14 @@ static void mme_s6a_pua_cb(void *data, struct msg **msg) } else { ogs_error("no_Origin-Realm"); error++; + goto cleanup; } - /* AVP: 'PUA-Flags'(1406) + /* AVP: 'PUA-Flags'(1442) * The PUA-Flags AVP contains a bit mask, whose meanings are defined in * table in 29.272 7.3.8/1. * Reference: 3GPP TS 29.272-f70 + * Note: This AVP is optional, so no error if not present */ ret = fd_msg_search_avp(*msg, ogs_diam_s6a_pua_flags, &avp); ogs_assert(ret == 0); @@ -1836,47 +1993,76 @@ static void mme_s6a_pua_cb(void *data, struct msg **msg) ret = fd_msg_avp_hdr(avp, &hdr); ogs_assert(ret == 0); pua_message->pua_flags = hdr->avp_value->i32; + ogs_debug(" PUA-Flags: %d", pua_message->pua_flags); + } else { + ogs_debug(" No PUA-Flags (optional AVP)"); + pua_message->pua_flags = 0; } + /* Send event to MME if no errors */ if (!error) { - int rv; e = mme_event_new(MME_EVENT_S6A_MESSAGE); - ogs_assert(e); + if (!e) { + ogs_error("Failed to create MME event"); + error++; + goto cleanup; + } e->mme_ue_id = mme_ue->id; e->enb_ue_id = enb_ue->id; e->s6a_message = s6a_message; rv = ogs_queue_push(ogs_app()->queue, e); if (rv != OGS_OK) { ogs_error("ogs_queue_push() failed:%d", (int)rv); - ogs_free(s6a_message); mme_event_free(e); + error++; + goto cleanup; } else { ogs_pollset_notify(ogs_app()->pollset); + /* Transfer ownership of s6a_message to event */ + s6a_message = NULL; } - } else { + } + +cleanup: + /* Free s6a_message if it wasn't transferred to event */ + if (s6a_message) { ogs_free(s6a_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; + } + + /* Display timing information */ + 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); } + if (error) ogs_diam_stats_self()->stats.nb_errs++; else @@ -1884,84 +2070,114 @@ static void mme_s6a_pua_cb(void *data, struct msg **msg) 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); - + /* Free the message */ ret = fd_msg_free(*msg); ogs_assert(ret == 0); *msg = NULL; - state_cleanup(sess_data, NULL, NULL); - return; + /* Clean up session data */ + if (sess_data) { + state_cleanup(sess_data, NULL, NULL); + } } /* Callback for incoming Cancel-Location-Request messages */ -static int mme_ogs_diam_s6a_clr_cb( struct msg **msg, struct avp *avp, +static int mme_s6a_clr_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int ret, rv; - - mme_event_t *e = NULL; - mme_ue_t *mme_ue = NULL; - struct msg *ans, *qry; - ogs_diam_s6a_clr_message_t *clr_message = NULL; - - struct avp_hdr *hdr; union avp_value val; - + struct avp_hdr *hdr; char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; + uint32_t result_code; + mme_event_t *e; + mme_ue_t *mme_ue; + ogs_diam_s6a_message_t *s6a_message; + ogs_diam_s6a_clr_message_t *clr_message; - uint32_t result_code = 0; + /* Initialize variables */ + result_code = 0; + e = NULL; + mme_ue = NULL; + s6a_message = NULL; + clr_message = NULL; ogs_assert(msg); - ogs_diam_s6a_message_t *s6a_message = NULL; - ogs_debug("Cancel-Location-Request"); + /* Allocate message structure early for proper cleanup */ s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); - ogs_assert(s6a_message); + if (!s6a_message) { + ogs_error("Failed to allocate s6a_message"); + result_code = OGS_DIAM_OUT_OF_SPACE; + goto error_out; + } + s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION; clr_message = &s6a_message->clr_message; - ogs_assert(clr_message); /* 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"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + goto error_out; + } ans = *msg; + /* Get User-Name AVP */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); ogs_assert(ret == 0); + if (!avp) { + ogs_error("User-Name AVP not found"); + result_code = OGS_DIAM_MISSING_AVP; + goto error_out; + } + ret = fd_msg_avp_hdr(avp, &hdr); ogs_assert(ret == 0); + if (!hdr->avp_value->os.data || hdr->avp_value->os.len == 0) { + ogs_error("Invalid User-Name AVP data"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + goto error_out; + } ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data, ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1); mme_ue = mme_ue_find_by_imsi_bcd(imsi_bcd); - if (!mme_ue) { ogs_error("Cancel Location for Unknown IMSI[%s]", imsi_bcd); result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; - goto out; + goto error_out; } + /* Get Cancellation-Type AVP */ ret = fd_msg_search_avp(qry, ogs_diam_s6a_cancellation_type, &avp); ogs_assert(ret == 0); + if (!avp) { + ogs_error("Cancellation-Type AVP not found"); + result_code = OGS_DIAM_MISSING_AVP; + goto error_out; + } + ret = fd_msg_avp_hdr(avp, &hdr); ogs_assert(ret == 0); clr_message->cancellation_type = hdr->avp_value->i32; - /* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */ + /* Get CLR-Flags AVP (optional) */ + ret = fd_msg_search_avp(qry, ogs_diam_s6a_clr_flags, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + clr_message->clr_flags = hdr->avp_value->i32; + } + + /* 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); @@ -1974,14 +2190,6 @@ static int mme_ogs_diam_s6a_clr_cb( struct msg **msg, struct avp *avp, ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); ogs_assert(ret == 0); - ret = fd_msg_search_avp(qry, ogs_diam_s6a_clr_flags, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - clr_message->clr_flags = hdr->avp_value->i32; - } - /* Set Vendor-Specific-Application-Id AVP */ ret = ogs_diam_message_vendor_specific_appid_set( ans, OGS_DIAM_S6A_APPLICATION_ID); @@ -1994,12 +2202,17 @@ static int mme_ogs_diam_s6a_clr_cb( struct msg **msg, struct avp *avp, ogs_debug("Cancel-Location-Answer"); /* Add this value to the stats */ - ogs_assert( pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0); + ogs_assert(pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0); ogs_diam_stats_self()->stats.nb_echoed++; - ogs_assert( pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0); + ogs_assert(pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0); + /* Send event to MME */ e = mme_event_new(MME_EVENT_S6A_MESSAGE); - ogs_assert(e); + if (!e) { + ogs_error("Failed to create MME event"); + ogs_free(s6a_message); + return 0; + } e->mme_ue_id = mme_ue->id; e->s6a_message = s6a_message; rv = ogs_queue_push(ogs_app()->queue, e); @@ -2009,13 +2222,27 @@ static int mme_ogs_diam_s6a_clr_cb( struct msg **msg, struct avp *avp, mme_event_free(e); } else { ogs_pollset_notify(ogs_app()->pollset); + /* Transfer ownership of s6a_message to event */ + s6a_message = NULL; } return 0; -out: - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); +error_out: + /* Free s6a_message if it wasn't transferred to event */ + if (s6a_message) { + ogs_free(s6a_message); + } + + /* Set appropriate error result code */ + if (result_code == OGS_DIAM_S6A_ERROR_USER_UNKNOWN) { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + ogs_assert(ret == 0); + } else { + ret = fd_msg_rescode_set(ans, (char*)"OGS_DIAM_UNABLE_TO_DELIVER", + NULL, NULL, 1); + ogs_assert(ret == 0); + } /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); @@ -2031,48 +2258,57 @@ out: ans, OGS_DIAM_S6A_APPLICATION_ID); ogs_assert(ret == 0); - /* Send the answer */ + /* Send error response */ ret = fd_msg_send(msg, NULL, NULL); ogs_assert(ret == 0); - ogs_free(s6a_message); - return 0; } /* Callback for incoming Insert-Subscriber-Data-Request messages * 29.272 5.2.2.1.2 */ -static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, +static int mme_s6a_idr_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { - int ret; + int ret, rv; char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; - uint32_t result_code = 0; - /* Clang scan-build SA: Branch condition evaluates to a garbage value: has_subscriber_data can be used uninitialized. */ - bool has_subscriber_data = false; - + uint32_t result_code; + bool has_subscriber_data; struct msg *ans, *qry; - - mme_event_t *e = NULL; - mme_ue_t *mme_ue = NULL; - ogs_diam_s6a_message_t *s6a_message = NULL; - ogs_diam_s6a_idr_message_t *idr_message = NULL; - ogs_subscription_data_t *subscription_data = NULL; - + mme_event_t *e; + mme_ue_t *mme_ue; + ogs_diam_s6a_message_t *s6a_message; + ogs_diam_s6a_idr_message_t *idr_message; + ogs_subscription_data_t *subscription_data; struct avp_hdr *hdr; union avp_value val; + uint32_t subdatamask; + + /* Initialize variables */ + result_code = 0; + has_subscriber_data = false; + e = NULL; + mme_ue = NULL; + s6a_message = NULL; + idr_message = NULL; + subscription_data = NULL; + subdatamask = 0; ogs_assert(msg); ogs_debug("Insert-Subscriber-Data-Request"); + /* Allocate message structure early for proper cleanup */ s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); - ogs_assert(s6a_message); + if (!s6a_message) { + ogs_error("Failed to allocate s6a_message"); + result_code = OGS_DIAM_OUT_OF_SPACE; + goto error_out; + } + s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_INSERT_SUBSCRIBER_DATA; idr_message = &s6a_message->idr_message; - ogs_assert(idr_message); subscription_data = &idr_message->subscription_data; - ogs_assert(subscription_data); /* Create answer header */ qry = *msg; @@ -2080,27 +2316,34 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, ogs_assert(ret == 0); ans = *msg; + /* Get User-Name AVP */ ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); ogs_assert(ret == 0); + if (!avp) { + ogs_error("User-Name AVP not found"); + result_code = OGS_DIAM_MISSING_AVP; + goto error_out; + } + ret = fd_msg_avp_hdr(avp, &hdr); ogs_assert(ret == 0); + if (!hdr->avp_value->os.data || hdr->avp_value->os.len == 0) { + ogs_error("Invalid User-Name AVP data"); + result_code = OGS_DIAM_INVALID_AVP_VALUE; + goto error_out; + } ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data, ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1); mme_ue = mme_ue_find_by_imsi_bcd(imsi_bcd); - if (!mme_ue) { ogs_error("Insert Subscriber Data for Unknown IMSI[%s]", imsi_bcd); result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; - goto out; + goto error_out; } - /* AVP: 'Subscription-Data'(1400) - * The Subscription-Data AVP contains the information related to the user - * profile relevant for EPS and GERAN/UTRAN. - * Reference: 3GPP TS 29.272-f70 - */ + /* AVP: 'Subscription-Data'(1400) - Optional */ ret = fd_msg_search_avp(qry, ogs_diam_s6a_subscription_data, &avp); ogs_assert(ret == 0); if (avp) { @@ -2111,16 +2354,19 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, ogs_info("[%s] Subscription-Data is Empty.", imsi_bcd); } else { has_subscriber_data = true; - uint32_t subdatamask = 0; ret = mme_s6a_subscription_data_from_avp(avp, subscription_data, mme_ue, &subdatamask); - /* Clang scan-build SA: Value stored is not used: add ogs_assert(). */ - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to parse subscription data"); + result_code = OGS_DIAM_UNABLE_TO_DELIVER; + goto error_out; + } idr_message->subdatamask = subdatamask; ogs_info("[%s] Subscription-Data Processed.", imsi_bcd); } } + /* AVP: 'IDR-Flags'(1490) - Optional */ ret = fd_msg_search_avp(qry, ogs_diam_s6a_idr_flags, &avp); ogs_assert(ret == 0); if (avp) { @@ -2129,25 +2375,25 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, idr_message->idr_flags = hdr->avp_value->i32; } + /* Handle EPS-Location-Information request */ if (idr_message->idr_flags & OGS_DIAM_S6A_IDR_FLAGS_EPS_LOCATION_INFO) { char buf[8]; - uint8_t ida_ecgi[8]; uint8_t ida_tai[5]; ogs_time_t ida_age; - ogs_nas_plmn_id_t ida_plmn_buf; char ida_cell_id_hex[9]; char ida_tac_hex[5]; - - uint32_t ida_cell_id = mme_ue->e_cgi.cell_id; - uint16_t ida_tac = mme_ue->tai.tac; - + uint32_t ida_cell_id; + uint16_t ida_tac; struct avp *avp_mme_location_information; struct avp *avp_e_utran_cell_global_identity; struct avp *avp_tracking_area_identity; struct avp *avp_age_of_location_information; + ida_cell_id = mme_ue->e_cgi.cell_id; + ida_tac = mme_ue->tai.tac; + ogs_snprintf(ida_cell_id_hex, sizeof(ida_cell_id_hex), "%08x", ida_cell_id); memcpy(ida_ecgi, @@ -2210,6 +2456,8 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); ogs_assert(ret == 0); } + + /* Handle EPS-User-State request */ if (idr_message->idr_flags & OGS_DIAM_S6A_IDR_FLAGS_EPS_USER_STATE) { #define OGS_DIAM_S6A_USER_STATE_DETACHED 0 #define OGS_DIAM_S6A_USER_STATE_ATTACHED_NOT_REACHABLE_FOR_PAGING 1 @@ -2217,12 +2465,13 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, #define OGS_DIAM_S6A_USER_STATE_CONNECTED_NOT_REACHABLE_FOR_PAGING 3 #define OGS_DIAM_S6A_USER_STATE_CONNECTED_REACHABLE_FOR_PAGING 4 #define OGS_DIAM_S6A_USER_STATE_RESERVED 5 + struct avp *avp_eps_user_state = NULL; struct avp *avp_mme_user_state = NULL; struct avp *avp_user_state = NULL; uint32_t user_state = 0; - /* check user state */ + /* Check user state */ if (!ECM_CONNECTED(mme_ue)) user_state = OGS_DIAM_S6A_USER_STATE_DETACHED; else if (mme_ue->paging.failed) @@ -2231,9 +2480,11 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, user_state = OGS_DIAM_S6A_USER_STATE_CONNECTED_REACHABLE_FOR_PAGING; /* Set the EPS-User-State AVP */ - ret = fd_msg_avp_new(ogs_diam_s6a_eps_user_state, 0, &avp_eps_user_state); + ret = fd_msg_avp_new(ogs_diam_s6a_eps_user_state, 0, + &avp_eps_user_state); ogs_assert(ret == 0); - ret = fd_msg_avp_new(ogs_diam_s6a_mme_user_state, 0, &avp_mme_user_state); + ret = fd_msg_avp_new(ogs_diam_s6a_mme_user_state, 0, + &avp_mme_user_state); ogs_assert(ret == 0); ret = fd_msg_avp_new(ogs_diam_s6a_user_state, 0, &avp_user_state); ogs_assert(ret == 0); @@ -2241,13 +2492,17 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, val.i32 = user_state; ret = fd_msg_avp_setvalue(avp_user_state, &val); ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp_mme_user_state, MSG_BRW_LAST_CHILD, avp_user_state); + ret = fd_msg_avp_add(avp_mme_user_state, MSG_BRW_LAST_CHILD, + avp_user_state); ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp_eps_user_state, MSG_BRW_LAST_CHILD, avp_mme_user_state); + ret = fd_msg_avp_add(avp_eps_user_state, MSG_BRW_LAST_CHILD, + avp_mme_user_state); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp_eps_user_state); ogs_assert(ret == 0); } + + /* Validate that we have meaningful data to process */ if (!has_subscriber_data && !(idr_message->idr_flags & OGS_DIAM_S6A_IDR_FLAGS_EPS_LOCATION_INFO) && !(idr_message->idr_flags & OGS_DIAM_S6A_IDR_FLAGS_EPS_USER_STATE)) @@ -2257,12 +2512,12 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, "or no Subscriber-Data for IMSI[%s]", imsi_bcd); /* Set the Origin-Host, Origin-Realm, and Result-Code AVPs */ ret = fd_msg_rescode_set( - ans, (char*)"DIAMETER_UNABLE_TO_COMPLY", NULL, NULL, 1); + ans, (char*)"OGS_DIAM_UNABLE_TO_DELIVER", NULL, NULL, 1); ogs_assert(ret == 0); goto outnoexp; } - /* 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); @@ -2287,13 +2542,18 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, ogs_debug("Insert-Subscriber-Data-Answer"); /* Add this value to the stats */ - ogs_assert( pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0); + ogs_assert(pthread_mutex_lock(&ogs_diam_stats_self()->stats_lock) == 0); ogs_diam_stats_self()->stats.nb_echoed++; - ogs_assert( pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0); + ogs_assert(pthread_mutex_unlock(&ogs_diam_stats_self()->stats_lock) == 0); - int rv; + /* Send event to MME */ e = mme_event_new(MME_EVENT_S6A_MESSAGE); - ogs_assert(e); + if (!e) { + ogs_error("Failed to create MME event"); + ogs_subscription_data_free(subscription_data); + ogs_free(s6a_message); + return 0; + } e->mme_ue_id = mme_ue->id; e->s6a_message = s6a_message; rv = ogs_queue_push(ogs_app()->queue, e); @@ -2304,13 +2564,25 @@ static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, mme_event_free(e); } else { ogs_pollset_notify(ogs_app()->pollset); + /* Transfer ownership of s6a_message to event */ + s6a_message = NULL; } return 0; -out: +error_out: + /* Free s6a_message if it wasn't transferred to event */ + if (s6a_message) { + if (subscription_data) { + ogs_subscription_data_free(subscription_data); + } + ogs_free(s6a_message); + } + + /* Set appropriate error result code */ ret = ogs_diam_message_experimental_rescode_set(ans, result_code); ogs_assert(ret == 0); + outnoexp: /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); @@ -2326,12 +2598,10 @@ outnoexp: ans, OGS_DIAM_S6A_APPLICATION_ID); ogs_assert(ret == 0); - /* Send the answer */ + /* Send error response */ ret = fd_msg_send(msg, NULL, NULL); ogs_assert(ret == 0); - ogs_free(s6a_message); - return 0; } @@ -2355,13 +2625,13 @@ int mme_fd_init(void) /* Specific handler for Cancel-Location-Request */ memset(&data, 0, sizeof(data)); data.command = ogs_diam_s6a_cmd_clr; - ret = fd_disp_register(mme_ogs_diam_s6a_clr_cb, DISP_HOW_CC, &data, NULL, + ret = fd_disp_register(mme_s6a_clr_cb, DISP_HOW_CC, &data, NULL, &hdl_s6a_clr); ogs_assert(ret == 0); /* Specific handler for Insert-Subscriber-Data-Request */ data.command = ogs_diam_s6a_cmd_idr; - ret = fd_disp_register(mme_ogs_diam_s6a_idr_cb, DISP_HOW_CC, &data, NULL, + ret = fd_disp_register(mme_s6a_idr_cb, DISP_HOW_CC, &data, NULL, &hdl_s6a_idr); ogs_assert(ret == 0); diff --git a/src/pcrf/pcrf-gx-path.c b/src/pcrf/pcrf-gx-path.c index 54b414a70..d0769bd3f 100644 --- a/src/pcrf/pcrf-gx-path.c +++ b/src/pcrf/pcrf-gx-path.c @@ -1,5 +1,5 @@ /* Gx Interface, 3GPP TS 29.212 section 4 - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -221,27 +221,30 @@ static int pcrf_gx_fb_cb(struct msg **msg, struct avp *avp, return ENOTSUP; } -static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, +static int pcrf_gx_ccr_cb(struct msg **msg, struct avp *avp, struct session *sess, void *opaque, enum disp_action *act) { int rv; int ret = 0, i; - - struct msg *ans, *qry; - struct avp *avpch1, *avpch2; - struct avp_hdr *hdr; + struct msg *ans = NULL, *qry = NULL; + struct avp *avpch1 = NULL, *avpch2 = NULL; + struct avp_hdr *hdr = NULL; union avp_value val; struct sess_state *sess_data = NULL; - ogs_diam_gx_message_t gx_message; - uint32_t cc_request_type = OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST; uint32_t cc_request_number = 0; uint32_t result_code = OGS_DIAM_MISSING_AVP; + int error_occurred = 0; + int charging_rule = 0; ogs_debug("Rx Credit-Control-Request"); - ogs_assert(msg); + /* Validate input parameters */ + if (!msg || !*msg || !sess) { + ogs_error("Invalid input parameters"); + return EINVAL; + } /* Initialize Message */ memset(&gx_message, 0, sizeof(ogs_diam_gx_message_t)); @@ -249,40 +252,78 @@ static int pcrf_gx_ccr_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_GX_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; + } /* Get CC-Request-Type */ ret = fd_msg_search_avp(qry, ogs_diam_gx_cc_request_type, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search CC-Request-Type AVP"); + error_occurred = 1; + goto out; + } + if (avp) { ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to get CC-Request-Type AVP header"); + error_occurred = 1; + goto out; + } cc_request_type = hdr->avp_value->i32; } else { - ogs_error("no_CC-Request-Type "); - ogs_assert_if_reached(); + ogs_error("No CC-Request-Type found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; } /* Get CC-Request-Number */ ret = fd_msg_search_avp(qry, ogs_diam_gx_cc_request_number, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search CC-Request-Number AVP"); + error_occurred = 1; + goto out; + } + if (avp) { ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to get CC-Request-Number AVP header"); + error_occurred = 1; + goto out; + } cc_request_number = hdr->avp_value->i32; } else { - ogs_error("no_CC-Request-Number"); - ogs_assert_if_reached(); + ogs_error("No CC-Request-Number found"); + result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; + goto out; } ogs_debug(" CC-Request-Type[%d] Number[%d]", @@ -290,25 +331,53 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, /* Set CC-Request-Type */ ret = fd_msg_avp_new(ogs_diam_gx_cc_request_type, 0, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create CC-Request-Type AVP"); + error_occurred = 1; + goto out; + } val.i32 = cc_request_type; ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set CC-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 CC-Request-Type AVP"); + error_occurred = 1; + goto out; + } /* Set CC-Request-Number */ ret = fd_msg_avp_new(ogs_diam_gx_cc_request_number, 0, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create CC-Request-Number AVP"); + error_occurred = 1; + goto out; + } val.i32 = cc_request_number; ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to set CC-Request-Number 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 CC-Request-Number AVP"); + error_occurred = 1; + goto out; + } /* Find Session */ ret = fd_sess_state_retrieve(pcrf_gx_reg, sess, &sess_data); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to retrieve session state"); + error_occurred = 1; + goto out; + } /* Check Session */ if (!sess_data && @@ -316,128 +385,210 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST)) { ogs_error("No Session for CC-Request-Type: [%d]", cc_request_type); result_code = OGS_DIAM_UNKNOWN_SESSION_ID; + error_occurred = 1; goto out; } if (!sess_data) { - os0_t sid; + os0_t sid = NULL; size_t sidlen; ret = fd_sess_getsid(sess, &sid, &sidlen); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to get session ID"); + error_occurred = 1; + goto out; + } sess_data = new_state(sid); - ogs_assert(sess_data); + if (!sess_data) { + ogs_error("Failed to create new session state"); + error_occurred = 1; + goto out; + } } /* Get Origin-Host */ ret = fd_msg_search_avp(qry, ogs_diam_origin_host, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Origin-Host AVP"); + error_occurred = 1; + goto out; + } + if (avp) { ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to get Origin-Host AVP header"); + error_occurred = 1; + goto out; + } - 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; + } } else { - ogs_error("no_CC-Request-Type "); + ogs_error("No Origin-Host found"); result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } /* Get Framed-IP-Address */ ret = fd_msg_search_avp(qry, ogs_diam_gx_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); - - ogs_assert(hdr->avp_value->os.len == sizeof sess_data->addr); - memcpy(&sess_data->addr, - hdr->avp_value->os.data, hdr->avp_value->os.len); - pcrf_sess_set_ipv4(&sess_data->addr, sess_data->sid); - sess_data->ipv4 = 1; + if (ret == 0 && hdr && + hdr->avp_value->os.len == sizeof(sess_data->addr)) { + memcpy(&sess_data->addr, + hdr->avp_value->os.data, hdr->avp_value->os.len); + pcrf_sess_set_ipv4(&sess_data->addr, sess_data->sid); + sess_data->ipv4 = 1; + } else if (ret != 0) { + ogs_warn("Failed to get Framed-IP-Address AVP header"); + } } /* Get Framed-IPv6-Prefix */ ret = fd_msg_search_avp(qry, ogs_diam_gx_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); - - paa = (ogs_paa_t *)hdr->avp_value->os.data; - ogs_assert(paa); - ogs_assert(paa->len == OGS_IPV6_DEFAULT_PREFIX_LEN /* 64bit */); - memcpy(sess_data->addr6, paa->addr6, paa->len >> 3); - pcrf_sess_set_ipv6(sess_data->addr6, sess_data->sid); - sess_data->ipv6 = 1; + if (ret == 0 && hdr) { + paa = (ogs_paa_t *)hdr->avp_value->os.data; + if (paa && paa->len == OGS_IPV6_DEFAULT_PREFIX_LEN) { + memcpy(sess_data->addr6, paa->addr6, paa->len >> 3); + pcrf_sess_set_ipv6(sess_data->addr6, sess_data->sid); + sess_data->ipv6 = 1; + } + } else if (ret != 0) { + ogs_warn("Failed to get Framed-IPv6-Prefix AVP header"); + } } /* Get IMSI + APN */ ret = fd_msg_search_avp(qry, ogs_diam_subscription_id, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Subscription-Id AVP"); + error_occurred = 1; + goto out; + } + if (avp) { ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to get Subscription-Id AVP header"); + error_occurred = 1; + goto out; + } + ret = fd_avp_search_avp(avp, ogs_diam_subscription_id_type, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Subscription-Id-Type AVP"); + error_occurred = 1; + goto out; + } + if (avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to get Subscription-Id-Type AVP header"); + error_occurred = 1; + goto out; + } if (hdr->avp_value->i32 != OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_IMSI) { ogs_error("Not implemented Subscription-Id-Type(%d)", hdr->avp_value->i32); result_code = OGS_DIAM_AVP_UNSUPPORTED; + error_occurred = 1; goto out; } } else { - ogs_error("no_Subscription-Id-Type"); + ogs_error("No Subscription-Id-Type found"); result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } + ret = fd_avp_search_avp(avp, ogs_diam_subscription_id_data, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to search Subscription-Id-Data AVP"); + error_occurred = 1; + goto out; + } + if (avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - if (sess_data->imsi_bcd) + if (ret != 0) { + ogs_error("Failed to get Subscription-Id-Data AVP header"); + error_occurred = 1; + goto out; + } + if (sess_data->imsi_bcd) { ogs_free(sess_data->imsi_bcd); + sess_data->imsi_bcd = NULL; + } sess_data->imsi_bcd = ogs_strdup((char *)hdr->avp_value->os.data); - ogs_assert(sess_data->imsi_bcd); + if (!sess_data->imsi_bcd) { + ogs_error("Failed to duplicate IMSI"); + error_occurred = 1; + goto out; + } } else { - ogs_error("no_Subscription-Id-Data"); + ogs_error("No Subscription-Id-Data found"); result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } } - if (sess_data->imsi_bcd == NULL) { - ogs_error("no_Subscription-Id"); + if (!sess_data->imsi_bcd) { + ogs_error("No Subscription-Id"); result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } ret = fd_msg_search_avp(qry, ogs_diam_gx_called_station_id, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - if (sess_data->apn) - ogs_free(sess_data->apn); - sess_data->apn = ogs_strdup((char *)hdr->avp_value->os.data); - ogs_assert(sess_data->apn); + if (ret != 0) { + ogs_error("Failed to search Called-Station-Id AVP"); + error_occurred = 1; + goto out; } - if (sess_data->apn == NULL) { - ogs_error("no_Called-Station-Id"); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + if (ret != 0) { + ogs_error("Failed to get Called-Station-Id AVP header"); + error_occurred = 1; + goto out; + } + if (sess_data->apn) { + ogs_free(sess_data->apn); + sess_data->apn = NULL; + } + sess_data->apn = ogs_strdup((char *)hdr->avp_value->os.data); + if (!sess_data->apn) { + ogs_error("Failed to duplicate APN"); + error_occurred = 1; + goto out; + } + } + + if (!sess_data->apn) { + ogs_error("No Called-Station-Id"); result_code = OGS_DIAM_MISSING_AVP; + error_occurred = 1; goto out; } @@ -445,15 +596,15 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, rv = pcrf_db_qos_data( sess_data->imsi_bcd, sess_data->apn, &gx_message.session_data); if (rv != OGS_OK) { - ogs_error("Cannot get data for IMSI(%s)+APN(%s)'", + ogs_error("Cannot get data for IMSI(%s)+APN(%s)", sess_data->imsi_bcd, sess_data->apn); result_code = OGS_DIAM_UNKNOWN_SESSION_ID; + error_occurred = 1; goto out; } if (cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST || cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_UPDATE_REQUEST) { - int charging_rule = 0; for (i = 0; i < gx_message.session_data.num_of_pcc_rule; i++) { ogs_pcc_rule_t *pcc_rule = &gx_message.session_data.pcc_rule[i]; @@ -461,137 +612,289 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, if (charging_rule == 0) { ret = fd_msg_avp_new( ogs_diam_gx_charging_rule_install, 0, &avp); - ogs_assert(ret == 0); - + if (ret != 0) { + ogs_error("Failed to create Charging-Rule-Install AVP"); + error_occurred = 1; + goto out; + } charging_rule = 1; } rv = encode_pcc_rule_definition(avp, pcc_rule, 1); - ogs_assert(rv == OGS_OK); + if (rv != OGS_OK) { + ogs_error("Failed to encode PCC rule definition"); + error_occurred = 1; + goto out; + } } } if (charging_rule) { ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to add Charging-Rule-Install AVP"); + error_occurred = 1; + goto out; + } } /* Set QoS-Information */ if (gx_message.session_data.session.ambr.downlink || gx_message.session_data.session.ambr.uplink) { ret = fd_msg_avp_new(ogs_diam_gx_qos_information, 0, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create QoS-Information AVP"); + error_occurred = 1; + goto out; + } if (gx_message.session_data.session.ambr.uplink) { ret = fd_msg_avp_new( ogs_diam_gx_apn_aggregate_max_bitrate_ul, 0, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create APN-AMBR-UL AVP"); + error_occurred = 1; + goto out; + } val.u32 = ogs_uint64_to_uint32( gx_message.session_data.session.ambr.uplink); - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set APN-AMBR-UL value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add APN-AMBR-UL AVP"); + error_occurred = 1; + goto out; + } } if (gx_message.session_data.session.ambr.downlink) { ret = fd_msg_avp_new( ogs_diam_gx_apn_aggregate_max_bitrate_dl, 0, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create APN-AMBR-DL AVP"); + error_occurred = 1; + goto out; + } val.u32 = ogs_uint64_to_uint32( gx_message.session_data.session.ambr.downlink); - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set APN-AMBR-DL value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add APN-AMBR-DL AVP"); + 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 QoS-Information AVP"); + error_occurred = 1; + goto out; + } } /* Set Default-EPS-Bearer-QoS */ ret = fd_msg_avp_new(ogs_diam_gx_default_eps_bearer_qos, 0, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Default-EPS-Bearer-QoS AVP"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_gx_qos_class_identifier, 0, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create QoS-Class-Identifier AVP"); + error_occurred = 1; + goto out; + } val.u32 = gx_message.session_data.session.qos.index; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set QoS-Class-Identifier value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add QoS-Class-Identifier AVP"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new( ogs_diam_gx_allocation_retention_priority, 0, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create ARP AVP"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_gx_priority_level, 0, &avpch2); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Priority-Level AVP"); + error_occurred = 1; + goto out; + } val.u32 = gx_message.session_data.session.qos.arp.priority_level; - ret = fd_msg_avp_setvalue (avpch2, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch2, &val); + if (ret != 0) { + ogs_error("Failed to set Priority-Level value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + if (ret != 0) { + ogs_error("Failed to add Priority-Level AVP"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_gx_pre_emption_capability, 0, &avpch2); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Pre-emption-Capability AVP"); + error_occurred = 1; + goto out; + } val.u32 = OGS_EPC_PRE_EMPTION_DISABLED; if (gx_message.session_data.session.qos.arp.pre_emption_capability == OGS_5GC_PRE_EMPTION_ENABLED) val.u32 = OGS_EPC_PRE_EMPTION_ENABLED; - ret = fd_msg_avp_setvalue (avpch2, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch2, &val); + if (ret != 0) { + ogs_error("Failed to set Pre-emption-Capability value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + if (ret != 0) { + ogs_error("Failed to add Pre-emption-Capability AVP"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_gx_pre_emption_vulnerability, 0, &avpch2); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Pre-emption-Vulnerability AVP"); + error_occurred = 1; + goto out; + } val.u32 = OGS_EPC_PRE_EMPTION_DISABLED; if (gx_message.session_data.session.qos.arp.pre_emption_vulnerability == OGS_5GC_PRE_EMPTION_ENABLED) val.u32 = OGS_EPC_PRE_EMPTION_ENABLED; - ret = fd_msg_avp_setvalue (avpch2, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch2, &val); + if (ret != 0) { + ogs_error("Failed to set Pre-emption-Vulnerability value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avpch1, MSG_BRW_LAST_CHILD, avpch2); + if (ret != 0) { + ogs_error("Failed to add Pre-emption-Vulnerability AVP"); + error_occurred = 1; + goto out; + } - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add ARP AVP"); + 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 Default-EPS-Bearer-QoS AVP"); + error_occurred = 1; + goto out; + } /* Set Supported Features */ ret = fd_msg_avp_new(ogs_diam_gx_supported_features, 0, &avp); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Supported-Features AVP"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_vendor_id, 0, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Vendor-Id AVP"); + error_occurred = 1; + goto out; + } val.i32 = OGS_3GPP_VENDOR_ID; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set Vendor-Id value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add Vendor-Id AVP"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_gx_feature_list_id, 0, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Feature-List-ID AVP"); + error_occurred = 1; + goto out; + } val.i32 = 1; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set Feature-List-ID value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add Feature-List-ID AVP"); + error_occurred = 1; + goto out; + } ret = fd_msg_avp_new(ogs_diam_gx_feature_list, 0, &avpch1); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to create Feature-List AVP"); + error_occurred = 1; + goto out; + } val.u32 = 0x0000000b; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); + ret = fd_msg_avp_setvalue(avpch1, &val); + if (ret != 0) { + ogs_error("Failed to set Feature-List value"); + error_occurred = 1; + goto out; + } + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch1); + if (ret != 0) { + ogs_error("Failed to add Feature-List AVP"); + 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 Supported-Features AVP"); + error_occurred = 1; + goto out; + } + } else if (cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { struct rx_sess_state *rx_sess_data = NULL, *next_rx_sess_data = NULL; @@ -599,80 +902,110 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, next_rx_sess_data, rx_sess_data) { rv = pcrf_rx_send_asr( rx_sess_data->sid, OGS_DIAM_RX_ABORT_CAUSE_BEARER_RELEASED); - ogs_expect(rv == OGS_OK); + if (rv != OGS_OK) { + ogs_warn("Failed to send ASR for RX session"); + /* Continue processing other sessions */ + } remove_rx_state(rx_sess_data); } } - /* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */ - ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); - ogs_assert(ret == 0); + if (!error_occurred) { + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; + goto out; + } - if (cc_request_type != OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { - /* Store this value in the session */ - ret = fd_sess_state_store(pcrf_gx_reg, sess, &sess_data); - ogs_assert(ret == 0); - ogs_assert(sess_data == NULL); - } else { - state_cleanup(sess_data, NULL, NULL); - } - - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - - ogs_debug("Tx Credit-Control-Answer"); - - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - PCRF_DIAM_PRIV_STATS_INC(gx.rx_ccr); - PCRF_DIAM_PRIV_STATS_INC(gx.tx_cca); - ) - - OGS_SESSION_DATA_FREE(&gx_message.session_data); - - return 0; - -out: - /* Set the Result-Code */ - 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 (sess_data) { - if (cc_request_type != - OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { + /* Store or cleanup session based on request type */ + if (cc_request_type != OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { /* Store this value in the session */ ret = fd_sess_state_store(pcrf_gx_reg, sess, &sess_data); - 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 */ } else { state_cleanup(sess_data, NULL, NULL); + sess_data = NULL; + } + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } + + ogs_debug("Tx Credit-Control-Answer"); + + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + PCRF_DIAM_PRIV_STATS_INC(gx.rx_ccr); + PCRF_DIAM_PRIV_STATS_INC(gx.tx_cca); + ) + + OGS_SESSION_DATA_FREE(&gx_message.session_data); + return 0; + } + +out: + /* Error handling */ + if (ans) { + /* Set the Result-Code */ + if (result_code == OGS_DIAM_AVP_UNSUPPORTED) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_AVP_UNSUPPORTED", NULL, NULL, 1); + } else if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1); + } else if (result_code == OGS_DIAM_MISSING_AVP) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_MISSING_AVP", NULL, NULL, 1); + } else { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + } + + if (ret != 0) { + ogs_error("Failed to set error result code"); + } + + /* Handle session state for error cases */ + if (sess_data) { + if (cc_request_type != + OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { + /* Store this value in the session */ + ret = fd_sess_state_store(pcrf_gx_reg, sess, &sess_data); + if (ret != 0) { + ogs_error("Failed to store session state in error path"); + } + sess_data = NULL; /* Ownership transferred */ + } else { + state_cleanup(sess_data, NULL, NULL); + sess_data = NULL; + } + } + + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); } } - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - + /* Update error stats */ OGS_DIAM_STATS_MTX( PCRF_DIAM_PRIV_STATS_INC(gx.rx_ccr); PCRF_DIAM_PRIV_STATS_INC(gx.rx_ccr_error); ) + /* Always free session data */ OGS_SESSION_DATA_FREE(&gx_message.session_data); return 0; @@ -1054,133 +1387,208 @@ out: static void pcrf_gx_raa_cb(void *data, struct msg **msg) { int ret; - struct sess_state *sess_data = NULL; struct timespec ts; - struct session *session; - struct avp *avp, *avpch1; - struct avp_hdr *hdr; + struct session *session = NULL; + struct avp *avp = NULL, *avpch1 = NULL; + struct avp_hdr *hdr = NULL; unsigned long dur; int error = 0; - int new; - - uint32_t result_code; + int new = 0; + uint32_t result_code = 0; ogs_debug("[PCRF] Rx Re-Auth-Answer"); + /* Validate input parameters */ + if (!msg || !*msg) { + ogs_error("Invalid message pointer"); + return; + } + + /* Get current timestamp */ ret = clock_gettime(CLOCK_REALTIME, &ts); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to get current time"); + goto cleanup; + } /* 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"); + error++; + goto cleanup; + } + if (new != 0) { + ogs_error("Session should already exist"); + error++; + goto cleanup; + } + + /* Retrieve session state */ ret = fd_sess_state_retrieve(pcrf_gx_reg, session, &sess_data); - ogs_assert(ret == 0); + if (ret != 0) { + ogs_error("Failed to retrieve session state"); + error++; + goto cleanup; + } + if (!sess_data) { ogs_error("No Session Data"); - return; + error++; + goto cleanup; + } + + /* Validate data pointer consistency */ + if ((void *)sess_data != data) { + ogs_error("Session data pointer mismatch"); + error++; + goto cleanup; } - ogs_assert((void *)sess_data == data); /* 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"); + error++; + goto parse_experimental_result; + } + 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"); + error++; + goto parse_experimental_result; + } result_code = hdr->avp_value->i32; - ogs_debug(" Result Code: %d", hdr->avp_value->i32); + ogs_debug(" Result Code: %d", result_code); } else { +parse_experimental_result: + /* 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"); + error++; + goto parse_origin_host; + } + 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"); + error++; + goto parse_origin_host; + } + 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"); + error++; + goto parse_origin_host; + } result_code = hdr->avp_value->i32; ogs_debug(" Experimental Result Code: %d", result_code); } } else { - ogs_error("no Result-Code"); + ogs_error("No Result-Code or Experimental-Result found"); error++; } } +parse_origin_host: /* 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); - ogs_debug(" From '%.*s'", - (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + if (ret == 0 && hdr) { + ogs_debug(" From '%.*s'", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_warn("Failed to get Origin-Host AVP header"); + } } else { - ogs_error("no_Origin-Host"); - error++; + 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); - ogs_debug(" ('%.*s')", - (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + if (ret == 0 && hdr) { + ogs_debug(" ('%.*s')", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_warn("Failed to get Origin-Realm AVP header"); + } } else { - ogs_error("no_Origin-Realm"); - error++; + ogs_warn("No Origin-Realm found"); } - /* Free the message */ - OGS_DIAM_STATS_MTX( - 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) + /* Update statistics and calculate duration if we have valid session data */ + if (sess_data) { + OGS_DIAM_STATS_MTX( + 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; + ogs_diam_stats_self()->stats.avg = dur; + } + + if (error) + ogs_diam_stats_self()->stats.nb_errs++; + else + ogs_diam_stats_self()->stats.nb_recv++; + + PCRF_DIAM_PRIV_STATS_INC(gx.rx_raa); + ) + + /* Display processing duration */ + if (ts.tv_nsec > sess_data->ts.tv_nsec) { + ogs_trace("Processed 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_diam_stats_self()->stats.shortest = dur; - ogs_diam_stats_self()->stats.longest = dur; - ogs_diam_stats_self()->stats.avg = dur; + ogs_trace("Processed 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); } - if (error) - ogs_diam_stats_self()->stats.nb_errs++; - else - ogs_diam_stats_self()->stats.nb_recv++; - PCRF_DIAM_PRIV_STATS_INC(gx.rx_raa); - ) + /* Store session state back */ + ret = fd_sess_state_store(pcrf_gx_reg, session, &sess_data); + if (ret != 0) { + ogs_error("Failed to store session state"); + } else { + sess_data = NULL; /* Ownership transferred */ + } + } - /* 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); - - ret = fd_sess_state_store(pcrf_gx_reg, session, &sess_data); - ogs_assert(ret == 0); - ogs_assert(sess_data == NULL); - - ret = fd_msg_free(*msg); - ogs_assert(ret == 0); - *msg = NULL; +cleanup: + /* Always free the message */ + if (msg && *msg) { + ret = fd_msg_free(*msg); + if (ret != 0) { + ogs_error("Failed to free message"); + } + *msg = NULL; + } return; } diff --git a/src/pcrf/pcrf-rx-path.c b/src/pcrf/pcrf-rx-path.c index dd691ccf1..49ec29359 100644 --- a/src/pcrf/pcrf-rx-path.c +++ b/src/pcrf/pcrf-rx-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -104,156 +104,213 @@ static int pcrf_rx_fb_cb(struct msg **msg, struct avp *avp, return ENOTSUP; } -static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp, +static int pcrf_rx_aar_cb(struct msg **msg, struct avp *avp, struct session *sess, void *opaque, enum disp_action *act) { 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); - 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_INET_NTOP(hdr->avp_value->os.data, buf)); + 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 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); - paa = (ogs_paa_t *)hdr->avp_value->os.data; - ogs_assert(paa); - ogs_assert(paa->len == OGS_IPV6_LEN * 8 /* 128bit */); - gx_sid = (os0_t)pcrf_sess_find_by_ipv6(paa->addr6); - if (!gx_sid) { - ogs_warn("Cannot find Gx Sesson for IPv6:%s", - OGS_INET6_NTOP(hdr->avp_value->os.data, buf)); + if (ret == 0 && hdr) { + paa = (ogs_paa_t *)hdr->avp_value->os.data; + 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 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, + ogs_error("OVERFLOW rx_message.ims_data.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); + &avpch3, NULL); + 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,99 +429,148 @@ 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); } - /* 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"); + 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) { + sess_data->gx_sid = (os0_t)ogs_strdup((char *)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); + if (ret == 0) { + val.i32 = OGS_DIAM_RX_IP_CAN_TYPE_3GPP_EPS; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } + 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); + if (ret == 0) { + val.i32 = OGS_DIAM_RAT_TYPE_EUTRAN; + ret = fd_msg_avp_setvalue(avp, &val); + if (ret == 0) { + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + } + } + if (ret != 0) { + ogs_error("Failed to add RAT-Type AVP"); + } + + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); + if (ret != 0) { + ogs_error("Failed to set success result code"); + error_occurred = 1; goto out; } + + /* Store session state */ + ret = fd_sess_state_store(pcrf_rx_reg, sess, &sess_data); + 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); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } + + ogs_debug("[PCRF] Tx AA-Answer"); + + /* Add to stats */ + OGS_DIAM_STATS_MTX( + OGS_DIAM_STATS_INC(nb_echoed); + PCRF_DIAM_PRIV_STATS_INC(rx.rx_aar); + PCRF_DIAM_PRIV_STATS_INC(rx.tx_aaa); + ) + + 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); + } else if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1); + } else if (result_code == OGS_DIAM_MISSING_AVP) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_MISSING_AVP", NULL, NULL, 1); + } else { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + } + + if (ret != 0) { + ogs_error("Failed to set error result code"); + } + + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send error response"); + } } - /* Store Gx Session-Id in this session */ - if (!sess_data->gx_sid) - sess_data->gx_sid = (os0_t)ogs_strdup((char *)gx_sid); - ogs_assert(sess_data->gx_sid); - - /* Set IP-Can-Type */ - ret = fd_msg_avp_new(ogs_diam_rx_ip_can_type, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_RX_IP_CAN_TYPE_3GPP_EPS; - 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 RAT-Type */ - ret = fd_msg_avp_new(ogs_diam_rat_type, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_RAT_TYPE_EUTRAN; - 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 */ - ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); - ogs_assert(ret == 0); - - /* Store this value in the session */ - ret = fd_sess_state_store(pcrf_rx_reg, sess, &sess_data); - ogs_assert(ret == 0); - ogs_assert(sess_data == NULL); - - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - - ogs_debug("[PCRF] Tx AA-Answer"); - - /* Add this value to the stats */ - OGS_DIAM_STATS_MTX( - OGS_DIAM_STATS_INC(nb_echoed); - PCRF_DIAM_PRIV_STATS_INC(rx.rx_aar); - PCRF_DIAM_PRIV_STATS_INC(rx.tx_aaa); - ) - - ogs_ims_data_free(&rx_message.ims_data); - - return 0; - -out: - 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); - } - - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - + /* Update error stats */ OGS_DIAM_STATS_MTX( PCRF_DIAM_PRIV_STATS_INC(rx.rx_aar); PCRF_DIAM_PRIV_STATS_INC(rx.rx_aar_error); ) - state_cleanup(sess_data, NULL, NULL); + /* 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,104 +700,144 @@ 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); - ogs_debug(" From '%.*s'", - (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + 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); - ogs_debug(" ('%.*s')", - (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + 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); ) - ret = fd_msg_free(*msg); - ogs_assert(ret == 0); - *msg = NULL; +cleanup: + /* Always free the message */ + if (msg && *msg) { + ret = fd_msg_free(*msg); + if (ret != 0) { + ogs_error("Failed to free message"); + } + *msg = NULL; + } return; } -static int pcrf_rx_str_cb( struct msg **msg, struct avp *avp, +static int pcrf_rx_str_cb(struct msg **msg, struct avp *avp, struct session *sess, void *opaque, enum disp_action *act) { 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,121 +846,191 @@ 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); - sess_data->termination_cause = hdr->avp_value->i32; - switch (sess_data->termination_cause) { - case OGS_DIAM_TERMINATION_CAUSE_DIAMETER_LOGOUT: - break; - default: - ogs_error("Termination-Cause Error : [%d]", - sess_data->termination_cause); - break; + if (ret == 0 && hdr) { + sess_data->termination_cause = hdr->avp_value->i32; + switch (sess_data->termination_cause) { + case OGS_DIAM_TERMINATION_CAUSE_DIAMETER_LOGOUT: + break; + default: + ogs_error("Termination-Cause Error : [%d]", + sess_data->termination_cause); + break; + } + } else { + ogs_error("Failed to get Termination-Cause AVP header"); } } else { - ogs_error("no_Termination-Cause"); + 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 */ - ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); - ogs_assert(ret == 0); + if (!error_occurred) { + /* Set success result code */ + ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); + 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); + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + if (ret != 0) { + ogs_error("Failed to send message"); + error_occurred = 1; + goto out; + } - ogs_debug("[PCRF] Tx Session-Termination-Answer"); + ogs_debug("[PCRF] Tx Session-Termination-Answer"); - /* Add this value to the 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); - ) + /* 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); + ) - state_cleanup(sess_data, NULL, NULL); - ogs_ims_data_free(&rx_message.ims_data); + /* Clean up session state */ + state_cleanup(sess_data, NULL, NULL); + ogs_ims_data_free(&rx_message.ims_data); - return 0; - -out: - 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); + return 0; } - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - ogs_debug("[PCRF] Tx Session-Termination-Answer"); +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); + } else if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1); + } else if (result_code == OGS_DIAM_MISSING_AVP) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_MISSING_AVP", NULL, NULL, 1); + } else { + ret = fd_msg_rescode_set(ans, + (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); + 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; diff --git a/src/smf/gx-path.c b/src/smf/gx-path.c index d66b7991c..6fa7148e6 100644 --- a/src/smf/gx-path.c +++ b/src/smf/gx-path.c @@ -1,5 +1,5 @@ /* Gx Interface, 3GPP TS 29.212 section 4 - * Copyright (C) 2019-2024 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * 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; } diff --git a/src/smf/gy-path.c b/src/smf/gy-path.c index b5848405b..b7e4a3b18 100644 --- a/src/smf/gy-path.c +++ b/src/smf/gy-path.c @@ -1,6 +1,7 @@ /* Gy Interface, 3GPP TS 32.299 * Copyright (C) 2019 by Sukchan Lee * Copyright (C) 2022 by sysmocom - s.f.m.c. GmbH + * Copyright (C) 2025 by Sukchan Lee * * 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; } diff --git a/src/smf/s6b-path.c b/src/smf/s6b-path.c index 826209653..ba3471738 100644 --- a/src/smf/s6b-path.c +++ b/src/smf/s6b-path.c @@ -1,5 +1,5 @@ /* 3GPP TS 29.273 section 9 - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * 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;