freebsd-skq/usr.sbin/atm/scspd/scsp_cafsm.c
phk c3dd1fa899 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

1449 lines
28 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_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);
}