/* * * =================================== * 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: src/usr.sbin/atm/scspd/scsp_hfsm.c,v 1.3 1999/08/28 01:15:33 peter Exp $ * @(#) $DragonFly: src/usr.sbin/atm/scspd/scsp_hfsm.c,v 1.4 2003/11/15 20:33:43 eirikn Exp $ */ /* * Server Cache Synchronization Protocol (SCSP) Support * ---------------------------------------------------- * * HELLO finite state machine * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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(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(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(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(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(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(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(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(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(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); }