summaryrefslogtreecommitdiffstats
path: root/usr.sbin/atm
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
committerphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
commitc3dd1fa899d435ea4bf79897f646a93cb80c94ac (patch)
tree98dfbc96e3c6aa7ff1f322855f6484c4e609819d /usr.sbin/atm
parent9ed6892f4808d56de443849229e151f8f7ad43b0 (diff)
downloadFreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.zip
FreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.tar.gz
Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc. This software was developed with the support of the Defense Advanced Research Projects Agency (DARPA).
Diffstat (limited to 'usr.sbin/atm')
-rw-r--r--usr.sbin/atm/Makefile33
-rw-r--r--usr.sbin/atm/Makefile.inc30
-rw-r--r--usr.sbin/atm/atmarpd/Makefile38
-rw-r--r--usr.sbin/atm/atmarpd/atmarp_config.c130
-rw-r--r--usr.sbin/atm/atmarpd/atmarp_log.c148
-rw-r--r--usr.sbin/atm/atmarpd/atmarp_scsp.c792
-rw-r--r--usr.sbin/atm/atmarpd/atmarp_subr.c962
-rw-r--r--usr.sbin/atm/atmarpd/atmarp_timer.c223
-rw-r--r--usr.sbin/atm/atmarpd/atmarp_var.h224
-rw-r--r--usr.sbin/atm/atmarpd/atmarpd.8129
-rw-r--r--usr.sbin/atm/atmarpd/atmarpd.c409
-rw-r--r--usr.sbin/atm/scspd/Makefile42
-rw-r--r--usr.sbin/atm/scspd/scsp_cafsm.c1448
-rw-r--r--usr.sbin/atm/scspd/scsp_config.c1160
-rw-r--r--usr.sbin/atm/scspd/scsp_config_lex.c528
-rw-r--r--usr.sbin/atm/scspd/scsp_config_parse.y410
-rw-r--r--usr.sbin/atm/scspd/scsp_hfsm.c580
-rw-r--r--usr.sbin/atm/scspd/scsp_if.c655
-rw-r--r--usr.sbin/atm/scspd/scsp_if.h194
-rw-r--r--usr.sbin/atm/scspd/scsp_input.c1103
-rw-r--r--usr.sbin/atm/scspd/scsp_log.c265
-rw-r--r--usr.sbin/atm/scspd/scsp_msg.c611
-rw-r--r--usr.sbin/atm/scspd/scsp_msg.h462
-rw-r--r--usr.sbin/atm/scspd/scsp_output.c934
-rw-r--r--usr.sbin/atm/scspd/scsp_print.c1315
-rw-r--r--usr.sbin/atm/scspd/scsp_socket.c1349
-rw-r--r--usr.sbin/atm/scspd/scsp_subr.c1123
-rw-r--r--usr.sbin/atm/scspd/scsp_timer.c265
-rw-r--r--usr.sbin/atm/scspd/scsp_var.h434
-rw-r--r--usr.sbin/atm/scspd/scspd.8443
-rw-r--r--usr.sbin/atm/scspd/scspd.c545
31 files changed, 16984 insertions, 0 deletions
diff --git a/usr.sbin/atm/Makefile b/usr.sbin/atm/Makefile
new file mode 100644
index 0000000..a32385f
--- /dev/null
+++ b/usr.sbin/atm/Makefile
@@ -0,0 +1,33 @@
+#
+#
+# ===================================
+# 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 $
+#
+#
+
+SUBDIR= atmarpd \
+ scspd
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/atm/Makefile.inc b/usr.sbin/atm/Makefile.inc
new file mode 100644
index 0000000..bcc3406
--- /dev/null
+++ b/usr.sbin/atm/Makefile.inc
@@ -0,0 +1,30 @@
+#
+#
+# ===================================
+# 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 $
+#
+#
+
+BINDIR?= /usr/sbin
diff --git a/usr.sbin/atm/atmarpd/Makefile b/usr.sbin/atm/atmarpd/Makefile
new file mode 100644
index 0000000..7a4ca81
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/Makefile
@@ -0,0 +1,38 @@
+#
+#
+# ===================================
+# 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= atmarpd
+SRCS= atmarpd.c atmarp_config.c atmarp_log.c atmarp_scsp.c \
+ atmarp_subr.c atmarp_timer.c
+MAN8= atmarpd.8
+
+CFLAGS+= -I ${.CURDIR}/../../../sys
+LDADD+= -latm -lmd
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/atm/atmarpd/atmarp_config.c b/usr.sbin/atm/atmarpd/atmarp_config.c
new file mode 100644
index 0000000..5a4b78d
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/atmarp_config.c
@@ -0,0 +1,130 @@
+/*
+ *
+ * ===================================
+ * 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: atmarp_config.c,v 1.5 1998/08/13 20:11:11 johnc Exp $
+ *
+ */
+
+/*
+ * Server Cache Synchronization Protocol (SCSP) Support
+ * ----------------------------------------------------
+ *
+ * SCSP-ATMARP server interface: configuration support
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: atmarp_config.c,v 1.5 1998/08/13 20:11:11 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 "../scspd/scsp_msg.h"
+#include "../scspd/scsp_if.h"
+#include "../scspd/scsp_var.h"
+#include "atmarp_var.h"
+
+
+/*
+ * Configure network interface for ATMARP cache synchronization
+ *
+ * Verify the network interface name and set the appropriate fields
+ * in the ATMARP interface entry.
+ *
+ * Arguments:
+ * netif pointer to network interface name
+ *
+ * Returns:
+ * 0 success
+ * errno reason for failure
+ *
+ */
+int
+atmarp_cfg_netif(netif)
+ char *netif;
+{
+ int rc;
+ Atmarp_intf *aip = (Atmarp_intf *)0;
+ Atm_addr_nsap *anp;
+
+ /*
+ * Get an ATMARP interface block
+ */
+ aip = (Atmarp_intf *)UM_ALLOC(sizeof(Atmarp_intf));
+ if (!aip)
+ atmarp_mem_err("atmarp_cfg_netif: sizeof(Atmarp_intf)");
+ UM_ZERO(aip, sizeof(Atmarp_intf));
+
+ /*
+ * Make sure we're configuring a valid
+ * network interface
+ */
+ rc = verify_nif_name(netif);
+ if (rc == 0) {
+ fprintf(stderr, "%s: \"%s\" is not a valid network interface\n",
+ prog, netif);
+ rc = EINVAL;
+ goto cfg_fail;
+ } else if (rc < 0) {
+ rc = errno;
+ fprintf(stderr, "%s: can't verify network interface \"%s\"\n",
+ prog, netif);
+ goto cfg_fail;
+ }
+
+ /*
+ * Update the interface entry
+ */
+ strcpy(aip->ai_intf, netif);
+ aip->ai_state = AI_STATE_NULL;
+ aip->ai_scsp_sock = -1;
+ LINK2TAIL(aip, Atmarp_intf, atmarp_intf_head, ai_next);
+
+ return(0);
+
+cfg_fail:
+ if (aip)
+ UM_FREE(aip);
+
+ return(rc);
+}
diff --git a/usr.sbin/atm/atmarpd/atmarp_log.c b/usr.sbin/atm/atmarpd/atmarp_log.c
new file mode 100644
index 0000000..8de5415
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/atmarp_log.c
@@ -0,0 +1,148 @@
+/*
+ *
+ * ===================================
+ * 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: atmarp_log.c,v 1.1 1998/07/24 17:11:51 johnc Exp $
+ *
+ */
+
+
+/*
+ * Server Cache Synchronization Protocol (SCSP) Support
+ * ----------------------------------------------------
+ *
+ * SCSP-ATMARP server interface: logging routines
+ *
+ */
+
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: atmarp_log.c,v 1.1 1998/07/24 17:11:51 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 "../scspd/scsp_msg.h"
+#include "../scspd/scsp_if.h"
+#include "../scspd/scsp_var.h"
+#include "atmarp_var.h"
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+
+/*
+ * Write a message to atmarpd's log
+ *
+ * Arguments:
+ * level the level (error, info, etc.) of the message
+ * fmt printf-style format string
+ * ... parameters for printf-style use according to fmt
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+#if __STDC__
+atmarp_log(const int level, const char *fmt, ...)
+#else
+atmarp_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 (atmarp_debug_mode) {
+ vprintf(fmt, ap);
+ printf("\n");
+ return;
+ }
+
+ /*
+ * Check whether we have a log file set up
+ */
+ if (!atmarp_log_file) {
+ /*
+ * Write to syslog
+ */
+ vsyslog(level, fmt, ap);
+ } else {
+ /*
+ * Write to the log file
+ */
+ vfprintf(atmarp_log_file, fmt, ap);
+ fprintf(atmarp_log_file, "\n");
+ }
+
+ va_end(ap);
+}
+
+
+/*
+ * Log a memory error and exit
+ *
+ * Arguments:
+ * cp message to log
+ *
+ * Returns:
+ * exits, does not return
+ *
+ */
+void
+atmarp_mem_err(cp)
+ char *cp;
+{
+ atmarp_log(LOG_CRIT, "out of memory: %s", cp);
+ exit(2);
+}
diff --git a/usr.sbin/atm/atmarpd/atmarp_scsp.c b/usr.sbin/atm/atmarpd/atmarp_scsp.c
new file mode 100644
index 0000000..e063821
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/atmarp_scsp.c
@@ -0,0 +1,792 @@
+/*
+ *
+ * ===================================
+ * 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: atmarp_scsp.c,v 1.6 1998/08/13 20:11:11 johnc Exp $
+ *
+ */
+
+/*
+ * Server Cache Synchronization Protocol (SCSP) Support
+ * ----------------------------------------------------
+ *
+ * SCSP-ATMARP server interface: SCSP/ATMARP interface code
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: atmarp_scsp.c,v 1.6 1998/08/13 20:11:11 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 <netatm/uni/uniip_var.h>
+
+#include <libatm.h>
+#include "../scspd/scsp_msg.h"
+#include "../scspd/scsp_if.h"
+#include "../scspd/scsp_var.h"
+#include "atmarp_var.h"
+
+
+/*
+ * Send the cache for a LIS to SCSP
+ *
+ *
+ * Arguments:
+ * aip pointer to interface block
+ *
+ * Returns:
+ * 0 cache sent to SCSP OK
+ * errno reason for failure
+ *
+ */
+int
+atmarp_scsp_cache(aip, msg)
+ Atmarp_intf *aip;
+ Scsp_if_msg *msg;
+{
+ int i, len, rc = 0;
+ Atmarp *aap;
+ Scsp_if_msg *smp = (Scsp_if_msg *)0;
+ Scsp_atmarp_msg *sap;
+
+ /*
+ * Figure out how big the message needs to be
+ */
+ len = sizeof(Scsp_if_msg_hdr);
+ for (i = 0; i < ATMARP_HASHSIZ; i++) {
+ for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) {
+ len += sizeof(Scsp_atmarp_msg);
+ }
+ }
+
+ /*
+ * Get memory for the cache message
+ */
+ smp = (Scsp_if_msg *)UM_ALLOC(len);
+ if (!smp) {
+ atmarp_mem_err("atmarp_scsp_cache: len");
+ }
+ UM_ZERO(smp, len);
+
+ /*
+ * Set header fields in SCSP message
+ */
+ smp->si_type = SCSP_CACHE_RSP;
+ smp->si_proto = SCSP_PROTO_ATMARP;
+ smp->si_len = len;
+ smp->si_tok = msg->si_tok;
+
+ /*
+ * Loop through the cache, adding each entry to the SCSP
+ * Cache Response message
+ */
+ sap = &smp->si_atmarp;
+ for (i = 0; i < ATMARP_HASHSIZ; i++) {
+ for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) {
+ sap->sa_state = SCSP_ASTATE_NEW;
+ sap->sa_cpa = aap->aa_dstip;
+ ATM_ADDR_COPY(&aap->aa_dstatm, &sap->sa_cha);
+ ATM_ADDR_COPY(&aap->aa_dstatmsub, &sap->sa_csa);
+ sap->sa_key = aap->aa_key;
+ sap->sa_oid = aap->aa_oid;
+ sap->sa_seq = aap->aa_seq;
+ sap++;
+ }
+ }
+
+ /*
+ * Send the message to SCSP
+ */
+ rc = atmarp_scsp_out(aip, (char *)smp, len);
+
+ /*
+ * Free the message
+ */
+cache_done:
+ if (smp)
+ UM_FREE(smp);
+
+ return(rc);
+}
+
+
+/*
+ * Answer a reqeust for information about a cache entry
+ *
+ * Arguments:
+ * aap pointer to entry
+ * state entry's new state
+ *
+ * Returns:
+ * 0 success
+ * errno reason for failure
+ *
+ */
+int
+atmarp_scsp_solicit(aip, smp)
+ Atmarp_intf *aip;
+ Scsp_if_msg *smp;
+{
+ int i, rc = 0;
+ Atmarp *aap;
+ Scsp_if_msg *rsp = (Scsp_if_msg *)0;
+
+ /*
+ * Search the interface's ATMARP cache for an entry with
+ * the specified cache key and origin ID
+ */
+ for (i = 0; i < ATMARP_HASHSIZ; i++) {
+ for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) {
+ if (KEY_EQUAL(&aap->aa_key,
+ &smp->si_sum.ss_key) &&
+ OID_EQUAL(&aap->aa_oid,
+ &smp->si_sum.ss_oid))
+ break;
+ }
+ if (aap)
+ break;
+ }
+
+ /*
+ * Get storage for a Solicit Response
+ */
+ rsp = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg));
+ if (!rsp) {
+ atmarp_mem_err("atmarp_scsp_solicit: sizeof(Scsp_if_msg)");
+ }
+ UM_ZERO(rsp, sizeof(Scsp_if_msg));
+
+ /*
+ * Fill out the Solicit Rsp
+ */
+ rsp->si_type = SCSP_SOLICIT_RSP;
+ rsp->si_proto = smp->si_proto;
+ rsp->si_tok = smp->si_tok;
+
+ if (aap) {
+ /*
+ * Copy fields from the ATMARP entry to the SCSP
+ * Update Request message
+ */
+ rsp->si_rc = SCSP_RSP_OK;
+ rsp->si_len = sizeof(Scsp_if_msg_hdr) +
+ sizeof(Scsp_atmarp_msg);
+ rsp->si_atmarp.sa_state = SCSP_ASTATE_UPD;
+ rsp->si_atmarp.sa_cpa = aap->aa_dstip;
+ ATM_ADDR_COPY(&aap->aa_dstatm, &rsp->si_atmarp.sa_cha);
+ ATM_ADDR_COPY(&aap->aa_dstatmsub, &rsp->si_atmarp.sa_csa);
+ rsp->si_atmarp.sa_key = aap->aa_key;
+ rsp->si_atmarp.sa_oid = aap->aa_oid;
+ rsp->si_atmarp.sa_seq = aap->aa_seq;
+ } else {
+ /*
+ * Entry not found--set return code
+ */
+ rsp->si_rc = SCSP_RSP_NOT_FOUND;
+ rsp->si_len = smp->si_len;
+ rsp->si_sum = smp->si_sum;
+ }
+
+ /*
+ * Send the message to SCSP
+ */
+ rc = atmarp_scsp_out(aip, (char *)rsp, rsp->si_len);
+ UM_FREE(rsp);
+
+ return(rc);
+}
+
+
+/*
+ * Send a cache update to SCSP
+ *
+ * Arguments:
+ * aap pointer to entry
+ * state entry's new state
+ *
+ * Returns:
+ * 0 success
+ * errno reason for failure
+ *
+ */
+int
+atmarp_scsp_update(aap, state)
+ Atmarp *aap;
+ int state;
+{
+ int i, len, rc = 0;
+ Atmarp_intf *aip = aap->aa_intf;
+ Scsp_if_msg *smp = (Scsp_if_msg *)0;
+ Scsp_atmarp_msg *sap;
+
+ /*
+ * Make sure the connection to SCSP is active
+ */
+ if (aip->ai_state == AI_STATE_NULL) {
+ return(0);
+ }
+
+ /*
+ * Get memory for the cache message
+ */
+ smp = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg));
+ if (!smp) {
+ atmarp_mem_err("atmarp_scsp_update: sizeof(Scsp_if_msg)");
+ }
+ UM_ZERO(smp, sizeof(Scsp_if_msg));
+
+ /*
+ * Set header fields in SCSP message
+ */
+ smp->si_type = SCSP_UPDATE_REQ;
+ smp->si_proto = SCSP_PROTO_ATMARP;
+ smp->si_len = sizeof(Scsp_if_msg_hdr) + sizeof(Scsp_atmarp_msg);
+
+ /*
+ * Copy fields from the ATMARP entry to the SCSP
+ * Update Request message
+ */
+ smp->si_atmarp.sa_state = state;
+ smp->si_atmarp.sa_cpa = aap->aa_dstip;
+ ATM_ADDR_COPY(&aap->aa_dstatm, &smp->si_atmarp.sa_cha);
+ ATM_ADDR_COPY(&aap->aa_dstatmsub, &smp->si_atmarp.sa_csa);
+ smp->si_atmarp.sa_key = aap->aa_key;
+ smp->si_atmarp.sa_oid = aap->aa_oid;
+ smp->si_atmarp.sa_seq = aap->aa_seq;
+
+ /*
+ * Send the message to SCSP
+ */
+ rc = atmarp_scsp_out(aap->aa_intf, (char *)smp, smp->si_len);
+
+ UM_FREE(smp);
+ return(rc);
+}
+
+
+/*
+ * Respond to a Cache Update Indication from SCSP
+ *
+ *
+ * Arguments:
+ * aip pointer to interface control block
+ * smp pointer to message from SCSP
+ *
+ * Returns:
+ * 0 Message processed OK
+ * errno Reason for failure
+ *
+ */
+int
+atmarp_scsp_update_in(aip, smp)
+ Atmarp_intf *aip;
+ Scsp_if_msg *smp;
+{
+ int accept, rc;
+ Atmarp *aap;
+
+ /*
+ * Look up the entry
+ */
+ ATMARP_LOOKUP(aip, smp->si_atmarp.sa_cpa.s_addr, aap);
+
+ /*
+ * Whether we accept the request depends on whether we
+ * already have an entry for it
+ */
+ if (!aap) {
+ /*
+ * We don't have this entry--accept it
+ */
+ accept = 1;
+ } else {
+ /*
+ * We do have an entry for this host--check the
+ * origin ID
+ */
+ if (bcmp(&aip->ai_ip_addr.s_addr,
+ smp->si_atmarp.sa_oid.id,
+ SCSP_ATMARP_ID_LEN) == 0) {
+ /*
+ * The received entry originated with us--
+ * reject it
+ */
+ accept = 0;
+ } else if (bcmp(&aip->ai_ip_addr.s_addr,
+ aap->aa_oid.id,
+ SCSP_ATMARP_ID_LEN) == 0) {
+ /*
+ * We originated the entry we currently have--
+ * only accept the new one if SCSP has higher
+ * priority than the existing entry
+ */
+ accept = aap->aa_origin < UAO_SCSP;
+ } else {
+ /*
+ * Accept the entry if it is more up-to-date
+ * than the existing entry
+ */
+ accept = KEY_EQUAL(&aap->aa_key,
+ &smp->si_atmarp.sa_key) &&
+ OID_EQUAL(&aap->aa_oid,
+ &smp->si_atmarp.sa_oid) &&
+ (aap->aa_seq < smp->si_atmarp.sa_seq);
+ }
+ }
+
+ /*
+ * Add the entry to the cache, if appropriate
+ */
+ if (accept) {
+ if (!aap) {
+ /*
+ * Copy info from SCSP to a new cache entry
+ */
+ aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp));
+ if (!aap)
+ atmarp_mem_err("atmarp_scsp_update_in: sizeof(Atmarp)");
+ UM_ZERO(aap, sizeof(Atmarp));
+
+ aap->aa_dstip = smp->si_atmarp.sa_cpa;
+ aap->aa_dstatm = smp->si_atmarp.sa_cha;
+ aap->aa_dstatmsub = smp->si_atmarp.sa_csa;
+ aap->aa_key = smp->si_atmarp.sa_key;
+ aap->aa_oid = smp->si_atmarp.sa_oid;
+ aap->aa_seq = smp->si_atmarp.sa_seq;
+ aap->aa_intf = aip;
+ aap->aa_origin = UAO_SCSP;
+
+ /*
+ * Add the new entry to our cache
+ */
+ ATMARP_ADD(aip, aap);
+ } else {
+ /*
+ * Update the existing entry
+ */
+ aap->aa_dstip = smp->si_atmarp.sa_cpa;
+ aap->aa_dstatm = smp->si_atmarp.sa_cha;
+ aap->aa_dstatmsub = smp->si_atmarp.sa_csa;
+ aap->aa_key = smp->si_atmarp.sa_key;
+ aap->aa_oid = smp->si_atmarp.sa_oid;
+ aap->aa_seq = smp->si_atmarp.sa_seq;
+ aap->aa_origin = UAO_SCSP;
+ }
+
+ /*
+ * Send the updated entry to the kernel
+ */
+ if (atmarp_update_kernel(aap) == 0)
+ rc = SCSP_RSP_OK;
+ else
+ rc = SCSP_RSP_REJ;
+ } else {
+ rc = SCSP_RSP_REJ;
+ }
+
+ /*
+ * Turn the received message into a response
+ */
+ smp->si_type = SCSP_UPDATE_RSP;
+ smp->si_rc = rc;
+
+ /*
+ * Send the message to SCSP
+ */
+ rc = atmarp_scsp_out(aip, (char *)smp, smp->si_len);
+
+ return(rc);
+}
+
+
+/*
+ * Read and process a message from SCSP
+ *
+ *
+ * Arguments:
+ * aip interface for read
+ *
+ * Returns:
+ * 0 success
+ * errno reason for failure
+ *
+ */
+int
+atmarp_scsp_read(aip)
+ Atmarp_intf *aip;
+{
+ int len, rc;
+ char *buff = (char *)0;
+ Scsp_if_msg *smp;
+ Scsp_if_msg_hdr msg_hdr;
+
+ /*
+ * Read the header of the message from SCSP
+ */
+ len = read(aip->ai_scsp_sock, (char *)&msg_hdr,
+ sizeof(msg_hdr));
+ if (len == -1) {
+ rc = errno;
+ goto read_fail;
+ } else if (len != sizeof(msg_hdr)) {
+ rc = EMSGSIZE;
+ goto read_fail;
+ }
+
+ /*
+ * Get a buffer that will hold the message
+ */
+ buff = UM_ALLOC(msg_hdr.sh_len);
+ if (!buff)
+ atmarp_mem_err("atmarp_scsp_read: msg_hdr.sh_len");
+ UM_COPY(&msg_hdr, buff, sizeof(msg_hdr));
+
+ /*
+ * Read the rest of the message, if there is more than
+ * just a header
+ */
+ len = msg_hdr.sh_len - sizeof(msg_hdr);
+ if (len > 0) {
+ len = read(aip->ai_scsp_sock, buff + sizeof(msg_hdr),
+ len);
+ if (len == -1) {
+ rc = errno;
+ goto read_fail;
+ } else if (len != msg_hdr.sh_len - sizeof(msg_hdr)) {
+ rc = EMSGSIZE;
+ goto read_fail;
+ }
+ }
+
+ /*
+ * Handle the message based on its type
+ */
+ smp = (Scsp_if_msg *)buff;
+ switch(smp->si_type) {
+ case SCSP_CFG_RSP:
+ if (smp->si_rc != SCSP_RSP_OK) {
+ goto read_fail;
+ }
+ break;
+ case SCSP_CACHE_IND:
+ rc = atmarp_scsp_cache(aip, smp);
+ break;
+ case SCSP_SOLICIT_IND:
+ rc = atmarp_scsp_solicit(aip, smp);
+ break;
+ case SCSP_UPDATE_IND:
+ rc = atmarp_scsp_update_in(aip, smp);
+ break;
+ case SCSP_UPDATE_RSP:
+ /*
+ * Ignore Update Responses
+ */
+ rc = 0;
+ break;
+ default:
+ atmarp_log(LOG_ERR, "Unexpected SCSP message received");
+ return(EOPNOTSUPP);
+ }
+
+ UM_FREE(buff);
+ return(rc);
+
+read_fail:
+ if (buff) {
+ UM_FREE(buff);
+ }
+
+ /*
+ * Error on socket to SCSP--close the socket and set the state
+ * so that we know to retry when the cache timer fires.
+ */
+ atmarp_scsp_close(aip);
+
+ return(rc);
+}
+
+
+/*
+ * Send a message to SCSP
+ *
+ *
+ * Arguments:
+ * aip pointer to ATMARP interface to send message on
+ * buff pointer to message buffer
+ * len length of message
+ *
+ * Returns:
+ * 0 message sent
+ * errno reason for failure
+ *
+ */
+int
+atmarp_scsp_out(aip, buff, len)
+ Atmarp_intf *aip;
+ char *buff;
+ int len;
+{
+ int rc;
+
+ /*
+ * Send the message to SCSP
+ */
+ rc = write(aip->ai_scsp_sock, buff, len);
+ if (rc == len)
+ return(0);
+
+ /*
+ * Error on write--close the socket to SCSP, clean up and
+ * set the state so that we know to retry when the cache
+ * timer fires.
+ */
+ atmarp_scsp_close(aip);
+
+ /*
+ * Set the return code
+ */
+ if (rc < 0) {
+ rc = errno;
+ } else {
+ rc = EFAULT;
+ }
+
+ return(rc);
+}
+
+
+/*
+ * Set up a socket and connect to SCSP
+ *
+ * Arguments:
+ * aip pointer to interface block
+ *
+ * Returns:
+ * 0 success, ai_scsp_sock is set
+ * errno reason for failure
+ *
+ *
+ */
+int
+atmarp_scsp_connect(aip)
+ Atmarp_intf *aip;
+{
+ int len, rc, sd;
+ char *sn;
+ Scsp_if_msg cfg_msg;
+
+ static struct sockaddr local_addr = {
+#if (defined(BSD) && (BSD >= 199103))
+ sizeof(struct sockaddr), /* sa_len */
+#endif
+ AF_UNIX, /* sa_family */
+ ATMARP_SOCK_PREFIX /* sa_data */
+ };
+ 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 */
+ };
+
+ /*
+ * Construct a name for the socket
+ */
+ strncpy(local_addr.sa_data, ATMARP_SOCK_PREFIX,
+ sizeof(local_addr.sa_data));
+ (void)strncat(local_addr.sa_data, aip->ai_intf,
+ sizeof(local_addr.sa_data));
+ sn = strdup(local_addr.sa_data);
+ if (!sn)
+ atmarp_mem_err("atmarp_scsp_connect: strdup");
+
+ /*
+ * Clean up any old socket
+ */
+ rc = unlink(sn);
+ if (rc < 0 && errno != ENOENT)
+ return(errno);
+
+ /*
+ * Open a socket to SCSP
+ */
+ sd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sd == -1) {
+ UM_FREE(sn);
+ return(errno);
+ }
+ if (sd > atmarp_max_socket) {
+ atmarp_max_socket = sd;
+ }
+
+ /*
+ * 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) {
+ rc = errno;
+ goto scsp_connect_fail;
+ }
+
+ /*
+ * Bind the local socket address
+ */
+ rc = bind(sd, &local_addr, sizeof(local_addr));
+ if (rc) {
+ rc = errno;
+ goto scsp_connect_fail;
+ }
+
+ /*
+ * Connect to SCSP
+ */
+ rc = connect(sd, &scsp_addr, sizeof(scsp_addr));
+ if (rc) {
+ rc = errno;
+ goto scsp_connect_fail;
+ }
+
+ /*
+ * Save socket information in interface control block
+ */
+ aip->ai_scsp_sock = sd;
+ aip->ai_scsp_sockname = sn;
+ aip->ai_state = AI_STATE_UP;
+
+ /*
+ * Send configuration information to SCSP
+ */
+ UM_ZERO(&cfg_msg, sizeof(cfg_msg));
+ cfg_msg.si_type = SCSP_CFG_REQ;
+ cfg_msg.si_proto = SCSP_PROTO_ATMARP;
+ strcpy(cfg_msg.si_cfg.atmarp_netif, aip->ai_intf);
+ len =sizeof(Scsp_if_msg_hdr) + strlen(aip->ai_intf) + 1;
+ cfg_msg.si_len = len;
+ rc = atmarp_scsp_out(aip, (char *)&cfg_msg, len);
+ if (rc) {
+ return(rc);
+ }
+
+ return(0);
+
+scsp_connect_fail:
+ (void)close(sd);
+ aip->ai_scsp_sock = -1;
+ UM_FREE(sn);
+ aip->ai_scsp_sockname = NULL;
+ aip->ai_state = AI_STATE_NULL;
+ return(rc);
+}
+
+
+/*
+ * Close a socket connection to SCSP
+ *
+ * Arguments:
+ * aip pointer to interface block for connection to be closed
+ *
+ * Returns:
+ * none
+ *
+ *
+ */
+void
+atmarp_scsp_close(aip)
+ Atmarp_intf *aip;
+{
+ /*
+ * Close and unlink the SCSP socket
+ */
+ (void)close(aip->ai_scsp_sock);
+ aip->ai_scsp_sock = -1;
+ (void)unlink(aip->ai_scsp_sockname);
+ UM_FREE(aip->ai_scsp_sockname);
+ aip->ai_scsp_sockname = NULL;
+
+ aip->ai_state = AI_STATE_NULL;
+
+ return;
+}
+
+
+/*
+ * Disconnect an interface from SCSP
+ *
+ * Arguments:
+ * aip pointer to interface block for connection to be closed
+ *
+ * Returns:
+ * 0 success, ai_scsp_sock is set
+ * errno reason for failure
+ *
+ *
+ */
+int
+atmarp_scsp_disconnect(aip)
+ Atmarp_intf *aip;
+{
+ int i;
+ Atmarp *aap;
+
+ /*
+ * Close and unlink the SCSP socket
+ */
+ atmarp_scsp_close(aip);
+
+ /*
+ * Free the ATMARP cache associated with the interface
+ */
+ for (i = 0; i < ATMARP_HASHSIZ; i++) {
+ for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) {
+ UM_FREE(aap);
+ }
+ aip->ai_arptbl[i] = (Atmarp *)0;
+ }
+
+ return(0);
+}
diff --git a/usr.sbin/atm/atmarpd/atmarp_subr.c b/usr.sbin/atm/atmarpd/atmarp_subr.c
new file mode 100644
index 0000000..3cc20e0
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/atmarp_subr.c
@@ -0,0 +1,962 @@
+/*
+ *
+ * ===================================
+ * 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: atmarp_subr.c,v 1.6 1998/08/13 20:11:11 johnc Exp $
+ *
+ */
+
+
+/*
+ * Server Cache Synchronization Protocol (SCSP) Support
+ * ----------------------------------------------------
+ *
+ * SCSP-ATMARP server interface: misc. subroutines
+ *
+ */
+
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: atmarp_subr.c,v 1.6 1998/08/13 20:11:11 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 <sys/sockio.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 <netatm/uni/uniip_var.h>
+
+#include <libatm.h>
+#include "../scspd/scsp_msg.h"
+#include "../scspd/scsp_if.h"
+#include "../scspd/scsp_var.h"
+#include "atmarp_var.h"
+
+
+/*
+ * Find an ATMARP interface, given its socket number
+ *
+ * Arguments:
+ * sd socket descriptor
+ *
+ * Returns:
+ * 0 failure
+ * else pointer to interface associated with socket
+ *
+ */
+Atmarp_intf *
+atmarp_find_intf_sock(sd)
+ int sd;
+{
+ Atmarp_intf *aip;
+
+ /*
+ * Loop through the list of interfaces
+ */
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ if (aip->ai_scsp_sock == sd)
+ break;
+ }
+
+ return(aip);
+}
+
+
+/*
+ * Find an ATMARP interface, given its name
+ *
+ * Arguments:
+ * name pointer to network interface name
+ *
+ * Returns:
+ * 0 failure
+ * else pointer to interface associated with name
+ *
+ */
+Atmarp_intf *
+atmarp_find_intf_name(name)
+ char *name;
+{
+ Atmarp_intf *aip;
+
+ /*
+ * Loop through the list of interfaces
+ */
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ if (strcmp(name, aip->ai_intf) == 0)
+ break;
+ }
+
+ return(aip);
+}
+
+
+/*
+ * Clear the mark field on all ATMARP cache entries
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+atmarp_clear_marks()
+
+{
+ int i;
+ Atmarp_intf *aip;
+ Atmarp *aap;
+
+ /*
+ * Loop through list of interfaces
+ */
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ /*
+ * Clear mark on every entry in the interface's cache
+ */
+ for (i = 0; i < ATMARP_HASHSIZ; i++ ) {
+ for (aap = aip->ai_arptbl[i]; aap;
+ aap = aap->aa_next) {
+ aap->aa_mark = 0;
+ }
+ }
+ }
+}
+
+
+/*
+ * Check whether the host system is an ATMARP server for
+ * the LIS associated with a given interface
+ *
+ * Arguments:
+ * aip pointer to an ATMARP interface control block
+ *
+ * Returns:
+ * 1 host is a server
+ * 0 host is not a server
+ *
+ */
+int
+atmarp_is_server(aip)
+ Atmarp_intf *aip;
+{
+ 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, aip->ai_intf);
+ 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);
+}
+
+
+/*
+ * Check whether an interface is up and ready for service
+ *
+ * Arguments:
+ * aip pointer to network interface block
+ *
+ * Returns:
+ * 0 interface not ready, errno has reason
+ * 1 interface is ready to go (interface block is updated)
+ *
+ */
+int
+atmarp_if_ready(aip)
+ Atmarp_intf *aip;
+{
+ int i, len, mtu, rc, sel;
+ Atmarp *aap = (Atmarp *)0;
+ 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 sockaddr_in *ip_addr;
+ struct sockaddr_in subnet_mask;
+ Atm_addr_nsap *anp;
+
+ /*
+ * 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, aip->ai_intf);
+ len = do_info_ioctl(&air, sizeof(struct air_netif_rsp));
+ if (len <= 0) {
+ goto if_ready_fail;
+ }
+ 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) {
+ errno = EAFNOSUPPORT;
+ goto if_ready_fail;
+ }
+
+ /*
+ * Get the MTU for the network interface
+ */
+ mtu = get_mtu(aip->ai_intf);
+ if (mtu < 0) {
+ goto if_ready_fail;
+ }
+
+
+ /*
+ * Get the subnet mask associated with the
+ * network interface
+ */
+ rc = get_subnet_mask(aip->ai_intf, &subnet_mask);
+ if (rc || subnet_mask.sin_family != AF_INET) {
+ goto if_ready_fail;
+ }
+
+ /*
+ * Get physical interface information
+ */
+ 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) {
+ goto if_ready_fail;
+ }
+ intf_rsp = (struct air_int_rsp *)air.air_buf_addr;
+
+ /*
+ * Check the signalling manager
+ */
+ 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) {
+ errno = EINVAL;
+ goto if_ready_fail;
+ }
+
+ /*
+ * Check the interface state
+ */
+ if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) {
+ errno = EINVAL;
+ goto if_ready_fail;
+ }
+
+ /*
+ * Check the address format
+ */
+ 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)) {
+ errno = EINVAL;
+ goto if_ready_fail;
+ }
+
+ /*
+ * Find the selector byte value for the interface
+ */
+ for (i=0; i<strlen(aip->ai_intf); i++) {
+ if (aip->ai_intf[i] >= '0' &&
+ aip->ai_intf[i] <= '9')
+ break;
+ }
+ sel = atoi(&aip->ai_intf[i]);
+
+ /*
+ * Make sure we're the server for this interface's LIS
+ */
+ if (!atmarp_is_server(aip)) {
+ rc = EINVAL;
+ goto if_ready_fail;
+ }
+
+ /*
+ * If we already have the interface active and the address
+ * hasn't changed, return
+ */
+ if (aip->ai_state != AI_STATE_NULL &&
+ bcmp((caddr_t) &((struct sockaddr_in *)
+ &netif_rsp->anp_proto_addr)->sin_addr,
+ (caddr_t)&aip->ai_ip_addr,
+ sizeof(aip->ai_ip_addr)) == 0 &&
+ ATM_ADDR_EQUAL(&intf_rsp->anp_addr,
+ &aip->ai_atm_addr) &&
+ ATM_ADDR_EQUAL(&intf_rsp->anp_subaddr,
+ &aip->ai_atm_subaddr)) {
+ return(1);
+ }
+
+ /*
+ * Delete any existing ATMARP cache entry for this interface
+ */
+ ATMARP_LOOKUP(aip, aip->ai_ip_addr.s_addr, aap);
+ if (aap) {
+ ATMARP_DELETE(aip, aap);
+ UM_FREE(aap);
+ }
+
+ /*
+ * Update the interface entry
+ */
+ aip->ai_ip_addr = ((struct sockaddr_in *)
+ &netif_rsp->anp_proto_addr)->sin_addr;
+ aip->ai_subnet_mask = subnet_mask.sin_addr;
+ aip->ai_mtu = mtu + 8;
+ ATM_ADDR_COPY(&intf_rsp->anp_addr,
+ &aip->ai_atm_addr);
+ ATM_ADDR_COPY(&intf_rsp->anp_subaddr,
+ &aip->ai_atm_subaddr);
+ anp = (Atm_addr_nsap *)aip->ai_atm_addr.address;
+ if (aip->ai_atm_addr.address_format == T_ATM_ENDSYS_ADDR) {
+ anp->aan_sel = sel;
+ } else if (aip->ai_atm_addr.address_format ==
+ T_ATM_E164_ADDR &&
+ aip->ai_atm_subaddr.address_format ==
+ T_ATM_ENDSYS_ADDR) {
+ anp->aan_sel = sel;
+ }
+
+ /*
+ * Get a new ATMARP cache for the interface
+ */
+ aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp));
+ if (!aap) {
+ atmarp_mem_err("atmarp_if_ready: sizeof(Atmarp)");
+ }
+ UM_ZERO(aap, sizeof(Atmarp));
+
+ /*
+ * Fill out the entry
+ */
+ aap->aa_dstip = aip->ai_ip_addr;
+ ATM_ADDR_COPY(&intf_rsp->anp_addr, &aap->aa_dstatm);
+ ATM_ADDR_COPY(&intf_rsp->anp_subaddr,
+ &aap->aa_dstatmsub);
+ aap->aa_key.key_len = SCSP_ATMARP_KEY_LEN;
+ scsp_cache_key(&aap->aa_dstatm, &aap->aa_dstip,
+ SCSP_ATMARP_KEY_LEN, aap->aa_key.key);
+ aap->aa_oid.id_len = SCSP_ATMARP_ID_LEN;
+ aap->aa_seq = SCSP_CSA_SEQ_MIN;
+ UM_COPY(&aap->aa_dstip.s_addr, aap->aa_oid.id,
+ SCSP_ATMARP_ID_LEN);
+ aap->aa_intf = aip;
+ aap->aa_flags = AAF_SERVER;
+ aap->aa_origin = UAO_LOCAL;
+
+ /*
+ * Add the entry to the cache
+ */
+ ATMARP_ADD(aip, aap);
+
+ /*
+ * Free dynamic data
+ */
+ UM_FREE(netif_rsp);
+ UM_FREE(intf_rsp);
+
+ return(1);
+
+if_ready_fail:
+ if (netif_rsp)
+ UM_FREE(netif_rsp);
+ if (intf_rsp)
+ UM_FREE(intf_rsp);
+
+ return(0);
+}
+
+
+/*
+ * Copy an ATMARP cache entry from kernel format into an entry
+ * suitable for our cache
+ *
+ * Arguments:
+ * cp pointer to kernel entry
+ *
+ * Returns:
+ * pointer to a new cache entry
+ * 0 error
+ *
+ */
+Atmarp *
+atmarp_copy_cache_entry(cp)
+ struct air_arp_rsp *cp;
+
+{
+ struct sockaddr_in *ipp;
+ Atmarp_intf *aip;
+ Atmarp *aap;
+
+ /*
+ * Sanity checks
+ */
+ if (!cp)
+ return((Atmarp *)0);
+ aip = atmarp_find_intf_name(cp->aap_intf);
+ if (!aip)
+ return((Atmarp *)0);
+
+ /*
+ * Get a new cache entry
+ */
+ aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp));
+ if (!aap) {
+ errno = ENOMEM;
+ return((Atmarp *)0);
+ }
+ UM_ZERO(aap, sizeof(Atmarp));
+ aap->aa_intf = aip;
+
+ /*
+ * Copy fields from the kernel entry to the new entry
+ */
+ ipp = (struct sockaddr_in *)&cp->aap_arp_addr;
+ UM_COPY(&ipp->sin_addr.s_addr, &aap->aa_dstip.s_addr,
+ sizeof(aap->aa_dstip.s_addr));
+ ATM_ADDR_COPY(&cp->aap_addr, &aap->aa_dstatm);
+ ATM_ADDR_COPY(&cp->aap_subaddr, &aap->aa_dstatmsub);
+ if (cp->aap_origin == UAO_PERM)
+ aap->aa_flags |= AAF_PERM;
+ aap->aa_origin = cp->aap_origin;
+
+ /*
+ * Set up fields for SCSP
+ */
+ aap->aa_key.key_len = SCSP_ATMARP_KEY_LEN;
+ scsp_cache_key(&cp->aap_addr, &aap->aa_dstip,
+ SCSP_ATMARP_KEY_LEN, (char *)aap->aa_key.key);
+ aap->aa_oid.id_len = SCSP_ATMARP_ID_LEN;
+ UM_COPY(&aip->ai_ip_addr.s_addr, aap->aa_oid.id,
+ SCSP_ATMARP_ID_LEN);
+ aap->aa_seq = SCSP_CSA_SEQ_MIN;
+
+ return(aap);
+}
+
+
+/*
+ * Send an updated ATMARP cache entry to the kernel
+ *
+ * Arguments:
+ * aap pointer to updated entry
+ *
+ * Returns:
+ * 0 success
+ * errno reason for failure
+ *
+ */
+int
+atmarp_update_kernel(aap)
+ Atmarp *aap;
+{
+ int rc = 0, sd;
+ struct atmaddreq aar;
+ struct sockaddr_in *ipp;
+
+ /*
+ * Build ioctl request
+ */
+ UM_ZERO(&aar, sizeof(aar));
+ aar.aar_opcode = AIOCS_ADD_ARP;
+ strncpy(aar.aar_arp_intf, aap->aa_intf->ai_intf,
+ sizeof(aar.aar_arp_intf));
+ aar.aar_arp_origin = UAO_SCSP;
+ ATM_ADDR_COPY(&aap->aa_dstatm, &aar.aar_arp_addr);
+ ipp = (struct sockaddr_in *)&aar.aar_arp_dst;
+ ipp->sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ ipp->sin_len = sizeof(struct sockaddr_in);
+#endif
+ ipp->sin_addr = aap->aa_dstip;
+
+ /*
+ * Pass the new mapping to the kernel
+ */
+ sd = socket(AF_ATM, SOCK_DGRAM, 0);
+ if (sd < 0) {
+ return(errno);
+ }
+ if (ioctl(sd, AIOCADD, (caddr_t)&aar) < 0) {
+ rc = errno;
+ }
+
+ (void)close(sd);
+ return(rc);
+}
+
+
+/*
+ * Read the ATMARP cache from the kernel and scan it, processing
+ * all entries
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+atmarp_get_updated_cache()
+{
+ int i, len, rc;
+ struct atminfreq air;
+ struct air_arp_rsp *cp;
+ struct sockaddr_in *ipp;
+ Atmarp_intf *aip;
+ Atmarp *aap;
+
+ /*
+ * Set up the request
+ */
+ air.air_opcode = AIOCS_INF_ARP;
+ air.air_arp_flags = ARP_RESET_REF;
+ ipp = (struct sockaddr_in *)&air.air_arp_addr;
+#if (defined(BSD) && (BSD >= 199103))
+ ipp->sin_len = sizeof(struct sockaddr_in);
+#endif
+ ipp->sin_family = AF_INET;
+ ipp->sin_addr.s_addr = INADDR_ANY;
+
+ /*
+ * Issue an ATMARP information request IOCTL
+ */
+ len = do_info_ioctl(&air, sizeof(struct air_arp_rsp) * 200);
+ if (len < 0) {
+ return;
+ }
+
+ /*
+ * Clear marks on all our cache entries
+ */
+ atmarp_clear_marks();
+
+ /*
+ * Loop through the cache, processing each entry
+ */
+ for (cp = (struct air_arp_rsp *) air.air_buf_addr;
+ len > 0;
+ cp++, len -= sizeof(struct air_arp_rsp)) {
+ atmarp_process_cache_entry(cp);
+ }
+
+ /*
+ * Now delete any old entries that aren't in the kernel's
+ * cache any more
+ */
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ for (i = 0; i < ATMARP_HASHSIZ; i++) {
+ for (aap = aip->ai_arptbl[i]; aap;
+ aap = aap->aa_next) {
+ /*
+ * Don't delete the entry for the server
+ */
+ if (aap->aa_flags & AAF_SERVER)
+ continue;
+ /*
+ * Delete any entry that isn't marked
+ */
+ if (!aap->aa_mark) {
+ rc = atmarp_scsp_update(aap,
+ SCSP_ASTATE_DEL);
+ if (rc == 0)
+ ATMARP_DELETE(aip, aap);
+ }
+ }
+ }
+ }
+
+ /*
+ * Free the ioctl response
+ */
+ UM_FREE(air.air_buf_addr);
+}
+
+
+/*
+ * Process an ATMARP cache entry from the kernel. If we already
+ * have the entry in our local cache, update it, otherwise, add
+ * it. In either case, mark our local copy so we know it's still
+ * in the kernel's cache.
+ *
+ * Arguments:
+ * cp pointer to kernel's cache entry
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+atmarp_process_cache_entry(cp)
+ struct air_arp_rsp *cp;
+
+{
+ int rc;
+ struct sockaddr_in *ipp = (struct sockaddr_in *)&cp->aap_arp_addr;
+ Atmarp_intf *aip;
+ Atmarp *aap;
+
+ /*
+ * See whether the entry is for an interface that's
+ * both configured and up
+ */
+ aip = atmarp_find_intf_name(cp->aap_intf);
+ if (!aip || aip->ai_state != AI_STATE_UP)
+ return;
+
+ /*
+ * Make sure the entry is valid
+ */
+ if (!(cp->aap_flags & ARPF_VALID))
+ return;
+
+ /*
+ * See whether we have the entry in our cache already
+ */
+ ATMARP_LOOKUP(aip, ipp->sin_addr.s_addr, aap);
+ if (aap) {
+ /*
+ * We already have this in our cache--update it
+ */
+ aap->aa_mark = 1;
+ if ((cp->aap_flags & ARPF_REFRESH) &&
+ cp->aap_origin != UAO_SCSP) {
+ aap->aa_seq++;
+ rc = atmarp_scsp_update(aap, SCSP_ASTATE_UPD);
+ }
+ } else {
+ /*
+ * This is a new entry--add it to the cache
+ */
+ aap = atmarp_copy_cache_entry(cp);
+ if (!aap)
+ return;
+ ATMARP_ADD(aip, aap);
+ aap->aa_mark = 1;
+ rc = atmarp_scsp_update(aap, SCSP_ASTATE_NEW);
+ }
+
+ return;
+}
+
+
+/*
+ * Print an SCSP ID
+ *
+ * Arguments:
+ * df pointer to a FILE for the dump
+ * ip pointer to the SCSP ID to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+print_scsp_id(df, ip)
+ FILE *df;
+ Scsp_id *ip;
+{
+ int i;
+
+ fprintf(df, "\t next: 0x%0x\n", (u_long)ip->next);
+ fprintf(df, "\t id_len: %d\n", ip->id_len);
+ fprintf(df, "\t id: 0x");
+ for (i = 0; i < ip->id_len; i++) {
+ fprintf(df, "%0x ", ip->id[i]);
+ }
+ fprintf(df, "\n");
+}
+
+
+/*
+ * Print an SCSP cacke key
+ *
+ * Arguments:
+ * df pointer to a FILE for the dump
+ * cp pointer to the cacke key to print
+ *
+ * Returns:
+ * None
+ *
+ */
+static void
+print_scsp_cache_key(df, cp)
+ FILE *df;
+ Scsp_ckey *cp;
+{
+ int i;
+
+ fprintf(df, "\t key_len: %d\n", cp->key_len);
+ fprintf(df, "\t key: 0x");
+ for (i = 0; i < cp->key_len; i++) {
+ fprintf(df, "%0x ", cp->key[i]);
+ }
+ fprintf(df, "\n");
+}
+
+
+/*
+ * Print an ATMARP interface entry
+ *
+ * Arguments:
+ * df pointer to a FILE for the dump
+ * aip pointer to interface entry
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+print_atmarp_intf(df, aip)
+ FILE *df;
+ Atmarp_intf *aip;
+{
+ if (!aip) {
+ fprintf(df, "print_atmarp_intf: NULL interface entry address\n");
+ return;
+ }
+
+ fprintf(df, "ATMARP network interface entry at 0x%0x\n",
+ (u_long)aip);
+ fprintf(df, "\tai_next: 0x%0x\n",
+ (u_long)aip->ai_next);
+ fprintf(df, "\tai_intf: %s\n", aip->ai_intf);
+ fprintf(df, "\tai_ip_addr: %s\n",
+ format_ip_addr(&aip->ai_ip_addr));
+ fprintf(df, "\tai_subnet_mask: %s\n",
+ inet_ntoa(aip->ai_subnet_mask));
+ fprintf(df, "\tai_mtu: %d\n", aip->ai_mtu);
+ fprintf(df, "\tai_atm_addr: %s\n",
+ format_atm_addr(&aip->ai_atm_addr));
+ fprintf(df, "\tai_atm_subaddr: %s\n",
+ format_atm_addr(&aip->ai_atm_subaddr));
+ fprintf(df, "\tai_scsp_sock: %d\n", aip->ai_scsp_sock);
+ fprintf(df, "\tai_scsp_sockname: %s\n", aip->ai_scsp_sockname);
+ fprintf(df, "\tai_state: %d\n", aip->ai_state);
+ fprintf(df, "\tai_mark: %d\n", aip->ai_mark);
+}
+
+
+/*
+ * Print an ATMARP cache entry
+ *
+ * Arguments:
+ * df pointer to a FILE for the dump
+ * aap pointer to cache entry
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+print_atmarp_cache(df, aap)
+ FILE *df;
+ Atmarp *aap;
+{
+ if (!aap) {
+ fprintf(df, "print_atmarp_cache: NULL ATMARP entry address\n");
+ return;
+ }
+
+ fprintf(df, "ATMARP entry at 0x%0x\n", (u_long)aap);
+ fprintf(df, "\taa_next: 0x%0x\n", (u_long)aap->aa_next);
+ fprintf(df, "\taa_dstip: %s\n", inet_ntoa(aap->aa_dstip));
+ fprintf(df, "\taa_dstatm: %s\n",
+ format_atm_addr(&aap->aa_dstatm));
+ fprintf(df, "\taa_dstatmsub: %s\n",
+ format_atm_addr(&aap->aa_dstatmsub));
+ fprintf(df, "\taa_key:\n");
+ print_scsp_cache_key(df, &aap->aa_key);
+ fprintf(df, "\taa_oid:\n");
+ print_scsp_id(df, &aap->aa_oid);
+ fprintf(df, "\taa_seq: %d (0x%x)\n", aap->aa_seq,
+ aap->aa_seq);
+ fprintf(df, "\taa_intf: 0x%0x\n", (u_long)aap->aa_intf);
+ fprintf(df, "\taa_flags: ");
+ if (aap->aa_flags & AAF_PERM)
+ fprintf(df, "Permanent ");
+ if (aap->aa_flags & AAF_SERVER)
+ fprintf(df, "Server ");
+ fprintf(df, "\n");
+ fprintf(df, "\taa_origin: %d\n", aap->aa_origin);
+ fprintf(df, "\taa_mark: %d\n", aap->aa_mark);
+}
+
+
+/*
+ * Print the entire ATMARP cache
+ *
+ * Arguments:
+ * df pointer to a FILE for the dump
+ * aip pointer to interface whose cache is to be printed
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+dump_atmarp_cache(df, aip)
+ FILE *df;
+ Atmarp_intf *aip;
+{
+ int i;
+ Atmarp *aap;
+
+ if (!aip) {
+ fprintf(df, "dump_atmarp_cache: NULL interface address\n");
+ return;
+ }
+
+ fprintf(df, "ATMARP cache for interface %s\n", aip->ai_intf);
+ for (i=0; i<ATMARP_HASHSIZ; i++) {
+ for (aap=aip->ai_arptbl[i]; aap; aap=aap->aa_next) {
+ print_atmarp_cache(df, aap);
+ }
+ }
+}
+
+
+#ifdef NOTDEF
+/*
+ * Print an ATMARP super-LIS entry
+ *
+ * Arguments:
+ * df pointer to a FILE for the dump
+ * asp pointer to super-LIS entry to be printed
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+print_atmarp_slis(df, asp)
+ FILE *df;
+ Atmarp_slis *asp;
+{
+ Atmarp_intf **aipp;
+
+ if (!asp) {
+ fprintf(df, "print_atmarp_slis: NULL SLIS address\n");
+ return;
+ }
+
+ fprintf(df, "SLIS entry at 0x%0x\n", (u_long)asp);
+ fprintf(df, "\tas_next: 0x%0x\n", (u_long)asp->as_next);
+ fprintf(df, "\tas_name: %s\n", asp->as_name);
+ fprintf(df, "\tas_cnt: %d\n", asp->as_cnt);
+ for (aipp = &asp->as_intfs; *aipp; aipp++) {
+ fprintf(df, "\t%s (%s)\n", (*aipp)->ai_name,
+ (*aipp)->ai_intf);
+ }
+}
+#endif
+
+
+/*
+ * Dump ATMARPD information
+ *
+ * Called as the result of a SIGINT signal.
+ *
+ * Arguments:
+ * sig signal number
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+atmarp_sigint(sig)
+ int sig;
+{
+ Atmarp_intf *aip;
+ FILE *df;
+ char fname[64];
+ static int dump_no = 0;
+
+ /*
+ * Build a file name
+ */
+ UM_ZERO(fname, sizeof(fname));
+ sprintf(fname, "/tmp/atmarpd.%d.%03d.out", getpid(), dump_no++);
+
+ /*
+ * Open the output file
+ */
+ df = fopen(fname, "w");
+ if (df == (FILE *)0)
+ return;
+
+ /*
+ * Dump the interface control blocks and
+ * associated ATMARP caches
+ */
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ print_atmarp_intf(df, aip);
+ fprintf(df, "\n");
+ dump_atmarp_cache(df, aip);
+ fprintf(df, "\n");
+ }
+
+ /*
+ * Close the output file
+ */
+ (void)fclose(df);
+}
diff --git a/usr.sbin/atm/atmarpd/atmarp_timer.c b/usr.sbin/atm/atmarpd/atmarp_timer.c
new file mode 100644
index 0000000..f9c41cc
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/atmarp_timer.c
@@ -0,0 +1,223 @@
+/*
+ *
+ * ===================================
+ * 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: atmarp_timer.c,v 1.2 1998/08/13 20:11:12 johnc Exp $
+ *
+ */
+
+/*
+ * Server Cache Synchronization Protocol (SCSP) Support
+ * ----------------------------------------------------
+ *
+ * SCSP-ATMARP server interface: timer routines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: atmarp_timer.c,v 1.2 1998/08/13 20:11:12 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 "../scspd/scsp_msg.h"
+#include "../scspd/scsp_if.h"
+#include "../scspd/scsp_var.h"
+#include "atmarp_var.h"
+
+
+/*
+ * Cache update timeout processing
+ *
+ * When the cache update timer fires, we read the cache from the
+ * kernel, update the internal cache, and restart the timer.
+ *
+ * Arguments:
+ * tp pointer to a HARP timer block
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+atmarp_cache_timeout(tp)
+ Harp_timer *tp;
+{
+ Atmarp_intf *aip;
+
+ /*
+ * Verify the status of all configured interfaces
+ */
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ if (atmarp_if_ready(aip)) {
+ /*
+ * The interface is up but we don't have
+ * a connection to SCSP--make a connection
+ */
+ if (aip->ai_state == AI_STATE_NULL)
+ (void)atmarp_scsp_connect(aip);
+ } else {
+ /*
+ * The interface is down--disconnect from SCSP
+ */
+ if (aip->ai_state != AI_STATE_NULL)
+ (void)atmarp_scsp_disconnect(aip);
+ }
+ }
+
+ /*
+ * Read the cache from the kernel
+ */
+ atmarp_get_updated_cache();
+
+ /*
+ * Restart the cache update timer
+ */
+ HARP_TIMER(tp, ATMARP_CACHE_INTERVAL, atmarp_cache_timeout);
+}
+
+
+/*
+ * Permanent cache entry timer processing
+ *
+ * Permanent cache entries (entries that are administratively added
+ * and the entry for the server itself) don't ever get refreshed, so
+ * we broadcast updates for them every 10 minutes so they won't get
+ * deleted from the remote servers' caches
+ *
+ * Arguments:
+ * tp pointer to a HARP timer block
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+atmarp_perm_timeout(tp)
+ Harp_timer *tp;
+{
+ int i, rc;
+ Atmarp_intf *aip;
+ Atmarp *aap;
+
+ /*
+ * Loop through all interfaces
+ */
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ /*
+ * Loop through the interface's cache
+ */
+ for (i = 0; i < ATMARP_HASHSIZ; i++) {
+ for (aap = aip->ai_arptbl[i]; aap;
+ aap = aap->aa_next) {
+ /*
+ * Find and update permanent entries
+ */
+ if ((aap->aa_flags & (AAF_PERM |
+ AAF_SERVER)) != 0) {
+ aap->aa_seq++;
+ rc = atmarp_scsp_update(aap,
+ SCSP_ASTATE_UPD);
+ }
+ }
+ }
+ }
+
+ /*
+ * Restart the permanent cache entry timer
+ */
+ HARP_TIMER(tp, ATMARP_PERM_INTERVAL, atmarp_perm_timeout);
+}
+
+
+/*
+ * Keepalive timeout processing
+ *
+ * When the keepalive timer fires, we send a NOP to SCSP. This
+ * will help us detect a broken connection.
+ *
+ * Arguments:
+ * tp pointer to a HARP timer block
+ *
+ * Returns:
+ * None
+ *
+ */
+void
+atmarp_keepalive_timeout(tp)
+ Harp_timer *tp;
+{
+ Atmarp_intf *aip;
+ Scsp_if_msg *msg;
+
+ /*
+ * Back off to start of DCS entry
+ */
+ aip = (Atmarp_intf *) ((caddr_t)tp -
+ (int)(&((Atmarp_intf *)0)->ai_keepalive_t));
+
+ /*
+ * Get a message buffer
+ */
+ msg = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg));
+ if (!msg) {
+ }
+ UM_ZERO(msg, sizeof(Scsp_if_msg));
+
+ /*
+ * Build a NOP message
+ */
+ msg->si_type = SCSP_NOP_REQ;
+ msg->si_proto = SCSP_PROTO_ATMARP;
+ msg->si_len = sizeof(Scsp_if_msg_hdr);
+
+ /*
+ * Send the message to SCSP
+ */
+ (void)atmarp_scsp_out(aip, (char *)msg, msg->si_len);
+ UM_FREE(msg);
+
+ /*
+ * Restart the keepalive timer
+ */
+ HARP_TIMER(&aip->ai_keepalive_t, ATMARP_KEEPALIVE_INTERVAL,
+ atmarp_keepalive_timeout);
+}
diff --git a/usr.sbin/atm/atmarpd/atmarp_var.h b/usr.sbin/atm/atmarpd/atmarp_var.h
new file mode 100644
index 0000000..e8dfa4b
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/atmarp_var.h
@@ -0,0 +1,224 @@
+/*
+ *
+ * ===================================
+ * 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: atmarp_var.h,v 1.6 1998/08/13 20:11:12 johnc Exp $
+ *
+ */
+
+/*
+ * Server Cache Synchronization Protocol (SCSP) Support
+ * ----------------------------------------------------
+ *
+ * SCSP-ATMARP server interface: control blocks
+ *
+ */
+
+#ifndef _ATMARP_ATMARP_VAR_H
+#define _ATMARP_ATMARP_VAR_H
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ * Operational constants
+ */
+#define ATMARP_DIR "/tmp"
+#define ATMARP_SOCK_PREFIX "AA_"
+#define ATMARP_CACHE_INTERVAL 50
+#define ATMARP_PERM_INTERVAL 600
+#define ATMARP_KEEPALIVE_INTERVAL 5
+
+
+/*
+ * Macros for manipulating ATMARP tables and entries
+ */
+#define ATMARP_HASHSIZ 19 /* Hash table size */
+
+#define ATMARP_HASH(ip) ((u_long)(ip) % ATMARP_HASHSIZ)
+
+#define ATMARP_ADD(ai, aa) \
+{ \
+ Atmarp **h; \
+ h = &ai->ai_arptbl[ATMARP_HASH((aa)->aa_dstip.s_addr)]; \
+ LINK2TAIL((aa), Atmarp, *h, aa_next); \
+}
+
+#define ATMARP_DELETE(ai, aa) \
+{ \
+ Atmarp **h; \
+ h = &ai->ai_arptbl[ATMARP_HASH((aa)->aa_dstip.s_addr)]; \
+ UNLINK((aa), Atmarp, *h, aa_next); \
+}
+
+#define ATMARP_LOOKUP(ai, ip, aa) \
+{ \
+ for ((aa) = (ai)->ai_arptbl[ATMARP_HASH(ip)]; \
+ (aa); (aa) = (aa)->aa_next) { \
+ if ((aa)->aa_dstip.s_addr == (ip)) \
+ break; \
+ } \
+}
+
+
+/*
+ * Macro to compare originator ID structures
+ */
+#define OID_EQUAL(id1, id2) \
+ (((id1)->id_len == (id2)->id_len) && \
+ (bcmp((caddr_t)(id1)->id, \
+ (caddr_t)(id2)->id, \
+ (id1)->id_len) == 0))
+
+#define KEY_EQUAL(key1, key2) \
+ (((key1)->key_len == (key2)->key_len) && \
+ (bcmp((caddr_t)(key1)->key, \
+ (caddr_t)(key2)->key, \
+ (key1)->key_len) == 0))
+
+
+/*
+ * Interface entry for ATMARP SCSP interface daemon
+ */
+struct atmarp_intf {
+ struct atmarp_intf *ai_next; /* Next chained I/F */
+ char ai_intf[IFNAMSIZ]; /* Network I/F name */
+ struct in_addr ai_ip_addr; /* IP address */
+ struct in_addr ai_subnet_mask; /* Subnet mask */
+ int ai_mtu; /* IP MTU */
+ Atm_addr ai_atm_addr; /* ATM address */
+ Atm_addr ai_atm_subaddr; /* ATM subaddress */
+ int ai_scsp_sock; /* Socket to SCSP */
+ Harp_timer ai_keepalive_t; /* Keepalive timer */
+ char *ai_scsp_sockname; /* Socket name */
+ u_char ai_state; /* Interface state */
+ u_char ai_mark;
+ struct atmarp *ai_arptbl[ATMARP_HASHSIZ]; /* ARP cache */
+};
+typedef struct atmarp_intf Atmarp_intf;
+
+#define AI_STATE_NULL 0
+#define AI_STATE_UP 1
+
+
+/*
+ * Super-LIS control block for ATMARP server daemon
+ */
+struct atmarp_slis {
+ struct atmarp_slis *as_next; /* Next super-LIS */
+ char *as_name; /* Name of super-LIS */
+ int as_cnt; /* LIS count */
+ Atmarp_intf *as_intfs; /* List of intfs */
+};
+typedef struct atmarp_slis Atmarp_slis;
+
+
+/*
+ * ATMARP cache entry format
+ */
+struct atmarp {
+ struct atmarp *aa_next; /* Hash chain link */
+ struct in_addr aa_dstip; /* Destination IP addr */
+ Atm_addr aa_dstatm; /* Destination ATM addr */
+ Atm_addr aa_dstatmsub; /* Destination ATM subaddr */
+ struct scsp_ckey aa_key; /* SCSP cache key */
+ struct scsp_id aa_oid; /* SCSP originator ID */
+ long aa_seq; /* SCSP sequence no. */
+ Atmarp_intf *aa_intf; /* Interface for entry */
+ u_char aa_flags; /* Flags (see below) */
+ u_char aa_origin; /* Entry origin */
+ char aa_mark; /* Mark */
+};
+typedef struct atmarp Atmarp;
+
+/*
+ * ATMARP Entry Flags
+ */
+#define AAF_PERM 0x01 /* Entry is permanent */
+#define AAF_SERVER 0x02 /* Entry is for the server */
+
+
+/*
+ * Global variables
+ */
+extern char *prog;
+extern int atmarp_debug_mode;
+extern int atmarp_max_socket;
+extern Atmarp_intf *atmarp_intf_head;
+extern Atmarp_slis *atmarp_slis_head;
+extern FILE *atmarp_log_file;
+
+
+/*
+ * Function definitions
+ */
+
+/* atmarp_config.c */
+extern int atmarp_cfg_netif __P((char *));
+
+/* atmarp_log.c */
+#if __STDC__
+extern void atmarp_log __P((const int, const char *, ...));
+#else
+extern void atmarp_log __P((int, char *, va_alist));
+#endif
+extern void atmarp_mem_err __P((char *));
+
+/* atmarp_scsp.c */
+extern int atmarp_scsp_cache __P((Atmarp_intf *, Scsp_if_msg *));
+extern int atmarp_scsp_update __P((Atmarp *, int));
+extern int atmarp_scsp_update_in __P((Atmarp_intf *,
+ Scsp_if_msg *));
+extern int atmarp_scsp_read __P((Atmarp_intf *));
+extern int atmarp_scsp_out __P((Atmarp_intf *, char *, int));
+extern int atmarp_scsp_connect __P((Atmarp_intf *));
+extern void atmarp_scsp_close __P((Atmarp_intf *));
+extern int atmarp_scsp_disconnect __P((Atmarp_intf *));
+
+/* atmarp_subr.c */
+extern Atmarp_intf *atmarp_find_intf_sock __P((int));
+extern Atmarp_intf *atmarp_find_intf_name __P((char *));
+extern void atmarp_clear_marks __P(());
+extern int atmarp_is_server __P((Atmarp_intf *));
+extern int atmarp_if_ready __P((Atmarp_intf *));
+extern Atmarp * atmarp_copy_cache_entry __P((struct air_arp_rsp *));
+extern void atmarp_get_updated_cache __P(());
+extern void atmarp_process_cache_entry __P((struct air_arp_rsp *));
+extern void print_atmarp_intf __P((FILE *, Atmarp_intf *));
+extern void print_atmarp_cache __P((FILE *, Atmarp *));
+extern void dump_atmarp_cache __P((FILE *, Atmarp_intf *));
+extern void atmarp_sigint __P((int));
+
+/* atmarp_timer.c */
+extern void atmarp_cache_timeout __P((Harp_timer *));
+extern void atmarp_perm_timeout __P((Harp_timer *));
+extern void atmarp_keepalive_timeout __P((Harp_timer *));
+
+
+#endif /* _ATMARP_ATMARP_VAR_H */
diff --git a/usr.sbin/atm/atmarpd/atmarpd.8 b/usr.sbin/atm/atmarpd/atmarpd.8
new file mode 100644
index 0000000..fe3f751
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/atmarpd.8
@@ -0,0 +1,129 @@
+.\"
+.\" ===================================
+.\" 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: atmarpd.1,v 1.2 1998/08/26 21:39:39 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 ATMARPD 8 "1998-08-04" "HARP"
+
+.SH NAME
+atmarpd \- ATMARP/SCSP interface daemon
+.SH SYNOPSIS
+.B atmarpd
+[\fB-l\fP <log file>]
+[\fB-d\fP]
+<netif> ...
+
+.SH DESCRIPTION
+\fIAtmarpd\fP provides an interface between the ATMARP server in the
+kernel and the SCSP daemon for the Host ATM Research Platform
+(HARP) networking software.
+\fIAtmarpd\fP reads the ATMARP cache from the kernel periodically
+and passes any updated entries to \fIscspd\fP so they will be
+propagated to remote servers.
+It also accepts updated entries that remote servers have sent to
+\fIscspd\fP and, if they are
+new or more up to date than current entries, installs them
+in the kernel's ATMARP cache.
+Both \fIatmarpd\fP and \fIscspd\fP must be running before any ATMARP
+cache synchronization can take place.
+
+When \fIatmarpd\fP starts, it parses its command line and puts
+itself into the background.
+
+The command-line options are:
+.IP "\fB-l\fP <log file>" 15
+Specifies that \fIatmarpd\fP is to write log messages to the the
+file named <log file> rather than to the system log.
+.IP "\fB-d\fP" 15
+Specifies that \fIatmarpd\fP is to be run in debug mode.
+In debug mode, \fIatmarpd\fP is not put into the background.
+Log messages are written to standard output instead of to
+the log file.
+.IP "<netif>" 15
+Specifies the network interface(s) for which the host is providing
+ATMARP service and whose caches are to be synchronized using SCSP.
+If multiple network interface names are be specified, \fIatmarpd\fP
+will provide an interface to \fIscspd\fP for the servers on all the
+specified interfaces.
+
+.SH SIGNAL PROCESSING
+The following signals can be used to control \fIatmarpd\fP:
+
+.IP \fBSIGINT\fP 10
+Dump debugging information to a file.
+When it receives a SIGINT signal, \fIatmarpd\fP dumps a summary of
+its control blocks to a text file (see "\fBFILES\fB").
+
+.SH FILES
+
+.IP "/tmp/atmarpd.<pid>.<seq>.out"
+Debugging information dump file name.
+\fIAtmarpd\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.
+
+.SH "SEE ALSO"
+\fIatm\fP (8);
+\fIscspd\fP (8);
+RFC 1577, \fIClassical IP and ARP over ATM\fP;
+RFC 2225, \fIClassical IP and ARP over ATM\fP;
+RFC 2334, \fIServer Cache Synchronization Protocol (SCSP)\fP;
+draft-ietf-ion-scsp-atmarpd-00.txt, \fIA Distributed ATMARP Service
+Using SCSP\fP.
+
+
+.SH BUGS
+Results are unpredictable if multiple instantiations of
+\fIatmarpd\fP are run simulatneously for a given network interface.
+
+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/atmarpd/atmarpd.c b/usr.sbin/atm/atmarpd/atmarpd.c
new file mode 100644
index 0000000..72ebb52
--- /dev/null
+++ b/usr.sbin/atm/atmarpd/atmarpd.c
@@ -0,0 +1,409 @@
+/*
+ *
+ * ===================================
+ * 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: atmarpd.c,v 1.5 1998/08/13 20:11:13 johnc Exp $
+ *
+ */
+
+/*
+ * Server Cache Synchronization Protocol (SCSP) Support
+ * ----------------------------------------------------
+ *
+ * SCSP-ATMARP server interface: main line code
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: atmarpd.c,v 1.5 1998/08/13 20:11:13 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 "../scspd/scsp_msg.h"
+#include "../scspd/scsp_if.h"
+#include "../scspd/scsp_var.h"
+#include "atmarp_var.h"
+
+
+/*
+ * Global variables
+ */
+char *prog;
+int atmarp_debug_mode = 0;
+int atmarp_max_socket = 0;
+Atmarp_intf *atmarp_intf_head = (Atmarp_intf *)0;
+Atmarp_slis *atmarp_slis_head = (Atmarp_slis *)0;
+FILE *atmarp_log_file = (FILE *)0;
+char *atmarp_log_file_name = (char *)0;
+Harp_timer cache_timer, perm_timer;
+
+
+
+/*
+ * Print a usage message
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * exits, does not return
+ *
+ */
+void
+usage()
+{
+ fprintf(stderr, "usage: %s [-d] [-l <log_file>] <net_intf> ...\n", prog);
+ exit(1);
+}
+
+
+/*
+ * Process command line parameters
+ *
+ * Arguments:
+ * argc number of command-line arguments
+ * argv list of pointers to command-line arguments
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+initialize(argc, argv)
+ int argc;
+ char *argv[];
+
+{
+ int i, rc;
+
+ /*
+ * 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);
+ }
+
+ /*
+ * Scan arguments, checking for options
+ */
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ if (strcmp(argv[i], "-d") == 0) {
+ atmarp_debug_mode = TRUE;
+ } else if (strcmp(argv[i], "-l") == 0) {
+ i++;
+ if (i >= argc) {
+ fprintf(stderr, "%s: Log file name missing\n",
+ prog);
+ exit(1);
+ }
+ atmarp_log_file_name = argv[i];
+ } else {
+ fprintf(stderr, "%s: Unrecognized option \"%s\"\n",
+ prog, argv[i]);
+ exit(1);
+ }
+ } else {
+ /*
+ * Parameter is a network interface name
+ */
+ rc = atmarp_cfg_netif(argv[i]);
+ if (rc) {
+ fprintf(stderr, "%s: Error configuring network interface %s\n",
+ prog, argv[i]);
+ exit(1);
+ }
+ }
+ }
+
+ /*
+ * Make sure we had at least one interface configured
+ */
+ if (!atmarp_intf_head) {
+ usage();
+ }
+}
+
+
+/*
+ * 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
+
+ /*
+ * Skip putting things into the background if we're
+ * in debugging mode
+ */
+ if (atmarp_debug_mode)
+ goto daemon_bypass;
+
+ /*
+ * Set up syslog for error logging
+ */
+ if (!atmarp_log_file) {
+ openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON);
+ }
+
+ /*
+ * Put the daemon into the background
+ */
+ dpid = fork();
+ if (dpid < 0) {
+ atmarp_log(LOG_ERR, "fork failed");
+ exit(1);
+ }
+ 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) {
+ atmarp_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);
+ }
+
+ /*
+ * Open log file, if specified
+ */
+ if (atmarp_log_file_name) {
+ atmarp_log_file = fopen(atmarp_log_file_name, "a");
+ if (!atmarp_log_file) {
+ atmarp_log(LOG_ERR, "%s: Can't open log file \'%s\'\n",
+ prog, atmarp_log_file_name);
+ exit(1);
+ }
+ }
+
+ /*
+ * Set up and start interval timer
+ */
+daemon_bypass:
+ init_timer();
+
+ /*
+ * Move to a safe directory
+ */
+ chdir(ATMARP_DIR);
+
+ /*
+ * Clear the file mode creation mask
+ */
+ umask(0);
+
+
+ /*
+ * Set up signal handlers
+ */
+ rc = (int)signal(SIGINT, atmarp_sigint);
+ if (rc == -1) {
+ atmarp_log(LOG_ERR, "SIGINT signal setup failed");
+ exit(1);
+ }
+}
+
+
+/*
+ * Main line code
+ *
+ * The ATMARP server resides in the kernel, while SCSP runs as a daemon
+ * in user space. This program exists to provide an interface between
+ * the two. It periodically polls the kernel to get the ATMARP cache
+ * and passes information about new entries to SCSP. It also accepts
+ * new information from SCSP and passes it to the kernel.
+ *
+ * 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;
+ fd_set read_set, write_set, except_set;
+ Atmarp_intf *aip;
+
+ /*
+ * Process command line arguments
+ */
+ initialize(argc, argv);
+
+ /*
+ * Put the daemon into the background
+ */
+ start_daemon();
+
+ /*
+ * Start the cache update timer
+ */
+ HARP_TIMER(&cache_timer, ATMARP_CACHE_INTERVAL,
+ atmarp_cache_timeout);
+
+ /*
+ * Start the permanent cache entry timer
+ */
+ HARP_TIMER(&perm_timer, ATMARP_PERM_INTERVAL,
+ atmarp_perm_timeout);
+
+ /*
+ * Establish a connection to SCSP for each interface. If a
+ * connect fails, it will be retried when the cache update
+ * timer fires.
+ */
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ if (atmarp_if_ready(aip)) {
+ (void)atmarp_scsp_connect(aip);
+ }
+ }
+
+ /*
+ * Read the cache from the kernel
+ */
+ atmarp_get_updated_cache();
+
+ /*
+ * Main program loop -- wait for data to come in from SCSP.
+ * When the timer fires, it will be handled elsewhere.
+ */
+ while (1) {
+ /*
+ * Wait for input from SCSP
+ */
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+ FD_ZERO(&except_set);
+ for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
+ if (aip->ai_scsp_sock != -1) {
+ FD_SET(aip->ai_scsp_sock, &read_set);
+ }
+ }
+ rc = select(atmarp_max_socket + 1,
+ &read_set, &write_set,
+ &except_set, (struct timeval *)0);
+ if (rc < 0) {
+ if (harp_timer_exec) {
+ timer_proc();
+ continue;
+ } else if (errno = EINTR) {
+ continue;
+ } else {
+ atmarp_log(LOG_ERR, "Select failed");
+ abort();
+ }
+ }
+
+ /*
+ * Read and process the input from SCSP
+ */
+ for (i = 0; i <= atmarp_max_socket; i++) {
+ if (FD_ISSET(i, &read_set)) {
+ aip = atmarp_find_intf_sock(i);
+ if (aip)
+ rc = atmarp_scsp_read(aip);
+ }
+ }
+ }
+}
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(&amp->sa_cpa));
+ fprintf(fp, "%sCached ATM addr: %s\n", indent,
+ format_atm_addr(&amp->sa_cha));
+ fprintf(fp, "%sCached ATM subaddr: %s\n", indent,
+ format_atm_addr(&amp->sa_csa));
+ fprintf(fp, "%sCache key:\n", indent);
+ print_scsp_cache_key(fp, &amp->sa_key);
+ fprintf(fp, "%sOriginator ID:\n", indent);
+ print_scsp_id(fp, &amp->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);
+ }
+ }
+ }
+ }
+}
OpenPOWER on IntegriCloud