freebsd-dev/usr.sbin/atm/scspd/scsp_hfsm.c
Poul-Henning Kamp 1820df7a2d Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc.
This software was developed with the support of the Defense Advanced
Research Projects Agency (DARPA).
1998-09-15 08:23:17 +00:00

581 lines
12 KiB
C

/*
*
* ===================================
* HARP | Host ATM Research Platform
* ===================================
*
*
* This Host ATM Research Platform ("HARP") file (the "Software") is
* made available by Network Computing Services, Inc. ("NetworkCS")
* "AS IS". NetworkCS does not provide maintenance, improvements or
* support of any kind.
*
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
* In no event shall NetworkCS be responsible for any damages, including
* but not limited to consequential damages, arising from or relating to
* any use of the Software or related support.
*
* Copyright 1994-1998 Network Computing Services, Inc.
*
* Copies of this Software may be made, however, the above copyright
* notice must be reproduced on all copies.
*
* @(#) $Id: scsp_hfsm.c,v 1.4 1998/07/16 15:59:25 johnc Exp $
*
*/
/*
* Server Cache Synchronization Protocol (SCSP) Support
* ----------------------------------------------------
*
* HELLO finite state machine
*
*/
#ifndef lint
static char *RCSid = "@(#) $Id: scsp_hfsm.c,v 1.4 1998/07/16 15:59:25 johnc Exp $";
#endif
#include <sys/types.h>
#include <sys/param.h>
#include <errno.h>
#include <stdio.h>
#include <syslog.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netatm/queue.h>
#include <netatm/atm.h>
#include <netatm/atm_if.h>
#include <netatm/atm_sap.h>
#include <netatm/atm_sys.h>
#include <netatm/atm_ioctl.h>
#include <libatm.h>
#include "scsp_msg.h"
#include "scsp_if.h"
#include "scsp_var.h"
/*
* HELLO FSM actions
*/
#define HELLO_ACTION_CNT 7
int scsp_hello_act_00 __P((Scsp_dcs *, Scsp_msg *));
int scsp_hello_act_01 __P((Scsp_dcs *, Scsp_msg *));
int scsp_hello_act_02 __P((Scsp_dcs *, Scsp_msg *));
int scsp_hello_act_03 __P((Scsp_dcs *, Scsp_msg *));
int scsp_hello_act_04 __P((Scsp_dcs *, Scsp_msg *));
int scsp_hello_act_05 __P((Scsp_dcs *, Scsp_msg *));
int scsp_hello_act_06 __P((Scsp_dcs *, Scsp_msg *));
static int (*scsp_action_vector[HELLO_ACTION_CNT])() = {
scsp_hello_act_00,
scsp_hello_act_01,
scsp_hello_act_02,
scsp_hello_act_03,
scsp_hello_act_04,
scsp_hello_act_05,
scsp_hello_act_06
};
/*
* HELLO FSM state table
*/
static int hello_state_table[SCSP_HFSM_EVENT_CNT][SCSP_HFSM_STATE_CNT] = {
/* 0 1 2 3 */
{ 1, 1, 1, 1 }, /* 0 */
{ 0, 2, 2, 2 }, /* 1 */
{ 0, 3, 3, 3 }, /* 2 */
{ 0, 0, 4, 4 }, /* 3 */
{ 0, 5, 5, 6 }, /* 4 */
};
/*
* HELLO finite state machine
*
* Arguments:
* dcsp pointer to a DCS control block for the neighbor
* event the event which has occurred
* msg pointer to received message, if there is one
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
scsp_hfsm(dcsp, event, msg)
Scsp_dcs *dcsp;
int event;
Scsp_msg *msg;
{
int action, rc, state;
/*
* Select an action from the state table
*/
state = dcsp->sd_hello_state;
action = hello_state_table[event][state];
if (scsp_trace_mode & SCSP_TRACE_HFSM) {
scsp_trace("HFSM: state=%d, event=%d, action=%d\n",
state, event, action);
}
if (action >= HELLO_ACTION_CNT || action <= 0) {
scsp_log(LOG_ERR, "Hello FSM--invalid action %d; state=%d, event=%d",
action, dcsp->sd_hello_state, event);
abort();
}
/*
* Perform the selected action
*/
rc = scsp_action_vector[action](dcsp, msg);
return(rc);
}
/*
* HELLO finite state machine action 0
* Unexpected action -- log an error message
*
* Arguments:
* dcsp pointer to DCS control block
* msg pointer to received message (ignored)
*
* Returns:
* EOPNOTSUPP always returns EOPNOTSUPP
*
*/
int
scsp_hello_act_00(dcsp, msg)
Scsp_dcs *dcsp;
Scsp_msg *msg;
{
scsp_log(LOG_ERR, "Hello FSM error--unexpected action, state=%d",
dcsp->sd_hello_state);
return(EOPNOTSUPP);
}
/*
* HELLO finite state machine action 1
* VCC open -- send HELLO message, start hello timer, go to Waiting
* state
*
* Arguments:
* dcsp pointer to DCS control block
* msg pointer to received message (ignored)
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
scsp_hello_act_01(dcsp, msg)
Scsp_dcs *dcsp;
Scsp_msg *msg;
{
int rc;
/*
* Cancel the VCC open timer if it's running
*/
HARP_CANCEL(&dcsp->sd_open_t);
/*
* Go to Waiting state
*/
dcsp->sd_hello_state = SCSP_HFSM_WAITING;
/*
* Send a Hello message
*/
rc = scsp_send_hello(dcsp);
if (rc == 0) {
/*
* Success--start the Hello timer
*/
HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval,
scsp_hello_timeout);
}
return(rc);
}
/*
* HELLO finite state machine action 2
* VCC closed -- notify CA FSM, go to Down state, try to re-open VCC
*
* Arguments:
* dcsp pointer to DCS control block
* msg pointer to received message (ignored)
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
scsp_hello_act_02(dcsp, msg)
Scsp_dcs *dcsp;
Scsp_msg *msg;
{
int rc;
struct in_addr addr;
/*
* Cancel any current timers
*/
HARP_CANCEL(&dcsp->sd_hello_h_t);
HARP_CANCEL(&dcsp->sd_hello_rcv_t);
/*
* Log the loss of the VCC
*/
if (dcsp->sd_hello_state > SCSP_HFSM_WAITING) {
scsp_log(LOG_ERR, "VC to %s closed",
format_atm_addr(&dcsp->sd_addr));
}
/*
* Tell the CA FSM that the conection to the DCS is lost
*/
rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0);
/*
* Go to Down state
*/
dcsp->sd_hello_state = SCSP_HFSM_DOWN;
/*
* If our ID is lower than the DCS's, wait a second before
* trying to connect. This should keep both of us from
* trying to connect at the same time, resulting in two
* VCCs being open.
*/
if (scsp_cmp_id(&dcsp->sd_server->ss_lsid,
&dcsp->sd_dcsid) < 0) {
/*
* Our ID is lower--start the VCC open timer for one
* second so we'll try to open the VCC if the DCS
* doesn't do it by then
*/
HARP_TIMER(&dcsp->sd_open_t, 1, scsp_open_timeout);
} else {
/*
* Our ID is higher--try to reopen the VCC immediately
*/
if (scsp_dcs_connect(dcsp)) {
/*
* Conncect failed -- set a timer and try
* again later
*/
HARP_TIMER(&dcsp->sd_open_t, SCSP_Open_Interval,
scsp_open_timeout);
}
}
return(0);
}
/*
* HELLO finite state machine action 3
* Hello timer expired -- send HELLO message, restart hello timer
*
* Arguments:
* dcsp pointer to DCS control block
* msg pointer to received message (ignored)
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
scsp_hello_act_03(dcsp, msg)
Scsp_dcs *dcsp;
Scsp_msg *msg;
{
int rc;
/*
* Send a Hello message
*/
rc = scsp_send_hello(dcsp);
if (rc == 0) {
/*
* Success--restart the Hello timer
*/
HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval,
scsp_hello_timeout);
}
return(rc);
}
/*
* HELLO finite state machine action 4
* Receive timer expired -- if we haven't received any Hellos, notify
* CA FSM and go to Waiting state; if we've received Hellos, but we
* weren't in the receiver ID list, go to Unidirectional state
*
* Arguments:
* dcsp pointer to DCS control block
* msg pointer to received message (ignored)
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
scsp_hello_act_04(dcsp, msg)
Scsp_dcs *dcsp;
Scsp_msg *msg;
{
int rc = 0;
/*
* Check whether we'ver received any Hellos lately
*/
if (dcsp->sd_hello_rcvd) {
/*
* We've had Hellos since the receive timer was
* started--go to Unidirectional state
*/
dcsp->sd_hello_rcvd = 0;
dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR;
} else {
/*
* We haven't seen any Hellos at all from the DCS in
* hello_interval * dead_factor seconds--go to Waiting
* state
*/
dcsp->sd_hello_state = SCSP_HFSM_WAITING;
}
/*
* Notify the CA FSM
*/
rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0);
return(rc);
}
/*
* HELLO finite state machine action 5
* Message received -- Ignore all but HELLO messages; if local server
* is in receiver list, notify CA FSM and go to Bidirectional state;
* otherwise, go to Unidirectional state
*
* Arguments:
* dcsp pointer to DCS control block
* msg pointer to received message
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
scsp_hello_act_05(dcsp, msg)
Scsp_dcs *dcsp;
Scsp_msg *msg;
{
int rc;
Scsp_id *ridp;
/*
* Null message pointer means message decode failed, so
* message must have been invalid. Go to Waiting state.
*/
if (msg == (Scsp_msg *)0) {
dcsp->sd_hello_state = SCSP_HFSM_WAITING;
HARP_CANCEL(&dcsp->sd_hello_rcv_t);
return(0);
}
/*
* Ignore the message if it isn't a Hello
*/
if (msg->sc_msg_type != SCSP_HELLO_MSG) {
return(0);
}
/*
* Save relevant information about DCS, but don't let him give
* us zero for timeout values
*/
if (msg->sc_hello->hello_int) {
dcsp->sd_hello_int = msg->sc_hello->hello_int;
} else {
dcsp->sd_hello_int = 1;
}
if (msg->sc_hello->dead_factor) {
dcsp->sd_hello_df = msg->sc_hello->dead_factor;
} else {
dcsp->sd_hello_df = 1;
}
dcsp->sd_dcsid = msg->sc_hello->hello_mcp.sid;
/*
* Check the message for the local server's ID
*/
for (ridp = &msg->sc_hello->hello_mcp.rid;
ridp;
ridp = ridp->next) {
if (scsp_cmp_id(&dcsp->sd_server->ss_lsid, ridp) == 0) {
/*
* Cancel and restart the receive timer
*/
HARP_CANCEL(&dcsp->sd_hello_rcv_t);
HARP_TIMER(&dcsp->sd_hello_rcv_t,
dcsp->sd_hello_int * dcsp->sd_hello_df,
scsp_hello_rcv_timeout);
/*
* Go to Bidirectional state and notify the
* CA FSM that the connection is up
*/
dcsp->sd_hello_state = SCSP_HFSM_BI_DIR;
rc = scsp_cafsm(dcsp,
SCSP_CAFSM_HELLO_UP,
(void *)0);
return(rc);
}
}
/*
* We weren't in the receiver ID list, so go to
* Unidirectional state
*/
dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR;
return(0);
}
/*
* HELLO finite state machine action 6
* Message received -- if message is not a HELLO, pass it to the CA
* FSM; otherwise, if local server is not in receiver list, notify
* CA FSM and go to Unidirectional state
*
* Arguments:
* dcsp pointer to DCS control block
* msg pointer to received message
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
scsp_hello_act_06(dcsp, msg)
Scsp_dcs *dcsp;
Scsp_msg *msg;
{
int rc, rcv_found;
Scsp_id *ridp;
/*
* Null message pointer means message decode failed, so
* message must have been invalid. Go to Waiting state.
*/
if (msg == (Scsp_msg *)0) {
HARP_CANCEL(&dcsp->sd_hello_rcv_t);
dcsp->sd_hello_state = SCSP_HFSM_WAITING;
rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0);
return(rc);
}
/*
* Process the message depending on its type
*/
switch(msg->sc_msg_type) {
case SCSP_CA_MSG:
rc = scsp_cafsm(dcsp, SCSP_CAFSM_CA_MSG, (void *)msg);
break;
case SCSP_CSU_REQ_MSG:
rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REQ, (void *)msg);
break;
case SCSP_CSU_REPLY_MSG:
rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REPLY,
(void *)msg);
break;
case SCSP_CSUS_MSG:
rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSUS_MSG, (void *)msg);
break;
case SCSP_HELLO_MSG:
/*
* Make sure DCS info is consistent. The sender ID,
* family ID, protocol ID, and server group ID are
* checked.
*/
if (scsp_cmp_id(&msg->sc_hello->hello_mcp.sid,
&dcsp->sd_dcsid) ||
(msg->sc_hello->family_id !=
dcsp->sd_server->ss_fid) ||
(msg->sc_hello->hello_mcp.pid !=
dcsp->sd_server->ss_pid) ||
(msg->sc_hello->hello_mcp.sgid !=
dcsp->sd_server->ss_sgid)) {
/*
* Bad info--revert to waiting state
*/
HARP_CANCEL(&dcsp->sd_hello_rcv_t);
dcsp->sd_hello_state = SCSP_HFSM_WAITING;
rc = scsp_cafsm(dcsp,
SCSP_CAFSM_HELLO_DOWN,
(void *)0);
return(rc);
}
/*
* Mark the arrival of the Hello message
*/
dcsp->sd_hello_rcvd = 1;
/*
* Check the message for the local server's ID
*/
rc = 0;
for (ridp = &msg->sc_hello->hello_mcp.rid,
rcv_found = 0;
ridp;
ridp = ridp->next) {
rcv_found = (scsp_cmp_id(ridp,
&dcsp->sd_server->ss_lsid) == 0);
}
if (rcv_found) {
/*
* The LS ID was in the list of receiver IDs--
* Reset the Hello receive timer
*/
dcsp->sd_hello_rcvd = 0;
HARP_CANCEL(&dcsp->sd_hello_rcv_t);
HARP_TIMER(&dcsp->sd_hello_rcv_t,
dcsp->sd_hello_int *
dcsp->sd_hello_df,
scsp_hello_rcv_timeout);
}
break;
}
return(rc);
}