1576 lines
45 KiB
C
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
|
|
****************************************************************************
|
|
*/
|
|
|