aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/atm/atmarpd/atmarp_scsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/atm/atmarpd/atmarp_scsp.c')
-rw-r--r--usr.sbin/atm/atmarpd/atmarp_scsp.c792
1 files changed, 792 insertions, 0 deletions
diff --git a/usr.sbin/atm/atmarpd/atmarp_scsp.c b/usr.sbin/atm/atmarpd/atmarp_scsp.c
new file mode 100644
index 000000000000..e0638211a27f
--- /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);
+}