578 lines
12 KiB
C
578 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.
|
|
*
|
|
* @(#) $FreeBSD$
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* Server Cache Synchronization Protocol (SCSP) Support
|
|
* ----------------------------------------------------
|
|
*
|
|
* HELLO finite state machine
|
|
*
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.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 <errno.h>
|
|
#include <libatm.h>
|
|
#include <stdio.h>
|
|
#include <syslog.h>
|
|
|
|
#include "scsp_msg.h"
|
|
#include "scsp_if.h"
|
|
#include "scsp_var.h"
|
|
|
|
#ifndef lint
|
|
__RCSID("@(#) $FreeBSD$");
|
|
#endif
|
|
|
|
|
|
/*
|
|
* HELLO FSM actions
|
|
*/
|
|
#define HELLO_ACTION_CNT 7
|
|
int scsp_hello_act_00(Scsp_dcs *, Scsp_msg *);
|
|
int scsp_hello_act_01(Scsp_dcs *, Scsp_msg *);
|
|
int scsp_hello_act_02(Scsp_dcs *, Scsp_msg *);
|
|
int scsp_hello_act_03(Scsp_dcs *, Scsp_msg *);
|
|
int scsp_hello_act_04(Scsp_dcs *, Scsp_msg *);
|
|
int scsp_hello_act_05(Scsp_dcs *, Scsp_msg *);
|
|
int scsp_hello_act_06(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;
|
|
|
|
/*
|
|
* 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 = 0, 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
|
|
*/
|
|
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);
|
|
}
|