freebsd-skq/usr.sbin/atm/scspd/scsp_cafsm.c
2002-10-10 00:32:55 +00:00

1440 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.
*
* @(#) $FreeBSD$
*
*/
/*
* Server Cache Synchronization Protocol (SCSP) Support
* ----------------------------------------------------
*
* Cache Alignment finite state machine
*
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netatm/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 <errno.h>
#include <libatm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "scsp_msg.h"
#include "scsp_if.h"
#include "scsp_var.h"
#ifndef lint
__RCSID("@(#) $FreeBSD$");
#endif
/*
* CA FSM actions
*/
#define CA_ACTION_CNT 20
int scsp_ca_act_00(Scsp_dcs *, void *);
int scsp_ca_act_01(Scsp_dcs *, void *);
int scsp_ca_act_02(Scsp_dcs *, void *);
int scsp_ca_act_03(Scsp_dcs *, void *);
int scsp_ca_act_04(Scsp_dcs *, void *);
int scsp_ca_act_05(Scsp_dcs *, void *);
int scsp_ca_act_06(Scsp_dcs *, void *);
int scsp_ca_act_07(Scsp_dcs *, void *);
int scsp_ca_act_08(Scsp_dcs *, void *);
int scsp_ca_act_09(Scsp_dcs *, void *);
int scsp_ca_act_10(Scsp_dcs *, void *);
int scsp_ca_act_11(Scsp_dcs *, void *);
int scsp_ca_act_12(Scsp_dcs *, void *);
int scsp_ca_act_13(Scsp_dcs *, void *);
int scsp_ca_act_14(Scsp_dcs *, void *);
int scsp_ca_act_15(Scsp_dcs *, void *);
int scsp_ca_act_16(Scsp_dcs *, void *);
int scsp_ca_act_17(Scsp_dcs *, void *);
int scsp_ca_act_18(Scsp_dcs *, void *);
int scsp_ca_act_19(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_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);
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 = calloc(1, sizeof(Scsp_cse));
if (csep == NULL)
scsp_mem_err("scsp_ca_act_11: 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);
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);
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 = calloc(1, sizeof(Scsp_cse));
if (csep == NULL)
scsp_mem_err("scsp_ca_act_14: 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);
free(csep);
if (csep1) {
UNLINK(csep1, Scsp_cse,
dcsp->sd_ca_csas,
sc_next);
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;
{
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 = calloc(1, sizeof(Scsp_csa));
if (csap == NULL)
scsp_mem_err("scsp_ca_act_19: 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);
}