diff options
Diffstat (limited to 'usr.sbin/atm/scspd')
-rw-r--r-- | usr.sbin/atm/scspd/Makefile | 42 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_cafsm.c | 1448 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_config.c | 1160 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_config_lex.c | 528 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_config_parse.y | 410 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_hfsm.c | 580 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_if.c | 655 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_if.h | 194 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_input.c | 1103 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_log.c | 265 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_msg.c | 611 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_msg.h | 462 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_output.c | 934 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_print.c | 1315 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_socket.c | 1349 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_subr.c | 1123 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_timer.c | 265 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scsp_var.h | 434 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scspd.8 | 443 | ||||
-rw-r--r-- | usr.sbin/atm/scspd/scspd.c | 545 |
20 files changed, 13866 insertions, 0 deletions
diff --git a/usr.sbin/atm/scspd/Makefile b/usr.sbin/atm/scspd/Makefile new file mode 100644 index 0000000..6bd5e1e --- /dev/null +++ b/usr.sbin/atm/scspd/Makefile @@ -0,0 +1,42 @@ +# +# +# =================================== +# 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: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +PROG= scspd +SRCS= scspd.c scsp_cafsm.c scsp_config.c scsp_config_lex.c \ + scsp_config_parse.y \ + scsp_hfsm.c scsp_if.c scsp_input.c scsp_log.c scsp_msg.c \ + scsp_output.c scsp_print.c scsp_socket.c scsp_subr.c \ + scsp_timer.c +MAN8= scspd.8 + +CFLAGS+= -I ${.CURDIR}/../../../sys +LDADD+= -latm +YFLAGS= -d + +.include <bsd.prog.mk> diff --git a/usr.sbin/atm/scspd/scsp_cafsm.c b/usr.sbin/atm/scspd/scsp_cafsm.c new file mode 100644 index 0000000..b9d2b51 --- /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); +} diff --git a/usr.sbin/atm/scspd/scsp_config.c b/usr.sbin/atm/scspd/scsp_config.c new file mode 100644 index 0000000..99eca7a --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_config.c @@ -0,0 +1,1160 @@ +/* + * + * =================================== + * 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_config.c,v 1.3 1998/08/13 20:11:14 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Configuration file processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_config.c,v 1.3 1998/08/13 20:11:14 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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" + + +/* + * Global variables + */ +FILE *cfg_file; +Scsp_server *current_server; +Scsp_dcs *current_dcs; + + + +/* + * Process the configuration file + * + * This routine is called when the daemon starts, and it can also be + * called while it is running, as the result of a SIGHUP signal. It + * therefore has to be capable of both configuring the daemon from + * scratch and modifying the configuration of a running daemon. + * + * Arguments: + * cfn configuration file name + * + * Returns: + * 0 configuration read with no errors + * else error found in configuration file + * + */ +int +scsp_config(cfn) + char *cfn; +{ + int rc; + Scsp_server *ssp, *snext; + + /* + * Open the configuration file + */ + cfg_file = fopen(cfn, "r"); + if (!cfg_file) { + scsp_log(LOG_ERR, "can't open config file %s", + (void *)cfn); + exit(1); + } + + /* + * Initialize current interface pointer + */ + current_server = (Scsp_server *)0; + + /* + * Clear marks on any existing servers + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + ssp->ss_mark = 0; + } + + /* + * Scan the configuration file, processing each line as + * it is read + */ + rc = yyparse(); + + /* + * Close the configuration file + */ + fclose(cfg_file); + + /* + * Delete any server entries that weren't updated + */ + for (ssp = scsp_server_head; ssp; ssp = snext) { + snext = ssp->ss_next; + if (!ssp->ss_mark) + scsp_server_delete(ssp); + } + + return(rc); +} + + +/* + * Prepare for SCSP DCS setup + * + * This routine is called from yyparse() when a DCS command is found. + * + * Arguments: + * none + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +start_dcs() +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + /* + * Allocate a DCS block + */ + dcsp = (Scsp_dcs *)UM_ALLOC(sizeof(Scsp_dcs)); + if (!dcsp) { + scsp_mem_err("start_dcs: sizeof(Scsp_dcs)"); + } + UM_ZERO(dcsp, sizeof(Scsp_dcs)); + + /* + * Fill out DCS links and default values + */ + dcsp->sd_server = current_server; + dcsp->sd_addr.address_format = T_ATM_ABSENT; + dcsp->sd_subaddr.address_format = T_ATM_ABSENT; + dcsp->sd_sock = -1; + dcsp->sd_ca_rexmt_int = SCSP_CAReXmitInterval; + dcsp->sd_csus_rexmt_int = SCSP_CSUSReXmitInterval; + dcsp->sd_hops = SCSP_CSA_HOP_CNT; + dcsp->sd_csu_rexmt_int = SCSP_CSUReXmitInterval; + dcsp->sd_csu_rexmt_max = SCSP_CSUReXmitMax; + LINK2TAIL(dcsp, Scsp_dcs, current_server->ss_dcs, sd_next); + + current_dcs = dcsp; + return(0); +} + + +/* + * Finish up server configuration + * + * This routine is called from yyparse() to at the end of a DCS + * command. It checks that required fields are set and finishes + * up the DCS block. + * + * Arguments: + * none + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +finish_dcs() +{ + int rc = 0; + Scsp_dcs *dcsp; + Scsp_server *ssp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + ssp = current_server; + dcsp = current_dcs; + + /* + * Make sure the DCS ID is set + */ + if (dcsp->sd_dcsid.id_len == 0) { + parse_error("DCS ID not set"); + rc++; + } + + /* + * Make sure the ATM address is set + */ + if (dcsp->sd_addr.address_format == T_ATM_ABSENT) { + parse_error("DCS ATM address not set"); + rc++; + } + + current_dcs = (Scsp_dcs *)0; + return(rc); +} + + +/* + * Configure DCS ATM address + * + * This routine is called from yyparse() to process an ATMaddr command. + * + * Arguments: + * ap pointer to DCS's ATM address (in ASCII) + * sap pointer to DCS's ATM subaddress (in ASCII) + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_addr(ap, sap) + char *ap, *sap; +{ + Scsp_dcs *dcsp; + Atm_addr addr, subaddr; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + /* + * Initialize + */ + UM_ZERO(&addr, sizeof(addr)); + addr.address_format = T_ATM_ABSENT; + UM_ZERO(&subaddr, sizeof(subaddr)); + subaddr.address_format = T_ATM_ABSENT; + + /* + * Convert the ATM address from character to internal format + */ + if (ap) { + addr.address_length = get_hex_atm_addr(ap, + (u_char *)addr.address, strlen(ap)); + if (addr.address_length == 0) { + parse_error("invalid ATM address"); + return(1); + } + if (addr.address_length == sizeof(Atm_addr_nsap)) { + addr.address_format = T_ATM_ENDSYS_ADDR; + } else if (addr.address_length <= + sizeof(Atm_addr_e164)) { + addr.address_format = T_ATM_E164_ADDR; + } else { + parse_error("invalid ATM address"); + return(1); + } + } + + /* + * Convert the ATM subaddress from character to internal format + */ + if (sap) { + subaddr.address_length = get_hex_atm_addr(sap, + (u_char *)subaddr.address, strlen(sap)); + if (subaddr.address_length == 0) { + parse_error("invalid ATM address"); + return(1); + } + if (subaddr.address_length == sizeof(Atm_addr_nsap)) { + subaddr.address_format = T_ATM_ENDSYS_ADDR; + } else if (subaddr.address_length <= + sizeof(Atm_addr_e164)) { + subaddr.address_format = T_ATM_E164_ADDR; + } else { + parse_error("invalid ATM subaddress"); + return(1); + } + } + + /* + * Make sure we have a legal ATM address type combination + */ + if (((addr.address_format != T_ATM_ENDSYS_ADDR) || + (subaddr.address_format != T_ATM_ABSENT)) && + ((addr.address_format != T_ATM_E164_ADDR) || + (subaddr.address_format != T_ATM_ENDSYS_ADDR))) { + parse_error("invalid address/subaddress combination"); + return(1); + } + + /* + * Save the address and subaddress + */ + ATM_ADDR_COPY(&addr, &dcsp->sd_addr); + ATM_ADDR_COPY(&subaddr, &dcsp->sd_subaddr); + + return(0); +} + + +/* + * Configure CA retransmit interval for DCS + * + * This routine is called from yyparse() to process a CAReXmitInt + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_ca_rexmit(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid CA retransmit interval"); + return(1); + } + + /* + * Set CA retransmit interval + */ + dcsp->sd_ca_rexmt_int = val; + + return(0); +} + + +/* + * Configure CSUS retransmit interval for DCS + * + * This routine is called from yyparse() to process a CSUSReXmitInt + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_csus_rexmit(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid CSUS retransmit interval"); + return(1); + } + + /* + * Set CSUS retransmit interval + */ + dcsp->sd_csus_rexmt_int = val; + + return(0); +} + + +/* + * Configure CSU retransmit interval for DCS + * + * This routine is called from yyparse() to process a CSUReXmitInt + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_csu_rexmit(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid CSU retransmit interval"); + return(1); + } + + /* + * Set CSU retransmit interval + */ + dcsp->sd_csu_rexmt_int = val; + + return(0); +} + + +/* + * Configure CSU retransmit limit for DCS + * + * This routine is called from yyparse() to process a CSUReXmitMax + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_csu_rexmit_max(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid CSU retransmit maximum"); + return(1); + } + + /* + * Set CSU retransmit limit + */ + dcsp->sd_csu_rexmt_max = val; + + return(0); +} + + +/* + * Configure Hello dead factor for DCS + * + * This routine is called from yyparse() to process a HelloDead + * command. + * + * Arguments: + * val number of times Hello interval has to expire before + * a DCS is considered dead + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_hello_df(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the limit + */ + if (val <= 0 || val > 1024) { + parse_error("invalid Hello dead factor"); + return(1); + } + + /* + * Set Hello dead factor + */ + dcsp->sd_hello_df = val; + + return(0); +} + + +/* + * Configure Hello interval for DCS + * + * This routine is called from yyparse() to process a HelloInt + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_hello_int(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid Hello interval"); + return(1); + } + + /* + * Set Hello interval + */ + dcsp->sd_hello_int = val; + + return(0); +} + + +/* + * Configure hop count for SCSP server + * + * This routine is called from yyparse() to process a Hops command. + * + * Arguments: + * hops number of hops + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_hops(hops) + int hops; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the count + */ + if (hops <= 0 || hops > 1024) { + parse_error("invalid hop count"); + return(1); + } + + /* + * Set hop count + */ + dcsp->sd_hops = hops; + + return(0); +} + + +/* + * Configure DCS ID + * + * This routine is called from yyparse() to process an ID command. + * + * Arguments: + * name pointer to DCS's DNS name or IP address (in ASCII) + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_id(name) + char *name; +{ + Scsp_dcs *dcsp; + Scsp_server *ssp; + struct sockaddr_in *ip_addr; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + ssp = current_server; + dcsp = current_dcs; + + /* + * Convert the DNS name or IP address + */ + ip_addr = get_ip_addr(name); + if (!ip_addr) { + parse_error("invalid DCS IP address"); + return(1); + } + + /* + * Verify the address length + */ + if (ssp->ss_id_len != sizeof(ip_addr->sin_addr)) { + parse_error("invalid DCS ID length"); + return(1); + } + + /* + * Set the ID in the DCS block + */ + dcsp->sd_dcsid.id_len = ssp->ss_id_len; + UM_COPY(&ip_addr->sin_addr, dcsp->sd_dcsid.id, ssp->ss_id_len); + + return(0); +} + + +/* + * Configure network interface for SCSP server + * + * This routine is called from yyparse() to process a Netif command. + * It verifies the network interface name, gets interface information + * from the kernel, and sets the appropriate fields in the server + * control block. + * + * Arguments: + * netif pointer to network interface name + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_intf(netif) + char *netif; +{ + int rc; + Scsp_server *ssp; + + /* + * Get the current network interface address + */ + ssp = current_server; + if (!ssp) { + parse_error("Server not found"); + rc = 1; + goto set_intf_done; + } + + /* + * Make sure we're configuring a valid + * network interface + */ + rc = verify_nif_name(netif); + if (rc == 0) { + parse_error("%s is not a valid network interface", + (void *)netif); + rc = 1; + goto set_intf_done; + } else if (rc < 0) { + scsp_log(LOG_ERR, "Netif name verify error"); + exit(1); + } + + /* + * Save the server's network interface name + */ + strcpy(ssp->ss_intf, netif); + rc = 0; + +set_intf_done: + return(rc); +} + + +/* + * Configure protocol for SCSP server + * + * This routine is called from yyparse() to process a Protocol command. + * + * Arguments: + * proto SCSP protocol being configured + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_protocol(proto) + int proto; +{ + Scsp_server *ssp; + + /* + * Get address of current server block + */ + ssp = current_server; + if (!ssp) { + parse_error("server not found"); + return(1); + } + + /* + * Process based on protocol ID + */ + switch(proto) { + case SCSP_PROTO_ATMARP: + ssp->ss_pid = proto; + ssp->ss_id_len = SCSP_ATMARP_ID_LEN; + ssp->ss_ckey_len = SCSP_ATMARP_KEY_LEN; + break; + case SCSP_PROTO_NHRP: + ssp->ss_pid = proto; + ssp->ss_id_len = SCSP_NHRP_ID_LEN; + ssp->ss_ckey_len = SCSP_NHRP_KEY_LEN; + break; + case SCSP_PROTO_MARS: + case SCSP_PROTO_DHCP: + case SCSP_PROTO_LNNI: + default: + parse_error("invalid protocol"); + return(1); + } + + return(0); +} + + +/* + * Configure server group for SCSP server + * + * This routine is called from yyparse() to process a ServerGroupID + * command. + * + * Arguments: + * sgid server group id + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_server_group(sgid) + int sgid; +{ + Scsp_server *ssp; + + /* + * Get address of current server block + */ + ssp = current_server; + if (!ssp) { + parse_error("server not found"); + return(1); + } + + /* + * Validate server group ID + */ + if (sgid <= 0) { + parse_error("invalid server group ID"); + return(1); + } + + /* + * Save the ID + */ + ssp->ss_sgid = sgid; + + return(0); +} + + +/* + * Prepare for SCSP server setup + * + * This routine is called from yyparse() when a Server statment is + * found. + * + * Arguments: + * name pointer to LIS name + * + * Returns: + * 0 success + * else error encountered + * + */ +int +start_server(name) + char *name; +{ + int i; + Scsp_server *ssp; + Scsp_dcs *dcsp, *next_dcs; + Scsp_cse *csep, *next_cse; + + /* + * See if we already have an entry for this name + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (strcasecmp(ssp->ss_name, name) == 0) + break; + } + + if (ssp) { + /* + * Log the fact that we're updating the entry + */ + scsp_log(LOG_INFO, "updating server entry for %s", + (void *)name); + + /* + * Free the existing cache + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (csep = ssp->ss_cache[i]; csep; + csep = next_cse) { + next_cse = csep->sc_next; + UNLINK(csep, Scsp_cse, ssp->ss_cache[i], + sc_next); + UM_FREE(csep); + } + } + + /* + * Delete existing DCS blocks + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = next_dcs) { + next_dcs = dcsp->sd_next; + scsp_dcs_delete(dcsp); + } + } else { + /* + * Get a new server entry + */ + ssp = (Scsp_server *)UM_ALLOC(sizeof(Scsp_server)); + if (!ssp) { + scsp_log(LOG_ERR, "unable to allocate server entry"); + exit(1); + } + UM_ZERO(ssp, sizeof(Scsp_server)); + ssp->ss_sock = -1; + ssp->ss_dcs_lsock = -1; + + /* + * Set the name + */ + ssp->ss_name = strdup(name); + + /* + * Link in the new interface entry + */ + LINK2TAIL(ssp, Scsp_server, scsp_server_head, + ss_next); + } + + /* + * If the mark is already set, this is a duplicate command + */ + if (ssp->ss_mark) { + parse_error("duplicate server \"%s\"", name); + return(1); + } + + /* + * Make this the current interface + */ + current_server = ssp; + + return(0); +} + + +/* + * Finish up server configuration + * + * This routine is called from yyparse() when the end of a server + * statement is reached. It checks that required fields are set + * and marks the entry as processed. + * + * Arguments: + * None + * + * Returns: + * 0 OK + * 1 Error + * + */ +int +finish_server() +{ + int rc = 0; + Scsp_server *ssp; + + /* + * Get the current network interface address + */ + ssp = current_server; + if (!ssp) { + parse_error("Server not found"); + rc++; + } + + /* + * Mark the interface as processed + */ + ssp->ss_mark = 1; + + /* + * Make sure the interface has been configured + */ + if (ssp->ss_intf == (char *)0) { + parse_error("netif missing from server specification"); + rc++; + } + + /* + * Make sure the protocol is set + */ + if (ssp->ss_pid == 0) { + parse_error("protocol missing from server specification"); + rc++; + } + + /* + * Make sure the server group is set + */ + if (ssp->ss_sgid == 0) { + parse_error("server group ID missing from server specification"); + rc++; + } + + /* + * Make sure at least one DCS is configured + */ + if (ssp->ss_dcs == (Scsp_dcs *)0) { + parse_error("no DCS configured for server"); + rc++; + } + + /* + * Mark the end of the server + */ + current_server = (Scsp_server *)0; + + return(rc); +} + + +/* + * Configure log file for SCSP server + * + * This routine is called from yyparse() to process a log File command. + * + * Arguments: + * file name of logging file + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_log_file(file) + char *file; +{ + /* + * Make sure we haven't already got a log file + */ + if (scsp_log_file) { + parse_error("multiple log files specified"); + return(1); + } + + /* + * Open the file + */ + scsp_log_file = fopen(file, "a"); + if (!scsp_log_file) { + parse_error("can't open log file"); + return(1); + } + + return(0); +} diff --git a/usr.sbin/atm/scspd/scsp_config_lex.c b/usr.sbin/atm/scspd/scsp_config_lex.c new file mode 100644 index 0000000..7b77ae6 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_config_lex.c @@ -0,0 +1,528 @@ +/* + * + * =================================== + * 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_config_lex.c,v 1.3 1998/08/13 20:11:14 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Parse a configuration file into tokens + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_config_lex.c,v 1.3 1998/08/13 20:11:14 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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" +#include "scsp_config_parse.h" + +/* + * Global variables + */ +int parse_line = 1; + +/* + * Local definitions + */ +#define TOK_MAX_LEN 128 + +/* + * Character classes + */ +#define CHAR_INVALID 0 /* Not allowed */ +#define CHAR_ALPHA 1 /* G-W, Y, Z */ +#define CHAR_HEX_DIGIT 2 /* A-F */ +#define CHAR_X 3 /* X */ +#define CHAR_0 4 /* '0' */ +#define CHAR_DIGIT 5 /* 1-9 */ +#define CHAR_SPACE 6 /* space, tab */ +#define CHAR_DECIMAL 7 /* period */ +#define CHAR_SLASH 8 /* slash */ +#define CHAR_ASTERISK 9 /* asterisk */ +#define CHAR_HASH 10 /* pound sign */ +#define CHAR_SPECIAL 11 /* semicolon, braces */ +#define CHAR_MISC 12 /* chars allowd in file names */ +#define CHAR_EOL 13 /* new line */ +#define CHAR_EOF 14 /* EOF */ +#define CHAR_CNT CHAR_EOF + 1 + +/* + * Character class table (initialized by init_class_tbl()) + */ +static char class_tbl[128]; + +/* + * State table element structure + */ +struct state_entry { + int action; + int next; +}; + +/* + * Scanner states + */ +#define TS_INIT 0 +#define TS_ALPHA 1 +#define TS_INT_1 2 +#define TS_INT 3 +#define TS_HEX 4 +#define TS_SLASH_1 5 +#define TS_COMMENT 6 +#define TS_COMMENT_1 7 +#define TS_FLUSH 8 +#define TS_HEX_1 9 +#define TS_CNT TS_HEX_1 + 1 + +/* + * Token scanner state table + */ +static struct state_entry token_state_tbl[CHAR_CNT][TS_CNT] = { +/* 0 1 2 3 4 5 6 7 8 9 */ +/* bad */{{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{0,6},{0,6},{0,8},{2,0}}, +/* g-z */{{1,1},{1,1},{1,1},{1,1},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}}, +/* a-f */{{1,1},{1,1},{1,1},{1,1},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}}, +/* x */{{1,1},{1,1},{1,4},{1,4},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}}, +/* 0 */{{1,2},{1,1},{1,3},{1,3},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}}, +/* 1-9 */{{1,3},{1,1},{1,3},{1,3},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}}, +/* sp */{{0,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}}, +/* . */{{2,0},{1,1},{1,1},{1,1},{1,4},{1,1},{0,6},{0,6},{0,8},{2,0}}, +/* / */{{1,5},{1,1},{1,1},{1,1},{7,0},{4,8},{0,6},{0,0},{0,8},{2,0}}, +/* * */{{2,0},{6,0},{8,0},{8,0},{7,0},{4,6},{0,7},{0,7},{0,8},{2,0}}, +/* # */{{0,8},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}}, +/* ;{} */{{3,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}}, +/* Msc */{{2,0},{1,1},{1,1},{1,1},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}}, +/* EOL */{{0,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,0},{2,0}}, +/* EOF */{{9,0},{6,0},{8,0},{8,0},{7,0},{6,0},{2,0},{2,0},{9,0},{2,0}}, +}; + + +/* + * Reserved words + */ +static struct { + char *word; + int token; +} rsvd_word_tbl[] = { + { "ATMaddr", TOK_DCS_ADDR }, + { "ATMARP", TOK_ATMARP }, + { "CAReXmitInt", TOK_DCS_CA_REXMIT_INT }, + { "CSUSReXmitInt", TOK_DCS_CSUS_REXMIT_INT }, + { "CSUReXmitInt", TOK_DCS_CSU_REXMIT_INT }, + { "CSUReXmitMax", TOK_DCS_CSU_REXMIT_MAX }, + { "DCS", TOK_DCS }, + { "DHCP", TOK_DHCP }, + { "familyID", TOK_FAMILY }, + { "file", TOK_LFN }, + { "hops", TOK_DCS_HOP_CNT }, + { "HelloDead", TOK_DCS_HELLO_DF }, + { "HelloInt", TOK_DCS_HELLO_INT }, + { "ID", TOK_DCS_ID }, + { "LNNI", TOK_LNNI }, + { "log", TOK_LOG }, + { "MARS", TOK_MARS }, + { "netif", TOK_NETIF }, + { "NHRP", TOK_NHRP }, + { "protocol", TOK_PROTOCOL }, + { "server", TOK_SERVER }, + { "ServerGroupID", TOK_SRVGRP }, + { "syslog", TOK_SYSLOG }, + { (char *)0, 0 }, +}; + + +/* + * Copy a character string + * + * Make a copy of a character string, using strdup. If strdup fails, + * meaning we're out of memory, then print an error message and exit. + * + * Arguments: + * s string to be copied + * + * Returns: + * char * pointer to area provided by strdup + * + */ +static char * +copy_buffer(s) + char *s; +{ + char *t; + + t = strdup(s); + + if (!t) { + fprintf(stderr, "%s: strdup failed\n", prog); + exit(1); + } + + return(t); +} + + +/* + * Push a character back onto the input stream. + * + * Arguments: + * c character to be pushed + * + * Returns: + * none + * + */ +static void +push_char(c) + char c; +{ + if (c == '\n') + parse_line--; + + ungetc(c, cfg_file); +} + + +/* + * Initialize the character class table. + * + * Set each entry in the character class table to the class + * corresponding to the character. + * + * Arguments: + * tbl pointer to table to be initialized + * + * Returns: + * None + */ +static void +init_class_tbl(tbl) + char *tbl; +{ + int i; + char c; + + /* + * Set up the table for all ASCII characters + */ + for (i=0; isascii((char)i); i++) { + /* + * Clear entry + */ + tbl[i] = CHAR_INVALID; + + /* + * Set entries depending on character type + */ + c = (char)i; + if (c == 'a' || c == 'b' || c == 'c' || + c == 'd' || c == 'e' || c == 'f' || + c == 'A' || c == 'B' || c == 'C' || + c == 'D' || c == 'E' || c == 'F') + tbl[i] = CHAR_HEX_DIGIT; + else if (c == 'x' || c == 'X') + tbl[i] = CHAR_X; + else if (isalpha(c)) + tbl[i] = CHAR_ALPHA; + else if (c == '0') + tbl[i] = CHAR_0; + else if (isdigit(c)) + tbl[i] = CHAR_DIGIT; + else if (c == '\n') + tbl[i] = CHAR_EOL; + else if (c == ' ' || c == '\t') + tbl[i] = CHAR_SPACE; + else if (c == '#') + tbl[i] = CHAR_HASH; + else if (c == '*') + tbl[i] = CHAR_ASTERISK; + else if (c == '.') + tbl[i] = CHAR_DECIMAL; + else if (c == '/') + tbl[i] = CHAR_SLASH; + else if (c == ';' || c == '{' || c == '}') + tbl[i] = CHAR_SPECIAL; + else if (c == '-' || c == '_' || c == '&' || c == '@' || + c == '~') + tbl[i] = CHAR_MISC; + } +} + + +/* + * Get the class of a character. + * + * Arguments: + * c character being scanned + * + * Returns: + * int character class + */ +static int +char_class(c) + char c; +{ + int class = CHAR_INVALID; + + if (c == EOF) { + class = CHAR_EOF; + } else if (c < 0 || !isascii(c)) { + class = CHAR_INVALID; + } else { + class = class_tbl[c]; + } + + return(class); +} + + +/* + * Print an error message when the scanner finds an error + * + * Arguments: + * c character on which the error was recognized + * state scanner state at error + * + * Returns: + * None + */ +static void +scan_error(c, state) + char c; + int state; +{ + /* + * Check for invalid character + */ + if (char_class(c) == CHAR_INVALID) { + parse_error("Invalid character 0x%x encountered", + c); + return; + } + + /* + * Check for unexpected EOF + */ + if (char_class(c) == CHAR_EOF) { + parse_error("Unexpected end of file"); + return; + } + + /* + * Error depends on state + */ + switch(state) { + case TS_INIT: + parse_error("Syntax error at '%c'", c); + break; + case TS_ALPHA: + case TS_INT_1: + case TS_INT: + case TS_SLASH_1: + case TS_COMMENT: + case TS_COMMENT_1: + case TS_FLUSH: + parse_error("Syntax error"); + break; + case TS_HEX: + case TS_HEX_1: + parse_error("Syntax error in hex string"); + break; + } +} + + +/* + * Assemble a token + * + * Read a character at a time from the input file, assembling the + * characters into tokens as specified by the token scanner state + * table. Return the completed token. + * + * Arguments: + * None + * + * Returns: + * token the type of the token found + */ +int +yylex() +{ + int i, state; + char c, token_buffer[TOK_MAX_LEN]; + + /* + * Initialize + */ + if (class_tbl['A'] != CHAR_HEX_DIGIT) + init_class_tbl(class_tbl); + state = TS_INIT; + UM_ZERO(token_buffer, sizeof(token_buffer)); + UM_ZERO(&yylval, sizeof(yylval)); + + /* + * Handle a character at a time until a token is built + */ + while(1) { + /* + * Read a character from the input file. + */ + c = (char)getc(cfg_file); + if (c == '\n') { + parse_line++; + } + +#ifdef NOTDEF + printf("token_state: state=%d, char=%c, class=%d, action=%d, next=%d\n", + state, + c, + char_class(c), + token_state_tbl[char_class][state].action, + token_state_tbl[char_class][state].next); +#endif + + /* + * Perform an action based on the state table + */ + switch(token_state_tbl[char_class(c)][state].action) { + case 0: + /* + * Ignore the character + */ + break; + case 1: + /* + * Add character to buffer + */ + if (strlen(token_buffer) < TOK_MAX_LEN) { + token_buffer[strlen(token_buffer)] = c; + } + break; + case 2: + /* + * Error--print a message and start over + */ + scan_error(c, state); + break; + case 3: + /* + * Return special character + */ + return(c); + break; + case 4: + /* + * Clear the token buffer + */ + UM_ZERO(token_buffer, sizeof(token_buffer)); + break; + case 5: + /* + * Not used + */ + break; + case 6: + /* + * Return character token + */ + push_char(c); + + /* + * Check for reserved words + */ + for (i=0; rsvd_word_tbl[i].word; i++) { + if (strcasecmp(token_buffer, + rsvd_word_tbl[i].word) == 0) + break; + } + if (rsvd_word_tbl[i].word) { + return(rsvd_word_tbl[i].token); + } + + /* + * Word isn't reserved, return alpha string + */ + yylval.tv_alpha = copy_buffer(token_buffer); + return(TOK_NAME); + break; + case 7: + /* + * Return hex string (ATM address) + */ + push_char(c); + yylval.tv_hex = copy_buffer(token_buffer); + return(TOK_HEX); + break; + case 8: + /* + * Return integer + */ + push_char(c); + yylval.tv_int = atoi(token_buffer); + return(TOK_INTEGER); + break; + case 9: + /* + * Return EOF + */ + return(0); + break; + default: + fprintf(stderr, "Invalid action indicator, state=%d, char=0x%02x\n", + state, c); + break; + } + + /* + * Set the next state and bump to the next character + */ + state = token_state_tbl[char_class(c)][state].next; + } +} diff --git a/usr.sbin/atm/scspd/scsp_config_parse.y b/usr.sbin/atm/scspd/scsp_config_parse.y new file mode 100644 index 0000000..4c02de28 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_config_parse.y @@ -0,0 +1,410 @@ +%{ +/* + * + * =================================== + * 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_config_parse.y,v 1.2 1998/07/24 17:12:14 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * YACC input for configuration file processing + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_config_parse.y,v 1.2 1998/07/24 17:12:14 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.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" + +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif +%} + + +/* + * Token value definition + */ +%union { + char *tv_alpha; + int tv_int; + char *tv_hex; +} + + +/* + * Token types returned by scanner + */ +%token <tv_alpha> TOK_NAME +%token <tv_int> TOK_INTEGER +%token <tv_hex> TOK_HEX + +/* + * Reserved words + */ +%token TOK_ATMARP +%token TOK_DCS +%token TOK_DCS_ADDR +%token TOK_DCS_CA_REXMIT_INT +%token TOK_DCS_CSUS_REXMIT_INT +%token TOK_DCS_CSU_REXMIT_INT +%token TOK_DCS_CSU_REXMIT_MAX +%token TOK_DCS_HELLO_DF +%token TOK_DCS_HELLO_INT +%token TOK_DCS_HOP_CNT +%token TOK_DCS_ID +%token TOK_DHCP +%token TOK_FAMILY +%token TOK_LFN +%token TOK_LNNI +%token TOK_LOG +%token TOK_MARS +%token TOK_NETIF +%token TOK_NHRP +%token TOK_PROTOCOL +%token TOK_SERVER +%token TOK_SRVGRP +%token TOK_SYSLOG + + +%% +cfg_file: /* Empty */ + | stmt_seq + +stmt_seq: stmt + | stmt_seq stmt + ; + +stmt: server_stmt ';' + | log_stmt ';' + ; + +/* + * SCSP server definition statements + */ +server_stmt: TOK_SERVER TOK_NAME + { + int rc; + + rc = start_server($2); + UM_FREE($2); + if (rc) + return(rc); + } + '{' server_def '}' + { + int rc; + + rc = finish_server(); + if (rc) + return(rc); + } + ; + +server_def: server_spec ';' + | server_def server_spec ';' + ; + +server_spec: /* Nothing */ + | dcs_stmt + | TOK_NETIF TOK_NAME + { + int rc; + + /* + * Configure the network interface + */ + rc = set_intf($2); + UM_FREE($2); + if (rc) + return(rc); + } + | TOK_PROTOCOL TOK_ATMARP + { + int rc; + + /* + * Configure the protocol + */ + rc = set_protocol(SCSP_PROTO_ATMARP); + if (rc) + return(rc); + } + | TOK_PROTOCOL TOK_DHCP | TOK_LNNI | TOK_MARS | TOK_NHRP + { + yyerror("Protocol not implemented"); + return(1); + } + | TOK_SRVGRP TOK_INTEGER + { + int rc; + + /* + * Configure the SCSP server group ID + */ + rc = set_server_group($2); + if (rc) + return(rc); + } + ; + +/* + * SCSP DCS definition statements + */ +dcs_stmt: TOK_DCS + { + int rc; + + rc = start_dcs(); + if (rc) + return(rc); + } + '{' dcs_def '}' + { + int rc; + + rc = finish_dcs(); + if (rc) + return(rc); + } + ; + +dcs_def: dcs_spec ';' + | dcs_def dcs_spec ';' + ; + +dcs_spec: /* Nothing */ + | TOK_DCS_ADDR TOK_HEX + { + int rc; + + /* + * Set DCS address + */ + rc = set_dcs_addr($2, (char *)0); + UM_FREE($2); + if (rc) + return(rc); + } + | TOK_DCS_ADDR TOK_HEX TOK_HEX + { + int rc; + + /* + * Set DCS address and subaddress + */ + rc = set_dcs_addr($2, $3); + UM_FREE($2); + UM_FREE($3); + if (rc) + return(rc); + } + | TOK_DCS_CA_REXMIT_INT TOK_INTEGER + { + int rc; + + /* + * Configure the CA retransmit interval + */ + rc = set_dcs_ca_rexmit($2); + if (rc) + return(rc); + } + | TOK_DCS_CSUS_REXMIT_INT TOK_INTEGER + { + int rc; + + /* + * Configure the CSUS retransmit interval + */ + rc = set_dcs_csus_rexmit($2); + if (rc) + return(rc); + } + | TOK_DCS_CSU_REXMIT_INT TOK_INTEGER + { + int rc; + + /* + * Configure the CSU retransmit interval + */ + rc = set_dcs_csu_rexmit($2); + if (rc) + return(rc); + } + | TOK_DCS_CSU_REXMIT_MAX TOK_INTEGER + { + int rc; + + /* + * Configure the CSU retransmit limit + */ + rc = set_dcs_csu_rexmit_max($2); + if (rc) + return(rc); + } + | TOK_DCS_HELLO_DF TOK_INTEGER + { + int rc; + + /* + * Configure the Hello dead factor + */ + rc = set_dcs_hello_df($2); + if (rc) + return(rc); + } + | TOK_DCS_HELLO_INT TOK_INTEGER + { + int rc; + + /* + * Configure the Hello interval + */ + rc = set_dcs_hello_int($2); + if (rc) + return(rc); + } + | TOK_DCS_HOP_CNT TOK_INTEGER + { + int rc; + + /* + * Configure the hop count + */ + rc = set_dcs_hops($2); + if (rc) + return(rc); + } + | TOK_DCS_ID TOK_NAME + { + int rc; + + /* + * Configure the DCS ID + */ + rc = set_dcs_id($2); + UM_FREE($2); + if (rc) + return(rc); + } + ; + + +/* + * Logging option statements + */ +log_stmt: TOK_LOG + '{' log_spec '}' + ; + +log_spec: /* Nothing */ + | TOK_LFN TOK_NAME ';' + { + /* + * Configure the log file name + */ + int rc; + + rc = set_log_file($2); + UM_FREE($2); + if (rc) + return(rc); + } + ; + | TOK_SYSLOG ';' + { + /* + * Configure logging to syslog + */ + scsp_log_syslog = 1; + } + ; + +%% + +void +#if __STDC__ +parse_error(const char *fmt, ...) +#else +parse_error(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; + char buff[256]; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + vsprintf(buff, fmt, ap); + scsp_log(LOG_ERR, "%s: Config file error at line %d: %s\n", + prog, parse_line, buff); +#ifdef NOTDEF + fprintf(stderr, "%s: Config file error at line %d: %s\n", + prog, parse_line, buff); +#endif + va_end(ap); +} + + +yyerror(s) + char *s; +{ + parse_error(s); +} diff --git a/usr.sbin/atm/scspd/scsp_hfsm.c b/usr.sbin/atm/scspd/scsp_hfsm.c new file mode 100644 index 0000000..2953804 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_hfsm.c @@ -0,0 +1,580 @@ +/* + * + * =================================== + * 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_hfsm.c,v 1.4 1998/07/16 15:59:25 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * HELLO finite state machine + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_hfsm.c,v 1.4 1998/07/16 15:59:25 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.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" + + +/* + * HELLO FSM actions + */ +#define HELLO_ACTION_CNT 7 +int scsp_hello_act_00 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_01 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_02 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_03 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_04 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_05 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_06 __P((Scsp_dcs *, Scsp_msg *)); + +static int (*scsp_action_vector[HELLO_ACTION_CNT])() = { + scsp_hello_act_00, + scsp_hello_act_01, + scsp_hello_act_02, + scsp_hello_act_03, + scsp_hello_act_04, + scsp_hello_act_05, + scsp_hello_act_06 +}; + +/* + * HELLO FSM state table + */ +static int hello_state_table[SCSP_HFSM_EVENT_CNT][SCSP_HFSM_STATE_CNT] = { + /* 0 1 2 3 */ + { 1, 1, 1, 1 }, /* 0 */ + { 0, 2, 2, 2 }, /* 1 */ + { 0, 3, 3, 3 }, /* 2 */ + { 0, 0, 4, 4 }, /* 3 */ + { 0, 5, 5, 6 }, /* 4 */ +}; + +/* + * HELLO finite state machine + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * event the event which has occurred + * msg pointer to received message, if there is one + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hfsm(dcsp, event, msg) + Scsp_dcs *dcsp; + int event; + Scsp_msg *msg; +{ + int action, rc, state; + + /* + * Select an action from the state table + */ + state = dcsp->sd_hello_state; + action = hello_state_table[event][state]; + if (scsp_trace_mode & SCSP_TRACE_HFSM) { + scsp_trace("HFSM: state=%d, event=%d, action=%d\n", + state, event, action); + } + if (action >= HELLO_ACTION_CNT || action <= 0) { + scsp_log(LOG_ERR, "Hello FSM--invalid action %d; state=%d, event=%d", + action, dcsp->sd_hello_state, event); + abort(); + } + + /* + * Perform the selected action + */ + rc = scsp_action_vector[action](dcsp, msg); + + return(rc); +} + + +/* + * HELLO finite state machine action 0 + * Unexpected action -- log an error message + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * EOPNOTSUPP always returns EOPNOTSUPP + * + */ +int +scsp_hello_act_00(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + scsp_log(LOG_ERR, "Hello FSM error--unexpected action, state=%d", + dcsp->sd_hello_state); + return(EOPNOTSUPP); +} + + +/* + * HELLO finite state machine action 1 + * VCC open -- send HELLO message, start hello timer, go to Waiting + * state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_01(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc; + + /* + * Cancel the VCC open timer if it's running + */ + HARP_CANCEL(&dcsp->sd_open_t); + + /* + * Go to Waiting state + */ + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + + /* + * Send a Hello message + */ + rc = scsp_send_hello(dcsp); + if (rc == 0) { + /* + * Success--start the Hello timer + */ + HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval, + scsp_hello_timeout); + } + + return(rc); +} + + +/* + * HELLO finite state machine action 2 + * VCC closed -- notify CA FSM, go to Down state, try to re-open VCC + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_02(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc; + struct in_addr addr; + + /* + * Cancel any current timers + */ + HARP_CANCEL(&dcsp->sd_hello_h_t); + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + + /* + * Log the loss of the VCC + */ + if (dcsp->sd_hello_state > SCSP_HFSM_WAITING) { + scsp_log(LOG_ERR, "VC to %s closed", + format_atm_addr(&dcsp->sd_addr)); + } + + /* + * Tell the CA FSM that the conection to the DCS is lost + */ + rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0); + + /* + * Go to Down state + */ + dcsp->sd_hello_state = SCSP_HFSM_DOWN; + + /* + * If our ID is lower than the DCS's, wait a second before + * trying to connect. This should keep both of us from + * trying to connect at the same time, resulting in two + * VCCs being open. + */ + if (scsp_cmp_id(&dcsp->sd_server->ss_lsid, + &dcsp->sd_dcsid) < 0) { + /* + * Our ID is lower--start the VCC open timer for one + * second so we'll try to open the VCC if the DCS + * doesn't do it by then + */ + HARP_TIMER(&dcsp->sd_open_t, 1, scsp_open_timeout); + } else { + /* + * Our ID is higher--try to reopen the VCC immediately + */ + if (scsp_dcs_connect(dcsp)) { + /* + * Conncect failed -- set a timer and try + * again later + */ + HARP_TIMER(&dcsp->sd_open_t, SCSP_Open_Interval, + scsp_open_timeout); + } + } + + return(0); +} + + +/* + * HELLO finite state machine action 3 + * Hello timer expired -- send HELLO message, restart hello timer + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_03(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc; + + /* + * Send a Hello message + */ + rc = scsp_send_hello(dcsp); + if (rc == 0) { + /* + * Success--restart the Hello timer + */ + HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval, + scsp_hello_timeout); + } + + return(rc); +} + + +/* + * HELLO finite state machine action 4 + * Receive timer expired -- if we haven't received any Hellos, notify + * CA FSM and go to Waiting state; if we've received Hellos, but we + * weren't in the receiver ID list, go to Unidirectional state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_04(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc = 0; + + /* + * Check whether we'ver received any Hellos lately + */ + if (dcsp->sd_hello_rcvd) { + /* + * We've had Hellos since the receive timer was + * started--go to Unidirectional state + */ + dcsp->sd_hello_rcvd = 0; + dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR; + } else { + /* + * We haven't seen any Hellos at all from the DCS in + * hello_interval * dead_factor seconds--go to Waiting + * state + */ + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + } + + /* + * Notify the CA FSM + */ + rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0); + + return(rc); +} + + +/* + * HELLO finite state machine action 5 + * Message received -- Ignore all but HELLO messages; if local server + * is in receiver list, notify CA FSM and go to Bidirectional state; + * otherwise, go to Unidirectional state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_05(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc; + Scsp_id *ridp; + + /* + * Null message pointer means message decode failed, so + * message must have been invalid. Go to Waiting state. + */ + if (msg == (Scsp_msg *)0) { + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + return(0); + } + + /* + * Ignore the message if it isn't a Hello + */ + if (msg->sc_msg_type != SCSP_HELLO_MSG) { + return(0); + } + + /* + * Save relevant information about DCS, but don't let him give + * us zero for timeout values + */ + if (msg->sc_hello->hello_int) { + dcsp->sd_hello_int = msg->sc_hello->hello_int; + } else { + dcsp->sd_hello_int = 1; + } + if (msg->sc_hello->dead_factor) { + dcsp->sd_hello_df = msg->sc_hello->dead_factor; + } else { + dcsp->sd_hello_df = 1; + } + dcsp->sd_dcsid = msg->sc_hello->hello_mcp.sid; + + /* + * Check the message for the local server's ID + */ + for (ridp = &msg->sc_hello->hello_mcp.rid; + ridp; + ridp = ridp->next) { + if (scsp_cmp_id(&dcsp->sd_server->ss_lsid, ridp) == 0) { + /* + * Cancel and restart the receive timer + */ + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + HARP_TIMER(&dcsp->sd_hello_rcv_t, + dcsp->sd_hello_int * dcsp->sd_hello_df, + scsp_hello_rcv_timeout); + + /* + * Go to Bidirectional state and notify the + * CA FSM that the connection is up + */ + dcsp->sd_hello_state = SCSP_HFSM_BI_DIR; + rc = scsp_cafsm(dcsp, + SCSP_CAFSM_HELLO_UP, + (void *)0); + return(rc); + } + } + + /* + * We weren't in the receiver ID list, so go to + * Unidirectional state + */ + dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR; + + return(0); +} + + +/* + * HELLO finite state machine action 6 + * Message received -- if message is not a HELLO, pass it to the CA + * FSM; otherwise, if local server is not in receiver list, notify + * CA FSM and go to Unidirectional state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_06(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc, rcv_found; + Scsp_id *ridp; + + /* + * Null message pointer means message decode failed, so + * message must have been invalid. Go to Waiting state. + */ + if (msg == (Scsp_msg *)0) { + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0); + return(rc); + } + + /* + * Process the message depending on its type + */ + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CA_MSG, (void *)msg); + break; + case SCSP_CSU_REQ_MSG: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REQ, (void *)msg); + break; + case SCSP_CSU_REPLY_MSG: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REPLY, + (void *)msg); + break; + case SCSP_CSUS_MSG: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSUS_MSG, (void *)msg); + break; + case SCSP_HELLO_MSG: + /* + * Make sure DCS info is consistent. The sender ID, + * family ID, protocol ID, and server group ID are + * checked. + */ + if (scsp_cmp_id(&msg->sc_hello->hello_mcp.sid, + &dcsp->sd_dcsid) || + (msg->sc_hello->family_id != + dcsp->sd_server->ss_fid) || + (msg->sc_hello->hello_mcp.pid != + dcsp->sd_server->ss_pid) || + (msg->sc_hello->hello_mcp.sgid != + dcsp->sd_server->ss_sgid)) { + /* + * Bad info--revert to waiting state + */ + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + rc = scsp_cafsm(dcsp, + SCSP_CAFSM_HELLO_DOWN, + (void *)0); + return(rc); + } + + /* + * Mark the arrival of the Hello message + */ + dcsp->sd_hello_rcvd = 1; + + /* + * Check the message for the local server's ID + */ + rc = 0; + for (ridp = &msg->sc_hello->hello_mcp.rid, + rcv_found = 0; + ridp; + ridp = ridp->next) { + rcv_found = (scsp_cmp_id(ridp, + &dcsp->sd_server->ss_lsid) == 0); + } + + if (rcv_found) { + /* + * The LS ID was in the list of receiver IDs-- + * Reset the Hello receive timer + */ + dcsp->sd_hello_rcvd = 0; + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + HARP_TIMER(&dcsp->sd_hello_rcv_t, + dcsp->sd_hello_int * + dcsp->sd_hello_df, + scsp_hello_rcv_timeout); + } + break; + } + + return(rc); +} diff --git a/usr.sbin/atm/scspd/scsp_if.c b/usr.sbin/atm/scspd/scsp_if.c new file mode 100644 index 0000000..1930990 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_if.c @@ -0,0 +1,655 @@ +/* + * + * =================================== + * 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_if.c,v 1.5 1998/08/13 20:11:14 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Interface to client server protocol + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_if.c,v 1.5 1998/08/13 20:11:14 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" + + +/* + * SCSP client server interface FSM actions + */ +#define SCSP_CIFSM_ACTION_CNT 11 +int scsp_client_act_00 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_01 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_02 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_03 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_04 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_05 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_06 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_07 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_08 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_09 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_10 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); + +static int (*scsp_action_vector[SCSP_CIFSM_ACTION_CNT])() = { + scsp_client_act_00, + scsp_client_act_01, + scsp_client_act_02, + scsp_client_act_03, + scsp_client_act_04, + scsp_client_act_05, + scsp_client_act_06, + scsp_client_act_07, + scsp_client_act_08, + scsp_client_act_09, + scsp_client_act_10 +}; + + +/* + * Client server interface FSM state table + */ +static int client_state_table[SCSP_CIFSM_EVENT_CNT][SCSP_CIFSM_STATE_CNT] = { + /* 0 1 2 3 */ + { 1, 3, 3, 3 }, /* 0 */ + { 2, 5, 5, 5 }, /* 1 */ + { 0, 4, 0, 0 }, /* 2 */ + { 0, 6, 6, 1 }, /* 3 */ + { 1, 0, 7, 7 }, /* 4 */ + { 7, 7, 7, 7 }, /* 5 */ + { 1, 1, 8, 8 }, /* 6 */ + { 0, 0, 10, 10 }, /* 7 */ + { 0, 0, 1, 1 }, /* 8 */ + { 0, 0, 9, 9 } /* 9 */ +}; + + +/* + * SCSP client server interface finite state machine + * + * Arguments: + * ssp pointer to server control block + * event the event which has occurred + * msg pointer to message from DCS, if there is one + * cmsg pointer to message from server, if there is one + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_cfsm(dcsp, event, msg, cmsg) + Scsp_dcs *dcsp; + int event; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int action, rc, state; + + /* + * Select an action from the state table + */ + state = dcsp->sd_client_state; + action = client_state_table[event][state]; + if (scsp_trace_mode & SCSP_TRACE_CFSM) { + scsp_trace("Server I/F FSM: state=%d, event=%d, action=%d\n", + state, event, action); + } + if (action >= SCSP_CIFSM_ACTION_CNT || action <= 0) { + scsp_log(LOG_ERR, "Server I/F FSM--invalid action %d; state=%d, event=%d", + action, dcsp->sd_client_state, event); + exit(1); + } + + /* + * Perform the selected action + */ + rc = scsp_action_vector[action](dcsp, msg, cmsg); + + return(rc); +} + + +/* + * SCSP client server interface finite state machine action 0 + * Unexpected action -- log an error message + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS (ignored) + * cmsg pointer to message from server (ignored) + * + * Returns: + * EOPNOTSUPP always returns EOPNOTSUPP + * + */ +int +scsp_client_act_00(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + scsp_log(LOG_ERR, "Server I/F FSM error--unexpected action, state=%d", + dcsp->sd_client_state); + return(EOPNOTSUPP); +} + + +/* + * SCSP client server interface finite state machine action 1 + * + * Ignore an event + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 always returns 0 + * + */ +int +scsp_client_act_01(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + return(0); +} + + +/* + * SCSP client server interface finite state machine action 2 + * + * CA FSM went to Cache Summarize state--go to Summarize + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_02(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_SUM; + + return(0); +} + + +/* + * SCSP client server interface finite state machine action 3 + * + * CA FSM went down--clean up and go to Null + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_03(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_NULL; + + return(0); +} + + +/* + * SCSP client server interface finite state machine action 4 + * + * CA FSM went to Update Cache state--go to Update state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_04(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_UPD; + + return(0); +} + + +/* + * SCSP client server interface finite state machine action 5 + * + * The CA FSM went to Cache Summarize state from Summarize, + * Update, or Aligned, implying that the CA FSM went down and came + * back up--copy the server's cache to the DCSs CSAS list and go to + * Summarize state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_05(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int i, rc; + Scsp_cse *csep, *ncsep; + + /* + * Copy the cache summmary to the CSAS list + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (csep = dcsp->sd_server->ss_cache[i]; csep; + csep = csep->sc_next) { + ncsep = scsp_dup_cse(csep); + LINK2TAIL(ncsep, Scsp_cse, dcsp->sd_ca_csas, + sc_next); + } + } + + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_SUM; + + return(0); + +act_05_fail: + for (csep = dcsp->sd_ca_csas; csep; csep = ncsep) { + ncsep = csep->sc_next; + UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next); + UM_FREE(csep); + } + + dcsp->sd_client_state = SCSP_CIFSM_NULL; + + return(rc); +} + + +/* + * SCSP client server interface finite state machine action 6 + * + * CA FSM went to Aligned state--go to Aligned + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_06(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_ALIGN; + + return(0); +} + + +/* + * SCSP client server interface finite state machine action 7 + * + * We received a Solicit Rsp or Update Req from the server--pass it + * to the CA FSM + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_07(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int rc; + Scsp_csa *csap; + Scsp_atmarp_csa *acp; + + /* + * Allocate memory for a CSA record + */ + csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!csap) { + scsp_mem_err("scsp_client_act_07: sizeof(Scsp_csa)"); + } + acp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa)); + if (!acp) { + scsp_mem_err("scsp_client_act_07: sizeof(Scsp_atmarp_csa)"); + } + UM_ZERO(csap, sizeof(Scsp_csa)); + UM_ZERO(acp, sizeof(Scsp_atmarp_csa)); + + /* + * Build a CSA record from the server's message + */ + csap->hops = dcsp->sd_hops; + csap->null = (cmsg->si_atmarp.sa_state == SCSP_ASTATE_DEL) || + (cmsg->si_type == SCSP_SOLICIT_RSP && + cmsg->si_rc != SCSP_RSP_OK); + csap->seq = cmsg->si_atmarp.sa_seq; + csap->key = cmsg->si_atmarp.sa_key; + csap->oid = cmsg->si_atmarp.sa_oid; + csap->atmarp_data = acp; + acp->sa_state = cmsg->si_atmarp.sa_state; + acp->sa_sha = cmsg->si_atmarp.sa_cha; + acp->sa_ssa = cmsg->si_atmarp.sa_csa; + acp->sa_spa = cmsg->si_atmarp.sa_cpa; + acp->sa_tpa = cmsg->si_atmarp.sa_cpa; + + /* + * Call the CA FSM + */ + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CACHE_UPD, (void *)csap); + + return(rc); +} + + +/* + * SCSP client server interface finite state machine action 8 + * + * Update Rsp from server--pass the update to the CA FSM. + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_08(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int rc; + + /* + * Pass the response to the CA FSM + */ + switch (dcsp->sd_server->ss_pid) { + case SCSP_PROTO_ATMARP: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CACHE_RSP, cmsg); + break; + default: + rc = EPROTONOSUPPORT; + } + + return(rc); +} + + +/* + * SCSP client server interface finite state machine action 9 + * + * CSU Solicit from DCS--pass Solicit Ind to server + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_09(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int rc, rrc = 0; + Scsp_csa *csap; + Scsp_if_msg *csip; + + /* + * Get memory for a Solicit Ind + */ + csip = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!csip) { + scsp_mem_err("scsp_client_act_09: sizeof(Scsp_if_msg)"); + } + + /* + * Loop through list of CSAs + */ + for (csap = msg->sc_csu_msg->csu_csa_rec; csap; + csap = csap->next) { + /* + * Fill out the Solicit Indication + */ + UM_ZERO(csip, sizeof(Scsp_if_msg)); + csip->si_type = SCSP_SOLICIT_IND; + csip->si_proto = dcsp->sd_server->ss_pid; + csip->si_tok = (u_long)dcsp; + csip->si_len = sizeof(Scsp_if_msg_hdr) + + sizeof(Scsp_sum_msg); + csip->si_sum.ss_hops = csap->hops; + csip->si_sum.ss_null = csap->null; + csip->si_sum.ss_seq = csap->seq; + csip->si_sum.ss_key = csap->key; + csip->si_sum.ss_oid = csap->oid; + + /* + * Send the Solicit Ind to the server + */ + rc = scsp_if_sock_write(dcsp->sd_server->ss_sock, csip); + if (rc) { + rrc = rc; + } + } + + UM_FREE(csip); + return(rrc); +} + + +/* + * SCSP client server interface finite state machine action 10 + * + * CSU Request from DCS--pass it to the server as a Cache Update + * Indication + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_10(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int rc, rrc = 0; + Scsp_csa *csap; + Scsp_atmarp_csa *acp; + Scsp_if_msg *cuip; + + /* + * Get memory for a Cache Update Ind + */ + cuip = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!cuip) { + scsp_mem_err("scsp_client_act_10: sizeof(Scsp_if_msg)"); + } + + /* + * Loop through CSAs in message + */ + for (csap = msg->sc_csu_msg->csu_csa_rec; csap; + csap = csap->next) { + acp = csap->atmarp_data; + if (!acp) + continue; + + /* + * Fill out the Cache Update Ind + */ + UM_ZERO(cuip, sizeof(Scsp_if_msg)); + cuip->si_type = SCSP_UPDATE_IND; + cuip->si_proto = dcsp->sd_server->ss_pid; + cuip->si_tok = (u_long)dcsp; + switch(dcsp->sd_server->ss_pid) { + case SCSP_PROTO_ATMARP: + cuip->si_len = sizeof(Scsp_if_msg_hdr) + + sizeof(Scsp_atmarp_msg); + cuip->si_atmarp.sa_state = acp->sa_state; + cuip->si_atmarp.sa_cpa = acp->sa_spa; + cuip->si_atmarp.sa_cha = acp->sa_sha; + cuip->si_atmarp.sa_csa = acp->sa_ssa; + cuip->si_atmarp.sa_key = csap->key; + cuip->si_atmarp.sa_oid = csap->oid; + cuip->si_atmarp.sa_seq = csap->seq; + break; + case SCSP_PROTO_NHRP: + /* + * Not implemented yet + */ + break; + } + + /* + * Send the Cache Update Ind to the server + */ + rc = scsp_if_sock_write(dcsp->sd_server->ss_sock, cuip); + if (rc) { + rrc = rc; + } + } + + UM_FREE(cuip); + return(rrc); +} diff --git a/usr.sbin/atm/scspd/scsp_if.h b/usr.sbin/atm/scspd/scsp_if.h new file mode 100644 index 0000000..dde3407 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_if.h @@ -0,0 +1,194 @@ +/* + * + * =================================== + * 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_if.h,v 1.2 1998/07/16 15:59:33 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Interface to server clients of SCSP + * + */ + +#ifndef _SCSP_SCSP_IF_H +#define _SCSP_SCSP_IF_H + + +/* + * SCSP configuration message + */ +struct scsp_cfg_msg { + char atmarp_netif[IFNAMSIZ]; +}; +typedef struct scsp_cfg_msg Scsp_cfg_msg; + + +/* + * SCSP cache summary + */ +struct scsp_sum_msg { + u_short ss_hops; /* Hop count */ + u_char ss_null; /* Null flag */ + long ss_seq; /* CSA seq. no. */ + Scsp_ckey ss_key; /* Cache key */ + Scsp_id ss_oid; /* Originator ID */ +}; +typedef struct scsp_sum_msg Scsp_sum_msg; + + +/* + * SCSP constants for ATMARP + */ +#define SCSP_ATMARP_PROTO 1 +#define SCSP_ATMARP_SIDL 4 +#define SCSP_ATMARP_RIDL 4 +#define SCSP_ATMARP_CKL 4 +#define SCSP_ATMARP_OIDL 4 + + +/* + * SCSP ATMARP message + */ +struct scsp_atmarp_msg { + u_char sa_state; /* Cache entry state (below) */ + struct in_addr sa_cpa; /* Cached protocol address */ + Atm_addr sa_cha; /* Cached ATM address */ + Atm_addr sa_csa; /* Cached ATM subaddress */ + Scsp_ckey sa_key; /* Cache key for entry */ + Scsp_id sa_oid; /* Originator ID */ + long sa_seq; /* Sequence no. */ +}; +typedef struct scsp_atmarp_msg Scsp_atmarp_msg; + +#define SCSP_ASTATE_NEW 0 /* ATMARP new server registration */ +#define SCSP_ASTATE_UPD 1 /* ATMARP server refreshed */ +#define SCSP_ASTATE_DEL 2 /* ATMARP server data deleted */ + + +/* + * SCSP constants for NHRP + */ +#define SCSP_NHRP_PROTO 2 +#define SCSP_NHRP_SIDL 4 +#define SCSP_NHRP_RIDL 4 +#define SCSP_NHRP_CKL 4 +#define SCSP_NHRP_OIDL 4 + + +/* + * SCSP NHRP message + */ +struct scsp_nhrp_msg { + u_short sn_af; /* Address family */ + u_short sn_proto; /* NHRP protocol type */ + u_char sn_snap[5]; /* SNAP */ + u_char sn_ver; /* NHRP version number */ + u_short sn_flags; /* Flags */ + u_long sn_rid; /* Request ID */ + u_char sn_state; /* State */ + u_char sn_prel; /* Prefix length */ + u_short sn_mtu; /* Maximum transmission unit */ + u_short sn_hold; /* Holding time */ + Atm_addr sn_addr; /* Server network address */ + Atm_addr sn_saddr; /* Server network subaddress */ + struct in_addr sn_paddr; /* Server protocol address */ + Scsp_ckey sn_key; /* Cache key for entry */ + Scsp_id sn_oid; /* Originator ID */ +}; +typedef struct scsp_nhrp_msg Scsp_nhrp_msg; + +#define SCSP_NSTATE_NEW 0 /* New NHRP server */ +#define SCSP_NSTATE_UPD 1 /* NHRP server re-registered */ +#define SCSP_NSTATE_DEL 2 /* NHRP server data purged */ +#define SCSP_NSTATE_NSD 3 /* NHRP no such data in server */ + + +/* + * SCSP/server message header + */ +struct scsp_if_msg_hdr { + u_char sh_type; /* Message type */ + u_char sh_rc; /* Response code */ + u_short sh_proto; /* SCSP protocol ID */ + int sh_len; /* Length of message */ + u_long sh_tok; /* Token from SCSP daemon */ +}; +typedef struct scsp_if_msg_hdr Scsp_if_msg_hdr; + + +/* + * SCSP-server message + */ +struct scsp_if_msg { + Scsp_if_msg_hdr si_hdr; /* Header fields */ + union { + Scsp_cfg_msg siu_cfg; /* Config data */ + Scsp_sum_msg siu_sum; /* Cache summary */ + Scsp_atmarp_msg siu_atmarp; /* ATMARP update */ + Scsp_nhrp_msg siu_nhrp; /* NHRP update */ + } si_u; +}; +typedef struct scsp_if_msg Scsp_if_msg; + +#define si_type si_hdr.sh_type +#define si_rc si_hdr.sh_rc +#define si_proto si_hdr.sh_proto +#define si_len si_hdr.sh_len +#define si_tok si_hdr.sh_tok + +#define si_cfg si_u.siu_cfg +#define si_sum si_u.siu_sum +#define si_atmarp si_u.siu_atmarp +#define si_nhrp si_u.siu_nhrp + + +/* + * Message types + */ +#define SCSP_NOP_REQ 1 +#define SCSP_CFG_REQ 2 +#define SCSP_CFG_RSP 3 +#define SCSP_CACHE_IND 4 +#define SCSP_CACHE_RSP 5 +#define SCSP_SOLICIT_IND 6 +#define SCSP_SOLICIT_RSP 7 +#define SCSP_UPDATE_IND 8 +#define SCSP_UPDATE_REQ 9 +#define SCSP_UPDATE_RSP 10 + + +/* + * Response codes + */ +#define SCSP_RSP_OK 0 +#define SCSP_RSP_ERR 1 +#define SCSP_RSP_REJ 2 +#define SCSP_RSP_NOT_FOUND 3 + + +#endif /* _SCSP_SCSP_IF_H */ diff --git a/usr.sbin/atm/scspd/scsp_input.c b/usr.sbin/atm/scspd/scsp_input.c new file mode 100644 index 0000000..21d0a07 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_input.c @@ -0,0 +1,1103 @@ +/* + * + * =================================== + * 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_input.c,v 1.3 1998/08/13 20:11:15 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Input packet processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_input.c,v 1.3 1998/08/13 20:11:15 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 <netinet/if_ether.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" + + +static int scsp_parse_atmarp __P((char *, int, Scsp_atmarp_csa **)); + + +/* + * Get a long ingeter + * + * This routine is provided to handle long integers that may not + * be word-aligned in the input buffer. + * + * Arguments: + * cp pointer to long int in message + * + * Returns: + * int long int in host order + * + */ +static u_long +get_long(cp) + u_char *cp; +{ + int i; + u_long l; + + /* + * Read the long out of the input buffer + */ + l = 0; + for (i = 0; i < sizeof(u_long); i++) + l = (l << 8) + *cp++; + + /* + * Return the value in host order + */ + return(l); +} + + +/* + * Free an SCSP Cache Alignment message in internal format + * + * Arguments: + * cap pointer to CA message + * + * Returns: + * None + * + */ +static void +scsp_free_ca(cap) + Scsp_ca *cap; +{ + Scsp_csa *csap, *ncsap; + + /* + * Return if there's nothing to free + */ + if (cap == (Scsp_ca *)0) + return; + + /* + * Free the CSAS records + */ + for (csap = cap->ca_csa_rec; csap; csap = ncsap) { + ncsap = csap->next; + SCSP_FREE_CSA(csap); + } + /* + * Free the CA message structure + */ + UM_FREE(cap); +} + + +/* + * Free an SCSP Cache State Update Request, Cache State Update Reply, + * or Cache State Update Solicit message in internal format + * + * Arguments: + * csup pointer to CSU message + * + * Returns: + * None + * + */ +static void +scsp_free_csu(csup) + Scsp_csu_msg *csup; +{ + Scsp_csa *csap, *ncsap; + + /* + * Return if there's nothing to free + */ + if (csup == (Scsp_csu_msg *)0) + return; + + /* + * Free the CSA records + */ + for (csap = csup->csu_csa_rec; csap; csap = ncsap) { + ncsap = csap->next; + SCSP_FREE_CSA(csap); + } + + /* + * Free the CSU message structure + */ + UM_FREE(csup); +} + + +/* + * Free an SCSP Hello message in internal format + * + * Arguments: + * hp pointer to Hello message + * + * Returns: + * None + * + */ +static void +scsp_free_hello(hp) + Scsp_hello *hp; +{ + /* + * Return if there's nothing to free + */ + if (hp == (Scsp_hello *)0) + return; + + /* + * Free the Hello message structure + */ + UM_FREE(hp); +} + + +/* + * Free an SCSP message in internal format + * + * Arguments: + * msg pointer to input packet + * + * Returns: + * None + * + */ +void +scsp_free_msg(msg) + Scsp_msg *msg; +{ + Scsp_ext *exp, *nexp; + + /* + * Return if there's nothing to free + */ + if (msg == (Scsp_msg *)0) + return; + + /* + * Free the message body + */ + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + scsp_free_ca(msg->sc_ca); + break; + case SCSP_CSU_REQ_MSG: + case SCSP_CSU_REPLY_MSG: + case SCSP_CSUS_MSG: + scsp_free_csu(msg->sc_csu_msg); + break; + case SCSP_HELLO_MSG: + scsp_free_hello(msg->sc_hello); + break; + } + + /* + * Free any extensions + */ + for (exp = msg->sc_ext; exp; exp = nexp) { + nexp = exp->next; + UM_FREE(exp); + } + + /* + * Free the message structure + */ + UM_FREE(msg); +} + + +/* + * Parse a Sender or Receiver ID + * + * Arguments: + * buff pointer to ID + * id_len length of ID + * idp pointer to structure to receive the ID + * + * Returns: + * 0 input was invalid + * else length of ID processed + * + */ +static int +scsp_parse_id(buff, id_len, idp) + char *buff; + int id_len; + Scsp_id *idp; +{ + /* + * Sanity check + */ + if (!buff || + id_len == 0 || id_len > SCSP_MAX_ID_LEN || + !idp) { + return(0); + } + + /* + * Save the ID length + */ + idp->id_len = id_len; + + /* + * Get the ID + */ + UM_COPY(buff, idp->id, id_len); + + /* + * Return the ID length + */ + return(id_len); +} + + +/* + * Parse the Mandatory Common Part of an SCSP input packet + * + * Arguments: + * buff pointer to mandatory common part + * pdu_len length of input packet + * mcp pointer to location of MCP in decoded record + * + * Returns: + * 0 input was invalid + * else length of MCP in message + * + */ +static int +scsp_parse_mcp(buff, pdu_len, mcp) + char *buff; + int pdu_len; + Scsp_mcp *mcp; +{ + int len; + u_char *idp, *odp; + struct scsp_nmcp *smp; + + /* + * Get the protocol ID + */ + smp = (struct scsp_nmcp *)buff; + mcp->pid = ntohs(smp->sm_pid); + if (mcp->pid < SCSP_PROTO_ATMARP || + mcp->pid > SCSP_PROTO_LNNI) { + /* Protocol ID is invalid */ + goto mcp_invalid; + } + + /* + * Get the server group ID + */ + mcp->sgid = ntohs(smp->sm_sgid); + + /* + * Get the flags + */ + mcp->flags = ntohs(smp->sm_flags); + + /* + * Get the sender ID and length + */ + idp = (u_char *) ((caddr_t)smp + sizeof(struct scsp_nmcp)); + len = scsp_parse_id(idp, smp->sm_sid_len, &mcp->sid); + if (len == 0) { + goto mcp_invalid; + } + + /* + * Get the receiver ID and length + */ + idp += len; + len = scsp_parse_id(idp, smp->sm_rid_len, &mcp->rid); + if (len == 0) { + goto mcp_invalid; + } + + /* + * Get the record count + */ + mcp->rec_cnt = ntohs(smp->sm_rec_cnt); + + /* + * Return the length of data we processed + */ + return(sizeof(struct scsp_nmcp) + smp->sm_sid_len + + smp->sm_rid_len); + +mcp_invalid: + return(0); +} + + +/* + * Parse an Extension + * + * Arguments: + * buff pointer to Extension + * pdu_len length of buffer + * expp pointer to location to receive pointer to the Extension + * + * Returns: + * 0 input was invalid + * else length of Extension processed + * + */ +static int +scsp_parse_ext(buff, pdu_len, expp) + char *buff; + int pdu_len; + Scsp_ext **expp; +{ + int len; + struct scsp_next *sep; + Scsp_ext *exp; + + /* + * Get memory for the extension + */ + sep = (struct scsp_next *)buff; + len = sizeof(Scsp_ext) + ntohs(sep->se_len); + exp = (Scsp_ext *)UM_ALLOC(len); + if (!exp) { + goto ext_invalid; + } + UM_ZERO(exp, len); + + /* + * Get the type + */ + exp->type = ntohs(sep->se_type); + + /* + * Get the length + */ + exp->len = ntohs(sep->se_len); + + /* + * Get the value + */ + if (exp->len > 0) { + UM_COPY((caddr_t)sep + sizeof(struct scsp_next), + (caddr_t)exp + sizeof(Scsp_ext), + exp->len); + } + + /* + * Save a pointer to the extension and return the + * number of bytes processed + */ + *expp = exp; + return(sizeof(struct scsp_next) + exp->len); + +ext_invalid: + if (exp) { + UM_FREE(exp); + } + return(0); +} + + +/* + * Parse a Cache State Advertisement or Cache State Advertisement + * Summary record + * + * Arguments: + * buff pointer to CSA or CSAS record + * pdu_len length of input packet + * csapp pointer to location to put pointer to CSA or CSAS + * + * Returns: + * 0 input was invalid + * else length of record processed + * + */ +static int +scsp_parse_csa(buff, pdu_len, csapp) + char *buff; + int pdu_len; + Scsp_csa **csapp; +{ + int len; + char *idp, *odp; + struct scsp_ncsa *scp; + Scsp_csa *csap; + + /* + * Check the record length + */ + scp = (struct scsp_ncsa *)buff; + if (ntohs(scp->scs_len) < (sizeof(struct scsp_ncsa) + + scp->scs_ck_len + scp->scs_oid_len)) { + goto csa_invalid; + } + + /* + * Get memory for the returned structure + */ + len = sizeof(Scsp_csa) + ntohs(scp->scs_len) - + sizeof(struct scsp_ncsa) - scp->scs_ck_len - + scp->scs_oid_len; + csap = (Scsp_csa *)UM_ALLOC(len); + if (!csap) { + goto csa_invalid; + } + UM_ZERO(csap, len); + + /* + * Get the hop count + */ + csap->hops = ntohs(scp->scs_hop_cnt); + + /* + * Set the null flag + */ + csap->null = (ntohs(scp->scs_nfill) & SCSP_CSAS_NULL) != 0; + + /* + * Get the sequence number + */ + csap->seq = get_long((u_char *)&scp->scs_seq); + + /* + * Get the cache key + */ + if (scp->scs_ck_len == 0 || + scp->scs_ck_len > SCSP_MAX_KEY_LEN) { + goto csa_invalid; + } + csap->key.key_len = scp->scs_ck_len; + idp = (char *) ((caddr_t)scp + sizeof(struct scsp_ncsa)); + UM_COPY(idp, csap->key.key, scp->scs_ck_len); + + /* + * Get the originator ID + */ + idp += scp->scs_ck_len; + len = scsp_parse_id(idp, scp->scs_oid_len, &csap->oid); + if (len == 0) { + goto csa_invalid; + } + + /* + * Get the protocol-specific data, if present + */ + len = ntohs(scp->scs_len) - (sizeof(struct scsp_ncsa) + + scp->scs_ck_len + scp->scs_oid_len); + if (len > 0) { + idp += scp->scs_oid_len; + len = scsp_parse_atmarp(idp, len, &csap->atmarp_data); + if (len == 0) + goto csa_invalid; + } + + /* + * Set a pointer to the MCP and return the length + * of data we processed + */ + *csapp = csap; + return(ntohs(scp->scs_len)); + +csa_invalid: + if (csap) + SCSP_FREE_CSA(csap); + return(0); +} + + +/* + * Parse a Cache Alignment message + * + * Arguments: + * buff pointer to start of CA in message + * pdu_len length of input packet + * capp pointer to location to put pointer to CA message + * + * Returns: + * 0 input was invalid + * else length of CA message processed + * + */ +static int +scsp_parse_ca(buff, pdu_len, capp) + char *buff; + int pdu_len; + Scsp_ca **capp; +{ + int i, len, proc_len; + struct scsp_nca *scap; + Scsp_ca *cap; + Scsp_csa **csapp; + + /* + * Get memory for the returned structure + */ + scap = (struct scsp_nca *)buff; + cap = (Scsp_ca *)UM_ALLOC(sizeof(Scsp_ca)); + if (!cap) { + goto ca_invalid; + } + UM_ZERO(cap, sizeof(Scsp_ca)); + + /* + * Get the sequence number + */ + cap->ca_seq = get_long((u_char *)&scap->sca_seq); + proc_len = sizeof(scap->sca_seq); + buff += sizeof(scap->sca_seq); + + /* + * Process the mandatory common part of the message + */ + len = scsp_parse_mcp(buff, + pdu_len - proc_len, + &cap->ca_mcp); + if (len == 0) + goto ca_invalid; + buff += len; + proc_len += len; + + /* + * Set the flags + */ + cap->ca_m = (cap->ca_mcp.flags & SCSP_CA_M) != 0; + cap->ca_i = (cap->ca_mcp.flags & SCSP_CA_I) != 0; + cap->ca_o = (cap->ca_mcp.flags & SCSP_CA_O) != 0; + + /* + * Get the CSAS records from the message + */ + for (i = 0, csapp = &cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt; + i++, csapp = &(*csapp)->next) { + len = scsp_parse_csa(buff, pdu_len - proc_len, csapp); + buff += len; + proc_len += len; + } + + /* + * Set the address of the CA message and + * return the length of processed data + */ + *capp = cap; + return(proc_len); + +ca_invalid: + if (cap) + scsp_free_ca(cap); + return(0); +} + + +/* + * Parse the ATMARP-specific part of a CSA record + * + * Arguments: + * buff pointer to ATMARP part of CSU message + * pdu_len length of data to process + * acspp pointer to location to put pointer to CSU message + * + * Returns: + * 0 input was invalid + * else length of CSU Req message processed + * + */ +static int +scsp_parse_atmarp(buff, pdu_len, acspp) + char *buff; + int pdu_len; + Scsp_atmarp_csa **acspp; +{ + int i, len, proc_len; + struct scsp_atmarp_ncsa *sacp; + Scsp_atmarp_csa *acsp; + + /* + * Initial packet verification + */ + sacp = (struct scsp_atmarp_ncsa *)buff; + if ((sacp->sa_hrd != ntohs(ARP_ATMFORUM)) || + (sacp->sa_pro != ntohs(ETHERTYPE_IP))) + goto acs_invalid; + + /* + * Get memory for the returned structure + */ + acsp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa)); + if (!acsp) { + goto acs_invalid; + } + UM_ZERO(acsp, sizeof(Scsp_atmarp_csa)); + + /* + * Get state code + */ + acsp->sa_state = sacp->sa_state; + proc_len = sizeof(struct scsp_atmarp_ncsa); + + /* + * Verify/gather source ATM address + */ + acsp->sa_sha.address_format = T_ATM_ABSENT; + acsp->sa_sha.address_length = 0; + if (len = (sacp->sa_shtl & ARP_TL_LMASK)) { + if (sacp->sa_shtl & ARP_TL_E164) { + if (len > sizeof(Atm_addr_e164)) + goto acs_invalid; + acsp->sa_sha.address_format = T_ATM_E164_ADDR; + } else { + if (len != sizeof(Atm_addr_nsap)) + goto acs_invalid; + acsp->sa_sha.address_format = T_ATM_ENDSYS_ADDR; + } + acsp->sa_sha.address_length = len; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)acsp->sa_sha.address, + len); + proc_len += len; + } + + /* + * Verify/gather source ATM subaddress + */ + acsp->sa_ssa.address_format = T_ATM_ABSENT; + acsp->sa_ssa.address_length = 0; + if (len = (sacp->sa_sstl & ARP_TL_LMASK)) { + if (((sacp->sa_sstl & ARP_TL_TMASK) != ARP_TL_NSAPA) || + (len != sizeof(Atm_addr_nsap))) + goto acs_invalid; + acsp->sa_ssa.address_format = T_ATM_ENDSYS_ADDR; + acsp->sa_ssa.address_length = len; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)acsp->sa_ssa.address, + len); + proc_len += len; + } + + /* + * Verify/gather source IP address + */ + if (len = sacp->sa_spln) { + if (len != sizeof(struct in_addr)) + goto acs_invalid; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)&acsp->sa_spa, len); + proc_len += len; + } else { + acsp->sa_spa.s_addr = 0; + } + + /* + * Verify/gather target ATM address + */ + acsp->sa_tha.address_format = T_ATM_ABSENT; + acsp->sa_tha.address_length = 0; + if (len = (sacp->sa_thtl & ARP_TL_LMASK)) { + if (sacp->sa_thtl & ARP_TL_E164) { + if (len > sizeof(Atm_addr_e164)) + goto acs_invalid; + acsp->sa_tha.address_format = T_ATM_E164_ADDR; + } else { + if (len != sizeof(Atm_addr_nsap)) + goto acs_invalid; + acsp->sa_tha.address_format = T_ATM_ENDSYS_ADDR; + } + acsp->sa_tha.address_length = len; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)acsp->sa_tha.address, + len); + proc_len += len; + } + + /* + * Verify/gather target ATM subaddress + */ + acsp->sa_tsa.address_format = T_ATM_ABSENT; + acsp->sa_tsa.address_length = 0; + if (len = (sacp->sa_tstl & ARP_TL_LMASK)) { + if (((sacp->sa_tstl & ARP_TL_TMASK) != ARP_TL_NSAPA) || + (len != sizeof(Atm_addr_nsap))) + goto acs_invalid; + acsp->sa_tsa.address_format = T_ATM_ENDSYS_ADDR; + acsp->sa_tsa.address_length = len; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)acsp->sa_tsa.address, + len); + proc_len += len; + } + + /* + * Verify/gather target IP address + */ + if (len = sacp->sa_tpln) { + if (len != sizeof(struct in_addr)) + goto acs_invalid; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)&acsp->sa_tpa, len); + proc_len += len; + } else { + acsp->sa_tpa.s_addr = 0; + } + + /* + * Verify packet length + */ + if (proc_len != pdu_len) + goto acs_invalid; + + *acspp = acsp; + return(proc_len); + +acs_invalid: + if (acsp) + UM_FREE(acsp); + return(0); +} + + +/* + * Parse a Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message. These all have the same format, + * a Mandatory Common Part followed by a number of CSA or CSAS records. + * + * Arguments: + * buff pointer to start of CSU message + * pdu_len length of input packet + * csupp pointer to location to put pointer to CSU message + * + * Returns: + * 0 input was invalid + * else length of CSU Req message processed + * + */ +static int +scsp_parse_csu(buff, pdu_len, csupp) + char *buff; + int pdu_len; + Scsp_csu_msg **csupp; +{ + int i, len, proc_len; + Scsp_csu_msg *csup; + Scsp_csa **csapp; + + /* + * Get memory for the returned structure + */ + csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csup) { + goto csu_invalid; + } + UM_ZERO(csup, sizeof(Scsp_csu_msg)); + + /* + * Process the mandatory common part of the message + */ + len = scsp_parse_mcp(buff, pdu_len, &csup->csu_mcp); + if (len == 0) + goto csu_invalid; + buff += len; + proc_len = len; + + /* + * Get the CSAS records from the message + */ + for (i = 0, csapp = &csup->csu_csa_rec; + i < csup->csu_mcp.rec_cnt; + i++, csapp = &(*csapp)->next) { + len = scsp_parse_csa(buff, pdu_len - proc_len, csapp); + buff += len; + proc_len += len; + } + + /* + * Set the address of the CSU Req message and + * return the length of processed data + */ + *csupp = csup; + return(proc_len); + +csu_invalid: + if (csup) + scsp_free_csu(csup); + return(0); +} + + +/* + * Parse a Hello message + * + * Arguments: + * buff pointer to start of Hello in message + * pdu_len length of input packet + * hpp pointer to location to put pointer to Hello message + * + * Returns: + * 0 input was invalid + * else length of Hello message processed + * + */ +static int +scsp_parse_hello(buff, pdu_len, hpp) + char *buff; + int pdu_len; + Scsp_hello **hpp; +{ + int i, len, proc_len; + struct scsp_nhello *shp = (struct scsp_nhello *)buff; + Scsp_hello *hp; + Scsp_id *idp; + Scsp_id **ridpp; + + /* + * Get memory for the returned structure + */ + hp = (Scsp_hello *)UM_ALLOC(sizeof(Scsp_hello)); + if (!hp) { + goto hello_invalid; + } + UM_ZERO(hp, sizeof(Scsp_hello)); + + /* + * Get the hello interval + */ + hp->hello_int = ntohs(shp->sch_hi); + + /* + * Get the dead factor + */ + hp->dead_factor = ntohs(shp->sch_df); + + /* + * Get the family ID + */ + hp->family_id = ntohs(shp->sch_fid); + + /* + * Process the mandatory common part of the message + */ + proc_len = sizeof(struct scsp_nhello) - + sizeof(struct scsp_nmcp); + buff += proc_len; + len = scsp_parse_mcp(buff, pdu_len - proc_len, + &hp->hello_mcp); + if (len == 0) + goto hello_invalid; + buff += len; + proc_len += len; + + /* + * Get additional receiver ID records from the message + */ + for (i = 0, ridpp = &hp->hello_mcp.rid.next; + i < hp->hello_mcp.rec_cnt; + i++, ridpp = &idp->next) { + idp = (Scsp_id *)UM_ALLOC(sizeof(Scsp_id)); + if (!idp) { + goto hello_invalid; + } + UM_ZERO(idp, sizeof(Scsp_id)); + len = scsp_parse_id(buff, + hp->hello_mcp.rid.id_len, + idp); + if (len == 0) { + UM_FREE(idp); + goto hello_invalid; + } + buff += len; + proc_len += len; + *ridpp = idp; + } + + /* + * Set the address of the CA message and + * return the length of processed data + */ + *hpp = hp; + return(proc_len); + +hello_invalid: + if (hp) + scsp_free_hello(hp); + return(0); +} + + +/* + * Parse an SCSP input packet + * + * Arguments: + * buff pointer to input packet + * pdu_len length of input packet + * + * Returns: + * NULL input packet was invalid + * else pointer to packet in internal format + * + */ +Scsp_msg * +scsp_parse_msg(buff, pdu_len) + char *buff; + int pdu_len; +{ + int ext_off, len, plen; + struct scsp_nhdr *shp; + Scsp_msg *msg = (Scsp_msg *)0; + Scsp_ext **expp; + + /* + * Check the message checksum + */ + if (ip_checksum(buff, pdu_len) != 0) { + /* + * Checksum was bad--discard the message + */ + goto ignore; + } + + /* + * Allocate storage for the message + */ + msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!msg) { + goto ignore; + } + UM_ZERO(msg, sizeof(Scsp_msg)); + + /* + * Decode the fixed header + * + * Check the version + */ + shp = (struct scsp_nhdr *)buff; + if (shp->sh_ver != SCSP_VER_1) + goto ignore; + + /* + * Get the message type + */ + msg->sc_msg_type = shp->sh_type; + + /* + * Get and check the length + */ + len = ntohs(shp->sh_len); + if (len != pdu_len) + goto ignore; + + /* + * Get the extension offset + */ + ext_off = ntohs(shp->sh_ext_off); + + /* + * Decode the body of the message, depending on the type + */ + buff += sizeof(struct scsp_nhdr); + len -= sizeof(struct scsp_nhdr); + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + plen = scsp_parse_ca(buff, len, &msg->sc_ca); + break; + case SCSP_CSU_REQ_MSG: + case SCSP_CSU_REPLY_MSG: + case SCSP_CSUS_MSG: + plen = scsp_parse_csu(buff, len, &msg->sc_csu_msg); + break; + case SCSP_HELLO_MSG: + plen = scsp_parse_hello(buff, len, &msg->sc_hello); + break; + default: + goto ignore; + } + if (plen == 0) { + goto ignore; + } + buff += plen; + len -= plen; + + /* + * Decode any extensions + */ + if (ext_off != 0) { + for (expp = &msg->sc_ext; len > 0; + expp = &(*expp)->next) { + plen = scsp_parse_ext(buff, len, expp); + if (plen == 0) { + goto ignore; + } + buff += plen; + len -= plen; + } + } + + /* + * Make sure we handled the whole message + */ + if (len != 0) { + goto ignore; + } + + /* + * Return the address of the SCSP message in internal format + */ + return(msg); + +ignore: + if (msg) + scsp_free_msg(msg); + return(Scsp_msg *)0; +} diff --git a/usr.sbin/atm/scspd/scsp_log.c b/usr.sbin/atm/scspd/scsp_log.c new file mode 100644 index 0000000..9088078 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_log.c @@ -0,0 +1,265 @@ +/* + * + * =================================== + * 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_log.c,v 1.2 1998/07/12 20:49:36 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP logging routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_log.c,v 1.2 1998/07/12 20:49:36 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" + +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + + +/* + * Global variables + */ +FILE *scsp_trace_file = (FILE *)0; + + +/* + * Write a message to SCSP's log + * + * Arguments: + * level pointer to an SCSP cache key structure + * fmt printf-style format string + * ... parameters for printf-style use according to fmt + * + * Returns: + * none + * + */ +void +#if __STDC__ +scsp_log(const int level, const char *fmt, ...) +#else +scsp_log(level, fmt, va_alist) + int level; + char *fmt; + va_dcl +#endif +{ + va_list ap; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + /* + * In debug mode, just write to stdout + */ + if (scsp_debug_mode) { + vprintf(fmt, ap); + printf("\n"); + return; + } + + /* + * Write to syslog if it's active or if no log file is set up + */ + if (scsp_log_syslog || !scsp_log_file) { + vsyslog(level, fmt, ap); + } + + /* + * Write to the log file if there's one set up + */ + if (scsp_log_file) { + vfprintf(scsp_log_file, fmt, ap); + fprintf(scsp_log_file, "\n"); + } + + va_end(ap); +} + + +/* + * Open SCSP's trace file + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +scsp_open_trace() +{ + char fname[64]; + + /* + * Build a file name + */ + UM_ZERO(fname, sizeof(fname)); + sprintf(fname, "/tmp/scspd.%d.trace", getpid()); + + /* + * Open the trace file. If the open fails, log an error, but + * keep going. The trace routine will notice that the file + * isn't open and won't try to write to it. + */ + scsp_trace_file = fopen(fname, "w"); + if (scsp_trace_file == (FILE *)0) { + scsp_log(LOG_ERR, "Can't open trace file"); + } +} + + +/* + * Write a message to SCSP's trace file + * + * Arguments: + * fmt printf-style format string + * ... parameters for printf-style use according to fmt + * + * Returns: + * none + * + */ +void +#if __STDC__ +scsp_trace(const char *fmt, ...) +#else +scsp_trace(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + /* + * Write the message to the trace file, if it's open + */ + if (scsp_trace_file) { + vfprintf(scsp_trace_file, fmt, ap); + } + + va_end(ap); +} + + +/* + * Write an SCSP message to SCSP's trace file + * + * Arguments: + * dcsp pointer to DCS block for the message + * msg pointer to the message + * dir a direction indicator--0 for sending, 1 for receiving + * + * Returns: + * none + * + */ +void +scsp_trace_msg(dcsp, msg, dir) + Scsp_dcs *dcsp; + Scsp_msg *msg; + int dir; +{ + struct in_addr addr; + + /* + * Copy the remote IP address into a struct in_addr + */ + UM_COPY(dcsp->sd_dcsid.id, &addr.s_addr, + sizeof(struct in_addr)); + + /* + * Write the message to the trace file, if it's open + */ + if (scsp_trace_file) { + scsp_trace("SCSP message at 0x%x %s %s\n", + (u_long)msg, + (dir ? "received from" : "sent to"), + format_ip_addr(&addr)); + print_scsp_msg(scsp_trace_file, msg); + } +} + + +/* + * Log a memory error and exit + * + * Arguments: + * cp message to log + * + * Returns: + * exits, does not return + * + */ +void +scsp_mem_err(cp) + char *cp; +{ + scsp_log(LOG_CRIT, "out of memory: %s", cp); + exit(2); +} diff --git a/usr.sbin/atm/scspd/scsp_msg.c b/usr.sbin/atm/scspd/scsp_msg.c new file mode 100644 index 0000000..bed2918 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_msg.c @@ -0,0 +1,611 @@ +/* + * + * =================================== + * 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_msg.c,v 1.6 1998/08/21 18:08:24 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP message-handling routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_msg.c,v 1.6 1998/08/21 18:08:24 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" + +/* + * Copy CSAS records into a CA record + * + * Arguments: + * dcsp pointer to DCS block for DCS + * cap pointer to CA record for CSASs + * + * + * Returns: + * none + * + */ +static void +scsp_ca_csas_setup(dcsp, cap) + Scsp_dcs *dcsp; + Scsp_ca *cap; +{ + int csas_len, len, mtu; + Scsp_server *ssp = dcsp->sd_server; + Scsp_cse *csep, *next_csep; + Scsp_csa *csap; + + /* + * Loop through pending CSAS records + */ + len = sizeof(struct scsp_nhdr) + sizeof(struct scsp_nmcp) + + ssp->ss_lsid.id_len + + dcsp->sd_dcsid.id_len; + csas_len = sizeof(struct scsp_ncsa) + + dcsp->sd_server->ss_id_len + + dcsp->sd_server->ss_ckey_len; + mtu = dcsp->sd_server->ss_mtu; + for (csep = dcsp->sd_ca_csas; + csep && (len < mtu - csas_len); + csep = next_csep) { + next_csep = csep->sc_next; + csap = scsp_cse2csas(csep); + LINK2TAIL(csap, Scsp_csa, cap->ca_csa_rec, next); + len += csas_len; + UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next); + UM_FREE(csep); + cap->ca_mcp.rec_cnt++; + } +} + + +/* + * Process CSA records from a CSU Request that may be in response to + * CSAS records sent in a CSUS + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message + * + * Returns: + * none + * + */ +void +scsp_csus_ack(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + Scsp_csu_msg *csusp; + Scsp_csa *csap, *csasp, *next_csasp; + + /* + * If this isn't a CSU Request, or there's no outstanding CSUS, + * or the outstanding CSUS has already been satisfied, just + * return + */ + if (!msg || msg->sc_msg_type != SCSP_CSU_REQ_MSG || + !dcsp->sd_csus_rexmt_msg || + !dcsp->sd_csus_rexmt_msg->sc_csu_msg || + !dcsp->sd_csus_rexmt_msg->sc_csu_msg->csu_csa_rec) + return; + + + /* + * Loop through the CSASs in the CSUS message, checking for + * each in the CSA records of the received CSU Request + */ + csusp = dcsp->sd_csus_rexmt_msg->sc_csu_msg; + for (csasp = csusp->csu_csa_rec; csasp; csasp = next_csasp) { + next_csasp = csasp->next; + for (csap = msg->sc_csu_msg->csu_csa_rec; + csap; csap = csap->next) { + /* + * If the records match, unlink and free the + * CSAS from the CSUS + */ + if (scsp_cmp_key(&csap->key, &csasp->key) == 0 && + scsp_cmp_key(&csap->key, &csasp->key) == 0 && + scsp_cmp_id(&csap->oid, &csasp->oid) == 0 && + csap->seq >= csasp->seq) { + UNLINK(csasp, Scsp_csa, + csusp->csu_csa_rec, + next); + SCSP_FREE_CSA(csasp); + dcsp->sd_csus_rexmt_msg->sc_csu_msg->csu_mcp.rec_cnt--; + break; + } + } + } + + if (csusp->csu_csa_rec == (Scsp_csa *)0) { + /* + * All CSASs in the CSUS message have been + * answered. Stop the timer and free the + * saved message. + */ + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0; + + /* + * If the CRL isn't empty, send another CSUS + */ + if (dcsp->sd_crl) { + (void)scsp_send_csus(dcsp); + } + } +} + + +/* + * Send a CA message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_ca(dcsp) + Scsp_dcs *dcsp; +{ + int rc; + Scsp_msg *ca_msg; + Scsp_ca *cap; + Scsp_server *ssp = dcsp->sd_server; + + /* + * Get memory for a CA message + */ + ca_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!ca_msg) { + scsp_mem_err("scsp_send_ca: sizeof(Scsp_msg)"); + } + cap = (Scsp_ca *)UM_ALLOC(sizeof(Scsp_ca)); + if (!cap) { + scsp_mem_err("scsp_send_ca: sizeof(Scsp_ca)"); + } + UM_ZERO(ca_msg, sizeof(Scsp_msg)); + UM_ZERO(cap, sizeof(Scsp_ca)); + + /* + * Fill out constant fields + */ + ca_msg->sc_msg_type = SCSP_CA_MSG; + ca_msg->sc_ca = cap; + cap->ca_seq = dcsp->sd_ca_seq; + cap->ca_mcp.pid = ssp->ss_pid; + cap->ca_mcp.sgid = ssp->ss_sgid; + cap->ca_mcp.sid = ssp->ss_lsid; + cap->ca_mcp.rid = dcsp->sd_dcsid; + + /* + * Fill out state-dependent fields + */ + switch(dcsp->sd_ca_state) { + case SCSP_CAFSM_NEG: + cap->ca_m = 1; + cap->ca_i = 1; + cap->ca_o = 1; + break; + case SCSP_CAFSM_MASTER: + cap->ca_m = 1; + cap->ca_i = 0; + scsp_ca_csas_setup(dcsp, cap); + cap->ca_o = dcsp->sd_ca_csas != (Scsp_cse *)0; + break; + case SCSP_CAFSM_SLAVE: + cap->ca_m = 0; + cap->ca_i = 0; + scsp_ca_csas_setup(dcsp, cap); + cap->ca_o = dcsp->sd_ca_csas != (Scsp_cse *)0; + break; + default: + scsp_log(LOG_ERR, "Invalid state in scsp_send_ca"); + abort(); + } + + /* + * Send the CA message and save a pointer to it in case + * it needs to be retransmitted + */ + rc = scsp_send_msg(dcsp, ca_msg); + if (rc == 0) { + dcsp->sd_ca_rexmt_msg = ca_msg; + } else { + scsp_free_msg(ca_msg); + } + + return(rc); +} + + +/* + * Send a CSU Solicit message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_csus(dcsp) + Scsp_dcs *dcsp; +{ + int csas_len, len, mtu, rc; + Scsp_msg *csus_msg; + Scsp_csu_msg *csusp; + Scsp_csa *csasp, *next_csasp; + Scsp_server *ssp = dcsp->sd_server; + + /* + * If we have a mesage saved for retransmission, use it. + * If not, get memory for a new one. + */ + if (dcsp->sd_csus_rexmt_msg) { + csus_msg = dcsp->sd_csus_rexmt_msg; + csusp = csus_msg->sc_csu_msg; + } else { + /* + * Get memory for a CSUS message + */ + csus_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csus_msg) { + scsp_mem_err("scsp_send_csus: sizeof(Scsp_msg)"); + } + csusp = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csusp) { + scsp_mem_err("scsp_send_csus: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csus_msg, sizeof(Scsp_msg)); + UM_ZERO(csusp, sizeof(Scsp_csu_msg)); + + /* + * Fill out constant fields + */ + csus_msg->sc_msg_type = SCSP_CSUS_MSG; + csus_msg->sc_csu_msg = csusp; + csusp->csu_mcp.pid = ssp->ss_pid; + csusp->csu_mcp.sgid = ssp->ss_sgid; + csusp->csu_mcp.sid = ssp->ss_lsid; + csusp->csu_mcp.rid = dcsp->sd_dcsid; + } + + /* + * Move CSAS records from CRL into message + */ + mtu = dcsp->sd_server->ss_mtu; + csas_len = sizeof(struct scsp_ncsa) + ssp->ss_id_len + + ssp->ss_ckey_len; + len = sizeof(struct scsp_nhdr) + sizeof(struct scsp_nmcp) + + 2 * ssp->ss_id_len + + csas_len * (csusp->csu_mcp.rec_cnt + 1); + for (csasp = dcsp->sd_crl; + csasp && ((len + csas_len) < mtu); + csasp = next_csasp, len += csas_len) { + next_csasp = csasp->next; + csusp->csu_mcp.rec_cnt++; + UNLINK(csasp, Scsp_csa, dcsp->sd_crl, next); + LINK2TAIL(csasp, Scsp_csa, csusp->csu_csa_rec, next); + csasp->hops = 1; + } + + /* + * Send the CSUS message and save a pointer to it in case + * it needs to be retransmitted + */ + rc = scsp_send_msg(dcsp, csus_msg); + if (rc == 0) { + /* + * Success--Save a pointer to the message and + * start the CSUS retransmit timer + */ + dcsp->sd_csus_rexmt_msg = csus_msg; + HARP_TIMER(&dcsp->sd_csus_rexmt_t, + dcsp->sd_csus_rexmt_int, + scsp_csus_retran_timeout); + } else { + /* + * Error--free the CSUS message + */ + scsp_free_msg(csus_msg); + } + + return(rc); +} + + +/* + * Send a CSU Request message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * csap pointer to CSAs to include + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_csu_req(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc; + Scsp_server *ssp = dcsp->sd_server; + Scsp_csa *cnt_csap; + Scsp_msg *csu_msg; + Scsp_csu_msg *csup; + Scsp_csu_rexmt *rxp; + + /* + * Return if CSA list is empty + */ + if (!csap) + return(0); + + /* + * Get memory for a CSU Req message + */ + csu_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csu_msg) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_msg)"); + } + csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csup) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csu_msg, sizeof(Scsp_msg)); + UM_ZERO(csup, sizeof(Scsp_csu_msg)); + + /* + * Get memory for a CSU Req retransmission queue entry + */ + rxp = (Scsp_csu_rexmt *)UM_ALLOC(sizeof(Scsp_csu_rexmt)); + if (!rxp) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_csu_rexmt)"); + } + UM_ZERO(rxp, sizeof(Scsp_csu_rexmt)); + + /* + * Fill out constant fields + */ + csu_msg->sc_msg_type = SCSP_CSU_REQ_MSG; + csu_msg->sc_csu_msg = csup; + csup->csu_mcp.pid = ssp->ss_pid; + csup->csu_mcp.sgid = ssp->ss_sgid; + csup->csu_mcp.sid = ssp->ss_lsid; + csup->csu_mcp.rid = dcsp->sd_dcsid; + + /* + * Put the CSA list into the message + */ + csup->csu_csa_rec = csap; + for (cnt_csap = csap; cnt_csap; cnt_csap = cnt_csap->next) { + csup->csu_mcp.rec_cnt++; + } + + /* + * Send the CSU Request + */ + rc = scsp_send_msg(dcsp, csu_msg); + if (rc) { + scsp_free_msg(csu_msg); + return(rc); + } + UM_FREE(csu_msg); + UM_FREE(csup); + + /* + * Save the CSA entries on the CSU Request retransmission + * queue and start the retransmission timer + */ + rxp->sr_dcs = dcsp; + rxp->sr_csa = csap; + HARP_TIMER(&rxp->sr_t, dcsp->sd_csu_rexmt_int, + scsp_csu_req_retran_timeout); + LINK2TAIL(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, sr_next); + + return(0); +} + + +/* + * Send a CSU Reply message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * csap pointer to CSAs to include + * + * Returns: + * 0 message sent OK + * errno reason for failure + * + */ +int +scsp_send_csu_reply(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc; + Scsp_server *ssp = dcsp->sd_server; + Scsp_csa *csap1; + Scsp_msg *csu_msg; + Scsp_csu_msg *csup; + + /* + * Return if CSA list is empty + */ + if (!csap) + return(0); + + /* + * Get memory for a CSU Reply message + */ + csu_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csu_msg) { + scsp_mem_err("scsp_send_csu_reply: sizeof(Scsp_msg)"); + } + csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csup) { + scsp_mem_err("scsp_send_csu_reply: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csu_msg, sizeof(Scsp_msg)); + UM_ZERO(csup, sizeof(Scsp_csu_msg)); + + /* + * Fill out constant fields + */ + csu_msg->sc_msg_type = SCSP_CSU_REPLY_MSG; + csu_msg->sc_csu_msg = csup; + csup->csu_mcp.pid = ssp->ss_pid; + csup->csu_mcp.sgid = ssp->ss_sgid; + csup->csu_mcp.sid = ssp->ss_lsid; + csup->csu_mcp.rid = dcsp->sd_dcsid; + + /* + * Put the CSA list into the message. Convert the CSAs into + * CSASs by freeing the protocol-specific portion. + */ + csup->csu_csa_rec = csap; + for (csap1 = csap; csap1; csap1 = csap1->next) { + switch(dcsp->sd_server->ss_pid) { + /* + * We currently only support ATMARP + */ + case SCSP_PROTO_ATMARP: + if (csap1->atmarp_data) { + UM_FREE(csap1->atmarp_data); + csap1->atmarp_data = + (Scsp_atmarp_csa *)0; + } + break; + } + csup->csu_mcp.rec_cnt++; + } + + /* + * Send the CSU Reply + */ + rc = scsp_send_msg(dcsp, csu_msg); + scsp_free_msg(csu_msg); + + return(rc); +} + + +/* + * Send a Hello message + * + * Arguments: + * dcsp pointer to DCS control block + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_send_hello(dcsp) + Scsp_dcs *dcsp; +{ + int rc; + Scsp_msg *hello; + Scsp_hello *hp; + + /* + * Get memory for a Hello message + */ + hello = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!hello) { + scsp_mem_err("scsp_send_hello: sizeof(Scsp_msg)"); + } + UM_ZERO(hello, sizeof(Scsp_msg)); + hp = (Scsp_hello *)UM_ALLOC(sizeof(Scsp_hello)); + if (!hp) { + scsp_mem_err("scsp_send_hello: sizeof(Scsp_hello)"); + } + UM_ZERO(hp, sizeof(Scsp_hello)); + + /* + * Set up the Hello message + */ + hello->sc_msg_type = SCSP_HELLO_MSG; + hello->sc_hello = hp; + hp->hello_int = SCSP_HELLO_Interval; + hp->dead_factor = SCSP_HELLO_DF; + hp->family_id = dcsp->sd_server->ss_fid; + hp->hello_mcp.pid = dcsp->sd_server->ss_pid; + hp->hello_mcp.sgid = dcsp->sd_server->ss_sgid; + hp->hello_mcp.flags = 0; + hp->hello_mcp.rec_cnt = 0; + hp->hello_mcp.sid = dcsp->sd_server->ss_lsid; + hp->hello_mcp.rid = dcsp->sd_dcsid; + + /* + * Send and free the message + */ + rc = scsp_send_msg(dcsp, hello); + scsp_free_msg(hello); + + return(rc); +} diff --git a/usr.sbin/atm/scspd/scsp_msg.h b/usr.sbin/atm/scspd/scsp_msg.h new file mode 100644 index 0000000..3ee3bf5 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_msg.h @@ -0,0 +1,462 @@ +/* + * + * =================================== + * 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_msg.h,v 1.1 1998/07/10 15:29:02 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP message formats + * + */ + +#ifndef _SCSP_SCSP_MSG_H +#define _SCSP_SCSP_MSG_H + + +/* + * ATMARP constants + */ +#define ARP_ATMFORUM 19 +#define ARP_TL_TMASK 0x40 /* Type mask */ +#define ARP_TL_NSAPA 0x00 /* Type = ATM Forum NSAPA */ +#define ARP_TL_E164 0x40 /* Type = E.164 */ +#define ARP_TL_LMASK 0x3f /* Length mask */ + + +/* + * SCSP version number + */ +#define SCSP_VER_1 1 + + +/* + * SCSP message types + */ +#define SCSP_CA_MSG 1 +#define SCSP_CSU_REQ_MSG 2 +#define SCSP_CSU_REPLY_MSG 3 +#define SCSP_CSUS_MSG 4 +#define SCSP_HELLO_MSG 5 + + +/* + * SCSP Client Protocol IDs + */ +#define SCSP_PROTO_ATMARP 1 +#define SCSP_PROTO_NHRP 2 +#define SCSP_PROTO_MARS 3 +#define SCSP_PROTO_DHCP 4 +#define SCSP_PROTO_LNNI 5 + + +/* + * Extension types + */ +#define SCSP_EXT_END 0 +#define SCSP_EXT_AUTH 1 +#define SCSP_EXT_VENDOR 2 + +/* + * Sequence number bounds + */ +#define SCSP_CSA_SEQ_MIN 0x80000001 +#define SCSP_CSA_SEQ_MAX 0x7FFFFFFF + + +/* + * Sender, Receiver, or Originator ID lengths + */ +#define SCSP_ATMARP_ID_LEN 4 +#define SCSP_NHRP_ID_LEN 4 +#define SCSP_MAX_ID_LEN 4 + + +/* + * Cache Key lengths + */ +#define SCSP_ATMARP_KEY_LEN 4 +#define SCSP_NHRP_KEY_LEN 4 +#define SCSP_MAX_KEY_LEN 4 + + +/* + * Fixed header + */ +struct scsp_nhdr { + u_char sh_ver; /* SCSP version */ + u_char sh_type; /* Message type */ + u_short sh_len; /* Message length */ + u_short sh_checksum; /* IP checksum over message */ + u_short sh_ext_off; /* Offset of first extension */ +}; + + +/* + * Mandatory common part + */ +struct scsp_nmcp { + u_short sm_pid; /* Protocol ID */ + u_short sm_sgid; /* Server group ID */ + u_short sm_fill_0; /* Unused */ + u_short sm_flags; /* Flags--see below */ + u_char sm_sid_len; /* Sender ID length */ + u_char sm_rid_len; /* Receiver ID length */ + u_short sm_rec_cnt; /* Number of records */ +#ifdef NOTDEF + /* Variable length fields */ + u_char sm_sid[]; /* Sender ID (variable) */ + u_char sm_rid[]; /* Receiver ID (variable) */ +#endif +}; + + +/* + * Extensions part + */ +struct scsp_next { + u_short se_type; /* Extension type */ + u_short se_len; /* Length */ +#ifdef NOTDEF + /* Variable length fields */ + u_char se_value[]; /* Extension value */ +#endif +}; + + +/* + * Cache State Advertisement record or + * Cache State Advertisement Summary record + */ +struct scsp_ncsa { + u_short scs_hop_cnt; /* Hop count */ + u_short scs_len; /* Record length */ + u_char scs_ck_len; /* Cache key length */ + u_char scs_oid_len; /* Originator ID length */ + u_short scs_nfill; /* Null bit and filler */ + long scs_seq; /* Sequence number */ +#ifdef NOTDEF + /* Variable length fields */ + u_char scs_ckey[]; /* Cache key */ + u_char scs_oid[]; /* Originator ID */ + u_char scs_proto[]; /* Protocol-specific (in CSA) */ +#endif +}; + +#define SCSP_CSAS_NULL 0x8000 + + +/* + * Cache Alignment message + */ +struct scsp_nca { + long sca_seq; /* Sequence number */ + struct scsp_nmcp sca_mcp; /* Mandatory common */ +#ifdef NOTDEF + /* Variable length fields */ + struct scsp_ncsa sca_rec[]; /* CSASs */ +#endif +}; + +#define SCSP_CA_M 0x8000 /* Master/Slave bit */ +#define SCSP_CA_I 0x4000 /* Initialization bit */ +#define SCSP_CA_O 0x2000 /* More bit */ + + +/* + * Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message + */ +struct scsp_ncsu_msg { + struct scsp_nmcp scr_mcp; /* Mandatory common */ +#ifdef NOTDEF + /* Variable length fields */ + struct scsp_ncsa scr_rec[]; /* CSAs */ +#endif +}; + + +/* + * Hello message + */ +struct scsp_nhello { + u_short sch_hi; /* Hello interval */ + u_short sch_df; /* Dead factor */ + u_short sch_fill_0; /* Unused */ + u_short sch_fid; /* Family ID */ + struct scsp_nmcp sch_mcp; /* Mandatory common */ +#ifdef NOTDEF + /* Variable-length fields */ + struct scsp_nrid sch_rid[]; /* Receiver IDs */ +#endif +}; + + +/* + * ATMARP-specific Cache State Advertisement record + */ +struct scsp_atmarp_ncsa { + u_short sa_hrd; /* Hardware type -- 0x0013 */ + u_short sa_pro; /* Protocol type -- 0x0800 */ + u_char sa_shtl; /* Src ATM addr type/len */ + u_char sa_sstl; /* Src ATM subaddr type/len */ + u_char sa_state; /* State */ + u_char sa_fill1; /* Unused */ + u_char sa_spln; /* Src proto addr type */ + u_char sa_thtl; /* Tgt ATM addr type/len */ + u_char sa_tstl; /* Tgt ATM subaddr type/len */ + u_char sa_tpln; /* Tgt proto addr len */ +#ifdef NOTDEF + /* Variable-length fields */ + u_char sa_sha[]; /* Source ATM addr */ + u_char sa_ssa[]; /* Source ATM subaddr */ + u_char sa_spa[]; /* Source IP addr */ + u_char sa_tha[]; /* Target ATM addr */ + u_char sa_tsa[]; /* Target ATM subaddr */ + u_char sa_tpa[]; /* Target IP addr */ +#endif +}; + + +/* + * NHRP-specific Cache State Advertisement record + */ +struct scsp_nhrp_ncsa { + u_short sn_af; /* Address family */ + u_short sn_pro; /* NHRP protocol type */ + u_char sn_snap[5]; /* SNAP header */ + u_char sn_ver; /* NHRP version no. */ + u_short sn_flags; /* Flags */ + u_long sn_rid; /* Request ID */ + u_char sn_state; /* State */ + u_char sn_pln; /* Prefix length */ + u_short sn_fill1; /* Unused */ + u_short sn_mtu; /* MTU */ + u_short sn_hold; /* Holding time */ + u_char sn_csatl; /* Client addr type/len */ + u_char sn_csstl; /* Client subaddr type/len */ + u_char sn_cpln; /* Client proto addr len */ + u_char sn_pref; /* Preference for next hop */ +#ifdef NOTDEF + /* Variable-length fields */ + u_char sn_csa[]; /* Client subnetwork addr */ + u_char sn_css[]; /* Client subnetwork subaddr */ + u_char sn_cpa[]; /* Client protocol addr */ +#endif +}; + + +/* + * SCSP messages in internal format + * + * + * Fixed message header + */ +struct scsp_hdr { + u_char msg_type; /* Message type */ +}; +typedef struct scsp_hdr Scsp_hdr; + + +/* + * Sender or Receiver ID structure + */ +struct scsp_id { + struct scsp_id *next; /* Next ID */ + u_char id_len; /* ID length */ + u_char id[SCSP_MAX_ID_LEN]; /* ID */ +}; +typedef struct scsp_id Scsp_id; + + +/* + * Cacke Key structure + */ +struct scsp_ckey { + u_char key_len; /* Cache key length */ + u_char key[SCSP_MAX_KEY_LEN]; /* Cache key */ +}; +typedef struct scsp_ckey Scsp_ckey; + + +/* + * Mandatory common part + */ +struct scsp_mcp { + u_short pid; /* Protocol ID */ + u_short sgid; /* Server group ID */ + u_short flags; /* Flags */ + u_short rec_cnt; /* No. of records attached */ + Scsp_id sid; /* Sender ID */ + Scsp_id rid; /* Receiver ID */ +}; +typedef struct scsp_mcp Scsp_mcp; + + +/* + * Extensions part + */ +struct scsp_ext { + struct scsp_ext *next; /* Next extension */ + u_short type; /* Extension type */ + u_short len; /* Length */ +#ifdef NOTDEF + /* Variable length fields */ + u_char value[]; /* Extension value */ +#endif +}; +typedef struct scsp_ext Scsp_ext; + + +/* + * Cache State Advertisement record or + * Cache State Advertisement Summary record + */ +struct scsp_csa { + struct scsp_csa *next; /* Next CSAS record */ + u_short hops; /* Hop count */ + u_char null; /* Null flag */ + u_long seq; /* CSA seq. no. */ + Scsp_ckey key; /* Cache key */ + Scsp_id oid; /* Originator ID */ + int trans_ct; /* No. of times CSA sent */ + struct scsp_atmarp_csa *atmarp_data; /* ATMARP data */ +#ifdef NOTDEF + struct scsp_nhrp_csa *nhrp_data; /* NHRP data */ +#endif +}; +typedef struct scsp_csa Scsp_csa; + +/* + * Macro to free a CSA and any associated protocol-specific data + */ +#define SCSP_FREE_CSA(c) \ +{ \ + if ((c)->atmarp_data) { \ + UM_FREE((c)->atmarp_data); \ + } \ + UM_FREE((c)); \ +} + + +/* + * Cache Alignment message + */ +struct scsp_ca { + long ca_seq; /* CA msg sequence no. */ + u_char ca_m; /* Master/slave bit */ + u_char ca_i; /* Initialization bit */ + u_char ca_o; /* More bit */ + Scsp_mcp ca_mcp; /* Mandatory common part */ + Scsp_csa *ca_csa_rec; /* Ptr. to CSAS records */ +}; +typedef struct scsp_ca Scsp_ca; + + +/* + * Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message + */ +struct scsp_csu_msg { + Scsp_mcp csu_mcp; /* Mandatory common part */ + Scsp_csa *csu_csa_rec; /* Ptr. to CSA records */ +}; +typedef struct scsp_csu_msg Scsp_csu_msg; + + +/* + * Hello message + */ +struct scsp_hello { + u_short hello_int; /* Hello interval */ + u_short dead_factor; /* When is DCS dead? */ + u_short family_id; /* Family ID */ + Scsp_mcp hello_mcp; /* Mandatory common part */ +}; +typedef struct scsp_hello Scsp_hello; + + +/* + * NHRP-specific Cache State Advertisement record + */ +struct scsp_nhrp_csa { + u_char req_id; /* Request ID */ + u_char state; /* State */ + u_char pref_len; /* Prefix length */ + u_short flags; /* See below */ + u_short mtu; /* Maximim transmission unit */ + u_short hold_time; /* Entry holding time */ + u_char caddr_tlen; /* Client addr type/length */ + u_char csaddr_tlen; /* Client subaddr type/length */ + u_char cproto_len; /* Client proto addr length */ + u_char pref; /* Preference */ + Atm_addr caddr; /* Client address */ + Atm_addr csaddr; /* Client subaddress */ + struct in_addr cproto_addr; /* Client protocol address */ +}; +typedef struct scsp_nhrp Scsp_nhrp; + +#define SCSP_NHRP_UNIQ 0x8000 +#define SCSP_NHRP_ARP 0x4000 + + +/* + * ATMARP-specific Cache State Advertisement record + */ +struct scsp_atmarp_csa { + u_char sa_state; /* State */ + Atm_addr sa_sha; /* Source ATM addr */ + Atm_addr sa_ssa; /* Source ATM subaddr */ + struct in_addr sa_spa; /* Source IP addr */ + Atm_addr sa_tha; /* Target ATM addr */ + Atm_addr sa_tsa; /* Target ATM subaddr */ + struct in_addr sa_tpa; /* Target IP addr */ +}; +typedef struct scsp_atmarp_csa Scsp_atmarp_csa; + + +/* + * SCSP message + */ +struct scsp_msg { + Scsp_hdr sc_hdr; + union { + Scsp_ca *sc_u_ca; + Scsp_csu_msg *sc_u_csu_msg; + Scsp_hello *sc_u_hello; + } sc_msg_u; + Scsp_ext *sc_ext; +}; +typedef struct scsp_msg Scsp_msg; + +#define sc_msg_type sc_hdr.msg_type +#define sc_ca sc_msg_u.sc_u_ca +#define sc_csu_msg sc_msg_u.sc_u_csu_msg +#define sc_hello sc_msg_u.sc_u_hello + +#endif /* _SCSP_SCSP_MSG_H */ diff --git a/usr.sbin/atm/scspd/scsp_output.c b/usr.sbin/atm/scspd/scsp_output.c new file mode 100644 index 0000000..10ee493 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_output.c @@ -0,0 +1,934 @@ +/* + * + * =================================== + * 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_output.c,v 1.2 1998/07/12 20:49:45 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Output packet processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_output.c,v 1.2 1998/07/12 20:49:45 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 <netinet/if_ether.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" + + +/* + * Put a long integer into the output buffer + * + * This routine is provided for cases where long ints may not be + * word-aligned in the output buffer. + * + * Arguments: + * l long integer + * cp pointer to output buffer + * + * Returns: + * None + * + */ +static void +put_long(l, cp) + u_long l; + u_char *cp; +{ + u_long nl; + + /* + * Convert to network order and copy to output buffer + */ + nl = htonl(l); + UM_COPY(&nl, cp, sizeof(u_long)); +} + + +/* + * Format a Sender or Receiver ID + * + * Arguments: + * idp ponter to ID structure + * buff pointer to ID + * + * Returns: + * 0 input was invalid + * else length of ID processed + * + */ +static int +scsp_format_id(idp, buff) + Scsp_id *idp; + char *buff; +{ + /* + * Copy the ID + */ + UM_COPY(idp->id, buff, idp->id_len); + + /* + * Return the ID length + */ + return(idp->id_len); +} + + +/* + * Format the Mandatory Common Part of an SCSP input packet + * + * Arguments: + * mcp pointer to MCP + * buff pointer to mandatory common part + * + * Returns: + * 0 input was invalid + * else length of MCP in message + * + */ +static int +scsp_format_mcp(mcp, buff) + Scsp_mcp *mcp; + char *buff; +{ + int len; + char *idp, *odp; + struct scsp_nmcp *smp; + + /* + * Set the protocol ID + */ + smp = (struct scsp_nmcp *)buff; + smp->sm_pid = htons(mcp->pid); + + /* + * Set the server group ID + */ + smp->sm_sgid = htons(mcp->sgid); + + /* + * Set the flags + */ + smp->sm_flags = htons(mcp->flags); + + /* + * Set the sender ID and length + */ + smp->sm_sid_len = mcp->sid.id_len; + odp = buff + sizeof(struct scsp_nmcp); + len = scsp_format_id(&mcp->sid, odp); + if (len == 0) { + goto mcp_invalid; + } + + /* + * Set the receiver ID and length + */ + smp->sm_rid_len = mcp->rid.id_len; + odp += mcp->sid.id_len; + len = scsp_format_id(&mcp->rid, odp); + if (len == 0) { + goto mcp_invalid; + } + + /* + * Set the record count + */ + smp->sm_rec_cnt = htons(mcp->rec_cnt); + + /* + * Return the length of data we processed + */ + return(sizeof(struct scsp_nmcp) + mcp->sid.id_len + + mcp->rid.id_len); + +mcp_invalid: + return(0); +} + + +/* + * Format an Extension + * + * Arguments: + * exp pointer to extension in internal format + * buff pointer to output buffer + * blen space available in buffer + * + * Returns: + * 0 input was invalid + * else length of extension processed + * + */ +static int +scsp_format_ext(exp, buff, blen) + Scsp_ext *exp; + char *buff; + int blen; +{ + int len; + struct scsp_next *sep; + + /* + * Make sure there's room in the buffer + */ + if (blen < (sizeof(struct scsp_next) + exp->len)) + return(0); + + /* + * Set the type + */ + sep = (struct scsp_next *)buff; + sep->se_type = htons(exp->type); + + /* + * Set the length + */ + sep->se_len = htons(exp->len); + + /* + * Set the value + */ + if (exp->len > 0) { + buff += sizeof(struct scsp_next); + UM_COPY((caddr_t)exp + sizeof(Scsp_ext), + buff, + exp->len); + } + + /* + * Return the number of bytes processed + */ + return(sizeof(struct scsp_next) + exp->len); +} + + +/* + * Format the ATMARP part of a CSA record + * + * Arguments: + * acsp pointer to ATMARP protocol-specific CSA record + * buff pointer to output buffer + * + * Returns: + * 0 input was invalid + * else length of record processed + * + */ +static int +scsp_format_atmarp(acsp, buff) + Scsp_atmarp_csa *acsp; + char *buff; +{ + char *cp; + int len, pkt_len, rc; + struct scsp_atmarp_ncsa *sanp; + + /* + * Figure out how long PDU is going to be + */ + pkt_len = sizeof(struct scsp_atmarp_ncsa); + switch (acsp->sa_sha.address_format) { + case T_ATM_ENDSYS_ADDR: + pkt_len += acsp->sa_sha.address_length; + break; + + case T_ATM_E164_ADDR: + pkt_len += acsp->sa_sha.address_length; + if (acsp->sa_ssa.address_format == T_ATM_ENDSYS_ADDR) + pkt_len += acsp->sa_ssa.address_length; + break; + } + + switch (acsp->sa_tha.address_format) { + case T_ATM_ENDSYS_ADDR: + pkt_len += acsp->sa_tha.address_length; + break; + + case T_ATM_E164_ADDR: + pkt_len += acsp->sa_tha.address_length; + if (acsp->sa_tha.address_format == T_ATM_ENDSYS_ADDR) + pkt_len += acsp->sa_tha.address_length; + break; + } + + if (acsp->sa_spa.s_addr != 0) + pkt_len += sizeof(struct in_addr); + + if (acsp->sa_tpa.s_addr != 0) + pkt_len += sizeof(struct in_addr); + + /* + * Set up pointers + */ + sanp = (struct scsp_atmarp_ncsa *)buff; + cp = (char *)sanp + sizeof(struct scsp_atmarp_ncsa); + + /* + * Build fields + */ + sanp->sa_hrd = htons(ARP_ATMFORUM); + sanp->sa_pro = htons(ETHERTYPE_IP); + + /* sa_sha */ + len = acsp->sa_sha.address_length; + switch (acsp->sa_sha.address_format) { + case T_ATM_ENDSYS_ADDR: + sanp->sa_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* sa_sha */ + UM_COPY(acsp->sa_sha.address, cp, len); + cp += len; + + sanp->sa_sstl = 0; + break; + + case T_ATM_E164_ADDR: + sanp->sa_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* sa_sha */ + UM_COPY(acsp->sa_sha.address, cp, len); + cp += len; + + if (acsp->sa_ssa.address_format == T_ATM_ENDSYS_ADDR) { + len = acsp->sa_ssa.address_length; + sanp->sa_sstl = ARP_TL_NSAPA | + (len & ARP_TL_LMASK); + + /* sa_ssa */ + UM_COPY(acsp->sa_ssa.address, cp, len); + cp += len; + } else + sanp->sa_sstl = 0; + break; + + default: + sanp->sa_shtl = 0; + sanp->sa_sstl = 0; + } + + /* sa_state */ + sanp->sa_state = acsp->sa_state; + sanp->sa_fill1 = 0; + + /* sa_spa */ + if (acsp->sa_spa.s_addr != 0) { + sanp->sa_spln = sizeof(struct in_addr); + UM_COPY(&acsp->sa_spa, cp, sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + } + + /* sa_tha */ + len = acsp->sa_tha.address_length; + switch (acsp->sa_tha.address_format) { + case T_ATM_ENDSYS_ADDR: + sanp->sa_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* sa_tha */ + UM_COPY(acsp->sa_tha.address, cp, len); + cp += len; + + sanp->sa_tstl = 0; + break; + + case T_ATM_E164_ADDR: + sanp->sa_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* sa_tha */ + UM_COPY(acsp->sa_tha.address, cp, len); + cp += len; + + if (acsp->sa_tsa.address_format == T_ATM_ENDSYS_ADDR) { + len = acsp->sa_tha.address_length; + sanp->sa_tstl = ARP_TL_NSAPA | + (len & ARP_TL_LMASK); + + /* sa_tsa */ + UM_COPY(acsp->sa_tsa.address, cp, len); + cp += len; + } else + sanp->sa_tstl = 0; + break; + + default: + sanp->sa_thtl = 0; + sanp->sa_tstl = 0; + } + + /* sa_tpa */ + if (acsp->sa_tpa.s_addr != 0) { + sanp->sa_tpln = sizeof(struct in_addr); + UM_COPY(&acsp->sa_tpa, cp, sizeof(struct in_addr)); + } + + return(pkt_len); +} + + +/* + * Format a Cache State Advertisement or Cache State Advertisement + * Summary record + * + * Arguments: + * csapp pointer to CSA or CSAS + * buff pointer to output buffer + * + * Returns: + * 0 input was invalid + * else length of record processed + * + */ +static int +scsp_format_csa(csap, buff) + Scsp_csa *csap; + char *buff; +{ + int len = 0; + char *idp, *odp; + struct scsp_ncsa *scp; + + /* + * Set the hop count + */ + scp = (struct scsp_ncsa *)buff; + scp->scs_hop_cnt = htons(csap->hops); + + /* + * Set the null flag + */ + if (csap->null) { + scp->scs_nfill = htons(SCSP_CSAS_NULL); + } + + /* + * Set the sequence number + */ + put_long(csap->seq, (u_char *)&scp->scs_seq); + + /* + * Set the cache key + */ + scp->scs_ck_len = csap->key.key_len; + odp = buff + sizeof(struct scsp_ncsa); + UM_COPY(csap->key.key, odp, scp->scs_ck_len); + + /* + * Set the originator ID + */ + odp += scp->scs_ck_len; + scp->scs_oid_len = scsp_format_id(&csap->oid, odp); + + /* + * Set the protocol-specific data, if present. At the + * moment, we only handle data for ATMARP. + */ + if (csap->atmarp_data) { + odp += scp->scs_oid_len; + len = scsp_format_atmarp(csap->atmarp_data, odp); + } + + /* + * Set the record length + */ + scp->scs_len = htons(sizeof(struct scsp_ncsa) + + scp->scs_ck_len + scp->scs_oid_len + + len); + + /* + * Return the length of data we processed + */ + return(ntohs(scp->scs_len)); +} + + +/* + * Format a Cache Alignment message + * + * Arguments: + * cap pointer to CA message + * buff pointer to output buffer + * blen space available in buffer + * + * Returns: + * 0 input was invalid + * else length of CA message processed + * + */ +static int +scsp_format_ca(cap, buff, blen) + Scsp_ca *cap; + char *buff; + int blen; +{ + int i, len, proc_len; + struct scsp_nca *scap; + Scsp_csa *csap; + + /* + * Set the sequence number + */ + scap = (struct scsp_nca *)buff; + put_long(cap->ca_seq, (u_char *)&scap->sca_seq); + proc_len = sizeof(scap->sca_seq); + buff += sizeof(scap->sca_seq); + + /* + * Set the flags + */ + cap->ca_mcp.flags = 0; + if (cap->ca_m) + cap->ca_mcp.flags |= SCSP_CA_M; + if (cap->ca_i) + cap->ca_mcp.flags |= SCSP_CA_I; + if (cap->ca_o) + cap->ca_mcp.flags |= SCSP_CA_O; + + /* + * Format the mandatory common part of the message + */ + len = scsp_format_mcp(&cap->ca_mcp, buff); + if (len == 0) + goto ca_invalid; + buff += len; + proc_len += len; + + /* + * Put any CSAS records into the message + */ + for (i = 0, csap = cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt; + i++, csap = csap->next) { + len = scsp_format_csa(csap, buff); + buff += len; + proc_len += len; + if (proc_len > blen) { + scsp_log(LOG_CRIT, "scsp_format_ca: buffer overflow"); + abort(); + } + } + + /* + * Return the length of processed data + */ + return(proc_len); + +ca_invalid: + return(0); +} + + +/* + * Format a Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message. These all have the same format, + * a Mandatory Common Part followed by a number of CSA or CSAS records. + * + * Arguments: + * csup pointer to location to put pointer to CSU Req message + * buff pointer to output buffer + * blen space available in buffer + * + * Returns: + * 0 input was invalid + * else length of CSU Req message processed + * + */ +static int +scsp_format_csu(csup, buff, blen) + Scsp_csu_msg *csup; + char *buff; + int blen; +{ + int i, len, proc_len; + struct scsp_ncsu_msg *scsup; + Scsp_csa *csap; + + /* + * Format the mandatory common part of the message + */ + scsup = (struct scsp_ncsu_msg *)buff; + len = scsp_format_mcp(&csup->csu_mcp, buff); + if (len == 0) + goto csu_invalid; + buff += len; + proc_len = len; + + /* + * Put the CSAS records into the message + */ + for (i = 0, csap = csup->csu_csa_rec; + i < csup->csu_mcp.rec_cnt && csap; + i++, csap = csap->next) { + len = scsp_format_csa(csap, buff); + buff += len; + proc_len += len; + if (proc_len > blen) { + scsp_log(LOG_CRIT, "scsp_format_csu: buffer overflow"); + abort(); + } + } + + /* + * Return the length of processed data + */ + return(proc_len); + +csu_invalid: + return(0); +} + + +/* + * Format a Hello message + * + * Arguments: + * hpp pointer to Hello message + * buff pointer to output buffer + * blen space available in buffer + * + * Returns: + * 0 input was invalid + * else length of Hello message processed + * + */ +static int +scsp_format_hello(hp, buff, blen) + Scsp_hello *hp; + char *buff; + int blen; +{ + int i, len, proc_len; + struct scsp_nhello *shp; + Scsp_id *idp; + Scsp_id *ridp; + + /* + * Set the hello interval + */ + shp = (struct scsp_nhello *)buff; + shp->sch_hi = htons(hp->hello_int); + + /* + * Set the dead factor + */ + shp->sch_df = htons(hp->dead_factor); + + /* + * Set the family ID + */ + shp->sch_fid = htons(hp->family_id); + + /* + * Process the mandatory common part of the message + */ + proc_len = sizeof(struct scsp_nhello) - + sizeof(struct scsp_nmcp); + buff += proc_len; + len = scsp_format_mcp(&hp->hello_mcp, buff); + if (len == 0) + goto hello_invalid; + proc_len += len; + buff += len; + + /* + * Add any additional receiver ID records to the message + */ + for (ridp = hp->hello_mcp.rid.next; ridp; + ridp = ridp->next) { + len = scsp_format_id(ridp, buff); + if (len == 0) { + goto hello_invalid; + } + proc_len += len; + buff += len; + } + + /* + * Return the length of the Hello message body + */ + if (proc_len > blen) { + scsp_log(LOG_CRIT, "scsp_format_hello: buffer overflow"); + abort(); + } + return(proc_len); + +hello_invalid: + return(0); +} + + +/* + * Format an SCSP output packet + * + * Arguments: + * dcsp pointer to DCS for which message is being prepared + * msg pointer to input packet + * bpp pointer to location to put pointer to formatted packet + * + * Returns: + * 0 input packet was invalid + * else length of formatted packet + * + */ +int +scsp_format_msg(dcsp, msg, bpp) + Scsp_dcs *dcsp; + Scsp_msg *msg; + char **bpp; +{ + char *buff = (char *)0, *e_buff = (char *)0; + int buff_len, e_buff_len; + int e_len, len, plen; + struct scsp_nhdr *shp; + Scsp_ext *exp; + + /* + * Allocate a buffer for the message + */ + buff_len = dcsp->sd_server->ss_mtu; + buff = (char *)UM_ALLOC(buff_len); + if (!buff) { + scsp_mem_err("scsp_format_msg: dcsp->sd_server->ss_mtu"); + } + UM_ZERO(buff, buff_len); + *bpp = buff; + + /* + * Encode the fixed header + * + * Set the version + */ + shp = (struct scsp_nhdr *)buff; + shp->sh_ver = SCSP_VER_1; + + /* + * Set the message type + */ + shp->sh_type = msg->sc_msg_type; + + /* + * Point past the fixed header + */ + len = sizeof(struct scsp_nhdr); + buff_len -= len; + + /* + * Encode any extensions into a temporary buffer + */ + e_len = 0; + if (msg->sc_ext) { + /* + * Get a buffer for the extensions + */ + e_buff_len = 1024; + e_buff = (char *)UM_ALLOC(e_buff_len); + if (!buff) { + scsp_mem_err("scsp_format_msg: e_buff_len"); + } + UM_ZERO(e_buff, e_buff_len); + + /* + * Encode the extensions + */ + for (exp = msg->sc_ext = 0; exp; exp = exp->next) { + plen = scsp_format_ext(exp, e_buff + e_len, + e_buff_len - e_len); + if (plen == 0) { + goto ignore; + } + e_len += plen; + } + + /* + * Free the buffer if we didn't use it + */ + if (!e_len) { + UM_FREE(e_buff); + e_buff = (char *)0; + } + } + buff_len -= e_len; + + /* + * Encode the body of the message, depending on the type + */ + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + plen = scsp_format_ca(msg->sc_ca, buff + len, buff_len); + break; + case SCSP_CSU_REQ_MSG: + case SCSP_CSU_REPLY_MSG: + case SCSP_CSUS_MSG: + plen = scsp_format_csu(msg->sc_csu_msg, buff + len, + buff_len); + break; + case SCSP_HELLO_MSG: + plen = scsp_format_hello(msg->sc_hello, buff + len, + buff_len); + break; + default: + goto ignore; + } + if (plen == 0) { + goto ignore; + } + len += plen; + + /* + * Copy the extensions to the end of the message + */ + if (e_len) { + shp->sh_ext_off = htons(len); + UM_COPY(e_buff, buff + len, e_len); + UM_FREE(e_buff); + } + + /* + * Set the length + */ + shp->sh_len = htons(len); + + /* + * Compute the message checksum + */ + shp->sh_checksum = htons(ip_checksum(buff, len)); + + /* + * Return the length of the buffer + */ + return(len); + +ignore: + if (buff) + UM_FREE(buff); + if (e_buff) + UM_FREE(e_buff); + *bpp = (char *)0; + return(0); +} + + +/* + * Send an SCSP message + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message to send + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_send_msg(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int len, rc; + char *buff; + + /* + * Make sure we have a socket open + */ + if (dcsp->sd_sock == -1) { + return(EBADF); + } + + /* + * Trace the message + */ + if (((scsp_trace_mode & SCSP_TRACE_HELLO_MSG) && + msg->sc_msg_type == SCSP_HELLO_MSG) || + ((scsp_trace_mode & SCSP_TRACE_CA_MSG) && + msg->sc_msg_type != SCSP_HELLO_MSG)) { + scsp_trace_msg(dcsp, msg, 0); + scsp_trace("\n"); + } + + /* + * Put the message into network format + */ + len = scsp_format_msg(dcsp, msg, &buff); + if (len == 0) { + scsp_log(LOG_ERR, "scsp_send_msg: message conversion failed\n"); + abort(); + } + + /* + * Write the message to the DCS + */ + rc = write(dcsp->sd_sock, (void *)buff, len); + UM_FREE(buff); + if (rc == len || (rc == -1 && errno == EINPROGRESS)) { + rc = 0; + } else { + /* + * There was an error on the write--close the VCC + */ + (void)close(dcsp->sd_sock); + dcsp->sd_sock = -1; + + /* + * Inform the Hello FSM + */ + (void)scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED, + (Scsp_msg *)0); + + /* + * Set the return code + */ + if (rc == -1) + rc = errno; + else + rc = EINVAL; + } + + return(rc); +} diff --git a/usr.sbin/atm/scspd/scsp_print.c b/usr.sbin/atm/scspd/scsp_print.c new file mode 100644 index 0000000..4655077 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_print.c @@ -0,0 +1,1315 @@ +/* + * + * =================================== + * 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_print.c,v 1.5 1998/08/13 20:11:16 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Print routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_print.c,v 1.5 1998/08/13 20:11:16 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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" + + +/* + * Indent string + */ +#define MIN_INDENT 2 +#define MAX_INDENT 64 +static char indent[MAX_INDENT + 1]; + + +/* + * Value-name translation table entry + */ +struct type_name { + char *name; + u_char type; +}; +typedef struct type_name Type_name; + + +/* + * SCSP name-type tables + */ +static Type_name if_msg_types[] = { + { "Config Request", SCSP_CFG_REQ }, + { "Config Response", SCSP_CFG_RSP }, + { "Cache Indication", SCSP_CACHE_IND }, + { "Cache Response", SCSP_CACHE_RSP }, + { "Solicit Indication", SCSP_SOLICIT_IND }, + { "Solicit Response", SCSP_SOLICIT_RSP }, + { "Cache Update Indication", SCSP_UPDATE_IND }, + { "Cache Update Request", SCSP_UPDATE_REQ }, + { "Cache Update Response", SCSP_UPDATE_RSP }, + { (char *)0, 0 } +}; + +static Type_name msg_types[] = { + { "Cache Alignment", SCSP_CA_MSG }, + { "CSU Request", SCSP_CSU_REQ_MSG }, + { "CSU Reply", SCSP_CSU_REPLY_MSG }, + { "CSU Solicit", SCSP_CSUS_MSG }, + { "Hello", SCSP_HELLO_MSG }, + { (char *)0, 0 } +}; + +static Type_name proto_types[] = { + { "ATMARP", SCSP_PROTO_ATMARP }, + { "NHRP", SCSP_PROTO_NHRP }, + { "MARS", SCSP_PROTO_MARS }, + { "DHCP", SCSP_PROTO_DHCP }, + { "LNNI", SCSP_PROTO_LNNI }, + { (char *)0, 0 } +}; + +static Type_name ext_types[] = { + { "End of Extensions", SCSP_EXT_END }, + { "Authentication", SCSP_EXT_AUTH }, + { "Vendor Private", SCSP_EXT_VENDOR }, + { (char *)0, 0 } +}; + +static Type_name hfsm_state_names[] = { + { "Down", SCSP_HFSM_DOWN }, + { "Waiting", SCSP_HFSM_WAITING }, + { "Unidirectional", SCSP_HFSM_UNI_DIR }, + { "Bidirectional", SCSP_HFSM_BI_DIR }, + { (char *)0, 0 } +}; + +static Type_name hfsm_event_names[] = { + { "VC open", SCSP_HFSM_VC_ESTAB }, + { "VC closed", SCSP_HFSM_VC_CLOSED }, + { "Hello timer", SCSP_HFSM_HELLO_T }, + { "Receive timer", SCSP_HFSM_RCV_T }, + { "Msg received", SCSP_HFSM_RCVD }, + { (char *)0, 0 } +}; + +static Type_name cafsm_state_names[] = { + { "Down", SCSP_CAFSM_DOWN }, + { "Master/Slave negotiation", SCSP_CAFSM_NEG }, + { "Master", SCSP_CAFSM_MASTER }, + { "Slave", SCSP_CAFSM_SLAVE }, + { "Update cache", SCSP_CAFSM_UPDATE }, + { "Aligned", SCSP_CAFSM_ALIGNED }, + { (char *)0, 0 } +}; + +static Type_name cafsm_event_names[] = { + { "Hello FSM up", SCSP_CAFSM_HELLO_UP }, + { "Hello FSM down", SCSP_CAFSM_HELLO_DOWN }, + { "CA received", SCSP_CAFSM_CA_MSG }, + { "CSU Solicit received", SCSP_CAFSM_CSUS_MSG }, + { "CSU Request received", SCSP_CAFSM_CSU_REQ }, + { "CSU Reply received", SCSP_CAFSM_CSU_REPLY }, + { "CA timer", SCSP_CAFSM_CA_T }, + { "CSUS timer", SCSP_CAFSM_CSUS_T }, + { "CSU timer", SCSP_CAFSM_CSU_T }, + { "Cache Update", SCSP_CAFSM_CACHE_UPD }, + { "Cache Response", SCSP_CAFSM_CACHE_RSP }, + { (char *)0, 0 } +}; + +static Type_name cifsm_state_names[] = { + { "Null", SCSP_CIFSM_NULL }, + { "Summarize", SCSP_CIFSM_SUM }, + { "Update", SCSP_CIFSM_UPD }, + { "Aligned", SCSP_CIFSM_ALIGN }, + { (char *)0, 0 } +}; + +static Type_name cifsm_event_names[] = { + { "CA FSM down", SCSP_CIFSM_CA_DOWN }, + { "CA FSM to Summarize",SCSP_CIFSM_CA_SUMM }, + { "CA FSM to Update", SCSP_CIFSM_CA_UPD }, + { "CA FSM to Aligned", SCSP_CIFSM_CA_ALIGN }, + { "Solicit Rsp", SCSP_CIFSM_SOL_RSP }, + { "Update Req", SCSP_CIFSM_UPD_REQ }, + { "Update Rsp", SCSP_CIFSM_UPD_RSP }, + { "CSU Request", SCSP_CIFSM_CSU_REQ }, + { "CSU Reply", SCSP_CIFSM_CSU_REPLY }, + { "CSU Solicit", SCSP_CIFSM_CSU_SOL }, + { (char *)0, 0 } +}; + +static Type_name atmarp_state_names[] = { + { "New", SCSP_ASTATE_NEW }, + { "Updated", SCSP_ASTATE_UPD }, + { "Deleted", SCSP_ASTATE_DEL }, + { (char *)0, 0 } +}; + + +/* + * Initialize the indent string + * + * Arguments: + * none + * + * Returns: + * none + * + */ +static void +init_indent() +{ + indent[0] = '\0'; +} + + +/* + * Increment the indent string + * + * Arguments: + * none + * + * Returns: + * none + * + */ +static void +inc_indent() +{ + if (strlen(indent) >= MAX_INDENT) + return; + strcat(indent, " "); +} + + +/* + * Decrement the indent string + * + * Arguments: + * none + * + * Returns: + * none + * + */ +static void +dec_indent() +{ + if (strlen(indent) < MIN_INDENT) + return; + indent[strlen(indent) - 2] = '\0'; +} + + + +/* + * Search for a type in a name-type table + * + * Arguments: + * type the value being searched for + * tbl pointer to the table to search + * + * Returns: + * pointer to a string identifying the type + * + */ +static char * +scsp_type_name(type, tbl) + u_char type; + Type_name *tbl; +{ + int i; + + /* + * Search the table + */ + for (i = 0; tbl[i].name != (char *)0 && tbl[i].type != type; + i++) + ; + + /* + * Check the result and return the appropriate value + */ + if (tbl[i].name) + return(tbl[i].name); + else + return("-"); +} + + +/* + * Format a Hello FSM state name + * + * Arguments: + * state the state + * + * Returns: + * pointer to a string identifying the state + * + */ +char * +format_hfsm_state(state) + int state; +{ + return(scsp_type_name((u_char)state, hfsm_state_names)); +} + + +/* + * Format a Hello FSM event name + * + * Arguments: + * event the event + * + * Returns: + * pointer to a string identifying the event + * + */ +char * +format_hfsm_event(event) + int event; +{ + char *cp; + + cp = scsp_type_name((u_char)event, hfsm_event_names); + return(cp); +} + + +/* + * Format a CA FSM state name + * + * Arguments: + * state the state + * + * Returns: + * pointer to a string identifying the state + * + */ +char * +format_cafsm_state(state) + int state; +{ + return(scsp_type_name((u_char)state, cafsm_state_names)); +} + + +/* + * Format a CA FSM event name + * + * Arguments: + * event the event + * + * Returns: + * pointer to a string identifying the event + * + */ +char * +format_cafsm_event(event) + int event; +{ + return(scsp_type_name((u_char)event, cafsm_event_names)); +} + + +/* + * Format a client interface FSM state name + * + * Arguments: + * state the state + * + * Returns: + * pointer to a string identifying the state + * + */ +char * +format_cifsm_state(state) + int state; +{ + return(scsp_type_name((u_char)state, cifsm_state_names)); +} + + +/* + * Format a client interface FSM event name + * + * Arguments: + * event the event + * + * Returns: + * pointer to a string identifying the event + * + */ +char * +format_cifsm_event(event) + int event; +{ + return(scsp_type_name((u_char)event, cifsm_event_names)); +} + + +/* + * Print a Sender or Receiver ID structure + * + * Arguments: + * fp file to print message to + * idp pointer to ID to be printed + * + * Returns: + * none + * + */ +void +print_scsp_id(fp, idp) + FILE *fp; + Scsp_id *idp; +{ + int i; + + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + (u_long)idp->next); + fprintf(fp, "%sLength: %d\n", indent, + idp->id_len); + fprintf(fp, "%sID: 0x", indent); + for (i = 0; i < idp->id_len; i++) + fprintf(fp, "%02x ", idp->id[i]); + fprintf(fp, "\n"); + dec_indent(); +} + + +/* + * Print a Cache Key structure + * + * Arguments: + * fp file to print message to + * ckp pointer to cache key structure + * + * Returns: + * none + * + */ +void +print_scsp_cache_key(fp, ckp) + FILE *fp; + Scsp_ckey *ckp; +{ + int i; + + inc_indent(); + fprintf(fp, "%sLength: %d\n", indent, + ckp->key_len); + fprintf(fp, "%sKey: 0x", indent); + for (i = 0; i < ckp->key_len; i++) + fprintf(fp, "%02x ", ckp->key[i]); + fprintf(fp, "\n"); + dec_indent(); +} + + +/* + * Print the mandatory common part of a message + * + * Arguments: + * fp file to print message to + * mcp pointer to mandatory common part structure + * + * Returns: + * none + * + */ +static void +print_scsp_mcp(fp, mcp) + FILE *fp; + Scsp_mcp *mcp; +{ + inc_indent(); + fprintf(fp, "%sProtocol ID: %s (0x%02x)\n", indent, + scsp_type_name(mcp->pid, proto_types), + mcp->pid); + fprintf(fp, "%sServer Group ID: %d\n", indent, mcp->sgid); + fprintf(fp, "%sFlags: 0x%04x\n", indent, + mcp->flags); + fprintf(fp, "%sRecord Count: %d\n", indent, + mcp->rec_cnt); + fprintf(fp, "%sSender ID:\n", indent); + print_scsp_id(fp, &mcp->sid); + fprintf(fp, "%sReceiver ID:\n", indent); + print_scsp_id(fp, &mcp->rid); + dec_indent(); +} + + +/* + * Print an extension + * + * Arguments: + * fp file to print message to + * exp pointer to extension + * + * Returns: + * none + * + */ +static void +print_scsp_ext(fp, exp) + FILE *fp; + Scsp_ext *exp; +{ + int i; + u_char *cp; + + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + exp->next); + fprintf(fp, "%sType: %s (0x%02x)\n", indent, + scsp_type_name(exp->type, ext_types), + exp->type); + fprintf(fp, "%sLength: %d\n", indent, exp->len); + if (exp->len) { + fprintf(fp, "%sValue: 0x", indent); + cp = (u_char *)((caddr_t)exp + sizeof(Scsp_ext)); + for (i = 0; i < exp->len; i++) + fprintf(fp, "%02x ", *cp++); + fprintf(fp, "\n"); + } + dec_indent(); +} + + +/* + * Print an ATMARP Cache State Advertisement record + * + * Arguments: + * fp file to print message to + * acsp pointer to extension + * + * Returns: + * none + * + */ +static void +print_scsp_atmarp_csa(fp, acsp) + FILE *fp; + Scsp_atmarp_csa *acsp; +{ + inc_indent(); + fprintf(fp, "%sState: %s (%d)\n", indent, + scsp_type_name(acsp->sa_state, + atmarp_state_names), + acsp->sa_state); + fprintf(fp, "%sSource ATM addr: %s\n", indent, + format_atm_addr(&acsp->sa_sha)); + fprintf(fp, "%sSource ATM subaddr: %s\n", indent, + format_atm_addr(&acsp->sa_ssa)); + fprintf(fp, "%sSource IP addr: %s\n", indent, + format_ip_addr(&acsp->sa_spa)); + fprintf(fp, "%sTarget ATM addr: %s\n", indent, + format_atm_addr(&acsp->sa_tha)); + fprintf(fp, "%sTarget ATM subaddr: %s\n", indent, + format_atm_addr(&acsp->sa_tsa)); + fprintf(fp, "%sTarget IP addr: %s\n", indent, + format_ip_addr(&acsp->sa_tpa)); + dec_indent(); +} + + +/* + * Print a Cache State Advertisement record or + * Cache State Advertisement Summary record + * + * Arguments: + * fp file to print message to + * csap pointer to CSA or CSAS + * + * Returns: + * none + * + */ +static void +print_scsp_csa(fp, csap) + FILE *fp; + Scsp_csa *csap; +{ + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + (u_long)csap->next); + fprintf(fp, "%sHops: %d\n", indent, csap->hops); + fprintf(fp, "%sNull Flag: %s\n", indent, + csap->null ? "True" : "False"); + fprintf(fp, "%sSequence no.: %d (0x%x)\n", + indent, csap->seq, csap->seq); + fprintf(fp, "%sCache Key:\n", indent); + print_scsp_cache_key(fp, &csap->key); + fprintf(fp, "%sOriginator ID:\n", indent); + print_scsp_id(fp, &csap->oid); + if (csap->atmarp_data) { + fprintf(fp, "%sATMARP data:\n", indent); + print_scsp_atmarp_csa(fp, csap->atmarp_data); + } + dec_indent(); +} + + +/* + * Print a Cache Alignment message + * + * Arguments: + * fp file to print message to + * cap pointer to extension + * + * Returns: + * none + * + */ +static void +print_scsp_ca(fp, cap) + FILE *fp; + Scsp_ca *cap; +{ + int n; + Scsp_csa *csap; + + inc_indent(); + fprintf(fp, "%sCA Seq. No.: %d\n", indent, + cap->ca_seq); + fprintf(fp, "%sM bit: %s\n", indent, + cap->ca_m ? "True" : "False"); + fprintf(fp, "%sI bit: %s\n", indent, + cap->ca_i ? "True" : "False"); + fprintf(fp, "%sO bit: %s\n", indent, + cap->ca_o ? "True" : "False"); + fprintf(fp, "%sMandatory Common Part:\n", indent); + print_scsp_mcp(fp, &cap->ca_mcp); + for (csap = cap->ca_csa_rec, n = 1; csap; + csap = csap->next, n++) { + fprintf(fp, "%sCSA Record %d (0x%x):\n", indent, n, + (u_long)csap); + print_scsp_csa(fp, csap); + } + dec_indent(); +} + + +/* + * Print a Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message + * + * Arguments: + * fp file to print message to + * csup pointer to CSU message + * + * Returns: + * none + * + */ +static void +print_scsp_csu(fp, csup) + FILE *fp; + Scsp_csu_msg *csup; +{ + int i; + Scsp_csa *csap; + + inc_indent(); + fprintf(fp, "%sMandatory Common Part:\n", indent); + print_scsp_mcp(fp, &csup->csu_mcp); + for (csap = csup->csu_csa_rec, i = 1; csap; + csap = csap->next, i++) { + fprintf(fp, "%sCSA Record %d:\n", indent, i); + print_scsp_csa(fp, csap); + } + dec_indent(); +} + + +/* + * Print a Hello message + * + * Arguments: + * fp file to print message to + * hp pointer to hello message + * + * Returns: + * none + * + */ +static void +print_scsp_hello(fp, hp) + FILE *fp; + Scsp_hello *hp; +{ + Scsp_id *ridp; + + inc_indent(); + fprintf(fp, "%sHello Interval: %d\n", indent, + hp->hello_int); + fprintf(fp, "%sDead Factor: %d\n", indent, + hp->dead_factor); + fprintf(fp, "%sFamily ID: %d\n", indent, + hp->family_id); + fprintf(fp, "%sMandatory Common Part:\n", indent); + print_scsp_mcp(fp, &hp->hello_mcp); + ridp = hp->hello_mcp.rid.next; + if (ridp) { + fprintf(fp, "%sAdditional Receiver IDs:\n", indent); + for (; ridp; ridp = ridp->next) + print_scsp_id(fp, ridp); + } + dec_indent(); +} + + +#ifdef NOTDEF +/* + * NHRP-specific Cache State Advertisement record + */ +struct scsp_nhrp_csa { + u_char req_id; /* Request ID */ + u_char state; /* State */ + u_char pref_len; /* Prefix length */ + u_short flags; /* See below */ + u_short mtu; /* Maximim transmission unit */ + u_short hold_time; /* Entry holding time */ + u_char caddr_tlen; /* Client addr type/length */ + u_char csaddr_tlen; /* Client subaddr type/length */ + u_char cproto_len; /* Client proto addr length */ + u_char pref; /* Preference */ + Atm_addr caddr; /* Client address */ + Atm_addr csaddr; /* Client subaddress */ + struct in_addr cproto_addr; /* Client protocol address */ +}; +typedef struct scsp_nhrp Scsp_nhrp; + +#define SCSP_NHRP_UNIQ 0x8000 +#define SCSP_NHRP_ARP 0x4000 + +#endif + + +/* + * Print an SCSP message + * + * Arguments: + * fp file to print message to + * msg pointer to message to be printed + * + * Returns: + * none + * + */ +void +print_scsp_msg(fp, msg) + FILE *fp; + Scsp_msg *msg; +{ + int n; + Scsp_ext *exp; + + /* + * Initialize + */ + init_indent(); + + /* + * Print the message type + */ + inc_indent(); + fprintf(fp, "%sMessage type: %s (0x%02x)\n", indent, + scsp_type_name(msg->sc_msg_type, msg_types), + msg->sc_msg_type); + + /* + * Print the body of the message + */ + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + print_scsp_ca(fp, msg->sc_ca); + break; + case SCSP_CSU_REQ_MSG: + case SCSP_CSU_REPLY_MSG: + case SCSP_CSUS_MSG: + print_scsp_csu(fp, msg->sc_csu_msg); + break; + case SCSP_HELLO_MSG: + print_scsp_hello(fp, msg->sc_hello); + break; + } + + /* + * Print any extensions + */ + for (exp = msg->sc_ext, n = 1; exp; exp = exp->next, n++) { + fprintf(fp, "%sExtension %d:\n", indent, n); + print_scsp_ext(fp, exp); + } + dec_indent(); + + (void)fflush(fp); +} + + +/* + * Print an SCSP ATMARP message + * + * Arguments: + * fp file to print message to + * acp pointer to ATMARP message + * + * Returns: + * none + * + */ +static void +print_scsp_if_atmarp(fp, amp) + FILE *fp; + Scsp_atmarp_msg *amp; +{ + inc_indent(); + fprintf(fp, "%sState: %s (%d)\n", indent, + scsp_type_name(amp->sa_state, + atmarp_state_names), + amp->sa_state); + fprintf(fp, "%sCached protocol addr: %s\n", indent, + format_ip_addr(&->sa_cpa)); + fprintf(fp, "%sCached ATM addr: %s\n", indent, + format_atm_addr(&->sa_cha)); + fprintf(fp, "%sCached ATM subaddr: %s\n", indent, + format_atm_addr(&->sa_csa)); + fprintf(fp, "%sCache key:\n", indent); + print_scsp_cache_key(fp, &->sa_key); + fprintf(fp, "%sOriginator ID:\n", indent); + print_scsp_id(fp, &->sa_oid); + fprintf(fp, "%sSequence number: %d (0x%08x)\n", indent, + amp->sa_seq, (u_long)amp->sa_seq); + dec_indent(); +} + + +/* + * Print an SCSP client interface message + * + * Arguments: + * fp file to print message to + * imsg pointer to message to be printed + * + * Returns: + * none + * + */ +void +print_scsp_if_msg(fp, imsg) + FILE *fp; + Scsp_if_msg *imsg; +{ + int len; + Scsp_atmarp_msg *ap; + + /* + * Initialize + */ + init_indent(); + fprintf(fp, "SCSP Client Interface Message at 0x%x\n", + (u_long)imsg); + + /* + * Print the message header + */ + inc_indent(); + fprintf(fp, "%sMessage type: %s (0x%02x)\n", indent, + scsp_type_name(imsg->si_type, if_msg_types), + imsg->si_type); + fprintf(fp, "%sResponse code: %d\n", indent, + imsg->si_rc); + fprintf(fp, "%sProtocol type: %s (%d)\n", indent, + scsp_type_name(imsg->si_proto, proto_types), + imsg->si_proto); + fprintf(fp, "%sLength: %d\n", indent, + imsg->si_len); + fprintf(fp, "%sToken: 0x%x\n", indent, + imsg->si_tok); + + /* + * Print the body of the message + */ + switch(imsg->si_type) { + case SCSP_CFG_REQ: + fprintf(fp, "%sInterface: %s\n", indent, + imsg->si_cfg.atmarp_netif); + break; + case SCSP_CACHE_RSP: + case SCSP_UPDATE_IND: + case SCSP_UPDATE_REQ: + len = imsg->si_len - sizeof(Scsp_if_msg_hdr); + ap = &imsg->si_atmarp; + while (len) { + switch(imsg->si_proto) { + case SCSP_PROTO_ATMARP: + fprintf(fp, "%sATMARP CSA:\n", indent); + print_scsp_if_atmarp(fp, ap); + len -= sizeof(Scsp_atmarp_msg); + ap++; + break; + case SCSP_PROTO_NHRP: + case SCSP_PROTO_MARS: + case SCSP_PROTO_DHCP: + case SCSP_PROTO_LNNI: + default: + fprintf(fp, "Protocol type not implemented\n"); + break; + } + } + break; + } + dec_indent(); + + (void)fflush(fp); +} + + +/* + * Print an SCSP pending connection block + * + * Arguments: + * fp file to print message to + * pp pointer to pending control block + * + * Returns: + * none + * + */ +void +print_scsp_pending(fp, pp) + FILE *fp; + Scsp_pending *pp; +{ + /* + * Initialize + */ + init_indent(); + + /* + * Print a header + */ + fprintf(fp, "Pending control block at 0x%x\n", (u_long)pp); + + /* + * Print the fields of the control block + */ + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + (u_long)pp->sp_next); + fprintf(fp, "%sSocket: %d\n", indent, + pp->sp_sock); + + dec_indent(); +} + + +/* + * Print an SCSP server control block + * + * Arguments: + * fp file to print message to + * ssp pointer to server control block + * + * Returns: + * none + * + */ +void +print_scsp_server(fp, ssp) + FILE *fp; + Scsp_server *ssp; +{ + /* + * Initialize + */ + init_indent(); + + /* + * Print a header + */ + fprintf(fp, "Server control block at 0x%x\n", (u_long)ssp); + + /* + * Print the fields of the client control block + */ + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + ssp->ss_next); + fprintf(fp, "%sName: %s\n", indent, + ssp->ss_name); + fprintf(fp, "%sNetwork Interface: %s\n", indent, + ssp->ss_intf); + fprintf(fp, "%sState: %d\n", indent, + ssp->ss_state); + fprintf(fp, "%sProtocol ID: 0x%x\n", indent, + ssp->ss_pid); + fprintf(fp, "%sID length: %d\n", indent, + ssp->ss_id_len); + fprintf(fp, "%sCache key length: %d\n", indent, + ssp->ss_ckey_len); + fprintf(fp, "%sServer Group ID: 0x%x\n", indent, + ssp->ss_sgid); + fprintf(fp, "%sFamily ID: 0x%x\n", indent, + ssp->ss_fid); + fprintf(fp, "%sSocket: %d\n", indent, + ssp->ss_sock); + fprintf(fp, "%sDCS Listen Socket: %d\n", indent, + ssp->ss_dcs_lsock); + fprintf(fp, "%sLocal Server ID:\n", indent); + print_scsp_id(fp, &ssp->ss_lsid); + fprintf(fp, "%sATM address: %s\n", indent, + format_atm_addr(&ssp->ss_addr)); + fprintf(fp, "%sATM subaddress: %s\n", indent, + format_atm_addr(&ssp->ss_subaddr)); + fprintf(fp, "%sInterface MTU: %d\n", indent, + ssp->ss_mtu); + fprintf(fp, "%sMark: %d\n", indent, + ssp->ss_mark); + dec_indent(); +} + + +/* + * Print an SCSP client cache summary entry control block + * + * Arguments: + * fp file to print message to + * csep pointer to summary entry + * + * Returns: + * none + * + */ +void +print_scsp_cse(fp, csep) + FILE *fp; + Scsp_cse *csep; +{ + /* + * Print the fields of the cache summary entry + */ + inc_indent(); + fprintf(fp, "%sNext CSE: 0x%x\n", indent, + (u_long)csep->sc_next); + fprintf(fp, "%sCSA sequence no.: %d (0x%x)\n", indent, + csep->sc_seq, csep->sc_seq); + fprintf(fp, "%sCache key:\n", indent); + print_scsp_cache_key(fp, &csep->sc_key); + fprintf(fp, "%sOrigin ID:\n", indent); + print_scsp_id(fp, &csep->sc_oid); + dec_indent(); +} + + +/* + * Print an SCSP CSU Request retransmission control block + * + * Arguments: + * fp file to print message to + * csurp pointer to retransmission entry + * + * Returns: + * none + * + */ +void +print_scsp_csu_rexmt(fp, rxp) + FILE *fp; + Scsp_csu_rexmt *rxp; +{ + int i; + Scsp_csa *csap; + + inc_indent(); + fprintf(fp, "%sNext CSU Req rexmt: 0x%x\n", indent, + (u_long)rxp->sr_next); + fprintf(fp, "%sDCS address: 0x%x\n", indent, + (u_long)rxp->sr_dcs); + for (csap = rxp->sr_csa, i = 1; csap; + csap = csap->next, i++) { + fprintf(fp, "%sCSA %d:\n", indent, i); + print_scsp_csa(fp, csap); + } + dec_indent(); +} + + +/* + * Print an SCSP DCS control block + * + * Arguments: + * fp file to print message to + * dcsp pointer to DCS control block + * + * Returns: + * none + * + */ +void +print_scsp_dcs(fp, dcsp) + FILE *fp; + Scsp_dcs *dcsp; +{ + Scsp_csa *csap; + Scsp_cse *csep; + Scsp_csu_rexmt *rxp; + + /* + * Initialize + */ + init_indent(); + + /* + * Print a header + */ + fprintf(fp, "DCS control block at 0x%x\n", (u_long)dcsp); + + /* + * Print the fields of the DCS control block + */ + inc_indent(); + fprintf(fp, "%sNext DCS block: 0x%x\n", indent, + (u_long)dcsp->sd_next); + fprintf(fp, "%sServer control block: 0x%x\n", indent, + (u_long)dcsp->sd_server); + fprintf(fp, "%sDCS ID:\n", indent); + print_scsp_id(fp, &dcsp->sd_dcsid); + fprintf(fp, "%sDCS address: %s\n", indent, + format_atm_addr(&dcsp->sd_addr)); + fprintf(fp, "%sDCS subaddress %s\n", indent, + format_atm_addr(&dcsp->sd_subaddr)); + fprintf(fp, "%sSocket: %d\n", indent, + dcsp->sd_sock); + fprintf(fp, "%sOpen VCC Retry Timer:\n", indent); + fprintf(fp, "%sHello FSM State: %s\n", indent, + format_hfsm_state(dcsp->sd_hello_state)); + fprintf(fp, "%sHello Interval: %d\n", indent, + dcsp->sd_hello_int); + fprintf(fp, "%sHello Dead Factor: %d\n", indent, + dcsp->sd_hello_df); + fprintf(fp, "%sHello Rcvd: %d\n", indent, + dcsp->sd_hello_rcvd); + fprintf(fp, "%sCA FSM State: %s\n", indent, + format_cafsm_state(dcsp->sd_ca_state)); + fprintf(fp, "%sCA Seq. No.: 0x%x\n", indent, + dcsp->sd_ca_seq); + fprintf(fp, "%sCA Rexmit Int: %d\n", indent, + dcsp->sd_ca_rexmt_int); + fprintf(fp, "%sCA Retransmit Msg: 0x%x\n", indent, + (u_long)dcsp->sd_ca_rexmt_msg); + fprintf(fp, "%sCSASs to send: ", indent); + if (dcsp->sd_ca_csas == (Scsp_cse *)0) { + fprintf(fp, "Empty\n"); + } else { + fprintf(fp, "0x%x\n", (u_long) dcsp->sd_ca_csas); + } + fprintf(fp, "%sCSUS Rexmit Int: %d\n", indent, + dcsp->sd_csus_rexmt_int); + fprintf(fp, "%sCache Request List: ", indent); + if (dcsp->sd_crl == (Scsp_csa *)0) { + fprintf(fp, "Empty\n"); + } else { + fprintf(fp, "0x%x\n", dcsp->sd_crl); + } + fprintf(fp, "%sCSUS Rexmit Msg: 0x%x\n", indent, + (u_long)dcsp->sd_csus_rexmt_msg); + fprintf(fp, "%sCSA Hop count: %d\n", indent, + dcsp->sd_hops); + fprintf(fp, "%sCSAs Pending ACK: 0x%x\n", indent, + (u_long)dcsp->sd_csu_ack_pend); + fprintf(fp, "%sCSAs ACKed: 0x%x\n", indent, + (u_long)dcsp->sd_csu_ack); + fprintf(fp, "%sCSU Req Rexmit Int: %d\n", indent, + dcsp->sd_csu_rexmt_int); + fprintf(fp, "%sCSU Req Rexmit Max: %d\n", indent, + dcsp->sd_csu_rexmt_max); + fprintf(fp, "%sCSU Req Rexmit Queue ", indent); + if (!dcsp->sd_csu_rexmt) { + fprintf(fp, "Empty\n"); + } else { + fprintf(fp, "0x%x\n", (u_long)dcsp->sd_csu_rexmt); + } + fprintf(fp, "%sClient I/F state: %d\n", indent, + dcsp->sd_client_state); + + /* + * Print the list of CSASs waiting to be sent + */ + if (dcsp->sd_ca_csas) { + fprintf(fp, "\n%sCSASs to send:", indent); + inc_indent(); + for (csep = dcsp->sd_ca_csas; csep; + csep = csep->sc_next) { + fprintf(fp, "%sCache summary entry at 0x%x\n", + indent, + (u_long)csep); + print_scsp_cse(fp, csep); + } + dec_indent(); + } + + /* + * Print the Cache Request List + */ + if (dcsp->sd_crl) { + fprintf(fp, "\n%sCache Request List:\n", indent); + inc_indent(); + for (csap = dcsp->sd_crl; csap; csap = csap->next) { + fprintf(fp, "%sCSA at 0x%x\n", indent, + (u_long)csap); + print_scsp_csa(fp, csap); + } + dec_indent(); + } + + /* + * Print the CSU retransmit queue + */ + if (dcsp->sd_csu_rexmt) { + fprintf(fp, "\n%sCSU Req Rexmit Queue:\n", indent); + inc_indent(); + for (rxp = dcsp->sd_csu_rexmt; rxp; + rxp = rxp->sr_next) { + fprintf(fp, "%sCSU Rexmit Block at 0x%x\n", + indent, (u_long)csap); + print_scsp_csu_rexmt(fp, rxp); + } + dec_indent(); + } + + dec_indent(); +} + + +/* + * Print SCSP's control blocks + * + * Arguments: + * none + * + * Returns: + * None + * + */ +void +print_scsp_dump() +{ + int i; + Scsp_server *ssp; + Scsp_dcs *dcsp; + Scsp_cse *scp; + Scsp_csu_rexmt *rxp; + Scsp_pending *pp; + FILE *df; + char fname[64]; + static int dump_no = 0; + + /* + * Build a file name + */ + UM_ZERO(fname, sizeof(fname)); + sprintf(fname, "/tmp/scspd.%d.%03d.out", getpid(), dump_no++); + + /* + * Open the output file + */ + df = fopen(fname, "w"); + if (df == (FILE *)0) + return; + + /* + * Dump the server control blocks + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + print_scsp_server(df, ssp); + fprintf(df, "\n"); + + /* + * Print the client's cache summary + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (scp = ssp->ss_cache[i]; scp; + scp = scp->sc_next) { + print_scsp_cse(df, scp); + fprintf(df, "\n"); + } + } + + /* + * Print the client's DCS control blocks + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + print_scsp_dcs(df, dcsp); + fprintf(df, "\n\n"); + } + fprintf(df, "\n\n"); + } + + /* + * Print the pending connection blocks + */ + for (pp = scsp_pending_head; pp; pp = pp->sp_next) { + print_scsp_pending(df, pp); + fprintf(df, "\n"); + } + + /* + * Close the output file + */ + (void)fclose(df); +} diff --git a/usr.sbin/atm/scspd/scsp_socket.c b/usr.sbin/atm/scspd/scsp_socket.c new file mode 100644 index 0000000..83f41cd --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_socket.c @@ -0,0 +1,1349 @@ +/* + * + * =================================== + * 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_socket.c,v 1.6 1998/08/21 18:08:24 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP socket management routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_socket.c,v 1.6 1998/08/21 18:08:24 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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" + + +/* + * Local variables + */ +static struct t_atm_llc llc_scsp = { + T_ATM_LLC_SHARING, + 8, + {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x5e, 0x00, 0x05} +}; + +static struct t_atm_aal5 aal5 = { + 0, /* forward_max_SDU_size */ + 0, /* backward_max_SDU_size */ + 0 /* SSCS_type */ +}; + +static struct t_atm_traffic traffic = { + { /* forward */ + T_ATM_ABSENT, /* PCR_high_priority */ + 0, /* PCR_all_traffic */ + T_ATM_ABSENT, /* SCR_high_priority */ + T_ATM_ABSENT, /* SCR_all_traffic */ + T_ATM_ABSENT, /* MBS_high_priority */ + T_ATM_ABSENT, /* MBS_all_traffic */ + T_NO /* tagging */ + }, + { /* backward */ + T_ATM_ABSENT, /* PCR_high_priority */ + 0, /* PCR_all_traffic */ + T_ATM_ABSENT, /* SCR_high_priority */ + T_ATM_ABSENT, /* SCR_all_traffic */ + T_ATM_ABSENT, /* MBS_high_priority */ + T_ATM_ABSENT, /* MBS_all_traffic */ + T_NO /* tagging */ + }, + T_YES /* best_effort */ +}; + +static struct t_atm_bearer bearer = { + T_ATM_CLASS_X, /* bearer_class */ + T_ATM_NULL, /* traffic_type */ + T_ATM_NULL, /* timing_requirements */ + T_NO, /* clipping_susceptibility */ + T_ATM_1_TO_1 /* connection_configuration */ +}; + +static struct t_atm_qos qos = { + T_ATM_NETWORK_CODING, /* coding_standard */ + { /* forward */ + T_ATM_QOS_CLASS_0 /* qos_class */ + }, + { /* backward */ + T_ATM_QOS_CLASS_0 /* qos_class */ + } +}; + +static struct t_atm_app_name appname = { + "SCSP" +}; + + +/* + * Find a DCS, given its socket + * + * Arguments: + * sd socket descriptor + * + * Returns: + * 0 not found + * address of DCS block corresponding to socket + * + */ +Scsp_dcs * +scsp_find_dcs(sd) + int sd; +{ + Scsp_server *ssp; + Scsp_dcs *dcsp; + + /* + * Loop through the list of servers + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + /* + * Check all the DCSs chained from each server + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (dcsp->sd_sock == sd) + break; + } + } + + return(dcsp); +} + + +/* + * Find a server, given its socket + * + * Arguments: + * sd socket descriptor + * + * Returns: + * 0 not found + * address of server block corresponding to socket + * + */ +Scsp_server * +scsp_find_server(sd) + int sd; +{ + Scsp_server *ssp; + + /* + * Loop through the list of servers + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_sock == sd) + break; + } + + return(ssp); +} + + +/* + * Connect to a directly connected server + * + * Arguments: + * dcsp pointer to DCS block for server + * + * Returns: + * 0 success (dcsp->sd_sock is set) + * else errno indicating reason for failure + * + */ +int +scsp_dcs_connect(dcsp) + Scsp_dcs *dcsp; + +{ + int rc, sd; + struct sockaddr_atm DCS_addr; + + /* + * If the DCS already has an open connection, just return + */ + if (dcsp->sd_sock != -1) { + return(0); + } + + /* + * Open an ATM socket + */ + sd = socket(PF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5); + if (sd == -1) { + return(ESOCKTNOSUPPORT); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set up connection parameters for SCSP connection + */ + UM_ZERO(&DCS_addr, sizeof(DCS_addr)); +#if (defined(BSD) && (BSD >= 199103)) + DCS_addr.satm_len = sizeof(DCS_addr); +#endif + DCS_addr.satm_family = AF_ATM; + DCS_addr.satm_addr.t_atm_sap_addr.SVE_tag_addr = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_addr.SVE_tag_selector = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_addr.address_format = + dcsp->sd_addr.address_format; + DCS_addr.satm_addr.t_atm_sap_addr.address_length = + dcsp->sd_addr.address_length; + UM_COPY(dcsp->sd_addr.address, + DCS_addr.satm_addr.t_atm_sap_addr.address, + dcsp->sd_addr.address_length); + + DCS_addr.satm_addr.t_atm_sap_layer2.SVE_tag = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_layer2.ID_type = + T_ATM_SIMPLE_ID; + DCS_addr.satm_addr.t_atm_sap_layer2.ID.simple_ID = + T_ATM_BLLI2_I8802; + + DCS_addr.satm_addr.t_atm_sap_layer3.SVE_tag = + T_ATM_ABSENT; + DCS_addr.satm_addr.t_atm_sap_appl.SVE_tag = + T_ATM_ABSENT; + + /* + * Bind the socket to our address + */ + if (bind(sd, (struct sockaddr *)&DCS_addr, + sizeof(DCS_addr))) { + rc = errno; + goto connect_fail; + } + + /* + * Set non-blocking operation + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + scsp_log(LOG_ERR, "scsp_dcs_connect: fcntl failed"); + rc = errno; + goto connect_fail; + } + + /* + * Set AAL 5 options + */ + aal5.forward_max_SDU_size = dcsp->sd_server->ss_mtu; + aal5.backward_max_SDU_size = dcsp->sd_server->ss_mtu; + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_AAL5, (caddr_t)&aal5, + sizeof(aal5)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set traffic options + */ + switch(dcsp->sd_server->ss_media) { + case MEDIA_TAXI_100: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI100; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI100; + break; + case MEDIA_TAXI_140: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI140; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI140; + break; + case MEDIA_OC3C: + case MEDIA_UTP155: + traffic.forward.PCR_all_traffic = ATM_PCR_OC3C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC3C; + break; + case MEDIA_OC12C: + traffic.forward.PCR_all_traffic = ATM_PCR_OC12C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC12C; + break; + } + + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_TRAFFIC, + (caddr_t)&traffic, sizeof(traffic)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set bearer capability options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_BEARER_CAP, + (caddr_t)&bearer, sizeof(bearer)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set QOS options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_QOS, + (caddr_t)&qos, sizeof(qos)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set LLC identifier + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_LLC, + (caddr_t)&llc_scsp, sizeof(llc_scsp)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Connect to DCS + */ + if (connect(sd, (struct sockaddr *)&DCS_addr, + sizeof(DCS_addr)) < 0 && + errno != EINPROGRESS) { + rc = errno; + goto connect_fail; + } + + /* + * Set return values + */ + dcsp->sd_sock = sd; + return(0); + +connect_fail: + /* + * Close the socket if something didn't work + */ + (void)close(sd); + dcsp->sd_sock = -1; + if (rc == 0) + rc = EFAULT; + return(rc); +} + + +/* + * Listen for ATM connections from DCSs + * + * Arguments: + * None + * + * Returns: + * sock socket which is listening (also set in + ssp->ss_dcs_lsock) + * -1 error encountered (reason in errno) + * + */ +int +scsp_dcs_listen(ssp) + Scsp_server *ssp; +{ + int rc, sd; + struct sockaddr_atm ls_addr; + + /* + * Open a socket + */ + sd = socket(PF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5); + if (sd == -1) { + rc = errno; + goto listen_fail; + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set up our address + */ + UM_ZERO(&ls_addr, sizeof(ls_addr)); +#if (defined(BSD) && (BSD >= 199103)) + ls_addr.satm_len = sizeof(ls_addr); +#endif + ls_addr.satm_family = AF_ATM; + ls_addr.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_addr.SVE_tag_selector = + T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_addr.address_format = + ssp->ss_addr.address_format; + ls_addr.satm_addr.t_atm_sap_addr.address_length = + ssp->ss_addr.address_length; + UM_COPY(ssp->ss_addr.address, + ls_addr.satm_addr.t_atm_sap_addr.address, + ssp->ss_addr.address_length); + + ls_addr.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID; + ls_addr.satm_addr.t_atm_sap_layer2.ID.simple_ID = + T_ATM_BLLI2_I8802; + + ls_addr.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT; + ls_addr.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT; + + /* + * Bind the socket to our address + */ + rc = bind(sd, (struct sockaddr *)&ls_addr, sizeof(ls_addr)); + if (rc == -1) { + rc = errno; + goto listen_fail; + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + scsp_log(LOG_ERR, "scsp_dcs_listen: fcntl failed"); + rc = errno; + goto listen_fail; + } + + /* + * Set AAL 5 options + */ + aal5.forward_max_SDU_size = ssp->ss_mtu; + aal5.backward_max_SDU_size = ssp->ss_mtu; + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_AAL5, (caddr_t)&aal5, + sizeof(aal5)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set traffic options + */ + switch(ssp->ss_media) { + case MEDIA_TAXI_100: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI100; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI100; + break; + case MEDIA_TAXI_140: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI140; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI140; + break; + case MEDIA_OC3C: + case MEDIA_UTP155: + traffic.forward.PCR_all_traffic = ATM_PCR_OC3C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC3C; + break; + case MEDIA_OC12C: + traffic.forward.PCR_all_traffic = ATM_PCR_OC12C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC12C; + break; + } + + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_TRAFFIC, + (caddr_t)&traffic, sizeof(traffic)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set bearer capability options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_BEARER_CAP, + (caddr_t)&bearer, sizeof(bearer)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set QOS options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_QOS, + (caddr_t)&qos, sizeof(qos)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set LLC identifier + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_LLC, + (caddr_t)&llc_scsp, sizeof(llc_scsp)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Listen for new connections + */ + if (listen(sd, 5) < 0) { + rc = errno; + goto listen_fail; + } + + ssp->ss_dcs_lsock = sd; + return(sd); + +listen_fail: + /* + * Close the socket if anything didn't work + */ + (void)close(sd); + if (rc == 0) + errno = EFAULT; + else + errno = rc; + ssp->ss_dcs_lsock = -1; + return(-1); +} + + +/* + * Accept a connection from a DCS + * + * Arguments: + * ssp pointer to server block + * + * Returns: + * address of DCS with new connection + * 0 failure (errno has reason) + * + */ +Scsp_dcs * +scsp_dcs_accept(ssp) + Scsp_server *ssp; +{ + int len, rc, sd; + struct sockaddr_atm dcs_sockaddr; + struct t_atm_sap_addr *dcs_addr = &dcs_sockaddr.satm_addr.t_atm_sap_addr; + Atm_addr dcs_atmaddr; + Scsp_dcs *dcsp; + + /* + * Accept the new connection + */ + len = sizeof(dcs_sockaddr); + sd = accept(ssp->ss_dcs_lsock, + (struct sockaddr *)&dcs_sockaddr, &len); + if (sd < 0) { + return((Scsp_dcs *)0); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Copy the DCS's address from the sockaddr to an Atm_addr + */ + if (dcs_addr->SVE_tag_addr != T_ATM_PRESENT) { + dcs_atmaddr.address_format = T_ATM_ABSENT; + dcs_atmaddr.address_length = 0; + } else { + dcs_atmaddr.address_format = dcs_addr->address_format; + dcs_atmaddr.address_length = dcs_addr->address_length; + UM_COPY(dcs_addr->address, dcs_atmaddr.address, + dcs_addr->address_length); + } + + /* + * Find out which DCS this connection is for + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + /* + * Compare DCS's address to address + * configured by user + */ + if (ATM_ADDR_EQUAL(&dcsp->sd_addr, + &dcs_atmaddr)) + break; + } + + /* + * Make sure we have this DCS configured + */ + if (!dcsp) { + errno = EINVAL; + goto dcs_accept_fail; + } + + /* + * Make sure we are in a state to accept the connection + */ + if (ssp->ss_state != SCSP_SS_ACTIVE) { + errno = EACCES; + goto dcs_accept_fail; + } + + /* + * Make sure we don't already have a connection to this DCS + */ + if (dcsp->sd_sock != -1) { + errno = EALREADY; + goto dcs_accept_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto dcs_accept_fail; + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + goto dcs_accept_fail; + } + + /* + * Cancel the open retry timer + */ + HARP_CANCEL(&dcsp->sd_open_t); + + /* + * Save the socket address and return the + * address of the DCS + */ + dcsp->sd_sock = sd; + return(dcsp); + +dcs_accept_fail: + /* + * An error has occured--clean up and return + */ + (void)close(sd); + return((Scsp_dcs *)0); +} + + +/* + * Read an SCSP message from a directly connected server + * + * Arguments: + * dcsp pointer to DCS block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_dcs_read(dcsp) + Scsp_dcs *dcsp; + +{ + int len, rc; + char *buff = (char *)0; + Scsp_server *ssp = dcsp->sd_server; + Scsp_msg *msg; + struct scsp_nhdr msg_hdr, *mhp; + + /* + * Get a buffer to hold the entire message + */ + len = ssp->ss_mtu; + buff = (char *)UM_ALLOC(len); + if (!buff) { + scsp_mem_err("scsp_dcs_read: ssp->ss_mtu"); + } + + /* + * Read the message + */ + len = read(dcsp->sd_sock, buff, len); + if (len < 0) { + goto dcs_read_fail; + } + + /* + * Parse the input message and pass it to the Hello FSM + */ + msg = scsp_parse_msg(buff, len); + if (msg) { + /* + * Write the message to the trace file if + * it's of a type we're tracing + */ + if (((scsp_trace_mode & SCSP_TRACE_HELLO_MSG) && + msg->sc_msg_type == SCSP_HELLO_MSG) || + ((scsp_trace_mode & SCSP_TRACE_CA_MSG) && + msg->sc_msg_type != SCSP_HELLO_MSG)) { + scsp_trace_msg(dcsp, msg, 1); + scsp_trace("\n"); + } + + /* + * Pass the message to the Hello FSM + */ + rc = scsp_hfsm(dcsp, SCSP_HFSM_RCVD, msg); + scsp_free_msg(msg); + } else { + /* + * Message was invalid. Write it to the trace file + * if we're tracing messages. + */ + if (scsp_trace_mode & (SCSP_TRACE_HELLO_MSG & + SCSP_TRACE_CA_MSG)) { + int i; + scsp_trace("Invalid message received:\n"); + scsp_trace("0x"); + for (i = 0; i < len; i++) { + scsp_trace("%02x ", (u_char)buff[i]); + } + scsp_trace("\n"); + } + } + UM_FREE(buff); + + return(0); + +dcs_read_fail: + /* + * Error on read--check for special conditions + */ + rc = errno; + if (errno == ECONNRESET) { + /* + * VCC has been closed--pass the event to + * the Hello FSM + */ + rc = scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED, + (Scsp_msg *)0); + } + if (errno == ECONNREFUSED) { + /* + * VCC open failed--set a timer and try + * again when it fires + */ + HARP_TIMER(&dcsp->sd_open_t, + SCSP_Open_Interval, + scsp_open_timeout); + rc = 0; + } + + if (buff) + UM_FREE(buff); + return(rc); +} + + +/* + * Listen for Unix connections from SCSP client servers + * + * Arguments: + * None + * + * Returns: + * sock socket which is listening + * -1 error (reason in errno) + * + */ +int +scsp_server_listen() +{ + int rc, sd; + + static struct sockaddr scsp_addr = { +#if (defined(BSD) && (BSD >= 199103)) + sizeof(struct sockaddr), /* sa_len */ +#endif + AF_UNIX, /* sa_family */ + SCSPD_SOCK_NAME /* sa_data */ + }; + + /* + * Unlink any old socket + */ + rc = unlink(SCSPD_SOCK_NAME); + if (rc < 0 && errno != ENOENT) + return(-1); + + /* + * Open a socket + */ + sd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sd == -1) { + return(-1); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Bind the socket's address + */ + rc = bind(sd, &scsp_addr, sizeof(scsp_addr)); + if (rc == -1) { + (void)close(sd); + return(-1); + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + (void)close(sd); + return(-1); + } + + /* + * Listen for new connections + */ + if (listen(sd, 5) < 0) { + (void)close(sd); + return(-1); + } + + return(sd); +} + + +/* + * Accept a connection from a server + * + * We accept a connection, but we won't know which server it is + * from until we get the configuration data from the server. We + * put the connection on a 'pending' queue and will assign it to + * a server when the config data arrives. + * + * Arguments: + * ls listening socket to accept from + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +scsp_server_accept(ls) + int ls; + +{ + int len, rc, sd; + struct sockaddr server_addr; + Scsp_pending *psp; + + /* + * Accept the new connection + */ + len = sizeof(server_addr); + sd = accept(ls, (struct sockaddr *)&server_addr, &len); + if (sd < 0) { + return(errno); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set non-blocking operation + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + (void)close(sd); + rc = errno; + } + + /* + * Put the new socket on the 'pending' queue + */ + psp = (Scsp_pending *) UM_ALLOC(sizeof(Scsp_pending)); + if (!psp) { + scsp_mem_err("scsp_server_accept: sizeof(Scsp_pending)"); + } + psp->sp_sock = sd; + LINK2TAIL(psp, Scsp_pending, scsp_pending_head, sp_next); + + return(0); +} + + +/* + * Read a server interface message from a socket + * + * Arguments: + * sd socket to read from + * + * Returns: + * msg pointer to message read + * 0 failure (errno has reason) + * + */ +Scsp_if_msg * +scsp_if_sock_read(sd) + int sd; + +{ + int len, rc; + char *buff = (char *)0; + Scsp_if_msg *msg; + Scsp_if_msg_hdr msg_hdr; + + /* + * Read the message header from the socket + */ + len = read(sd, (char *)&msg_hdr, sizeof(msg_hdr)); + if (len != sizeof(msg_hdr)) { + if (len >= 0) + errno = EINVAL; + goto socket_read_fail; + } + + /* + * Get a buffer and read the rest of the message into it + */ + buff = (char *)UM_ALLOC(msg_hdr.sh_len); + if (!buff) { + scsp_mem_err("scsp_if_sock_read: msg_hdr.sh_len"); + } + msg = (Scsp_if_msg *)buff; + msg->si_hdr = msg_hdr; + len = read(sd, &buff[sizeof(Scsp_if_msg_hdr)], + msg->si_len - sizeof(Scsp_if_msg_hdr)); + if (len != msg->si_len - sizeof(Scsp_if_msg_hdr)) { + if (len >= 0) { + errno = EINVAL; + } + goto socket_read_fail; + } + + /* + * Trace the message + */ + if (scsp_trace_mode & SCSP_TRACE_IF_MSG) { + scsp_trace("Received server I/F message:\n"); + print_scsp_if_msg(scsp_trace_file, msg); + scsp_trace("\n"); + } + + return(msg); + +socket_read_fail: + if (buff) + UM_FREE(buff); + return((Scsp_if_msg *)0); +} + + +/* + * Write a server interface message to a socket + * + * Arguments: + * sd socket to write to + * msg pointer to message to write + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +scsp_if_sock_write(sd, msg) + int sd; + Scsp_if_msg *msg; +{ + int len, rc; + + /* + * Trace the message + */ + if (scsp_trace_mode & SCSP_TRACE_IF_MSG) { + scsp_trace("Writing server I/F message:\n"); + print_scsp_if_msg(scsp_trace_file, msg); + scsp_trace("\n"); + } + + /* + * Write the message to the indicated socket + */ + len = write(sd, (char *)msg, msg->si_len); + if (len != msg->si_len) { + if (len < 0) + rc = errno; + else + rc = EINVAL; + } else { + rc = 0; + } + + return(rc); +} + + +/* + * Read data from a local server + * + * Arguments: + * ssp pointer to server block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_server_read(ssp) + Scsp_server *ssp; +{ + int rc; + Scsp_dcs *dcsp; + Scsp_if_msg *msg; + + /* + * Read the message + */ + msg = scsp_if_sock_read(ssp->ss_sock); + if (!msg) { + if (errno == EWOULDBLOCK) { + /* + * Nothing to read--just return + */ + return(0); + } else { + /* + * Error--shut down the server entry + */ + scsp_server_shutdown(ssp); + } + return(errno); + } + + /* + * Process the received message + */ + switch(msg->si_type) { + case SCSP_NOP_REQ: + /* + * Ignore a NOP + */ + break; + case SCSP_CACHE_RSP: + /* + * Summarize the server's cache and try to open + * connections to all of its DCSs + */ + scsp_process_cache_rsp(ssp, msg); + ssp->ss_state = SCSP_SS_ACTIVE; + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (scsp_dcs_connect(dcsp)) { + /* + * Connect failed -- the DCS may not + * be up yet, so we'll try again later + */ + HARP_TIMER(&dcsp->sd_open_t, + SCSP_Open_Interval, + scsp_open_timeout); + } + } + ssp->ss_state = SCSP_SS_ACTIVE; + break; + case SCSP_SOLICIT_RSP: + /* + * The server has answered our request for a particular + * entry from its cache + */ + dcsp = (Scsp_dcs *)msg->si_tok; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_SOL_RSP, (Scsp_msg *)0, + msg); + break; + case SCSP_UPDATE_REQ: + /* + * Pass the update request to the FSMs for all + * DCSs associated with the server + */ + if (ssp->ss_state == SCSP_SS_ACTIVE) { + for (dcsp = ssp->ss_dcs; dcsp; + dcsp = dcsp->sd_next) { + rc = scsp_cfsm(dcsp, SCSP_CIFSM_UPD_REQ, + (Scsp_msg *)0, msg); + } + } + break; + case SCSP_UPDATE_RSP: + /* + * Pass the update response to the FSM for the + * DCS associated with the request + */ + dcsp = (Scsp_dcs *)msg->si_tok; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_UPD_RSP, + (Scsp_msg *)0, msg); + break; + default: + scsp_log(LOG_ERR, "invalid message type %d from server", + msg->si_type); + return(EINVAL); + } + + UM_FREE(msg); + return(0); +} + + +/* + * Send a Cache Indication to a server + * + * Arguments: + * ssp pointer to server block block + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_send_cache_ind(ssp) + Scsp_server *ssp; +{ + int rc; + Scsp_if_msg *msg; + + /* + * Get storage for a server interface message + */ + msg = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!msg) { + scsp_mem_err("scsp_send_cache_ind: sizeof(Scsp_if_msg)"); + } + UM_ZERO(msg, sizeof(Scsp_if_msg)); + + /* + * Fill out the message + */ + msg->si_type = SCSP_CACHE_IND; + msg->si_rc = 0; + msg->si_proto = ssp->ss_pid; + msg->si_len = sizeof(Scsp_if_msg_hdr); + msg->si_tok = (u_long)ssp; + + /* + * Send the message + */ + rc = scsp_if_sock_write(ssp->ss_sock, msg); + UM_FREE(msg); + return(rc); +} + + +/* + * Read data from a pending server connection + * + * Arguments: + * psp pointer to pending block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_pending_read(psp) + Scsp_pending *psp; + +{ + int rc; + Scsp_server *ssp; + Scsp_dcs *dcsp; + Scsp_if_msg *msg; + + /* + * Read the message from the pending socket + */ + msg = scsp_if_sock_read(psp->sp_sock); + if (!msg) { + rc = errno; + goto pending_read_fail; + } + + /* + * Make sure this is configuration data + */ + if (msg->si_type != SCSP_CFG_REQ) { + scsp_log(LOG_ERR, "invalid message type %d from pending server", + msg->si_type); + rc = EINVAL; + goto pending_read_fail; + } + + /* + * Find the server this message is for + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (strcmp(ssp->ss_intf, msg->si_cfg.atmarp_netif) == 0) + break; + } + if (!ssp) { + scsp_log(LOG_ERR, "refused connection from server for %s", + msg->si_cfg.atmarp_netif); + rc = EINVAL; + goto config_reject; + } + + /* + * Make sure the server is ready to go + */ + rc = scsp_get_server_info(ssp); + if (rc) { + goto config_reject; + } + + /* + * Save the socket + */ + ssp->ss_sock = psp->sp_sock; + ssp->ss_state = SCSP_SS_CFG; + UNLINK(psp, Scsp_pending, scsp_pending_head, sp_next); + UM_FREE(psp); + + /* + * Listen for connections from the server's DCSs + */ + rc = scsp_dcs_listen(ssp); + if (rc < 0) { + rc = errno; + goto config_reject; + } + + /* + * Respond to the configuration message + */ + msg->si_type = SCSP_CFG_RSP; + msg->si_rc = SCSP_RSP_OK; + msg->si_len = sizeof(Scsp_if_msg_hdr); + rc = scsp_if_sock_write(ssp->ss_sock, msg); + if (rc) { + goto config_error;; + } + + /* + * Ask the server to send us its cache + */ + rc = scsp_send_cache_ind(ssp); + if (rc) { + goto config_error; + } + + UM_FREE(msg); + return(0); + +config_reject: + /* + * Respond to the configuration message + */ + msg->si_type = SCSP_CFG_RSP; + msg->si_rc = SCSP_RSP_REJ; + msg->si_len = sizeof(Scsp_if_msg_hdr); + (void)scsp_if_sock_write(ssp->ss_sock, msg); + +config_error: + if (ssp->ss_sock != -1) { + (void)close(ssp->ss_sock); + ssp->ss_sock = -1; + } + if (ssp->ss_dcs_lsock != -1) { + (void)close(ssp->ss_dcs_lsock); + ssp->ss_sock = -1; + } + ssp->ss_state = SCSP_SS_NULL; + UM_FREE(msg); + + return(rc); + +pending_read_fail: + /* + * Close the socket and free the pending read block + */ + (void)close(psp->sp_sock); + UNLINK(psp, Scsp_pending, scsp_pending_head, sp_next); + UM_FREE(psp); + if (msg) + UM_FREE(msg); + return(rc); +} diff --git a/usr.sbin/atm/scspd/scsp_subr.c b/usr.sbin/atm/scspd/scsp_subr.c new file mode 100644 index 0000000..c14195b --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_subr.c @@ -0,0 +1,1123 @@ +/* + * + * =================================== + * 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_subr.c,v 1.5 1998/08/13 20:11:16 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP subroutines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_subr.c,v 1.5 1998/08/13 20:11:16 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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_sigmgr.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> +#include <netatm/uni/unisig_var.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Hash an SCSP cache key + * + * Arguments: + * ckp pointer to an SCSP cache key structure + * + * Returns: + * hashed value + * + */ +int +scsp_hash(ckp) + Scsp_ckey *ckp; +{ + int i, j, h; + + /* + * Turn cache key into a positive integer + */ + h = 0; + for (i = ckp->key_len-1, j = 0; + i > 0, j < sizeof(int); + i--, j++) + h = (h << 8) + ckp->key[i]; + h = abs(h); + + /* + * Return the hashed value + */ + return(h % SCSP_HASHSZ); +} + + +/* + * Compare two SCSP IDs + * + * Arguments: + * id1p pointer to an SCSP ID structure + * id2p pointer to an SCSP ID structure + * + * Returns: + * < 0 id1 is less than id2 + * 0 id1 and id2 are equal + * > 0 id1 is greater than id2 + * + */ +int +scsp_cmp_id(id1p, id2p) + Scsp_id *id1p; + Scsp_id *id2p; +{ + int diff, i; + + /* + * Compare the two IDs, byte for byte + */ + for (i = 0; i < id1p->id_len && i < id2p->id_len; i++) { + diff = id1p->id[i] - id2p->id[i]; + if (diff) { + return(diff); + } + } + + /* + * IDs are equal. If lengths differ, the longer ID is + * greater than the shorter. + */ + return(id1p->id_len - id2p->id_len); +} + + +/* + * Compare two SCSP cache keys + * + * Arguments: + * ck1p pointer to an SCSP cache key structure + * ck2p pointer to an SCSP cache key structure + * + * Returns: + * < 0 ck1 is less than ck2 + * 0 ck1 and ck2 are equal + * > 0 ck1 is greater than ck2 + * + */ +int +scsp_cmp_key(ck1p, ck2p) + Scsp_ckey *ck1p; + Scsp_ckey *ck2p; +{ + int diff, i; + + /* + * Compare the two keys, byte for byte + */ + for (i = 0; i < ck1p->key_len && i < ck2p->key_len; i++) { + diff = ck1p->key[i] - ck2p->key[i]; + if (diff) + return(diff); + } + + /* + * Keys are equal. If lengths differ, the longer key is + * greater than the shorter. + */ + return(ck1p->key_len - ck2p->key_len); +} + + +/* + * Check whether the host system is an ATMARP server for + * the LIS associated with a given interface + * + * Arguments: + * netif pointer to the network interface name + * + * Returns: + * 1 host is a server + * 0 host is not a server + * + */ +int +scsp_is_atmarp_server(netif) + char *netif; +{ + int rc; + int buf_len = sizeof(struct air_asrv_rsp); + struct atminfreq air; + struct air_asrv_rsp *asrv_info; + + /* + * Get interface information from the kernel + */ + strcpy(air.air_int_intf, netif); + air.air_opcode = AIOCS_INF_ASV; + buf_len = do_info_ioctl(&air, buf_len); + if (buf_len < 0) + return(0); + + /* + * Check the interface's ATMARP server address + */ + asrv_info = (struct air_asrv_rsp *) air.air_buf_addr; + rc = (asrv_info->asp_addr.address_format == T_ATM_ABSENT) && + (asrv_info->asp_subaddr.address_format == + T_ATM_ABSENT); + UM_FREE(asrv_info); + return(rc); +} + + +/* + * Make a copy of a cache summary entry + * + * Arguments: + * csep pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to new CSE entry + * + */ +Scsp_cse * +scsp_dup_cse(csep) + Scsp_cse *csep; +{ + Scsp_cse *dupp; + + /* + * Allocate memory for the duplicate + */ + dupp = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!dupp) { + scsp_mem_err("scsp_dup_cse: sizeof(Scsp_cse)"); + } + + /* + * Copy data to the duplicate + */ + UM_COPY(csep, dupp, sizeof(Scsp_cse)); + dupp->sc_next = (Scsp_cse *)0; + + return(dupp); +} + + +/* + * Make a copy of a CSA or CSAS record + * + * Arguments: + * csap pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to new CSA or CSAS record + * + */ +Scsp_csa * +scsp_dup_csa(csap) + Scsp_csa *csap; +{ + Scsp_csa *dupp; + Scsp_atmarp_csa *adp; + + /* + * Allocate memory for the duplicate + */ + dupp = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!dupp) { + scsp_mem_err("scsp_dup_csa: sizeof(Scsp_csa)"); + } + + /* + * Copy data to the duplicate + */ + UM_COPY(csap, dupp, sizeof(Scsp_csa)); + dupp->next = (Scsp_csa *)0; + + /* + * Copy protocol-specific data, if it's present + */ + if (csap->atmarp_data) { + adp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa)); + if (!adp) { + scsp_mem_err("scsp_dup_csa: sizeof(Scsp_atmarp_csa)"); + } + UM_COPY(csap->atmarp_data, adp, sizeof(Scsp_atmarp_csa)); + dupp->atmarp_data = adp; + } + + return(dupp); +} + + +/* + * Copy a cache summary entry into a CSAS + * + * Arguments: + * csep pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to CSAS record summarizing the entry + * + */ +Scsp_csa * +scsp_cse2csas(csep) + Scsp_cse *csep; +{ + Scsp_csa *csap; + + /* + * Allocate memory for the duplicate + */ + csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!csap) { + scsp_mem_err("scsp_cse2csas: sizeof(Scsp_csa)"); + } + UM_ZERO(csap, sizeof(Scsp_csa)); + + /* + * Copy data to the CSAS entry + */ + csap->seq = csep->sc_seq; + csap->key = csep->sc_key; + csap->oid = csep->sc_oid; + + return(csap); +} + + +/* + * Copy an ATMARP cache entry into a cache summary entry + * + * Arguments: + * aap pointer to ATMARP cache entry to copy + * + * Returns: + * 0 copy failed + * else pointer to CSE record summarizing the entry + * + */ +Scsp_cse * +scsp_atmarp2cse(aap) + Scsp_atmarp_msg *aap; +{ + Scsp_cse *csep; + + /* + * Allocate memory for the duplicate + */ + csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!csep) { + scsp_mem_err("scsp_atmarp2cse: sizeof(Scsp_cse)"); + } + UM_ZERO(csep, sizeof(Scsp_cse)); + + /* + * Copy data to the CSE entry + */ + csep->sc_seq = aap->sa_seq; + csep->sc_key = aap->sa_key; + csep->sc_oid = aap->sa_oid; + + return(csep); +} + + +/* + * Clean up a DCS block. This routine is called to clear out any + * lingering state information when the CA FSM reverts to an 'earlier' + * state (Down or Master/Slave Negotiation). + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * + * Returns: + * none + * + */ +void +scsp_dcs_cleanup(dcsp) + Scsp_dcs *dcsp; +{ + Scsp_cse *csep, *ncsep; + Scsp_csa *csap, *next_csap; + Scsp_csu_rexmt *rxp, *rx_next; + + /* + * Free any CSAS entries waiting to be sent + */ + for (csep = dcsp->sd_ca_csas; csep; csep = ncsep) { + ncsep = csep->sc_next; + UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next); + UM_FREE(csep); + } + + /* + * Free any entries on the CRL + */ + for (csap = dcsp->sd_crl; csap; csap = next_csap) { + next_csap = csap->next; + UNLINK(csap, Scsp_csa, dcsp->sd_crl, next); + SCSP_FREE_CSA(csap); + } + + /* + * Free any saved CA message and cancel the CA + * retransmission timer + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0; + } + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + + /* + * Free any saved CSU Solicit message and cancel the CSUS + * retransmission timer + */ + if (dcsp->sd_csus_rexmt_msg) { + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0; + } + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + + /* + * Free any entries on the CSU Request retransmission queue + */ + for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = rx_next) { + rx_next = rxp->sr_next; + HARP_CANCEL(&rxp->sr_t); + for (csap = rxp->sr_csa; csap; csap = next_csap) { + next_csap = csap->next; + SCSP_FREE_CSA(csap); + } + UNLINK(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, + sr_next); + UM_FREE(rxp); + } +} + + +/* + * Delete an SCSP DCS block and any associated information + * + * Arguments: + * dcsp pointer to a DCS control block to delete + * + * Returns: + * none + * + */ +void +scsp_dcs_delete(dcsp) + Scsp_dcs *dcsp; +{ + Scsp_cse *csep, *next_cse; + Scsp_csu_rexmt *rxp, *next_rxp; + Scsp_csa *csap, *next_csa; + + /* + * Cancel any pending DCS timers + */ + HARP_CANCEL(&dcsp->sd_open_t); + HARP_CANCEL(&dcsp->sd_hello_h_t); + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + + /* + * Unlink the DCS block from the server block + */ + UNLINK(dcsp, Scsp_dcs, dcsp->sd_server->ss_dcs, sd_next); + + /* + * Close the VCC to the DCS, if one is open + */ + if (dcsp->sd_sock != -1) { + (void)close(dcsp->sd_sock); + } + + /* + * Free any saved CA message + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + } + + /* + * Free any pending CSAs waiting for cache alignment + */ + for (csep = dcsp->sd_ca_csas; csep; csep = next_cse) { + next_cse = csep->sc_next; + UM_FREE(csep); + } + + /* + * Free anything on the cache request list + */ + for (csap = dcsp->sd_crl; csap; csap = next_csa) { + next_csa = csap->next; + SCSP_FREE_CSA(csap); + } + + /* + * Free any saved CSUS message + */ + if (dcsp->sd_csus_rexmt_msg) { + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + } + + /* + * Free anything on the CSU Request retransmit queue + */ + for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = next_rxp) { + /* + * Cancel the retransmit timer + */ + HARP_CANCEL(&rxp->sr_t); + + /* + * Free the CSAs to be retransmitted + */ + for (csap = rxp->sr_csa; csap; csap = next_csa) { + next_csa = csap->next; + SCSP_FREE_CSA(csap); + } + + /* + * Free the CSU Req retransmission control block + */ + next_rxp = rxp->sr_next; + UM_FREE(rxp); + } + + /* + * Free the DCS block + */ + UM_FREE(dcsp); +} + + +/* + * Shut down a server. This routine is called when a connection to + * a server is lost. It will clear the server's state without deleting + * the server. + * + * Arguments: + * ssp pointer to a server control block + * + * Returns: + * none + * + */ +void +scsp_server_shutdown(ssp) + Scsp_server *ssp; +{ + int i; + Scsp_dcs *dcsp; + Scsp_cse *csep; + + /* + * Trace the shutdown + */ + if (scsp_trace_mode & (SCSP_TRACE_IF_MSG | SCSP_TRACE_CFSM)) { + scsp_trace("Server %s being shut down\n", + ssp->ss_name); + } + + /* + * Terminate up all the DCS connections and clean + * up the control blocks + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (dcsp->sd_sock != -1) { + (void)close(dcsp->sd_sock); + dcsp->sd_sock = -1; + } + HARP_CANCEL(&dcsp->sd_open_t); + HARP_CANCEL(&dcsp->sd_hello_h_t); + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + scsp_dcs_cleanup(dcsp); + dcsp->sd_hello_state = SCSP_HFSM_DOWN; + dcsp->sd_ca_state = SCSP_CAFSM_DOWN; + dcsp->sd_client_state = SCSP_CIFSM_NULL; + } + + /* + * Clean up the server control block + */ + if (ssp->ss_sock != -1) { + (void)close(ssp->ss_sock); + ssp->ss_sock = -1; + } + if (ssp->ss_dcs_lsock != -1) { + (void)close(ssp->ss_dcs_lsock); + ssp->ss_dcs_lsock = -1; + } + ssp->ss_state = SCSP_SS_NULL; + + /* + * Free the entries in the server's summary cache + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + while (ssp->ss_cache[i]) { + csep = ssp->ss_cache[i]; + UNLINK(csep, Scsp_cse, ssp->ss_cache[i], + sc_next); + UM_FREE(csep); + } + } +} + + +/* + * Delete an SCSP server block and any associated information + * + * Arguments: + * ssp pointer to a server control block to delete + * + * Returns: + * none + * + */ +void +scsp_server_delete(ssp) + Scsp_server *ssp; +{ + int i; + Scsp_dcs *dcsp, *next_dcs; + Scsp_cse *csep, *next_cse; + + /* + * Unlink the server block from the chain + */ + UNLINK(ssp, Scsp_server, scsp_server_head, ss_next); + + /* + * Free the DCS blocks associated with the server + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = next_dcs) { + next_dcs = dcsp->sd_next; + scsp_dcs_delete(dcsp); + } + + /* + * Free the entries in the server's summary cache + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (csep = ssp->ss_cache[i]; csep; csep = next_cse) { + next_cse = csep->sc_next; + UM_FREE(csep); + } + } + + /* + * Free the server block + */ + UM_FREE(ssp->ss_name); + UM_FREE(ssp); +} + + +/* + * Get informtion about a server from the kernel + * + * Arguments: + * ssp pointer to the server block + * + * Returns: + * 0 server info is OK + * errno server is not ready + * + */ +int +scsp_get_server_info(ssp) + Scsp_server *ssp; +{ + int i, len, mtu, rc, sel; + struct atminfreq air; + struct air_netif_rsp *netif_rsp = (struct air_netif_rsp *)0; + struct air_int_rsp *intf_rsp = (struct air_int_rsp *)0; + struct air_cfg_rsp *cfg_rsp = (struct air_cfg_rsp *)0; + struct sockaddr_in *ip_addr; + struct sockaddr_in subnet_mask; + Atm_addr_nsap *anp; + + /* + * Make sure we're the server for the interface + */ + if (!scsp_is_atmarp_server(ssp->ss_intf)) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Get the IP address and physical interface name + * associated with the network interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_NIF; + strcpy(air.air_netif_intf, ssp->ss_intf); + len = do_info_ioctl(&air, sizeof(struct air_netif_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + netif_rsp = (struct air_netif_rsp *)air.air_buf_addr; + + ip_addr = (struct sockaddr_in *)&netif_rsp->anp_proto_addr; + if (ip_addr->sin_family != AF_INET || + ip_addr->sin_addr.s_addr == 0) { + rc = EADDRNOTAVAIL; + goto server_info_done; + } + + /* + * Get the MTU for the network interface + */ + mtu = get_mtu(ssp->ss_intf); + if (mtu < 0) { + rc = EIO; + goto server_info_done; + } + + /* + * Get the ATM address associated with the + * physical interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_INT; + strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); + len = do_info_ioctl(&air, sizeof(struct air_int_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + intf_rsp = (struct air_int_rsp *)air.air_buf_addr; + + /* + * Make sure we're running UNI signalling + */ + if (intf_rsp->anp_sig_proto != ATM_SIG_UNI30 && + intf_rsp->anp_sig_proto != ATM_SIG_UNI31 && + intf_rsp->anp_sig_proto != ATM_SIG_UNI40) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Check the physical interface's state + */ + if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) { + rc = EHOSTDOWN; + goto server_info_done; + } + + /* + * Make sure the interface's address is valid + */ + if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR && + !(intf_rsp->anp_addr.address_format == + T_ATM_E164_ADDR && + intf_rsp->anp_subaddr.address_format == + T_ATM_ENDSYS_ADDR)) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Find the selector byte value for the interface + */ + for (i=0; i<strlen(ssp->ss_intf); i++) { + if (ssp->ss_intf[i] >= '0' && + ssp->ss_intf[i] <= '9') + break; + } + sel = atoi(&ssp->ss_intf[i]); + + /* + * Get configuration information associated with the + * physical interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_CFG; + strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); + len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + cfg_rsp = (struct air_cfg_rsp *)air.air_buf_addr; + + /* + * Update the server entry + */ + UM_COPY(&ip_addr->sin_addr, ssp->ss_lsid.id, ssp->ss_id_len); + ssp->ss_lsid.id_len = ssp->ss_id_len; + ssp->ss_mtu = mtu + 8; + ATM_ADDR_COPY(&intf_rsp->anp_addr, &ssp->ss_addr); + ATM_ADDR_COPY(&intf_rsp->anp_subaddr, &ssp->ss_subaddr); + if (ssp->ss_addr.address_format == T_ATM_ENDSYS_ADDR) { + anp = (Atm_addr_nsap *)ssp->ss_addr.address; + anp->aan_sel = sel; + } else if (ssp->ss_addr.address_format == T_ATM_E164_ADDR && + ssp->ss_subaddr.address_format == + T_ATM_ENDSYS_ADDR) { + anp = (Atm_addr_nsap *)ssp->ss_subaddr.address; + anp->aan_sel = sel; + } + ssp->ss_media = cfg_rsp->acp_cfg.ac_media; + rc = 0; + + /* + * Free dynamic data + */ +server_info_done: + if (netif_rsp) + UM_FREE(netif_rsp); + if (intf_rsp) + UM_FREE(intf_rsp); + if (cfg_rsp) + UM_FREE(cfg_rsp); + + return(rc); +} + + +/* + * Process a CA message + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * cap pointer to the CA part of the received message + * + * Returns: + * none + * + */ +void +scsp_process_ca(dcsp, cap) + Scsp_dcs *dcsp; + Scsp_ca *cap; +{ + Scsp_csa *csap, *next_csap; + Scsp_cse *csep; + Scsp_server *ssp = dcsp->sd_server; + + /* + * Process CSAS records from the CA message + */ + for (csap = cap->ca_csa_rec; csap; csap = next_csap) { + next_csap = csap->next; + SCSP_LOOKUP(ssp, &csap->key, csep); + if (!csep || scsp_cmp_id(&csap->oid, + &csep->sc_oid) == 0 && + csap->seq > csep->sc_seq) { + /* + * CSAS entry not in cache or more + * up to date than cache, add it to CRL + */ + UNLINK(csap, Scsp_csa, cap->ca_csa_rec, next); + LINK2TAIL(csap, Scsp_csa, dcsp->sd_crl, next); + } + } +} + + +/* + * Process a Cache Response message from a server + * + * Arguments: + * ssp pointer to the server block + * smp pointer to the message + * + * Returns: + * none + * + */ +void +scsp_process_cache_rsp(ssp, smp) + Scsp_server *ssp; + Scsp_if_msg *smp; +{ + int len; + Scsp_atmarp_msg *aap; + Scsp_cse *csep; + + /* + * Loop through the message, processing each cache entry + */ + len = smp->si_len; + len -= sizeof(Scsp_if_msg_hdr); + aap = &smp->si_atmarp; + while (len > 0) { + switch(smp->si_proto) { + case SCSP_ATMARP_PROTO: + /* + * If we already have an entry with this key, + * delete it + */ + SCSP_LOOKUP(ssp, &aap->sa_key, csep); + if (csep) { + SCSP_DELETE(ssp, csep); + UM_FREE(csep); + } + + /* + * Copy the data from the server to a cache + * summary entry + */ + csep = scsp_atmarp2cse(aap); + + /* + * Point past this entry + */ + len -= sizeof(Scsp_atmarp_msg); + aap++; + break; + case SCSP_NHRP_PROTO: + /* + * Not implemented yet + */ + return; + } + + /* + * Add the new summary entry to the cache + */ + SCSP_ADD(ssp, csep); + } +} + + +/* + * Propagate a CSA to all the DCSs in the server group except + * the one the CSA was received from + * + * Arguments: + * dcsp pointer to a the DCS the CSA came from + * csap pointer to a the CSA + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_propagate_csa(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc, ret_rc = 0; + Scsp_server *ssp = dcsp->sd_server; + Scsp_dcs *dcsp1; + Scsp_csa *csap1; + + /* + * Check the hop count in the CSA + */ + if (csap->hops <= 1) + return(0); + + /* + * Pass the cache entry on to the server's other DCSs + */ + for (dcsp1 = ssp->ss_dcs; dcsp1; dcsp1 = dcsp1->sd_next) { + /* + * Skip this DCS if it's the one we got + * the entry from + */ + if (dcsp1 == dcsp) + continue; + + /* + * Copy the CSA + */ + csap1 = scsp_dup_csa(csap); + + /* + * Decrement the hop count + */ + csap1->hops--; + + /* + * Send the copy of the CSA to the CA FSM for the DCS + */ + rc = scsp_cafsm(dcsp1, SCSP_CAFSM_CACHE_UPD, + (void *) csap1); + if (rc) + ret_rc = rc; + } + + return(ret_rc); +} + + +/* + * Update SCSP's cache given a CSA or CSAS + * + * Arguments: + * dcsp pointer to a DCS + * csap pointer to a CSA + * + * Returns: + * none + * + */ +void +scsp_update_cache(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + Scsp_cse *csep; + + /* + * Check whether we already have this in the cache + */ + 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_update_cache: sizeof(Scsp_cse)"); + } + UM_ZERO(csep, sizeof(Scsp_cse)); + + /* + * Fill out the new cache summary entry + */ + csep->sc_seq = csap->seq; + csep->sc_key = csap->key; + csep->sc_oid = csap->oid; + + /* + * Add the new entry to the cache + */ + SCSP_ADD(dcsp->sd_server, csep); + } + + /* + * Update or delete the entry + */ + if (csap->null) { + /* + * The null flag is set--delete the entry + */ + if (csep) { + SCSP_DELETE(dcsp->sd_server, csep); + UM_FREE(csep); + } + } else { + /* + * Update the existing entry + */ + csep->sc_seq = csap->seq; + csep->sc_oid = csap->oid; + } +} + + +/* + * Reconfigure SCSP + * + * Called as the result of a SIGHUP interrupt. Reread the + * configuration file and solicit the cache from the server. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +scsp_reconfigure() +{ + int rc; + Scsp_server *ssp; + + /* + * Log a message saying we're reconfiguring + */ + scsp_log(LOG_ERR, "Reconfiguring ..."); + + /* + * Re-read the configuration file + */ + rc = scsp_config(scsp_config_file); + if (rc) { + scsp_log(LOG_ERR, "Found %d error%s in configuration file", + rc, ((rc == 1) ? "" : "s")); + exit(1); + } + + /* + * If a connection to a server is open, get the cache from + * the server + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_sock != -1) { + rc = scsp_send_cache_ind(ssp); + } + } +} diff --git a/usr.sbin/atm/scspd/scsp_timer.c b/usr.sbin/atm/scspd/scsp_timer.c new file mode 100644 index 0000000..0ec6169d --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_timer.c @@ -0,0 +1,265 @@ +/* + * + * =================================== + * 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_timer.c,v 1.2 1998/07/16 15:59:50 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Timer processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_timer.c,v 1.2 1998/07/16 15:59:50 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.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" + + +/* + * Process an SCSP Open timeout + * + * The open timer is set when an attempt to open a VCC to a DCS fails. + * This routine will be called when the timer fires and will retry + * the open. Retries can continue indefinitely. + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_open_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_open_t)); + + /* + * Retry the connection + */ + if (scsp_dcs_connect(dcsp)) { + /* + * Connect failed -- we hope the error was temporary + * and set the timer to try again later + */ + HARP_TIMER(&dcsp->sd_open_t, SCSP_Open_Interval, + scsp_open_timeout); + } +} + + +/* + * Process an SCSP Hello timeout + * + * The Hello timer fires every SCSP_HELLO_Interval seconds. This + * routine will notify the Hello FSM when the timer fires. + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_hello_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_hello_h_t)); + + /* + * Call the Hello FSM + */ + (void)scsp_hfsm(dcsp, SCSP_HFSM_HELLO_T, (Scsp_msg *)0); + + return; +} + + +/* + * Process an SCSP receive timeout + * + * The receive timer is started whenever the Hello FSM receives a + * Hello message from its DCS. If the timer fires, it means that no + * Hello messages have been received in the DCS's Hello interval. + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_hello_rcv_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_hello_rcv_t)); + + /* + * Call the Hello FSM + */ + (void)scsp_hfsm(dcsp, SCSP_HFSM_RCV_T, (void *)0); + + return; +} + + +/* + * Process an SCSP CA retransmit timeout + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_ca_retran_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_ca_rexmt_t)); + + /* + * Call the CA FSM + */ + (void)scsp_cafsm(dcsp, SCSP_CAFSM_CA_T, (void *)0); + + return; +} + + +/* + * Process an SCSP CSUS retransmit timeout + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_csus_retran_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_csus_rexmt_t)); + + /* + * Call the CA FSM + */ + (void)scsp_cafsm(dcsp, SCSP_CAFSM_CSUS_T, (void *)0); + + return; +} + + +/* + * Process an SCSP CSU Req retransmit timeout + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_csu_req_retran_timeout(stp) + Harp_timer *stp; +{ + Scsp_csu_rexmt *rxp; + Scsp_dcs *dcsp; + + /* + * Back off to start of CSU Request retransmission entry + */ + rxp = (Scsp_csu_rexmt *) ((caddr_t)stp - + (int)(&((Scsp_csu_rexmt *)0)->sr_t)); + dcsp = rxp->sr_dcs; + + /* + * Call the CA FSM + */ + (void)scsp_cafsm(dcsp, SCSP_CAFSM_CSU_T, (void *)rxp); + + return; +} diff --git a/usr.sbin/atm/scspd/scsp_var.h b/usr.sbin/atm/scspd/scsp_var.h new file mode 100644 index 0000000..ba383d5 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_var.h @@ -0,0 +1,434 @@ +/* + * + * =================================== + * 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_var.h,v 1.5 1998/08/13 20:11:17 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP message formats + * + */ + +#ifndef _SCSP_SCSP_VAR_H +#define _SCSP_SCSP_VAR_H + + +/* + * Protocol constants + */ +#define SCSP_Open_Interval 30 +#define SCSP_HELLO_Interval 3 +#define SCSP_HELLO_DF 3 +#define SCSP_CAReXmitInterval 3 +#define SCSP_CSUSReXmitInterval 3 +#define SCSP_CSA_HOP_CNT 3 +#define SCSP_CSUReXmitInterval 2 +#define SCSP_CSUReXmitMax 5 + + +/* + * Operational constants + */ +#define SCSPD_CONFIG "/etc/scspd.conf" +#define SCSPD_DIR "/tmp" +#define SCSPD_DUMP "/tmp/scspd.dump" +#define SCSP_HASHSZ 19 +#define SCSPD_SOCK_NAME "SCSPD" + + +/* + * HELLO finite state machine states + */ +#define SCSP_HFSM_DOWN 0 +#define SCSP_HFSM_WAITING 1 +#define SCSP_HFSM_UNI_DIR 2 +#define SCSP_HFSM_BI_DIR 3 +#define SCSP_HFSM_STATE_CNT SCSP_HFSM_BI_DIR + 1 + + +/* + * HELLO finite state machine events + */ +#define SCSP_HFSM_VC_ESTAB 0 +#define SCSP_HFSM_VC_CLOSED 1 +#define SCSP_HFSM_HELLO_T 2 +#define SCSP_HFSM_RCV_T 3 +#define SCSP_HFSM_RCVD 4 +#define SCSP_HFSM_EVENT_CNT SCSP_HFSM_RCVD + 1 + + +/* + * Cache Alignment finite state machine states + */ +#define SCSP_CAFSM_DOWN 0 +#define SCSP_CAFSM_NEG 1 +#define SCSP_CAFSM_MASTER 2 +#define SCSP_CAFSM_SLAVE 3 +#define SCSP_CAFSM_UPDATE 4 +#define SCSP_CAFSM_ALIGNED 5 +#define SCSP_CAFSM_STATE_CNT SCSP_CAFSM_ALIGNED + 1 + + +/* + * Cache Alignment finite state machine events + */ +#define SCSP_CAFSM_HELLO_UP 0 +#define SCSP_CAFSM_HELLO_DOWN 1 +#define SCSP_CAFSM_CA_MSG 2 +#define SCSP_CAFSM_CSUS_MSG 3 +#define SCSP_CAFSM_CSU_REQ 4 +#define SCSP_CAFSM_CSU_REPLY 5 +#define SCSP_CAFSM_CA_T 6 +#define SCSP_CAFSM_CSUS_T 7 +#define SCSP_CAFSM_CSU_T 8 +#define SCSP_CAFSM_CACHE_UPD 9 +#define SCSP_CAFSM_CACHE_RSP 10 +#define SCSP_CAFSM_EVENT_CNT SCSP_CAFSM_CACHE_RSP + 1 + + +/* + * Client Interface finite state machine states + */ +#define SCSP_CIFSM_NULL 0 +#define SCSP_CIFSM_SUM 1 +#define SCSP_CIFSM_UPD 2 +#define SCSP_CIFSM_ALIGN 3 +#define SCSP_CIFSM_STATE_CNT SCSP_CIFSM_ALIGN + 1 + + +/* + * Client Interface finite state machine events + */ +#define SCSP_CIFSM_CA_DOWN 0 +#define SCSP_CIFSM_CA_SUMM 1 +#define SCSP_CIFSM_CA_UPD 2 +#define SCSP_CIFSM_CA_ALIGN 3 +#define SCSP_CIFSM_SOL_RSP 4 +#define SCSP_CIFSM_UPD_REQ 5 +#define SCSP_CIFSM_UPD_RSP 6 +#define SCSP_CIFSM_CSU_REQ 7 +#define SCSP_CIFSM_CSU_REPLY 8 +#define SCSP_CIFSM_CSU_SOL 9 +#define SCSP_CIFSM_EVENT_CNT SCSP_CIFSM_CSU_SOL + 1 + + +/* + * Server connection states (not part of any FSM) + */ +#define SCSP_SS_NULL 0 +#define SCSP_SS_CFG 1 +#define SCSP_SS_ACTIVE 2 + + +/* + * Hash a cache key + * + * key pointer to an Scsp_ckey structure + */ +#define SCSP_HASH(key) scsp_hash((key)) + + +/* + * Add a cache summary entry to a client's cache summary + * + * cpp pointer to a server control block + * key pointer to an Scsp_cse structure + */ +#define SCSP_ADD(cpp, key) \ +{ \ + Scsp_cse **c; \ + c = &(cpp)->ss_cache[SCSP_HASH(&(key)->sc_key)]; \ + LINK2TAIL((key), Scsp_cse, *c, sc_next); \ +} + + +/* + * Delete a cache summary entry from a client's cache summary + * + * cpp pointer to a server control block + * s pointer to an Scsp_cse structure + */ +#define SCSP_DELETE(cpp, s) \ +{ \ + Scsp_cse **c; \ + c = &(cpp)->ss_cache[SCSP_HASH(&(s)->sc_key)]; \ + UNLINK((s), Scsp_cse, *c, sc_next); \ +} + + +/* + * Search a client's cache summary for a given key + * + * cpp pointer to a server control block + * key pointer to an Scsp_ckey structure to find + * s Scsp_cse structure pointer to be set + */ +#define SCSP_LOOKUP(cpp, key, s) \ +{ \ + for ((s) = (cpp)->ss_cache[SCSP_HASH(key)]; \ + (s); \ + (s) = (s)->sc_next) { \ + if (scsp_cmp_key((key), &(s)->sc_key) == 0) \ + break; \ + } \ +} + + +/* + * SCSP pending connection control block + * + * The pending connection block is used to keep track of server + * connections which are open but haven't been identified yet. + */ +struct scsp_pending { + struct scsp_pending *sp_next; + int sp_sock; +}; +typedef struct scsp_pending Scsp_pending; + + +/* + * SCSP Server instance control block + */ +struct scsp_server { + struct scsp_server *ss_next; /* Server chain */ + char *ss_name; /* Server name */ + char ss_intf[IFNAMSIZ]; /* Interface */ + Atm_media ss_media; /* Physical comm medium */ + char ss_state; /* Server connection state */ + u_long ss_pid; /* Protocol ID */ + int ss_id_len; /* ID length */ + int ss_ckey_len; /* Cache key length */ + u_long ss_sgid; /* Server group ID */ + u_long ss_fid; /* Family ID */ + int ss_sock; /* Socket to client */ + int ss_dcs_lsock; /* DCS listen socket */ + Scsp_id ss_lsid; /* Local Server ID */ + Atm_addr ss_addr; /* Local ATM addr */ + Atm_addr ss_subaddr; /* Local ATM subaddr */ + int ss_mtu; /* Interface MTU */ + int ss_mark; + struct scsp_dcs *ss_dcs; /* Ptr to list of DCSs */ + struct scsp_cse *ss_cache[SCSP_HASHSZ]; /* Client's cache */ +}; +typedef struct scsp_server Scsp_server; + + +/* + * SCSP client cache summary entry control block + */ +struct scsp_cse { + struct scsp_cse *sc_next; /* Next on chain */ + long sc_seq; /* CSA sequence no */ + Scsp_ckey sc_key; /* Cache key */ + Scsp_id sc_oid; /* Origin ID */ +}; +typedef struct scsp_cse Scsp_cse; + + +/* + * CSU Request retransmission control block + */ +struct scsp_csu_rexmt { + struct scsp_csu_rexmt *sr_next; /* Next rexmit block */ + struct scsp_dcs *sr_dcs; /* DCS block */ + Scsp_csa *sr_csa; /* CSAs for rexmit */ + Harp_timer sr_t; /* Rexmit timer */ +}; +typedef struct scsp_csu_rexmt Scsp_csu_rexmt; + + +/* + * SCSP DCS control block + */ +struct scsp_dcs { + struct scsp_dcs *sd_next; /* DCS chain */ + Scsp_server *sd_server; /* Local server */ + Scsp_id sd_dcsid; /* DCS ID */ + Atm_addr sd_addr; /* DCS ATM address */ + Atm_addr sd_subaddr; /* DCS ATM subaddress */ + int sd_sock; /* Socket to DCS */ + Harp_timer sd_open_t; /* Open VCC retry timer */ + int sd_hello_state; /* Hello FSM state */ + int sd_hello_int; /* Hello interval */ + int sd_hello_df; /* Hello dead factor */ + int sd_hello_rcvd; /* Hello msg received */ + Harp_timer sd_hello_h_t; /* Hello timer */ + Harp_timer sd_hello_rcv_t; /* Hello receive timer */ + int sd_ca_state; /* CA FSM state */ + long sd_ca_seq; /* CA sequence number */ + int sd_ca_rexmt_int; /* CA rexmit interval */ + Scsp_msg *sd_ca_rexmt_msg; /* Saved CA msg */ + Scsp_cse *sd_ca_csas; /* CSAS still to send */ + Harp_timer sd_ca_rexmt_t; /* CA rexmit timer */ + int sd_csus_rexmt_int; /* CSUS rexmit int */ + Scsp_csa *sd_crl; /* Cache req list */ + Scsp_msg *sd_csus_rexmt_msg; /* Saved CSUS msg */ + Harp_timer sd_csus_rexmt_t; /* CSUS rexmit timer */ + int sd_hops; /* CSA hop count */ + Scsp_csa *sd_csu_ack_pend; /* CSUs to be ACKed */ + Scsp_csa *sd_csu_ack; /* CSUs ACKed */ + int sd_csu_rexmt_int; /* CSU Req rxmt time */ + int sd_csu_rexmt_max; /* CSU Req rxmt limit */ + Scsp_csu_rexmt *sd_csu_rexmt; /* CSU Req rxmt queue */ + int sd_client_state; /* Client I/F state */ +}; +typedef struct scsp_dcs Scsp_dcs; + +/* + * Trace options + */ +#define SCSP_TRACE_HFSM 1 /* Trace the Hello FSM */ +#define SCSP_TRACE_CAFSM 2 /* Trace the CA FSM */ +#define SCSP_TRACE_CFSM 4 /* Trace the server I/F FSM */ +#define SCSP_TRACE_HELLO_MSG 8 /* Trace Hello protocol msgs */ +#define SCSP_TRACE_CA_MSG 16 /* Trace CA protocol msgs */ +#define SCSP_TRACE_IF_MSG 32 /* Trace server I/F msgs */ + + +/* + * Global variables + */ +extern char *prog; +extern FILE *cfg_file; +extern int parse_line; +extern char *scsp_config_file; +extern FILE *scsp_log_file; +extern int scsp_log_syslog; +extern Scsp_server *scsp_server_head; +extern Scsp_pending *scsp_pending_head; +extern int scsp_max_socket; +extern int scsp_debug_mode; +extern int scsp_trace_mode; +extern FILE *scsp_trace_file; + + +/* + * Executable functions + */ +/* scsp_cafsm.c */ +extern int scsp_cafsm __P((Scsp_dcs *, int, void *)); + +/* scsp_config.c */ +extern int scsp_config __P((char *)); + +/* scsp_hfsm.c */ +extern int scsp_hfsm __P((Scsp_dcs *, int, Scsp_msg *)); + +/* scsp_if.c */ +extern int scsp_cfsm __P((Scsp_dcs *, int, Scsp_msg *, + Scsp_if_msg *)); + +/* scsp_input.c */ +extern void scsp_free_msg __P((Scsp_msg *)); +extern Scsp_msg *scsp_parse_msg __P((char *, int)); + +/* scsp_log.c */ +#if __STDC__ +extern void scsp_log __P((const int, const char *, ...)); +extern void scsp_trace __P((const char *, ...)); +#else +extern void scsp_log __P((int, char *, va_alist)); +extern void scsp_trace __P((const char *, va_alist)); +#endif +extern void scsp_open_trace __P(()); +extern void scsp_trace_msg __P((Scsp_dcs *, Scsp_msg *, int)); +extern void scsp_mem_err __P((char *)); + +/* scsp_msg.c */ +extern void scsp_csus_ack __P((Scsp_dcs *, Scsp_msg *)); +extern int scsp_send_ca __P((Scsp_dcs *)); +extern int scsp_send_csus __P((Scsp_dcs *)); +extern int scsp_send_csu_req __P((Scsp_dcs *, Scsp_csa *)); +extern int scsp_send_csu_reply __P((Scsp_dcs *, Scsp_csa *)); +extern int scsp_send_hello __P((Scsp_dcs *)); + +/* scsp_output.c */ +extern int scsp_format_msg __P((Scsp_dcs *, Scsp_msg *, char **)); +extern int scsp_send_msg __P((Scsp_dcs *, Scsp_msg *)); + +/* scsp_print.c */ +extern char *format_hfsm_state __P((int)); +extern char *format_hfsm_event __P((int)); +extern char *format_cafsm_state __P((int)); +extern char *format_cafsm_event __P((int)); +extern char *format_cifsm_state __P((int)); +extern char *format_cifsm_event __P((int)); +extern void print_scsp_cse __P((FILE *, Scsp_cse *)); +extern void print_scsp_msg __P((FILE *, Scsp_msg *)); +extern void print_scsp_if_msg __P((FILE *, Scsp_if_msg *)); +extern void print_scsp_pending __P((FILE *, Scsp_pending *)); +extern void print_scsp_server __P((FILE *, Scsp_server *)); +extern void print_scsp_dcs __P((FILE *, Scsp_dcs *)); +extern void print_scsp_dump __P(()); + +/* scsp_socket.c */ +extern Scsp_dcs * scsp_find_dcs __P((int)); +extern Scsp_server * scsp_find_server __P((int)); +extern int scsp_dcs_connect __P((Scsp_dcs *)); +extern int scsp_dcs_listen __P((Scsp_server *)); +extern Scsp_dcs * scsp_dcs_accept __P((Scsp_server *)); +extern int scsp_dcs_read __P((Scsp_dcs *)); +extern int scsp_server_listen __P(()); +extern int scsp_server_accept __P((int)); +extern Scsp_if_msg * scsp_if_sock_read __P((int)); +extern int scsp_server_read __P((Scsp_server *)); +extern int scsp_pending_read __P((Scsp_pending *)); + +/* scsp_subr.c */ +extern int scsp_hash __P((Scsp_ckey *)); +extern int scsp_cmp_id __P((Scsp_id *, Scsp_id *)); +extern int scsp_cmp_key __P((Scsp_ckey *, Scsp_ckey *)); +extern int scsp_is_atmarp_server __P((char *)); +extern Scsp_cse * scsp_dup_cse __P((Scsp_cse *)); +extern Scsp_csa * scsp_dup_csa __P((Scsp_csa *)); +extern Scsp_csa * scsp_cse2csas __P((Scsp_cse *)); +extern void scsp_dcs_cleanup __P((Scsp_dcs *)); +extern void scsp_dcs_delete __P((Scsp_dcs *)); +extern void scsp_server_shutdown __P((Scsp_server *)); +extern void scsp_server_delete __P((Scsp_server *)); +extern int scsp_get_server_info __P((Scsp_server *)); +extern void scsp_process_ca __P((Scsp_dcs *, Scsp_ca *)); +extern int scsp_propagate_csa __P(( Scsp_dcs *, + Scsp_csa *)); +extern void scsp_update_cache __P(( Scsp_dcs *, + Scsp_csa *)); +extern void scsp_reconfigure __P(()); + +/* scsp_timer.c */ +extern void scsp_open_timeout __P((Harp_timer *)); +extern void scsp_hello_timeout __P((Harp_timer *)); +extern void scsp_hello_rcv_timeout __P((Harp_timer *)); +extern void scsp_ca_retran_timeout __P((Harp_timer *)); +extern void scsp_csus_retran_timeout __P((Harp_timer *)); +extern void scsp_csu_req_retran_timeout __P((Harp_timer *)); + + + +#endif /* _SCSP_SCSP_VAR_H */ diff --git a/usr.sbin/atm/scspd/scspd.8 b/usr.sbin/atm/scspd/scspd.8 new file mode 100644 index 0000000..1a9b0ab --- /dev/null +++ b/usr.sbin/atm/scspd/scspd.8 @@ -0,0 +1,443 @@ +.\" +.\" =================================== +.\" 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: scspd.1,v 1.2 1998/08/26 21:39:38 johnc Exp $ +.\" +.\" +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH SCSPD 8 "1998-08-21" "HARP" + +.SH NAME +scspd \- SCSP daemon +.SH SYNOPSIS +.B scspd +[\fB-f\fP <cfg-file>] +[\fB-d\fP] +[\fB-T\fP<options>] + +.SH DESCRIPTION +\fIScspd\fP is an implementation of the Server Cache Synchronization +Protocol (SCSP) for the Host ATM Research Platform (HARP) +networking software. +\fIScspd\fP synchronizes the cache(s) of server(s) +running on a host with the caches of servers on remote hosts. +SCSP is defined for a number of different protocols, but the present +version of \fIscspd\fP only supports ATMARP. +.PP +By using \fIscspd\fP and \fIatmarpd\fP, one can provide multiple +ATMARP servers in a single ATM LIS. +This might be useful, for example, when a LIS consists of a number of +local-area ATM networks connected by long-distance links. +Each local-area network could have its own ATMARP server, with all the +servers' caches being synchronized by SCSP. +Then, if a long-distance link fails, hosts on a local-area network +will still have connectivity to other local hosts (since they all use +the local ATMARP server); when the long-distance link is restored, +SCSP will re-synchronize the servers' caches, restoring +connectivity to remote hosts. +Both \fIscspd\fP and \fIatmarpd\fP must be running before any ATMARP +cache synchronization can take place. +.PP +\fIScspd\fP implements SCSP as specified in RFC 2334, \fIServer Cache +Synchronization Protocol (SCSP)\fP and +draft-ietf-ion-scspd-atmarpd-00.txt, \fIA Distributed ATMARP Service +using SCSP\fP. + +When \fIscspd\fP starts, it parses its command line and puts +itself into the background. + +.SH TERMINOLOGY +Some of the vocabulary associated with SCSP can be confusing. +In this document, the following definitions are used: + +\fBClient server\fP or \fBlocal server\fP means the server running on +the same host as \fIscspd\fP whose cache is to be synchronized with that +of one or more remote servers. +When the word \fBserver\fP is used alone, it means "client server". + +\fBRemote server\fP means a server running on some host other than +the one where \fIscspd\fP is running. + +\fBDirectly Connected Server\fP (DCS) means a remote server that +\fIscspd\fP communicates with directly. +The remote server will also be running an implementation of SCSP. + +\fBCache Alignment\fP (CA) has two meanings. +The Cache Alignment protocol is a part of the SCSP protocol +specification, and the Cache Alignment finite state machine (FSM) +is a finite state machine that implements the Cache Alignment +protocol. + +.SH OPTIONS +The command-line options are: +.IP "\fB-f\fP <cfg-file>" 15 +Specifies the name of the configuration file. +If this option is not specified, \fIscspd\fP looks for the +file /etc/scspd.conf. +.IP "\fB-d\fP" 15 +Specifies that \fIscspd\fP is to be run in debug mode. +In debug mode, the daemon is not put into the background. +Log messages are written to standard output instead of to +the log file specified in the configuration file. +.IP "\fB-T\fP<options>" 15 +Specifies that \fIscspd\fP will trace specified events and messages +as it executes. +The \fB-T\fP flag is followed by one or more of the following +options: +.in +4 +.ti -4 +\fBc\fP\ -\ trace \fIscspd\fP's CA Finite State Machine (FSM), +.ti -4 +\fBh\fP\ -\ trace \fIscspd\fP's Hello FSM, +.ti -4 +\fBi\fP\ -\ trace \fIscspd\fP's Client Interface FSM, +.ti -4 +\fBC\fP\ -\ trace CA, CSUS, CSU Request, and CSU Reply messages, +.ti -4 +\fBH\fP\ -\ trace Hello messages, +.ti -4 +\fBI\fP\ -\ trace interface messages to and from \fIscspd\fP's +clients. +.in -4 +.SH CONFIGURATION + +The configuration file consists of a sequence of configuration +statements. +These statements specify information about the servers, +both local and remote, whose +caches are to be synchronized by \fIscspd\fP. +RFC 2334, \fIServer Cache +Synchronization Protocol (SCSP)\fP and +draft-ietf-ion-scspd-atmarpd-00.txt, \fIA Distributed ATMARP Service +using SCSP\fP +will be valuable in understanding how to configure \fIscspd\fP. + +A configuration statement other than a comment is terminated by a +semicolon. +Some statements contain blocks, delimited by braces ("{" and "}"). +Configuration statement keywords are not case-sensitive, +but some parameters (e.g. interface names) are. +Configuration statments can span multiple lines. + +.SS Comments +Three types of comments are allowed: + +\fB# comments\fP: +any characters from "#" to the end of the line are ignored. + +\fBC comments\fP: +any characters between "/*" and "*/" are ignored. + +\fBC++ comments\fP: +any characters from "//" to the end of the line are ignored. + +.SS "Statements" +The configuration statements recognized by \fIscspd\fP are: + +Server <name> { +.in +5 +Protocol <protocol ID>; +.br +Netif <if_name>; +.br +ServerGroupID <ID>; +.br +FamilyID <ID>; +.br +DCS { +.in +5 +ATMaddr <ATM address>; +.br +ID <host>; +.br +CAReXmitInt <int>; +.br +CSUSReXmitInt <int>; +.br +CSUReXmitInt <int>; +.br +CSUReXmitMax <cnt>; +.br +HelloDead <cnt>; +.br +HelloInt <int>; +.br +Hops <cnt>; +.in -5 +}; +.in -5 +}; +.sp +Log { +.in +5 +File <file name>; +.br +Syslog; +.in -5 +}; +.PP +Where a host address needs to be specified in the configuration file, +either a DNS name or an IP address in dotted decimal format can +be used. +.PP +ATM addresses are specified as strings of hex digits, with an +optional leading "0x". +Fields within the address may be separated by periods, but periods +are for readability only and are ignored. +ATM addresses are 20 bytes long. +The full address, including any leading zeroes, must be given. +For example: +.in +5 +0x47.0005.80.ffe100.0000.f21a.0170.0020481a0170.00 +.in -5 + +.SS "Server Statement" +The \fBserver\fP statement specifies a client server whose cache +to be synchronized with the caches of other servers +running on remote hosts. +There will be one \fBserver\fP statement in the configuration file +for each client server whose cache is to be synchronized by \fIscspd\fP. +The format of the \fBserver\fP statement is: +.ti +5 +\fBServer <name> { <statements> };\fP + +A name must be specified on the \fBserver\fP statement, but it is +not used by \fIscspd\fP. +It is expected to give a brief description of the server's purpose. + +The \fBserver\fP statement has several sub-statements +that specify the details of the \fIscspd\fP's configuration. +They are: +.IP "\fBProtocol ATMARP;\fP" 5 +The only protocol supported by the current version of \fIscspd\fP +is ATMARP. +The \fBprotocol\fP statement must always be specified. +.IP "\fBNetif <intf>;\fP" 5 +The \fBnetif\fP statement specifies the name of the ATM network +interface on which a client server is providing service. +The \fBnetif\fP statement must always be specified. +.IP "\fBServerGroupID <ID>;\fP" 5 +The \fBServerGroupID\fP statement specifies an identifier for the +group of servers being synchronized by \fIscspd\fP. +The ID is specified as a decimal number in the range 0 - 65,535. +The server group ID must be the same for all servers whose caches +are being synchronized by an SCSP session. +That is, the server group ID for a host must be the same for all +Directly Connected Servers (DCSs) pointed to within a +\fBserver\fP statement. +The \fBServerGroupID\fP statement must always be specified. +.IP "\fBFamilyID <ID>;\fP" 5 +The \fBfamilyID\fP statement specifies an identifier for a family +of parallel SCSP sessions running between a group of hosts (i.e. a +set of SCSP sessions with different protocol IDs but the same set +of servers). +The ID is specified as a decimal number in the range 0 - 65,535. +The family ID is currently not used by \fIscspd\fP. + +.SS "DCS Statement" +The \fBDCS\fP statement is a sub-statement of the \fBserver\fP statement +that specifies the characteristics of a Directly Connected Server (DCS). +The \fBserver\fP statement will have one \fBDCS\fP statement for +each DCS that \fIscspd\fP is to exchange information with. +The \fBDCS\fP statement has a number of sub-statements that specify the +details of the configuration for the DCS. They are: +.IP "\fBATMaddr <ATM address>;\fP" 5 +The \fBATMaddr\fP statement specifies the ATM address of the DCS. +The \fBATMaddr\fP statement must always be specified. +.IP "\fBID <host>;\fP" 5 +The \fBID\fP statement specifies the SCSP identifier of the DCS. +For ATMARP, the ID is the IP address or DNS name associated with the +ATM interface of the DCS. +The \fBID\fP statement must always be specified. +.IP "\fBCAReXmitInt <int>;\fP" 5 +The \fBCAReXmitInt\fP statement specifies the interval that is +allowed to elapse between retransmissions of CA messages. +If a CA message is sent and an acknowledgement is not received within +CAReXmitInt seconds, the message will be retransmitted. +The default value for \fBCAReXmitInt\fP is 3 seconds. +.IP "\fBCSUSReXmitInt <int>;\fP" 5 +The \fBCSUSReXmitInt\fP statement specifies the interval that is +allowed to elapse between retransmissions of CSU Solicit messages. +When a CSUS message is sent, any Cache State Advertisements (CSAs) +requested by the CSUS that have +not been received within CSUSReXmitInt seconds will be requested +again by another CSUS message. +The default value for \fBCSUSReXmitInt\fP is 3 seconds. +Be careful not to confuse \fBCSUSReXmitInt\fP and \fBCSUReXmitInt\fP. +.IP "\fBCSUReXmitInt <int>;\fP" 5 +The \fBCSUReXmitInt\fP statement specifies the interval that is +allowed to elapse between retransmissions of CSU Request messages. +When a CSU Request message is sent, any CSAs that are not acknowledged +by a CSU Reply message within CSUReXmitInt seconds will +be retransmitted. +The default value for \fBCSUReXmitInt\fP is 2 seconds. +Be careful not to confuse \fBCSUReXmitInt\fP and \fBCSUSReXmitInt\fP. +.IP "\fBCSUReXmitMax <cnt>;\fP" 5 +The \fBCSUReXmitMax\fP statement specifies the number of times that +a CSA will be retransmitted as described above before SCSP gives up +on the CSA and discards it. +The default value for \fBCSUReXmitMax\fP is 5. +.IP "\fBHelloDead <cnt>;\fP" 5 +The \fBHelloDead\fP statement specifies the Hello Dead Factor that +will be sent to the DCS in Hello messages. +A "DCS down" condition will be detected when nothing is received from +a DCS in HelloDead * HelloInt seconds. +The default value for \fBHelloDead\fP is 3. +.IP "\fBHelloInt <int>;\fP" 5 +The \fBHelloInt\fP statement specifies the Hello Interval that +will be sent to the DCS in Hello messages. +The default value for \fBHelloInt\fP is 3 seconds. +.IP "\fBHops <cnt>;\fP" 5 +The \fBHops\fP statement specifies the number of hops (DCS to DCS) +that will be specified in CSAs originating from the local server. +This number must be at least as large as the diameter of the +server group. +That is, it must be large enough for a CSA to be propagated from +server to server all the way across the server group. +The default value for \fBHops\fP is 3. + +.SS "Log Statement" +The \fBlog\fP statement specifies how \fIscspd\fP is to log +information about its operation. +\fIScspd\fP can write log information to a file, to the system log, +or both. +.IP "\fBFile <file name>;\fP" 5 +The \fBfile\fP statement specifies that \fIscspd\fP is to write +its log messages to the named file. +Log messages will be appended to the end of the file if +it already exists. +.IP "\fBSyslog;\fP" 5 +The \fBsyslog\fP statement specifies that \fIscspd\fP is to write +its log messages to the syslog facility. +\fIScspd\fP writes its messages to syslog with a facility code +of LOG_DAEMON. + +.in -5 +If no \fBlog\fP statement is specified, \fIscspd\fP writes log +messages to the system log. +If both \fBfile\fP and \fBsyslog\fP are specified, \fIscspd\fP will +write log messages to both the named file and the system log. + +.SS Examples + +An example of a simple configuration file for \fIscspd\fP might be: +.in +5 +server atmarp_ni0 { +.in +5 +protocol ATMARP; +.br +netif ni0; +.br +ServerGroupID 23; +.br +DCS { +.in +5 +.br +ID 10.1.1.2; +.br +ATMaddr 0x47.0005.80.ffdc00.0000.0002.0001.002048061de7.00; +.br +hops 2; +.in -5 +}; +.in -5 +}; +.in -5 + +This configuration would synchronize the cache of the ATMARP server +operating on network interface ni0 with the cache of a second server +running on a host whose IP address is 10.1.1.2. +Log messages would be written to the system log. + + +.SH SIGNAL PROCESSING +The following signals can be used to control \fIscspd\fP: + +.IP \fBSIGHUP\fP 10 +Reread the configuration file and restart \fIscspd\fP. + +.IP \fBSIGINT\fP 10 +Dump debugging information to a file. +When it receives a SIGINT signal, \fIscspd\fP dumps a summary of +its control blocks to a text file (see "\fBFILES\fP"). + +.SH FILES + +.IP "/etc/scspd.conf" +\fIScspd\fP default configuration file name. +A different file name can be specified with the \fB-f\fP command-line +option. + +.IP "/tmp/scspd.<pid>.<seq>.out" +Debugging information dump file name. +\fIScspd\fP writes a summary of its control blocks to this file +when it receives a SIGINT signal. +<pid> is the process ID of the daemon and <seq> is a sequence +number which is incremented every time a dump is taken. + +.IP "/tmp/scspd.<pid>.trace" +Trace file. +\fIScspd\fP writes trace information to this file if the \fB-T\fP +option is specified on the command line. + +.SH "SEE ALSO" +\fIatm\fP (8); +\fIatmarpd\fP (8); +RFC 2334, \fIServer Cache Synchronization Protocol (SCSP)\fP; +draft-ietf-ion-scsp-atmarpd-00.txt, \fIA Distributed ATMARP Service +Using SCSP\fP. + + +.SH BUGS +If \fIscspd\fP terminates and is restarted, there will be a period of +instability while previously-synchronized cache entries time out and are +refreshed. + +Please report any bugs to harp-bugs@magic.net. + +.SH COPYRIGHT +Copyright (c) 1994-1998, Network Computing Services, Inc. + +.SH AUTHORS +John Cavanaugh, Network Computing Services, Inc. +.br +Mike Spengler, Network Computing Services, Inc. +.br +Joe Thomas, Network Computing Services, Inc. +.fi +.SH ACKNOWLEDGMENTS +This software was developed with the support of the Defense +Advanced Research Projects Agency (DARPA). diff --git a/usr.sbin/atm/scspd/scspd.c b/usr.sbin/atm/scspd/scspd.c new file mode 100644 index 0000000..74fe868 --- /dev/null +++ b/usr.sbin/atm/scspd/scspd.c @@ -0,0 +1,545 @@ +/* + * + * =================================== + * 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: scspd.c,v 1.6 1998/08/21 18:08:25 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP server daemon main line code + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scspd.c,v 1.6 1998/08/21 18:08:25 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/ttycom.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" + + +/* + * Global variables + */ +char *prog; +char *scsp_config_file = SCSPD_CONFIG; +FILE *scsp_log_file = (FILE *)0; +int scsp_log_syslog = 0; +Scsp_server *scsp_server_head = (Scsp_server *)0; +Scsp_pending *scsp_pending_head = (Scsp_pending *)0; +int scsp_max_socket = -1; +int scsp_debug_mode = 0; +int scsp_trace_mode = 0; + + +/* + * Local variables + */ +static int scsp_hup_signal = 0; +static int scsp_int_signal = 0; + + +/* + * SIGHUP signal handler + * + * Arguments: + * sig signal number + * + * Returns: + * none + * + */ +void +scsp_sighup(sig) + int sig; +{ + /* + * Flag the signal + */ + scsp_hup_signal = 1; +} + + +/* + * SIGINT signal handler + * + * Arguments: + * sig signal number + * + * Returns: + * none + * + */ +void +scsp_sigint(sig) + int sig; +{ + /* + * Flag the signal + */ + scsp_int_signal = 1; +} + + +/* + * Process command line parameters + * + * Arguments: + * argc number of command-line arguments + * argv list of pointers to command-line arguments + * + * Returns: + * none + * + */ +void +initialize(argc, argv) + int argc; + char **argv; +{ + int i; + char *cp; + + /* + * Save program name, ignoring any path components + */ + if (prog = (char *)strrchr(argv[0], '/')) + prog++; + else + prog = argv[0]; + + /* + * Make sure we're being invoked by the super user + */ + i = getuid(); + if (i != 0) { + fprintf(stderr, "%s: You must be root to run this program\n", + prog); + exit(1); + } + + /* + * Check for command-line options + */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-d") == 0) { + /* + * -d option -- set debug mode + */ + scsp_debug_mode = 1; + } else if (strcmp(argv[i], "-f") == 0) { + /* + * -f option -- set config file name + */ + i++; + if (i >= argc) { + fprintf(stderr, "%s: Configuration file name missing\n", + prog); + exit(1); + } + scsp_config_file = argv[i]; + } else if (strncmp(argv[i], "-T", 2) == 0) { + /* + * -T option -- trace options + */ + for (cp = &argv[i][2]; *cp; cp++) { + if (*cp == 'c') + scsp_trace_mode |= SCSP_TRACE_CAFSM; + else if (*cp == 'h') + scsp_trace_mode |= SCSP_TRACE_HFSM; + else if (*cp == 'i') + scsp_trace_mode |= SCSP_TRACE_CFSM; + else if (*cp == 'C') + scsp_trace_mode |= SCSP_TRACE_CA_MSG; + else if (*cp == 'H') + scsp_trace_mode |= SCSP_TRACE_HELLO_MSG; + else if (*cp == 'I') + scsp_trace_mode |= SCSP_TRACE_IF_MSG; + else + fprintf(stderr, "Invalid trace specification '%c' ignored\n", + *cp); + } + } else { + /* + * Error -- unrecognized option + */ + fprintf(stderr, "%s: Unrecognized option \"%s\"\n", + prog, argv[i]); + exit(1); + } + } +} + + +/* + * Daemon housekeeping + * + * Arguments: + * None + * + * Returns: + * None + * + */ +static void +start_daemon() + +{ + int dpid, fd, file_count, rc; + + /* + * Ignore selected signals + */ +#ifdef SIGTTOU + signal(SIGTTOU, SIG_IGN); +#endif +#ifdef SIGTTIN + signal(SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + + /* + * Don't put the daemon into the background if + * we're in debug mode + */ + if (scsp_debug_mode) + goto daemon_bypass; + + /* + * Put the daemon into the background + */ + dpid = fork(); + if (dpid < 0) { + scsp_log(LOG_ERR, "fork failed"); + abort(); + } + if (dpid > 0) { + /* + * This is the parent process--just exit and let + * the daughter do all the work + */ + exit(0); + } + + /* + * Disassociate from any controlling terminal + */ + rc = setpgrp(0, getpid()); + if (rc <0) { + scsp_log(LOG_ERR, "can't change process group"); + exit(1); + } + fd = open("/dev/tty", O_RDWR); + if (fd >= 0) { + ioctl(fd, TIOCNOTTY, (char *)0); + close(fd); + } + + /* + * Close all open file descriptors + */ + file_count = getdtablesize(); + for (fd=0; fd<file_count; fd++) { + close(fd); + } + + /* + * Set up timers + */ +daemon_bypass: + init_timer(); + + /* + * Move to a safe directory + */ + chdir(SCSPD_DIR); + + /* + * Clear the file mode creation mask + */ + umask(0); + + + /* + * Set up signal handlers + */ + rc = (int)signal(SIGHUP, scsp_sighup); + if (rc == -1) { + scsp_log(LOG_ERR, "SIGHUP signal setup failed"); + exit(1); + } + + rc = (int)signal(SIGINT, scsp_sigint); + if (rc == -1) { + scsp_log(LOG_ERR, "SIGINT signal setup failed"); + exit(1); + } + + /* + * Set up syslog for error logging + */ + if (scsp_log_syslog || !scsp_log_file) { + openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON); + } + scsp_log(LOG_INFO, "Starting SCSP daemon"); +} + + +/* + * Main line code + * + * Process command line parameters, read configuration file, connect + * to configured clients, process data from DCSs. + * + * Arguments: + * argc number of command-line arguments + * argv list of pointers to command-line arguments + * + * Returns: + * none + * + */ +main(argc, argv) + int argc; + char *argv[]; + +{ + int i, rc, scsp_server_lsock; + Scsp_server *ssp; + Scsp_dcs *dcsp; + Scsp_pending *next_psp, *psp; + fd_set read_set, write_set, except_set; + + /* + * Process command line arguments + */ + initialize(argc, argv); + + /* + * Put the daemon into the background + */ + start_daemon(); + + /* + * Process configuration file + */ + rc = scsp_config(scsp_config_file); + if (rc) { + scsp_log(LOG_ERR, "Found %d error%s in configuration file", + rc, ((rc == 1) ? "" : "s")); + exit(1); + } + + /* + * Open the trace file if we need one + */ + if (scsp_trace_mode) { + scsp_open_trace(); + } + + /* + * Listen for connections from clients + */ + scsp_server_lsock = scsp_server_listen(); + if (scsp_server_lsock == -1) { + scsp_log(LOG_ERR, "server listen failed"); + abort(); + } + + /* + * Main program loop -- we wait for: + * a server listen to complete + * a DCS listen to complete + * a DCS connect to complete + * data from a server + * data from a DCS + */ + while (1) { + /* + * Set up the file descriptor sets and select to wait + * for input + */ + FD_ZERO(&read_set); + FD_ZERO(&write_set); + FD_ZERO(&except_set); + FD_SET(scsp_server_lsock, &read_set); + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_dcs_lsock != -1) + FD_SET(ssp->ss_dcs_lsock, &read_set); + if (ssp->ss_sock != -1) + FD_SET(ssp->ss_sock, &read_set); + for (dcsp = ssp->ss_dcs; dcsp; + dcsp = dcsp->sd_next) { + if (dcsp->sd_sock != -1) { + if (dcsp->sd_hello_state == + SCSP_HFSM_DOWN ) + FD_SET(dcsp->sd_sock, + &write_set); + else + FD_SET(dcsp->sd_sock, + &read_set); + } + } + } + for (psp = scsp_pending_head; psp; psp = psp->sp_next) { + FD_SET(psp->sp_sock, &read_set); + } + rc = select(scsp_max_socket + 1, &read_set, + &write_set, &except_set, + (struct timeval *)0); + if (rc < 0) { + /* + * Select error--check for possible signals + */ + if (harp_timer_exec) { + /* + * Timer tick--process it + */ + timer_proc(); + continue; + } else if (scsp_hup_signal) { + /* + * SIGHUP signal--reconfigure + */ + scsp_hup_signal = 0; + scsp_reconfigure(); + continue; + } else if (scsp_int_signal) { + /* + * SIGINT signal--dump control blocks + */ + print_scsp_dump(); + scsp_int_signal = 0; + continue; + } else if (errno == EINTR) { + /* + * EINTR--just ignore it + */ + continue; + } else { + /* + * Other error--this is a problem + */ + scsp_log(LOG_ERR, "Select failed"); + abort(); + } + } + + /* + * Check the read set for connections from servers + */ + if (FD_ISSET(scsp_server_lsock, &read_set)) { + FD_CLR(scsp_server_lsock, &read_set); + rc = scsp_server_accept(scsp_server_lsock); + } + + /* + * Check the write set for new connections to DCSs + */ + for (i = 0; i <= scsp_max_socket; i++) { + if (FD_ISSET(i, &write_set)) { + FD_CLR(i, &write_set); + if (dcsp = scsp_find_dcs(i)) { + rc = scsp_hfsm(dcsp, + SCSP_HFSM_VC_ESTAB, + (Scsp_msg *)0); + } + } + } + + /* + * Check the read set for connections from DCSs + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_dcs_lsock != -1 && + FD_ISSET(ssp->ss_dcs_lsock, + &read_set)) { + FD_CLR(ssp->ss_dcs_lsock, &read_set); + dcsp = scsp_dcs_accept(ssp); + if (dcsp) { + rc = scsp_hfsm(dcsp, + SCSP_HFSM_VC_ESTAB, + (Scsp_msg *)0); + } + } + } + + /* + * Check the read set for data from pending servers + */ + for (psp = scsp_pending_head; psp; psp = next_psp) { + next_psp = psp->sp_next; + if (FD_ISSET(psp->sp_sock, &read_set)) { + FD_CLR(psp->sp_sock, &read_set); + rc = scsp_pending_read(psp); + } + } + + /* + * Check the read set for data from servers or DCSs + */ + for (i = 0; i <= scsp_max_socket; i++) { + if (FD_ISSET(i, &read_set)) { + if (ssp = scsp_find_server(i)) { + rc = scsp_server_read(ssp); + } else if (dcsp = scsp_find_dcs(i)) { + rc = scsp_dcs_read(dcsp); + } + } + } + } +} |