Files
m241Neelima/components/ip_net2-6.9/ipdiameter/src/ipdiameter_tx.c
T
2026-07-30 11:19:44 +05:30

1417 lines
43 KiB
C

/* ipdiameter_tx.c - Diameter packet transmission routines */
/*
* Copyright (c) 2007 Wind River Systems, Inc.
*
* The right to copy, distribute or otherwise make use of this software
* may be licensed only pursuant to the terms of an applicable Wind River
* license agreement. No license to Wind River intellectual property rights
* is granted herein. All rights not licensed by Wind River are reserved
* by Wind River.
*/
/*
modification history
--------------------
01l,20mar09,tlu Add function to format and send out RAA pkts
01k,10mar09,tlu Fix Linux build warning
01j,06feb09,tlu Modify ASA and STR pkt to use application's appl id in
the pkt's header
01i,10oct07,tlu Port to Linux
01h,20sep07,tlu Take a peer's semaphore before transmiting over the peer's
TLS connection
01g,19sep07,tlu Modify file name comment for apigen
01f,13aug07,tlu Add TLS support
01e,10jul07,tlu Reset tried server flag if found a reachable server
01d,06jul07,tlu Add redundant server handling
01c,04jul07,tlu Add application ID AVPs to CER/CEA packets
01b,19jun07,tlu Add AVP flag and vendor_id to ipdiameter_avp_add_** functions
01a,12apr07,tlu Created.
*/
/*
DESCRIPTION
This library provides routines to transmit Diameter packets.
To use this feature, include the following component: INCLUDE_IPDIAMETERC
INCLUDE FILES: ipdiameter.h
*/
/*
****************************************************************************
* INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_type.h>
#include <ipcom_os.h>
#include <ipcom_list.h>
#include <ipcom_err.h>
#include <ipcom_syslog.h>
#include <ipcom_time.h>
#include <ipcom_clib.h>
#include "ipdiameter.h"
/*
****************************************************************************
* EXTERN PROTOTYPES
****************************************************************************
*/
IP_EXTERN Ipdiameter_data ipdiameter;
/*
****************************************************************************
* DEFINES
****************************************************************************
*/
/* This is a compile flag, turning on it will build debug message into image */
#undef DIAMETER_DEBUG
/* The following are for Open Diameter tests */
#undef OPEN_DIAMETER_TEST
/*
****************************************************************************
* LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdiameter_pkt_send
*===========================================================================
* Description: send the diameter message out
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_pkt_send(Ip_fd fd, SSL *ssl, Ipdiameter_header *package)
{
Ip_err retval = IPCOM_SUCCESS;
Ip_u32 code, length;
#ifdef IPSSL
int len;
#endif /* IPSSL */
#ifdef DIAMETER_DEBUG
ipcom_printf("Calling ipdiameter_pkt_send, fd %d, ssl %ld\n", fd, ssl);
#endif
if (fd == IP_INVALID_SOCKET)
return IPDIAMETER_ERR_NO_SERVER;
if (package == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_pkt_send(): NULL package");
return IPCOM_ERR_INVALID_ARG;
}
code = ipdiameter_get_hdr_code((Ip_u32 *)package);
length = ipdiameter_get_hdr_length((Ip_u32 *)package);
#ifdef DIAMETER_DEBUG
ipcom_printf("ipdiameter_pkt_send -> tx DIAMETER packet [code=%lu, flags=%x, length=%lu, appl_id=%lu, hbh_id=%lu, e2e_id=%lu]\n",
code, package->flags, length, ip_ntohl(package->appl_id),
ip_ntohl(package->hbh_id), ip_ntohl(package->e2e_id));
ipdiameter_print_pkt(package);
#endif
#ifdef IPSSL
if (ssl != IP_NULL)
{
#ifdef DIAMETER_DEBUG
ipcom_printf("ipdiameter_pkt_send: write to TLS, ssl %d\n", ssl);
#endif
len = ipdiameter_tls_write(ssl, (char *)package, length);
if (len == 0)
{
IPCOM_LOG2(WARNING, "ipdiameter_pkt_send(): tls_write(%d, %d) failed",
fd, ssl);
/* peer closed the connection */
retval = IPCOM_ERR_FAILED;
}
}
else
#endif /* IPSSL */
{
#ifdef DIAMETER_DEBUG
ipcom_printf("ipdiameter_pkt_send: write to socket %d\n", fd);
#endif
/* Use ipcom_sendto() to transmit the DIAMETER TCP packet. */
if (ipcom_send(fd, package, length, 0) == IP_SOCKERR)
{
Ip_socklen_t optlen;
int error;
IPCOM_LOG2(WARNING, "ipdiameter_pkt_send(): ipcom_sendto(%d) failed : %s",
fd,
ipcom_strerror(ipcom_errno));
/* Clear socket errno. */
optlen = sizeof(error);
(void)ipcom_getsockopt(fd, IP_SOL_SOCKET, IP_SO_ERROR, &error, &optlen);
retval = IP_SOCKERR;
}
}
return retval;
}
/*
*===========================================================================
* ipdiameter_session_pkt_send
*===========================================================================
* Description: send the diameter message to the server associated with the session
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_session_pkt_send(Ipdiameter_session *session, Ipdiameter_header *package)
{
Ip_err retval = IPCOM_SUCCESS;
Ip_fd fd = IP_INVALID_SOCKET;
Ipdiameter_peer_entry *peer;
Ip_u32 length;
Ip_u8 *data;
Ip_s8 index_v;
#ifdef DIAMETER_DEBUG
ipcom_printf("Calling ipdiameter_session_pkt_send\n");
ipdiameter_print_session(session);
#endif
if (session == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_session_pkt_send: invalid session specified\n");
return IPCOM_ERR_INVALID_ARG;
}
/* Add Session-ID AVP if not already present */
retval = ipdiameter_get_avp(package, DIAMETER_AVP_CODE_Session_Id, &length, &data);
if (retval != IPCOM_SUCCESS)
{
/* Add Session-Id AVP */
length = (Ip_u32)ipcom_strlen(session->session_id);
(void)ipdiameter_avp_add_array(package, DIAMETER_AVP_CODE_Session_Id,
DIAMETER_AVP_M_FLAG, IP_NULL,
(Ip_u8 *)session->session_id, length);
}
/* decide next hop to send the packet */
if (session->peer == IP_NULL)
{
peer = (Ipdiameter_peer_entry *)ipdiameter_session_select_route(session);
/* select a different server if cannot find next hop */
while (peer == IP_NULL)
{
if (ipdiameter_set_server(session) == IPCOM_SUCCESS)
{
peer = (Ipdiameter_peer_entry *)ipdiameter_session_select_route(session);
if (peer)
{
ipdiameter_session_update_reqs(session);
/* Found route, reset the tried server record */
ipdiameter_reset_tried_servers(session);
}
}
else
{
IPCOM_LOG0(ERR, "ipdiameter_session_pkt_send: cannot find a route\n");
return IPCOM_ERR_NO_ROUTE;
}
}
ipdiameter_session_set_peer(session, (struct Ipdiameter_peer_entry *)peer);
}
else
peer = (Ipdiameter_peer_entry *)session->peer;
/* start a timer for the request packet */
retval = ipdiameter_pkt_start_timer(package);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(WARNING, "ipdiameter_session_pkt_send: failed to start re-transmission timer\n");
if ((peer->state == DIAMETER_PEER_STATE_R_OPEN) ||
(peer->state == DIAMETER_PEER_STATE_I_OPEN))
goto transmit;
retval = ipdiameter_peer_add_tx_pending_pkt(peer,
(struct Ipdiameter_header *)package);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_session_pkt_send: fail to add package to peer's transmiting list\n");
return retval;
}
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_START);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_session_pkt_send: fail to run peer FSM\n");
return retval;
transmit:
/* Pick matching IPv4 or IPv6 socket. */
index_v = session->selected_server;
#ifdef IPCOM_USE_INET
if (((Ipdiameter_server *)session->serv_list[index_v])->server_addr.sa.sa_family == IP_AF_INET)
fd = ((Ipdiameter_peer_entry *)session->peer)->fd;
#endif
#ifdef IPCOM_USE_INET6
if (((Ipdiameter_server *)session->serv_list[index_v])->server_addr.sa.sa_family == IP_AF_INET6)
fd = ((Ipdiameter_peer_entry *)session->peer)->fd6;
#endif
if (fd == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR, "ipdiameter_session_pkt_send: No valid socket descriptor to send to peer %s",
ipdiameter_addr_to_str(&((Ipdiameter_peer_entry *)session->peer)->peer_addr));
return IPCOM_ERR_INVALID_ARG;
}
#ifdef DIAMETER_DEBUG
ipcom_printf("ipdiameter_session_pkt_send: socket descriptor %d, to send to peer %s\n",
fd, ipdiameter_addr_to_str(&((Ipdiameter_peer_entry *)session->peer)->peer_addr));
#endif
ipdiameter_pkt_set_starttime(package);
/* Send the packet out */
IPDIAMETER_PEER_LOCK(peer);
retval = ipdiameter_pkt_send(fd, peer->ssl, package);
IPDIAMETER_PEER_UNLOCK(peer);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_session_pkt_send: failed to send out the package\n");
return retval;
}
/*******************************************************************************
*
* ipdiameter_peer_pkt_send - send a Diameter package out to a peer
*
* This routine transmits a Diameter package to a Diameter peer.
*
* Note that this function is exported to application API to be used
* only by ipdiameter_register_access_function(). Applications must NOT
* modify any fields in the peer structure.
*
* Parameters:
*
* \is
* \i <peer>
* Diameter peer.
* \i <package>
* A Diameter package.
* \ie
*
* RETURNS:
* \is
* \i IPCOM_SUCCESS
* \i IPCOM_ERR_INVALID_ARG if peer is NULL
* \i IPCOM_ERR_FAILED if it fails to send out the package
* \ie
*
* ERRNO: N/A
*
*/
IP_PUBLIC Ip_err ipdiameter_peer_pkt_send
(
Ipdiameter_peer_entry *peer,
Ipdiameter_header *package
)
{
Ip_err retval = IPCOM_SUCCESS;
Ip_fd fd = IP_INVALID_SOCKET;
if (peer == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_peer_pkt_send: invalid peer specified\n");
return IPCOM_ERR_INVALID_ARG;
}
/* Pick matching IPv4 or IPv6 socket. */
#ifdef IPCOM_USE_INET
if (peer->peer_addr.sa.sa_family == IP_AF_INET)
fd = peer->fd;
#endif
#ifdef IPCOM_USE_INET6
if (peer->peer_addr.sa.sa_family == IP_AF_INET6)
fd = peer->fd6;
#endif
if (fd == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR, "ipdiameter_peer_pkt_send: No valid socket descriptor to send to peer %s",
ipdiameter_addr_to_str(&peer->peer_addr));
return IPCOM_ERR_INVALID_ARG;
}
#ifdef DIAMETER_DEBUG
ipcom_printf("ipdiameter_peer_pkt_send: fd %d, to send to peer %s\n",
fd, ipdiameter_addr_to_str(&peer->peer_addr));
#endif
ipdiameter_pkt_set_starttime(package);
/* start a timer for the request packet */
retval = ipdiameter_pkt_start_timer(package);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(WARNING, "ipdiameter_peer_pkt_send: failed to start re-transmission timer\n");
/* Send the packet out */
IPDIAMETER_PEER_LOCK(peer);
retval = ipdiameter_pkt_send(fd, peer->ssl, package);
IPDIAMETER_PEER_UNLOCK(peer);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_peer_pkt_send: failed to send out the package\n");
return retval;
}
/*
*===========================================================================
* ipdiameter_send_ASA
*===========================================================================
* Description: Complete an abort session answer packet and send out
*
* 8.5.2. Abort-Session-Answer
*
* The Abort-Session-Answer (ASA), indicated by the Command-Code set to
* 274 and the message flags' 'R' bit clear, is sent in response to the
* ASR. The Result-Code AVP MUST be present, and indicates the
* disposition of the request.
*
* If the session identified by Session-Id in the ASR was successfully
* terminated, Result-Code is set to DIAMETER_SUCCESS. If the session
* is not currently active, Result-Code is set to
* DIAMETER_UNKNOWN_SESSION_ID. If the access device does not stop the
* session for any other reason, Result-Code is set to
* DIAMETER_UNABLE_TO_COMPLY.
*
* Message Format
*
* <ASA> ::= < Diameter Header: 274, PXY >
* < Session-Id >
* { Result-Code }
* { Origin-Host }
* { Origin-Realm }
* [ User-Name ]
* [ Origin-State-Id ]
* [ Error-Message ]
* [ Error-Reporting-Host ]
* * [ Failed-AVP ]
* * [ Redirect-Host ]
* [ Redirect-Host-Usage ]
* [ Redirect-Max-Cache-Time ]
* * [ Proxy-Info ]
* * [ AVP ]
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_ASA(Ipdiameter_session *session, Ip_fd fd, SSL *ssl,
Ipdiameter_header *ASR_package, Ip_u32 result_code)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
Ip_u8 *user_name = IP_NULL;
char session_id[IPDIAMETER_MAX_SESSION_ID_SIZE] = IPDIAMETER_NULL_STRING;
message = ipdiameter_answer_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Abort_Session_Answer);
message->appl_id = ASR_package->appl_id;
message->hbh_id = ASR_package->hbh_id;
message->e2e_id = ASR_package->e2e_id;
/* Get Session-Id */
if (session != IP_NULL)
ipcom_strcpy(session_id, session->session_id);
else
(void)ipdiameter_avp_get_session_id(ASR_package, session_id);
/* Add Session-Id AVP */
length = (Ip_u32)ipcom_strlen(session_id);
retval = ipdiameter_avp_add_array(message, DIAMETER_AVP_CODE_Session_Id,
DIAMETER_AVP_M_FLAG, IP_NULL,
(Ip_u8 *)session_id, length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_ASA: failed to add Session-Id AVP\n");
goto out;
}
/* Add Result-Code AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Result_Code,
0, IP_NULL, result_code);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_ASA: failed to add Result-Code AVP\n");
goto out;
}
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_ASA: failed to add Origin-Host AVP\n");
goto out;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_ASA: failed to add Origin-Realm AVP\n");
goto out;
}
/* Optional: add User-Name AVP */
(void)ipdiameter_get_avp(ASR_package, DIAMETER_AVP_CODE_User_Name, &length, &user_name);
if (user_name != IP_NULL)
{
retval = ipdiameter_avp_add_array(message, DIAMETER_AVP_CODE_User_Name,
0, IP_NULL, user_name, length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_ASA: failed to add User-Name AVP\n");
goto out;
}
}
/* Send the packet out */
if (session != IP_NULL)
retval = ipdiameter_session_pkt_send(session, message);
else
retval = ipdiameter_pkt_send(fd, ssl, message);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_send_ASA: failed to send out ASA message\n");
out:
ipdiameter_answer_pkt_free(message);
return retval;
}
/*
*===========================================================================
* ipdiameter_send_RAA
*===========================================================================
* Description: Complete a Re-Auth-Answer packet and send out
*
* 8.3.2. Re-Auth-Answer
*
* The Re-Auth-Answer (RAA), indicated by the Command-Code set to
* 258 and the message flags' 'R' bit clear, is sent in response to
* the RAR. The Result-Code AVP MUST be present, and indicates
* the disposition of the request.
*
* A successful RAA message MUST be followed by an application-specific
* authentication and/or authorization message.
*
* Message Format
*
* <RAA> ::= < Diameter Header: 258, PXY >
* < Session-Id >
* { Result-Code }
* { Origin-Host }
* { Origin-Realm }
* [ User-Name ]
* [ Origin-State-Id ]
* [ Error-Message ]
* [ Error-Reporting-Host ]
* * [ Failed-AVP ]
* * [ Redirect-Host ]
* [ Redirect-Host-Usage ]
* [ Redirect-Max-Cache-Time ]
* * [ Proxy-Info ]
* * [ AVP ]
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_RAA(Ipdiameter_session *session, Ip_fd fd, SSL *ssl,
Ipdiameter_header *RAR_package, Ip_u32 result_code)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
Ip_u8 *user_name = IP_NULL;
Ip_u8 *server_realm = IP_NULL;
char session_id[IPDIAMETER_MAX_SESSION_ID_SIZE] = IPDIAMETER_NULL_STRING;
message = ipdiameter_answer_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Re_Auth_Answer);
message->appl_id = RAR_package->appl_id;
message->hbh_id = RAR_package->hbh_id;
message->e2e_id = RAR_package->e2e_id;
/* Get Session-Id */
if (session != IP_NULL)
ipcom_strcpy(session_id, session->session_id);
else
(void)ipdiameter_avp_get_session_id(RAR_package, session_id);
/* Add Session-Id AVP */
length = (Ip_u32)ipcom_strlen(session_id);
retval = ipdiameter_avp_add_array(message, DIAMETER_AVP_CODE_Session_Id,
DIAMETER_AVP_M_FLAG, IP_NULL,
(Ip_u8 *)session_id, length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_RAA: failed to add Session-Id AVP\n");
goto out;
}
/* Add Result-Code AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Result_Code,
0, IP_NULL, result_code);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_RAA: failed to add Result-Code AVP\n"); goto out;
}
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_RAA: failed to add Origin-Host AVP\n"); goto out;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_RAA: failed to add Origin-Realm AVP\n");
goto out;
}
/* Optional: add User-Name AVP */
(void)ipdiameter_get_avp(RAR_package, DIAMETER_AVP_CODE_User_Name, &length, &user_name);
if (user_name != IP_NULL)
{
retval = ipdiameter_avp_add_array(message, DIAMETER_AVP_CODE_User_Name,
0, IP_NULL, user_name, length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_RAA: failed to add User-Name AVP");
goto out;
}
}
/* Add Server-Realm AVP */
(void)ipdiameter_get_avp(RAR_package, DIAMETER_AVP_CODE_Origin_Realm,
&length, &server_realm);
if (server_realm != IP_NULL)
{
retval = ipdiameter_avp_add_array(message,
DIAMETER_AVP_CODE_Destination_Realm,
DIAMETER_AVP_M_FLAG, IP_NULL,
server_realm, length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_RAA: failed to add Server-Realm AVP");
goto out;
}
}
/* Send the packet out */
if (session != IP_NULL)
retval = ipdiameter_session_pkt_send(session, message);
else
retval = ipdiameter_pkt_send(fd, ssl, message);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_send_RAA: failed to send out RAA message\n");
out:
ipdiameter_answer_pkt_free(message);
return retval;
}
/*
*===========================================================================
* ipdiameter_send_STR
*===========================================================================
* Description: Complete a session termination request packet and send out
*
* 8.4.1. Session-Termination-Request
*
* The Session-Termination-Request (STR), indicated by the Command-Code
* set to 275 and the Command Flags' 'R' bit set, is sent by the access
* device to inform the Diameter Server that an authenticated and/or
* authorized session is being terminated.
*
* Message Format
*
* <STR> ::= < Diameter Header: 275, REQ, PXY >
* < Session-Id >
* { Origin-Host }
* { Origin-Realm }
* { Destination-Realm }
* { Auth-Application-Id }
* { Termination-Cause }
* [ User-Name ]
* [ Destination-Host ]
* * [ Class ]
* [ Origin-State-Id ]
* * [ Proxy-Info ]
* * [ Route-Record ]
* * [ AVP ]
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_STR(Ipdiameter_session *session, Ip_u32 cause)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
Ip_s8 index_v;
message = ipdiameter_request_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Session_Termination_Request);
#ifdef OPEN_DIAMETER_TEST
message->appl_id = (Ip_u32)ip_htonl(DIAMETER_Common_Message);
#else
message->appl_id = (Ip_u32)ip_htonl(session->appl_id);
#endif /* OPEN_DIAMETER_TEST */
message->hbh_id = ipdiameter_get_unique_id();
message->e2e_id = message->hbh_id;
/* Insert request into session's request list */
ipdiameter_session_add_req(session, (struct Ipdiameter_header *)message);
/* Add Session-Id AVP */
length = (Ip_u32)ipcom_strlen(session->session_id);
retval = ipdiameter_avp_add_array(message, DIAMETER_AVP_CODE_Session_Id,
DIAMETER_AVP_M_FLAG, IP_NULL,
(Ip_u8 *)session->session_id, length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_STR: failed to add Session-Id AVP\n");
goto err;
}
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_STR: failed to add Origin-Host AVP\n");
goto err;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_STR: failed to add Origin-Realm AVP\n");
goto err;
}
/* Add Destination-Realm AVP */
index_v = session->selected_server;
length = (Ip_u32)ipcom_strlen(((Ipdiameter_server *)session->serv_list[index_v])->realm);
retval = ipdiameter_avp_add_array(message, DIAMETER_AVP_CODE_Destination_Realm,
DIAMETER_AVP_M_FLAG, IP_NULL,
(Ip_u8 *)(((Ipdiameter_server *)session->serv_list[index_v])->realm),
length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_STR: failed to add Destination-Realm AVP\n");
goto err;
}
/* Add Auth-Application-Id AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Auth_Application_Id,
DIAMETER_AVP_M_FLAG, IP_NULL, session->appl_id);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_STR: failed to add Auth-Application-Id AVP\n");
goto err;
}
/* Add Termination-Cause AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Termination_Cause,
DIAMETER_AVP_M_FLAG, IP_NULL, cause);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_STR: failed to add Termination-Cause AVP\n");
goto err;
}
/* Send the packet out */
retval = ipdiameter_session_pkt_send(session, message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_STR: failed to send out STR message\n");
goto err;
}
return retval;
err:
ipdiameter_request_pkt_free(message);
return retval;
}
/*
*===========================================================================
* ipdiameter_send_CER
*===========================================================================
* Description: Complete a capabilities exchange Request packet and send out
*
* 5.3.1. Capabilities-Exchange-Request
*
* The Capabilities-Exchange-Request (CER), indicated by the Command-
* Code set to 257 and the Command Flags' 'R' bit set, is sent to
* exchange local capabilities. Upon detection of a transport failure,
* this message MUST NOT be sent to an alternate peer.
*
* When Diameter is run over SCTP [SCTP], which allows for connections
* to span multiple interfaces and multiple IP addresses, the
* Capabilities-Exchange-Request message MUST contain one Host-IP-
* Address AVP for each potential IP address that MAY be locally used
* when transmitting Diameter messages.
*
*
* Message Format
*
* <CER> ::= < Diameter Header: 257, REQ >
* { Origin-Host }
* { Origin-Realm }
* 1* { Host-IP-Address }
* { Vendor-Id }
* { Product-Name }
* [ Origin-State-Id ]
* * [ Supported-Vendor-Id ]
* * [ Auth-Application-Id ]
* * [ Inband-Security-Id ]
* * [ Acct-Application-Id ]
* * [ Vendor-Specific-Application-Id ]
* [ Firmware-Revision ]
* * [ AVP ]
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_CER(Ipdiameter_peer_entry *peer)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
message = ipdiameter_request_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Capabilities_Exchange_Request);
message->appl_id = ip_htonl(DIAMETER_Common_Message);
message->hbh_id = ipdiameter_get_unique_id();
message->e2e_id = message->hbh_id;
/* Insert request into peer's request list */
ipdiameter_peer_add_req(peer, (struct Ipdiameter_header *)message);
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Origin-Host AVP\n");
goto err;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Origin-Realm AVP\n");
goto err;
}
/* Add Host-IP-Address AVP */
retval = ipdiameter_avp_add_host_address(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Host-IP-Address AVP\n");
goto err;
}
/* Add Vendor-Id AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Vendor_Id,
DIAMETER_AVP_M_FLAG, IP_NULL, ipdiameter.vendor_id);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Vendor-Id AVP\n");
goto err;
}
/* Add Product-Name AVP */
length = (Ip_u32)ipcom_strlen(IPDIAMETER_PRODUCT_NAME);
retval = ipdiameter_avp_add_array(message, DIAMETER_AVP_CODE_Product_Name,
0, IP_NULL, (Ip_u8 *)IPDIAMETER_PRODUCT_NAME, length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Product-Name AVP\n");
goto err;
}
/* Add Application-Id AVPs */
retval = ipdiameter_avp_add_appl_ids(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Application-Id AVP\n");
goto err;
}
/* Send the packet out */
retval = ipdiameter_peer_pkt_send(peer, message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to send out CER message\n");
goto err;
}
return retval;
err:
ipdiameter_request_pkt_free(message);
return retval;
}
/*
*===========================================================================
* ipdiameter_send_CEA
*===========================================================================
* Description: Complete a capabilities exchange Answer packet and send out
*
* 5.3.2. Capabilities-Exchange-Answer
*
* The Capabilities-Exchange-Answer (CEA), indicated by the Command-Code
* set to 257 and the Command Flags' 'R' bit cleared, is sent in
* response to a CER message.
*
* When Diameter is run over SCTP [SCTP], which allows connections to
* span multiple interfaces, hence, multiple IP addresses, the
* Capabilities-Exchange-Answer message MUST contain one Host-IP-Address
* AVP for each potential IP address that MAY be locally used when
* transmitting Diameter messages.
*
* Message Format
*
* <CEA> ::= < Diameter Header: 257 >
* { Result-Code }
* { Origin-Host }
* { Origin-Realm }
* 1* { Host-IP-Address }
* { Vendor-Id }
* { Product-Name }
* [ Origin-State-Id ]
* [ Error-Message ]
* * [ Failed-AVP ]
* * [ Supported-Vendor-Id ]
* * [ Auth-Application-Id ]
* * [ Inband-Security-Id ]
* * [ Acct-Application-Id ]
* * [ Vendor-Specific-Application-Id ]
* [ Firmware-Revision ]
* * [ AVP ]
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_CEA(Ipdiameter_peer_entry *peer, Ipdiameter_header *CER_package, Ip_u32 result_code)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
#ifdef DIAMETER_DEBUG
ipcom_printf("Calling ipdiameter_send_CEA\n");
#endif
message = ipdiameter_answer_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Capabilities_Exchange_Answer);
message->appl_id = ip_htonl(DIAMETER_Common_Message);
message->hbh_id = CER_package->hbh_id;
message->e2e_id = CER_package->e2e_id;
/* Add Result-Code AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Result_Code,
DIAMETER_AVP_M_FLAG, IP_NULL, result_code);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CEA: failed to add Result-Code AVP\n");
goto out;
}
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CEA: failed to add Origin-Host AVP\n");
goto out;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CEA: failed to add Origin-Realm AVP\n");
goto out;
}
/* Add Host-IP-Address AVP */
retval = ipdiameter_avp_add_host_address(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CEA: failed to add Host-IP-Address AVP\n");
goto out;
}
/* Add Vendor-Id AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Vendor_Id,
DIAMETER_AVP_M_FLAG, IP_NULL, ipdiameter.vendor_id);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Vendor-Id AVP\n");
goto out;
}
/* Add Product-Name AVP */
length = (Ip_u32)ipcom_strlen(IPDIAMETER_PRODUCT_NAME);
retval = ipdiameter_avp_add_array(message, DIAMETER_AVP_CODE_Product_Name,
0, IP_NULL, (Ip_u8 *)IPDIAMETER_PRODUCT_NAME, length);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Product-Name AVP\n");
goto out;
}
/* Add Application-Id AVPs */
retval = ipdiameter_avp_add_appl_ids(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_CER: failed to add Application-Id AVP\n");
goto out;
}
/* Send the packet out */
retval = ipdiameter_peer_pkt_send(peer, message);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_send_CEA: failed to send out CEA message\n");
out:
ipdiameter_answer_pkt_free(message);
return retval;
}
/*
*===========================================================================
* ipdiameter_send_DWR
*===========================================================================
* Description: Complete a device watchdog request packet and send out
*
* 5.5.2. Device-Watchdog-Request
*
* The Device-Watchdog-Request (DWR), indicated by the Command-Code set
* to 280 and the Command Flags' 'R' bit set, is sent to a peer when no
* traffic has been exchanged between two peers (see Section 5.5.3).
* Upon detection of a transport failure, this message MUST NOT be sent
* to an alternate peer.
*
* Message Format
*
* <DWR> ::= < Diameter Header: 280, REQ >
* { Origin-Host }
* { Origin-Realm }
* [ Origin-State-Id ]
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_DWR(Ipdiameter_peer_entry *peer)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
message = ipdiameter_request_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Device_Watchdog_Request);
message->appl_id = ip_htonl(DIAMETER_Common_Message);
message->hbh_id = ipdiameter_get_unique_id();
message->e2e_id = message->hbh_id;
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DWR: failed to add Origin-Host AVP\n");
goto out;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DWR: failed to add Origin-Realm AVP\n");
goto out;
}
/* Send the packet out */
retval = ipdiameter_peer_pkt_send(peer, message);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_send_DWR: failed to send out DWR message\n");
out:
ipdiameter_request_pkt_free(message);
return retval;
}
/*
*===========================================================================
* ipdiameter_send_DWA
*===========================================================================
* Description: Complete a device watchdog answer packet and send out
*
* 5.5.2. Device-Watchdog-Answer
*
* The Device-Watchdog-Answer (DWA), indicated by the Command-Code set
* to 280 and the Command Flags' 'R' bit cleared, is sent as a response
* to the Device-Watchdog-Request message.
*
* Message Format
*
* <DWA> ::= < Diameter Header: 280 >
* { Result-Code }
* { Origin-Host }
* { Origin-Realm }
* [ Error-Message ]
* * [ Failed-AVP ]
* [ Original-State-Id ]
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_DWA(Ipdiameter_peer_entry *peer, Ipdiameter_header *DWR_package, Ip_u32 result_code)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
message = ipdiameter_answer_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Device_Watchdog_Answer);
message->appl_id = ip_htonl(DIAMETER_Common_Message);
message->hbh_id = DWR_package->hbh_id;
message->e2e_id = DWR_package->e2e_id;
/* Add Result-Code AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Result_Code,
DIAMETER_AVP_M_FLAG, IP_NULL, result_code);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DWA: failed to add Result-Code AVP\n");
goto out;
}
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DWA: failed to add Origin-Host AVP\n");
goto out;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DWA: failed to add Origin-Realm AVP\n");
goto out;
}
/* Send the packet out */
retval = ipdiameter_peer_pkt_send(peer, message);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_send_DWA: failed to send out DWA message\n");
out:
ipdiameter_answer_pkt_free(message);
return retval;
}
/*
*===========================================================================
* ipdiameter_send_DPR
*===========================================================================
* Description: Complete a disconnect peer request packet and send out
*
* 5.4.1. Disconnect-Peer-Request
*
* The Disconnect-Peer-Request (DPR), indicated by the Command-Code set
* to 282 and the Command Flags' 'R' bit set, is sent to a peer to
* inform its intentions to shutdown the transport connection. Upon
* detection of a transport failure, this message MUST NOT be sent to an
* alternate peer.
*
* Message Format
*
* <DPR> ::= < Diameter Header: 282, REQ >
* { Origin-Host }
* { Origin-Realm }
* { Disconnect-Cause }
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_DPR(Ipdiameter_peer_entry *peer, Ip_u32 cause)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
message = ipdiameter_request_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Disconnect_Peer_Request);
message->appl_id = ip_htonl(DIAMETER_Common_Message);
message->hbh_id = ipdiameter_get_unique_id();
message->e2e_id = message->hbh_id;
/* Insert request into peer's request list */
ipdiameter_peer_add_req(peer, (struct Ipdiameter_header *)message);
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DPR: failed to add Origin-Host AVP\n");
goto err;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_ASA: failed to add Origin-Realm AVP\n");
goto err;
}
/* Add Disconnect-Cause AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Disconnect_Cause,
DIAMETER_AVP_M_FLAG, IP_NULL, cause);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DPR: failed to add Disconnect-Cause AVP\n");
goto err;
}
/* Send the packet out */
retval = ipdiameter_peer_pkt_send(peer, message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DPR: failed to send out DPR message\n");
goto err;
}
return retval;
err:
ipdiameter_request_pkt_free(message);
return retval;
}
/*
*===========================================================================
* ipdiameter_send_DPA
*===========================================================================
* Description: Complete a disconnect peer answer packet and send out
*
* 5.4.2. Disconnect-Peer-Answer
*
* The Disconnect-Peer-Answer (DPA), indicated by the Command-Code set
* to 282 and the Command Flags' 'R' bit cleared, is sent as a response
* to the Disconnect-Peer-Request message. Upon receipt of this
* message, the transport connection is shutdown.
*
* Message Format
*
* <DPA> ::= < Diameter Header: 282 >
* { Result-Code }
* { Origin-Host }
* { Origin-Realm }
* [ Error-Message ]
* * [ Failed-AVP ]
*
* Parameters:
* Returns: result
*
*/
IP_PUBLIC Ip_err
ipdiameter_send_DPA(Ipdiameter_peer_entry *peer, Ipdiameter_header *DPR_package, Ip_u32 result_code)
{
Ipdiameter_header *message;
Ip_u32 length = 0;
Ip_err retval = IPCOM_SUCCESS;
message = ipdiameter_answer_pkt_malloc(length);
if(message == IP_NULL)
{
return IPCOM_ERR_FAILED;
}
ipdiameter_set_hdr_code((Ip_u32 *)message, DIAMETER_CODE_Disconnect_Peer_Answer);
message->appl_id = ip_htonl(DIAMETER_Common_Message);
message->hbh_id = DPR_package->hbh_id;
message->e2e_id = DPR_package->e2e_id;
/* Add Result-Code AVP */
retval = ipdiameter_avp_add_u32(message, DIAMETER_AVP_CODE_Result_Code,
DIAMETER_AVP_M_FLAG, IP_NULL, result_code);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DPA: failed to add Result-Code AVP\n");
goto out;
}
/* Add Origin-Host AVP */
retval = ipdiameter_avp_add_origin_host(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DPA: failed to add Origin-Host AVP\n");
goto out;
}
/* Add Origin-Realm AVP */
retval = ipdiameter_avp_add_origin_realm(message);
if (retval != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipdiameter_send_DPA: failed to add Origin-Realm AVP\n");
goto out;
}
/* Send the packet out */
retval = ipdiameter_peer_pkt_send(peer, message);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_send_DPA: failed to send out DPA message\n");
out:
ipdiameter_answer_pkt_free(message);
return retval;
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/