886 lines
32 KiB
C
886 lines
32 KiB
C
/* ipdiameter_peer_fsm.c - IPNet Diameter peer FSM file */
|
|
|
|
/*
|
|
* 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
|
|
--------------------
|
|
01e,03feb09,tlu Remove R_RCV_CEA and I_RCV_CER events from peer FSM
|
|
01d,05apr08,ggz Modifications for non blocking TCP connection with peers
|
|
01c,05sep07,tlu Fix checking of the return code from processing CER
|
|
01b,05jul07,tlu Replace ipcom_printf by IPCOM_LOG
|
|
01a,03may07,tlu Created.
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_ipd.h>
|
|
|
|
#include <ipnet_h.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
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
* Refer to RFC 3588, section 5.6
|
|
*/
|
|
|
|
IP_PUBLIC Ip_err
|
|
ipdiameter_peer_fsm(Ipdiameter_peer_entry *peer, struct Ipdiameter_header *hdr, int event)
|
|
{
|
|
Ip_err retval = IPCOM_SUCCESS;
|
|
Ipdiameter_header *hdr_v = (Ipdiameter_header *)hdr;
|
|
Ip_bool win_elect;
|
|
Ip_u32 result_code = DIAMETER_SUCCESS;
|
|
Ip_fd fd = IP_INVALID_SOCKET, fd6 = IP_INVALID_SOCKET;
|
|
|
|
#ifdef DIAMETER_DEBUG
|
|
ipcom_printf("Calling ipdiameter_peer_fsm, state %s, event %d\n",
|
|
ipdiameter_peer_state(peer->state), event);
|
|
#endif
|
|
if (peer == IP_NULL) {
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, pass in a NULL peer\n");
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
switch (peer->state)
|
|
{
|
|
case DIAMETER_PEER_STATE_CLOSED:
|
|
switch (event) {
|
|
case DIAMETER_PEER_EV_START:
|
|
|
|
if (ipdiameter.node_type == DIAMETER_PEER_PROXY_AGENT)
|
|
{
|
|
/* initiate non-blocking connection */
|
|
retval = ipdiameter_peer_init_conn_req(peer);
|
|
|
|
/* Warning: this state of peer is used in non blocking select processing */
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK);
|
|
|
|
/* The socket is in non blocing mode but the connection might
|
|
have already been established. If yes then continue procesiing here.
|
|
Otherwise the connection will be processed in select function after
|
|
the socket reply */
|
|
if ((retval != IPCOM_SUCCESS) && (retval != IP_ERRNO_EINPROGRESS))
|
|
{
|
|
ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_NACK);
|
|
retval = IPCOM_ERR_FAILED;
|
|
}
|
|
else if (retval == IP_ERRNO_EINPROGRESS)
|
|
{
|
|
/* IP_ERRNO_EINPROGRESS - leave the peers state in
|
|
DIAMETER_PEER_STATE_WAIT_CONN_ACK. The connection will be handled
|
|
when the socket replyes */
|
|
retval = IPCOM_SUCCESS;
|
|
}
|
|
else /* Success */
|
|
{
|
|
/* Immidiate socket connection has been established. Run the peer FSM */
|
|
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_ACK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* initiate connect request */
|
|
retval = ipdiameter_peer_init_conn_req(peer);
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK);
|
|
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the packet\n");
|
|
ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_NACK);
|
|
retval = IPCOM_ERR_FAILED;
|
|
} else {
|
|
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_ACK);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_CONN_CER:
|
|
case DIAMETER_PEER_EV_R_RCV_CER:
|
|
#ifdef IPCOM_USE_INET
|
|
fd = peer->fd;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
fd6 = peer->fd6;
|
|
#endif
|
|
|
|
if (fd == IP_INVALID_SOCKET && fd6 == IP_INVALID_SOCKET)
|
|
/* peer is not connected, remains in CLOSED state */
|
|
break;
|
|
|
|
if (!peer->initiator)
|
|
{
|
|
#ifdef DIAMETER_DEBUG
|
|
ipcom_printf("ipdiameter_peer_fsm: respond to accept the connect\n");
|
|
#endif
|
|
/* respond to accept the connection */
|
|
retval = ipdiameter_peer_resp_accept(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to accept the connect\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* process the CER */
|
|
result_code = ipdiameter_peer_process_CER(peer, hdr);
|
|
|
|
if (!peer->initiator)
|
|
{
|
|
/* cancel the recon timer */
|
|
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
|
|
|
/* respond to send the CEA */
|
|
retval = ipdiameter_send_CEA(peer, hdr_v, result_code);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_R_OPEN);
|
|
|
|
/* check whether there is pending package to transmit */
|
|
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DIAMETER_PEER_STATE_WAIT_CONN_ACK:
|
|
switch (event) {
|
|
case DIAMETER_PEER_EV_I_RCV_CONN_ACK:
|
|
if (peer->initiator)
|
|
{
|
|
/* send the CER */
|
|
retval = ipdiameter_send_CER(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_I_CEA);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_RCV_CONN_NACK:
|
|
/* clean up */
|
|
retval = ipdiameter_peer_cleanup(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer cleanup\n");
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_CONN_CER:
|
|
if (!peer->initiator)
|
|
{
|
|
/* respond to accept the connection */
|
|
retval = ipdiameter_peer_resp_accept(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to accept the connect\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* process the CER */
|
|
retval = ipdiameter_peer_process_CER(peer, hdr);
|
|
if (retval != DIAMETER_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to process the CER\n");
|
|
goto error;
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK_ELECT);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_TIMEOUT:
|
|
/* process the error */
|
|
retval = ipdiameter_peer_error(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DIAMETER_PEER_STATE_WAIT_I_CEA:
|
|
switch (event) {
|
|
case DIAMETER_PEER_EV_I_RCV_CEA:
|
|
/* process the CEA */
|
|
retval = ipdiameter_peer_process_CEA(peer, hdr);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to process the CEA\n");
|
|
goto error;
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_I_OPEN);
|
|
|
|
/* check whether there is pending package to transmit */
|
|
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_CONN_CER:
|
|
if (!peer->initiator)
|
|
{
|
|
/* respond to accept the connection */
|
|
retval = ipdiameter_peer_resp_accept(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to accept the connect\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* process the CER */
|
|
retval = ipdiameter_peer_process_CER(peer, hdr);
|
|
if (retval != DIAMETER_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to process the CER\n");
|
|
goto error;
|
|
}
|
|
|
|
/* perform the peer election */
|
|
win_elect = ipdiameter_peer_elect(peer);
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_RETURNS);
|
|
|
|
if (win_elect)
|
|
{
|
|
retval = ipdiameter_peer_fsm(peer, hdr, DIAMETER_PEER_EV_WIN_ELECTION);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed in peer FSM with EV_WIN_ELECTION\n");
|
|
}
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_PEER_DISC:
|
|
if (peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_RCV_NON_CEA:
|
|
/* process the error */
|
|
retval = ipdiameter_peer_error(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_TIMEOUT:
|
|
/* process the error */
|
|
retval = ipdiameter_peer_error(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DIAMETER_PEER_STATE_WAIT_CONN_ACK_ELECT:
|
|
switch (event) {
|
|
case DIAMETER_PEER_EV_I_RCV_CONN_ACK:
|
|
if (peer->initiator)
|
|
{
|
|
/* send the CER */
|
|
retval = ipdiameter_send_CER(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* perform the peer election */
|
|
win_elect = ipdiameter_peer_elect(peer);
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_RETURNS);
|
|
|
|
if (win_elect)
|
|
{
|
|
retval = ipdiameter_peer_fsm(peer, hdr, DIAMETER_PEER_EV_WIN_ELECTION);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed in peer FSM with EV_WIN_ELECTION\n");
|
|
}
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_RCV_CONN_NACK:
|
|
if (!peer->initiator)
|
|
{
|
|
/* cancel the recon timer */
|
|
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
|
|
|
/* send the CEA */
|
|
retval = ipdiameter_send_CEA(peer, hdr_v, DIAMETER_SUCCESS);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* Change the state to open */
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_R_OPEN);
|
|
|
|
/* check whether there is pending package to transmit */
|
|
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_PEER_DISC:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_CONN_CER:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Reject the peer */
|
|
retval = ipdiameter_peer_reject(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to reject the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK_ELECT);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_TIMEOUT:
|
|
/* process the error */
|
|
retval = ipdiameter_peer_error(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DIAMETER_PEER_STATE_WAIT_RETURNS:
|
|
switch (event) {
|
|
case DIAMETER_PEER_EV_WIN_ELECTION:
|
|
if (peer->initiator)
|
|
{
|
|
/* Disconnect the peer if the local host is the winner */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
else
|
|
{
|
|
/* cancel the recon timer */
|
|
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
|
|
|
/* Send the CEA */
|
|
retval = ipdiameter_send_CEA(peer, hdr_v, DIAMETER_SUCCESS);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_R_OPEN);
|
|
|
|
/* check whether there is pending package to transmit */
|
|
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_PEER_DISC:
|
|
if (peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
else
|
|
{
|
|
/* cancel the recon timer */
|
|
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
|
|
|
/* Send the CEA */
|
|
retval = ipdiameter_send_CEA(peer, hdr_v, DIAMETER_SUCCESS);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_R_OPEN);
|
|
|
|
/* check whether there is pending package to transmit */
|
|
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_RCV_CEA:
|
|
if (!peer->initiator)
|
|
{
|
|
/* cancel the recon timer */
|
|
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
|
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_I_OPEN);
|
|
|
|
/* check whether there is pending package to transmit */
|
|
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_PEER_DISC:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_I_CEA);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_CONN_CER:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Reject the peer */
|
|
retval = ipdiameter_peer_reject(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to reject the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_RETURNS);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_TIMEOUT:
|
|
/* process the error */
|
|
retval = ipdiameter_peer_error(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DIAMETER_PEER_STATE_R_OPEN:
|
|
switch (event) {
|
|
case DIAMETER_PEER_EV_SEND_MESSAGE:
|
|
if (peer->initiator)
|
|
{
|
|
/* send out the messge */
|
|
retval = ipdiameter_peer_send_msg(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm: failed to send out the message\n");
|
|
}
|
|
|
|
/* the peer remains R-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_RCV_MESSAGE:
|
|
/* process the messge */
|
|
retval = ipdiameter_peer_process_msg(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm: failed to process the message\n");
|
|
|
|
/* the peer remains R-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_RCV_DWR:
|
|
/* process the DWR messge */
|
|
result_code = ipdiameter_peer_process_DWR(peer, hdr);
|
|
|
|
if (!peer->initiator)
|
|
{
|
|
/* send out the DWA messge */
|
|
retval = ipdiameter_send_DWA(peer, hdr_v, result_code);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to send out the DWA message\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* the peer remains R-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_RCV_DWA:
|
|
/* process the DWA messge */
|
|
retval = ipdiameter_peer_process_DWA(peer, hdr);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to process the DWA\n");
|
|
goto error;
|
|
}
|
|
|
|
/* the peer remains R-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_CONN_CER:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Reject the peer */
|
|
retval = ipdiameter_peer_reject(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to reject the peer\n");
|
|
}
|
|
|
|
/* the peer remains R-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_STOP:
|
|
if (!peer->initiator)
|
|
{
|
|
/* start reconn timer */
|
|
retval = ipdiameter_peer_start_reconn_timer(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to start reconn timer\n");
|
|
|
|
/* send out the DPR */
|
|
retval = ipdiameter_send_DPR(peer, DIAMETER_PEER_DO_NOT_WANT_TO_TALK_TO_YOU);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the DPR message\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSING);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_RCV_DPR:
|
|
if (!peer->initiator)
|
|
{
|
|
/* send out the DPA */
|
|
retval = ipdiameter_send_DPA(peer, hdr_v, DIAMETER_SUCCESS);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the DPA message\n");
|
|
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_PEER_DISC:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DIAMETER_PEER_STATE_I_OPEN:
|
|
switch (event) {
|
|
case DIAMETER_PEER_EV_SEND_MESSAGE:
|
|
if (peer->initiator)
|
|
{
|
|
/* send out the messge */
|
|
retval = ipdiameter_peer_send_msg(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* the session remains I-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_RCV_MESSAGE:
|
|
/* process the messge */
|
|
retval = ipdiameter_peer_process_msg(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm: failed to process the message\n");
|
|
|
|
/* the session remains I-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_RCV_DWR:
|
|
/* process the DWR messge */
|
|
result_code = ipdiameter_peer_process_DWR(peer, hdr);
|
|
|
|
if (peer->initiator)
|
|
{
|
|
/* send out the DWA messge */
|
|
retval = ipdiameter_send_DWA(peer, hdr_v, result_code);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to send out the DWA message\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* the session remains I-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_RCV_DWA:
|
|
/* process the DWA messge */
|
|
retval = ipdiameter_peer_process_DWA(peer, hdr);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to process the DWA\n");
|
|
goto error;
|
|
}
|
|
|
|
/* the session remains I-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_CONN_CER:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Reject the peer */
|
|
retval = ipdiameter_peer_reject(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to reject the peer\n");
|
|
}
|
|
|
|
/* the session remains I-Open state */
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_STOP:
|
|
if (peer->initiator)
|
|
{
|
|
/* start reconn timer */
|
|
retval = ipdiameter_peer_start_reconn_timer(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to start reconn timer\n");
|
|
|
|
/* send out the DPR */
|
|
retval = ipdiameter_send_DPR(peer, DIAMETER_PEER_DO_NOT_WANT_TO_TALK_TO_YOU);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the DPR message\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSING);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_RCV_DPR:
|
|
if (peer->initiator)
|
|
{
|
|
/* send out the DPA */
|
|
retval = ipdiameter_send_DPA(peer, hdr_v, DIAMETER_SUCCESS);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the DPA message\n");
|
|
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_PEER_DISC:
|
|
if (peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DIAMETER_PEER_STATE_CLOSING:
|
|
switch (event) {
|
|
case DIAMETER_PEER_EV_I_RCV_DPA:
|
|
if (peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_RCV_DPA:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_TIMEOUT:
|
|
/* process the error */
|
|
retval = ipdiameter_peer_error(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
|
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_I_PEER_DISC:
|
|
if (peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
|
break;
|
|
|
|
case DIAMETER_PEER_EV_R_PEER_DISC:
|
|
if (!peer->initiator)
|
|
{
|
|
/* Disconnect the peer */
|
|
retval = ipdiameter_peer_disc(peer);
|
|
if (retval != IPCOM_SUCCESS)
|
|
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
|
}
|
|
|
|
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#ifdef DIAMETER_DEBUG
|
|
ipcom_printf("ipdiameter_peer_fsm successful\n");
|
|
ipdiameter_print_peer(peer);
|
|
#endif
|
|
return retval;
|
|
|
|
error:
|
|
(void)ipdiameter_peer_disc(peer);
|
|
|
|
#ifdef DIAMETER_DEBUG
|
|
ipcom_printf("ipdiameter_peer_fsm failed\n");
|
|
ipdiameter_print_peer(peer);
|
|
#endif
|
|
return retval;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|