aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/atm/scspd/scsp_cafsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/atm/scspd/scsp_cafsm.c')
-rw-r--r--usr.sbin/atm/scspd/scsp_cafsm.c1448
1 files changed, 1448 insertions, 0 deletions
diff --git a/usr.sbin/atm/scspd/scsp_cafsm.c b/usr.sbin/atm/scspd/scsp_cafsm.c
new file mode 100644
index 000000000000..b9d2b512ca9e
--- /dev/null
+++ b/usr.sbin/atm/scspd/scsp_cafsm.c
@@ -0,0 +1,1448 @@
+/*
+ *
+ * ===================================
+ * 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_cafsm.c,v 1.7 1998/08/21 18:08:23 johnc Exp $
+ *
+ */
+
+
+/*
+ * Server Cache Synchronization Protocol (SCSP) Support
+ * ----------------------------------------------------
+ *
+ * Cache Alignment finite state machine
+ *
+ */
+
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: scsp_cafsm.c,v 1.7 1998/08/21 18:08:23 johnc Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netatm/port.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"
+
+
+/*
+ * CA FSM actions
+ */
+#define CA_ACTION_CNT 20
+int scsp_ca_act_00 __P((Scsp_dcs *, void *));
+int scsp_ca_act_01 __P((Scsp_dcs *, void *));
+int scsp_ca_act_02 __P((Scsp_dcs *, void *));
+int scsp_ca_act_03 __P((Scsp_dcs *, void *));
+int scsp_ca_act_04 __P((Scsp_dcs *, void *));
+int scsp_ca_act_05 __P((Scsp_dcs *, void *));
+int scsp_ca_act_06 __P((Scsp_dcs *, void *));
+int scsp_ca_act_07 __P((Scsp_dcs *, void *));
+int scsp_ca_act_08 __P((Scsp_dcs *, void *));
+int scsp_ca_act_09 __P((Scsp_dcs *, void *));
+int scsp_ca_act_10 __P((Scsp_dcs *, void *));
+int scsp_ca_act_11 __P((Scsp_dcs *, void *));
+int scsp_ca_act_12 __P((Scsp_dcs *, void *));
+int scsp_ca_act_13 __P((Scsp_dcs *, void *));
+int scsp_ca_act_14 __P((Scsp_dcs *, void *));
+int scsp_ca_act_15 __P((Scsp_dcs *, void *));
+int scsp_ca_act_16 __P((Scsp_dcs *, void *));
+int scsp_ca_act_17 __P((Scsp_dcs *, void *));
+int scsp_ca_act_18 __P((Scsp_dcs *, void *));
+int scsp_ca_act_19 __P((Scsp_dcs *, void *));
+
+static int (*scsp_ca_act_vec[CA_ACTION_CNT])() = {
+ scsp_ca_act_00,
+ scsp_ca_act_01,
+ scsp_ca_act_02,
+ scsp_ca_act_03,
+ scsp_ca_act_04,
+ scsp_ca_act_05,
+ scsp_ca_act_06,
+ scsp_ca_act_07,
+ scsp_ca_act_08,
+ scsp_ca_act_09,
+ scsp_ca_act_10,
+ scsp_ca_act_11,
+ scsp_ca_act_12,
+ scsp_ca_act_13,
+ scsp_ca_act_14,
+ scsp_ca_act_15,
+ scsp_ca_act_16,
+ scsp_ca_act_17,
+ scsp_ca_act_18,
+ scsp_ca_act_19
+};
+
+/*
+ * CA FSM state table
+ */
+static int ca_state_table[SCSP_CAFSM_EVENT_CNT][SCSP_CAFSM_STATE_CNT] = {
+ /* 0 1 2 3 4 5 */
+ { 1, 1, 1, 1, 1, 1 }, /* 0 */
+ { 2, 2, 2, 2, 2, 2 }, /* 1 */
+ { 0, 3, 4, 5, 15, 15 }, /* 2 */
+ { 0, 17, 17, 17, 7, 7 }, /* 3 */
+ { 0, 17, 17, 17, 8, 8 }, /* 4 */
+ { 0, 17, 17, 17, 10, 10 }, /* 5 */
+ { 0, 6, 6, 0, 9, 9 }, /* 6 */
+ { 0, 0, 0, 0, 12, 12 }, /* 7 */
+ { 0, 0, 0, 0, 13, 13 }, /* 8 */
+ { 18, 14, 14, 14, 11, 11 }, /* 9 */
+ { 0, 19, 0, 0, 16, 16 }, /* 10 */
+};
+
+
+/*
+ * Cache Alignment finite state machine
+ *
+ * Arguments:
+ * dcsp pointer to a DCS control block for the neighbor
+ * event the event which has occurred
+ * p pointer to further parameter, if there is one
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_cafsm(dcsp, event, p)
+ Scsp_dcs *dcsp;
+ int event;
+ void *p;
+{
+ int action, rc, state;
+
+ /*
+ * Select an action from the state table
+ */
+ state = dcsp->sd_ca_state;
+ action = ca_state_table[event][state];
+ if (scsp_trace_mode & SCSP_TRACE_CAFSM) {
+ scsp_trace("CAFSM: state=%d, event=%d, action=%d\n",
+ state, event, action);
+ }
+ if (action >= CA_ACTION_CNT || action < 0) {
+ scsp_log(LOG_ERR, "CA FSM--invalid action state=%d, event=%d, action=%d",
+ state, event, action);
+ abort();
+ }
+
+ /*
+ * Perform the selected action
+ */
+ rc = scsp_ca_act_vec[action](dcsp, p);
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 0
+ * Unexpected action -- log an error message and go to Master/Slave
+ * Negotiation. The unexpected action is probably from a protocol
+ * error.
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p ignored
+ *
+ * Returns:
+ * EOPNOTSUPP always returns EOPNOTSUPP
+ *
+ */
+int
+scsp_ca_act_00(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc;
+
+ /*
+ * Log an error message
+ */
+ scsp_log(LOG_ERR, "CA FSM error--unexpected action, state=%d",
+ dcsp->sd_ca_state);
+
+ /*
+ * Set the new state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_NEG;
+
+ /*
+ * Clear out the DCS block
+ */
+ scsp_dcs_cleanup(dcsp);
+
+ /*
+ * Notify the client I/F FSM
+ */
+ rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_DOWN, (Scsp_msg *)0,
+ (Scsp_if_msg *)0);
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 1
+ * Hello FSM has reached Bidirectional state -- go to Master/Slave
+ * Negotiation state, make a copy of the client's cache, send first CA
+ * message.
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p ignored
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_01(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int i, rc;
+ Scsp_cse *csep, *dupp;
+
+ /*
+ * Set the new state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_NEG;
+
+ /*
+ * Make a copy of client's cache entries for cache alignment
+ */
+ for (i = 0; i < SCSP_HASHSZ; i++) {
+ for (csep = dcsp->sd_server->ss_cache[i];
+ csep; csep = csep->sc_next) {
+ dupp = scsp_dup_cse(csep);
+ LINK2TAIL(dupp, Scsp_cse, dcsp->sd_ca_csas,
+ sc_next);
+ }
+ }
+
+ /*
+ * Select an initial sequence number
+ */
+ dcsp->sd_ca_seq = (int)time((time_t *)0);
+
+ /*
+ * Send a CA message
+ */
+ rc = scsp_send_ca(dcsp);
+ if (rc == 0) {
+ HARP_TIMER(&dcsp->sd_ca_rexmt_t, dcsp->sd_ca_rexmt_int,
+ scsp_ca_retran_timeout);
+ }
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 2
+ * Hello FSM has gone down -- go to Down state
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p ignored
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_02(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc;
+
+ /*
+ * Set the new state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_DOWN;
+
+ /*
+ * Clear out the DCS block
+ */
+ scsp_dcs_cleanup(dcsp);
+
+ /*
+ * Notify the client I/F FSM
+ */
+ rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_DOWN, (Scsp_msg *)0,
+ (Scsp_if_msg *)0);
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 3
+ * CA message received -- select Cache Summarize Master or Slave state
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to received message
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_03(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc = 0;
+ Scsp_msg *msg = (Scsp_msg *)p;
+
+ /*
+ * Check for slave role for LS
+ */
+ if (msg->sc_ca->ca_m &&
+ msg->sc_ca->ca_i &&
+ msg->sc_ca->ca_o &&
+ msg->sc_ca->ca_mcp.rec_cnt == 0 &&
+ scsp_cmp_id(&msg->sc_ca->ca_mcp.sid,
+ &msg->sc_ca->ca_mcp.rid) > 0) {
+
+ /*
+ * Stop the retransmit timer
+ */
+ HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
+
+ /*
+ * Set the new state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_SLAVE;
+ (void)scsp_cfsm(dcsp, SCSP_CIFSM_CA_SUMM,
+ (Scsp_msg *)0, (Scsp_if_msg *)0);
+
+ /*
+ * Save the master's sequence number
+ */
+ dcsp->sd_ca_seq = msg->sc_ca->ca_seq;
+
+ /*
+ * Send a CA message
+ */
+ rc = scsp_send_ca(dcsp);
+ } else
+ /*
+ * Check for master role for LS
+ */
+ if (!msg->sc_ca->ca_m &&
+ !msg->sc_ca->ca_i &&
+ scsp_cmp_id(&msg->sc_ca->ca_mcp.sid,
+ &msg->sc_ca->ca_mcp.rid) < 0) {
+ /*
+ * Stop the retransmit timer
+ */
+ HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
+
+ /*
+ * Set the new state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_MASTER;
+ rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_SUMM,
+ (Scsp_msg *)0, (Scsp_if_msg *)0);
+
+ /*
+ * Process the CA message
+ */
+ scsp_process_ca(dcsp, msg->sc_ca);
+
+ /*
+ * Increment the sequence number
+ */
+ dcsp->sd_ca_seq++;
+
+ /*
+ * Send a CA in reply
+ */
+ rc = scsp_send_ca(dcsp);
+ if (rc == 0) {
+ HARP_TIMER(&dcsp->sd_ca_rexmt_t,
+ dcsp->sd_ca_rexmt_int,
+ scsp_ca_retran_timeout);
+ }
+ } else {
+ /*
+ * Ignore the message, go to Master/Slave Negotiation
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_NEG;
+ }
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 4
+ * CA message received while in Cache Summarize Master state -- process
+ * CA message
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to received message
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_04(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc = 0;
+ Scsp_msg *msg = (Scsp_msg *)p;
+
+ /*
+ * If the other side thinks he's the master, or if the
+ * initialization bit is set, or if the message is out
+ * of sequence, go back to Master/Slave Negotiation state
+ */
+ if (msg->sc_ca->ca_m || msg->sc_ca->ca_i ||
+ msg->sc_ca->ca_seq < dcsp->sd_ca_seq - 1 ||
+ msg->sc_ca->ca_seq > dcsp->sd_ca_seq) {
+ HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
+ dcsp->sd_ca_state = SCSP_CAFSM_NEG;
+ scsp_dcs_cleanup(dcsp);
+ return(scsp_ca_act_01(dcsp, (Scsp_msg *)0));
+ }
+
+ /*
+ * Ignore any duplicate messages
+ */
+ if (msg->sc_ca->ca_seq == dcsp->sd_ca_seq - 1) {
+ return(0);
+ }
+
+ /*
+ * Stop the retransmission timer
+ */
+ HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
+
+ /*
+ * Process the CA message
+ */
+ scsp_process_ca(dcsp, msg->sc_ca);
+
+ /*
+ * Increment the CA sequence number
+ */
+ dcsp->sd_ca_seq++;
+
+ /*
+ * If we have no more CSAS records to send and the slave sent
+ * a message with the 'O' bit off, we're done with Summarize
+ * state
+ */
+ if (!dcsp->sd_ca_csas && !msg->sc_ca->ca_o) {
+ /*
+ * Free any CA message saved for retransmission
+ */
+ if (dcsp->sd_ca_rexmt_msg) {
+ scsp_free_msg(dcsp->sd_ca_rexmt_msg);
+ dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
+ }
+
+ /*
+ * If the CRL is empty, we go directly to Aligned state;
+ * otherwise, we go to Update Cache and send a CSUS
+ */
+ if (!dcsp->sd_crl) {
+ /*
+ * Go to Aligned state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED;
+ rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN,
+ (Scsp_msg *)0,
+ (Scsp_if_msg *)0);
+ } else {
+ /*
+ * Go to Cache Update state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_UPDATE;
+ (void)scsp_cfsm(dcsp, SCSP_CIFSM_CA_UPD,
+ (Scsp_msg *)0,
+ (Scsp_if_msg *)0);
+ rc = scsp_send_csus(dcsp);
+ }
+ } else {
+ /*
+ * There are more CSAS records to be exchanged--
+ * continue the cache exchange
+ */
+ rc = scsp_send_ca(dcsp);
+ }
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 5
+ * CA message received while in Cache Summarize Slave state -- process
+ * CA message
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to received message
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_05(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc = 0;
+ Scsp_msg *msg = (Scsp_msg *)p;
+
+ /*
+ * If the other side thinks we're the master, or if the
+ * initialization bit is set, or if the message is out
+ * of sequence, go back to Master/Slave Negotiation state
+ */
+ if (!msg->sc_ca->ca_m || msg->sc_ca->ca_i ||
+ msg->sc_ca->ca_seq < dcsp->sd_ca_seq ||
+ msg->sc_ca->ca_seq > dcsp->sd_ca_seq + 1) {
+ HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
+ dcsp->sd_ca_state = SCSP_CAFSM_NEG;
+ scsp_dcs_cleanup(dcsp);
+ return(scsp_ca_act_01(dcsp, (Scsp_msg *)0));
+ }
+
+ /*
+ * If this is a duplicate, retransmit the last message
+ */
+ if (msg->sc_ca->ca_seq == dcsp->sd_ca_seq) {
+ if (dcsp->sd_ca_rexmt_msg) {
+ rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg);
+ if (rc == 0) {
+ HARP_TIMER(&dcsp->sd_ca_rexmt_t,
+ dcsp->sd_ca_rexmt_int,
+ scsp_ca_retran_timeout);
+ }
+ }
+ return(rc);
+ }
+
+ /*
+ * Free the last CA message
+ */
+ if (dcsp->sd_ca_rexmt_msg) {
+ scsp_free_msg(dcsp->sd_ca_rexmt_msg);
+ dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
+ }
+
+ /*
+ * Process the CA message
+ */
+ scsp_process_ca(dcsp, msg->sc_ca);
+
+ /*
+ * Increment the CA sequence number
+ */
+ dcsp->sd_ca_seq++;
+
+ /*
+ * Answer the CA message
+ */
+ rc = scsp_send_ca(dcsp);
+ if (rc)
+ return(rc);
+
+ /*
+ * If we're done sending CSAS records and the other side is,
+ * too, we're done with Summarize state
+ */
+ if (!dcsp->sd_ca_csas && !msg->sc_ca->ca_o) {
+ /*
+ * If the CRL is empty, we go directly to Aligned state;
+ * otherwise, we go to Update Cache and send a CSUS
+ */
+ if (!dcsp->sd_crl) {
+ /*
+ * Go to Aligned state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED;
+ rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN,
+ (Scsp_msg *)0,
+ (Scsp_if_msg *)0);
+ } else {
+ /*
+ * Go to Cache Update state
+ */
+ dcsp->sd_ca_state = SCSP_CAFSM_UPDATE;
+ HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
+ HARP_TIMER(&dcsp->sd_ca_rexmt_t,
+ dcsp->sd_ca_rexmt_int,
+ scsp_ca_retran_timeout);
+ (void)scsp_cfsm(dcsp, SCSP_CIFSM_CA_UPD,
+ (Scsp_msg *)0,
+ (Scsp_if_msg *)0);
+ rc = scsp_send_csus(dcsp);
+ }
+ }
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 6
+ * Retransmit timer expired -- retransmit last CA message
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p ignored
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_06(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc;
+
+ /*
+ * Resend the CA message
+ */
+ rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg);
+
+ /*
+ * Restart the retransmit timer
+ */
+ if (rc == 0) {
+ HARP_TIMER(&dcsp->sd_ca_rexmt_t, dcsp->sd_ca_rexmt_int,
+ scsp_ca_retran_timeout);
+ }
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 7
+ * CSU Solicit received -- send it to the client interface FSM
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to received message
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_07(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc;
+ Scsp_msg *msg = (Scsp_msg *)p;
+
+ /*
+ * Cancel the CA retransmit timer and free any CA message
+ * saved for retransmission
+ */
+ if (dcsp->sd_ca_rexmt_msg) {
+ HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
+ scsp_free_msg(dcsp->sd_ca_rexmt_msg);
+ dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
+ }
+
+ /*
+ * Pass the CSUS to the client interface FSM
+ */
+ rc = scsp_cfsm(dcsp, SCSP_CIFSM_CSU_SOL, msg,
+ (Scsp_if_msg *)0);
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 8
+ * CSU Request received -- pass it to the client interface FSM
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to received message
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_08(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc;
+ Scsp_msg *msg = (Scsp_msg *)p;
+ Scsp_csu_msg *csusp;
+ Scsp_csa *csap;
+
+ /*
+ * Check whether this messages answers a CSUS
+ */
+ scsp_csus_ack(dcsp, msg);
+
+ /*
+ * If all CSAs requestd in CSUS messages have been
+ * received, the cache is aligned, so go to Aligned State
+ */
+ if (!dcsp->sd_csus_rexmt_msg && !dcsp->sd_crl &&
+ dcsp->sd_ca_state != SCSP_CAFSM_ALIGNED) {
+ dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED;
+ rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN,
+ (Scsp_msg *)0, (Scsp_if_msg *)0);
+ }
+
+ /*
+ * Pass the CSU Req to the client interface FSM
+ */
+ rc = scsp_cfsm(dcsp, SCSP_CIFSM_CSU_REQ, msg,
+ (Scsp_if_msg *)0);
+
+ /*
+ * Move the CSA chain from the message to the list of
+ * requests that need acknowledgements
+ */
+ for (csap = msg->sc_csu_msg->csu_csa_rec; csap;
+ csap = csap->next) {
+ LINK2TAIL(csap, Scsp_csa, dcsp->sd_csu_ack_pend, next);
+ }
+ msg->sc_csu_msg->csu_csa_rec = (Scsp_csa *)0;
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 9
+ * CA Retransmit timer expired in Update Cache or Aligned state--free
+ * the saved CA message
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p ignored
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_09(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ /*
+ * Free any CA message saved for retransmission
+ */
+ if (dcsp->sd_ca_rexmt_msg) {
+ scsp_free_msg(dcsp->sd_ca_rexmt_msg);
+ dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0;
+ }
+
+ return(0);
+}
+
+
+/*
+ * CA finite state machine action 10
+ * CSU Reply received -- Process the message
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to received message
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_10(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc = 0;
+ Scsp_msg *msg = (Scsp_msg *)p;
+ Scsp_csu_rexmt *rxp, *next_rxp;
+ Scsp_csa *csap, *next_csap, *mcp;
+
+ /*
+ * Dequeue acknowledged CSAs. For each CSAS in the received
+ * message, find the corresponding CSA on the CSU Request
+ * retransmit queue. Remove the CSA from the queue; if this
+ * results in the retransmit queue entry being empty, delete
+ * the entry. If the DCS has a newer CSA, send a CSUS to
+ * request it.
+ *
+ * Caution--potentially confusing lack of indentation ahead.
+ */
+ for (mcp = msg->sc_csu_msg->csu_csa_rec; mcp;
+ mcp = mcp->next) {
+ for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = next_rxp) {
+ next_rxp = rxp->sr_next;
+ for (csap = rxp->sr_csa; csap; csap = next_csap) {
+ next_csap = csap->next;
+ if (scsp_cmp_key(&csap->key, &mcp->key) ||
+ scsp_cmp_id(&csap->oid, &mcp->oid))
+ continue;
+ /*
+ * Found a CSA whose key and ID are equal to
+ * those in the CSU Reply
+ */
+ if (csap->seq == mcp->seq) {
+ /*
+ * The queued seq no is equal to the
+ * received seq no--the CSA is acknowledged
+ */
+ UNLINK(csap, Scsp_csa, rxp->sr_csa, next);
+ SCSP_FREE_CSA(csap);
+ } else if (csap->seq < mcp->seq) {
+ /*
+ * Queued seq no is less than received.
+ * We must dequeue the CSA and send a
+ * CSUS to request the more-up-to-date
+ * cache entry.
+ */
+ UNLINK(mcp, Scsp_csa,
+ msg->sc_csu_msg->csu_csa_rec,
+ next);
+ LINK2TAIL(mcp, Scsp_csa, dcsp->sd_crl, next);
+ UNLINK(csap, Scsp_csa, rxp->sr_csa, next);
+ SCSP_FREE_CSA(csap);
+ if (!dcsp->sd_csus_rexmt_msg) {
+ rc = scsp_send_csus(dcsp);
+ if (rc) {
+ return(rc);
+ }
+ }
+ }
+ /*
+ * Queued seq no is greater than
+ * received. Ignore the received CSAS.
+ */
+
+ /*
+ * If the retransmission block is empty, stop the
+ * timer and free it
+ */
+ if (!rxp->sr_csa) {
+ HARP_CANCEL(&rxp->sr_t);
+ UNLINK(rxp, Scsp_csu_rexmt,
+ dcsp->sd_csu_rexmt, sr_next);
+ UM_FREE(rxp);
+ }
+
+ break;
+ } /* for (csap = ... */
+ } /* for (rxp = ... */
+ } /* for (mcp = ... */
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 11
+ * Updated cache entry -- update the summary cache and send a
+ * CSU Request
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to CSA describing new cache entry
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_11(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc, state;
+ Scsp_csa *csap = (Scsp_csa *)p;
+ Scsp_cse *csep;
+
+ /*
+ * Get the state of the CSA
+ */
+ switch(dcsp->sd_server->ss_pid) {
+ case SCSP_PROTO_ATMARP:
+ state = csap->atmarp_data->sa_state;
+ break;
+ default:
+ SCSP_FREE_CSA(csap);
+ return(EINVAL);
+ }
+
+ if (state < SCSP_ASTATE_NEW || state > SCSP_ASTATE_DEL) {
+ SCSP_FREE_CSA(csap);
+ return(EINVAL);
+ }
+
+ /*
+ * Look up the cache summary entry for the CSA
+ */
+ SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep);
+
+ /*
+ * Process ATMARP entries
+ */
+ if (dcsp->sd_server->ss_pid == SCSP_PROTO_ATMARP) {
+ switch(state) {
+ case SCSP_ASTATE_NEW:
+ case SCSP_ASTATE_UPD:
+ /*
+ * Add the entry if we don't have it already
+ */
+ if (!csep) {
+ csep = (Scsp_cse *)UM_ALLOC(
+ sizeof(Scsp_cse));
+ if (!csep)
+ scsp_mem_err("scsp_ca_act_11: sizeof(Scsp_cse)");
+ UM_ZERO(csep, sizeof(Scsp_cse));
+
+ csep->sc_key = csap->key;
+ SCSP_ADD(dcsp->sd_server, csep);
+ }
+
+ /*
+ * Update the cache summary entry
+ */
+ csep->sc_seq = csap->seq;
+ csep->sc_oid = csap->oid;
+ break;
+ case SCSP_ASTATE_DEL:
+ /*
+ * Delete any entry, but don't send the
+ * delete to the DCS
+ */
+ if (csep) {
+ SCSP_DELETE(dcsp->sd_server, csep);
+ UM_FREE(csep);
+ }
+
+ SCSP_FREE_CSA(csap);
+ return(0);
+ }
+ }
+
+ /*
+ * Send the CSA in a CSU Request
+ */
+ csap->trans_ct = 0;
+ rc = scsp_send_csu_req(dcsp, csap);
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 12
+ * CSUS retransmit timer expired--send a CSUS with any pending CSA
+ * records
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p ignored
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_12(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc;
+
+ rc = scsp_send_csus(dcsp);
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 13
+ * CSU retransmit timer fired in Update or Aligned state--
+ * retransmit CSU Req
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to retransmission block whose timer fired
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_13(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc = 0;
+ Scsp_csu_rexmt *rxp = (Scsp_csu_rexmt *)p;
+ Scsp_csa *csap, *csap1, *next_csap;
+
+ /*
+ * Unlink and free the retransmit request block
+ */
+ csap = rxp->sr_csa;
+ UNLINK(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, sr_next);
+ UM_FREE(rxp);
+
+ /*
+ * Increment the transmission count for the CSAs in the request
+ */
+ for (csap1 = csap; csap1; csap1 = next_csap) {
+ next_csap = csap1->next;
+ csap1->trans_ct++;
+ if (csap1->trans_ct >= dcsp->sd_csu_rexmt_max) {
+ /*
+ * We've already sent this as many times as
+ * the limit allows. Drop this CSA.
+ */
+ UNLINK(csap1, Scsp_csa, csap, next);
+ SCSP_FREE_CSA(csap1);
+ }
+ }
+
+ /*
+ * Send another CSU Request with the CSA list, if it isn't
+ * empty now
+ */
+ if (csap) {
+ rc = scsp_send_csu_req(dcsp, csap);
+ }
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 14
+ * Updated cache entry in Master/Slave Negotiation, Master, or
+ * Slave state--add entry to cache and CSA list
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to new cache summary entry
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_14(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ Scsp_csa *csap = (Scsp_csa *)p;
+ Scsp_cse *csep, *csep1;
+
+ /*
+ * Check to see whether we already have this
+ */
+ SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep);
+
+ /*
+ * If we don't already have it and it's not being deleted,
+ * build a new cache summary entry
+ */
+ if (!csep && !csap->null) {
+ /*
+ * Get memory for a new entry
+ */
+ csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse));
+ if (!csep) {
+ scsp_mem_err("scsp_ca_act_14: sizeof(Scsp_cse)");
+ }
+ UM_ZERO(csep, sizeof(Scsp_cse));
+
+ /*
+ * Fill out the new cache entry
+ */
+ csep->sc_seq = csap->seq;
+ csep->sc_key = csap->key;
+ csep->sc_oid = csap->oid;
+
+ /*
+ * Duplicate the new cache entry
+ */
+ csep1 = scsp_dup_cse(csep);
+
+ /*
+ * Add entry to the summary cache and the CSAS list
+ */
+ SCSP_ADD(dcsp->sd_server, csep);
+ LINK2TAIL(csep1, Scsp_cse, dcsp->sd_ca_csas, sc_next);
+ } else {
+ /*
+ * We already have the entry. Find it on the CSAS
+ * list.
+ */
+ for (csep1 = dcsp->sd_ca_csas; csep1;
+ csep1 = csep1->sc_next) {
+ if (scsp_cmp_key(&csep->sc_key,
+ &csep1->sc_key) == 0)
+ break;
+ }
+
+ /*
+ * Update or delete the entry
+ */
+ if (csap->null) {
+ /*
+ * The null flag is set--delete the entry
+ */
+ SCSP_DELETE(dcsp->sd_server, csep);
+ UM_FREE(csep);
+ if (csep1) {
+ UNLINK(csep1, Scsp_cse,
+ dcsp->sd_ca_csas,
+ sc_next);
+ UM_FREE(csep1);
+ }
+ } else {
+ /*
+ * Update the entry
+ */
+ csep->sc_seq = csap->seq;
+ csep->sc_oid = csap->oid;
+ if (!csep1) {
+ csep1 = scsp_dup_cse(csep);
+ LINK2TAIL(csep1, Scsp_cse,
+ dcsp->sd_ca_csas, sc_next);
+ } else {
+ csep1->sc_seq = csap->seq;
+ csep1->sc_oid = csap->oid;
+ }
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * CA finite state machine action 15
+ * CA message received in Update Cache state--if we have a saved CA
+ * message, retransmit it; otherwise, go to Master/Slave Negotiation
+ * state
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p ignored
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_15(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int rc;
+ Scsp_msg *msg = (Scsp_msg *)p;
+
+ /*
+ * If we don't have a saved CA message, or the sequence no. in
+ * the received message isn't right, fall back to Master/Slave
+ * Negotiation state
+ */
+ if (!dcsp->sd_ca_rexmt_msg ||
+ msg->sc_ca->ca_seq != dcsp->sd_ca_seq) {
+ dcsp->sd_ca_state = SCSP_CAFSM_NEG;
+ scsp_dcs_cleanup(dcsp);
+ rc = scsp_ca_act_01(dcsp, (Scsp_msg *)0);
+ } else {
+ /*
+ * Retransmit the saved CA message and reset the
+ * CA timer
+ */
+ rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg);
+ if (rc == 0) {
+ HARP_CANCEL(&dcsp->sd_ca_rexmt_t);
+ HARP_TIMER(&dcsp->sd_ca_rexmt_t,
+ dcsp->sd_ca_rexmt_int,
+ scsp_ca_retran_timeout);
+ }
+ }
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 16
+ * Update Response received from client in Update Cache or Aligned
+ * state. Move the acknowledged CSA to the acknowledged queue. If
+ * the list of CSAs pending acknowledgement is empty, send a CSU
+ * Reply.
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to message from client
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_16(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int found, rc = 0;
+ Scsp_if_msg *cmsg = (Scsp_if_msg *)p;
+ Scsp_csa *csap;
+
+ /*
+ * Find the acknowledged CSA
+ */
+ for (csap = dcsp->sd_csu_ack_pend, found = 0; csap && !found;
+ csap = csap->next) {
+ switch (dcsp->sd_server->ss_pid) {
+ case SCSP_PROTO_ATMARP:
+ found = ((scsp_cmp_key(&csap->key,
+ &cmsg->si_atmarp.sa_key) == 0) &&
+ (scsp_cmp_id(&csap->oid,
+ &cmsg->si_atmarp.sa_oid) == 0));
+ break;
+ default:
+ /*
+ * Protocol not implemented
+ */
+ return(EPROTONOSUPPORT);
+ }
+ if (found)
+ break;
+ }
+
+ if (!found) {
+ if (scsp_trace_mode & SCSP_TRACE_CAFSM) {
+ scsp_trace("scsp_ca_act_16: can't find CSA entry for Update Response\n");
+ }
+ return(0);
+ }
+
+ if (cmsg->si_rc == SCSP_RSP_OK) {
+ /*
+ * The server accepted the cache entry
+ */
+
+ /*
+ * Update SCSP's cache
+ */
+ scsp_update_cache(dcsp, csap);
+
+ /*
+ * Send this CSA to any other DCSs in the server group
+ */
+ rc = scsp_propagate_csa(dcsp, csap);
+ }
+
+ /*
+ * Move the CSA from the ACK pending queue to the
+ * acknowledged queue
+ */
+ UNLINK(csap, Scsp_csa, dcsp->sd_csu_ack_pend, next);
+ LINK2TAIL(csap, Scsp_csa, dcsp->sd_csu_ack, next);
+ if (!dcsp->sd_csu_ack_pend) {
+ /*
+ * ACK pending list is empty--send a CSU Reply
+ */
+ csap = dcsp->sd_csu_ack;
+ dcsp->sd_csu_ack = (Scsp_csa *)0;
+ rc = scsp_send_csu_reply(dcsp, csap);
+ }
+
+ return(rc);
+}
+
+
+/*
+ * CA finite state machine action 17
+ * Ignore an event.
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p ignored
+ *
+ * Returns:
+ * always returns 0
+ *
+ */
+int
+scsp_ca_act_17(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ return(0);
+}
+
+
+/*
+ * CA finite state machine action 18
+ * Updated cache entry in Down state--add entry to summary cache
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to new cache summary entry
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_18(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ Scsp_csa *csap = (Scsp_csa *)p;
+
+ /*
+ * Update the cache as appropriate
+ */
+ scsp_update_cache(dcsp, csap);
+
+ return(0);
+}
+
+
+/*
+ * CA finite state machine action 19
+ * Update Response received from client in Master/Slave Negotiation
+ * state. Update the cache as appropriate.
+ *
+ * Arguments:
+ * dcsp pointer to DCS control block
+ * p pointer to message from client
+ *
+ * Returns:
+ * 0 success
+ * errno error encountered
+ *
+ */
+int
+scsp_ca_act_19(dcsp, p)
+ Scsp_dcs *dcsp;
+ void *p;
+{
+ int found, rc = 0;
+ Scsp_if_msg *cmsg = (Scsp_if_msg *)p;
+ Scsp_csa *csap;
+
+ /*
+ * Ignore the message if the client rejected the update
+ */
+ if (cmsg->si_rc != SCSP_RSP_OK) {
+ return(0);
+ }
+
+ /*
+ * Create a CSAS from the client's update
+ */
+ csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa));
+ if (!csap) {
+ scsp_mem_err("scsp_ca_act_19: sizeof(Scsp_csa)");
+ }
+ UM_ZERO(csap, sizeof(Scsp_csa));
+
+ csap->hops = 1;
+ switch (dcsp->sd_server->ss_pid) {
+ case SCSP_PROTO_ATMARP:
+ csap->null = cmsg->si_atmarp.sa_state ==
+ SCSP_ASTATE_DEL;
+ csap->seq = cmsg->si_atmarp.sa_seq;
+ csap->key = cmsg->si_atmarp.sa_key;
+ csap->oid = cmsg->si_atmarp.sa_oid;
+ break;
+ default:
+ return(EINVAL);
+ }
+
+ /*
+ * Update SCSP's cache
+ */
+ scsp_update_cache(dcsp, csap);
+
+ return(0);
+}