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

1576 lines
45 KiB
C

/* ipdiameter.c - Diameter node common 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
--------------------
01t,23nov10,hfc fir buildwarning.Defect WIND00242868
01s,16jul10,hfc secureKeyDB support for diameter
01r,24mar10,zhr LP64 bits adaption
01q,19aug09,tlu Coverity fix
01p,10mar09,tlu Fix Linux build warning
01o,24apr08,ggz Added ipdiameter_set_wfd function
01n,17apr08,tlu Fix for show routines
01m,03apr08,ggz Added wdfs support for non blocking connection establisment
01l,24jan08,tlu Add policy show routine
01k,13dec07,tlu Limit session configuration parameters to client only in
the node show routine
01j,14nov07,tlu Set floating point flag for Diameter task
01i,17oct07,tlu Port to Linux
01h,19sep07,tlu Set TLS CA rootdir field to NULL if the configuration
parameter is an empty string
01g,09aug07,tlu Add TLS support
01f,02aug07,tlu Initialize session ID seed and free the memory dynamically
allocated by ipcom_sysvar_get()
01e,04jul07,tlu Add supported application IDs as a configuration parameter
and add display supported applications to node show routine
01d,28jun07,tlu Add local host IP address as configuration parameters
01c,20jun07,tlu Add port number as an argument for open socket functions
01b,13jun07,tlu Update after code inspection
01a,05apr07,tlu Created.
*/
/*
****************************************************************************
* DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* CONFIGURATION
****************************************************************************
*/
#include "ipdiameter_config.h"
/*
****************************************************************************
* INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
/* ipcom */
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#include <ipcom_clib.h>
#include <ipcom_os.h>
#include <ipcom_sysvar.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_err.h>
#include <ipcom_syslog.h>
#include <ipcom_ipd.h>
#include <ipcom_sock2.h>
#include <ipcom_list.h>
#include <ipcom_time.h>
/* ipdiameter */
#include "ipdiameter.h"
/*
****************************************************************************
* DEFINES
****************************************************************************
*/
/* This is a compile flag, turning on it will build debug message into image */
#undef DIAMETER_DEBUG
/*
****************************************************************************
* LOCAL TYPES
****************************************************************************
*/
typedef struct Ipdiameter_selectfd_struct
{
Ipcom_list fd_list;
Ip_fd fd;
Ipdiameter_peer_entry *peer; /* the peer that fd is associated with */
}
Ipdiameter_selectfd;
/*
*===========================================================================
* Global ipdiameter data
*===========================================================================
* All global IPDiameter data is located in this structure.
*/
IP_PUBLIC Ipdiameter_data ipdiameter;
/*
****************************************************************************
* LOCAL Data
****************************************************************************
*/
IP_STATIC Ip_bool daemon_started = IP_FALSE;
IP_PUBLIC Ip_bool diameterStopFlag;
/* diameter node daemon name */
#define IPDIAMETER_PROC_NAME 20
IP_STATIC char procname[IPDIAMETER_PROC_NAME];
/* FDs the daemon is selecting on */
IP_STATIC Ip_fd_set fds; /* Read */
IP_STATIC Ip_fd_set wfds; /* Write */
IP_STATIC Ip_u32 max;
/*
****************************************************************************
* LOCAL PROTOTYPES
****************************************************************************
*/
#ifdef IPCOM_USE_INET
IP_STATIC Ip_fd ipdiameter_tcp4rx_socket(Ip_u16 port);
#endif
#ifdef IPCOM_USE_INET6
IP_STATIC Ip_fd ipdiameter_tcp6rx_socket(Ip_u16 port);
#endif
IP_STATIC Ip_err ipdiameter_common_init(Ipdiameter_peer_type node_type);
/*
****************************************************************************
* LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdiameter_tcp4rx_socket
*===========================================================================
* Description: Open Diameter IPv4 TCP listening socket
* Parameters:
* Returns:
*
*/
#ifdef IPCOM_USE_INET
IP_STATIC Ip_fd
ipdiameter_tcp4rx_socket(Ip_u16 port)
{
Ip_fd fd;
int opt_val = 1;
/* Get DIAMETER IPv4 TCP socket. */
fd = ipcom_socket(IP_AF_INET, IP_SOCK_STREAM, 0);
if (fd != IP_INVALID_SOCKET)
{
struct Ip_sockaddr_in addr;
/* Bind socket to a local random port. */
ipcom_memset(&addr, 0, sizeof(addr));
IPCOM_SA_LEN_SET(&addr, sizeof(struct Ip_sockaddr_in));
addr.sin_family = IP_AF_INET;
addr.sin_port = ip_htons(port);
addr.sin_addr.s_addr = IP_INADDR_ANY;
if (ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_REUSEADDR, (void*) &opt_val, sizeof(opt_val)))
{
IPCOM_LOG1(WARNING,
"ipdiameter_tcp4rx_socket: ipcom_setsockopt(IP_SO_REUSEADDR) failed for AF_INET: %s",
ipcom_strerror(ipcom_errno));
}
if (ipcom_bind(fd, (struct Ip_sockaddr *)&addr, sizeof(addr)) < 0)
{
IPCOM_LOG1(ERR, "ipdiameter_tcp4rx_socket: failed to bind TCP socket, errno = %d"IP_LF, ipcom_errno);
ipcom_socketclose(fd);
return IP_INVALID_SOCKET;
}
}
else
{
IPCOM_LOG1(ERR, "ipdiameter_tcp4rx_socket: failed to open IPv4 TCP listening socket, errno = %d"IP_LF, ipcom_errno);
return IP_INVALID_SOCKET;
}
/* move the socket to LISTEN state */
if (ipcom_listen(fd, 1) != 0)
{
IPCOM_LOG1(ERR, "ipdiameter_tcp4rx_socket: cannot listen on socket %d\n", fd);
ipcom_socketclose(fd);
return IP_INVALID_SOCKET;
}
return fd;
}
#endif
/*
*===========================================================================
* ipdiameter_tcp6rx_socket
*===========================================================================
* Description: Open Diameter IPv6 TCP listening socket
* Parameters:
* Returns:
*
*/
#ifdef IPCOM_USE_INET6
IP_STATIC Ip_fd
ipdiameter_tcp6rx_socket(Ip_u16 port)
{
Ip_fd fd6;
int opt_val = 1;
/* Get DIAMETER IPv6 TCP socket. */
fd6 = ipcom_socket(IP_AF_INET6, IP_SOCK_STREAM, 0);
if (fd6 != IP_INVALID_SOCKET)
{
struct Ip_sockaddr_in6 addr6;
/* Bind socket to a local random port. */
ipcom_memset(&addr6, 0, sizeof(addr6));
IPCOM_SA_LEN_SET(&addr6, sizeof(struct Ip_sockaddr_in6));
addr6.sin6_family = IP_AF_INET6;
addr6.sin6_port = ip_htons(port);
if (ipcom_bind(fd6, (struct Ip_sockaddr *)&addr6, sizeof(addr6)) < 0)
{
IPCOM_LOG1(ERR,
"ipdiameter_tcp6rx_socket: failed to bind IPv6 TCP socket, errno = %d\n",
ipcom_errno);
ipcom_socketclose(fd6);
return IP_INVALID_SOCKET;
}
if (ipcom_setsockopt(fd6, IP_SOL_SOCKET, IP_SO_REUSEADDR, (void*) &opt_val, sizeof(opt_val)))
{
IPCOM_LOG1(WARNING,
"ipdiameter_tcp6rx_socket: ipcom_setsockopt(IP_SO_REUSEADDR) failed for AF_INET6: %s",
ipcom_strerror(ipcom_errno));
}
}
else
{
IPCOM_LOG1(ERR, "ipdiameter_tcp6rx_socket: failed to open IPv6 TCP listening socket, errno = %d\n",
ipcom_errno);
return IP_INVALID_SOCKET;
}
/* move the socket to LISTEN state */
if (ipcom_listen(fd6, 1) != 0)
{
IPCOM_LOG1(ERR, "ipdiameter_tcp6rx_socket: cannot listen on socket %d\n", fd6);
ipcom_socketclose(fd6);
return IP_INVALID_SOCKET;
}
return fd6;
}
#endif
/*
*===========================================================================
* ipdiameterd
*===========================================================================
* Description: Diameter node daemon
* Parameters:
* Returns:
*
*/
IPCOM_PROCESS(ipdiameterd);
IPCOM_PROCESS(ipdiameterd)
{
Ip_err ret;
Ip_bool ipdiameter_open_ok = IP_FALSE;
Ip_fd ipd_fd = IP_INVALID_SOCKET;
Ip_fd_set read_set, write_set;
Ip_s32 num;
struct Ip_timeval tv, *ptv = IP_NULL;
Ipdiameter_selectfd *selectfd, *nselectfd;
Ip_socklen_t errlen;
int so_errno = 0;
int off = 0;
#ifdef IPCOM_USE_INET
Ip_fd tcp_fd = IP_INVALID_SOCKET;
#endif
#ifdef IPCOM_USE_INET6
Ip_fd tcp_fd6 = IP_INVALID_SOCKET;
#endif
ipcom_proc_init();
#ifdef DIAMETER_DEBUG
ipcom_printf("%s :: starting daemon\n", procname);
#endif
diameterStopFlag = IP_FALSE;
errlen = sizeof(int);
/***** Open IPDIAMETER. *****/
ret = ipdiameter_common_open();
if(ret != IPCOM_SUCCESS) {
IPCOM_LOG1(ERR, "ipdiameterd :: ipdiameter_common_open() failed, err = %ld", ret);
goto badout;
}
ipdiameter_open_ok = IP_TRUE;
#ifdef DIAMETER_DEBUG
ipcom_printf("ipdiameterd :: open ok\n");
#endif
/***** Get diameter tcp listening socket */
#ifdef IPCOM_USE_INET
tcp_fd = ipdiameter.fd;
#ifdef DIAMETER_DEBUG
ipcom_printf("ipdiameterd :: tcp listening fd %d\n", tcp_fd);
#endif
#endif
#ifdef IPCOM_USE_INET6
tcp_fd6 = ipdiameter.fd6;
#ifdef DIAMETER_DEBUG
ipcom_printf("ipdiameterd :: tcp listening fd6 %d\n", tcp_fd6);
#endif
#endif
/* IPD init. */
if(ipcom_ipd_init(procname, IPCOM_SUCCESS, &ipd_fd) != IPCOM_SUCCESS) {
IPCOM_LOG1(ERR, "%s: ipcom_ipd_init() failed", procname);
goto badout;
}
/***** Input loop. *****/
IP_FD_ZERO(&fds);
max = (Ip_u32)ipd_fd;
IP_FD_SET(ipd_fd, &fds);
IP_FD_ZERO(&wfds);
#ifdef IPCOM_USE_INET
max = IP_MAX(max, (Ip_u32)tcp_fd);
IP_FD_SET(tcp_fd, &fds);
#endif
#ifdef IPCOM_USE_INET6
max = IP_MAX(max, tcp_fd6);
IP_FD_SET(tcp_fd6, &fds);
#endif
/* Set daemon_started after set select fds */
daemon_started = IP_TRUE;
/* set the timeout value */
memset(&tv, 0, sizeof(struct Ip_timeval));
tv.tv_sec = 1;
tv.tv_usec = 0;
ptv = &tv;
#ifdef DIAMETER_DEBUG
ipcom_printf("**** Started loop **** \n");
#endif
while (1) {
/* Check diametercStop() wasn't called */
if (diameterStopFlag) {
IPCOM_LOG0(INFO, "Diameter node daemon to close. Closing down");
goto badout;
}
read_set = fds;
write_set = wfds;
num = ipcom_tmo2_select(ipdiameter.tmo_head, (int)max + 1, &read_set, &write_set, IP_NULL, ptv);
if (diameterStopFlag) {
IPCOM_LOG0(INFO, "Diameter node daemon to close. Closing down");
goto badout;
}
switch (num) {
case -1:
IPCOM_LOG0(WARNING, "diameterd select error");
continue;
case 0:
continue;
default:
#ifdef DIAMETER_DEBUG
ipcom_printf("Received message from a socket\n");
#endif
#ifdef IPCOM_USE_INET
if (IP_FD_ISSET(tcp_fd, &read_set))
{
IPCOM_LOG0 (INFO, "Diameter IPv4 listening fd receives message");
if (ipdiameter_ctrl_recv(tcp_fd) != IPCOM_SUCCESS)
IPCOM_LOG1(WARNING, "Diameter daemon IPv4 TCP socket %d rcv an error msg\n", tcp_fd);
}
#endif
#ifdef IPCOM_USE_INET6
if (IP_FD_ISSET(tcp_fd6, &read_set))
{
IPCOM_LOG0(INFO, "Diameter IPv6 listening fd receives message");
if (ipdiameter_ctrl_recv(tcp_fd6) != IPCOM_SUCCESS)
IPCOM_LOG1(WARNING, "Diameter daemon IPv6 TCP socket %d rcv error msg\n", tcp_fd6);
}
#endif
/* go through all data sockets */
for (selectfd = IPCOM_LIST_FIRST(&ipdiameter.fd_head);
selectfd != IP_NULL;
selectfd = nselectfd)
{
/* get next fd */
nselectfd = IPCOM_LIST_NEXT(&selectfd->fd_list);
/* Check if the fd is set. */
if (IP_FD_ISSET(selectfd->fd, &read_set))
{
#ifdef DIAMETER_DEBUG
ipcom_printf("Receives message on fd %d, from peer %x\n",
selectfd->fd, selectfd->peer);
#endif
if (ipdiameter_recv(selectfd->fd, selectfd->peer) != IPCOM_SUCCESS)
{
#ifdef DIAMETER_DEBUG
ipcom_printf("Diameter daemon rx wrong data, fd %d, from peer %x\n",
selectfd->fd, selectfd->peer);
#endif
}
}
else if (IP_FD_ISSET(selectfd->fd, &write_set))
{
if (ipdiameter.node_type == DIAMETER_PEER_PROXY_AGENT)
{
if (selectfd->peer->state == DIAMETER_PEER_STATE_WAIT_CONN_ACK)
{
/* Process non blocking socket connection errors */
if (0 == ipcom_getsockopt(selectfd->fd, IP_SOL_SOCKET, IP_SO_ERROR,
&so_errno, &errlen));
{
if (so_errno == IP_ERRNO_ENETUNREACH)
{
/* This is the case when a nonblocking connection has
been initiated by the peer_fsm. */
/* Set the socket back to the blocking mode */
if (ipcom_socketioctl(selectfd->fd, IP_FIONBIO, (char*)&off))
{
IPCOM_LOG0(WARNING, "IPCOM_PROCESS: socket IP_FIONBIO set failed\n");
}
ipdiameter_peer_fsm(selectfd->peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_NACK);
so_errno = 0; /* Reset the local so_errno */
}
/* Process non blocking socket connection event */
else /*(so_errno == 0)*/
{
IP_FD_CLR(selectfd->fd, &wfds);
/* Set the socket back to the blocking mode */
if (ipcom_socketioctl(selectfd->fd, IP_FIONBIO, (char*)&off))
{
IPCOM_LOG0(WARNING, "IPCOM_PROCESS: socket IP_FIONBIO set failed\n");
}
ipdiameter_peer_fsm(selectfd->peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_ACK);
}
}
}
}
}
}
if (IP_FD_ISSET(ipd_fd, &read_set))
{
int event;
event = ipcom_ipd_input(ipd_fd);
switch(event) {
case IPCOM_IPD_EVENT_KILL:
IPCOM_LOG0(INFO, "received IPD kill message");
goto badout;
default:
break;
}
}
} /* switch */
} /* while */
badout:
if(ipd_fd == IP_INVALID_SOCKET)
(void)ipcom_ipd_init(procname, IPCOM_ERR_FAILED, &ipd_fd);
if (ipdiameter_open_ok)
{
(void)ipdiameter.close();
}
(void)ipdiameter.exit();
(void)ipcom_ipd_exit(procname, ipd_fd);
#ifdef DIAMETER_DEBUG
ipcom_printf("%s :: ending", procname);
#endif
ipcom_proc_exit();
}
/*
*===========================================================================
* ipdiameter_common_init
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
ipdiameter_common_init(Ipdiameter_peer_type node_type)
{
Ip_err retval = IPCOM_SUCCESS;
ipcom_memset(&ipdiameter, 0, sizeof(Ipdiameter_data));
/* Set node type */
ipdiameter.node_type = node_type;
/* Initialize session ID seed */
IP_U64_SET(ipdiameter.session_id_seed, ipcom_time(0), 0);
/* Initialize lists. */
ipcom_list_init(&ipdiameter.session_head);
ipcom_list_init(&ipdiameter.peer_head);
ipcom_list_init(&ipdiameter.fd_head);
ipcom_list_init(&ipdiameter.route_head);
ipcom_list_init(&ipdiameter.policy_head);
/* Initialize the timeout related parameters to default values */
ipdiameter.session_timeout = IPDIAMETER_SESSION_TIMEOUT;
ipdiameter.auth_lifetime = IPDIAMETER_AUTH_LIFETIME;
ipdiameter.auth_grace_period = IPDIAMETER_AUTH_GRACE_PERIOD;
ipdiameter.peer_reconn_interval = IPDIAMETER_PEER_RECONN_INTERVAL;
ipdiameter.max_reconn_attemp = IPDIAMETER_MAX_PEER_RECONN_ATTEMPT;
ipdiameter.req_retx_interval = IPDIAMETER_REQ_RETX_INTERVAL;
ipdiameter.max_req_retx = IPDIAMETER_MAX_REQ_RETX;
/* Create timeout queue */
ipdiameter.tmo_head = ipcom_tmo2_new();
if (ipdiameter.tmo_head == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_common_init: fail to create timeout queue\n");
IPDIAMETER_LEAVE(IPCOM_ERR_NO_MEMORY);
}
/* create semaphore */
#ifdef IPDIAMETER_ENABLE_REENTRANT
(void)ipcom_mutex_create(&ipdiameter.code_mutex);
#endif
leave:
return retval;
}
/*
*===========================================================================
* ipdiameter_common_open
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_common_open(void)
{
Ip_err retval = IPCOM_SUCCESS;
char *diameterid, *realm, *addr;
Ip_s32 address_family;
char *appl_list, *appl, *last;
Ip_size_t length;
IPDIAMETER_LOCK();
/** Get IPDIAMETER configuration parameters **/
/* Get diameter identifier */
diameterid = ipcom_sysvar_get("ipdiameter.identifier", IP_NULL, IP_NULL);
if (diameterid != IP_NULL)
{
length = ipcom_strlen(diameterid);
if ( (length < IPDIAMETER_MAX_FQDN_SIZE-1) &&
(length > 0) )
{
ipcom_strcpy(ipdiameter.host_id, diameterid);
ipcom_free(diameterid);
}
else
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_IDENTIFIER\n");
ipcom_free(diameterid);
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
}
else
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_IDENTIFIER\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
/* Get diameter node realm */
realm = ipcom_sysvar_get("ipdiameter.realm", IP_NULL, IP_NULL);
if (realm != IP_NULL)
{
length = ipcom_strlen(realm);
if ( (length < IPDIAMETER_MAX_FQDN_SIZE-1) &&
(length > 0) )
{
ipcom_strcpy(ipdiameter.realm_id, realm);
ipcom_free(realm);
}
else
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong size of config parameter DIAMETER_HOST_REALM\n");
ipcom_free(realm);
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
}
else
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_HOST_REALM\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
/* Get diameter node's address family */
address_family = ipcom_sysvar_get_as_int("ipdiameter.domain", -1);
if ((address_family) != IP_AF_INET && (address_family != IP_AF_INET6))
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_HOST_DOMAIN\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
if (address_family == IP_AF_INET)
{
#ifdef IPCOM_USE_INET
addr = ipcom_sysvar_get("ipdiameter.ipv4_address", IP_NULL, IP_NULL);
if (addr != IP_NULL)
{
if (ipcom_inet_pton(IP_AF_INET, addr, &ipdiameter.addr.sin.sin_addr) == 1)
{
ipdiameter.addr.sa.sa_family = IP_AF_INET;
IPCOM_SA_LEN_SET(&ipdiameter.addr.sa, sizeof(struct Ip_sockaddr_in));
}
ipcom_free(addr);
}
else
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_HOST_IPV4_ADDRESS\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
#endif
}
else
{
#ifdef IPCOM_USE_INET6
addr = ipcom_sysvar_get("ipdiameter.ipv6_address", IP_NULL, IP_NULL);
if (addr != IP_NULL)
{
if (ipcom_inet_pton(IP_AF_INET6, addr, &ipdiameter.addr.sin6.sin6_addr) == 1)
{
ipdiameter.addr.sa.sa_family = IP_AF_INET6;
IPCOM_SA_LEN_SET(&ipdiameter.addr.sa, sizeof(struct Ip_sockaddr_in6));
}
ipcom_free(addr);
}
else
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_HOST_IPV6_ADDRESS\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
#endif
}
/* Get local node TCP listening port number */
ipdiameter.tcp_port = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.tcp_port", -1);
/* Get supported aplication ID list */
last = appl_list = ipcom_sysvar_get("ipdiameter.appl_list",IP_NULL,IP_NULL);
if (appl_list == IP_NULL)
IPCOM_LOG0(INFO, "ipdiameter_common_open: no application configured");
else
{
while (IP_NULL != (appl = ipcom_strtok_r(last == appl_list?appl_list:
IP_NULL, ",", &last)))
{
Ip_u32 appl_id = (Ip_u32)ipcom_atoi(appl);
if (!(IPDIAMETER_VALID_APP_ID(appl_id)))
{
IPCOM_LOG1(ERR, "ipdiameter_common_open:, invalid appl ID %d\n",
appl_id);
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
ipdiameter.appl_ids[ipdiameter.num_appls] = appl_id;
ipdiameter.num_appls++;
}
ipcom_free(appl_list);
}
/* Get diameter vendor ID */
ipdiameter.vendor_id = (Ip_u32)ipcom_sysvar_get_as_int("ipdiameter.vendorid", -1);
if ((Ip_s32)(ipdiameter.vendor_id ) < 0)
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_VENDOR_ID\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
/* Get diameter peer reconnect interval in seconds */
ipdiameter.peer_reconn_interval = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.timeout.reconninterval", -1);
/* Get diameter max peer reconnection attempts */
ipdiameter.max_reconn_attemp = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.maxreconnattempt", -1);
/* Get diameter watchdog timeout in seconds */
ipdiameter.watchdog_timeout = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.timeout.watchdog", -1);
/* Get diameter request retransmission interval in seconds */
ipdiameter.req_retx_interval = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.timeout.reqretxinterval", -1);
/* Get diameter max request retransmission */
ipdiameter.max_req_retx = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.maxreqretx", -1);
/* Get TLS enabled flag */
ipdiameter.tls_enabled = ipcom_sysvar_get_as_int("ipdiameter.tls", -1);
if (ipdiameter.tls_enabled != 0 && ipdiameter.tls_enabled != 1)
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_TLS_ENABLED\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
if (ipdiameter.tls_enabled)
{
/* Read in other TLS configuration parameters */
/* Get Local node's certificate file */
ipdiameter.certfile = ipcom_sysvar_get("ipdiameter.tls.certfile", IP_NULL, IP_NULL);
if (ipdiameter.certfile == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_TLS_CERTIFICATE\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
#if defined(IPCOM_USE_KEY_DB) && defined(_WRS_CONFIG_IPDIAMETER_SEC_KEY_DB)
/* Get local node's private key Id and store it in keyfile variavle*/
ipdiameter.keyfile = ipcom_sysvar_get("ipdiameter.tls.tlsPKeyId", IP_NULL, IP_NULL);
if (ipdiameter.keyfile == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_TLS_KEY_ID\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
#else
/* Get local node's private key file */
ipdiameter.keyfile = ipcom_sysvar_get("ipdiameter.tls.keyfile", IP_NULL, IP_NULL);
if (ipdiameter.keyfile == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_TLS_KEY_FILE\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
/* Get local node's private key file's key password */
ipdiameter.keypasswd = ipcom_sysvar_get("ipdiameter.tls.keypasswd", IP_NULL, IP_NULL);
if (ipdiameter.keypasswd == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_TLS_KEY_PASSWORD\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
#endif /* _WRS_CONFIG_IPDIAMETER_SEC_KEY_DB */
/* Get CA root certificate file */
ipdiameter.cacertfile = ipcom_sysvar_get("ipdiameter.tls.cacertfile", IP_NULL, IP_NULL);
if (ipdiameter.cacertfile == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_TLS_ROOT_CERTIFICATE\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
/* Get certificate root directory */
ipdiameter.rootdir = ipcom_sysvar_get("ipdiameter.tls.rootdir", IP_NULL, IP_NULL);
if (ipdiameter.rootdir == IP_NULL)
{
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_TLS_ROOT_DIR\n");
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
else if (ipcom_strcmp(ipdiameter.rootdir, "") == 0)
{
IPCOM_LOG0(INFO, "ipdiameter_common_open: DIAMETER_TLS_ROOT_DIR is empty string\n");
ipcom_free(ipdiameter.rootdir);
ipdiameter.rootdir = IP_NULL;
}
#ifdef IPSSL
/* Init ssl_ctx context */
retval = ipdiameter_setup_ssl_ctx();
if (retval != IPCOM_SUCCESS) IPDIAMETER_LEAVE(retval);
#endif /* IPSSL */
}
/* Get node specific configuration parameters */
retval = ipdiameter.open();
if (retval != IPCOM_SUCCESS) IPDIAMETER_LEAVE(retval);
/* Open Dimaeter tcp listening socket */
#ifdef IPCOM_USE_INET
ipdiameter.fd = ipdiameter_tcp4rx_socket(ipdiameter.tcp_port);
#endif
#ifdef IPCOM_USE_INET6
ipdiameter.fd6 = ipdiameter_tcp6rx_socket(ipdiameter.tcp_port);
#endif
ipdiameter.opened = IP_TRUE;
leave:
IPDIAMETER_UNLOCK();
return retval;
}
/*
****************************************************************************
* PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdiameter_common_create
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_common_create(Ipdiameter_peer_type node_type)
{
Ip_err retval = IPCOM_SUCCESS;
/* init Diameter global data structure */
retval = ipdiameter_common_init(node_type);
if (retval != IPCOM_SUCCESS)
IPCOM_LOG0(ERR, "ipdiameter_common_create: failed on ipdiameter_common_init");
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdiameter_common_start
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_common_start(char *proc_name)
{
Ip_err ret = IPCOM_SUCCESS;
Ipcom_proc_attr attr;
Ip_u16 length;
/* get IPD name from the Diameter node daemon's name */
/* IPD name is one letter shorter than node daemon's name, */
/* i.e. IPD name "ipdiameterc" and node daemon's name "ipdiametercd" */
length = (Ip_u16)ipcom_strlen(proc_name);
ipcom_memcpy(procname, proc_name, (Ip_size_t)length-1);
procname[length-1] = '\0';
ipcom_proc_attr_init(&attr);
attr.priority = IPCOM_PRIORITY_DEFAULT - 1;
attr.stacksize = 20000;
attr.flags = IPCOM_PROC_FLAG_FP;
ret = ipcom_proc_acreate(proc_name, ipdiameterd, &attr, IP_NULL);
if (ret != IPCOM_SUCCESS) {
IPCOM_LOG0(ERR, "ipdiameter_common_start: Failed on ipcom_proc_acreate");
}
return ret;
}
/*
*===========================================================================
* ipdiameter_common_close
*===========================================================================
* Description: Close an opened Diameter
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_common_close(void)
{
Ip_err retval = IPCOM_SUCCESS;
Ipdiameter_session *session, *session_v;
Ipdiameter_peer_entry *peer, *peer_v;
Ipdiameter_route_entry *route, *route_v;
Ipdiameter_policy_entry *policy, *policy_v;
if (ipdiameter.opened == IP_FALSE)
return IPCOM_ERR_ALREADY_CLOSED;
IPDIAMETER_LOCK();
/* close all sessions */
for (session = IPCOM_LIST_FIRST(&ipdiameter.session_head); session;
session = session_v)
{
session_v = IPCOM_LIST_NEXT(&session->session_list);
ipdiameter_delete_session(session);
}
/* remove all peers */
for (peer = IPCOM_LIST_FIRST(&ipdiameter.peer_head); peer;
peer = peer_v)
{
peer_v = IPCOM_LIST_NEXT(&peer->peer_list);
(void)ipdiameter_delete_peer(&peer->peer_addr);
}
/* remove all routes */
for (route = IPCOM_LIST_FIRST(&ipdiameter.route_head); route;
route = route_v)
{
route_v = IPCOM_LIST_NEXT(&route->route_list);
ipdiameter_del_route(route);
}
/* remove all policies */
for (policy = IPCOM_LIST_FIRST(&ipdiameter.policy_head); policy;
policy = policy_v)
{
policy_v = IPCOM_LIST_NEXT(&policy->policy_list);
(void)ipdiameter_delete_policy(policy);
}
/* free memory dynamically allocated for TLS config parameters */
if (ipdiameter.certfile) ipcom_free(ipdiameter.certfile);
if (ipdiameter.keyfile) ipcom_free(ipdiameter.keyfile);
if (ipdiameter.keypasswd) ipcom_free(ipdiameter.keypasswd);
if (ipdiameter.cacertfile) ipcom_free(ipdiameter.cacertfile);
if (ipdiameter.rootdir) ipcom_free(ipdiameter.rootdir);
#ifdef IPSSL
/* free ssl_ctx context */
if (ipdiameter.ssl_ctx) SSL_CTX_free(ipdiameter.ssl_ctx);
#endif /* IPSSL */
/* Close TCP sockets */
#ifdef IPCOM_USE_INET
if (ipdiameter.fd != IP_INVALID_SOCKET)
ipcom_socketclose(ipdiameter.fd);
#endif
#ifdef IPCOM_USE_INET6
if (ipdiameter.fd6 != IP_INVALID_SOCKET)
ipcom_socketclose(ipdiameter.fd6);
#endif
/* free user registered callback data and reset callback funciton */
ipdiameter.user_callback = IP_NULL;
if (ipdiameter.opaque_callback_data)
ipcom_free(ipdiameter.opaque_callback_data);
ipdiameter.opaque_callback_data = IP_NULL;
ipdiameter.opened = IP_FALSE;
IPDIAMETER_UNLOCK();
return retval;
}
/*
*===========================================================================
* ipdiameter_common_exit
*===========================================================================
* Description: Exit an opened Diameter
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_common_exit(void)
{
Ip_err retval = IPCOM_SUCCESS;
IPDIAMETER_LOCK();
/* delete timeout queue */
if (ipdiameter.tmo_head != IP_NULL)
ipcom_tmo2_delete(ipdiameter.tmo_head);
IPDIAMETER_UNLOCK();
#ifdef IPDIAMETER_ENABLE_REENTRANT
(void)ipcom_mutex_delete(&ipdiameter.code_mutex);
#endif
/* reset the global data */
ipcom_memset(&ipdiameter, 0, sizeof(Ipdiameter_data));
return retval;
}
/*
*===========================================================================
* ipdiameter_common_stop
*===========================================================================
* Description: Stop the Diameter daemon
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_common_stop(void)
{
diameterStopFlag = IP_TRUE;
daemon_started = IP_FALSE;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdiameter_node_add_session
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_node_add_session(Ipdiameter_session *session)
{
Ip_err retval = IPCOM_SUCCESS;
if (ipdiameter.opened == IP_FALSE)
return IPCOM_ERR_NOT_OPENED;
IPDIAMETER_LOCK();
if (ipdiameter.session_num > IPDIAMETER_MAX_SESSIONS)
IPDIAMETER_LEAVE(IPCOM_ERR_REACHED_MAX);
ipcom_list_insert_last(&ipdiameter.session_head, &session->session_list);
ipdiameter.session_num++;
leave:
IPDIAMETER_UNLOCK();
return retval;
}
/*
*===========================================================================
* ipdiameter_node_remove_session
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipdiameter_node_remove_session(Ipdiameter_session *session)
{
IPDIAMETER_LOCK();
ip_assert(ipdiameter.session_num > 0);
ipdiameter.session_num--;
IPDIAMETER_UNLOCK();
}
/*
*===========================================================================
* ipdiameter_node_add_peer
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_node_add_peer(Ipdiameter_peer_entry *peer)
{
Ip_err retval = IPCOM_SUCCESS;
if (ipdiameter.opened == IP_FALSE)
return IPCOM_ERR_NOT_OPENED;
IPDIAMETER_LOCK();
if (ipdiameter.peer_num > IPDIAMETER_MAX_PEERS)
IPDIAMETER_LEAVE(IPCOM_ERR_REACHED_MAX);
ipcom_list_insert_last(&ipdiameter.peer_head, &peer->peer_list);
ipdiameter.peer_num++;
leave:
IPDIAMETER_UNLOCK();
return retval;
}
/*
*===========================================================================
* ipdiameter_node_remove_peer
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipdiameter_node_remove_peer(Ipdiameter_peer_entry *peer)
{
IPDIAMETER_LOCK();
ip_assert(ipdiameter.peer_num > 0);
ipdiameter.peer_num--;
IPDIAMETER_UNLOCK();
}
/*
*===========================================================================
* ipdiameter_node_show_config
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipdiameter_node_show_config(void)
{
int i;
if (ipdiameter.opened == IP_FALSE)
{
ipcom_printf("Diameter is not opened\n");
return;
}
IPDIAMETER_LOCK();
if (daemon_started)
ipcom_printf("State: opened and running\n");
else
ipcom_printf("State: opened and NOT running\n");
ipcom_printf("Node type: %s\n", ipdiameter_peer_type(ipdiameter.node_type));
if ( ipdiameter.addr.sa.sa_family == IP_AF_INET ||
ipdiameter.addr.sa.sa_family == IP_AF_INET6 )
ipcom_printf("Node Addr: %s\n",
ipdiameter_addr_to_str(&ipdiameter.addr));
else
ipcom_printf("Node Addr: Unknow\n");
ipcom_printf("Diameter Id: %s\n", ipdiameter.host_id);
ipcom_printf("Realm Id: %s\n", ipdiameter.realm_id);
ipcom_printf("Vendor Id: %d\n", ipdiameter.vendor_id);
ipcom_printf("TCP listening port: %u\n", ipdiameter.tcp_port);
if (ipdiameter.num_appls == 0)
ipcom_printf("Supported application: None\n");
for (i = 0; i < (Ip_s32)ipdiameter.num_appls; i++)
ipcom_printf("Supported application: (%lu)%s\n",
ipdiameter.appl_ids[i],
ipdiameter_peer_appl(ipdiameter.appl_ids[i]));
ipcom_printf("\nTimers:\n");
if (ipdiameter.node_type == DIAMETER_PEER_CLIENT)
{
ipcom_printf(" Session timeout: %d\n", ipdiameter.session_timeout);
ipcom_printf(" Authorization lifetime: %d\n", ipdiameter.auth_lifetime);
ipcom_printf(" Auth Grace Period: %d\n", ipdiameter.auth_grace_period);
}
ipcom_printf(" Peer reconnection interval: %d\n", ipdiameter.peer_reconn_interval);
ipcom_printf(" Max reconnection attemps: %d\n", ipdiameter.max_reconn_attemp);
ipcom_printf(" Watchdog timeout: %d\n", ipdiameter.watchdog_timeout);
ipcom_printf(" Request retx interval: %d\n", ipdiameter.req_retx_interval);
ipcom_printf(" Max request retx: %d\n", ipdiameter.max_req_retx);
ipcom_printf("\nTLS:\n");
ipcom_printf(" TLS enabled: %s\n",
ipdiameter.tls_enabled ? "Yes" : "No");
ipcom_printf(" Node certficate file: %s\n", ipdiameter.certfile ?
ipdiameter.certfile : "N/A");
#if defined(IPCOM_USE_KEY_DB) && defined(_WRS_CONFIG_IPDIAMETER_SEC_KEY_DB)
ipcom_printf(" Node private key ID: %s\n", ipdiameter.keyfile ?
ipdiameter.keyfile : "N/A");
#else
ipcom_printf(" Node private key file: %s\n", ipdiameter.keyfile ?
ipdiameter.keyfile : "N/A");
ipcom_printf(" Node key file's key passwd: %s\n", ipdiameter.keypasswd ?
ipdiameter.keypasswd : "N/A");
#endif /* _WRS_CONFIG_IPDIAMETER_SEC_KEY_DB */
ipcom_printf(" CA root certificate file: %s\n", ipdiameter.cacertfile ?
ipdiameter.cacertfile : "N/A");
ipcom_printf(" Certificate root directory: %s\n", ipdiameter.rootdir ?
ipdiameter.rootdir : "N/A");
ipcom_printf("\n");
IPDIAMETER_UNLOCK();
}
/*
*===========================================================================
* ipdiameter_node_show_peer
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipdiameter_node_show_peer(void)
{
Ipdiameter_peer_entry *peer;
if (ipdiameter.opened == IP_FALSE)
{
ipcom_printf("Diameter is not opened\n");
return;
}
IPDIAMETER_LOCK();
if (ipdiameter.peer_num == 0)
ipcom_printf("Diameter Peers: None\n");
else
ipcom_printf("Diameter Peers: %d\n", ipdiameter.peer_num);
for (peer = IPCOM_LIST_FIRST(&ipdiameter.peer_head);
peer != IP_NULL;
peer = IPCOM_LIST_NEXT(&peer->peer_list))
{
ipdiameter_print_peer(peer);
ipcom_printf("\n");
}
IPDIAMETER_UNLOCK();
}
/*
*===========================================================================
* ipdiameter_node_show_session
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipdiameter_node_show_session(void)
{
Ipdiameter_session *session;
if (ipdiameter.opened == IP_FALSE)
{
ipcom_printf("Diameter is not opened\n");
return;
}
IPDIAMETER_LOCK();
if (ipdiameter.session_num == 0)
ipcom_printf("Diameter Sessions: None\n");
else
ipcom_printf("Diameter Sessions: %d\n", ipdiameter.session_num);
for (session = IPCOM_LIST_FIRST(&ipdiameter.session_head);
session != IP_NULL;
session = IPCOM_LIST_NEXT(&session->session_list))
{
ipdiameter_print_session(session);
ipcom_printf("\n");
}
IPDIAMETER_UNLOCK();
}
/*
*===========================================================================
* ipdiameter_select_add_fd
*===========================================================================
* Description: Add a new fd to daemon select fds
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_select_add_fd(Ip_fd fd, Ipdiameter_peer_entry *peer)
{
Ipdiameter_selectfd *selectfd = IP_NULL;
Ip_err retval = IPCOM_SUCCESS;
IPDIAMETER_LOCK();
if (daemon_started == IP_FALSE)
IPDIAMETER_LEAVE(IPCOM_ERR_NOT_STARTED);
if (ipdiameter.fd_num > IPDIAMETER_MAX_FDS)
IPDIAMETER_LEAVE(IPCOM_ERR_REACHED_MAX);
/* go through all data sockets */
for (selectfd = IPCOM_LIST_FIRST(&ipdiameter.fd_head);
selectfd != IP_NULL;
selectfd = IPCOM_LIST_NEXT(&selectfd->fd_list))
{
ip_assert(selectfd->peer != peer);
ip_assert(selectfd->fd != fd);
}
/* allocated a new selectfd structure */
selectfd = (Ipdiameter_selectfd *)ipcom_malloc(sizeof(Ipdiameter_selectfd));
if (selectfd == IP_NULL)
{
IPCOM_LOG1(ERR, "ipdiameter_select_add_fd: out of memory ('selectfd' %ld bytes)",
sizeof(Ipdiameter_selectfd));
IPDIAMETER_LEAVE(IPCOM_ERR_NO_MEMORY);
}
/* Fill in the fields */
selectfd->fd = fd;
selectfd->peer = peer;
/* add the new selectfd to the list */
ipcom_list_insert_last(&ipdiameter.fd_head, &selectfd->fd_list);
ipdiameter.fd_num++;
/* reset the max and readfd set */
max = (Ip_u32)IP_MAX(max, (Ip_u32)fd);
IP_FD_SET(fd, &fds);
leave:
IPDIAMETER_UNLOCK();
return retval;
}
/*
*===========================================================================
* ipdiameter_select_del_fd
*===========================================================================
* Description: Delete a fd from daemon select fds
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipdiameter_select_del_fd(Ip_fd fd)
{
Ipdiameter_selectfd *selectfd;
Ip_err retval = IPCOM_ERR_NOT_FOUND;
IPDIAMETER_LOCK();
for (selectfd = IPCOM_LIST_FIRST(&ipdiameter.fd_head);
selectfd != IP_NULL;
selectfd = IPCOM_LIST_NEXT(&selectfd->fd_list))
{
/* Find a selectfd entry with same fd. */
if (selectfd->fd == fd)
{
ip_assert(ipdiameter.fd_num > 0);
/* remove the fd from the list */
ipcom_list_remove(&selectfd->fd_list);
ipdiameter.fd_num--;
/* free the memory */
ipcom_free(selectfd);
/* remove the fd from the readfd set */
IP_FD_CLR(fd, &fds);
/* remove the fd from the writefd set. It should be safe to clear
the bit even if it is not set */
IP_FD_CLR(fd, &wfds);
IPDIAMETER_LEAVE(IPCOM_SUCCESS);
}
}
leave:
IPDIAMETER_UNLOCK();
return retval;
}
/*
*===========================================================================
* ipdiameter_set_wfd
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void ipdiameter_set_wfd(Ip_fd fd)
{
IP_FD_SET(fd, &wfds);
}
/*
*===========================================================================
* ipdiameter_node_show_route
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipdiameter_node_show_route(void)
{
Ipdiameter_route_entry *route;
if (ipdiameter.opened == IP_FALSE)
{
ipcom_printf("Diameter is not opened\n");
return;
}
IPDIAMETER_LOCK();
if (ipdiameter.route_num == 0)
ipcom_printf("Diameter routes: None\n");
else
ipcom_printf("Diameter routes: %d\n", ipdiameter.route_num);
for( route = IPCOM_LIST_FIRST(&ipdiameter.route_head);
route != IP_NULL;
route = IPCOM_LIST_NEXT(&route->route_list))
{
ipdiameter_print_route(route);
ipcom_printf("\n");
}
IPDIAMETER_UNLOCK();
}
/*
*===========================================================================
* ipdiameter_node_show_policy
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC void
ipdiameter_node_show_policy(void)
{
Ipdiameter_policy_entry *policy;
if (ipdiameter.opened == IP_FALSE)
{
ipcom_printf("Diameter is not opened\n");
return;
}
IPDIAMETER_LOCK();
if (ipdiameter.policy_num == 0)
ipcom_printf("Diameter proxy local policies: None\n");
else
ipcom_printf("Diameter proxy local policies: %d\n",
ipdiameter.policy_num);
for( policy = IPCOM_LIST_FIRST(&ipdiameter.policy_head);
policy != IP_NULL;
policy = IPCOM_LIST_NEXT(&policy->policy_list))
{
ipdiameter_print_policy(policy);
ipcom_printf("\n");
}
IPDIAMETER_UNLOCK();
}
/*
*===========================================================================
* ipdiameter_version
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC const char *
ipdiameter_version(void)
{
return "@(#) WR DIAMETER - Copyright 2007 Wind River (http://www.windriver.com). All rights reserved.";
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/