diff options
Diffstat (limited to 'usr.sbin/atm/scspd/scsp_cafsm.c')
-rw-r--r-- | usr.sbin/atm/scspd/scsp_cafsm.c | 1448 |
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); +} |